/* * Boot entry point and assembler functions for aarch64 tests. * * Copyright (C) 2017, Red Hat Inc, Andrew Jones * * This work is licensed under the terms of the GNU GPL, version 2. */ #include #include #include #include #include #include #include #include #include #ifdef CONFIG_EFI #include "efi/crt0-efi-aarch64.S" #else .macro zero_range, tmp1, tmp2 9998: cmp \tmp1, \tmp2 b.eq 9997f stp xzr, xzr, [\tmp1], #16 b 9998b 9997: .endm .section .init /* * Bootloader params are in x0-x3. See kernel doc * Documentation/arm64/booting.txt */ .globl start start: /* get our base address */ adrp x4, start add x4, x4, :lo12:start /* * Update all R_AARCH64_RELATIVE relocations using the table * of Elf64_Rela entries between reloc_start/end. The build * will not emit other relocation types. * * struct Elf64_Rela { * uint64_t r_offset; * uint64_t r_info; * int64_t r_addend; * } */ adrp x5, reloc_start add x5, x5, :lo12:reloc_start adrp x6, reloc_end add x6, x6, :lo12:reloc_end 1: cmp x5, x6 b.hs 1f ldr x7, [x5] // r_offset ldr x8, [x5, #16] // r_addend add x8, x8, x4 // val = base + r_addend str x8, [x4, x7] // base[r_offset] = val add x5, x5, #24 b 1b 1: /* zero BSS */ adrp x4, bss add x4, x4, :lo12:bss adrp x5, ebss add x5, x5, :lo12:ebss zero_range x4, x5 /* zero and set up stack */ adrp x5, stacktop add x5, x5, :lo12:stacktop sub x4, x5, #THREAD_SIZE zero_range x4, x5 /* set SCTLR_EL1 to a known value */ ldr x4, =INIT_SCTLR_EL1_MMU_OFF msr sctlr_el1, x4 isb mov x4, #1 msr spsel, x4 adrp x4, stackptr add sp, x4, :lo12:stackptr /* enable FP/ASIMD and SVE */ mov x4, (3 << 20) orr x4, x4, (3 << 16) msr cpacr_el1, x4 /* set up exception handling */ bl exceptions_init /* complete setup */ adrp x1, stacktop add x1, x1, :lo12:stacktop // x1 is the base of free memory bl setup // x0 is the addr of the dtb /* run the test */ adrp x0, __argc ldr w0, [x0, :lo12:__argc] adrp x1, __argv add x1, x1, :lo12:__argv adrp x2, __environ add x2, x2, :lo12:__environ bl main bl exit b halt #endif .text /* * arm_smccc_hvc / arm_smccc_smc * * Inputs: * w0 -- function_id * x1 -- arg0 * x2 -- arg1 * x3 -- arg2 * x4 -- arg3 * x5 -- arg4 * x6 -- arg5 * x7 -- arg6 * sp -- { arg7, arg8, arg9, arg10, result } * * Outputs: * x0 -- return code * * If result pointer is not NULL: * result.r0 -- return code * result.r1 -- x1 * result.r2 -- x2 * result.r3 -- x3 * result.r4 -- x4 * result.r5 -- x5 * result.r6 -- x6 * result.r7 -- x7 * result.r8 -- x8 * result.r9 -- x9 */ .macro do_smccc_call instr /* Save x8-x11 on stack */ stp x9, x8, [sp, #-16]! stp x11, x10, [sp, #-16]! /* Load arg7 - arg10 from the stack */ ldp x8, x9, [sp, #32] ldp x10, x11, [sp, #48] \instr #0 /* Get the result address */ ldr x10, [sp, #64] cmp x10, xzr b.eq 1f stp x0, x1, [x10, #0] stp x2, x3, [x10, #16] stp x4, x5, [x10, #32] stp x6, x7, [x10, #48] stp x8, x9, [x10, #64] 1: /* Restore x8-x11 from stack */ ldp x11, x10, [sp], #16 ldp x9, x8, [sp], #16 ret .endm .globl arm_smccc_hvc arm_smccc_hvc: do_smccc_call hvc .globl arm_smccc_smc arm_smccc_smc: do_smccc_call smc get_mmu_off: adrp x0, auxinfo ldr x0, [x0, :lo12:auxinfo + 8] and x0, x0, #AUXINFO_MMU_OFF ret .globl secondary_entry secondary_entry: /* enable FP/ASIMD and SVE */ mov x0, #(3 << 20) orr x0, x0, #(3 << 16) msr cpacr_el1, x0 /* set up exception handling */ bl exceptions_init /* enable the MMU unless requested off */ bl get_mmu_off cbnz x0, 1f adrp x0, mmu_idmap ldr x0, [x0, :lo12:mmu_idmap] bl asm_mmu_enable 1: /* set the stack */ adrp x0, secondary_data ldr x0, [x0, :lo12:secondary_data] mov sp, x0 /* finish init in C code */ bl secondary_cinit /* x0 is now the entry function, run it */ blr x0 b do_idle .globl halt halt: 1: wfi b 1b /* * asm_mmu_enable * Inputs: * x0 is the base address of the translation table * Outputs: none * * Adapted from * arch/arm64/kernel/head.S * arch/arm64/mm/proc.S */ /* * Memory region attributes for LPAE: * * n = AttrIndx[2:0] * n MAIR * DEVICE_nGnRnE 000 00000000 * DEVICE_nGnRE 001 00000100 * DEVICE_GRE 010 00001100 * NORMAL_NC 011 01000100 * NORMAL 100 11111111 * NORMAL_WT 101 10111011 * DEVICE_nGRE 110 00001000 * NORMAL_TAGGED 111 11110000 */ #define MAIR(attr, mt) ((attr) << ((mt) * 8)) #if PAGE_SIZE == SZ_64K #define TCR_TG_FLAGS TCR_TG0_64K | TCR_TG1_64K #elif PAGE_SIZE == SZ_16K #define TCR_TG_FLAGS TCR_TG0_16K | TCR_TG1_16K #elif PAGE_SIZE == SZ_4K #define TCR_TG_FLAGS TCR_TG0_4K | TCR_TG1_4K #endif .globl asm_mmu_enable asm_mmu_enable: tlbi vmalle1 // invalidate I + D TLBs dsb nsh /* TCR */ ldr x1, =TCR_TxSZ(VA_BITS) | \ TCR_TG_FLAGS | \ TCR_IRGN_WBWA | TCR_ORGN_WBWA | \ TCR_SHARED | \ TCR_EPD1 mrs x2, id_aa64mmfr0_el1 bfi x1, x2, #32, #3 msr tcr_el1, x1 /* MAIR */ ldr x1, =MAIR(0x00, MT_DEVICE_nGnRnE) | \ MAIR(0x04, MT_DEVICE_nGnRE) | \ MAIR(0x0c, MT_DEVICE_GRE) | \ MAIR(0x44, MT_NORMAL_NC) | \ MAIR(0xff, MT_NORMAL) | \ MAIR(0xbb, MT_NORMAL_WT) | \ MAIR(0x08, MT_DEVICE_nGRE) | \ MAIR(0xf0, MT_NORMAL_TAGGED) msr mair_el1, x1 /* TTBR0 */ msr ttbr0_el1, x0 isb /* SCTLR */ mrs x1, sctlr_el1 orr x1, x1, SCTLR_EL1_C orr x1, x1, SCTLR_EL1_I orr x1, x1, SCTLR_EL1_M msr sctlr_el1, x1 isb ret .globl asm_mmu_disable asm_mmu_disable: mrs x0, sctlr_el1 bic x0, x0, SCTLR_EL1_M msr sctlr_el1, x0 isb /* Clean + invalidate the entire memory */ adrp x0, __phys_offset ldr x0, [x0, :lo12:__phys_offset] adrp x1, __phys_end ldr x1, [x1, :lo12:__phys_end] sub x1, x1, x0 dcache_by_line_op civac, sy, x0, x1, x2, x3 ret /* * Vectors */ .globl exceptions_init exceptions_init: adrp x4, vector_table add x4, x4, :lo12:vector_table msr vbar_el1, x4 isb ret /* * Vector stubs * Adapted from arch/arm64/kernel/entry.S * Declare as weak to allow external tests to redefine and override a * vector_stub. */ .macro vector_stub, name, vec .weak \name \name: stp x0, x1, [sp, #-S_FRAME_SIZE]! stp x2, x3, [sp, #16] stp x4, x5, [sp, #32] stp x6, x7, [sp, #48] stp x8, x9, [sp, #64] stp x10, x11, [sp, #80] stp x12, x13, [sp, #96] stp x14, x15, [sp, #112] stp x16, x17, [sp, #128] stp x18, x19, [sp, #144] stp x20, x21, [sp, #160] stp x22, x23, [sp, #176] stp x24, x25, [sp, #192] stp x26, x27, [sp, #208] stp x28, x29, [sp, #224] str x30, [sp, #S_LR] .if \vec >= 8 mrs x1, sp_el0 .else add x1, sp, #S_FRAME_SIZE .endif str x1, [sp, #S_SP] mrs x1, elr_el1 mrs x2, spsr_el1 stp x1, x2, [sp, #S_PC] /* * Save a frame pointer using the link to allow unwinding of * exceptions. */ stp x29, x1, [sp, #S_FP] add x29, sp, #S_FP mov x0, \vec mov x1, sp mrs x2, esr_el1 bl do_handle_exception ldp x1, x2, [sp, #S_PC] msr spsr_el1, x2 msr elr_el1, x1 .if \vec >= 8 ldr x1, [sp, #S_SP] msr sp_el0, x1 .endif ldr x30, [sp, #S_LR] ldp x28, x29, [sp, #224] ldp x26, x27, [sp, #208] ldp x24, x25, [sp, #192] ldp x22, x23, [sp, #176] ldp x20, x21, [sp, #160] ldp x18, x19, [sp, #144] ldp x16, x17, [sp, #128] ldp x14, x15, [sp, #112] ldp x12, x13, [sp, #96] ldp x10, x11, [sp, #80] ldp x8, x9, [sp, #64] ldp x6, x7, [sp, #48] ldp x4, x5, [sp, #32] ldp x2, x3, [sp, #16] ldp x0, x1, [sp], #S_FRAME_SIZE eret .endm .globl vector_stub_start vector_stub_start: vector_stub el1t_sync, 0 vector_stub el1t_irq, 1 vector_stub el1t_fiq, 2 vector_stub el1t_error, 3 vector_stub el1h_sync, 4 vector_stub el1h_irq, 5 vector_stub el1h_fiq, 6 vector_stub el1h_error, 7 vector_stub el0_sync_64, 8 vector_stub el0_irq_64, 9 vector_stub el0_fiq_64, 10 vector_stub el0_error_64, 11 vector_stub el0_sync_32, 12 vector_stub el0_irq_32, 13 vector_stub el0_fiq_32, 14 vector_stub el0_error_32, 15 .globl vector_stub_end vector_stub_end: .section .text.ex .macro ventry, label .align 7 b \label .endm /* * Declare as weak to allow external tests to redefine and override the * default vector table. */ .align 11 .weak vector_table vector_table: ventry el1t_sync // Synchronous EL1t ventry el1t_irq // IRQ EL1t ventry el1t_fiq // FIQ EL1t ventry el1t_error // Error EL1t ventry el1h_sync // Synchronous EL1h ventry el1h_irq // IRQ EL1h ventry el1h_fiq // FIQ EL1h ventry el1h_error // Error EL1h ventry el0_sync_64 // Synchronous 64-bit EL0 ventry el0_irq_64 // IRQ 64-bit EL0 ventry el0_fiq_64 // FIQ 64-bit EL0 ventry el0_error_64 // Error 64-bit EL0 ventry el0_sync_32 // Synchronous 32-bit EL0 ventry el0_irq_32 // IRQ 32-bit EL0 ventry el0_fiq_32 // FIQ 32-bit EL0 ventry el0_error_32 // Error 32-bit EL0