- Add support for APC-delivery after context-switch (not yet programmed)

- Detect and crash if context switch is done inside a DPC.
- Switch kernel stack a bit earlier
- Don't switch address space if we're still in the same process, and fix some duplicated code that was mixed up together.
- Move LDT setup out-of-line.

svn path=/trunk/; revision=23621
This commit is contained in:
Alex Ionescu 2006-08-20 19:55:32 +00:00
parent 9348f70d7d
commit 233e643648
3 changed files with 69 additions and 49 deletions

View file

@ -148,6 +148,7 @@ Author:
#define KPCR_DR6 0x428 #define KPCR_DR6 0x428
#define KPCR_DR7 0x42C #define KPCR_DR7 0x42C
#define KPCR_SYSTEM_CALLS 0x6B8 #define KPCR_SYSTEM_CALLS 0x6B8
#define KPCR_PRCB_DPC_ROUTINE_ACTIVE 0x994
// //
// KGDTENTRY Offsets // KGDTENTRY Offsets
@ -383,6 +384,7 @@ Author:
#define APC_INDEX_MISMATCH 0x01 #define APC_INDEX_MISMATCH 0x01
#define IRQL_GT_ZERO_AT_SYSTEM_SERVICE 0x4A #define IRQL_GT_ZERO_AT_SYSTEM_SERVICE 0x4A
#define UNEXPECTED_KERNEL_MODE_TRAP 0x7F #define UNEXPECTED_KERNEL_MODE_TRAP 0x7F
#define ATTEMPTED_SWITCH_FROM_DPC 0xB8
#endif #endif
// //

View file

@ -115,19 +115,30 @@ BadThread:
.globl @KiSwapContextInternal@0 .globl @KiSwapContextInternal@0
@KiSwapContextInternal@0: @KiSwapContextInternal@0:
/* Save WaitIrql APC-bypass in EFLAGS */
or cl, cl
/* Set the Thread to running */ /* Set the Thread to running */
mov byte ptr [esi+KTHREAD_STATE], Running mov byte ptr [esi+KTHREAD_STATE], Running
/* Save the flags */
pushf
/* Save the Exception list */ /* Save the Exception list */
push [ebx+KPCR_EXCEPTION_LIST] push [ebx+KPCR_EXCEPTION_LIST]
/* DPC shouldn't be active */
cmp byte ptr [ebx+KPCR_PRCB_DPC_ROUTINE_ACTIVE], 0
jnz BugCheckDpc
/* Switching, disable interrupts now */ /* Switching, disable interrupts now */
cli cli
/* Save the initial stack in EAX */ /* Update kernel stack */
mov eax, [esi+KTHREAD_INITIAL_STACK] mov [edi+KTHREAD_KERNEL_STACK], esp
/* Save the stack limit in ecx */ /* Get stack pointers */
mov eax, [esi+KTHREAD_INITIAL_STACK]
mov ecx, [esi+KTHREAD_STACK_LIMIT] mov ecx, [esi+KTHREAD_STACK_LIMIT]
/* Make space for the NPX Frame */ /* Make space for the NPX Frame */
@ -137,8 +148,7 @@ BadThread:
mov [ebx+KPCR_INITIAL_STACK], eax mov [ebx+KPCR_INITIAL_STACK], eax
mov [ebx+KPCR_STACK_LIMIT], ecx mov [ebx+KPCR_STACK_LIMIT], ecx
/* Save the stack pointer in this processors TSS */ /* FIXME Check and update CR0 */
mov ebp, [ebx+KPCR_TSS]
/* Check if this isn't V86 Mode, so we can bias the Esp0 */ /* 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], X86_EFLAGS_VM
@ -150,38 +160,22 @@ BadThread:
NoAdjust: NoAdjust:
/* Set new ESP0 */ /* Set new ESP0 */
mov [ebp+KTSS_ESP0], eax mov ecx, [ebx+KPCR_TSS]
mov [ecx+KTSS_ESP0], eax
/* Switch to new stack */
mov esp, [esi+KTHREAD_KERNEL_STACK]
/* Set TEB pointer */ /* Set TEB pointer */
mov eax, [esi+KTHREAD_TEB] mov eax, [esi+KTHREAD_TEB]
mov [ebx+KPCR_TEB], eax mov [ebx+KPCR_TEB], eax
/* Check if address space switch is needed */
mov eax, [esi+KTHREAD_APCSTATE_PROCESS]
cmp eax, [edi+KTHREAD_APCSTATE_PROCESS]
mov eax, [eax+KPROCESS_DIRECTORY_TABLE_BASE]
/* Switch stacks */
mov [edi+KTHREAD_KERNEL_STACK], esp
mov esp, [esi+KTHREAD_KERNEL_STACK]
jz NoAddressSpaceSwitch
/* Clear gs */
xor ecx, ecx
mov gs, cx
/* Switch address space */
mov cr3, eax
mov [ebp+KTSS_CR3], eax
NoAddressSpaceSwitch:
/* Stack is OK, safe to enable interrupts now */ /* Stack is OK, safe to enable interrupts now */
sti sti
/* Check if address space switch is needed (the result from above is valid) */ /* Check if address space switch is needed */
/* If they match, then use the fast-path and skip all this */ mov eax, [esi+KTHREAD_APCSTATE_PROCESS]
cmp eax, [edi+KTHREAD_APCSTATE_PROCESS]
jz SameProcess jz SameProcess
/* Get the new Process. */ /* Get the new Process. */
@ -190,31 +184,31 @@ NoAddressSpaceSwitch:
/* Check if we need an LDT */ /* Check if we need an LDT */
xor eax, eax xor eax, eax
cmp [edi+KPROCESS_LDT_DESCRIPTOR0], eax cmp [edi+KPROCESS_LDT_DESCRIPTOR0], eax
jz NoLdt jnz LdtStuff
/* Write the LDT Selector */
mov ecx, [ebx+KPCR_GDT]
mov eax, [edi+KPROCESS_LDT_DESCRIPTOR0]
mov [ecx+KGDT_LDT], eax
mov eax, [edi+KPROCESS_LDT_DESCRIPTOR1]
mov [ecx+KGDT_LDT+4], eax
/* Save LDT Selector */
mov eax, KGDT_LDT
NoLdt:
LoadLdt:
/* Load LDT */ /* Load LDT */
lldt ax lldt ax
/* Get the IOPM */ /* Clear gs */
xor eax, eax
mov gs, ax
/* Get the address space */
mov eax, [edi+KPROCESS_DIRECTORY_TABLE_BASE]
/* Get the IOPM and TSS */
mov ebp, [ebx+KPCR_TSS]
mov ecx, [edi+KPROCESS_IOPM_OFFSET] mov ecx, [edi+KPROCESS_IOPM_OFFSET]
/* Switch address space */
mov [ebp+KTSS_CR3], eax
mov cr3, eax
/* Set current IOPM offset in the TSS */ /* Set current IOPM offset in the TSS */
mov [ebp+KTSS_IOMAPBASE], cx mov [ebp+KTSS_IOMAPBASE], cx
SameProcess: SameProcess:
/* Set the TEB */ /* Set the TEB */
mov eax, [esi+KTHREAD_TEB] mov eax, [esi+KTHREAD_TEB]
mov ecx, [ebx+KPCR_GDT] mov ecx, [ebx+KPCR_GDT]
@ -225,13 +219,35 @@ SameProcess:
/* Increase context switches */ /* Increase context switches */
inc dword ptr [esi+KTHREAD_CONTEXT_SWITCHES] inc dword ptr [esi+KTHREAD_CONTEXT_SWITCHES]
//inc dword ptr [esi+KPRC_PRCB_CONTEXT_SWITCHES]
/* Restore exception list */ /* Restore exception list */
pop [ebx+KPCR_EXCEPTION_LIST] pop [ebx+KPCR_EXCEPTION_LIST]
/* Return */ /* Retore EFLAGS */
popf
/* Return no APC pending */
xor eax, eax
ret ret
LdtStuff:
/* Write the LDT Selector */
mov ecx, [ebx+KPCR_GDT]
mov eax, [edi+KPROCESS_LDT_DESCRIPTOR0]
mov [ecx+KGDT_LDT], eax
mov eax, [edi+KPROCESS_LDT_DESCRIPTOR1]
mov [ecx+KGDT_LDT+4], eax
/* Save LDT Selector */
mov eax, KGDT_LDT
jmp LoadLdt
BugCheckDpc:
push ATTEMPTED_SWITCH_FROM_DPC
call _KeBugCheck@4
/*++ /*++
* KiSwapContext * KiSwapContext
* *
@ -275,12 +291,12 @@ SameProcess:
/* Get the New Thread */ /* Get the New Thread */
mov esi, edx mov esi, edx
/* Get the wait IRQL */
movzx ecx, byte ptr [edi+KTHREAD_WAIT_IRQL]
/* Save it as Current thread */ /* Save it as Current thread */
mov fs:[KPCR_CURRENT_THREAD], esi mov fs:[KPCR_CURRENT_THREAD], esi
/* Get the wait IRQL */
movzx ecx, byte ptr [edi+KTHREAD_WAIT_IRQL]
/* Do the swap with the registers correctly setup */ /* Do the swap with the registers correctly setup */
call @KiSwapContextInternal@0 call @KiSwapContextInternal@0

View file

@ -15,6 +15,7 @@
typedef struct _KSHARED_CTXSWITCH_FRAME typedef struct _KSHARED_CTXSWITCH_FRAME
{ {
PVOID ExceptionList; PVOID ExceptionList;
ULONG Flags;
PVOID RetEip; PVOID RetEip;
} KSHARED_CTXSWITCH_FRAME, *PKSHARED_CTXSWITCH_FRAME; } KSHARED_CTXSWITCH_FRAME, *PKSHARED_CTXSWITCH_FRAME;
@ -230,6 +231,7 @@ Ke386InitThreadWithContext(PKTHREAD Thread,
/* And set up the Context Switch Frame */ /* And set up the Context Switch Frame */
CtxSwitchFrame->RetEip = KiThreadStartup; CtxSwitchFrame->RetEip = KiThreadStartup;
CtxSwitchFrame->Flags = EFLAGS_INTERRUPT_MASK;
CtxSwitchFrame->ExceptionList = (PVOID)0xFFFFFFFF; CtxSwitchFrame->ExceptionList = (PVOID)0xFFFFFFFF;
/* Save back the new value of the kernel stack. */ /* Save back the new value of the kernel stack. */