[10 bug fixes]:

- Simplify KiSelectReadyThread.
- Use ASSERT_IRQL_EQUAL instead of ASSERT_IRQL, because ASSERT_IRQL is braindead and doesn't actually do what the name proposes. This caused us to miss many critical bugs.
- Don't lower IRQL to PASSIVE_LEVEL after KeInsertQueueApc. This caused a call to KiExitDispatcher at PASSIVE, which is completely fucked. Also do the same fix in KeFreezeAllThreads and KeThawAllThreads.
- Implement code in KiDispatchInterrupt to switch to a new thread, but don't enable for now.
- Fix the KiMask32Array. One of the values was totally off and screwed up priority/affinity masks.
- Exit the dispatcher in KiAdjustQuantumThread. This wasn't done, thus causing a weird system state.
- Fix a bug in KiSetPriorityThread which wasn't properly checking the ProcessReadyQueue member and thus not applying priority changes.
- Fixup lock release and dispatcher exit in wait functions in the NoWait case. It was inverted and messed up, leading to system inconsistency.

svn path=/trunk/; revision=25501
This commit is contained in:
Alex Ionescu 2007-01-17 20:44:37 +00:00
parent 22033f60ea
commit a04cac242c
16 changed files with 123 additions and 97 deletions

View file

@ -101,15 +101,16 @@ Author:
#define KTHREAD_STACK_LIMIT 0x1C
#define KTHREAD_TEB 0x74
#define KTHREAD_KERNEL_STACK 0x20
#define KTHREAD_STATE 0x4C
#define KTHREAD_NPX_STATE 0x4D
#define KTHREAD_ALERTED 0x5E
#define KTHREAD_APCSTATE_PROCESS 0x28 + 0x10
#define KTHREAD_PENDING_USER_APC 0x28 + 0x16
#define KTHREAD_PENDING_KERNEL_APC 0x28 + 0x15
#define KTHREAD_CONTEXT_SWITCHES 0x48
#define KTHREAD_STATE 0x4C
#define KTHREAD_NPX_STATE 0x4D
#define KTHREAD_WAIT_IRQL 0x4E
#define KTHREAD_NEXT_PROCESSOR 0x40
#define KTHREAD_WAIT_REASON 0x5A
#define KTHREAD_SWAP_BUSY 0x5D
#define KTHREAD_SERVICE_TABLE 0x118
#define KTHREAD_PREVIOUS_MODE 0xD7

View file

@ -8,13 +8,16 @@
// Do NOT ask when it will be fixed.
// Failure to respect this will *ACHIEVE NOTHING*.
//
// Ex:
// - Use pushlocks for handle implementation.
//
// Ke1:
// - Implement KiInitMachineDependent.
// - Implement Privileged Instruction Handler in Umode GPF.
//
// Ex:
// - Use pushlocks for handle implementation.
//
// Ke2:
// - Dispatcher Rewrite (DPCs-Timers-Waits).
//
// Hal:
// - Use APC and DPC Interrupt Dispatchers.
// - CMOS Initialization and CMOS Spinlock.
@ -22,10 +25,6 @@
// Fstub:
// - Implement IoAssignDriveLetters using mount manager support.
//
// Ke2:
// - New optimized table-based tick-hashed timer implementation.
// - New Thread Scheduler based on 2003.
//
// Kd:
// - Implement KD Kernel Debugging and WinDBG support.
//

View file

@ -1257,21 +1257,20 @@ PKTHREAD
KiSelectReadyThread(IN KPRIORITY Priority,
IN PKPRCB Prcb)
{
LONG PriorityMask, PrioritySet, HighPriority;
ULONG PrioritySet, HighPriority;
PLIST_ENTRY ListEntry;
PKTHREAD Thread = NULL;
/* Save the current mask and get the priority set for the CPU */
PriorityMask = Priority;
PrioritySet = Prcb->ReadySummary >> (UCHAR)Priority;
PrioritySet = Prcb->ReadySummary >> Priority;
if (!PrioritySet) goto Quickie;
/* Get the highest priority possible */
/* Get the highest priority possible */
BitScanReverse((PULONG)&HighPriority, PrioritySet);
ASSERT((PrioritySet & PRIORITY_MASK(HighPriority)) != 0);
HighPriority += PriorityMask;
HighPriority += Priority;
/* Make sure the list isn't at highest priority */
/* Make sure the list isn't empty at the highest priority */
ASSERT(IsListEmpty(&Prcb->DispatcherReadyListHead[HighPriority]) == FALSE);
/* Get the first thread on the list */

View file

@ -28,7 +28,7 @@ IoAllocateController(IN PCONTROLLER_OBJECT ControllerObject,
IN PVOID Context)
{
IO_ALLOCATION_ACTION Result;
ASSERT_IRQL(DISPATCH_LEVEL);
ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
/* Initialize the Wait Context Block */
DeviceObject->Queue.Wcb.DeviceContext = Context;

View file

@ -632,7 +632,7 @@ IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject,
NTSTATUS Status;
PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension;
ASSERT_IRQL(PASSIVE_LEVEL);
ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
PhysicalDeviceObject, ReferenceString);

View file

@ -725,7 +725,7 @@ KeInsertQueueApc(IN PKAPC Apc,
}
/* Release the APC lock and return success */
KiReleaseApcLock(&ApcLock);
KiReleaseApcLockFromDpcLevel(&ApcLock);
KiExitDispatcher(ApcLock.OldIrql);
return State;
}
@ -951,3 +951,4 @@ KeAreAllApcsDisabled(VOID)
}

View file

@ -199,7 +199,7 @@ KiRetireDpcList(IN PKPRCB Prcb)
DeferredContext,
SystemArgument1,
SystemArgument2);
ASSERT_IRQL(DISPATCH_LEVEL);
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
/* Disable interrupts and keep looping */
_disable();

View file

@ -764,7 +764,7 @@ NTAPI
KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save)
{
PFNSAVE_FORMAT FpState;
ASSERT_IRQL(DISPATCH_LEVEL);
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
DPRINT1("%s is not really implemented\n", __FUNCTION__);
/* check if we are doing software emulation */

View file

@ -11,11 +11,11 @@
/* INCLUDES ******************************************************************/
#include <roscfg.h>
#include <internal/i386/ke.h>
#include <ndk/asm.h>
.intel_syntax noprefix
#define Running 2
#define WrDispatchInt 0x1F
/* FUNCTIONS ****************************************************************/
@ -289,6 +289,7 @@ BadThread:
* Absolutely all registers except ESP can be trampled here for maximum code flexibility.
*
*--*/
.globl @KiSwapContextInternal@0
.func @KiSwapContextInternal@0, @KiSwapContextInternal@0
@KiSwapContextInternal@0:
@ -413,7 +414,7 @@ SameProcess:
sub eax, NPX_FRAME_LENGTH
/* Check if this isn't V86 Mode, so we can bias the Esp0 */
test dword ptr [eax - KTRAP_FRAME_SIZE + KTRAP_FRAME_EFLAGS], X86_EFLAGS_VM
test dword ptr [eax - KTRAP_FRAME_SIZE + KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jnz NoAdjust
/* Bias esp */
@ -562,7 +563,6 @@ WrongCpu:
.globl @KiSwapContext@8
.func @KiSwapContext@8, @KiSwapContext@8
@KiSwapContext@8:
/* Note, we CANNOT touch ebp */
/* Save 4 registers */
sub esp, 4 * 4
@ -664,7 +664,7 @@ CheckSchedule:
/* Set the current thread to ready */
mov edi, [ebx+KPCR_CURRENT_THREAD]
#ifdef CONFIG_SMP
mov [edi+KTHREAD_STATE], Ready
mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1
/* Acquire the PRCB Lock */
lock bts [ebx+KPCR_PRCB_PRCB_LOCK], 0

View file

@ -6,18 +6,18 @@
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES ****************************************************************/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
#include <debug.h>
typedef struct _KSHARED_CTXSWITCH_FRAME
typedef struct _KSWITCHFRAME
{
PVOID ExceptionList;
KIRQL WaitIrql;
PVOID RetEip;
} KSHARED_CTXSWITCH_FRAME, *PKSHARED_CTXSWITCH_FRAME;
BOOLEAN ApcBypassDisable;
PVOID RetAddr;
} KSWITCHFRAME, *PKSWITCHFRAME;
typedef struct _KSTART_FRAME
{
@ -27,65 +27,47 @@ typedef struct _KSTART_FRAME
BOOLEAN UserThread;
} KSTART_FRAME, *PKSTART_FRAME;
/*
* This is the Initial Thread Stack Frame on i386.
*
* It is composed of :
*
* - A shared Thread Switching frame so that we can use
* the context-switching code when initializing the thread.
*
* - The Stack Frame for KiThreadStartup, which are the parameters
* that it will receive (System/Start Routines & Context)
*
* - A Trap Frame with the Initial Context *IF AND ONLY IF THE THREAD IS USER*
*
* - The FPU Save Area, theoretically part of the Trap Frame's "ExtendedRegisters"
*
* This Initial Thread Stack Frame starts at Thread->InitialStack and it spans
* a total size of 0x2B8 bytes.
*/
typedef struct _KUINIT_FRAME {
KSHARED_CTXSWITCH_FRAME CtxSwitchFrame; /* -0x2B8 */
KSTART_FRAME StartFrame; /* -0x2AC */
KTRAP_FRAME TrapFrame; /* -0x29C */
FX_SAVE_AREA FxSaveArea; /* -0x210 */
typedef struct _KUINIT_FRAME
{
KSWITCHFRAME CtxSwitchFrame;
KSTART_FRAME StartFrame;
KTRAP_FRAME TrapFrame;
FX_SAVE_AREA FxSaveArea;
} KUINIT_FRAME, *PKUINIT_FRAME;
typedef struct _KKINIT_FRAME {
KSHARED_CTXSWITCH_FRAME CtxSwitchFrame; /* -0x22C */
KSTART_FRAME StartFrame; /* -0x220 */
FX_SAVE_AREA FxSaveArea; /* -0x210 */
typedef struct _KKINIT_FRAME
{
KSWITCHFRAME CtxSwitchFrame;
KSTART_FRAME StartFrame;
FX_SAVE_AREA FxSaveArea;
} KKINIT_FRAME, *PKKINIT_FRAME;
/* FUNCTIONS *****************************************************************/
VOID
STDCALL
Ke386InitThreadWithContext(PKTHREAD Thread,
PKSYSTEM_ROUTINE SystemRoutine,
PKSTART_ROUTINE StartRoutine,
PVOID StartContext,
PCONTEXT ContextPointer)
NTAPI
Ke386InitThreadWithContext(IN PKTHREAD Thread,
IN PKSYSTEM_ROUTINE SystemRoutine,
IN PKSTART_ROUTINE StartRoutine,
IN PVOID StartContext,
IN PCONTEXT ContextPointer)
{
PFX_SAVE_AREA FxSaveArea;
PFXSAVE_FORMAT FxSaveFormat;
PKSTART_FRAME StartFrame;
PKSHARED_CTXSWITCH_FRAME CtxSwitchFrame;
PKSWITCHFRAME CtxSwitchFrame;
PKTRAP_FRAME TrapFrame;
CONTEXT LocalContext;
PCONTEXT Context = NULL;
ULONG ContextFlags;
/* Check if this is a With-Context Thread */
DPRINT("Ke386InitThreadContext\n");
if (ContextPointer)
{
/* Set up the Initial Frame */
PKUINIT_FRAME InitFrame;
InitFrame = (PKUINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
sizeof(KUINIT_FRAME));
DPRINT("Setting up a user-mode thread. InitFrame at: %p\n", InitFrame);
/* Copy over the context we got */
RtlCopyMemory(&LocalContext, ContextPointer, sizeof(CONTEXT));
@ -190,7 +172,6 @@ Ke386InitThreadWithContext(PKTHREAD Thread,
PKKINIT_FRAME InitFrame;
InitFrame = (PKKINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
sizeof(KKINIT_FRAME));
DPRINT("Setting up a kernel thread. InitFrame at: %p\n", InitFrame);
/* Setup the Fx Area */
FxSaveArea = &InitFrame->FxSaveArea;
@ -230,15 +211,14 @@ Ke386InitThreadWithContext(PKTHREAD Thread,
StartFrame->SystemRoutine = SystemRoutine;
/* And set up the Context Switch Frame */
CtxSwitchFrame->RetEip = KiThreadStartup;
CtxSwitchFrame->WaitIrql = APC_LEVEL;
CtxSwitchFrame->ExceptionList = (PVOID)0xFFFFFFFF;
CtxSwitchFrame->RetAddr = KiThreadStartup;
CtxSwitchFrame->ApcBypassDisable = TRUE;
CtxSwitchFrame->ExceptionList = EXCEPTION_CHAIN_END;;
/* Save back the new value of the kernel stack. */
DPRINT("Final Kernel Stack: %x \n", CtxSwitchFrame);
Thread->KernelStack = (PVOID)CtxSwitchFrame;
return;
}
/* EOF */

View file

@ -12,6 +12,9 @@
#include <internal/i386/asmmacro.S>
.intel_syntax noprefix
#define Running 2
#define WrDispatchInt 0x1F
/* GLOBALS *******************************************************************/
.data
@ -2082,7 +2085,7 @@ _KiDispatchInterrupt@0:
/* Restore stack and exception list */
pop esp
pop dword ptr [ebx]
pop dword ptr [ebx+KPCR_EXCEPTION_LIST]
pop ebp
CheckQuantum:
@ -2096,10 +2099,44 @@ CheckQuantum:
/* Check if we have a thread to swap to */
cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
jz Return
jmp Return
/* FIXME: Schedule new thread */
UNHANDLED_PATH
/* Make space on the stack to save registers */
sub esp, 3 * 4
mov [esp+8], esi
mov [esi+4], edi
mov [esi+0], ebp
/* Get the current thread */
mov edi, [ebx+KPCR_CURRENT_THREAD]
#ifdef CONFIG_SMP
#error SMP Interrupt not handled!
#endif
/* Get the next thread and clear it */
mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
/* Set us as the current running thread */
mov [ebx+KPCR_CURRENT_THREAD], esi
mov byte ptr [esi+KTHREAD_STATE], Running
mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt
/* Put thread in ECX and get the PRCB in EDX */
mov ecx, edi
lea edx, [ebx+KPCR_PRCB_DATA]
call @KiQueueReadyThread@8
/* Set APC_LEVEL and do the swap */
mov cl, APC_LEVEL
call @KiSwapContextInternal@0
/* Restore registers */
mov ebp, [esp+0]
mov edi, [esp+4]
mov esi, [esp+8]
add esp, 3*4
Return:
/* All done */

View file

@ -18,7 +18,7 @@ extern LIST_ENTRY PspReaperListHead;
ULONG KiMask32Array[MAXIMUM_PRIORITY] =
{
0x1, 0x2, 0x4, 0x8, 0x10, 0x20,
0x40, 0x80, 0x100, 0x200, 0x4000, 0x800,
0x40, 0x80, 0x100, 0x200, 0x400, 0x800,
0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000,
0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000,
0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000,
@ -311,7 +311,7 @@ KeFreezeAllThreads(VOID)
} while (NextEntry != ListHead);
/* Release the process lock and exit the dispatcher */
KiReleaseProcessLock(&LockHandle);
KiReleaseProcessLockFromDpcLevel(&LockHandle);
KiExitDispatcher(LockHandle.OldIrql);
}
@ -634,7 +634,7 @@ KeThawAllThreads(VOID)
} while (NextEntry != ListHead);
/* Release the process lock and exit the dispatcher */
KiReleaseProcessLock(&LockHandle);
KiReleaseProcessLockFromDpcLevel(&LockHandle);
KiExitDispatcher(LockHandle.OldIrql);
/* Leave the critical region */

View file

@ -21,6 +21,15 @@ ULONG KiIdleSMTSummary;
/* FUNCTIONS *****************************************************************/
VOID
FASTCALL
KiQueueReadyThread(IN PKTHREAD Thread,
IN PKPRCB Prcb)
{
/* Call the macro. We keep the API for compatibility with ASM code */
KxQueueReadyThread(Thread, Prcb);
}
static
VOID
KiInsertIntoThreadList(KPRIORITY Priority,
@ -247,7 +256,7 @@ KiReadyThread(IN PKTHREAD Thread)
if (Process->State != ProcessInMemory)
{
/* We don't page out processes in ROS */
ASSERT(FALSE);
KEBUGCHECK(0);
}
else if (!Thread->KernelStackResident)
{
@ -260,7 +269,7 @@ KiReadyThread(IN PKTHREAD Thread)
Thread->State = Transition;
/* The stack is always resident in ROS */
ASSERT(FALSE);
KEBUGCHECK(0);
}
else
{
@ -326,10 +335,11 @@ KiAdjustQuantumThread(IN PKTHREAD Thread)
/* Release locks */
KiReleasePrcbLock(Prcb);
KiReleaseThreadLock(Thread);
KiExitDispatcher(Thread->WaitIrql);
}
VOID
STDCALL
NTAPI
KiSetPriorityThread(IN PKTHREAD Thread,
IN KPRIORITY Priority,
OUT PBOOLEAN Released)
@ -351,7 +361,7 @@ KiSetPriorityThread(IN PKTHREAD Thread,
if (Thread->State == Ready)
{
/* Make sure we're not on the ready queue */
if (Thread->ProcessReadyQueue)
if (!Thread->ProcessReadyQueue)
{
/* Get the PRCB for the thread and lock it */
Processor = Thread->NextProcessor;
@ -362,12 +372,12 @@ KiSetPriorityThread(IN PKTHREAD Thread,
if ((Thread->State == Ready) &&
(Thread->NextProcessor == Prcb->Number))
{
#ifdef NEW_SCHEDULER
/* Sanity check */
ASSERT((Prcb->ReadySummary &
PRIORITY_MASK(Thread->Priority)));
/* Remove it from the current queue */
#ifdef NEW_SCHEDULER
if (RemoveEntryList(&Thread->WaitListEntry))
{
/* Update the ready summary */
@ -395,7 +405,6 @@ KiSetPriorityThread(IN PKTHREAD Thread,
else
{
/* Release the lock and loop again */
KEBUGCHECK(0);
KiReleasePrcbLock(Prcb);
continue;
}
@ -409,7 +418,6 @@ KiSetPriorityThread(IN PKTHREAD Thread,
else if (Thread->State == Standby)
{
/* Get the PRCB for the thread and lock it */
KEBUGCHECK(0);
Processor = Thread->NextProcessor;
Prcb = KiProcessorBlock[Processor];
KiAcquirePrcbLock(Prcb);

View file

@ -161,7 +161,7 @@ KiExitDispatcher(IN KIRQL OldIrql)
BOOLEAN PendingApc;
/* Make sure we're at synchronization level */
ASSERT_IRQL(SYNCH_LEVEL);
ASSERT_IRQL_EQUAL(SYNCH_LEVEL);
/* Check if we have deferred threads */
KiCheckDeferredReadyList(Prcb);
@ -484,11 +484,11 @@ StartWait:
return WaitStatus;
DontWait:
/* Adjust the Quantum */
KiAdjustQuantumThread(Thread);
/* Release dispatcher lock but maintain high IRQL */
KiReleaseDispatcherLockFromDpcLevel();
/* Release & Return */
KiReleaseDispatcherLock(Thread->WaitIrql);
/* Adjust the Quantum and return the wait status */
KiAdjustQuantumThread(Thread);
return WaitStatus;
}
@ -761,11 +761,11 @@ StartWait:
return WaitStatus;
DontWait:
/* Adjust the Quantum */
KiAdjustQuantumThread(Thread);
/* Release dispatcher lock but maintain high IRQL */
KiReleaseDispatcherLockFromDpcLevel();
/* Release & Return */
KiReleaseDispatcherLock(Thread->WaitIrql);
/* Adjust the Quantum and return the wait status */
KiAdjustQuantumThread(Thread);
return WaitStatus;
}

View file

@ -911,7 +911,7 @@ PspTerminateThreadByPointer(IN PETHREAD Thread,
if ((bSelf) || (PsGetCurrentThread() == Thread))
{
/* This should only happen at passive */
ASSERT_IRQL(PASSIVE_LEVEL);
ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
/* Mark it as terminated */
PspSetCrossThreadFlag(Thread, CT_TERMINATED_BIT);

View file

@ -49,7 +49,7 @@ VdmSwapContext(IN PKTRAP_FRAME TrapFrame,
ULONG EFlags, OldEFlags;
/* Make sure that we're at APC_LEVEL and that this is a valid frame */
ASSERT_IRQL(APC_LEVEL);
ASSERT(KeGetCurrentIrql() == APC_LEVEL);
ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
/* Check if this is a V86 frame */
@ -321,3 +321,4 @@ VdmDispatchBop(IN PKTRAP_FRAME TrapFrame)
return TRUE;
}