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