![Shanker Donthineni](/assets/img/avatar_default.png)
The ARM architecture defines the memory locations that are permitted to be accessed as the result of a speculative instruction fetch from an exception level for which all stages of translation are disabled. Specifically, the core is permitted to speculatively fetch from the 4KB region containing the current program counter 4K and next 4K. When translation is changed from enabled to disabled for the running exception level (SCTLR_ELn[M] changed from a value of 1 to 0), the Falkor core may errantly speculatively access memory locations outside of the 4KB region permitted by the architecture. The errant memory access may lead to one of the following unexpected behaviors. 1) A System Error Interrupt (SEI) being raised by the Falkor core due to the errant memory access attempting to access a region of memory that is protected by a slave-side memory protection unit. 2) Unpredictable device behavior due to a speculative read from device memory. This behavior may only occur if the instruction cache is disabled prior to or coincident with translation being changed from enabled to disabled. The conditions leading to this erratum will not occur when either of the following occur: 1) A higher exception level disables translation of a lower exception level (e.g. EL2 changing SCTLR_EL1[M] from a value of 1 to 0). 2) An exception level disabling its stage-1 translation if its stage-2 translation is enabled (e.g. EL1 changing SCTLR_EL1[M] from a value of 1 to 0 when HCR_EL2[VM] has a value of 1). To avoid the errant behavior, software must execute an ISB immediately prior to executing the MSR that will change SCTLR_ELn[M] from 1 to 0. Signed-off-by: Shanker Donthineni <shankerd@codeaurora.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
125 lines
2.9 KiB
ArmAsm
125 lines
2.9 KiB
ArmAsm
/*
|
|
* EFI entry point.
|
|
*
|
|
* Copyright (C) 2013, 2014 Red Hat, Inc.
|
|
* Author: Mark Salter <msalter@redhat.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
*/
|
|
#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)
|