1/* 2 * Minimal AArch64 system boot code. 3 * 4 * Copyright Linaro Ltd 2019 5 * 6 * Loosely based on the newlib/libgloss setup stubs. Using semihosting 7 * for serial output and exit functions. 8 */ 9 10/* 11 * Semihosting interface on ARM AArch64 12 * See "Semihosting for AArch32 and AArch64 Release 2.0" by ARM 13 * w0 - semihosting call number 14 * x1 - semihosting parameter 15 */ 16#define semihosting_call hlt 0xf000 17#define SYS_WRITEC 0x03 /* character to debug channel */ 18#define SYS_WRITE0 0x04 /* string to debug channel */ 19#define SYS_EXIT 0x18 20 21 .align 12 22 23 .macro ventry label 24 .align 7 25 b \label 26 .endm 27 28vector_table: 29 /* Current EL with SP0. */ 30 ventry curr_sp0_sync /* Synchronous */ 31 ventry curr_sp0_irq /* Irq/vIRQ */ 32 ventry curr_sp0_fiq /* Fiq/vFIQ */ 33 ventry curr_sp0_serror /* SError/VSError */ 34 35 /* Current EL with SPx. */ 36 ventry curr_spx_sync /* Synchronous */ 37 ventry curr_spx_irq /* IRQ/vIRQ */ 38 ventry curr_spx_fiq /* FIQ/vFIQ */ 39 ventry curr_spx_serror /* SError/VSError */ 40 41 /* Lower EL using AArch64. */ 42 ventry lower_a64_sync /* Synchronous */ 43 ventry lower_a64_irq /* IRQ/vIRQ */ 44 ventry lower_a64_fiq /* FIQ/vFIQ */ 45 ventry lower_a64_serror /* SError/VSError */ 46 47 /* Lower EL using AArch32. */ 48 ventry lower_a32_sync /* Synchronous */ 49 ventry lower_a32_irq /* IRQ/vIRQ */ 50 ventry lower_a32_fiq /* FIQ/vFIQ */ 51 ventry lower_a32_serror /* SError/VSError */ 52 53 .text 54 .align 4 55 56 /* Common vector handling for now */ 57curr_sp0_sync: 58curr_sp0_irq: 59curr_sp0_fiq: 60curr_sp0_serror: 61curr_spx_sync: 62curr_spx_irq: 63curr_spx_fiq: 64curr_spx_serror: 65lower_a64_sync: 66lower_a64_irq: 67lower_a64_fiq: 68lower_a64_serror: 69lower_a32_sync: 70lower_a32_irq: 71lower_a32_fiq: 72lower_a32_serror: 73 mov x0, SYS_WRITE0 74 adr x1, .error 75 semihosting_call 76 mov x0, SYS_EXIT 77 mov x1, 1 78 semihosting_call 79 /* never returns */ 80 81 .section .rodata 82.error: 83 .string "Terminated by exception.\n" 84 85 .text 86 .align 4 87 .global __start 88__start: 89 /* Installs a table of exception vectors to catch and handle all 90 exceptions by terminating the process with a diagnostic. */ 91 adr x0, vector_table 92 msr vbar_el1, x0 93 94 /* Page table setup (identity mapping). */ 95 adrp x0, ttb 96 add x0, x0, :lo12:ttb 97 msr ttbr0_el1, x0 98 99 /* 100 * Setup a flat address mapping page-tables. Stage one simply 101 * maps RAM to the first Gb. The stage2 tables have two 2mb 102 * translation block entries covering a series of adjacent 103 * 4k pages. 104 */ 105 106 /* Stage 1 entry: indexed by IA[38:30] */ 107 adr x1, . /* phys address */ 108 bic x1, x1, #(1 << 30) - 1 /* 1GB alignment*/ 109 add x2, x0, x1, lsr #(30 - 3) /* offset in l1 page table */ 110 111 /* point to stage 2 table [47:12] */ 112 adrp x0, ttb_stage2 113 orr x1, x0, #3 /* ptr to stage 2 */ 114 str x1, [x2] 115 116 /* Stage 2 entries: indexed by IA[29:21] */ 117 ldr x5, =(((1 << 9) - 1) << 21) 118 119 /* First block: .text/RO/execute enabled */ 120 adr x1, . /* phys address */ 121 bic x1, x1, #(1 << 21) - 1 /* 2mb block alignment */ 122 and x4, x1, x5 /* IA[29:21] */ 123 add x2, x0, x4, lsr #(21 - 3) /* offset in l2 page table */ 124 ldr x3, =0x401 /* attr(AF, block) */ 125 orr x1, x1, x3 126 str x1, [x2] /* 1st 2mb (.text & rodata) */ 127 128 /* Second block: .data/RW/no execute */ 129 adrp x1, .data 130 add x1, x1, :lo12:.data 131 bic x1, x1, #(1 << 21) - 1 /* 2mb block alignment */ 132 and x4, x1, x5 /* IA[29:21] */ 133 add x2, x0, x4, lsr #(21 - 3) /* offset in l2 page table */ 134 ldr x3, =(3 << 53) | 0x401 /* attr(AF, NX, block) */ 135 orr x1, x1, x3 136 str x1, [x2] /* 2nd 2mb (.data & .bss)*/ 137 138 /* Third block: at 'mte_page', set in kernel.ld */ 139 adrp x1, mte_page 140 add x1, x1, :lo12:mte_page 141 bic x1, x1, #(1 << 21) - 1 142 and x4, x1, x5 143 add x2, x0, x4, lsr #(21 - 3) 144 /* attr(AF, NX, block, AttrIndx=Attr1) */ 145 ldr x3, =(3 << 53) | 0x401 | (1 << 2) 146 orr x1, x1, x3 147 str x1, [x2] 148 149 /* Setup/enable the MMU. */ 150 151 /* 152 * TCR_EL1 - Translation Control Registers 153 * 154 * IPS[34:32] = 40-bit PA, 1TB 155 * TG0[14:15] = b00 => 4kb granuale 156 * ORGN0[11:10] = Outer: Normal, WB Read-Alloc No Write-Alloc Cacheable 157 * IRGN0[9:8] = Inner: Normal, WB Read-Alloc No Write-Alloc Cacheable 158 * T0SZ[5:0] = 2^(64 - 25) 159 * 160 * The size of T0SZ controls what the initial lookup level. It 161 * would be nice to start at level 2 but unfortunately for a 162 * flat-mapping on the virt machine we need to handle IA's 163 * with at least 1gb range to see RAM. So we start with a 164 * level 1 lookup. 165 */ 166 ldr x0, = (2 << 32) | 25 | (3 << 10) | (3 << 8) 167 msr tcr_el1, x0 168 169 mov x0, #0xee /* Inner/outer cacheable WB */ 170 msr mair_el1, x0 171 isb 172 173 /* 174 * SCTLR_EL1 - System Control Register 175 * 176 * WXN[19] = 0 = no effect, Write does not imply XN (execute never) 177 * I[12] = Instruction cachability control 178 * SA[3] = SP alignment check 179 * C[2] = Data cachability control 180 * M[0] = 1, enable stage 1 address translation for EL0/1 181 */ 182 mrs x0, sctlr_el1 183 ldr x1, =0x100d /* bits I(12) SA(3) C(2) M(0) */ 184 bic x0, x0, #(1 << 1) /* clear bit A(1) */ 185 bic x0, x0, #(1 << 19) /* clear WXN */ 186 orr x0, x0, x1 /* set bits */ 187 188 dsb sy 189 msr sctlr_el1, x0 190 isb 191 192 /* 193 * Enable FP/SVE registers. The standard C pre-amble will be 194 * saving these and A-profile compilers will use AdvSIMD 195 * registers unless we tell it not to. 196 */ 197 mrs x0, cpacr_el1 198 orr x0, x0, #(3 << 20) 199 orr x0, x0, #(3 << 16) 200 msr cpacr_el1, x0 201 202 /* Setup some stack space and enter the test code. 203 * Assume everything except the return value is garbage when we 204 * return, we won't need it. 205 */ 206 adrp x0, stack_end 207 add x0, x0, :lo12:stack_end 208 mov sp, x0 209 bl main 210 211 /* pass return value to sys exit */ 212_exit: 213 mov x1, x0 214 ldr x0, =0x20026 /* ADP_Stopped_ApplicationExit */ 215 stp x0, x1, [sp, #-16]! 216 mov x1, sp 217 mov x0, SYS_EXIT 218 semihosting_call 219 /* never returns */ 220 221 /* 222 * Helper Functions 223 */ 224 225 /* Output a single character to serial port */ 226 .global __sys_outc 227__sys_outc: 228 stp x0, x1, [sp, #-16]! 229 /* pass address of c on stack */ 230 mov x1, sp 231 mov x0, SYS_WRITEC 232 semihosting_call 233 ldp x0, x1, [sp], #16 234 ret 235 236 .data 237 .align 12 238 239 /* Translation table 240 * @4k granuale: 9 bit lookup, 512 entries 241 */ 242ttb: 243 .space 4096, 0 244 245 .align 12 246ttb_stage2: 247 .space 4096, 0 248 249 .align 12 250stack: 251 .space 65536, 0 252stack_end: 253