HLE : Move IsXboxCodeAddress check into it's own function, and call it first in IsXboxCodeAddress (instead of later, in EmuX86_DecodeException).
Also, optimize IsRdtscInstruction() and it's emulation, by calling directly into CxbxRdTsc(). Additionally, use unsigned ULARGE_INTEGER and ULONGLONG variables.
This commit is contained in:
parent
f8c023d2e1
commit
a9d1f60b04
|
@ -689,14 +689,13 @@ bool IsRdtscInstruction(xbaddr addr)
|
|||
{
|
||||
// First the fastest check - is this a patch? (see PatchRdtsc)
|
||||
uint8_t* opAddr = (uint8_t*)addr;
|
||||
if ((opAddr[0] == 0xEF) // OUT DX, EAX
|
||||
&& (opAddr[1] == 0x90)) { // NOP
|
||||
if (std::find(g_RdtscPatches.begin(), g_RdtscPatches.end(), addr) != g_RdtscPatches.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// Note : Check second opcode first, as that's most likely to fail fast
|
||||
return (opAddr[1] == 0x90) // NOP
|
||||
&& (opAddr[0] == 0xEF) // OUT DX, EAX
|
||||
// Note : It's not needed to check for g_SkipRdtscPatching,
|
||||
// as when that's set, the g_RdtscPatches vector will be empty
|
||||
// anyway, failing this lookup :
|
||||
&& (std::find(g_RdtscPatches.begin(), g_RdtscPatches.end(), addr) != g_RdtscPatches.end());
|
||||
}
|
||||
|
||||
void PatchRdtsc(xbaddr addr)
|
||||
|
|
|
@ -216,25 +216,41 @@ void EmuExceptionNonBreakpointUnhandledShow(LPEXCEPTION_POINTERS e)
|
|||
}
|
||||
}
|
||||
|
||||
// Returns weither the given address is part of an Xbox managed memory region
|
||||
bool IsXboxCodeAddress(xbaddr addr)
|
||||
{
|
||||
// TODO : Replace the following with a (fast) check weither
|
||||
// the given address lies in xbox allocated virtual memory,
|
||||
// for example by g_VMManager.CheckConflictingVMA(addr, 0).
|
||||
return (addr >= XBE_IMAGE_BASE) && (addr <= XBE_MAX_VA);
|
||||
// Note : Not IS_USER_ADDRESS(), that would include host DLL code
|
||||
}
|
||||
|
||||
bool IsRdtscInstruction(xbaddr addr);
|
||||
ULONGLONG CxbxRdTsc(bool xbox);
|
||||
bool TryHandleException(EXCEPTION_POINTERS *e)
|
||||
{
|
||||
// Only handle exceptions which originate from Xbox code
|
||||
if (!IsXboxCodeAddress(e->ContextRecord->Eip)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure access-violations reach EmuX86_DecodeException() as soon as possible
|
||||
if (e->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) {
|
||||
switch (e->ExceptionRecord->ExceptionCode) {
|
||||
case STATUS_PRIVILEGED_INSTRUCTION:
|
||||
// When the g_SkipRdtscPatching hack is disabled
|
||||
if (!g_SkipRdtscPatching) {
|
||||
// Check if this exception came from rdtsc
|
||||
if (IsRdtscInstruction(e->ContextRecord->Eip)) {
|
||||
LARGE_INTEGER PerformanceCount;
|
||||
PerformanceCount.QuadPart = xboxkrnl::KeQueryPerformanceCounter();
|
||||
// If so, use a return value that updates with Xbox frequency;
|
||||
// Avoid the overhead of xboxkrnl::KeQueryPerformanceCounter,
|
||||
// by calling directly into it's backing implementation:
|
||||
ULARGE_INTEGER PerformanceCount;
|
||||
PerformanceCount.QuadPart = CxbxRdTsc(/*xbox=*/true);
|
||||
e->ContextRecord->Eax = PerformanceCount.LowPart;
|
||||
e->ContextRecord->Edx = PerformanceCount.HighPart;
|
||||
e->ContextRecord->Eip += 2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATUS_BREAKPOINT:
|
||||
// Let user choose between continue or break
|
||||
|
|
|
@ -248,21 +248,21 @@ void InitDpcAndTimerThread()
|
|||
|
||||
// Xbox Performance Counter Frequency = 733333333 (CPU Clock)
|
||||
#define XBOX_PERFORMANCE_FREQUENCY 733333333
|
||||
uint64_t NativeToXbox_FactorForPerformanceFrequency;
|
||||
ULONGLONG NativeToXbox_FactorForPerformanceFrequency;
|
||||
|
||||
void ConnectKeInterruptTimeToThunkTable(); // forward
|
||||
|
||||
uint64_t CxbxRdTsc(bool xbox) {
|
||||
ULONGLONG CxbxRdTsc(bool xbox) {
|
||||
LARGE_INTEGER tsc;
|
||||
|
||||
QueryPerformanceCounter(&tsc);
|
||||
|
||||
if (xbox && NativeToXbox_FactorForPerformanceFrequency) {
|
||||
LARGE_INTEGER scaledTsc;
|
||||
ULARGE_INTEGER scaledTsc;
|
||||
scaledTsc.QuadPart = 1000000000;
|
||||
scaledTsc.QuadPart *= tsc.QuadPart;
|
||||
scaledTsc.QuadPart *= (ULONGLONG)tsc.QuadPart;
|
||||
scaledTsc.QuadPart /= NativeToXbox_FactorForPerformanceFrequency;
|
||||
return (uint64_t)scaledTsc.QuadPart;
|
||||
return scaledTsc.QuadPart;
|
||||
}
|
||||
|
||||
return (uint64_t)tsc.QuadPart;
|
||||
|
@ -1127,8 +1127,8 @@ XBSYSAPI EXPORTNUM(126) xboxkrnl::ULONGLONG NTAPI xboxkrnl::KeQueryPerformanceCo
|
|||
ULONGLONG ret;
|
||||
|
||||
//no matter rdtsc is patched or not, we should always return a scaled performance counter here.
|
||||
DbgPrintf("host tick count : %lu\n", CxbxRdTsc(false));
|
||||
ret = CxbxRdTsc(true);
|
||||
DbgPrintf("host tick count : %lu\n", CxbxRdTsc(/*xbox=*/false));
|
||||
ret = CxbxRdTsc(/*xbox=*/true);
|
||||
DbgPrintf("emulated tick count : %lu\n", ret);
|
||||
|
||||
RETURN(ret);
|
||||
|
|
|
@ -1043,11 +1043,6 @@ int EmuX86_OpcodeSize(uint8_t *Eip)
|
|||
|
||||
bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
|
||||
{
|
||||
// Only decode instructions which reside in the loaded Xbe
|
||||
if (e->ContextRecord->Eip > XBE_MAX_VA || e->ContextRecord->Eip < XBE_IMAGE_BASE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decoded instruction information.
|
||||
// Opcode handler note :
|
||||
// If an opcode or one of it's operand can't be decoded, that's a clear failure.
|
||||
|
@ -1137,7 +1132,7 @@ void EmuX86_Init()
|
|||
{
|
||||
DbgPrintf("X86 : Initializing distorm version %d\n", distorm_version());
|
||||
#ifndef USE_SEH // implies VEH
|
||||
AddVectoredExceptionHandler(1, EmuException);
|
||||
AddVectoredExceptionHandler(/*FirstHandler=*/ULONG(true), EmuException);
|
||||
#endif // !USE_SEG
|
||||
EmuX86_InitContextRecordOffsetByRegisterType();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue