⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ctxswitch.s

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 S
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -