forked from rust-embedded/riscv-rt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
asm.S
189 lines (166 loc) · 3.72 KB
/
asm.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
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
187
188
189
#if __riscv_xlen == 64
# define STORE sd
# define LOAD ld
# define LOG_REGBYTES 3
#else
# define STORE sw
# define LOAD lw
# define LOG_REGBYTES 2
#endif
#define REGBYTES (1 << LOG_REGBYTES)
/*
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.
*/
.section .init, "ax"
.global _start
_start:
/* Jump to the absolute address defined by the linker script. */
// for 32bit
.if __riscv_xlen == 32
lui ra, %hi(_abs_start)
jr %lo(_abs_start)(ra)
.endif
// for 64bit
.if __riscv_xlen == 64
.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
.endif
_abs_start:
.cfi_startproc
.cfi_undefined ra
#ifdef SMODE
csrw sie, 0 // interrupt disable
csrw sip, 0 // no pending interrupts
#else
csrw mie, 0
csrw mip, 0
#endif
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
#ifdef SMODE
// there is no equivalent of mhartid in supervisor mode.
// instead, the hartid is passed as paramter by SMODE
mv t2, a0
#else
csrr t2, mhartid
#endif
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)
#ifdef __riscv_mul
mul t0, t2, t0
#else
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:
#endif
sub sp, sp, t0
// Set frame pointer
add s0, sp, zero
jal zero, _start_rust
.cfi_endproc
/*
Trap entry point (_start_trap)
Saves caller saved registers ra, t0..6, a0..7, calls _start_trap_rust,
restores caller saved registers and then returns.
*/
.section .trap, "ax"
.global default_start_trap
default_start_trap:
addi sp, sp, -16*REGBYTES
STORE ra, 0*REGBYTES(sp)
STORE t0, 1*REGBYTES(sp)
STORE t1, 2*REGBYTES(sp)
STORE t2, 3*REGBYTES(sp)
STORE t3, 4*REGBYTES(sp)
STORE t4, 5*REGBYTES(sp)
STORE t5, 6*REGBYTES(sp)
STORE t6, 7*REGBYTES(sp)
STORE a0, 8*REGBYTES(sp)
STORE a1, 9*REGBYTES(sp)
STORE a2, 10*REGBYTES(sp)
STORE a3, 11*REGBYTES(sp)
STORE a4, 12*REGBYTES(sp)
STORE a5, 13*REGBYTES(sp)
STORE a6, 14*REGBYTES(sp)
STORE a7, 15*REGBYTES(sp)
add a0, sp, zero
jal ra, _start_trap_rust
LOAD ra, 0*REGBYTES(sp)
LOAD t0, 1*REGBYTES(sp)
LOAD t1, 2*REGBYTES(sp)
LOAD t2, 3*REGBYTES(sp)
LOAD t3, 4*REGBYTES(sp)
LOAD t4, 5*REGBYTES(sp)
LOAD t5, 6*REGBYTES(sp)
LOAD t6, 7*REGBYTES(sp)
LOAD a0, 8*REGBYTES(sp)
LOAD a1, 9*REGBYTES(sp)
LOAD a2, 10*REGBYTES(sp)
LOAD a3, 11*REGBYTES(sp)
LOAD a4, 12*REGBYTES(sp)
LOAD a5, 13*REGBYTES(sp)
LOAD a6, 14*REGBYTES(sp)
LOAD a7, 15*REGBYTES(sp)
addi sp, sp, 16*REGBYTES
#ifdef SMODE
sret
#else
mret
#endif
/* Make sure there is an abort when linking */
.section .text.abort
.globl abort
abort:
j abort