kernel-zig/src/arch/x86/switch_tasks.s

55 lines
2.3 KiB
ArmAsm

//https://wiki.osdev.org/Multitasking_Systems
//C declaration:
// void switch_tasks(thread_control_block *next_thread)//
//
//WARNING: Caller is expected to disable IRQs before calling, and enable IRQs again after function returns
.type switch_tasks, @function
.global switch_tasks
switch_tasks:
push %ebp
mov %esp, %ebp
mov +12(%esp), %eax
mov %esp, (%eax) //save old esp
mov +8(%esp), %eax
mov %eax, %esp // move the forged stack to esp
pop %ebp // the top of the forged stack contains ebp
ret //the top of the forged stack contains eip to go to
//Save previous task'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 task 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,[current_task] //edi = address of the previous task's "thread control block"
// mov [edi+TCB.ESP], %esp //Save ESP for previous task's kernel stack in the thread's TCB
// Load next task's state
// mov %esi,[esp+(4+1)*4] //esi = address of the next task's "thread control block" (parameter passed on stack)
// mov [current_task], %esi //Current task's TCB is the next task TCB
// mov %esp,[esi+TCB.ESP] //Load ESP for next task's kernel stack from the thread's TCB
// mov eax,[esi+TCB.CR3] //eax = address of page directory for next task
// mov %ebx,[esi+TCB.ESP0] //ebx = address for the top of the next task's kernel stack
// mov [TSS.ESP0],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 task'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 task's virtual address space
// .doneVAS:
// pop %ebp
// pop %edi
// pop %esi
// pop %ebx