os/kernel/cpu/i386/tasking_helpers.asm
2020-07-22 19:26:55 -05:00

76 lines
2.4 KiB
NASM

section .text
global switch_to_thread_asm
extern currentThread
extern tss
;WARNING: Caller is expected to disable IRQs before calling, and enable IRQs again after function returns
switch_to_thread_asm:
;Save previous thread's state
;Notes:
; For cdecl; EAX, ECX, and EDX are already saved by the caller and don't need to be saved again
; EIP is already saved on the stack by the caller's "CALL" instruction
; The thread isn't able to change CR3 so it doesn't need to be saved
; Segment registers are constants (while running kernel code) so they don't need to be saved
push ebx
push esi
push edi
push ebp
mov edi,[currentThread] ;edi = address of the previous thread's data structure
mov [edi],esp ;Save ESP for the thread's kernel stack in the thread's data structure
;Load next thread's state
mov esi,[esp+(4+1)*4] ;esi = address of the next thread's data structure
mov [currentThread],esi ;Set the current thread to the thread we are switching to
mov esp,[esi] ;Load ESP for next thread's kernel stack from the thread's data structure
mov eax,[esi+8] ;eax = address of page directory for next thread
mov ebx,[esi+4] ;ebx = address for the top of the next thread's kernel stack
mov [tss+4],ebx ;Adjust the ESP0 field in the TSS (used by CPU for for CPL=3 -> CPL=0 privilege level changes)
mov ecx,cr3 ;ecx = previous thread's virtual address space
cmp eax,ecx ;Does the virtual address space need to being changed?
je .doneVAS ; no, virtual address space is the same, so don't reload it and cause TLB flushes
mov cr3,eax ; yes, load the next thread's virtual address space
.doneVAS:
pop ebp
pop edi
pop esi
pop ebx
ret ;Load next thread's EIP from its kernel stack
global task_init
task_init:
pop ecx
pop ebx
cli
mov ax, 0x23
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, ecx
push 0x23
push eax
pushf
pop eax
or eax, 0x200
push eax
push 0x1B
push ebx
iret
global wait_for_unblocked_thread_asm
wait_for_unblocked_thread_asm:
sti ;As interrupts are stopped in tasking code, re-enable them
hlt ;Wait for an interrupt handler to run and return.
cli ;Clear interrupts, as tasking code must not be run with interrupts on.