2 * Minimal AArch64 system boot code.
4 * Copyright Linaro Ltd 2019
6 * Loosely based on the newlib/libgloss setup stubs. Using semihosting
7 * for serial output and exit functions.
11 * Semihosting interface on ARM AArch64
12 * See "Semihosting for AArch32 and AArch64 Relase 2.0" by ARM
13 * w0 - semihosting call number
14 * x1 - semihosting parameter
16 #define semihosting_call hlt 0xf000
17 #define SYS_WRITEC 0x03 /* character to debug channel */
18 #define SYS_WRITE0 0x04 /* string to debug channel */
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 */
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 */
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 */
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 */
56 /* Common vector handling for now */
83 .string "Terminated by exception.\n"
89 /* Installs a table of exception vectors to catch and handle all
90 exceptions by terminating the process with a diagnostic. */
94 /* Page table setup (identity mapping). */
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
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 */
111 /* point to stage 2 table [47:12] */
113 orr x1, x0, #3 /* ptr to stage 2 */
116 /* Stage 2 entries: indexed by IA[29:21] */
117 ldr x5, =(((1 << 9) - 1) << 21)
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) */
126 str x1, [x2] /* 1st 2mb (.text & rodata) */
128 /* Second block: .data/RW/no execute */
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) */
136 str x1, [x2] /* 2nd 2mb (.data & .bss)*/
138 /* Setup/enable the MMU. */
141 * TCR_EL1 - Translation Control Registers
143 * IPS[34:32] = 40-bit PA, 1TB
144 * TG0[14:15] = b00 => 4kb granuale
145 * ORGN0[11:10] = Outer: Normal, WB Read-Alloc No Write-Alloc Cacheable
146 * IRGN0[9:8] = Inner: Normal, WB Read-Alloc No Write-Alloc Cacheable
147 * T0SZ[5:0] = 2^(64 - 25)
149 * The size of T0SZ controls what the initial lookup level. It
150 * would be nice to start at level 2 but unfortunatly for a
151 * flat-mapping on the virt machine we need to handle IA's
152 * with at least 1gb range to see RAM. So we start with a
155 ldr x0, = (2 << 32) | 25 | (3 << 10) | (3 << 8)
158 mov x0, #0xee /* Inner/outer cacheable WB */
163 * SCTLR_EL1 - System Control Register
165 * WXN[19] = 0 = no effect, Write does not imply XN (execute never)
166 * I[12] = Instruction cachability control
167 * SA[3] = SP alignment check
168 * C[2] = Data cachability control
169 * M[0] = 1, enable stage 1 address translation for EL0/1
172 ldr x1, =0x100d /* bits I(12) SA(3) C(2) M(0) */
173 bic x0, x0, #(1 << 1) /* clear bit A(1) */
174 bic x0, x0, #(1 << 19) /* clear WXN */
175 orr x0, x0, x1 /* set bits */
182 * Enable FP registers. The standard C pre-amble will be
183 * saving these and A-profile compilers will use AdvSIMD
184 * registers unless we tell it not to.
187 orr x0, x0, #(3 << 20)
190 /* Setup some stack space and enter the test code.
191 * Assume everthing except the return value is garbage when we
192 * return, we won't need it.
195 add x0, x0, :lo12:stack_end
199 /* pass return value to sys exit */
202 ldr x0, =0x20026 /* ADP_Stopped_ApplicationExit */
203 stp x0, x1, [sp, #-16]!
213 /* Output a single character to serial port */
216 stp x0, x1, [sp, #-16]!
217 /* pass address of c on stack */
221 ldp x0, x1, [sp], #16
228 * @4k granuale: 9 bit lookup, 512 entries