Hello again, I’m Asami. I’ve just finished 4 weeks as a GSoC student. I’m currently debugging the implementation of my main project, which is adding QEMU/AArch64 support. I can see nothing output right now when I start a QEMU with the coreboot.rom that has my implementation. It means there is something wrong before a hardware initialization has finished. In this article, I’m going to talk about what I found while debugging the bootblock for ARMv8.
Code Path of Bootblock Stage
The bootblock is executed just after CPU reset and it is almost written by assembly language. The main task is to set up a C-environment. The basic code path for ARMv8 from the beginning the bootblock to the romstage is:
- _start() at src/arch/arm64/armv8/bootblock.S
- arm64_init_cpu() at src/arch/arm64/armv8/cpu.S
- main() at srclib/bootblock.c
- run_romstage() at src/lib/prog_loaders.c
- prog_run() at src/lib/prog_ops.c
- arch_prog_run() at src/arch/arm64/boot.c
- main() at src/arch/arm64/romstage.c // The entry point of the romstage
You can use your custom
_start function instead of the common
_start function by
CONFIG_BOOTBLOCK_CUSTOM=y and adding
bootblock-y += bootblock_custom.S which is your custom assembly file.
The Reason Why Execution Stopped inside arm64_init_cpu()
I found that an execution stopped inside the arm64_init_cpu function for some reason. The line that has some problem is
mrs x22, sctlr_el3 . MRS instruction can read a system control register and store the value into a general purpose register. So this line means to store the value of SCTLR_EL3 into the X22 register.
According to the “ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile”, the purpose of SCTLR_EL3 is
Provides top level control of the system, including its memory system, at EL3. This register is part of the Other system control registers functional group.
Also, SCTLR_EL3 is accessible only from EL3 mode. EL3 is the highest privileged mode that a low-level firmware, including the secure monitor, works on it.
Next, I checked the current mode via
mrs x0, CurrentEL. CurrentEL is a register that holds the current exception level. The result of CurrentEL was 0x04, which means the program works on EL1 mode. EL1 is the mode that an operating system kernel typically described as privileged. I didn’t have the right to access SCTLR_EL3. That’s why an execution stopped.
Ideas to Solve EL3 Issue
I considered 2 solutions:
- Use only EL1 registers
- Run QEMU in EL3
Firstly, I tried to use only EL1 registers. I replaced
arm64_init_cpu_el1 that is a new function I created. Then I replaced
TLBI ALLE3 with
TLBI VMALLE1. It seems to work well but still, there was nothing output.
Secondly, I tried to run QEMU in EL3 that is enabled by
-machine flag. QEMU can work on EL2 with
-machine virtualization=on and EL3 with
-machine secure=on to enable EL3. The following command works well for me.
$ qemu-system-aarch64 -bios ./build/coreboot.rom -M virt -cpu cortex-a53 -nographic -smp 1 -machine secure=on
My mentor Raul told me the second solution. Thank you so much!