Xyris  0.5
tasks.s
Go to the documentation of this file.
1 struc task
2  .stack: resd 1
3  .page_dir: resd 1
4  .next_task: resd 1
5  .state: resd 1
6  .time_used: resq 1
7 endstruc
8 
9 %define TASK_RUNNING 0
10 %define TASK_READY 1
11 
12 bits 32
13 section .text
14 extern current_task:data, tasks_ready_tail:data
15 extern _tasks_enqueue_ready:function
16 global tasks_switch_to:function
17 tasks_switch_to:
18  ;Save previous task's state
19  ;Notes:
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
24  push ebx
25  push esi
26  push edi
27  push ebp
28 
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
32  jne .state_updated
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
37  .state_updated:
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
41 
42  mov esp,[esi+task.stack] ;Load ESP for next task's kernel stack from the thread's TCB
43 
44  ; at this point we are operating under the new task's stack
45 
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
51 
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
55 .done_virt_addr:
56  pop ebp
57  pop edi
58  pop esi
59  pop ebx
60  ret ;Load next task's EIP from its kernel stack