55 lines
2.3 KiB
ArmAsm
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
|