master
s 319 lines 6.44 KB
Raw
1 /*
2 * Minimal ArmV7 system boot code.
3 *
4 * Using semihosting for serial output and exit functions.
5 */
6
7 /*
8 * Semihosting interface on ARM AArch32
9 * R0 - semihosting call number
10 * R1 - semihosting parameter
11 */
12 #define semihosting_call svc 0x123456
13 #define SYS_WRITEC 0x03 /* character to debug channel */
14 #define SYS_WRITE0 0x04 /* string to debug channel */
15 #define SYS_EXIT 0x18
16
17 #define ADP_Stopped_ApplicationExit 0x20026
18 #define ADP_Stopped_InternalError 0x20024
19
20 /*
21 * Helper macro for annotating functions with elf type and size.
22 */
23 .macro endf name
24 .global \name
25 .type \name, %function
26 .size \name, . - \name
27 .endm
28
29 .section .interrupt_vector, "ax"
30 .align 5
31
32 vector_table:
33 b reset /* reset vector */
34 b undef_instr /* undefined instruction vector */
35 b software_intr /* software interrupt vector */
36 b prefetch_abort /* prefetch abort vector */
37 b data_abort /* data abort vector */
38 nop /* reserved */
39 b IRQ_handler /* IRQ vector */
40 b FIQ_handler /* FIQ vector */
41
42 endf vector_table
43
44 .text
45 __start:
46 ldr r0, =vector_table
47 mcr p15, 0, r0, c12, c0, 0 /* Set up VBAR */
48
49 ldr sp, =stack_end /* Set up the stack */
50 bl mmu_setup /* Set up the MMU */
51 bl main /* Jump to main */
52
53 endf __start
54
55 _exit:
56 cmp r0, #0
57 ite EQ // if-then-else. "EQ" is for if equal, else otherwise
58 ldreq r1, =ADP_Stopped_ApplicationExit // if r0 == 0
59 ldrne r1, =ADP_Stopped_InternalError // else
60 mov r0, #SYS_EXIT
61 semihosting_call
62
63 endf _exit
64
65 /*
66 * Helper Functions
67 */
68
69 mmu_setup:
70 /*
71 * The MMU setup for this is very simple using two stage one
72 * translations. The first 1Mb section points to the text
73 * section and the second points to the data and rss.
74 * Currently the fattest test only needs ~50k for that so we
75 * have plenty of space.
76 *
77 * The short descriptor Section format is as follows:
78 *
79 * PA[31:20] - Section Base Address
80 * NS[19] - Non-secure bit
81 * 0[18] - Section (1 for Super Section)
82 * nG[17] - Not global bit
83 * S[16] - Shareable
84 * TEX[14:12] - Memory Region Attributes
85 * AP[15, 11:10] - Access Permission Bits
86 * IMPDEF[9]
87 * Domain[8:5]
88 * XN[4] - Execute never bit
89 * C[3] - Memory Region Attributes
90 * B[2] - Memory Region Attributes
91 * 1[1]
92 * PXN[0] - Privileged Execute Never
93 *
94 * r0 - point at the table
95 * r1 - address
96 * r2 - entry
97 * r3 - common section bits
98 * r4 - scratch
99 */
100
101 /*
102 * Memory Region Bits
103 *
104 * TEX[14:12] = 000
105 * C[3] = 1
106 * B[2] = 1
107 *
108 * Outer and Inner WB, no write allocate
109 */
110 mov r3, #0
111 ldr r4, =(3 << 2)
112 orr r3, r4, r4
113
114 /* Section bit */
115 orr r3, r3, #2
116
117 /* Page table setup (identity mapping). */
118 ldr r0, =ttb
119
120 /* First block: .text/RO/execute enabled */
121 ldr r1, =.text
122 ldr r2, =0xFFF00000 /* 1MB block alignment */
123 and r2, r1, r2
124 orr r2, r2, r3 /* common bits */
125 orr r2, r2, #(1 << 15) /* AP[2] = 1 */
126 orr r2, r2, #(1 << 10) /* AP[0] = 1 => RO @ PL1 */
127
128 lsr r4, r2, #(20 - 2)
129 str r2, [r0, r4, lsl #0] /* write entry */
130
131 /* Second block: .data/RW/no execute */
132 ldr r1, =.data
133 ldr r2, =0xFFF00000 /* 1MB block alignment */
134 and r2, r1, r2
135 orr r2, r2, r3 /* common bits */
136 orr r2, r2, #(1 << 10) /* AP[0] = 1 => RW @ PL1 */
137 orr r2, r2, #(1 << 4) /* XN[4] => no execute */
138
139 lsr r4, r2, #(20 - 2)
140 str r2, [r0, r4, lsl #0] /* write entry */
141
142 /*
143 * DACR - Domain Control
144 *
145 * Enable client mode for domain 0 (we don't use any others)
146 */
147 ldr r0, =0x1
148 mcr p15, 0, r0, c3, c0, 0
149
150 /*
151 * TTCBR - Translation Table Base Control Register
152 *
153 * EAE[31] = 0, 32-bit translation, short descriptor format
154 * N[2:0] = 5 ( TTBRO uses 31:14-5 => 9 bit lookup stage )
155 */
156 ldr r0, =0x5
157 mcr p15, 0, r0, c1, c0, 2
158
159 /*
160 * TTBR0 -Translation Table Base Register 0
161 *
162 * [31:9] = Base address of table
163 *
164 * QEMU doesn't really care about the cache sharing
165 * attributes so we don't need to either.
166 */
167 ldr r0, =ttb
168 mcr p15, 0, r0, c2, c0, 0
169
170 /*
171 * SCTLR- System Control Register
172 *
173 * TE[30] = 0, exceptions to A32 state
174 * AFE[29] = 0, AP[0] is the access permissions bit
175 * EE[25] = 0, Little-endian
176 * WXN[19] = 0 = no effect, Write does not imply XN (execute never)
177 * I[12] = Instruction cachability control
178 * C[2] = Data cachability control
179 * M[0] = 1, enable stage 1 address translation for EL0/1
180 *
181 * At this point virtual memory is enabled.
182 */
183 ldr r0, =0x1005
184 mcr p15, 0, r0, c1, c0, 0
185
186 isb
187
188 mov pc, lr /* done, return to caller */
189
190 endf mmu_setup
191
192 /* Output a single character to serial port */
193 __sys_outc:
194 STMFD sp!, {r0-r1} // push r0, r1 onto stack
195 mov r1, sp
196 mov r0, #SYS_WRITEC
197 semihosting_call
198 LDMFD sp!, {r0-r1} // pop r0, r1 from stack
199 bx lr
200
201 endf __sys_outc
202
203 reset:
204 ldr r1, =reset_error
205 b exception_handler
206
207 endf reset
208
209 undef_instr:
210 ldr r1, =undef_intr_error
211 b exception_handler
212
213 endf undef_instr
214
215 software_intr:
216 ldr r1, =software_intr_error
217 b exception_handler
218
219 endf software_intr
220
221 prefetch_abort:
222 ldr r1, =prefetch_abort_error
223 b exception_handler
224
225 endf prefetch_abort
226
227 data_abort:
228 ldr r1, =data_abort_error
229 b exception_handler
230
231 endf data_abort
232
233 IRQ_handler:
234 ldr r1, =irq_error
235 b exception_handler
236
237 endf IRQ_handler
238
239 FIQ_handler:
240 ldr r1, =fiq_error
241 b exception_handler
242
243 endf FIQ_handler
244
245 /*
246 * Initiate a exit semihosting call whenever there is any exception
247 * r1 already holds the string.
248 */
249 exception_handler:
250 mov r0, #SYS_WRITE0
251 semihosting_call
252 mov r0, #SYS_EXIT
253 mov r1, #1
254 semihosting_call
255
256 endf exception_handler
257
258 /*
259 * We implement a stub raise() function which errors out as tests
260 * shouldn't trigger maths errors.
261 */
262 .global raise
263 raise:
264 mov r0, #SYS_WRITE0
265 ldr r1, =maths_error
266 semihosting_call
267 mov r0, #SYS_EXIT
268 ldr r1, =ADP_Stopped_InternalError
269 semihosting_call
270
271 endf raise
272
273 .data
274
275 .data
276
277 reset_error:
278 .ascii "Reset exception occurred.\n\0"
279
280 undef_intr_error:
281 .ascii "Undefined Instruction Exception Occurred.\n\0"
282
283 software_intr_error:
284 .ascii "Software Interrupt Occurred.\n\0"
285
286 prefetch_abort_error:
287 .ascii "Prefetch Abort Occurred.\n\0"
288
289 data_abort_error:
290 .ascii "Data Abort Occurred.\n\0"
291
292 irq_error:
293 .ascii "IRQ exception occurred.\n\0"
294
295 fiq_error:
296 .ascii "FIQ exception occurred.\n\0"
297
298 maths_error:
299 .ascii "Software maths exception.\n\0"
300
301
302 /*
303 * 1st Stage Translation table
304 * 4096 entries, indexed by [31:20]
305 * each entry covers 1Mb of address space
306 * aligned on 16kb
307 */
308 .align 15
309 ttb:
310 .space (4096 * 4), 0
311
312 .align 12
313
314 /* Space for stack */
315 .align 5
316 .section .bss
317 stack:
318 .space 65536, 0
319 stack_end: