This ensures that primary and secondary cores will have the same values for SCTLR_EL1. Signed-off-by: Joey Gouly --- arm/cstart64.S | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arm/cstart64.S b/arm/cstart64.S index 014c9c7b..dcdd1516 100644 --- a/arm/cstart64.S +++ b/arm/cstart64.S @@ -185,6 +185,11 @@ get_mmu_off: .globl secondary_entry secondary_entry: + /* set SCTLR_EL1 to a known value */ + ldr x0, =INIT_SCTLR_EL1_MMU_OFF + msr sctlr_el1, x0 + isb + /* enable FP/ASIMD and SVE */ mov x0, #(3 << 20) orr x0, x0, #(3 << 16) -- 2.25.1 EL2 is not currently supported, drop to EL1 to conitnue booting. This sets up a minimal EL2 environment. It is similar to el2_setup.h in Linux, but since kvm-unit-tests does not currently use any of the features (stage2, POE, PIE, BRBE, GCS, ...) covered by that file, only the Fine Grained Traps registers are dealt with. Signed-off-by: Joey Gouly Acked-by: Marc Zyngier --- arm/cstart64.S | 48 +++++++++++++++++++++++++++++++++++++++--- lib/arm64/asm/sysreg.h | 14 ++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/arm/cstart64.S b/arm/cstart64.S index dcdd1516..2b93f234 100644 --- a/arm/cstart64.S +++ b/arm/cstart64.S @@ -15,6 +15,46 @@ #include #include +.macro init_el, tmp + mrs \tmp, CurrentEL + cmp \tmp, CurrentEL_EL2 + b.ne 1f + /* EL2 setup */ + mrs \tmp, mpidr_el1 + msr vmpidr_el2, \tmp + mrs \tmp, midr_el1 + msr vpidr_el2, \tmp + /* clear FGT registers if supported */ + mrs \tmp, id_aa64mmfr0_el1 + ubfx \tmp, \tmp, #ID_AA64MMFR0_EL1_FGT_SHIFT, #4 + cbz \tmp, .Lskip_fgt_\@ + mov \tmp, #0 + msr_s SYS_HFGRTR_EL2, \tmp + msr_s SYS_HFGWTR_EL2, \tmp + msr_s SYS_HFGITR_EL2, \tmp + mrs \tmp, id_aa64mmfr0_el1 + ubfx \tmp, \tmp, #ID_AA64MMFR0_EL1_FGT_SHIFT, #4 + cmp \tmp, #ID_AA64MMFR0_EL1_FGT_FGT2 + bne .Lskip_fgt_\@ + mov \tmp, #0 + msr_s SYS_HFGRTR2_EL2, \tmp + msr_s SYS_HFGWTR2_EL2, \tmp + msr_s SYS_HFGITR2_EL2, \tmp +.Lskip_fgt_\@: + mov \tmp, #0 + msr cptr_el2, \tmp + ldr \tmp, =(INIT_HCR_EL2_EL1_ONLY) + msr hcr_el2, \tmp + mov \tmp, PSR_MODE_EL1t + msr spsr_el2, \tmp + adrp \tmp, 1f + add \tmp, \tmp, :lo12:1f + msr elr_el2, \tmp + eret +1: +.endm + + #ifdef CONFIG_EFI #include "efi/crt0-efi-aarch64.S" #else @@ -56,15 +96,15 @@ start: add x6, x6, :lo12:reloc_end 1: cmp x5, x6 - b.hs 1f + b.hs reloc_done ldr x7, [x5] // r_offset ldr x8, [x5, #16] // r_addend add x8, x8, x4 // val = base + r_addend str x8, [x4, x7] // base[r_offset] = val add x5, x5, #24 b 1b - -1: +reloc_done: + init_el x4 /* zero BSS */ adrp x4, bss add x4, x4, :lo12:bss @@ -185,6 +225,8 @@ get_mmu_off: .globl secondary_entry secondary_entry: + init_el x0 + /* set SCTLR_EL1 to a known value */ ldr x0, =INIT_SCTLR_EL1_MMU_OFF msr sctlr_el1, x0 diff --git a/lib/arm64/asm/sysreg.h b/lib/arm64/asm/sysreg.h index e537bb46..ed776716 100644 --- a/lib/arm64/asm/sysreg.h +++ b/lib/arm64/asm/sysreg.h @@ -77,6 +77,9 @@ asm( #define ID_AA64ISAR0_EL1_RNDR_SHIFT 60 #define ID_AA64PFR1_EL1_MTE_SHIFT 8 +#define ID_AA64MMFR0_EL1_FGT_SHIFT 56 +#define ID_AA64MMFR0_EL1_FGT_FGT2 0x2 + #define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0) #define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5) #define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0) @@ -113,6 +116,17 @@ asm( #define SCTLR_EL1_TCF0_SHIFT 38 #define SCTLR_EL1_TCF0_MASK GENMASK_ULL(39, 38) +#define HCR_EL2_RW _BITULL(31) + +#define INIT_HCR_EL2_EL1_ONLY (HCR_EL2_RW) + +#define SYS_HFGRTR_EL2 sys_reg(3, 4, 1, 1, 4) +#define SYS_HFGWTR_EL2 sys_reg(3, 4, 1, 1, 5) +#define SYS_HFGITR_EL2 sys_reg(3, 4, 1, 1, 6) +#define SYS_HFGRTR2_EL2 sys_reg(3, 4, 3, 1, 2) +#define SYS_HFGWTR2_EL2 sys_reg(3, 4, 3, 1, 3) +#define SYS_HFGITR2_EL2 sys_reg(3, 4, 3, 1, 7) + #define INIT_SCTLR_EL1_MMU_OFF \ (SCTLR_EL1_ITD | SCTLR_EL1_SED | SCTLR_EL1_EOS | \ SCTLR_EL1_TSCXT | SCTLR_EL1_EIS | SCTLR_EL1_SPAN | \ -- 2.25.1 Don't rely on the value of SCTLR_ELx when booting via EFI. Signed-off-by: Joey Gouly Acked-by: Marc Zyngier --- lib/arm/asm/setup.h | 6 ++++++ lib/arm/setup.c | 2 ++ lib/arm64/processor.c | 14 ++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h index 9f8ef82e..4e60d552 100644 --- a/lib/arm/asm/setup.h +++ b/lib/arm/asm/setup.h @@ -28,6 +28,12 @@ void setup(const void *fdt, phys_addr_t freemem_start); #include +#ifdef __aarch64__ +void setup_efi_sctlr(void); +#else +static inline void setup_efi_sctlr(void) {} +#endif + efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo); #endif diff --git a/lib/arm/setup.c b/lib/arm/setup.c index 67b5db07..49f5e0f6 100644 --- a/lib/arm/setup.c +++ b/lib/arm/setup.c @@ -349,6 +349,8 @@ efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo) { efi_status_t status; + setup_efi_sctlr(); + exceptions_init(); memregions_init(arm_mem_regions, NR_MEM_REGIONS); diff --git a/lib/arm64/processor.c b/lib/arm64/processor.c index eb93fd7c..f9fea519 100644 --- a/lib/arm64/processor.c +++ b/lib/arm64/processor.c @@ -8,6 +8,7 @@ #include #include #include +#include #include static const char *vector_names[] = { @@ -271,3 +272,16 @@ bool __mmu_enabled(void) { return read_sysreg(sctlr_el1) & SCTLR_EL1_M; } + +#ifdef CONFIG_EFI + +void setup_efi_sctlr(void) +{ + /* + * EFI exits boot services with SCTLR_ELx.M=1, so keep + * the MMU enabled. + */ + write_sysreg(INIT_SCTLR_EL1_MMU_OFF | SCTLR_EL1_M, sctlr_el1); +} + +#endif -- 2.25.1 Initialise the exception level, which may include dropping to EL1 from EL2, if VHE is not supported. Signed-off-by: Joey Gouly Acked-by: Marc Zyngier Reviewed-by: Eric Auger --- arm/efi/crt0-efi-aarch64.S | 5 +++++ lib/arm/asm/setup.h | 2 ++ lib/arm/setup.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/arm/efi/crt0-efi-aarch64.S b/arm/efi/crt0-efi-aarch64.S index 71ce2794..5632fee0 100644 --- a/arm/efi/crt0-efi-aarch64.S +++ b/arm/efi/crt0-efi-aarch64.S @@ -147,6 +147,11 @@ _start: 0: ldp x29, x30, [sp], #32 ret +.globl do_init_el +do_init_el: + init_el x16 + ret + .section .data .balign 65536 diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h index 4e60d552..bf05ffbb 100644 --- a/lib/arm/asm/setup.h +++ b/lib/arm/asm/setup.h @@ -29,8 +29,10 @@ void setup(const void *fdt, phys_addr_t freemem_start); #include #ifdef __aarch64__ +void do_init_el(void); void setup_efi_sctlr(void); #else +static inline void do_init_el(void) {} static inline void setup_efi_sctlr(void) {} #endif diff --git a/lib/arm/setup.c b/lib/arm/setup.c index 49f5e0f6..5ff40b54 100644 --- a/lib/arm/setup.c +++ b/lib/arm/setup.c @@ -349,6 +349,8 @@ efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo) { efi_status_t status; + do_init_el(); + setup_efi_sctlr(); exceptions_init(); -- 2.25.1 At EL2, with VHE: CNT{P,V}_{TVAL,CTL}_EL0 is forwarded to CNTH{P,V}_{CVAL,TVAL,CTL}_EL0. Save the hypervisor physical and virtual timer IRQ numbers from the DT/ACPI. Signed-off-by: Joey Gouly Reviewed-by: Alexandru Elisei Acked-by: Marc Zyngier Reviewed-by: Eric Auger --- arm/timer.c | 12 +++++++++--- lib/acpi.h | 2 ++ lib/arm/asm/timer.h | 11 +++++++++++ lib/arm/timer.c | 19 +++++++++++++++++-- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/arm/timer.c b/arm/timer.c index 2cb80518..43fb6d88 100644 --- a/arm/timer.c +++ b/arm/timer.c @@ -346,9 +346,15 @@ static void test_ptimer(void) static void test_init(void) { - assert(TIMER_PTIMER_IRQ != -1 && TIMER_VTIMER_IRQ != -1); - ptimer_info.irq = TIMER_PTIMER_IRQ; - vtimer_info.irq = TIMER_VTIMER_IRQ; + if (current_level() == CurrentEL_EL1) { + assert(TIMER_PTIMER_IRQ != -1 && TIMER_VTIMER_IRQ != -1); + ptimer_info.irq = TIMER_PTIMER_IRQ; + vtimer_info.irq = TIMER_VTIMER_IRQ; + } else { + assert(TIMER_HPTIMER_IRQ != -1 && TIMER_HVTIMER_IRQ != -1); + ptimer_info.irq = TIMER_HPTIMER_IRQ; + vtimer_info.irq = TIMER_HVTIMER_IRQ; + } install_exception_handler(EL1H_SYNC, ESR_EL1_EC_UNKNOWN, ptimer_unsupported_handler); ptimer_info.read_ctl(); diff --git a/lib/acpi.h b/lib/acpi.h index c330c877..66e3062d 100644 --- a/lib/acpi.h +++ b/lib/acpi.h @@ -290,6 +290,8 @@ struct acpi_table_gtdt { u64 counter_read_block_address; u32 platform_timer_count; u32 platform_timer_offset; + u32 virtual_el2_timer_interrupt; + u32 virtual_el2_timer_flags; }; /* Reset to default packing */ diff --git a/lib/arm/asm/timer.h b/lib/arm/asm/timer.h index fd8f7796..0dcebc1c 100644 --- a/lib/arm/asm/timer.h +++ b/lib/arm/asm/timer.h @@ -21,12 +21,23 @@ struct timer_state { u32 irq; u32 irq_flags; } vtimer; + struct { + u32 irq; + u32 irq_flags; + } hptimer; + struct { + u32 irq; + u32 irq_flags; + } hvtimer; }; extern struct timer_state __timer_state; #define TIMER_PTIMER_IRQ (__timer_state.ptimer.irq) #define TIMER_VTIMER_IRQ (__timer_state.vtimer.irq) +#define TIMER_HPTIMER_IRQ (__timer_state.hptimer.irq) +#define TIMER_HVTIMER_IRQ (__timer_state.hvtimer.irq) + void timer_save_state(void); #endif /* !__ASSEMBLER__ */ diff --git a/lib/arm/timer.c b/lib/arm/timer.c index ae702e41..8e36a570 100644 --- a/lib/arm/timer.c +++ b/lib/arm/timer.c @@ -38,10 +38,11 @@ static void timer_save_state_fdt(void) * secure timer irq * non-secure timer irq (ptimer) * virtual timer irq (vtimer) - * hypervisor timer irq + * hypervisor timer irq (hptimer) + * hypervisor virtual timer irq (hvtimer) */ prop = fdt_get_property(fdt, node, "interrupts", &len); - assert(prop && len == (4 * 3 * sizeof(u32))); + assert(prop && len >= (4 * 3 * sizeof(u32))); data = (u32 *) prop->data; assert(fdt32_to_cpu(data[3]) == 1 /* PPI */ ); @@ -50,6 +51,14 @@ static void timer_save_state_fdt(void) assert(fdt32_to_cpu(data[6]) == 1 /* PPI */ ); __timer_state.vtimer.irq = PPI(fdt32_to_cpu(data[7])); __timer_state.vtimer.irq_flags = fdt32_to_cpu(data[8]); + if (len == (5 * 3 * sizeof(u32))) { + assert(fdt32_to_cpu(data[9]) == 1 /* PPI */); + __timer_state.hptimer.irq = PPI(fdt32_to_cpu(data[10])); + __timer_state.hptimer.irq_flags = fdt32_to_cpu(data[11]); + assert(fdt32_to_cpu(data[12]) == 1 /* PPI */); + __timer_state.hvtimer.irq = PPI(fdt32_to_cpu(data[13])); + __timer_state.hvtimer.irq_flags = fdt32_to_cpu(data[14]); + } } #ifdef CONFIG_EFI @@ -72,6 +81,12 @@ static void timer_save_state_acpi(void) __timer_state.vtimer.irq = gtdt->virtual_timer_interrupt; __timer_state.vtimer.irq_flags = gtdt->virtual_timer_flags; + + __timer_state.hptimer.irq = gtdt->non_secure_el2_interrupt; + __timer_state.hptimer.irq_flags = gtdt->non_secure_el2_flags; + + __timer_state.hvtimer.irq = gtdt->virtual_el2_timer_interrupt; + __timer_state.hvtimer.irq_flags = gtdt->virtual_el2_timer_flags; } #else -- 2.25.1 Enable the correct (hvtimer) IRQ when at EL2. Signed-off-by: Joey Gouly Reviewed-by: Alexandru Elisei Acked-by: Marc Zyngier Reviewed-by: Eric Auger --- arm/micro-bench.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arm/micro-bench.c b/arm/micro-bench.c index 22408955..f47c5fc1 100644 --- a/arm/micro-bench.c +++ b/arm/micro-bench.c @@ -42,7 +42,7 @@ static void gic_irq_handler(struct pt_regs *regs) irq_received = true; gic_write_eoir(irqstat); - if (irqstat == TIMER_VTIMER_IRQ) { + if (irqstat == TIMER_VTIMER_IRQ || irqstat == TIMER_HVTIMER_IRQ) { write_sysreg((ARCH_TIMER_CTL_IMASK | ARCH_TIMER_CTL_ENABLE), cntv_ctl_el0); isb(); @@ -215,7 +215,11 @@ static bool timer_prep(void) install_irq_handler(EL1H_IRQ, gic_irq_handler); local_irq_enable(); - gic_enable_irq(TIMER_VTIMER_IRQ); + if (current_level() == CurrentEL_EL1) + gic_enable_irq(TIMER_VTIMER_IRQ); + else + gic_enable_irq(TIMER_HVTIMER_IRQ); + write_sysreg(ARCH_TIMER_CTL_IMASK | ARCH_TIMER_CTL_ENABLE, cntv_ctl_el0); isb(); -- 2.25.1 From: Alexandru Elisei At EL2, hvc would target the current EL, use smc so that it targets EL3. Signed-off-by: Alexandru Elisei Signed-off-by: Joey Gouly Acked-by: Marc Zyngier Reviewed-by: Eric Auger --- arm/micro-bench.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/arm/micro-bench.c b/arm/micro-bench.c index f47c5fc1..a6a78f20 100644 --- a/arm/micro-bench.c +++ b/arm/micro-bench.c @@ -282,6 +282,11 @@ static bool mmio_read_user_prep(void) return true; } +static void smc_exec(void) +{ + asm volatile("mov w0, #0x4b000000; smc #0" ::: "w0"); +} + static void mmio_read_user_exec(void) { readl(userspace_emulated_addr); @@ -300,6 +305,8 @@ static void eoi_exec(void) write_eoir(spurious_id); } +static bool exec_select(void); + struct exit_test { const char *name; bool (*prep)(void); @@ -310,7 +317,7 @@ struct exit_test { }; static struct exit_test tests[] = { - {"hvc", NULL, hvc_exec, NULL, 65536, true}, + {"hyp_call", exec_select, hvc_exec, NULL, 65536, true}, {"mmio_read_user", mmio_read_user_prep, mmio_read_user_exec, NULL, 65536, true}, {"mmio_read_vgic", NULL, mmio_read_vgic_exec, NULL, 65536, true}, {"eoi", NULL, eoi_exec, NULL, 65536, true}, @@ -320,6 +327,15 @@ static struct exit_test tests[] = { {"timer_10ms", timer_prep, timer_exec, timer_post, 256, true}, }; +static bool exec_select(void) +{ + if (current_level() == CurrentEL_EL2) + tests[0].exec = &smc_exec; + else + tests[0].exec = &hvc_exec; + return true; +} + struct ns_time { uint64_t ns; uint64_t ns_frac; -- 2.25.1 From: Alexandru Elisei Remove some hard-coded assumptions that this test is running at EL1. Signed-off-by: Alexandru Elisei Signed-off-by: Joey Gouly Acked-by: Marc Zyngier Reviewed-by: Eric Auger --- arm/selftest.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/arm/selftest.c b/arm/selftest.c index 1553ed8e..9e30ce41 100644 --- a/arm/selftest.c +++ b/arm/selftest.c @@ -232,6 +232,7 @@ static void user_psci_system_off(struct pt_regs *regs) __user_psci_system_off(); } #elif defined(__aarch64__) +static unsigned long expected_level; /* * Capture the current register state and execute an instruction @@ -276,8 +277,7 @@ static bool check_regs(struct pt_regs *regs) { unsigned i; - /* exception handlers should always run in EL1 */ - if (current_level() != CurrentEL_EL1) + if (current_level() != expected_level) return false; for (i = 0; i < ARRAY_SIZE(regs->regs); ++i) { @@ -301,7 +301,11 @@ static enum vector check_vector_prep(void) return EL0_SYNC_64; asm volatile("mrs %0, daif" : "=r" (daif) ::); - expected_regs.pstate = daif | PSR_MODE_EL1h; + expected_regs.pstate = daif; + if (current_level() == CurrentEL_EL1) + expected_regs.pstate |= PSR_MODE_EL1h; + else + expected_regs.pstate |= PSR_MODE_EL2h; return EL1H_SYNC; } @@ -317,8 +321,8 @@ static bool check_und(void) install_exception_handler(v, ESR_EL1_EC_UNKNOWN, unknown_handler); - /* try to read an el2 sysreg from el0/1 */ - test_exception("", "mrs x0, sctlr_el2", "", "x0"); + /* try to read an el3 sysreg from el0/1/2 */ + test_exception("", "mrs x0, sctlr_el3", "", "x0"); install_exception_handler(v, ESR_EL1_EC_UNKNOWN, NULL); @@ -426,6 +430,10 @@ int main(int argc, char **argv) { report_prefix_push("selftest"); +#if defined(__aarch64__) + expected_level = current_level(); +#endif + if (argc < 2) report_abort("no test specified"); -- 2.25.1 Count EL2 cycles if that's the EL kvm-unit-tests is running at! Signed-off-by: Joey Gouly Acked-by: Marc Zyngier Reviewed-by: Eric Auger --- arm/pmu.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arm/pmu.c b/arm/pmu.c index 2dc0822b..2fcec71a 100644 --- a/arm/pmu.c +++ b/arm/pmu.c @@ -121,6 +121,8 @@ static struct pmu pmu; #define PMINTENCLR __ACCESS_CP15(c9, 0, c14, 2) #define PMCCNTR64 __ACCESS_CP15_64(0, c9) +#define PMCCFILTR_EL0_DEFAULT 0 + static inline uint32_t get_id_dfr0(void) { return read_sysreg(ID_DFR0); } static inline uint32_t get_pmcr(void) { return read_sysreg(PMCR); } static inline void set_pmcr(uint32_t v) { write_sysreg(v, PMCR); } @@ -206,6 +208,9 @@ static void test_overflow_interrupt(bool overflow_at_64bits) {} #define ID_DFR0_PMU_V3_8_5 0b0110 #define ID_DFR0_PMU_IMPDEF 0b1111 +#define PMCCFILTR_EL0_NSH BIT(27) +#define PMCCFILTR_EL0_DEFAULT (current_level() == CurrentEL_EL2 ? PMCCFILTR_EL0_NSH : 0) + static inline uint32_t get_id_aa64dfr0(void) { return read_sysreg(id_aa64dfr0_el1); } static inline uint32_t get_pmcr(void) { return read_sysreg(pmcr_el0); } static inline void set_pmcr(uint32_t v) { write_sysreg(v, pmcr_el0); } @@ -246,8 +251,7 @@ static inline void precise_instrs_loop(int loop, uint32_t pmcr) #define PMCNTENSET_EL0 sys_reg(3, 3, 9, 12, 1) #define PMCNTENCLR_EL0 sys_reg(3, 3, 9, 12, 2) -#define PMEVTYPER_EXCLUDE_EL1 BIT(31) -#define PMEVTYPER_EXCLUDE_EL0 BIT(30) +#define PMEVTYPER_EXCLUDE_EL0 (BIT(30) | (current_level() == CurrentEL_EL2 ? BIT(27) : 0)) static bool is_event_supported(uint32_t n, bool warn) { @@ -1063,7 +1067,8 @@ static bool check_cycles_increase(void) /* init before event access, this test only cares about cycle count */ pmu_reset(); set_pmcntenset(1 << PMU_CYCLE_IDX); - set_pmccfiltr(0); /* count cycles in EL0, EL1, but not EL2 */ + + set_pmccfiltr(PMCCFILTR_EL0_DEFAULT); set_pmcr(get_pmcr() | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_E); isb(); @@ -1118,7 +1123,7 @@ static bool check_cpi(int cpi) /* init before event access, this test only cares about cycle count */ pmu_reset(); set_pmcntenset(1 << PMU_CYCLE_IDX); - set_pmccfiltr(0); /* count cycles in EL0, EL1, but not EL2 */ + set_pmccfiltr(PMCCFILTR_EL0_DEFAULT); if (cpi > 0) printf("Checking for CPI=%d.\n", cpi); -- 2.25.1 If VHE is supported, continue booting at EL2, otherwise continue booting at EL1. Signed-off-by: Joey Gouly Acked-by: Marc Zyngier Reviewed-by: Eric Auger --- arm/cstart64.S | 21 +++++++++++++++++---- lib/arm64/asm/sysreg.h | 5 +++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/arm/cstart64.S b/arm/cstart64.S index 2b93f234..49cf8ed6 100644 --- a/arm/cstart64.S +++ b/arm/cstart64.S @@ -15,10 +15,14 @@ #include #include +/* + * Initialise the EL used for running the tests. + * If started at EL2 and VHE is supported, EL2 is used, otherwise EL1 is used. + */ .macro init_el, tmp mrs \tmp, CurrentEL cmp \tmp, CurrentEL_EL2 - b.ne 1f + b.ne 2f /* EL2 setup */ mrs \tmp, mpidr_el1 msr vmpidr_el2, \tmp @@ -41,17 +45,26 @@ msr_s SYS_HFGWTR2_EL2, \tmp msr_s SYS_HFGITR2_EL2, \tmp .Lskip_fgt_\@: + /* check VHE is supported */ + mrs \tmp, ID_AA64MMFR1_EL1 + ubfx \tmp, \tmp, ID_AA64MMFR1_EL1_VH_SHIFT, #4 + cbz \tmp, 1f + ldr \tmp, =(INIT_HCR_EL2) + msr hcr_el2, \tmp + isb + b 2f +1: mov \tmp, #0 msr cptr_el2, \tmp ldr \tmp, =(INIT_HCR_EL2_EL1_ONLY) msr hcr_el2, \tmp mov \tmp, PSR_MODE_EL1t msr spsr_el2, \tmp - adrp \tmp, 1f - add \tmp, \tmp, :lo12:1f + adrp \tmp, 2f + add \tmp, \tmp, :lo12:2f msr elr_el2, \tmp eret -1: +2: .endm diff --git a/lib/arm64/asm/sysreg.h b/lib/arm64/asm/sysreg.h index ed776716..f2d05018 100644 --- a/lib/arm64/asm/sysreg.h +++ b/lib/arm64/asm/sysreg.h @@ -80,6 +80,8 @@ asm( #define ID_AA64MMFR0_EL1_FGT_SHIFT 56 #define ID_AA64MMFR0_EL1_FGT_FGT2 0x2 +#define ID_AA64MMFR1_EL1_VH_SHIFT 8 + #define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0) #define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5) #define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0) @@ -116,9 +118,12 @@ asm( #define SCTLR_EL1_TCF0_SHIFT 38 #define SCTLR_EL1_TCF0_MASK GENMASK_ULL(39, 38) +#define HCR_EL2_TGE _BITULL(27) #define HCR_EL2_RW _BITULL(31) +#define HCR_EL2_E2H _BITULL(34) #define INIT_HCR_EL2_EL1_ONLY (HCR_EL2_RW) +#define INIT_HCR_EL2 (HCR_EL2_TGE | HCR_EL2_E2H | HCR_EL2_RW) #define SYS_HFGRTR_EL2 sys_reg(3, 4, 1, 1, 4) #define SYS_HFGWTR_EL2 sys_reg(3, 4, 1, 1, 5) -- 2.25.1 This variable when set to y/Y will cause QEMU/kvmtool to start at EL2. Signed-off-by: Joey Gouly Acked-by: Marc Zyngier Reviewed-by: Eric Auger --- arm/run | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arm/run b/arm/run index 858333fc..dd641772 100755 --- a/arm/run +++ b/arm/run @@ -59,6 +59,10 @@ function arch_run_qemu() M+=",highmem=off" fi + if [ "$EL2" = "Y" ] || [ "$EL2" = "y" ]; then + M+=",virtualization=on" + fi + if ! $qemu $M -device '?' | grep -q virtconsole; then echo "$qemu doesn't support virtio-console for chr-testdev. Exiting." exit 2 @@ -116,6 +120,9 @@ function arch_run_kvmtool() fi command="$(timeout_cmd) $kvmtool run" + if [ "$EL2" = "Y" ] || [ "$EL2" = "y" ]; then + command+=" --nested" + fi if [ "$HOST" = "aarch64" ] && [ "$ARCH" = "arm" ]; then run_test_status $command --kernel "$@" --aarch32 else -- 2.25.1