Completed KeSetTimerEx
This commit is contained in:
parent
3f50f6de29
commit
b6fce711a9
|
@ -97,18 +97,21 @@ void InsertTailList(xboxkrnl::PLIST_ENTRY pListHead, xboxkrnl::PLIST_ENTRY pEntr
|
|||
|
||||
//#define RemoveEntryList(e) do { PLIST_ENTRY f = (e)->Flink, b = (e)->Blink; f->Blink = b; b->Flink = f; (e)->Flink = (e)->Blink = NULL; } while (0)
|
||||
|
||||
void RemoveEntryList(xboxkrnl::PLIST_ENTRY pEntry)
|
||||
// Returns TRUE if the list has become empty after removing the element, FALSE otherwise.
|
||||
xboxkrnl::BOOLEAN RemoveEntryList(xboxkrnl::PLIST_ENTRY pEntry)
|
||||
{
|
||||
xboxkrnl::PLIST_ENTRY _EX_Flink = pEntry->Flink;
|
||||
xboxkrnl::PLIST_ENTRY _EX_Blink = pEntry->Blink;
|
||||
|
||||
if (_EX_Flink != nullptr) {
|
||||
if (_EX_Blink != nullptr) {
|
||||
_EX_Blink->Flink = _EX_Flink;
|
||||
}
|
||||
|
||||
if (_EX_Flink != nullptr) {
|
||||
_EX_Flink->Blink = _EX_Blink;
|
||||
}
|
||||
|
||||
return (_EX_Flink == _EX_Blink);
|
||||
}
|
||||
|
||||
xboxkrnl::PLIST_ENTRY RemoveHeadList(xboxkrnl::PLIST_ENTRY pListHead)
|
||||
|
|
|
@ -52,7 +52,7 @@ void InsertHeadList(xboxkrnl::PLIST_ENTRY pListHead, xboxkrnl::PLIST_ENTRY pEntr
|
|||
void InsertTailList(xboxkrnl::PLIST_ENTRY pListHead, xboxkrnl::PLIST_ENTRY pEntry);
|
||||
//#define RemoveEntryList(e) do { PLIST_ENTRY f = (e)->Flink, b = (e)->Blink; f->Blink = b; b->Flink = f; (e)->Flink = (e)->Blink = NULL; } while (0)
|
||||
|
||||
void RemoveEntryList(xboxkrnl::PLIST_ENTRY pEntry);
|
||||
xboxkrnl::BOOLEAN RemoveEntryList(xboxkrnl::PLIST_ENTRY pEntry);
|
||||
xboxkrnl::PLIST_ENTRY RemoveHeadList(xboxkrnl::PLIST_ENTRY pListHead);
|
||||
xboxkrnl::PLIST_ENTRY RemoveTailList(xboxkrnl::PLIST_ENTRY pListHead);
|
||||
|
||||
|
|
|
@ -1756,8 +1756,6 @@ XBSYSAPI EXPORTNUM(150) xboxkrnl::BOOLEAN NTAPI xboxkrnl::KeSetTimerEx
|
|||
assert(Timer);
|
||||
assert(Timer->Header.Type == TimerNotificationObject || Timer->Header.Type == TimerSynchronizationObject);
|
||||
|
||||
// NOTE: in ReactOS, this function raises the irql to SYNCH_LEVEL and it's a nop in single-cpu systems. I disassembled the function
|
||||
// from my kernel dump and saw that it calls KeRaiseIrqlToDpcLevel
|
||||
KiLockDispatcherDatabase(&OldIrql);
|
||||
|
||||
// Same as KeCancelTimer(Timer) :
|
||||
|
@ -1775,11 +1773,10 @@ XBSYSAPI EXPORTNUM(150) xboxkrnl::BOOLEAN NTAPI xboxkrnl::KeSetTimerEx
|
|||
/* Signal the timer */
|
||||
RequestInterrupt = KiSignalTimer(Timer);
|
||||
|
||||
/* Release the dispatcher lock */
|
||||
KiReleaseDispatcherLockFromDpcLevel();
|
||||
|
||||
/* Check if we need to do an interrupt */
|
||||
if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
if (RequestInterrupt) {
|
||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1789,7 +1786,7 @@ XBSYSAPI EXPORTNUM(150) xboxkrnl::BOOLEAN NTAPI xboxkrnl::KeSetTimerEx
|
|||
}
|
||||
|
||||
/* Exit the dispatcher */
|
||||
KiExitDispatcher(OldIrql);
|
||||
KiUnlockDispatcherDatabase(OldIrql);
|
||||
|
||||
/* Dxbx has this :
|
||||
EnterCriticalSection(&(g_DpcData.Lock));
|
||||
|
@ -1893,8 +1890,6 @@ XBSYSAPI EXPORTNUM(155) xboxkrnl::BOOLEAN NTAPI xboxkrnl::KeTestAlertThread
|
|||
// ******************************************************************
|
||||
XBSYSAPI EXPORTNUM(156) xboxkrnl::DWORD VOLATILE xboxkrnl::KeTickCount = 0;
|
||||
|
||||
const xboxkrnl::ULONG CLOCK_TIME_INCREMENT = 0x2710;
|
||||
|
||||
// ******************************************************************
|
||||
// * 0x009D - KeTimeIncrement
|
||||
// ******************************************************************
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace xboxkrnl
|
|||
};
|
||||
|
||||
#include "Logging.h" // For LOG_FUNC()
|
||||
#include "EmuKrnlLogging.h"
|
||||
#include "EmuKrnl.h" // for the list support functions
|
||||
#include "EmuKrnlKi.h"
|
||||
|
||||
// ReactOS uses a size of 512, but disassembling the kernel reveals it to be 32 instead
|
||||
|
@ -60,6 +60,123 @@ namespace xboxkrnl
|
|||
xboxkrnl::KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE];
|
||||
|
||||
|
||||
VOID xboxkrnl::KxInsertTimer(
|
||||
IN xboxkrnl::PKTIMER Timer,
|
||||
IN xboxkrnl::ULONG Hand
|
||||
)
|
||||
{
|
||||
/* Try to insert the timer */
|
||||
if (KiInsertTimerTable(Timer, Hand))
|
||||
{
|
||||
/* Complete it */
|
||||
KiCompleteTimer(Timer, Hand);
|
||||
}
|
||||
}
|
||||
|
||||
VOID FASTCALL xboxkrnl::KiCompleteTimer(
|
||||
IN xboxkrnl::PKTIMER Timer,
|
||||
IN xboxkrnl::ULONG Hand
|
||||
)
|
||||
{
|
||||
LIST_ENTRY ListHead;
|
||||
BOOLEAN RequestInterrupt = FALSE;
|
||||
|
||||
/* Remove it from the timer list */
|
||||
KiRemoveEntryTimer(Timer, Hand);
|
||||
|
||||
/* Link the timer list to our stack */
|
||||
ListHead.Flink = &Timer->TimerListEntry;
|
||||
ListHead.Blink = &Timer->TimerListEntry;
|
||||
Timer->TimerListEntry.Flink = &ListHead;
|
||||
Timer->TimerListEntry.Blink = &ListHead;
|
||||
|
||||
/* Signal the timer if it's still on our list */
|
||||
if (!IsListEmpty(&ListHead)) {
|
||||
RequestInterrupt = KiSignalTimer(Timer);
|
||||
}
|
||||
|
||||
/* Request a DPC if needed */
|
||||
if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
}
|
||||
|
||||
VOID xboxkrnl::KiRemoveEntryTimer(
|
||||
IN xboxkrnl::PKTIMER Timer,
|
||||
IN xboxkrnl::ULONG Hand
|
||||
)
|
||||
{
|
||||
ULONG Hand;
|
||||
PKTIMER_TABLE_ENTRY TableEntry;
|
||||
|
||||
/* Remove the timer from the timer list and check if it's empty */
|
||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
||||
{
|
||||
/* Get the respective timer table entry */
|
||||
TableEntry = &KiTimerTableListHead[Hand];
|
||||
if (&TableEntry->Entry == TableEntry->Entry.Flink)
|
||||
{
|
||||
/* Set the entry to an infinite absolute time */
|
||||
TableEntry->Time.u.HighPart = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the list entries so we can tell the timer is gone */
|
||||
Timer->TimerListEntry.Flink = NULL;
|
||||
Timer->TimerListEntry.Blink = NULL;
|
||||
}
|
||||
|
||||
xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTimerTable(
|
||||
IN xboxkrnl::PKTIMER Timer,
|
||||
IN xboxkrnl::ULONG Hand
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER InterruptTime;
|
||||
LONGLONG DueTime = Timer->DueTime.QuadPart;
|
||||
BOOLEAN Expired = FALSE;
|
||||
PLIST_ENTRY ListHead, NextEntry;
|
||||
PKTIMER CurrentTimer;
|
||||
|
||||
DBG_PRINTF("%s: inserting Timer %p, Hand: %lu\n", __func__, Timer, Hand);
|
||||
|
||||
/* Check if the period is zero */
|
||||
if (!Timer->Period) {
|
||||
Timer->Header.SignalState = FALSE;
|
||||
}
|
||||
|
||||
/* Loop the timer list backwards */
|
||||
ListHead = &KiTimerTableListHead[Hand].Entry;
|
||||
NextEntry = ListHead->Blink;
|
||||
while (NextEntry != ListHead)
|
||||
{
|
||||
/* Get the timer */
|
||||
CurrentTimer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
|
||||
|
||||
/* Now check if we can fit it before */
|
||||
if ((ULONGLONG)DueTime >= CurrentTimer->DueTime.QuadPart) break;
|
||||
|
||||
/* Keep looping */
|
||||
NextEntry = NextEntry->Blink;
|
||||
}
|
||||
|
||||
/* Looped all the list, insert it here and get the interrupt time again */
|
||||
InsertHeadList(NextEntry, &Timer->TimerListEntry);
|
||||
|
||||
/* Check if we didn't find it in the list */
|
||||
if (NextEntry == ListHead)
|
||||
{
|
||||
/* Set the time */
|
||||
KiTimerTableListHead[Hand].Time.QuadPart = DueTime;
|
||||
|
||||
/* Make sure it hasn't expired already */
|
||||
InterruptTime.QuadPart = KeQueryInterruptTime();
|
||||
if (DueTime <= InterruptTime.QuadPart) {
|
||||
Expired = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return expired state */
|
||||
return Expired;
|
||||
}
|
||||
|
||||
xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTreeTimer(
|
||||
IN xboxkrnl::PKTIMER Timer,
|
||||
IN xboxkrnl::LARGE_INTEGER Interval
|
||||
|
@ -68,9 +185,6 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTreeTimer(
|
|||
BOOLEAN Inserted = FALSE;
|
||||
ULONG Hand = 0;
|
||||
|
||||
/* This should only be called at dpc level */
|
||||
assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||||
|
||||
/* Setup the timer's due time */
|
||||
if (KiComputeDueTime(Timer, Interval, &Hand))
|
||||
{
|
||||
|
@ -78,7 +192,7 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTreeTimer(
|
|||
if (KiInsertTimerTable(Timer, Hand))
|
||||
{
|
||||
/* It was already there, remove it */
|
||||
KiRemoveEntryTimer(Timer);
|
||||
KiRemoveEntryTimer(Timer, Hand);
|
||||
Timer->Header.Inserted = FALSE;
|
||||
}
|
||||
else
|
||||
|
@ -88,7 +202,6 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTreeTimer(
|
|||
}
|
||||
}
|
||||
|
||||
/* Release the lock and return insert status */
|
||||
return Inserted;
|
||||
}
|
||||
|
||||
|
@ -96,7 +209,7 @@ xboxkrnl::ULONG xboxkrnl::KiComputeTimerTableIndex(
|
|||
IN xboxkrnl::ULONGLONG Interval
|
||||
)
|
||||
{
|
||||
return (Interval / KeMaximumIncrement) & (TIMER_TABLE_SIZE - 1);
|
||||
return (Interval / CLOCK_TIME_INCREMENT) & (TIMER_TABLE_SIZE - 1);
|
||||
}
|
||||
|
||||
xboxkrnl::BOOLEAN xboxkrnl::KiComputeDueTime(
|
||||
|
@ -143,3 +256,78 @@ xboxkrnl::BOOLEAN xboxkrnl::KiComputeDueTime(
|
|||
Timer->Header.Inserted = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiSignalTimer(
|
||||
IN xboxkrnl::PKTIMER Timer
|
||||
)
|
||||
{
|
||||
BOOLEAN RequestInterrupt = FALSE;
|
||||
PKDPC Dpc = Timer->Dpc;
|
||||
ULONG Period = Timer->Period;
|
||||
LARGE_INTEGER Interval, SystemTime;
|
||||
|
||||
/* Set default values */
|
||||
Timer->Header.Inserted = FALSE;
|
||||
Timer->Header.SignalState = TRUE;
|
||||
|
||||
/* Check if the timer has waiters */
|
||||
if (!IsListEmpty(&Timer->Header.WaitListHead))
|
||||
{
|
||||
/* Check the type of event */
|
||||
if (Timer->Header.Type == TimerNotificationObject)
|
||||
{
|
||||
/* Unwait the thread */
|
||||
//KxUnwaitThread(&Timer->Header, IO_NO_INCREMENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise unwait the thread and signal the timer */
|
||||
//KxUnwaitThreadForEvent((PKEVENT)Timer, IO_NO_INCREMENT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we have a period */
|
||||
if (Period)
|
||||
{
|
||||
/* Calculate the interval and insert the timer */
|
||||
Interval.QuadPart = Int32x32To64(Period, -10000);
|
||||
while (!KiInsertTreeTimer(Timer, Interval));
|
||||
}
|
||||
|
||||
/* Check if we have a DPC */
|
||||
if (Dpc)
|
||||
{
|
||||
/* Insert it in the queue */
|
||||
KeQuerySystemTime(&SystemTime);
|
||||
KeInsertQueueDpc(Dpc,
|
||||
ULongToPtr(SystemTime.u.LowPart),
|
||||
ULongToPtr(SystemTime.u.HighPart));
|
||||
RequestInterrupt = TRUE;
|
||||
}
|
||||
|
||||
/* Return whether we need to request a DPC interrupt or not */
|
||||
return RequestInterrupt;
|
||||
}
|
||||
|
||||
VOID xboxkrnl::KxRemoveTreeTimer(
|
||||
IN xboxkrnl::PKTIMER Timer
|
||||
)
|
||||
{
|
||||
ULONG Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
|
||||
PKTIMER_TABLE_ENTRY TimerEntry;
|
||||
|
||||
/* Set the timer as non-inserted */
|
||||
Timer->Header.Inserted = FALSE;
|
||||
|
||||
/* Remove it from the timer list */
|
||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
||||
{
|
||||
/* Get the entry and check if it's empty */
|
||||
TimerEntry = &KiTimerTableListHead[Hand];
|
||||
if (IsListEmpty(&TimerEntry->Entry))
|
||||
{
|
||||
/* Clear the time then */
|
||||
TimerEntry->Time.u.HighPart = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,8 +33,6 @@
|
|||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
namespace xboxkrnl
|
||||
{
|
||||
#define KiLockDispatcherDatabase(OldIrql) \
|
||||
*(OldIrql) = KeRaiseIrqlToDpcLevel()
|
||||
|
||||
|
@ -48,20 +46,56 @@ namespace xboxkrnl
|
|||
(Timer)->Header.Inserted = FALSE; \
|
||||
RemoveEntryList(&(Timer)->TimerListEntry)
|
||||
|
||||
namespace xboxkrnl
|
||||
{
|
||||
typedef struct _KTIMER_TABLE_ENTRY
|
||||
{
|
||||
LIST_ENTRY Entry;
|
||||
ULARGE_INTEGER Time;
|
||||
} KTIMER_TABLE_ENTRY, *PKTIMER_TABLE_ENTRY;
|
||||
|
||||
const ULONG CLOCK_TIME_INCREMENT = 0x2710;
|
||||
|
||||
VOID KxInsertTimer(
|
||||
IN PKTIMER Timer,
|
||||
IN ULONG Hand
|
||||
);
|
||||
|
||||
VOID FASTCALL KiCompleteTimer(
|
||||
IN PKTIMER Timer,
|
||||
IN ULONG Hand
|
||||
);
|
||||
|
||||
VOID KiRemoveEntryTimer(
|
||||
IN PKTIMER Timer,
|
||||
IN ULONG Hand
|
||||
);
|
||||
|
||||
BOOLEAN FASTCALL KiInsertTimerTable(
|
||||
IN PKTIMER Timer,
|
||||
IN ULONG Hand
|
||||
);
|
||||
|
||||
BOOLEAN FASTCALL KiInsertTreeTimer(
|
||||
IN PKTIMER Timer,
|
||||
IN LARGE_INTEGER Interval
|
||||
);
|
||||
|
||||
ULONG KiComputeTimerTableIndex(
|
||||
IN ULONGLONG Interval
|
||||
);
|
||||
|
||||
BOOLEAN KiComputeDueTime(
|
||||
IN PKTIMER Timer,
|
||||
IN LARGE_INTEGER DueTime,
|
||||
OUT PULONG Hand
|
||||
);
|
||||
|
||||
BOOLEAN FASTCALL KiSignalTimer(
|
||||
IN PKTIMER Timer
|
||||
);
|
||||
|
||||
VOID KxRemoveTreeTimer(
|
||||
IN PKTIMER Timer
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue