User Task

先前的 task 都是跑在 kernel mode,將 user task 引進後可以進一步限縮 process 權限,提高安全性。

User mode context saving

調整一下之前的 kernel_entrykernel_exit,也要同時保存 user stack 相關的 system registers:

  • SP_EL0: The address of user mode’s stack pointer.
  • ELR_EL1: The program counter of user mode’s procedure.
  • SPSR_EL1: The CPU state of user mode.

否則如果遇到 nested interrupt,先前的狀態就會被覆蓋。

exception.S

 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
51
52
    .macro kernel_entry
    sub sp, sp, #272
    stp x0, x1, [sp, #16 * 0]
    stp x2, x3, [sp, #16 * 1]
    stp x4, x5, [sp, #16 * 2]
    stp x6, x7, [sp, #16 * 3]
    stp x8, x9, [sp, #16 * 4]
    stp x10, x11, [sp, #16 * 5]
    stp x12, x13, [sp, #16 * 6]
    stp x14, x15, [sp, #16 * 7]
    stp x16, x17, [sp, #16 * 8]
    stp x18, x19, [sp, #16 * 9]
    stp x20, x21, [sp, #16 * 10]
    stp x22, x23, [sp, #16 * 11]
    stp x24, x25, [sp, #16 * 12]
    stp x26, x27, [sp, #16 * 13]
    stp x28, x29, [sp, #16 * 14]

    mrs x21, sp_el0
    stp x30, x21, [sp, #16 * 15]

    mrs x21, elr_el1
    mrs x22, spsr_el1
    stp x21, x22, [sp, #16 * 16]
    .endm

    .macro kernel_exit
    ldp x21, x22, [sp, #16 * 16]
    msr spsr_el1, x22
    msr elr_el1, x21

    ldp x30, x21, [sp, #16 * 15]
    msr sp_el0, x21

    ldp x28, x29, [sp, #16 * 14]
    ldp x26, x27, [sp, #16 * 13]
    ldp x24, x25, [sp, #16 * 12]
    ldp x22, x23, [sp, #16 * 11]
    ldp x20, x21, [sp, #16 * 10]
    ldp x18, x19, [sp, #16 * 9]
    ldp x16, x17, [sp, #16 * 8]
    ldp x14, x15, [sp, #16 * 7]
    ldp x12, x13, [sp, #16 * 6]
    ldp x10, x11, [sp, #16 * 5]
    ldp x8, x9, [sp, #16 * 4]
    ldp x6, x7, [sp, #16 * 3]
    ldp x4, x5, [sp, #16 * 2]
    ldp x2, x3, [sp, #16 * 1]
    ldp x0, x1, [sp, #16 * 0]
    add sp, sp, #272
    eret
    .endm

do_exec

通常 exec 是帶一個 program file,但是目前 file system 還沒有實作,所以將他改一下變成帶進一個 function pointer。

schedule.c

將 stack 切換至 user stack,並從 EL1 跳回 EL0。

1
2
3
4
5
6
7
void do_exec(void (*func)()) {
    struct task_t *current = get_current_task();
    asm volatile("msr sp_el0, %0" : : "r"(&ustack_pool[current->id][USTACK_TOP_IDX]));
    asm volatile("msr elr_el1, %0": : "r"(func));
    asm volatile("msr spsr_el1, %0" : : "r"(SPSR_EL1_VALUE));
    asm volatile("eret");
}

User tasks preemption

圖片來自 Lab 4 Spec

這部分功能已經在 Involuntary context switch 的 Reschedule 中實作。

comments powered by Disqus