78 lines
2.4 KiB
NASM
78 lines
2.4 KiB
NASM
; ke_switch.asm - context switch and thread entry stubs (MASM64 / ML64)
|
|
;
|
|
; Generated struct offsets (regenerate with gen_offsets.exe if structs change):
|
|
; sizeof(OBJECT) = 16 (type:4, refcount:4, destroy:8)
|
|
; THREAD.SavedContext offset = 88
|
|
; THREAD.TssRsp0 offset = 104
|
|
; TSS64.RSP0 offset = 4
|
|
;
|
|
THREAD_SavedContext EQU 88
|
|
THREAD_TssRsp0 EQU 104
|
|
TSS_RSP0_OFFSET EQU 4
|
|
|
|
EXTERN gTss:QWORD ; address of the single TSS, exported from ke_idt.c
|
|
|
|
.CODE
|
|
|
|
; -------------------------------------------------------------------------
|
|
; void KeSwitchContext(THREAD* from, THREAD* to)
|
|
; RCX = from, RDX = to (Microsoft x64)
|
|
; -------------------------------------------------------------------------
|
|
KeSwitchContext PROC
|
|
; Save non-volatile registers onto the current (outgoing) kernel stack.
|
|
push rbx
|
|
push rbp
|
|
push r12
|
|
push r13
|
|
push r14
|
|
push r15
|
|
|
|
; from->SavedContext = rsp
|
|
mov [rcx + THREAD_SavedContext], rsp
|
|
|
|
; rsp = to->SavedContext
|
|
mov rsp, [rdx + THREAD_SavedContext]
|
|
|
|
; Update TSS.RSP0 so that the next interrupt/syscall uses the
|
|
; incoming thread's kernel stack top.
|
|
mov rax, [rdx + THREAD_TssRsp0]
|
|
mov r8, gTss
|
|
mov qword ptr [r8 + TSS_RSP0_OFFSET], rax
|
|
|
|
; Restore non-volatile registers of the incoming thread.
|
|
pop r15
|
|
pop r14
|
|
pop r13
|
|
pop r12
|
|
pop rbp
|
|
pop rbx
|
|
ret
|
|
KeSwitchContext ENDP
|
|
|
|
; -------------------------------------------------------------------------
|
|
; KeThreadEntry - landing pad for brand-new threads.
|
|
;
|
|
; Stack layout when we arrive here (set up by KeCreateThread):
|
|
; [rsp+00] = KCONTEXT (already popped by KeSwitchContext ret)
|
|
; After ret from KeSwitchContext RSP points here:
|
|
; [rsp+00] = user RCX arg
|
|
; [rsp+08] = user RIP
|
|
; [rsp+16] = user CS (0x1B)
|
|
; [rsp+24] = RFLAGS (0x202)
|
|
; [rsp+32] = user RSP
|
|
; [rsp+40] = user SS (0x23)
|
|
;
|
|
; We load RCX from the stack (first arg per MS x64), then IRETQ.
|
|
; -------------------------------------------------------------------------
|
|
EXTERN KeSchedulerPostSwitch : PROC
|
|
|
|
KeThreadEntry PROC
|
|
sub rsp, 32 ; Reserve shadow space
|
|
call KeSchedulerPostSwitch
|
|
add rsp, 32
|
|
pop rcx ; load user arg
|
|
iretq ; -> ring 3
|
|
KeThreadEntry ENDP
|
|
|
|
END
|