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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
.extern hart0_boot
.extern hart0_early_boot
.section .text.start
.global _start
.type _start, STT_FUNC
_start:
## Have harts other than hart0 spin until hart0 wakes them up. As a
## side effect, load every hart's thread pointer register with MHARTID.
csrr tp, mhartid
bnez tp, wait_for_hart0
### Set up trap handling.
## Set MENVCFG.STCE, to enable the Sstc extension, which will allow us
## to delegate timer interrupts to Supervisor mode.
li t0, 1<<63
csrs menvcfg, t0
## Set MCOUNTEREN.{CY, TM, IR} to 1, enabling Supervisor mode accesses
## to the cycle, time, stimecmp, and instret MSRs.
li t0, 0b111
csrs mcounteren, t0
## Set MIE.{SSIE, STIE, SEIE} to 1, enabling software, timer, and
## exception traps in Supervisor mode.
li t0, 0b1000100010
csrs mie, t0
## Delegate all exceptions to Supervisor mode.
li t0, 0xffff
csrw medeleg, t0
csrw mideleg, t0
### Go from Machine mode to Supervisor mode by fictitiously returning from a
### trap.
## First, set MSTATUS.MPP to Supervisor, so that when we execute mret,
## the privilege level will lower to Supervisor.
li t0, 0b11 << 11
csrc mstatus, t0
li t0, 0b01 << 11
csrs mstatus, t0
## Next, set MEPC to the address of hart0_full_boot, so that when we
## execute mret, execution will continue there.
la t0, hart0_full_boot
csrw mepc, t0
## Set SATP.MODE to Bare, and clear the rest of the bits. This disables
## paging in Supervisor mode.
csrw satp, zero
## Set PMP0CFG.{R, W, X} to 1, PMP0CFG.A to TOR, and PMP0ADDR to the
## maximum value. This allows supervisor mode to access all of physical
## memory.
li t0, (0b01 << 3) | 0b111
csrw pmpcfg0, t0
li t0, -1
csrw pmpaddr0, t0
## Jump to supervisor mode.
mret
.size _start, . - _start
.section .text
.type hart0_full_boot, STT_FUNC
hart0_full_boot:
## Set up hart0's stack.
la sp, hart0_initial_stack_top
## Write a canary to hart0's stack.
li t0, 0xdead0bad0defaced
la t1, hart0_initial_stack
sd t0, (t1)
## Call hart0_early_boot, passing it the DeviceTree we received and
## getting back the address of a stack to switch to.
mv a0, a1
call hart0_early_boot
## Switch to the returned stack.
mv sp, a0
## Load the canary back from hart0's stack.
la t0, hart0_initial_stack
ld a0, (t0)
## Jump to hart0_boot.
j hart0_boot
.size hart0_full_boot, . - hart0_full_boot
.section .text
.type wait_for_hart0, STT_FUNC
wait_for_hart0:
# TODO
wfi
j wait_for_hart0
.size wait_for_hart0, . - wait_for_hart0
|