Updated KeInterruptTime, KeSystemTime, KeTickCount and timer handling
This commit is contained in:
parent
62dfa7b4e2
commit
1ae67fb215
|
@ -249,7 +249,7 @@ XBSYSAPI EXPORTNUM(119) BOOLEAN NTAPI KeInsertQueueDpc
|
|||
// ******************************************************************
|
||||
// * 0x0078 - KeInterruptTime
|
||||
// ******************************************************************
|
||||
XBSYSAPI EXPORTNUM(120) PKSYSTEM_TIME KeInterruptTime;
|
||||
XBSYSAPI EXPORTNUM(120) KSYSTEM_TIME KeInterruptTime;
|
||||
|
||||
// ******************************************************************
|
||||
// * 0x0079 - KeIsExecutingDpc()
|
||||
|
@ -490,7 +490,7 @@ XBSYSAPI EXPORTNUM(153) BOOLEAN NTAPI KeSynchronizeExecution
|
|||
// ******************************************************************
|
||||
// * 0x009A - KeSystemTime
|
||||
// ******************************************************************
|
||||
XBSYSAPI EXPORTNUM(154) PKSYSTEM_TIME KeSystemTime;
|
||||
XBSYSAPI EXPORTNUM(154) KSYSTEM_TIME KeSystemTime;
|
||||
|
||||
// ******************************************************************
|
||||
// * 0x009B - KeTestAlertThread()
|
||||
|
|
|
@ -154,7 +154,7 @@ void RestoreInterruptMode(bool value)
|
|||
g_bInterruptsEnabled = value;
|
||||
}
|
||||
|
||||
extern DWORD ExecuteDpcQueue();
|
||||
extern void ExecuteDpcQueue();
|
||||
|
||||
void KiUnexpectedInterrupt()
|
||||
{
|
||||
|
|
|
@ -71,10 +71,9 @@ typedef struct _DpcData {
|
|||
CRITICAL_SECTION Lock;
|
||||
HANDLE DpcEvent;
|
||||
xboxkrnl::LIST_ENTRY DpcQueue; // TODO : Use KeGetCurrentPrcb()->DpcListHead instead
|
||||
xboxkrnl::LIST_ENTRY TimerQueue;
|
||||
} DpcData;
|
||||
|
||||
DpcData g_DpcData = { 0 }; // Note : g_DpcData is initialized in InitDpcAndTimerThread()
|
||||
DpcData g_DpcData = { 0 }; // Note : g_DpcData is initialized in InitDpcThread()
|
||||
|
||||
xboxkrnl::ULONGLONG LARGE_INTEGER2ULONGLONG(xboxkrnl::LARGE_INTEGER value)
|
||||
{
|
||||
|
@ -220,23 +219,9 @@ xboxkrnl::KPRCB *KeGetCurrentPrcb()
|
|||
#define KeRaiseIrql(NewIrql, OldIrql) \
|
||||
*(OldIrql) = KfRaiseIrql(NewIrql)
|
||||
|
||||
ULONGLONG BootTickCount = 0;
|
||||
|
||||
// The Xbox GetTickCount is measured in milliseconds, just like the native GetTickCount.
|
||||
// The only difference we'll take into account here, is that the Xbox will probably reboot
|
||||
// much more often than Windows, so we correct this with a 'BootTickCount' value :
|
||||
DWORD CxbxXboxGetTickCount()
|
||||
{
|
||||
return (DWORD)(GetTickCount64() - BootTickCount);
|
||||
}
|
||||
|
||||
DWORD ExecuteDpcQueue()
|
||||
void ExecuteDpcQueue()
|
||||
{
|
||||
xboxkrnl::PKDPC pkdpc;
|
||||
DWORD dwWait;
|
||||
DWORD dwNow;
|
||||
LONG lWait;
|
||||
xboxkrnl::PKTIMER pktimer;
|
||||
|
||||
// While we're working with the DpcQueue, we need to be thread-safe :
|
||||
EnterCriticalSection(&(g_DpcData.Lock));
|
||||
|
@ -274,64 +259,18 @@ DWORD ExecuteDpcQueue()
|
|||
KeGetCurrentPrcb()->DpcRoutineActive = FALSE; // Experimental
|
||||
}
|
||||
|
||||
dwWait = INFINITE;
|
||||
if (!IsListEmpty(&(g_DpcData.TimerQueue)))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
dwNow = CxbxXboxGetTickCount();
|
||||
dwWait = INFINITE;
|
||||
pktimer = (xboxkrnl::PKTIMER)g_DpcData.TimerQueue.Flink;
|
||||
pkdpc = nullptr;
|
||||
while (pktimer != (xboxkrnl::PKTIMER)&(g_DpcData.TimerQueue))
|
||||
{
|
||||
lWait = (LONG)pktimer->DueTime.u.LowPart - dwNow;
|
||||
if (lWait <= 0)
|
||||
{
|
||||
pktimer->DueTime.u.LowPart = pktimer->Period + dwNow;
|
||||
pkdpc = pktimer->Dpc;
|
||||
break; // while
|
||||
}
|
||||
|
||||
if (dwWait > (DWORD)lWait)
|
||||
dwWait = (DWORD)lWait;
|
||||
|
||||
pktimer = (xboxkrnl::PKTIMER)pktimer->TimerListEntry.Flink;
|
||||
}
|
||||
|
||||
if (pkdpc == nullptr)
|
||||
break; // while
|
||||
|
||||
DBG_PRINTF("Global TimerQueue, calling DPC at 0x%.8X\n", pkdpc->DeferredRoutine);
|
||||
|
||||
__try {
|
||||
pkdpc->DeferredRoutine(
|
||||
pkdpc,
|
||||
pkdpc->DeferredContext,
|
||||
pkdpc->SystemArgument1,
|
||||
pkdpc->SystemArgument2);
|
||||
} __except (EmuException(GetExceptionInformation()))
|
||||
{
|
||||
EmuLog(LOG_LEVEL::WARNING, "Problem with ExceptionFilter!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assert(g_DpcData._dwThreadId == GetCurrentThreadId());
|
||||
// Assert(g_DpcData._dwDpcThreadId == g_DpcData._dwThreadId);
|
||||
// g_DpcData._dwDpcThreadId = 0;
|
||||
LeaveCriticalSection(&(g_DpcData.Lock));
|
||||
|
||||
return dwWait;
|
||||
}
|
||||
|
||||
void InitDpcAndTimerThread()
|
||||
void InitDpcThread()
|
||||
{
|
||||
DWORD dwThreadId = 0;
|
||||
|
||||
InitializeCriticalSection(&(g_DpcData.Lock));
|
||||
InitializeListHead(&(g_DpcData.DpcQueue));
|
||||
InitializeListHead(&(g_DpcData.TimerQueue));
|
||||
|
||||
DBG_PRINTF_EX(CXBXR_MODULE::INIT, "Creating DPC event\n");
|
||||
g_DpcData.DpcEvent = CreateEvent(/*lpEventAttributes=*/nullptr, /*bManualReset=*/FALSE, /*bInitialState=*/FALSE, /*lpName=*/nullptr);
|
||||
|
@ -342,8 +281,6 @@ void InitDpcAndTimerThread()
|
|||
ULONGLONG NativeToXbox_FactorForRdtsc;
|
||||
ULONGLONG NativeToXbox_FactorForAcpi;
|
||||
|
||||
void ConnectKeInterruptTimeToThunkTable(); // forward
|
||||
|
||||
ULONGLONG CxbxGetPerformanceCounter(bool acpi) {
|
||||
LARGE_INTEGER tsc;
|
||||
ULARGE_INTEGER scaledTsc;
|
||||
|
@ -377,11 +314,9 @@ void CxbxInitPerformanceCounters()
|
|||
t /= XBOX_ACPI_FREQUENCY;
|
||||
NativeToXbox_FactorForAcpi = t;
|
||||
|
||||
ConnectKeInterruptTimeToThunkTable();
|
||||
|
||||
// Let's initialize the Dpc and timer handling thread too,
|
||||
// Let's initialize the Dpc handling thread too,
|
||||
// here for now (should be called by our caller)
|
||||
InitDpcAndTimerThread();
|
||||
InitDpcThread();
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
|
@ -1107,14 +1042,7 @@ XBSYSAPI EXPORTNUM(121) xboxkrnl::BOOLEAN NTAPI xboxkrnl::KeIsExecutingDpc
|
|||
// ******************************************************************
|
||||
// * 0x0078 - KeInterruptTime
|
||||
// ******************************************************************
|
||||
// Dxbx note : This was once a value, but instead we now point to
|
||||
// the native Windows versions (see ConnectWindowsTimersToThunkTable) :
|
||||
XBSYSAPI EXPORTNUM(120) xboxkrnl::PKSYSTEM_TIME xboxkrnl::KeInterruptTime = nullptr; // Set by ConnectKeInterruptTimeToThunkTable
|
||||
|
||||
void ConnectKeInterruptTimeToThunkTable()
|
||||
{
|
||||
xboxkrnl::KeInterruptTime = (xboxkrnl::PKSYSTEM_TIME)CxbxKrnl_KernelThunkTable[120];
|
||||
}
|
||||
XBSYSAPI EXPORTNUM(120) xboxkrnl::KSYSTEM_TIME xboxkrnl::KeInterruptTime = { 0, 0, 0 };
|
||||
|
||||
// ******************************************************************
|
||||
// * 0x007A - KeLeaveCriticalRegion()
|
||||
|
@ -1204,12 +1132,12 @@ XBSYSAPI EXPORTNUM(125) xboxkrnl::ULONGLONG NTAPI xboxkrnl::KeQueryInterruptTime
|
|||
{
|
||||
// Don't use NtDll::QueryInterruptTime, it's too new (Windows 10).
|
||||
// Instead, read KeInterruptTime from our kernel thunk table.
|
||||
InterruptTime.u.HighPart = KeInterruptTime->High1Time;
|
||||
InterruptTime.u.LowPart = KeInterruptTime->LowPart;
|
||||
InterruptTime.u.HighPart = KeInterruptTime.High1Time;
|
||||
InterruptTime.u.LowPart = KeInterruptTime.LowPart;
|
||||
|
||||
// Read InterruptTime atomically with a spinloop to avoid errors
|
||||
// when High1Time and High2Time differ (during unprocessed overflow in LowPart).
|
||||
if (InterruptTime.u.HighPart == KeInterruptTime->High2Time)
|
||||
if (InterruptTime.u.HighPart == KeInterruptTime.High2Time)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1254,12 +1182,12 @@ XBSYSAPI EXPORTNUM(128) xboxkrnl::VOID NTAPI xboxkrnl::KeQuerySystemTime
|
|||
|
||||
while (true)
|
||||
{
|
||||
SystemTime.u.HighPart = KeSystemTime->High1Time;
|
||||
SystemTime.u.LowPart = KeSystemTime->LowPart;
|
||||
SystemTime.u.HighPart = KeSystemTime.High1Time;
|
||||
SystemTime.u.LowPart = KeSystemTime.LowPart;
|
||||
|
||||
// Read InterruptTime atomically with a spinloop to avoid errors
|
||||
// when High1Time and High2Time differ (during unprocessed overflow in LowPart).
|
||||
if (SystemTime.u.HighPart == KeSystemTime->High2Time)
|
||||
if (SystemTime.u.HighPart == KeSystemTime.High2Time)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1858,9 +1786,7 @@ XBSYSAPI EXPORTNUM(153) xboxkrnl::BOOLEAN NTAPI xboxkrnl::KeSynchronizeExecution
|
|||
// ******************************************************************
|
||||
// * 0x009A - KeSystemTime
|
||||
// ******************************************************************
|
||||
// Dxbx note : This was once a value, but instead we now point to
|
||||
// the native Windows versions (see ConnectWindowsTimersToThunkTable) :
|
||||
// XBSYSAPI EXPORTNUM(154) xboxkrnl::PKSYSTEM_TIME xboxkrnl::KeSystemTime; // Used for KernelThunk[154]
|
||||
// XBSYSAPI EXPORTNUM(154) xboxkrnl::KSYSTEM_TIME xboxkrnl::KeSystemTime; // Used for KernelThunk[154]
|
||||
|
||||
// ******************************************************************
|
||||
// * 0x009B - KeTestAlertThread()
|
||||
|
|
|
@ -72,26 +72,26 @@ VOID xboxkrnl::KiClockIsr(unsigned int ScalingFactor)
|
|||
OldIrql = KfRaiseIrql(CLOCK_LEVEL);
|
||||
|
||||
// Update the interrupt time
|
||||
InterruptTime.u.LowPart = KeInterruptTime->LowPart;
|
||||
InterruptTime.u.HighPart = KeInterruptTime->High1Time;
|
||||
InterruptTime.u.LowPart = KeInterruptTime.LowPart;
|
||||
InterruptTime.u.HighPart = KeInterruptTime.High1Time;
|
||||
InterruptTime.QuadPart += (CLOCK_TIME_INCREMENT * ScalingFactor);
|
||||
KeInterruptTime->High2Time = InterruptTime.u.HighPart;
|
||||
KeInterruptTime->LowPart = InterruptTime.u.LowPart;
|
||||
KeInterruptTime->High1Time = InterruptTime.u.HighPart;
|
||||
KeInterruptTime.High2Time = InterruptTime.u.HighPart;
|
||||
KeInterruptTime.LowPart = InterruptTime.u.LowPart;
|
||||
KeInterruptTime.High1Time = InterruptTime.u.HighPart;
|
||||
|
||||
// Update the system time
|
||||
// NOTE: I'm not sure if we should round down the host system time to the nearest multiple
|
||||
// of the Xbox clock increment...
|
||||
GetSystemTimeAsFileTime((LPFILETIME)&HostSystemTime);
|
||||
HostSystemTime.QuadPart += HostSystemTimeDelta.QuadPart;
|
||||
KeSystemTime->High2Time = HostSystemTime.u.HighPart;
|
||||
KeSystemTime->LowPart = HostSystemTime.u.LowPart;
|
||||
KeSystemTime->High1Time = HostSystemTime.u.HighPart;
|
||||
KeSystemTime.High2Time = HostSystemTime.u.HighPart;
|
||||
KeSystemTime.LowPart = HostSystemTime.u.LowPart;
|
||||
KeSystemTime.High1Time = HostSystemTime.u.HighPart;
|
||||
|
||||
// Update the tick counter
|
||||
KeTickCount += ScalingFactor;
|
||||
|
||||
// Check if a timer have expired
|
||||
// Check if a timer has expired
|
||||
Hand = KeTickCount & (TIMER_TABLE_SIZE - 1);
|
||||
if (KiTimerTableListHead[Hand].Entry.Flink != &KiTimerTableListHead[Hand].Entry &&
|
||||
InterruptTime.QuadPart >= KiTimerTableListHead[Hand].Time.QuadPart) {
|
||||
|
|
|
@ -175,7 +175,7 @@ uint32 CxbxKrnl_KernelThunkTable[379] =
|
|||
(uint32)FUNC(&xboxkrnl::KeInsertQueue), // 0x0075 (117)
|
||||
(uint32)FUNC(&xboxkrnl::KeInsertQueueApc), // 0x0076 (118)
|
||||
(uint32)FUNC(&xboxkrnl::KeInsertQueueDpc), // 0x0077 (119)
|
||||
(uint32)VARIABLE(0x0078), // 0x0078 (120) KeInterruptTime (Set by ConnectWindowsTimersToThunkTable)
|
||||
(uint32)VARIABLE(&xboxkrnl::KeInterruptTime), // 0x0078 (120) KeInterruptTime
|
||||
(uint32)FUNC(&xboxkrnl::KeIsExecutingDpc), // 0x0079 (121)
|
||||
(uint32)FUNC(&xboxkrnl::KeLeaveCriticalRegion), // 0x007A (122)
|
||||
(uint32)FUNC(&xboxkrnl::KePulseEvent), // 0x007B (123)
|
||||
|
@ -209,7 +209,7 @@ uint32 CxbxKrnl_KernelThunkTable[379] =
|
|||
(uint32)FUNC(&xboxkrnl::KeStallExecutionProcessor), // 0x0097 (151)
|
||||
(uint32)FUNC(&xboxkrnl::KeSuspendThread), // 0x0098 (152)
|
||||
(uint32)FUNC(&xboxkrnl::KeSynchronizeExecution), // 0x0099 (153)
|
||||
(uint32)VARIABLE(0x009A), // 0x009A (154) KeSystemTime (Set by ConnectWindowsTimersToThunkTable)
|
||||
(uint32)VARIABLE(&xboxkrnl::KeSystemTime), // 0x009A (154) KeSystemTime
|
||||
(uint32)FUNC(&xboxkrnl::KeTestAlertThread), // 0x009B (155)
|
||||
(uint32)VARIABLE(&xboxkrnl::KeTickCount), // 0x009C (156)
|
||||
(uint32)VARIABLE(&xboxkrnl::KeTimeIncrement), // 0x009D (157)
|
||||
|
@ -435,44 +435,3 @@ uint32 CxbxKrnl_KernelThunkTable[379] =
|
|||
(uint32)FUNC(&xboxkrnl::MmDbgReleaseAddress), // 0x0179 (377) DEVKIT ONLY!
|
||||
(uint32)FUNC(&xboxkrnl::MmDbgWriteCheck), // 0x017A (378) DEVKIT ONLY!
|
||||
};
|
||||
|
||||
/* prevent name collisions */
|
||||
namespace NtDll
|
||||
{
|
||||
#include "core\kernel\support\EmuNtDll.h"
|
||||
};
|
||||
|
||||
// Virtual memory location of KUSER_SHARED_DATA :
|
||||
// See http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/base/md/i386/sim/_pertest2.c.htm
|
||||
// and http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/base/md/i386/sim/_glue.c.htm
|
||||
// and http://processhacker.sourceforge.net/doc/ntexapi_8h_source.html
|
||||
// and http://forum.sysinternals.com/0x7ffe0000-what-is-in-it_topic10012.html
|
||||
#define MM_SHARED_USER_DATA_VA 0x7FFE0000
|
||||
#define USER_SHARED_DATA ((NtDll::KUSER_SHARED_DATA * const)MM_SHARED_USER_DATA_VA)
|
||||
|
||||
// KUSER_SHARED_DATA Offsets
|
||||
// See http://native-nt-toolkit.googlecode.com/svn/trunk/ndk/asm.h
|
||||
// Note : KUSER_SHARED_DATA.TickCountLow seems deprecated
|
||||
const UINT USER_SHARED_DATA_TICK_COUNT = 0x320;
|
||||
|
||||
// Here we define the addresses of the native Windows timers :
|
||||
// Source: Dxbx
|
||||
const xboxkrnl::PKSYSTEM_TIME CxbxNtTickCount = (xboxkrnl::PKSYSTEM_TIME)(MM_SHARED_USER_DATA_VA + USER_SHARED_DATA_TICK_COUNT);
|
||||
|
||||
void ConnectWindowsTimersToThunkTable()
|
||||
{
|
||||
// Couple the xbox thunks for xboxkrnl::KeInterruptTime and xboxkrnl::KeSystemTime
|
||||
// to their actual counterparts on Windows, this way we won't have to spend any
|
||||
// time on updating them ourselves, and still get highly accurate timers!
|
||||
// See http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
|
||||
|
||||
// Point Xbox KeInterruptTime to host InterruptTime:
|
||||
CxbxKrnl_KernelThunkTable[120] = (uint32)&(USER_SHARED_DATA->InterruptTime);
|
||||
|
||||
// Point Xbox KeSystemTime to host SystemTime; If read directly (thus skipping
|
||||
// KeQuerySystemTime), this value is not adjusted with HostSystemTimeDelta!
|
||||
CxbxKrnl_KernelThunkTable[154] = (uint32)&(USER_SHARED_DATA->SystemTime);
|
||||
|
||||
// We can't point Xbox KeTickCount to host TickCount, because it
|
||||
// updates slower on the xbox. See EmuUpdateTickCount().
|
||||
}
|
||||
|
|
|
@ -1247,9 +1247,6 @@ void CxbxKrnlMain(int argc, char* argv[])
|
|||
// Restore enough of the executable image headers to keep WinAPI's working :
|
||||
RestoreExeImageHeader();
|
||||
}
|
||||
|
||||
// Before readout, make sure our kernel thunk table references the Windows host timer addresses :
|
||||
ConnectWindowsTimersToThunkTable();
|
||||
|
||||
// Decode kernel thunk table address :
|
||||
uint32_t kt = CxbxKrnl_Xbe->m_Header.dwKernelImageThunkAddr;
|
||||
|
|
|
@ -266,8 +266,6 @@ void CxbxInitPerformanceCounters(); // Implemented in EmuKrnlKe.cpp
|
|||
|
||||
void CxbxInitFilePaths();
|
||||
|
||||
void ConnectWindowsTimersToThunkTable();
|
||||
|
||||
/*! Generate a standard arg format string */
|
||||
void CxbxConvertArgToString(std::string &dest, const char* krnlExe, const char* xbeFile, HWND hwndParent, DebugMode krnlDebug, const char* krnlDebugFile);
|
||||
|
||||
|
|
Loading…
Reference in New Issue