14 extern current_task:data, tasks_ready_tail:data
15 extern _tasks_enqueue_ready:function
16 global tasks_switch_to:function
18 ;Save previous task's state
20 ; For cdecl; EAX, ECX, and EDX are already saved by the caller and don't need to be saved again
21 ; EIP is already saved on the stack by the caller's "CALL" instruction
22 ; The task isn't able to change CR3 so it doesn't need to be saved
23 ; Segment registers are constants (while running kernel code) so they don't need to be saved
29 mov edi,[current_task] ;edi = address of the previous task's "thread control block"
30 mov [edi+task.stack],esp ;Save ESP for previous task's kernel stack in the thread's TCB
31 cmp dword [edi+task.state],TASK_RUNNING
33 mov dword [edi+task.state],TASK_READY ;Set the task's state to ready (from running)
34 push edi ; push the task to be enqueued
35 call _tasks_enqueue_ready ; call the enqueue function
36 add esp,4 ; fix up the stack
38 ;Load next task's state
39 mov esi,[esp+(4+1)*4] ;esi = address of the next task's "thread control block" (parameter passed on stack)
40 mov [current_task],esi ;Current task's TCB is the next task TCB
42 mov esp,[esi+task.stack] ;Load ESP for next task's kernel stack from the thread's TCB
44 ; at this point we are operating under the new task's stack
46 mov dword [esi+task.state],TASK_RUNNING ;this task is now running
47 mov eax,[esi+task.page_dir] ;eax = address of page directory for next task
48 ;mov ebx,[esi+TCB.ESP0] ;ebx = address for the top of the next task's kernel stack
49 ;mov [TSS.ESP0],ebx ;Adjust the ESP0 field in the TSS (used by CPU for for CPL=3 -> CPL=0 privilege level changes)
50 mov ecx,cr3 ;ecx = previous task's virtual address space
52 cmp eax,ecx ;Does the virtual address space need to being changed?
53 je .done_virt_addr ; no, virtual address space is the same, so don't reload it and cause TLB flushes
54 mov cr3,eax ; yes, load the next task's virtual address space
60 ret ;Load next task's EIP from its kernel stack