Implement KeSetTimerEx (in progress)
This commit is contained in:
parent
0fc2a7c3b2
commit
3f50f6de29
|
@ -897,7 +897,9 @@ XBSYSAPI EXPORTNUM(113) xboxkrnl::VOID NTAPI xboxkrnl::KeInitializeTimerEx
|
|||
LOG_FUNC_BEGIN
|
||||
LOG_FUNC_ARG(Timer)
|
||||
LOG_FUNC_ARG(Type)
|
||||
LOG_FUNC_END;
|
||||
LOG_FUNC_END;
|
||||
|
||||
assert(Timer);
|
||||
|
||||
// Initialize header :
|
||||
Timer->Header.Type = Type + TimerNotificationObject;
|
||||
|
@ -1742,45 +1744,53 @@ XBSYSAPI EXPORTNUM(150) xboxkrnl::BOOLEAN NTAPI xboxkrnl::KeSetTimerEx
|
|||
LOG_FUNC_ARG(DueTime)
|
||||
LOG_FUNC_ARG(Period)
|
||||
LOG_FUNC_ARG(Dpc)
|
||||
LOG_FUNC_END;
|
||||
LOG_FUNC_END;
|
||||
|
||||
BOOLEAN Inserted;
|
||||
BOOLEAN Inserted;
|
||||
BOOLEAN RequestInterrupt = FALSE;
|
||||
LARGE_INTEGER Interval;
|
||||
LARGE_INTEGER SystemTime;
|
||||
|
||||
if (Timer->Header.Type != TimerNotificationObject && Timer->Header.Type != TimerSynchronizationObject) {
|
||||
CxbxKrnlCleanup("Assertion: '(Timer)->Header.Type == TimerNotificationObject) || ((Timer)->Header.Type == TimerSynchronizationObject)' in KeSetTimerEx()");
|
||||
}
|
||||
LARGE_INTEGER SystemTime;
|
||||
KIRQL OldIrql;
|
||||
ULONG Hand;
|
||||
|
||||
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) :
|
||||
Inserted = Timer->Header.Inserted;
|
||||
if (Inserted != FALSE) {
|
||||
// Do some unlinking if already inserted in the linked list
|
||||
KiRemoveTreeTimer(Timer);
|
||||
KxRemoveTreeTimer(Timer);
|
||||
}
|
||||
|
||||
/* Set Default Timer Data */
|
||||
Timer->Dpc = Dpc;
|
||||
Timer->Period = Period;
|
||||
if (!KiComputeDueTime(Timer, DueTime, &Hand))
|
||||
{
|
||||
/* Signal the timer */
|
||||
RequestInterrupt = KiSignalTimer(Timer);
|
||||
|
||||
/* Release the dispatcher lock */
|
||||
KiReleaseDispatcherLockFromDpcLevel();
|
||||
|
||||
/* Check if we need to do an interrupt */
|
||||
if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Insert the timer */
|
||||
Timer->Header.SignalState = FALSE;
|
||||
KxInsertTimer(Timer, Hand);
|
||||
}
|
||||
|
||||
/* Exit the dispatcher */
|
||||
KiExitDispatcher(OldIrql);
|
||||
|
||||
Timer->Header.SignalState = FALSE;
|
||||
Timer->Dpc = Dpc;
|
||||
Timer->Period = Period;
|
||||
|
||||
if (!KiInsertTreeTimer(Timer, DueTime)) {
|
||||
if (!IsListEmpty(&(Timer->Header.WaitListHead))) {
|
||||
// KiWaitTest(Timer, 0);
|
||||
}
|
||||
|
||||
if (Dpc != NULL) {
|
||||
// Call the Dpc routine if one is specified
|
||||
KeQuerySystemTime(&SystemTime);
|
||||
KeInsertQueueDpc(Timer->Dpc, (PVOID)SystemTime.u.LowPart, (PVOID)SystemTime.u.HighPart);
|
||||
}
|
||||
|
||||
if (Period != 0) {
|
||||
// Prepare the repetition if Timer is periodic
|
||||
Interval.QuadPart = (LONGLONG)(-10 * 1000) * Timer->Period;
|
||||
while (!KiInsertTreeTimer(Timer, Interval))
|
||||
;
|
||||
}
|
||||
}
|
||||
/* Dxbx has this :
|
||||
EnterCriticalSection(&(g_DpcData.Lock));
|
||||
if (Timer->TimerListEntry.Flink == nullptr)
|
||||
|
|
|
@ -33,7 +33,13 @@
|
|||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
// ******************************************************************
|
||||
|
||||
// Acknowledgment: ReactOS (GPLv2)
|
||||
// https://github.com/reactos/reactos
|
||||
|
||||
// Changed from ReactOS: slight changes to the Hand parameter usage
|
||||
|
||||
#define _XBOXKRNL_DEFEXTRN_
|
||||
|
||||
#define LOG_PREFIX CXBXR_MODULE::KI
|
||||
|
@ -46,46 +52,94 @@ namespace xboxkrnl
|
|||
|
||||
#include "Logging.h" // For LOG_FUNC()
|
||||
#include "EmuKrnlLogging.h"
|
||||
|
||||
//#include "EmuKrnl.h" // For InitializeListHead(), etc.
|
||||
|
||||
xboxkrnl::BOOLEAN KiInsertTimerTable(
|
||||
IN xboxkrnl::LARGE_INTEGER Interval,
|
||||
xboxkrnl::ULONGLONG,
|
||||
IN xboxkrnl::PKTIMER Timer
|
||||
)
|
||||
{
|
||||
// TODO
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
xboxkrnl::BOOLEAN KiInsertTreeTimer(
|
||||
IN xboxkrnl::PKTIMER Timer,
|
||||
IN xboxkrnl::LARGE_INTEGER Interval
|
||||
)
|
||||
{
|
||||
// Is the given time absolute (indicated by a positive number)?
|
||||
if (Interval.u.HighPart >= 0) {
|
||||
// Convert absolute time to a time relative to the system time :
|
||||
xboxkrnl::LARGE_INTEGER SystemTime;
|
||||
xboxkrnl::KeQuerySystemTime(&SystemTime);
|
||||
Interval.QuadPart = SystemTime.QuadPart - Interval.QuadPart;
|
||||
if (Interval.u.HighPart >= 0) {
|
||||
// If the relative time is already passed, return without inserting :
|
||||
Timer->Header.Inserted = FALSE;
|
||||
Timer->Header.SignalState = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Timer->Header.Absolute = TRUE;
|
||||
}
|
||||
else
|
||||
// Negative intervals are relative, not absolute :
|
||||
Timer->Header.Absolute = FALSE;
|
||||
|
||||
if (Timer->Period == 0)
|
||||
Timer->Header.SignalState = FALSE;
|
||||
|
||||
Timer->Header.Inserted = TRUE;
|
||||
return KiInsertTimerTable(Interval, xboxkrnl::KeQueryInterruptTime(), Timer);
|
||||
}
|
||||
#include "EmuKrnlKi.h"
|
||||
|
||||
// ReactOS uses a size of 512, but disassembling the kernel reveals it to be 32 instead
|
||||
#define TIMER_TABLE_SIZE 32
|
||||
|
||||
xboxkrnl::KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE];
|
||||
|
||||
|
||||
xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTreeTimer(
|
||||
IN xboxkrnl::PKTIMER Timer,
|
||||
IN xboxkrnl::LARGE_INTEGER Interval
|
||||
)
|
||||
{
|
||||
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))
|
||||
{
|
||||
/* Insert the timer */
|
||||
if (KiInsertTimerTable(Timer, Hand))
|
||||
{
|
||||
/* It was already there, remove it */
|
||||
KiRemoveEntryTimer(Timer);
|
||||
Timer->Header.Inserted = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, we're now inserted */
|
||||
Inserted = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the lock and return insert status */
|
||||
return Inserted;
|
||||
}
|
||||
|
||||
xboxkrnl::ULONG xboxkrnl::KiComputeTimerTableIndex(
|
||||
IN xboxkrnl::ULONGLONG Interval
|
||||
)
|
||||
{
|
||||
return (Interval / KeMaximumIncrement) & (TIMER_TABLE_SIZE - 1);
|
||||
}
|
||||
|
||||
xboxkrnl::BOOLEAN xboxkrnl::KiComputeDueTime(
|
||||
IN xboxkrnl::PKTIMER Timer,
|
||||
IN xboxkrnl::LARGE_INTEGER DueTime,
|
||||
OUT xboxkrnl::PULONG Hand)
|
||||
{
|
||||
LARGE_INTEGER InterruptTime, SystemTime, DifferenceTime;
|
||||
|
||||
/* Convert to relative time if needed */
|
||||
Timer->Header.Absolute = FALSE;
|
||||
if (DueTime.u.HighPart >= 0)
|
||||
{
|
||||
/* Get System Time */
|
||||
KeQuerySystemTime(&SystemTime);
|
||||
|
||||
/* Do the conversion */
|
||||
DifferenceTime.QuadPart = SystemTime.QuadPart - DueTime.QuadPart;
|
||||
|
||||
/* Make sure it hasn't already expired */
|
||||
Timer->Header.Absolute = TRUE;
|
||||
if (DifferenceTime.u.HighPart >= 0)
|
||||
{
|
||||
/* Cancel everything */
|
||||
DBG_PRINTF("Timer %p already expired\n", Timer);
|
||||
Timer->Header.SignalState = TRUE;
|
||||
Timer->DueTime.QuadPart = 0;
|
||||
*Hand = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Set the time as Absolute */
|
||||
DueTime = DifferenceTime;
|
||||
}
|
||||
|
||||
/* Get the Interrupt Time */
|
||||
InterruptTime.QuadPart = KeQueryInterruptTime();
|
||||
|
||||
/* Recalculate due time */
|
||||
Timer->DueTime.QuadPart = InterruptTime.QuadPart - DueTime.QuadPart;
|
||||
|
||||
/* Get the handle */
|
||||
*Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
|
||||
Timer->Header.Inserted = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,9 @@
|
|||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace xboxkrnl
|
||||
{
|
||||
#define KiLockDispatcherDatabase(OldIrql) \
|
||||
*(OldIrql) = KeRaiseIrqlToDpcLevel()
|
||||
|
||||
|
@ -44,9 +46,22 @@
|
|||
|
||||
#define KiRemoveTreeTimer(Timer) \
|
||||
(Timer)->Header.Inserted = FALSE; \
|
||||
RemoveEntryList(&(Timer)->TimerListEntry)
|
||||
RemoveEntryList(&(Timer)->TimerListEntry)
|
||||
|
||||
typedef struct _KTIMER_TABLE_ENTRY
|
||||
{
|
||||
LIST_ENTRY Entry;
|
||||
ULARGE_INTEGER Time;
|
||||
} KTIMER_TABLE_ENTRY, *PKTIMER_TABLE_ENTRY;
|
||||
|
||||
xboxkrnl::BOOLEAN KiInsertTreeTimer(
|
||||
IN xboxkrnl::PKTIMER Timer,
|
||||
IN xboxkrnl::LARGE_INTEGER Interval
|
||||
);
|
||||
BOOLEAN FASTCALL KiInsertTreeTimer(
|
||||
IN PKTIMER Timer,
|
||||
IN LARGE_INTEGER Interval
|
||||
);
|
||||
|
||||
BOOLEAN KiComputeDueTime(
|
||||
IN PKTIMER Timer,
|
||||
IN LARGE_INTEGER DueTime,
|
||||
OUT PULONG Hand
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue