os/kernel/cpu/i386/tasking_helpers.asm

78 lines
2.7 KiB
NASM
Raw Normal View History

2019-05-21 19:16:19 -05:00
section .text
2020-07-20 09:51:30 -05:00
global switch_to_thread_asm
2020-07-22 21:28:00 -05:00
extern load_address_space
2020-07-25 18:00:53 -05:00
extern current_thread
2019-05-21 19:16:19 -05:00
extern tss
;WARNING: Caller is expected to disable IRQs before calling, and enable IRQs again after function returns
2020-07-20 09:51:30 -05:00
switch_to_thread_asm:
2019-05-21 19:16:19 -05:00
;Save previous thread's state
2019-05-21 19:16:19 -05:00
;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
2019-05-21 19:16:19 -05:00
; Segment registers are constants (while running kernel code) so they don't need to be saved
push ebx
push esi
push edi
push ebp
2020-07-25 18:00:53 -05:00
mov edi,[current_thread] ;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
2019-05-21 19:16:19 -05:00
;Load next thread's state
2019-05-21 19:16:19 -05:00
mov esi,[esp+(4+1)*4] ;esi = address of the next thread's data structure
2020-07-25 18:00:53 -05:00
mov [current_thread],esi ;Set the current thread to the thread we are switching to
2019-05-21 19:16:19 -05:00
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
2019-05-21 19:16:19 -05:00
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
2019-05-21 19:16:19 -05:00
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
2020-07-22 21:28:00 -05:00
; yes, load the next thread's virtual address space
mov cr3, eax
2019-05-21 19:16:19 -05:00
.doneVAS:
pop ebp
pop edi
pop esi
pop ebx
ret ;Load next thread's EIP from its kernel stack
2019-05-21 19:16:19 -05:00
global task_init
2020-07-23 21:00:54 -05:00
; Switch to usermode, given a usermode stack and EIP to switch to
2019-05-21 19:16:19 -05:00
task_init:
2020-07-23 21:00:54 -05:00
pop ecx ; ecx = user ESP
pop ebx ; ebx = user EIP
mov ax, 0x23 ; Load data segment selectors with the usermode data segment
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
2020-07-23 21:00:54 -05:00
push 0x23 ; Push SS
push ecx ; push user ESP
pushf ; push flags
pop eax ; pop flags into eax
or eax, 0x200 ; enable interrupts when iret runs
push eax ; push modified flags
push 0x1B ; push CS
push ebx ; push user EIP
iret
2020-07-22 19:26:55 -05:00
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.