On Mon, 28 Apr 2025 15:59, Alex Bennée <alex.ben...@linaro.org> wrote: >Currently the boot.S code assumes everything starts at EL1. This will >break things like the memory test which will barf on unaligned memory >access when run at a higher level. > >Adapt the boot code to do some basic verification of the starting mode >and the minimal configuration to move to the lower exception levels. >With this we can run the memory test with: > > -M virt,secure=on > -M virt,secure=on,virtualization=on > -M virt,virtualisation=on > >If a test needs to be at a particular EL it can use the semihosting >command line to indicate the level we should execute in. > >Cc: Julian Armistead <julian.armist...@linaro.org> >Cc: Jim MacArthur <jim.macart...@linaro.org> >Signed-off-by: Alex Bennée <alex.ben...@linaro.org> > >--- >v2 > - allow tests to control the final EL we end up at >--- > tests/tcg/aarch64/Makefile.softmmu-target | 3 +- > tests/tcg/aarch64/system/boot.S | 127 +++++++++++++++++++++- > 2 files changed, 128 insertions(+), 2 deletions(-) > >diff --git a/tests/tcg/aarch64/Makefile.softmmu-target >b/tests/tcg/aarch64/Makefile.softmmu-target >index 9c52475b7a..f7a7d2b800 100644 >--- a/tests/tcg/aarch64/Makefile.softmmu-target >+++ b/tests/tcg/aarch64/Makefile.softmmu-target >@@ -68,7 +68,8 @@ run-plugin-semiconsole-with-%: semiconsole > > # vtimer test needs EL2 > QEMU_EL2_MACHINE=-machine virt,virtualization=on,gic-version=2 -cpu > cortex-a57 -smp 4 >-run-vtimer: QEMU_OPTS=$(QEMU_EL2_MACHINE) $(QEMU_BASE_ARGS) -kernel >+QEMU_EL2_BASE_ARGS=-semihosting-config >enable=on,target=native,chardev=output,arg="2" >+run-vtimer: QEMU_OPTS=$(QEMU_EL2_MACHINE) $(QEMU_EL2_BASE_ARGS) -kernel > > # Simple Record/Replay Test > .PHONY: memory-record
The insertions in boot.S have mixed spaces/tabs >diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S >index a5df9c173d..19b18bdeec 100644 >--- a/tests/tcg/aarch64/system/boot.S >+++ b/tests/tcg/aarch64/system/boot.S >@@ -16,6 +16,7 @@ > #define semihosting_call hlt 0xf000 > #define SYS_WRITEC 0x03 /* character to debug channel */ > #define SYS_WRITE0 0x04 /* string to debug channel */ >+#define SYS_GET_CMDLINE 0x15 /* get command line */ > #define SYS_EXIT 0x18 > > .align 12 >@@ -81,10 +82,129 @@ lower_a32_serror: > .error: > .string "Terminated by exception.\n" > >+ .align 8 >+.get_cmd: >+ .quad cmdline >+ .quad 128 >+ > .text > .align 4 > .global __start > __start: >+ /* >+ * The test can set the semihosting command line to the target >+ * EL needed for the test. Keep that in w11. >+ */ >+ mov x0, SYS_GET_CMDLINE >+ adr x1, .get_cmd >+ semihosting_call >+ adrp x10, cmdline >+ add x10, x10, :lo12:cmdline >+ ldrb w11, [x10] >+ cbz w11, 1f Suggested sanity check: cmp w11, #'0' b.lt curr_sp0_sync cmp w11, #'4' b.ge curr_sp0_sync >+ sub w11, w11, #'0' >+1: >+ >+ /* Determine current Exception Level */ >+ mrs x0, CurrentEL >+ lsr x0, x0, #2 /* CurrentEL[3:2] contains the current EL */ >+ >+ /* Branch based on current EL */ >+ cmp x0, #3 >+ b.eq setup_el3 >+ cmp x0, #2 >+ b.eq setup_el2 >+ cmp x0, #1 >+ b.eq at_testel /* Already at EL1, skip transition */ >+ /* Should not be at EL0 - error out */ >+ b curr_sp0_sync >+ >+setup_el3: >+ /* Ensure we trap if we get anything wrong */ >+ adr x0, vector_table >+ msr vbar_el3, x0 >+ >+ /* Does the test want to be at EL3? */ >+ cmp w11, #3 >+ beq at_testel >+ >+ /* Configure EL3 to for lower states (EL2 or EL1) */ >+ mrs x0, scr_el3 >+ orr x0, x0, #(1 << 10) /* RW = 1: EL2/EL1 execution state is >AArch64 */ >+ orr x0, x0, #(1 << 0) /* NS = 1: Non-secure state */ >+ msr scr_el3, x0 >+ >+ /* >+ * We need to check if EL2 is actually enabled via ID_AA64PFR0_EL1, >+ * otherwise we should just jump straight to EL1. >+ */ >+ mrs x0, id_aa64pfr0_el1 >+ ubfx x0, x0, #8, #4 /* Extract EL2 field (bits 11:8) */ >+ cbz x0, el2_not_present /* If field is 0 no EL2 */ >+ >+ >+ /* Prepare SPSR for exception return to EL2 */ >+ mov x0, #0x3c9 /* DAIF bits and EL2h mode (9) */ >+ msr spsr_el3, x0 >+ >+ /* Set EL2 entry point */ >+ adr x0, setup_el2 >+ msr elr_el3, x0 >+ >+ /* Return to EL2 */ >+ eret >+ nop >+ >+el2_not_present: >+ /* Initialize SCTLR_EL1 with reset value */ >+ msr sctlr_el1, xzr >+ >+ /* Set EL1 entry point */ >+ adr x0, at_testel >+ msr elr_el3, x0 >+ >+ /* Prepare SPSR for exception return to EL1h with interrupts masked */ >+ mov x0, #0x3c5 /* DAIF bits and EL1h mode (5) */ >+ msr spsr_el3, x0 >+ >+ isb /* Synchronization barrier */ >+ eret /* Jump to EL1 */ >+ >+setup_el2: >+ /* Ensure we trap if we get anything wrong */ >+ adr x0, vector_table >+ msr vbar_el2, x0 >+ >+ /* Does the test want to be at EL2? */ >+ cmp w11, #2 >+ beq at_testel >+ >+ /* Configure EL2 to allow transition to EL1 */ >+ mrs x0, hcr_el2 >+ orr x0, x0, #(1 << 31) /* RW = 1: EL1 execution state is AArch64 >*/ >+ msr hcr_el2, x0 >+ >+ /* Initialize SCTLR_EL1 with reset value */ >+ msr sctlr_el1, xzr >+ >+ /* Set EL1 entry point */ >+ adr x0, at_testel >+ msr elr_el2, x0 >+ >+ /* Prepare SPSR for exception return to EL1 */ >+ mov x0, #(0x5 << 0) /* EL1h (SPx), with interrupts disabled */ >+ msr spsr_el2, x0 >+ >+ /* Return to EL1 */ >+ eret >+ >+ nop >+ >+ /* >+ * At the target EL for the test, usually EL1. Note we still >+ * set everything up as if we were at EL1. >+ */ >+at_testel: > /* Installs a table of exception vectors to catch and handle all > exceptions by terminating the process with a diagnostic. */ > adr x0, vector_table >@@ -100,7 +220,7 @@ __start: > * maps RAM to the first Gb. The stage2 tables have two 2mb > * translation block entries covering a series of adjacent > * 4k pages. >- */ >+ */ Accidental space > > /* Stage 1 entry: indexed by IA[38:30] */ > adr x1, . /* phys address */ >@@ -233,6 +353,11 @@ __sys_outc: > ret > > .data >+ >+ .align 8 >+cmdline: >+ .space 128, 0 >+ > .align 12 > > /* Translation table >-- >2.39.5 Otherwise, Reviewed-by: Manos Pitsidianakis <manos.pitsidiana...@linaro.org>