summaryrefslogtreecommitdiff
path: root/kc/core/cpu/cpu_task.S
blob: 4f9fd7b4bf24ea1bd7cfe512f4132af79a0cc68a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/* thread switching routines for x86_64
* adapted from:
* https://wiki.osdev.org/Brendan%27s_Multi-tasking_Tutorial
* 
* 
*/

.hidden cpu_set_thread
.global cpu_set_thread
.type cpu_set_thread, @function
cpu_set_thread:
    /* x86_64 SysV ABI
    *  must save the following registers to the stack:
    *   rbx, rsp, rbp, r12, r13, r14, r15
    *  the following are the parameters for switching tasks
    *   rdi: pointer to control block of thread being switched to 
    *   rsi: pointer to control block of the current thread
    *   rdx: pointer to this cpu's task state segment esp0 field
    */
    // test for a NULL origin thread
    test %rsi,%rsi
    // skip saving the state for a NULL origin thread
    jz .Lnull_thread
    push %rbx
    push %r12
    push %r13
    push %r14
    push %r15
    push %rbp
    /* the current task will be in rsi */
    mov %rsp, 0(%rsi) // save the stack pointer for the current task
.Lnull_thread:
    mov 0(%rdi),%rsp // new stack is the next's task's stack
    mov 8(%rdi),%rbx // top of the next task's kernel stack
    mov %rbx,0(%rdx) // save the esp0 to the tss
    mov 16(%rdi),%rax // page map for the next task
    mov %cr3, %rcx // in case we need to change the page map
    cmp %rax,%rcx
    je .Lfinish
    mov %rax,%cr3 // if the page maps are not the same, reload
.Lfinish:
    pop %rbp // get all the registers off the new task's stack
    pop %r15
    pop %r14
    pop %r13
    pop %r12
    pop %rbx
    ret // leave into the new task
.size cpu_set_thread, . - cpu_set_thread