📄 ctxswitch.s
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/i386/ctxswitch.S
* PURPOSE: Thread Context Switching
*
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
* Gregor Anich (FPU Code)
*/
/* INCLUDES ******************************************************************/
//#include <roscfg.h>
#include <ndk/asm.h>
.intel_syntax noprefix
#define Running 2
#define WrDispatchInt 0x1F
Dividend: .float 4195835.0
Divisor: .float 3145727.0
Result1: .float 0
Result2: .float 0
/* FUNCTIONS ****************************************************************/
.globl _KiIsNpxErrataPresent@0
.func KiIsNpxErrataPresent@0
_KiIsNpxErrataPresent@0:
/* Disable interrupts */
cli
/* Get CR0 and mask out FPU flags */
mov eax, cr0
mov ecx, eax
and eax, ~(CR0_MP + CR0_TS + CR0_EM)
mov cr0, eax
/* Initialize the FPU */
fninit
/* Do the divison and inverse multiplication */
fld qword ptr Dividend
fstp qword ptr Result1
fld qword ptr Divisor
fstp qword ptr Result2
fld qword ptr Result1
fdiv qword ptr Result2
fmul qword ptr Result2
/* Do the compare and check flags */
fcomp qword ptr Result1
fstsw ax
sahf
/* Restore CR0 and interrupts */
mov cr0, ecx
sti
/* Return errata status */
xor eax, eax
jz NoErrata
inc eax
NoErrata:
ret
.endfunc
.globl _KiIsNpxPresent@0
.func KiIsNpxPresent@0
_KiIsNpxPresent@0:
/* Save stack */
push ebp
/* Get CR0 and mask out FPU flags */
mov eax, cr0
and eax, ~(CR0_MP + CR0_TS + CR0_EM + CR0_ET)
/* Initialize the FPU and assume FALSE for return */
xor edx, edx
fninit
/* Save magic value on stack */
mov ecx, 0x42424242
push ecx
/* Setup stack for FPU store */
mov ebp ,esp
fnstsw [ebp]
/* Now check if our magic got cleared */
cmp byte ptr [ebp], 0
jnz NoFpu
/* Enable FPU, set return to TRUE */
or eax, CR0_ET
mov edx, 1
/* If this is a 486 or higher, enable INT 16 as well */
cmp dword ptr fs:KPCR_PRCB_CPU_TYPE, 3
jbe NoFpu
or eax, CR0_NE
NoFpu:
/* Set emulation enabled during the first boot phase and set the CR0 */
or eax, (CR0_EM + CR0_TS)
mov cr0, eax
/* Restore stack */
pop eax
pop ebp
/* Return true or false */
mov eax, edx
ret
.endfunc
.globl _KiFlushNPXState@4
.func KiFlushNPXState@4
_KiFlushNPXState@4:
/* Save volatiles and disable interrupts */
push esi
push edi
push ebx
pushfd
cli
/* Save the PCR and get the current thread */
mov edi, fs:[KPCR_SELF]
mov esi, [edi+KPCR_CURRENT_THREAD]
/* Check if we're already loaded */
cmp byte ptr [esi+KTHREAD_NPX_STATE], NPX_STATE_LOADED
je IsValid
/* Check if we're supposed to get it */
cmp dword ptr [esp+20], 0
je Return
#ifdef DBG
/* Assert Fxsr support */
test byte ptr _KeI386FxsrPresent, 1
jnz AssertOk
int 3
AssertOk:
#endif
/* Get CR0 and test if it's valid */
mov ebx, cr0
test bl, CR0_MP + CR0_TS + CR0_EM
jz Cr0OK
/* Enable fnsave to work */
and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
mov cr0, ebx
Cr0OK:
/* Check if we are the NPX Thread */
mov eax, [edi+KPCR_NPX_THREAD]
or eax, eax
jz DontSave
/* Check if it's not loaded */
cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
jnz DontSave
#ifdef DBG
/* We are the NPX Thread with an unloaded NPX State... this isn't normal! */
int 3
#endif
/* Save the NPX State */
mov ecx, [eax+KTHREAD_INITIAL_STACK]
sub ecx, NPX_FRAME_LENGTH
fxsave [ecx]
mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
DontSave:
/* Load the NPX State */
mov ecx, [esi+KTHREAD_INITIAL_STACK]
sub ecx, NPX_FRAME_LENGTH
fxrstor [ecx]
/* Get the CR0 state and destination */
mov edx, [ecx+FN_CR0_NPX_STATE]
mov ecx, [esp+20]
jmp DoneLoad
IsValid:
/* We already have a valid state, flush it */
mov ebx, cr0
test bl, CR0_MP + CR0_TS + CR0_EM
jz Cr0OK2
/* Enable fnsave to work */
and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
mov cr0, ebx
Cr0OK2:
/* Get the kernel stack */
mov ecx, [esi+KTHREAD_INITIAL_STACK]
test byte ptr _KeI386FxsrPresent, 1
lea ecx, [ecx-NPX_FRAME_LENGTH]
/* Set the NPX State */
mov byte ptr [esi+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
/* Get Cr0 */
mov edx, [ecx+FN_CR0_NPX_STATE]
jz DoneLoad
/* Save the FX State */
fxsave [ecx]
/* Check if we also have to save it in the parameter */
mov ecx, [esp+20]
jecxz NoSave
DoneLoad:
/* Save the Fn state in the parameter we got */
fnsave [ecx]
fwait
NoSave:
/* Clear eax */
xor eax, eax
/* Add NPX State */
or ebx, NPX_STATE_NOT_LOADED
/* Clear the NPX thread */
mov [edi+KPCR_NPX_THREAD], eax
/* Add saved CR0 into NPX State, and set it */
or ebx, edx
mov cr0, ebx
/* Re-enable interrupts and return */
Return:
popf
pop ebx
pop edi
pop esi
ret 4
.endfunc
/*++
* KiThreadStartup
*
* The KiThreadStartup routine is the beginning of any thread.
*
* Params:
* SystemRoutine - Pointer to the System Startup Routine. Either
* PspUserThreadStartup or PspSystemThreadStartup
*
* StartRoutine - For Kernel Threads only, specifies the starting execution
* point of the new thread.
*
* StartContext - For Kernel Threads only, specifies a pointer to variable
* context data to be sent to the StartRoutine above.
*
* UserThread - Indicates whether or not this is a user thread. This tells
* us if the thread has a context or not.
*
* TrapFrame - Pointer to the KTHREAD to which the caller wishes to
* switch from.
*
* Returns:
* Should never return for a system thread. Returns through the System Call
* Exit Dispatcher for a user thread.
*
* Remarks:
* If a return from a system thread is detected, a bug check will occur.
*
*--*/
.func KiThreadStartup@156
.globl _KiThreadStartup@156
_KiThreadStartup@156:
/*
* Clear all the non-volatile registers, so the thread won't be tempted to
* expect any static data (like some badly coded usermode/win9x apps do)
*/
xor ebx, ebx
xor esi, esi
xor edi, edi
xor ebp, ebp
/* It's now safe to go to APC */
mov ecx, APC_LEVEL
call @KfLowerIrql@4
/*
* Call the System Routine which is right on our stack now.
* After we pop the pointer, the Start Routine/Context will be on the
* stack, as parameters to the System Routine
*/
pop eax
call eax
/* The thread returned... was it a user-thread? */
pop ecx
or ecx, ecx
jz BadThread
/* Yes it was, set our trapframe for the System Call Exit Dispatcher */
mov ebp, esp
/* Exit back to user-mode */
jmp _KiServiceExit2
BadThread:
/* A system thread returned...this is very bad! */
int 3
.endfunc
/*++
* KiSwapContextInternal
*
* The KiSwapContextInternal routine switches context to another thread.
*
* Params:
* ESI - Pointer to the KTHREAD to which the caller wishes to
* switch to.
* EDI - Pointer to the KTHREAD to which the caller wishes to
* switch from.
*
* Returns:
* None.
*
* Remarks:
* Absolutely all registers except ESP can be trampled here for maximum code flexibility.
*
*--*/
.globl @KiSwapContextInternal@0
.func @KiSwapContextInternal@0, @KiSwapContextInternal@0
@KiSwapContextInternal@0:
/* Save the IRQL */
push ecx
#ifdef CONFIG_SMP
GetSwapLock:
/* Acquire the swap lock */
cmp [esi+KTHREAD_SWAP_BUSY], 0
jz NotBusy
pause
jmp GetSwapLock
#endif
/* Increase context switches (use ES for lazy load) */
inc dword ptr es:[ebx+KPCR_CONTEXT_SWITCHES]
/* Save the Exception list */
push [ebx+KPCR_EXCEPTION_LIST]
/* Check for WMI */
cmp dword ptr [ebx+KPCR_PERF_GLOBAL_GROUP_MASK], 0
jnz WmiTrace
AfterTrace:
#ifdef CONFIG_SMP
#ifdef DBG
/* Assert that we're on the right CPU */
mov cl, [esi+KTHREAD_NEXT_PROCESSOR]
cmp cl, [ebx+KPCR_PROCESSOR_NUMBER]
jnz WrongCpu
#endif
#endif
/* Get CR0 and save it */
mov ebp, cr0
mov edx, ebp
#ifdef CONFIG_SMP
/* Check NPX State */
cmp byte ptr [edi+KTHREAD_NPX_STATE], NPX_STATE_LOADED
jz NpxLoaded
#endif
SetStack:
/* Set new stack */
mov [edi+KTHREAD_KERNEL_STACK], esp
/* Checking NPX, disable interrupts now */
mov eax, [esi+KTHREAD_INITIAL_STACK]
cli
/* Get the NPX State */
movzx ecx, byte ptr [esi+KTHREAD_NPX_STATE]
/* Clear the other bits, merge in CR0, merge in FPU CR0 bits and compare */
and edx, ~(CR0_MP + CR0_EM + CR0_TS)
or ecx, edx
or ecx, [eax - (NPX_FRAME_LENGTH - FN_CR0_NPX_STATE)]
cmp ebp, ecx
jnz NewCr0
StackOk:
/* Enable interrupts and set the current stack */
sti
mov esp, [esi+KTHREAD_KERNEL_STACK]
/* Check if address space switch is needed */
mov ebp, [esi+KTHREAD_APCSTATE_PROCESS]
mov eax, [edi+KTHREAD_APCSTATE_PROCESS]
cmp ebp, eax
jz SameProcess
#ifdef CONFIG_SMP
/* Get the active processors and XOR with the process' */
mov ecx, [ebx+KPCR_SET_MEMBER_COPY]
lock xor [ebp+KPROCESS_ACTIVE_PROCESSORS], ecx
lock xor [eax+KPROCESS_ACTIVE_PROCESSORS], ecx
/* Assert change went ok */
#ifdef DBG
test [ebp+KPROCESS_ACTIVE_PROCESSORS], ecx
jz WrongActiveCpu
test [eax+KPROCESS_ACTIVE_PROCESSORS], ecx
jz WrongActiveCpu
#endif
#endif
/* Check if we need an LDT */
mov ecx, [ebp+KPROCESS_LDT_DESCRIPTOR0]
or ecx, [eax+KPROCESS_LDT_DESCRIPTOR0]
jnz LdtReload
UpdateCr3:
/* Switch address space */
mov eax, [ebp+KPROCESS_DIRECTORY_TABLE_BASE]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -