Fix a deadlock in KiTimerExpiration caused by KeWaitForSingleObject

This also fixes LLE USB not working for homebrews
This commit is contained in:
ergo720 2019-03-30 18:06:11 +01:00
parent f58d3ce6cf
commit 9270091d99
7 changed files with 201 additions and 78 deletions

View File

@ -1580,6 +1580,7 @@ typedef enum _KOBJECTS
MutantObject = 2, MutantObject = 2,
QueueObject = 4, QueueObject = 4,
SemaphoreObject = 5, SemaphoreObject = 5,
ThreadObject = 6,
TimerNotificationObject = 8, TimerNotificationObject = 8,
TimerSynchronizationObject = 9, TimerSynchronizationObject = 9,
ApcObject = 0x12, ApcObject = 0x12,
@ -1961,7 +1962,7 @@ typedef struct _KTHREAD
/* 0x55/85 */ CHAR WaitMode; /* 0x55/85 */ CHAR WaitMode;
/* 0x56/86 */ CHAR WaitNext; /* 0x56/86 */ CHAR WaitNext;
/* 0x57/87 */ CHAR WaitReason; /* 0x57/87 */ CHAR WaitReason;
/* 0x58/88 */ PVOID WaitBlockList; /* 0x58/88 */ PKWAIT_BLOCK WaitBlockList;
/* 0x5C/92 */ LIST_ENTRY WaitListEntry; /* 0x5C/92 */ LIST_ENTRY WaitListEntry;
/* 0x64/100 */ ULONG WaitTime; /* 0x64/100 */ ULONG WaitTime;
/* 0x68/104 */ ULONG KernelApcDisable; /* 0x68/104 */ ULONG KernelApcDisable;

View File

@ -102,8 +102,13 @@ xboxkrnl::BOOLEAN RemoveEntryList(xboxkrnl::PLIST_ENTRY pEntry)
_EX_Flink->Blink = _EX_Blink; _EX_Flink->Blink = _EX_Blink;
} }
if (_EX_Blink != nullptr && _EX_Flink != nullptr) {
return (_EX_Flink == _EX_Blink); return (_EX_Flink == _EX_Blink);
} }
// If we reach here then it means we have erroneously been called on a detached element. In this case,
// always report FALSE to avoid possible side effects
return FALSE;
}
xboxkrnl::PLIST_ENTRY RemoveHeadList(xboxkrnl::PLIST_ENTRY pListHead) xboxkrnl::PLIST_ENTRY RemoveHeadList(xboxkrnl::PLIST_ENTRY pListHead)
{ {

View File

@ -165,7 +165,8 @@ xboxkrnl::KPRCB *KeGetCurrentPrcb()
// ****************************************************************** // ******************************************************************
// * KeSetSystemTime() // * KeSetSystemTime()
// ****************************************************************** // ******************************************************************
xboxkrnl::VOID NTAPI xboxkrnl::KeSetSystemTime( xboxkrnl::VOID NTAPI xboxkrnl::KeSetSystemTime
(
IN xboxkrnl::PLARGE_INTEGER NewTime, IN xboxkrnl::PLARGE_INTEGER NewTime,
OUT xboxkrnl::PLARGE_INTEGER OldTime OUT xboxkrnl::PLARGE_INTEGER OldTime
) )
@ -255,6 +256,19 @@ xboxkrnl::VOID NTAPI xboxkrnl::KeSetSystemTime(
KiTimerListExpire(&TempList2, OldIrql); KiTimerListExpire(&TempList2, OldIrql);
} }
// ******************************************************************
// * KeInitializeTimer()
// ******************************************************************
xboxkrnl::VOID NTAPI xboxkrnl::KeInitializeTimer
(
IN PKTIMER Timer
)
{
LOG_FORWARD("KeInitializeTimerEx");
KeInitializeTimerEx(Timer, NotificationTimer);
}
// Forward KeLowerIrql() to KfLowerIrql() // Forward KeLowerIrql() to KfLowerIrql()
#define KeLowerIrql(NewIrql) \ #define KeLowerIrql(NewIrql) \
KfLowerIrql(NewIrql) KfLowerIrql(NewIrql)
@ -1923,6 +1937,8 @@ XBSYSAPI EXPORTNUM(158) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForMultipleObje
BOOLEAN WaitSatisfied; BOOLEAN WaitSatisfied;
NTSTATUS WaitStatus; NTSTATUS WaitStatus;
PKMUTANT ObjectMutant; PKMUTANT ObjectMutant;
// Hack variable (remove this when the thread scheduler is here)
bool timeout_set = false;
do { do {
// Check if we need to let an APC run. This should immediately trigger APC interrupt via a call to UnlockDispatcherDatabase // Check if we need to let an APC run. This should immediately trigger APC interrupt via a call to UnlockDispatcherDatabase
if (Thread->ApcState.KernelApcPending && (Thread->WaitIrql < APC_LEVEL)) { if (Thread->ApcState.KernelApcPending && (Thread->WaitIrql < APC_LEVEL)) {
@ -1997,7 +2013,8 @@ XBSYSAPI EXPORTNUM(158) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForMultipleObje
goto NoWait; goto NoWait;
} }
// Setup a timer for the thread // Setup a timer for the thread but only once (for now)
if (!timeout_set) {
KiTimerLock(); KiTimerLock();
PKTIMER Timer = &Thread->Timer; PKTIMER Timer = &Thread->Timer;
PKWAIT_BLOCK WaitTimer = &Thread->TimerWaitBlock; PKWAIT_BLOCK WaitTimer = &Thread->TimerWaitBlock;
@ -2011,9 +2028,22 @@ XBSYSAPI EXPORTNUM(158) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForMultipleObje
goto NoWait; goto NoWait;
} }
// Boring, ensure that we only set the thread timer once. Otherwise, this will cause to insert the same
// thread timer over and over in the timer list, which will prevent KiTimerExpiration from removing these
// duplicated timers and thus it will attempt to endlessly remove the same unremoved timers, causing a deadlock.
// This can be removed once KiSwapThread and the kernel/user APCs are implemented
timeout_set = true;
DueTime.QuadPart = Timer->DueTime.QuadPart; DueTime.QuadPart = Timer->DueTime.QuadPart;
KiTimerUnlock(); KiTimerUnlock();
} }
// KiTimerExpiration has removed the timer but the objects were not signaled, so we have a timeout
// (remove this when the thread scheduler is here)
if (Thread->Timer.Header.Inserted == FALSE) {
WaitStatus = (NTSTATUS)(STATUS_TIMEOUT);
goto NoWait;
}
}
else { else {
WaitBlock->NextWaitBlock = WaitBlock; WaitBlock->NextWaitBlock = WaitBlock;
} }
@ -2028,9 +2058,9 @@ XBSYSAPI EXPORTNUM(158) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForMultipleObje
/* /*
TODO: We can't implement this and the return values until we have our own thread schedular TODO: We can't implement this and the return values until we have our own thread scheduler
For now, we'll have to implement waiting here instead of the schedular. For now, we'll have to implement waiting here instead of the scheduler.
This code can all be enabled once we have CPU emulation and our own schedular in v1.0 This code can all be enabled once we have CPU emulation and our own scheduler in v1.0
*/ */
// Insert the WaitBlock // Insert the WaitBlock
@ -2061,7 +2091,7 @@ XBSYSAPI EXPORTNUM(158) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForMultipleObje
// return WaitStatus; // return WaitStatus;
//} //}
// TODO: Remove this after we have our own schedular and the above is implemented // TODO: Remove this after we have our own scheduler and the above is implemented
Sleep(0); Sleep(0);
// Reduce the timout if necessary // Reduce the timout if necessary
@ -2076,6 +2106,10 @@ XBSYSAPI EXPORTNUM(158) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForMultipleObje
} }
} while (TRUE); } while (TRUE);
// NOTE: we don't need to remove the wait blocks for the object and/or the timer because InsertTailList is disabled at
// the moment, which means they are never attached to the object wait list. TimerWaitBlock can also stay attached to the timer wait
// list since KiTimerExpiration disregards it for now.
// The waiting thead has been alerted, or an APC needs to be delivered // The waiting thead has been alerted, or an APC needs to be delivered
// So unlock the dispatcher database, lower the IRQ and return the status // So unlock the dispatcher database, lower the IRQ and return the status
KiUnlockDispatcherDatabase(Thread->WaitIrql); KiUnlockDispatcherDatabase(Thread->WaitIrql);
@ -2090,6 +2124,14 @@ NoWait:
// Unlock the database and return the status // Unlock the database and return the status
//TODO: KiAdjustQuantumThread(Thread); //TODO: KiAdjustQuantumThread(Thread);
// Don't forget to remove the thread timer if the objects were signaled before the timer expired
// (remove this when the thread scheduler is here)
if (timeout_set && Thread->Timer.Header.Inserted == TRUE) {
KiTimerLock();
KxRemoveTreeTimer(&Thread->Timer);
KiTimerUnlock();
}
KiUnlockDispatcherDatabase(Thread->WaitIrql); KiUnlockDispatcherDatabase(Thread->WaitIrql);
if (WaitStatus == STATUS_USER_APC) { if (WaitStatus == STATUS_USER_APC) {
@ -2135,6 +2177,8 @@ XBSYSAPI EXPORTNUM(159) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForSingleObject
KWAIT_BLOCK StackWaitBlock; KWAIT_BLOCK StackWaitBlock;
PKWAIT_BLOCK WaitBlock = &StackWaitBlock; PKWAIT_BLOCK WaitBlock = &StackWaitBlock;
NTSTATUS WaitStatus; NTSTATUS WaitStatus;
// Hack variable (remove this when the thread scheduler is here)
bool timeout_set = false;
do { do {
// Check if we need to let an APC run. This should immediately trigger APC interrupt via a call to UnlockDispatcherDatabase // Check if we need to let an APC run. This should immediately trigger APC interrupt via a call to UnlockDispatcherDatabase
if (Thread->ApcState.KernelApcPending && (Thread->WaitIrql < APC_LEVEL)) { if (Thread->ApcState.KernelApcPending && (Thread->WaitIrql < APC_LEVEL)) {
@ -2182,7 +2226,8 @@ XBSYSAPI EXPORTNUM(159) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForSingleObject
goto NoWait; goto NoWait;
} }
// Setup a timer for the thread // Setup a timer for the thread but only once (for now)
if (!timeout_set) {
KiTimerLock(); KiTimerLock();
PKTIMER Timer = &Thread->Timer; PKTIMER Timer = &Thread->Timer;
PKWAIT_BLOCK WaitTimer = &Thread->TimerWaitBlock; PKWAIT_BLOCK WaitTimer = &Thread->TimerWaitBlock;
@ -2191,22 +2236,36 @@ XBSYSAPI EXPORTNUM(159) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForSingleObject
Timer->Header.WaitListHead.Blink = &WaitTimer->WaitListEntry; Timer->Header.WaitListHead.Blink = &WaitTimer->WaitListEntry;
WaitTimer->NextWaitBlock = WaitBlock; WaitTimer->NextWaitBlock = WaitBlock;
if (KiInsertTreeTimer(Timer, *Timeout) == FALSE) { if (KiInsertTreeTimer(Timer, *Timeout) == FALSE) {
DBG_PRINTF("%s: KiInsertTreeTimer(Timer, *Timeout) == FALSE\n", __func__);
WaitStatus = (NTSTATUS)STATUS_TIMEOUT; WaitStatus = (NTSTATUS)STATUS_TIMEOUT;
KiTimerUnlock(); KiTimerUnlock();
goto NoWait; goto NoWait;
} }
// Boring, ensure that we only set the thread timer once. Otherwise, this will cause to insert the same
// thread timer over and over in the timer list, which will prevent KiTimerExpiration from removing these
// duplicated timers and thus it will attempt to endlessly remove the same unremoved timers, causing a deadlock.
// This can be removed once KiSwapThread and the kernel/user APCs are implemented
timeout_set = true;
DueTime.QuadPart = Timer->DueTime.QuadPart; DueTime.QuadPart = Timer->DueTime.QuadPart;
KiTimerUnlock(); KiTimerUnlock();
} }
// KiTimerExpiration has removed the timer but the object was not signaled, so we have a timeout
// (remove this when the thread scheduler is here)
if (Thread->Timer.Header.Inserted == FALSE) {
WaitStatus = (NTSTATUS)(STATUS_TIMEOUT);
goto NoWait;
}
}
else { else {
WaitBlock->NextWaitBlock = WaitBlock; WaitBlock->NextWaitBlock = WaitBlock;
} }
/* /*
TODO: We can't implement this and the return values until we have our own thread schedular TODO: We can't implement this and the return values until we have our own thread scheduler
For now, we'll have to implement waiting here instead of the schedular. For now, we'll have to implement waiting here instead of the scheduler.
This code can all be enabled once we have CPU emulation and our own schedular in v1.0 This code can all be enabled once we have CPU emulation and our own scheduler in v1.0
*/ */
// Insert the WaitBlock // Insert the WaitBlock
@ -2238,7 +2297,7 @@ XBSYSAPI EXPORTNUM(159) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForSingleObject
return WaitStatus; return WaitStatus;
} */ } */
// TODO: Remove this after we have our own schedular and the above is implemented // TODO: Remove this after we have our own scheduler and the above is implemented
Sleep(0); Sleep(0);
// Reduce the timout if necessary // Reduce the timout if necessary
@ -2253,6 +2312,10 @@ XBSYSAPI EXPORTNUM(159) xboxkrnl::NTSTATUS NTAPI xboxkrnl::KeWaitForSingleObject
} }
} while (TRUE); } while (TRUE);
// NOTE: we don't need to remove the wait blocks for the object and/or the timer because InsertTailList is disabled at
// the moment, which means they are never attached to the object wait list. TimerWaitBlock can also stay attached to the timer wait
// list since KiTimerExpiration disregards it for now.
// The waiting thead has been alerted, or an APC needs to be delivered // The waiting thead has been alerted, or an APC needs to be delivered
// So unlock the dispatcher database, lower the IRQ and return the status // So unlock the dispatcher database, lower the IRQ and return the status
KiUnlockDispatcherDatabase(Thread->WaitIrql); KiUnlockDispatcherDatabase(Thread->WaitIrql);
@ -2267,6 +2330,14 @@ NoWait:
// Unlock the database and return the status // Unlock the database and return the status
//TODO: KiAdjustQuantumThread(Thread); //TODO: KiAdjustQuantumThread(Thread);
// Don't forget to remove the thread timer if the object was signaled before the timer expired
// (remove this when the thread scheduler is here)
if (timeout_set && Thread->Timer.Header.Inserted == TRUE) {
KiTimerLock();
KxRemoveTreeTimer(&Thread->Timer);
KiTimerUnlock();
}
KiUnlockDispatcherDatabase(Thread->WaitIrql); KiUnlockDispatcherDatabase(Thread->WaitIrql);
if (WaitStatus == STATUS_USER_APC) { if (WaitStatus == STATUS_USER_APC) {

View File

@ -27,8 +27,14 @@
namespace xboxkrnl namespace xboxkrnl
{ {
VOID NTAPI KeSetSystemTime( VOID NTAPI KeSetSystemTime
(
IN PLARGE_INTEGER NewTime, IN PLARGE_INTEGER NewTime,
OUT PLARGE_INTEGER OldTime OUT PLARGE_INTEGER OldTime
); );
VOID NTAPI KeInitializeTimer
(
IN PKTIMER Timer
);
} }

View File

@ -91,7 +91,7 @@ namespace xboxkrnl
#define MAX_TIMER_DPCS 16 #define MAX_TIMER_DPCS 16
#define ASSERT_TIMER_LOCKED assert(KiTimerMtx.Acquired == true) #define ASSERT_TIMER_LOCKED assert(KiTimerMtx.Acquired > 0)
const xboxkrnl::ULONG CLOCK_TIME_INCREMENT = 0x2710; const xboxkrnl::ULONG CLOCK_TIME_INCREMENT = 0x2710;
xboxkrnl::KDPC KiTimerExpireDpc; xboxkrnl::KDPC KiTimerExpireDpc;
@ -118,16 +118,17 @@ xboxkrnl::VOID xboxkrnl::KiInitSystem()
xboxkrnl::VOID xboxkrnl::KiTimerLock() xboxkrnl::VOID xboxkrnl::KiTimerLock()
{ {
KiTimerMtx.Mtx.lock(); KiTimerMtx.Mtx.lock();
KiTimerMtx.Acquired = true; KiTimerMtx.Acquired++;
} }
xboxkrnl::VOID xboxkrnl::KiTimerUnlock() xboxkrnl::VOID xboxkrnl::KiTimerUnlock()
{ {
KiTimerMtx.Acquired = false; KiTimerMtx.Acquired--;
KiTimerMtx.Mtx.unlock(); KiTimerMtx.Mtx.unlock();
} }
xboxkrnl::VOID xboxkrnl::KiClockIsr( xboxkrnl::VOID xboxkrnl::KiClockIsr
(
unsigned int ScalingFactor unsigned int ScalingFactor
) )
{ {
@ -165,10 +166,10 @@ xboxkrnl::VOID xboxkrnl::KiClockIsr(
if (KiTimerMtx.Mtx.try_lock()) { if (KiTimerMtx.Mtx.try_lock()) {
KiTimerMtx.Acquired = true; KiTimerMtx.Acquired = true;
// Check if a timer has expired // Check if a timer has expired
Hand = KeTickCount & (TIMER_TABLE_SIZE - 1); Hand = OldKeTickCount & (TIMER_TABLE_SIZE - 1);
if (KiTimerTableListHead[Hand].Entry.Flink != &KiTimerTableListHead[Hand].Entry && if (KiTimerTableListHead[Hand].Entry.Flink != &KiTimerTableListHead[Hand].Entry &&
(ULONGLONG)InterruptTime.QuadPart >= KiTimerTableListHead[Hand].Time.QuadPart) { (ULONGLONG)InterruptTime.QuadPart >= KiTimerTableListHead[Hand].Time.QuadPart) {
KeInsertQueueDpc(&KiTimerExpireDpc, (PVOID)OldKeTickCount, 0); KeInsertQueueDpc(&KiTimerExpireDpc, (PVOID)Hand, 0);
} }
KiTimerMtx.Acquired = false; KiTimerMtx.Acquired = false;
KiTimerMtx.Mtx.unlock(); KiTimerMtx.Mtx.unlock();
@ -177,7 +178,8 @@ xboxkrnl::VOID xboxkrnl::KiClockIsr(
KfLowerIrql(OldIrql); KfLowerIrql(OldIrql);
} }
xboxkrnl::VOID NTAPI xboxkrnl::KiCheckTimerTable( xboxkrnl::VOID NTAPI xboxkrnl::KiCheckTimerTable
(
IN xboxkrnl::ULARGE_INTEGER CurrentTime IN xboxkrnl::ULARGE_INTEGER CurrentTime
) )
{ {
@ -218,7 +220,8 @@ xboxkrnl::VOID NTAPI xboxkrnl::KiCheckTimerTable(
KfLowerIrql(OldIrql); KfLowerIrql(OldIrql);
} }
xboxkrnl::VOID xboxkrnl::KxInsertTimer( xboxkrnl::VOID xboxkrnl::KxInsertTimer
(
IN xboxkrnl::PKTIMER Timer, IN xboxkrnl::PKTIMER Timer,
IN xboxkrnl::ULONG Hand IN xboxkrnl::ULONG Hand
) )
@ -233,7 +236,8 @@ xboxkrnl::VOID xboxkrnl::KxInsertTimer(
} }
} }
xboxkrnl::VOID FASTCALL xboxkrnl::KiCompleteTimer( xboxkrnl::VOID FASTCALL xboxkrnl::KiCompleteTimer
(
IN xboxkrnl::PKTIMER Timer, IN xboxkrnl::PKTIMER Timer,
IN xboxkrnl::ULONG Hand IN xboxkrnl::ULONG Hand
) )
@ -263,7 +267,8 @@ xboxkrnl::VOID FASTCALL xboxkrnl::KiCompleteTimer(
} }
} }
xboxkrnl::VOID xboxkrnl::KiRemoveEntryTimer( xboxkrnl::VOID xboxkrnl::KiRemoveEntryTimer
(
IN xboxkrnl::PKTIMER Timer, IN xboxkrnl::PKTIMER Timer,
IN xboxkrnl::ULONG Hand IN xboxkrnl::ULONG Hand
) )
@ -289,7 +294,8 @@ xboxkrnl::VOID xboxkrnl::KiRemoveEntryTimer(
Timer->TimerListEntry.Blink = NULL; Timer->TimerListEntry.Blink = NULL;
} }
xboxkrnl::VOID xboxkrnl::KxRemoveTreeTimer( xboxkrnl::VOID xboxkrnl::KxRemoveTreeTimer
(
IN xboxkrnl::PKTIMER Timer IN xboxkrnl::PKTIMER Timer
) )
{ {
@ -314,7 +320,8 @@ xboxkrnl::VOID xboxkrnl::KxRemoveTreeTimer(
} }
} }
xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTimerTable( xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTimerTable
(
IN xboxkrnl::PKTIMER Timer, IN xboxkrnl::PKTIMER Timer,
IN xboxkrnl::ULONG Hand IN xboxkrnl::ULONG Hand
) )
@ -370,7 +377,8 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTimerTable(
return Expired; return Expired;
} }
xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTreeTimer( xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTreeTimer
(
IN xboxkrnl::PKTIMER Timer, IN xboxkrnl::PKTIMER Timer,
IN xboxkrnl::LARGE_INTEGER Interval IN xboxkrnl::LARGE_INTEGER Interval
) )
@ -400,14 +408,16 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTreeTimer(
return Inserted; return Inserted;
} }
xboxkrnl::ULONG xboxkrnl::KiComputeTimerTableIndex( xboxkrnl::ULONG xboxkrnl::KiComputeTimerTableIndex
(
IN xboxkrnl::ULONGLONG Interval IN xboxkrnl::ULONGLONG Interval
) )
{ {
return (Interval / CLOCK_TIME_INCREMENT) & (TIMER_TABLE_SIZE - 1); return (Interval / CLOCK_TIME_INCREMENT) & (TIMER_TABLE_SIZE - 1);
} }
xboxkrnl::BOOLEAN xboxkrnl::KiComputeDueTime( xboxkrnl::BOOLEAN xboxkrnl::KiComputeDueTime
(
IN xboxkrnl::PKTIMER Timer, IN xboxkrnl::PKTIMER Timer,
IN xboxkrnl::LARGE_INTEGER DueTime, IN xboxkrnl::LARGE_INTEGER DueTime,
OUT xboxkrnl::PULONG Hand) OUT xboxkrnl::PULONG Hand)
@ -455,7 +465,8 @@ xboxkrnl::BOOLEAN xboxkrnl::KiComputeDueTime(
return TRUE; return TRUE;
} }
xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiSignalTimer( xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiSignalTimer
(
IN xboxkrnl::PKTIMER Timer IN xboxkrnl::PKTIMER Timer
) )
{ {
@ -509,7 +520,8 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiSignalTimer(
return RequestInterrupt; return RequestInterrupt;
} }
xboxkrnl::VOID NTAPI xboxkrnl::KiTimerExpiration( xboxkrnl::VOID NTAPI xboxkrnl::KiTimerExpiration
(
IN xboxkrnl::PKDPC Dpc, IN xboxkrnl::PKDPC Dpc,
IN xboxkrnl::PVOID DeferredContext, IN xboxkrnl::PVOID DeferredContext,
IN xboxkrnl::PVOID SystemArgument1, IN xboxkrnl::PVOID SystemArgument1,
@ -752,7 +764,8 @@ xboxkrnl::VOID NTAPI xboxkrnl::KiTimerExpiration(
} }
} }
xboxkrnl::VOID FASTCALL xboxkrnl::KiTimerListExpire( xboxkrnl::VOID FASTCALL xboxkrnl::KiTimerListExpire
(
IN xboxkrnl::PLIST_ENTRY ExpiredListHead, IN xboxkrnl::PLIST_ENTRY ExpiredListHead,
IN xboxkrnl::KIRQL OldIrql IN xboxkrnl::KIRQL OldIrql
) )
@ -869,8 +882,6 @@ xboxkrnl::VOID FASTCALL xboxkrnl::KiWaitSatisfyAll
IN xboxkrnl::PKWAIT_BLOCK WaitBlock IN xboxkrnl::PKWAIT_BLOCK WaitBlock
) )
{ {
using namespace xboxkrnl;
PKMUTANT Object; PKMUTANT Object;
PRKTHREAD Thread; PRKTHREAD Thread;
PKWAIT_BLOCK WaitBlock1; PKWAIT_BLOCK WaitBlock1;

View File

@ -18,6 +18,7 @@
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. // * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// * // *
// * (c) 2018 Patrick van Logchem <pvanlogchem@gmail.com> // * (c) 2018 Patrick van Logchem <pvanlogchem@gmail.com>
// * (c) 2019 ergo720
// * // *
// * All rights reserved // * All rights reserved
// * // *
@ -48,7 +49,7 @@ namespace xboxkrnl
typedef struct _KI_TIMER_LOCK typedef struct _KI_TIMER_LOCK
{ {
std::recursive_mutex Mtx; std::recursive_mutex Mtx;
bool Acquired; int Acquired;
} KI_TIMER_LOCK; } KI_TIMER_LOCK;
@ -58,70 +59,84 @@ namespace xboxkrnl
VOID KiTimerUnlock(); VOID KiTimerUnlock();
VOID KiClockIsr( VOID KiClockIsr
(
IN unsigned int ScalingFactor IN unsigned int ScalingFactor
); );
VOID NTAPI KiCheckTimerTable( VOID NTAPI KiCheckTimerTable
(
IN ULARGE_INTEGER CurrentTime IN ULARGE_INTEGER CurrentTime
); );
VOID KxInsertTimer( VOID KxInsertTimer
(
IN PKTIMER Timer, IN PKTIMER Timer,
IN ULONG Hand IN ULONG Hand
); );
VOID FASTCALL KiCompleteTimer( VOID FASTCALL KiCompleteTimer
(
IN PKTIMER Timer, IN PKTIMER Timer,
IN ULONG Hand IN ULONG Hand
); );
VOID KiRemoveEntryTimer( VOID KiRemoveEntryTimer
(
IN PKTIMER Timer, IN PKTIMER Timer,
IN ULONG Hand IN ULONG Hand
); );
VOID KxRemoveTreeTimer( VOID KxRemoveTreeTimer
(
IN PKTIMER Timer IN PKTIMER Timer
); );
BOOLEAN FASTCALL KiInsertTimerTable( BOOLEAN FASTCALL KiInsertTimerTable
(
IN PKTIMER Timer, IN PKTIMER Timer,
IN ULONG Hand IN ULONG Hand
); );
BOOLEAN FASTCALL KiInsertTreeTimer( BOOLEAN FASTCALL KiInsertTreeTimer
(
IN PKTIMER Timer, IN PKTIMER Timer,
IN LARGE_INTEGER Interval IN LARGE_INTEGER Interval
); );
ULONG KiComputeTimerTableIndex( ULONG KiComputeTimerTableIndex
(
IN ULONGLONG Interval IN ULONGLONG Interval
); );
BOOLEAN KiComputeDueTime( BOOLEAN KiComputeDueTime
(
IN PKTIMER Timer, IN PKTIMER Timer,
IN LARGE_INTEGER DueTime, IN LARGE_INTEGER DueTime,
OUT PULONG Hand OUT PULONG Hand
); );
BOOLEAN FASTCALL KiSignalTimer( BOOLEAN FASTCALL KiSignalTimer
(
IN PKTIMER Timer IN PKTIMER Timer
); );
VOID NTAPI KiTimerExpiration( VOID NTAPI KiTimerExpiration
(
IN PKDPC Dpc, IN PKDPC Dpc,
IN PVOID DeferredContext, IN PVOID DeferredContext,
IN PVOID SystemArgument1, IN PVOID SystemArgument1,
IN PVOID SystemArgument2 IN PVOID SystemArgument2
); );
VOID FASTCALL KiTimerListExpire( VOID FASTCALL KiTimerListExpire
(
IN PLIST_ENTRY ExpiredListHead, IN PLIST_ENTRY ExpiredListHead,
IN KIRQL OldIrql IN KIRQL OldIrql
); );
VOID FASTCALL KiWaitSatisfyAll( VOID FASTCALL KiWaitSatisfyAll
(
IN PKWAIT_BLOCK WaitBlock IN PKWAIT_BLOCK WaitBlock
); );
}; };

View File

@ -35,6 +35,7 @@ namespace xboxkrnl
}; };
#include "core\kernel\exports\EmuKrnl.h" // For InitializeListHead(), etc. #include "core\kernel\exports\EmuKrnl.h" // For InitializeListHead(), etc.
#include "core\kernel\exports\EmuKrnlKe.h"
#include "EmuFS.h" #include "EmuFS.h"
#include "core\kernel\init\CxbxKrnl.h" #include "core\kernel\init\CxbxKrnl.h"
#include "core\kernel\memory-manager\VMManager.h" #include "core\kernel\memory-manager\VMManager.h"
@ -652,6 +653,19 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData)
EThread->UniqueThread = GetCurrentThreadId(); EThread->UniqueThread = GetCurrentThreadId();
// Set PrcbData.CurrentThread // Set PrcbData.CurrentThread
Prcb->CurrentThread = (xboxkrnl::KTHREAD*)EThread; Prcb->CurrentThread = (xboxkrnl::KTHREAD*)EThread;
// Initialize the thread header and its wait list
Prcb->CurrentThread->Header.Type = xboxkrnl::ThreadObject;
Prcb->CurrentThread->Header.Size = sizeof(xboxkrnl::KTHREAD) / sizeof(xboxkrnl::LONG);
InitializeListHead(&Prcb->CurrentThread->Header.WaitListHead);
// Also initialize the timer associated with the thread
xboxkrnl::KeInitializeTimer(&Prcb->CurrentThread->Timer);
xboxkrnl::PKWAIT_BLOCK WaitBlock = &Prcb->CurrentThread->TimerWaitBlock;
WaitBlock->Object = &Prcb->CurrentThread->Timer;
WaitBlock->WaitKey = (xboxkrnl::CSHORT)STATUS_TIMEOUT;
WaitBlock->WaitType = xboxkrnl::WaitAny;
WaitBlock->Thread = Prcb->CurrentThread;
WaitBlock->WaitListEntry.Flink = &Prcb->CurrentThread->Timer.Header.WaitListHead;
WaitBlock->WaitListEntry.Blink = &Prcb->CurrentThread->Timer.Header.WaitListHead;
} }
// Make the KPCR struct available to KeGetPcr() // Make the KPCR struct available to KeGetPcr()