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 32vector_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 42endf 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 53endf __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 63endf _exit 64 65/* 66 * Helper Functions 67 */ 68 69mmu_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 190endf 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 201endf __sys_outc 202 203reset: 204 ldr r1, =reset_error 205 b exception_handler 206 207endf reset 208 209undef_instr: 210 ldr r1, =undef_intr_error 211 b exception_handler 212 213endf undef_instr 214 215software_intr: 216 ldr r1, =software_intr_error 217 b exception_handler 218 219endf software_intr 220 221prefetch_abort: 222 ldr r1, =prefetch_abort_error 223 b exception_handler 224 225endf prefetch_abort 226 227data_abort: 228 ldr r1, =data_abort_error 229 b exception_handler 230 231endf data_abort 232 233IRQ_handler: 234 ldr r1, =irq_error 235 b exception_handler 236 237endf IRQ_handler 238 239FIQ_handler: 240 ldr r1, =fiq_error 241 b exception_handler 242 243endf FIQ_handler 244 245/* 246 * Initiate a exit semihosting call whenever there is any exception 247 * r1 already holds the string. 248 */ 249exception_handler: 250 mov r0, #SYS_WRITE0 251 semihosting_call 252 mov r0, #SYS_EXIT 253 mov r1, #1 254 semihosting_call 255 256endf 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 263raise: 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 271endf raise 272 273 .data 274 275.data 276 277reset_error: 278 .ascii "Reset exception occurred.\n\0" 279 280undef_intr_error: 281 .ascii "Undefined Instruction Exception Occurred.\n\0" 282 283software_intr_error: 284 .ascii "Software Interrupt Occurred.\n\0" 285 286prefetch_abort_error: 287 .ascii "Prefetch Abort Occurred.\n\0" 288 289data_abort_error: 290 .ascii "Data Abort Occurred.\n\0" 291 292irq_error: 293 .ascii "IRQ exception occurred.\n\0" 294 295fiq_error: 296 .ascii "FIQ exception occurred.\n\0" 297 298maths_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 309ttb: 310 .space (4096 * 4), 0 311 312 .align 12 313 314 /* Space for stack */ 315 .align 5 316 .section .bss 317stack: 318 .space 65536, 0 319stack_end: 320