- 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_DR7 0x42C
#define KPCR_SYSTEM_CALLS 0x6B8
#define KPCR_PRCB_DPC_ROUTINE_ACTIVE 0x994
//
// KGDTENTRY Offsets
@ -383,6 +384,7 @@ Author:
#define APC_INDEX_MISMATCH 0x01
#define IRQL_GT_ZERO_AT_SYSTEM_SERVICE 0x4A
#define UNEXPECTED_KERNEL_MODE_TRAP 0x7F
#define ATTEMPTED_SWITCH_FROM_DPC 0xB8
#endif
//

View file

@ -115,19 +115,30 @@ BadThread:
.globl @KiSwapContextInternal@0
@KiSwapContextInternal@0:
/* Save WaitIrql APC-bypass in EFLAGS */
or cl, cl
/* Set the Thread to running */
mov byte ptr [esi+KTHREAD_STATE], Running
/* Save the flags */
pushf
/* Save the 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 */
cli
/* Save the initial stack in EAX */
mov eax, [esi+KTHREAD_INITIAL_STACK]
/* Update kernel 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]
/* Make space for the NPX Frame */
@ -137,8 +148,7 @@ BadThread:
mov [ebx+KPCR_INITIAL_STACK], eax
mov [ebx+KPCR_STACK_LIMIT], ecx
/* Save the stack pointer in this processors TSS */
mov ebp, [ebx+KPCR_TSS]
/* FIXME Check and update CR0 */
/* 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
@ -150,38 +160,22 @@ BadThread:
NoAdjust:
/* 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 */
mov eax, [esi+KTHREAD_TEB]
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 */
sti
/* Check if address space switch is needed (the result from above is valid) */
/* If they match, then use the fast-path and skip all this */
/* Check if address space switch is needed */
mov eax, [esi+KTHREAD_APCSTATE_PROCESS]
cmp eax, [edi+KTHREAD_APCSTATE_PROCESS]
jz SameProcess
/* Get the new Process. */
@ -190,31 +184,31 @@ NoAddressSpaceSwitch:
/* Check if we need an LDT */
xor eax, eax
cmp [edi+KPROCESS_LDT_DESCRIPTOR0], eax
jz NoLdt
/* 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:
jnz LdtStuff
LoadLdt:
/* Load LDT */
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]
/* Switch address space */
mov [ebp+KTSS_CR3], eax
mov cr3, eax
/* Set current IOPM offset in the TSS */
mov [ebp+KTSS_IOMAPBASE], cx
SameProcess:
/* Set the TEB */
mov eax, [esi+KTHREAD_TEB]
mov ecx, [ebx+KPCR_GDT]
@ -225,13 +219,35 @@ SameProcess:
/* Increase context switches */
inc dword ptr [esi+KTHREAD_CONTEXT_SWITCHES]
//inc dword ptr [esi+KPRC_PRCB_CONTEXT_SWITCHES]
/* Restore exception list */
pop [ebx+KPCR_EXCEPTION_LIST]
/* Return */
/* Retore EFLAGS */
popf
/* Return no APC pending */
xor eax, eax
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
*
@ -275,12 +291,12 @@ SameProcess:
/* Get the New Thread */
mov esi, edx
/* Get the wait IRQL */
movzx ecx, byte ptr [edi+KTHREAD_WAIT_IRQL]
/* Save it as Current thread */
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 */
call @KiSwapContextInternal@0

View file

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