Linux should boot in EL2 or EL1. If in EL3, jump down before handing off to Linux.
Signed-off-by: Peter Crosthwaite <[email protected]> --- hw/arm/boot.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 840f5da..f1f6365 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -35,6 +35,7 @@ typedef enum { FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */ FIXUP_BOOTREG, /* overwrite with boot register address */ FIXUP_DSB, /* overwrite with correct DSB insn for cpu */ + FIXUP_EL, /* overwrite with kernel entry EL */ FIXUP_MAX, } FixupType; @@ -46,6 +47,20 @@ typedef struct ARMInsnFixup { } ARMInsnFixup; static const ARMInsnFixup bootloader_aarch64[] = { + { 0xd5384240 }, /* mrs x0, currentel */ + { 0x7100301f }, /* cmp w0, #0xc */ + { 0x54000001 + (9 << 5) }, /* b.ne ELx_start */ +/* Jump down from EL3 to ELx */ + { 0x10000001 + (9 << 5) }, /* adr x1, ELx_start */ + { 0xd53e1100 }, /* mrs x0, scr_el3 */ + { 0xb2400000 }, /* orr x0, x0, #0x1 - SCR.NS */ + { 0xb2780000 }, /* orr x0, x0, #0x80 - SCR.HCE */ + { 0xd51e1100 }, /* msr scr_el3, x0 */ + { 0xd2807820, FIXUP_EL, 7, 2 }, /* movz x0, 0x3c1 (+ EL<<2) */ + { 0xd51e4000 }, /* msr spsr_el3, x0 */ + { 0xd51e4021 }, /* msr elr_el3, x1 */ + { 0xd69f03e0 }, /* eret */ +/* ELx_start: */ { 0x580000c0 }, /* ldr x0, arg ; Load the lower 32-bits of DTB */ { 0xaa1f03e1 }, /* mov x1, xzr */ { 0xaa1f03e2 }, /* mov x2, xzr */ @@ -141,6 +156,7 @@ static void write_bootloader(const char *name, hwaddr addr, case FIXUP_GIC_CPU_IF: case FIXUP_BOOTREG: case FIXUP_DSB: + case FIXUP_EL: insn = deposit32(insn, shift, length, fixupcontext[fixup]); break; default: @@ -583,6 +599,11 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) } fixupcontext[FIXUP_ENTRYPOINT] = entry; + fixupcontext[FIXUP_EL] = 1; + if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) { + fixupcontext[FIXUP_EL] = 2; + } + write_bootloader("bootloader", info->loader_start, primary_loader, fixupcontext); -- 2.0.1.1.gfbfc394
