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:
patrickvl 2018-07-11 17:34:00 +02:00
parent f8c023d2e1
commit a9d1f60b04
4 changed files with 43 additions and 33 deletions

View File

@ -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)

View File

@ -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();
e->ContextRecord->Eax = PerformanceCount.LowPart;
e->ContextRecord->Edx = PerformanceCount.HighPart;
e->ContextRecord->Eip += 2;
return true;
}
}
// Check if this exception came from rdtsc
if (IsRdtscInstruction(e->ContextRecord->Eip)) {
// 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

View File

@ -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);

View File

@ -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();
}