From: Jan Kiszka <jan.kis...@siemens.com> This brings the arm64-specific bits to handle management interrupts sent via SDEI.
The pattern for processing them is derived from NMI-based injection on x86: The SDEI event can come asynchronously at any time while in EL2, EL1 or EL0. To avoid having to synchronize with running EL2, translate it into a trap that is triggered on EL1/0 reentry. We use an invalid VTCR_EL2 value for this and set the per-cpu sdei_event flag. When EL2 finds this flag set on handling the trap, it kicks off SGI_EVENT handling and restores VTCR_EL2. Signed-off-by: Jan Kiszka <jan.kis...@siemens.com> --- .../arch/arm-common/include/asm/smccc.h | 8 ++++++++ hypervisor/arch/arm64/asm-defines.c | 1 + hypervisor/arch/arm64/entry.S | 18 ++++++++++++++++++ hypervisor/arch/arm64/include/asm/entry.h | 2 ++ .../arch/arm64/include/asm/percpu_fields.h | 3 ++- hypervisor/arch/arm64/setup.c | 19 +++++++++++++++++++ hypervisor/arch/arm64/traps.c | 10 ++++++++++ 7 files changed, 60 insertions(+), 1 deletion(-) diff --git a/hypervisor/arch/arm-common/include/asm/smccc.h b/hypervisor/arch/arm-common/include/asm/smccc.h index 0d1ecd86..fdfe49a2 100644 --- a/hypervisor/arch/arm-common/include/asm/smccc.h +++ b/hypervisor/arch/arm-common/include/asm/smccc.h @@ -17,8 +17,16 @@ #define SMCCC_ARCH_WORKAROUND_1 0x80008000 #define SMCCC_ARCH_WORKAROUND_2 0x80007fff +#define SDEI_EVENT_REGISTER 0xc4000021 +#define SDEI_EVENT_ENABLE 0xc4000022 +#define SDEI_EVENT_COMPLETE 0xc4000025 +#define SDEI_EVENT_UNREGISTER 0xc4000027 +#define SDEI_PE_MASK 0xc400002b +#define SDEI_PE_UNMASK 0xc400002c #define SDEI_EVENT_SIGNAL 0xc400002f +#define SDEI_EV_HANDLED 0 + #define ARM_SMCCC_OWNER_MASK BIT_MASK(29, 24) #define ARM_SMCCC_OWNER_SHIFT 24 diff --git a/hypervisor/arch/arm64/asm-defines.c b/hypervisor/arch/arm64/asm-defines.c index 1fcffcc3..774dd145 100644 --- a/hypervisor/arch/arm64/asm-defines.c +++ b/hypervisor/arch/arm64/asm-defines.c @@ -29,6 +29,7 @@ void common(void) OFFSET(SYSCONFIG_HYPERVISOR_PHYS, jailhouse_system, hypervisor_memory.phys_start); OFFSET(PERCPU_ID_AA64MMFR0, per_cpu, id_aa64mmfr0); + OFFSET(PERCPU_SDEI_EVENT, per_cpu, sdei_event); BLANK(); DEFINE(PERCPU_STACK_END, diff --git a/hypervisor/arch/arm64/entry.S b/hypervisor/arch/arm64/entry.S index c958ea4e..3f4ee871 100644 --- a/hypervisor/arch/arm64/entry.S +++ b/hypervisor/arch/arm64/entry.S @@ -539,3 +539,21 @@ __vmreturn: dsb nsh isb .popsection + + + .globl sdei_handler +sdei_handler: + mov w0, #1 + strh w0, [x1, #PERCPU_SDEI_EVENT] + + mrs x0, vtcr_el2 + orr x0, x0, #0xff + msr vtcr_el2, x0 + isb + tlbi vmalls12e1is + + ldr x0, =SDEI_EVENT_COMPLETE + mov x1, #SDEI_EV_HANDLED + smc #0 + + b . diff --git a/hypervisor/arch/arm64/include/asm/entry.h b/hypervisor/arch/arm64/include/asm/entry.h index 335ac607..d663cbf6 100644 --- a/hypervisor/arch/arm64/include/asm/entry.h +++ b/hypervisor/arch/arm64/include/asm/entry.h @@ -20,3 +20,5 @@ void enable_mmu_el2(u64 ttbr0_el2); void __attribute__((noreturn)) shutdown_el2(struct per_cpu *cpu_data); void __attribute__((noreturn)) vmreturn(union registers *guest_regs); + +void sdei_handler(void *param); diff --git a/hypervisor/arch/arm64/include/asm/percpu_fields.h b/hypervisor/arch/arm64/include/asm/percpu_fields.h index 2afd32a8..67573fd6 100644 --- a/hypervisor/arch/arm64/include/asm/percpu_fields.h +++ b/hypervisor/arch/arm64/include/asm/percpu_fields.h @@ -12,4 +12,5 @@ #define ARCH_PERCPU_FIELDS \ ARM_PERCPU_FIELDS \ - unsigned long id_aa64mmfr0; + unsigned long id_aa64mmfr0; \ + bool sdei_event; diff --git a/hypervisor/arch/arm64/setup.c b/hypervisor/arch/arm64/setup.c index 58c90276..d8c58504 100644 --- a/hypervisor/arch/arm64/setup.c +++ b/hypervisor/arch/arm64/setup.c @@ -19,6 +19,7 @@ #include <asm/entry.h> #include <asm/irqchip.h> #include <asm/setup.h> +#include <asm/smc.h> #include <asm/smccc.h> extern u8 __trampoline_start[]; @@ -62,6 +63,19 @@ int arch_cpu_init(struct per_cpu *cpu_data) if (err) return err; + if (sdei_available) { + if (smc_arg5(SDEI_EVENT_REGISTER, 0, + (unsigned long)sdei_handler, LOCAL_CPU_BASE, + 0, 0) != ARM_SMCCC_SUCCESS) + return trace_error(-EIO); + + if (smc_arg1(SDEI_EVENT_ENABLE, 0) != ARM_SMCCC_SUCCESS) + return trace_error(-EIO); + + if (smc(SDEI_PE_UNMASK) != ARM_SMCCC_SUCCESS) + return trace_error(-EIO); + } + /* Setup guest traps */ arm_write_sysreg(HCR_EL2, hcr); @@ -99,6 +113,11 @@ void arch_shutdown_self(struct per_cpu *cpu_data) void (*shutdown_func)(struct per_cpu *) = (void (*)(struct per_cpu *))paging_hvirt2phys(shutdown_el2); + if (sdei_available) { + smc(SDEI_PE_MASK); + smc_arg1(SDEI_EVENT_UNREGISTER, 0); + } + irqchip_cpu_shutdown(&cpu_data->public); /* Free the guest */ diff --git a/hypervisor/arch/arm64/traps.c b/hypervisor/arch/arm64/traps.c index a9086c79..488dd7f8 100644 --- a/hypervisor/arch/arm64/traps.c +++ b/hypervisor/arch/arm64/traps.c @@ -73,6 +73,16 @@ static enum trap_return handle_iabt(struct trap_context *ctx) { unsigned long hpfar, hdfar; + if (this_cpu_data()->sdei_event) { + this_cpu_data()->sdei_event = false; + arm_write_sysreg(VTCR_EL2, VTCR_CELL); + isb(); + + arch_handle_sgi(SGI_EVENT, 1); + + return TRAP_HANDLED; + } + arm_read_sysreg(HPFAR_EL2, hpfar); arm_read_sysreg(FAR_EL2, hdfar); -- 2.26.2 -- You received this message because you are subscribed to the Google Groups "Jailhouse" group. To unsubscribe from this group and stop receiving emails from it, send an email to jailhouse-dev+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/jailhouse-dev/482b64b129b5506065095d4e76165bd53ee87d9e.1616139045.git.jan.kiszka%40siemens.com.