This repository has been archived by the owner on Nov 28, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 78
/
asm.rs
186 lines (176 loc) · 5.26 KB
/
asm.rs
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
use core::arch::global_asm;
/// Parse cfg attributes inside a global_asm call.
macro_rules! cfg_global_asm {
{@inner, [$($x:tt)*], } => {
global_asm!{$($x)*}
};
(@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
#[cfg($meta)]
cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
#[cfg(not($meta))]
cfg_global_asm!{@inner, [$($x)*], $($rest)*}
};
{@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
};
{$($asms:tt)*} => {
cfg_global_asm!{@inner, [], $($asms)*}
};
}
// Entry point of all programs (_start). It initializes DWARF call frame information,
// the stack pointer, the frame pointer (needed for closures to work in start_rust)
// and the global pointer. Then it calls _start_rust.
cfg_global_asm!(
".section .init, \"ax\"
.global _start
_start:",
#[cfg(riscv32)]
"lui ra, %hi(_abs_start)
jr %lo(_abs_start)(ra)",
#[cfg(riscv64)]
".option push
.option norelax // to prevent an unsupported R_RISCV_ALIGN relocation from being generated
1:
auipc ra, %pcrel_hi(1f)
ld ra, %pcrel_lo(1b)(ra)
jr ra
.align 3
1:
.dword _abs_start
.option pop",
"
_abs_start:
.option norelax
.cfi_startproc
.cfi_undefined ra",
#[cfg(feature = "s-mode")]
"csrw sie, 0
csrw sip, 0",
#[cfg(not(feature = "s-mode"))]
"csrw mie, 0
csrw mip, 0",
"li x1, 0
li x2, 0
li x3, 0
li x4, 0
li x5, 0
li x6, 0
li x7, 0
li x8, 0
li x9, 0
// a0..a2 (x10..x12) skipped
li x13, 0
li x14, 0
li x15, 0
li x16, 0
li x17, 0
li x18, 0
li x19, 0
li x20, 0
li x21, 0
li x22, 0
li x23, 0
li x24, 0
li x25, 0
li x26, 0
li x27, 0
li x28, 0
li x29, 0
li x30, 0
li x31, 0
.option push
.option norelax
la gp, __global_pointer$
.option pop",
#[cfg(all(not(feature = "single-hart"), feature = "s-mode"))]
"mv t2, a0 // the hartid is passed as parameter by SMODE",
#[cfg(all(not(feature = "single-hart"), not(feature = "s-mode")))]
"csrr t2, mhartid",
#[cfg(not(feature = "single-hart"))]
"lui t0, %hi(_max_hart_id)
add t0, t0, %lo(_max_hart_id)
bgtu t2, t0, abort",
"// Allocate stacks
la sp, _stack_start
lui t0, %hi(_hart_stack_size)
add t0, t0, %lo(_hart_stack_size)",
#[cfg(all(not(feature = "single-hart"), riscvm))]
"mul t0, t2, t0",
#[cfg(all(not(feature = "single-hart"), not(riscvm)))]
"beqz t2, 2f // Jump if single-hart
mv t1, t2
mv t3, t0
1:
add t0, t0, t3
addi t1, t1, -1
bnez t1, 1b
2: ",
"sub sp, sp, t0
// Set frame pointer
add s0, sp, zero
jal zero, _start_rust
.cfi_endproc",
);
/// Trap entry point (_start_trap). It saves caller saved registers, calls
/// _start_trap_rust, restores caller saved registers and then returns.
///
/// # Usage
///
/// The macro takes 5 arguments:
/// - `$STORE`: the instruction used to store a register in the stack (e.g. `sd` for riscv64)
/// - `$LOAD`: the instruction used to load a register from the stack (e.g. `ld` for riscv64)
/// - `$BYTES`: the number of bytes used to store a register (e.g. 8 for riscv64)
/// - `$TRAP_SIZE`: the number of registers to store in the stack (e.g. 32 for all the user registers)
/// - list of tuples of the form `($REG, $LOCATION)`, where:
/// - `$REG`: the register to store/load
/// - `$LOCATION`: the location in the stack where to store/load the register
#[rustfmt::skip]
macro_rules! trap_handler {
($STORE:ident, $LOAD:ident, $BYTES:literal, $TRAP_SIZE:literal, [$(($REG:ident, $LOCATION:literal)),*]) => {
global_asm!(
"
.section .trap, \"ax\"
.global default_start_trap
default_start_trap:",
// save space for trap handler in stack
concat!("addi sp, sp, -", stringify!($TRAP_SIZE * $BYTES)),
// save registers in the desired order
$(concat!(stringify!($STORE), " ", stringify!($REG), ", ", stringify!($LOCATION * $BYTES), "(sp)"),)*
// call rust trap handler
"add a0, sp, zero
jal ra, _start_trap_rust",
// restore registers in the desired order
$(concat!(stringify!($LOAD), " ", stringify!($REG), ", ", stringify!($LOCATION * $BYTES), "(sp)"),)*
// free stack
concat!("addi sp, sp, ", stringify!($TRAP_SIZE * $BYTES)),
);
cfg_global_asm!(
// return from trap
#[cfg(feature = "s-mode")]
"sret",
#[cfg(not(feature = "s-mode"))]
"mret",
);
};
}
#[rustfmt::skip]
#[cfg(riscv32)]
trap_handler!(
sw, lw, 4, 16,
[(ra, 0), (t0, 1), (t1, 2), (t2, 3), (t3, 4), (t4, 5), (t5, 6), (t6, 7),
(a0, 8), (a1, 9), (a2, 10), (a3, 11), (a4, 12), (a5, 13), (a6, 14), (a7, 15)]
);
#[rustfmt::skip]
#[cfg(riscv64)]
trap_handler!(
sd, ld, 8, 16,
[(ra, 0), (t0, 1), (t1, 2), (t2, 3), (t3, 4), (t4, 5), (t5, 6), (t6, 7),
(a0, 8), (a1, 9), (a2, 10), (a3, 11), (a4, 12), (a5, 13), (a6, 14), (a7, 15)]
);
// Make sure there is an abort when linking
global_asm!(
".section .text.abort
.globl abort
abort:
j abort"
);