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