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.

Reply via email to