| /* SPDX-License-Identifier: GPL-2.0-only */ |
| /* |
| * EFI entry point. |
| * |
| * Copyright (C) 2013, 2014 Red Hat, Inc. |
| * Author: Mark Salter <msalter@redhat.com> |
| */ |
| #include <linux/linkage.h> |
| #include <linux/init.h> |
| |
| #include <asm/assembler.h> |
| |
| #define EFI_LOAD_ERROR 0x8000000000000001 |
| |
| __INIT |
| |
| /* |
| * We arrive here from the EFI boot manager with: |
| * |
| * * CPU in little-endian mode |
| * * MMU on with identity-mapped RAM |
| * * Icache and Dcache on |
| * |
| * We will most likely be running from some place other than where |
| * we want to be. The kernel image wants to be placed at TEXT_OFFSET |
| * from start of RAM. |
| */ |
| ENTRY(entry) |
| /* |
| * Create a stack frame to save FP/LR with extra space |
| * for image_addr variable passed to efi_entry(). |
| */ |
| stp x29, x30, [sp, #-32]! |
| mov x29, sp |
| |
| /* |
| * Call efi_entry to do the real work. |
| * x0 and x1 are already set up by firmware. Current runtime |
| * address of image is calculated and passed via *image_addr. |
| * |
| * unsigned long efi_entry(void *handle, |
| * efi_system_table_t *sys_table, |
| * unsigned long *image_addr) ; |
| */ |
| adr_l x8, _text |
| add x2, sp, 16 |
| str x8, [x2] |
| bl efi_entry |
| cmn x0, #1 |
| b.eq efi_load_fail |
| |
| /* |
| * efi_entry() will have copied the kernel image if necessary and we |
| * return here with device tree address in x0 and the kernel entry |
| * point stored at *image_addr. Save those values in registers which |
| * are callee preserved. |
| */ |
| mov x20, x0 // DTB address |
| ldr x0, [sp, #16] // relocated _text address |
| ldr w21, =stext_offset |
| add x21, x0, x21 |
| |
| /* |
| * Calculate size of the kernel Image (same for original and copy). |
| */ |
| adr_l x1, _text |
| adr_l x2, _edata |
| sub x1, x2, x1 |
| |
| /* |
| * Flush the copied Image to the PoC, and ensure it is not shadowed by |
| * stale icache entries from before relocation. |
| */ |
| bl __flush_dcache_area |
| ic ialluis |
| |
| /* |
| * Ensure that the rest of this function (in the original Image) is |
| * visible when the caches are disabled. The I-cache can't have stale |
| * entries for the VA range of the current image, so no maintenance is |
| * necessary. |
| */ |
| adr x0, entry |
| adr x1, entry_end |
| sub x1, x1, x0 |
| bl __flush_dcache_area |
| |
| /* Turn off Dcache and MMU */ |
| mrs x0, CurrentEL |
| cmp x0, #CurrentEL_EL2 |
| b.ne 1f |
| mrs x0, sctlr_el2 |
| bic x0, x0, #1 << 0 // clear SCTLR.M |
| bic x0, x0, #1 << 2 // clear SCTLR.C |
| pre_disable_mmu_workaround |
| msr sctlr_el2, x0 |
| isb |
| b 2f |
| 1: |
| mrs x0, sctlr_el1 |
| bic x0, x0, #1 << 0 // clear SCTLR.M |
| bic x0, x0, #1 << 2 // clear SCTLR.C |
| pre_disable_mmu_workaround |
| msr sctlr_el1, x0 |
| isb |
| 2: |
| /* Jump to kernel entry point */ |
| mov x0, x20 |
| mov x1, xzr |
| mov x2, xzr |
| mov x3, xzr |
| br x21 |
| |
| efi_load_fail: |
| mov x0, #EFI_LOAD_ERROR |
| ldp x29, x30, [sp], #32 |
| ret |
| |
| entry_end: |
| ENDPROC(entry) |