Patch rdtsc instructions
This commit is contained in:
parent
d24b7e54fd
commit
e53213f056
|
@ -191,12 +191,6 @@ WndMain::WndMain(HINSTANCE x_hInstance) :
|
|||
m_UseAllCores = 0;
|
||||
}
|
||||
|
||||
dwType = REG_DWORD; dwSize = sizeof(DWORD);
|
||||
result = RegQueryValueEx(hKey, "HackPatchCpuFrequency", NULL, &dwType, (PBYTE)&m_PatchCpuFrequency, &dwSize);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
m_PatchCpuFrequency = 0;
|
||||
}
|
||||
|
||||
dwType = REG_DWORD; dwSize = sizeof(DWORD);
|
||||
result = RegQueryValueEx(hKey, "CxbxDebug", NULL, &dwType, (PBYTE)&m_CxbxDebug, &dwSize);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
|
@ -356,9 +350,6 @@ WndMain::~WndMain()
|
|||
dwType = REG_DWORD; dwSize = sizeof(DWORD);
|
||||
RegSetValueEx(hKey, "HackUseAllCores", 0, dwType, (PBYTE)&m_UseAllCores, dwSize);
|
||||
|
||||
dwType = REG_DWORD; dwSize = sizeof(DWORD);
|
||||
RegSetValueEx(hKey, "HackPatchCpuFrequency", 0, dwType, (PBYTE)&m_PatchCpuFrequency, dwSize);
|
||||
|
||||
dwType = REG_DWORD; dwSize = sizeof(DWORD);
|
||||
RegSetValueEx(hKey, "CxbxDebug", 0, dwType, (PBYTE)&m_CxbxDebug, dwSize);
|
||||
|
||||
|
@ -1333,11 +1324,6 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP
|
|||
RefreshMenus();
|
||||
break;
|
||||
|
||||
case ID_HACKS_PATCHCPUFREQUENCY:
|
||||
m_PatchCpuFrequency = !m_PatchCpuFrequency;
|
||||
RefreshMenus();
|
||||
break;
|
||||
|
||||
case ID_HELP_ABOUT:
|
||||
{
|
||||
ShowAboutDialog(hwnd);
|
||||
|
@ -1765,9 +1751,6 @@ void WndMain::RefreshMenus()
|
|||
|
||||
chk_flag = (m_UseAllCores) ? MF_CHECKED : MF_UNCHECKED;
|
||||
CheckMenuItem(settings_menu, ID_HACKS_RUNXBOXTHREADSONALLCORES, chk_flag);
|
||||
|
||||
chk_flag = (m_PatchCpuFrequency) ? MF_CHECKED : MF_UNCHECKED;
|
||||
CheckMenuItem(settings_menu, ID_HACKS_PATCHCPUFREQUENCY, chk_flag);
|
||||
}
|
||||
|
||||
// emulation menu
|
||||
|
@ -2141,7 +2124,6 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState /
|
|||
g_EmuShared->SetDisablePixelShaders(&m_DisablePixelShaders);
|
||||
g_EmuShared->SetUncapFramerate(&m_UncapFramerate);
|
||||
g_EmuShared->SetUseAllCores(&m_UseAllCores);
|
||||
g_EmuShared->SetPatchCpuFrequency(&m_PatchCpuFrequency);
|
||||
|
||||
// shell exe
|
||||
{
|
||||
|
|
|
@ -216,7 +216,6 @@ class WndMain : public Wnd
|
|||
int m_DisablePixelShaders;
|
||||
int m_UncapFramerate;
|
||||
int m_UseAllCores;
|
||||
int m_PatchCpuFrequency;
|
||||
|
||||
// ******************************************************************
|
||||
// * debug output filenames
|
||||
|
|
|
@ -582,7 +582,6 @@ void PrintCurrentConfigurationLog()
|
|||
printf("Disable Pixel Shaders: %s\n", g_DisablePixelShaders == 1 ? "On" : "Off");
|
||||
printf("Uncap Framerate: %s\n", g_UncapFramerate == 1 ? "On" : "Off");
|
||||
printf("Run Xbox threads on all cores: %s\n", g_UseAllCores == 1 ? "On" : "Off");
|
||||
printf("Patch CPU Frequency (rdtsc): %s\n", g_PatchCpuFrequency == 1 ? "On" : "Off");
|
||||
}
|
||||
|
||||
printf("------------------------- END OF CONFIG LOG ------------------------\n");
|
||||
|
@ -652,11 +651,21 @@ static unsigned int WINAPI CxbxKrnlInterruptThread(PVOID param)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void PatchPerformanceFrequency()
|
||||
std::vector<xbaddr> g_RdtscPatches;
|
||||
|
||||
bool IsRdtscInstruction(xbaddr addr)
|
||||
{
|
||||
DWORD xboxFrequency = 733333333; // 733mhz
|
||||
LARGE_INTEGER hostFrequency;
|
||||
QueryPerformanceFrequency(&hostFrequency);
|
||||
if (std::find(g_RdtscPatches.begin(), g_RdtscPatches.end(), addr) != g_RdtscPatches.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "distorm.h"
|
||||
void PatchRdtscInstruction()
|
||||
{
|
||||
uint8_t rdtsc[2] = { 0x0F, 0x31 };
|
||||
DWORD sizeOfImage = CxbxKrnl_XbeHeader->dwSizeofImage;
|
||||
|
||||
// Iterate through each CODE section
|
||||
|
@ -664,22 +673,36 @@ void PatchPerformanceFrequency()
|
|||
if (!CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwFlags.bExecutable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip some segments known to never contain rdtsc (to avoid false positives)
|
||||
if (std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "DSOUND"
|
||||
|| std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "XGRPH") {
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("INIT: Searching for xbox performance frequency in section %s\n", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]);
|
||||
printf("INIT: Searching for rdtsc in section %s\n", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]);
|
||||
xbaddr startAddr = CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwVirtualAddr;
|
||||
xbaddr endAddr = startAddr + CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwSizeofRaw;
|
||||
for (xbaddr addr = startAddr; addr < endAddr; addr++)
|
||||
{
|
||||
if (memcmp((void*)addr, &xboxFrequency, sizeof(DWORD)) == 0) {
|
||||
printf("INIT: Patching Frequency at 0x%.8X\n", addr);
|
||||
*(uint32*)(addr) = (uint32)hostFrequency.QuadPart;
|
||||
addr += sizeof(DWORD);
|
||||
for (xbaddr addr = startAddr; addr < endAddr; addr++) {
|
||||
if (memcmp((void*)addr, rdtsc, 2) == 0) {
|
||||
printf("INIT: Patching rdtsc opcode at 0x%.8X\n", (DWORD)addr);
|
||||
uint8_t* opAddr = (uint8_t*)addr;
|
||||
|
||||
// Patch away rdtsc with an opcode we can intercept
|
||||
// We use a privilaged instruction rather than int 3 for debugging
|
||||
// When using int 3, attached debuggers trap and rdtsc is used often enough
|
||||
// that it makes Cxbx-Reloaded unusable
|
||||
// A privilaged instruction (like OUT) does not suffer from this
|
||||
opAddr[0] = 0xEF; // OUT DX, EAX
|
||||
opAddr[1] = 0x90; // NOP
|
||||
g_RdtscPatches.push_back(addr);
|
||||
addr += 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("INIT: Done patching xbox performance frequency\n");
|
||||
printf("INIT: Done patching rdtsc\n");
|
||||
}
|
||||
|
||||
void CxbxKrnlMain(int argc, char* argv[])
|
||||
|
@ -1100,8 +1123,6 @@ __declspec(noreturn) void CxbxKrnlInit
|
|||
g_UncapFramerate = !!HackEnabled;
|
||||
g_EmuShared->GetUseAllCores(&HackEnabled);
|
||||
g_UseAllCores = !!HackEnabled;
|
||||
g_EmuShared->GetPatchCpuFrequency(&HackEnabled);
|
||||
g_PatchCpuFrequency = !!HackEnabled;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG_PRINT_CURRENT_CONF
|
||||
|
@ -1264,9 +1285,7 @@ __declspec(noreturn) void CxbxKrnlInit
|
|||
// See: https://multimedia.cx/eggs/xbox-sphinx-protocol/
|
||||
ApplyMediaPatches();
|
||||
|
||||
if (g_PatchCpuFrequency) {
|
||||
PatchPerformanceFrequency();
|
||||
}
|
||||
PatchRdtscInstruction();
|
||||
|
||||
// Setup per-title encryption keys
|
||||
SetupPerTitleKeys();
|
||||
|
|
|
@ -67,7 +67,6 @@ bool g_XInputEnabled = false;
|
|||
bool g_DisablePixelShaders = false;
|
||||
bool g_UncapFramerate = false;
|
||||
bool g_UseAllCores = false;
|
||||
bool g_PatchCpuFrequency = false;
|
||||
|
||||
// Delta added to host SystemTime, used in xboxkrnl::KeQuerySystemTime and xboxkrnl::NtSetSystemTime
|
||||
LARGE_INTEGER HostSystemTimeDelta = {};
|
||||
|
@ -218,6 +217,7 @@ void EmuExceptionNonBreakpointUnhandledShow(LPEXCEPTION_POINTERS e)
|
|||
}
|
||||
|
||||
// exception handler
|
||||
bool IsRdtscInstruction(xbaddr addr);
|
||||
extern int EmuException(LPEXCEPTION_POINTERS e)
|
||||
{
|
||||
g_bEmuException = true;
|
||||
|
@ -233,6 +233,19 @@ extern int EmuException(LPEXCEPTION_POINTERS e)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Check if this exception came from rdtsc
|
||||
if (e->ExceptionRecord->ExceptionCode == STATUS_PRIVILEGED_INSTRUCTION) {
|
||||
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;
|
||||
g_bEmuException = false;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip past CxbxDebugger-specific exceptions thrown when an unsupported was attached (ie Visual Studio)
|
||||
if (CxbxDebugger::IsDebuggerException(e->ExceptionRecord->ExceptionCode))
|
||||
{
|
||||
|
|
|
@ -110,5 +110,4 @@ typedef struct DUMMY_KERNEL
|
|||
extern bool g_DisablePixelShaders;
|
||||
extern bool g_UncapFramerate;
|
||||
extern bool g_UseAllCores;
|
||||
extern bool g_PatchCpuFrequency;
|
||||
#endif
|
||||
|
|
|
@ -1096,11 +1096,6 @@ XBSYSAPI EXPORTNUM(126) xboxkrnl::ULONGLONG NTAPI xboxkrnl::KeQueryPerformanceCo
|
|||
ULONGLONG ret;
|
||||
::LARGE_INTEGER PerformanceCounter;
|
||||
|
||||
if (g_PatchCpuFrequency) {
|
||||
RETURN((ULONGLONG)__rdtsc());
|
||||
}
|
||||
|
||||
|
||||
// TODO : When Cxbx emulates the RDTSC opcode, use the same handling here.
|
||||
|
||||
// Dxbx note : Xbox actually uses the RDTSC machine code instruction for this,
|
||||
|
|
|
@ -126,8 +126,6 @@ class EmuShared : public Mutex
|
|||
void SetUncapFramerate(int* value) { Lock(); m_UncapFramerate = *value; Unlock(); }
|
||||
void GetUseAllCores(int* value) { Lock(); *value = m_UseAllCores; Unlock(); }
|
||||
void SetUseAllCores(int* value) { Lock(); m_UseAllCores = *value; Unlock(); }
|
||||
void GetPatchCpuFrequency(int* value) { Lock(); *value = m_PatchCpuFrequeny; Unlock(); }
|
||||
void SetPatchCpuFrequency(int* value) { Lock(); m_PatchCpuFrequeny = *value; Unlock(); }
|
||||
|
||||
// ******************************************************************
|
||||
// * MSpF/Benchmark values Accessors
|
||||
|
@ -196,7 +194,6 @@ class EmuShared : public Mutex
|
|||
int m_DisablePixelShaders;
|
||||
int m_UncapFramerate;
|
||||
int m_UseAllCores;
|
||||
int m_PatchCpuFrequeny;
|
||||
float m_MSpF;
|
||||
float m_FPS;
|
||||
bool m_bMultiXbeFlag;
|
||||
|
|
|
@ -944,25 +944,6 @@ LPVOID WINAPI XTL::EMUPATCH(ConvertThreadToFiber)
|
|||
RETURN(pRet);
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
// * patch: QueryPerformanceCounter
|
||||
// ******************************************************************
|
||||
BOOL WINAPI XTL::EMUPATCH(QueryPerformanceCounter)
|
||||
(
|
||||
LARGE_INTEGER *lpPerformanceCount
|
||||
)
|
||||
{
|
||||
FUNC_EXPORTS;
|
||||
|
||||
if (g_PatchCpuFrequency) {
|
||||
lpPerformanceCount->QuadPart = (LONGLONG)__rdtsc();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
lpPerformanceCount->QuadPart = xboxkrnl::KeQueryPerformanceCounter();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
// * patch: QueueUserAPC
|
||||
// ******************************************************************
|
||||
|
|
Loading…
Reference in New Issue