diff mbox series

[RFC,08/11] kvm/arm: plumb in a basic trap harder handler

Message ID 20250617163351.2640572-9-alex.bennee@linaro.org
State New
Headers show
Series kvm/arm: trap-me-harder implementation | expand

Commit Message

Alex Bennée June 17, 2025, 4:33 p.m. UTC
Currently we do nothing but report we don't handle anything and let
KVM come to a halt.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h |  4 ++++
 target/arm/kvm-stub.c |  5 +++++
 target/arm/kvm.c      | 44 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+)
diff mbox series

Patch

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 3244e0740d..29b95bdd36 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -88,6 +88,10 @@  typedef enum {
 #define ARM_EL_ISV_SHIFT 24
 #define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
 #define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT)
+#define ARM_EL_ISS_SHIFT 0
+#define ARM_EL_ISS_LENGTH 25
+#define ARM_EL_ISS2_SHIFT 32
+#define ARM_EL_ISS2_LENGTH 24
 
 /* In the Data Abort syndrome */
 #define ARM_EL_VNCR (1 << 13)
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index 34e57fab01..765efb1848 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -60,6 +60,11 @@  void kvm_arm_add_vcpu_properties(ARMCPU *cpu)
     g_assert_not_reached();
 }
 
+int kvm_arm_get_type(MachineState *ms)
+{
+    g_assert_not_reached();
+}
+
 int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa)
 {
     g_assert_not_reached();
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index c5374d12cf..f2255cfdc8 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1414,6 +1414,43 @@  static bool kvm_arm_handle_debug(ARMCPU *cpu,
     return false;
 }
 
+/**
+ * kvm_arm_handle_hard_trap:
+ * @cpu: ARMCPU
+ * @esr: full exception state register
+ * @elr: exception link return address
+ * @far: fault address (if used)
+ *
+ * Returns: 0 if the exception has been handled, < 0 otherwise
+ */
+static int kvm_arm_handle_hard_trap(ARMCPU *cpu,
+                                    uint64_t esr,
+                                    uint64_t elr,
+                                    uint64_t far)
+{
+    CPUState *cs = CPU(cpu);
+    int esr_ec = extract64(esr, ARM_EL_EC_SHIFT, ARM_EL_EC_LENGTH);
+    int esr_iss = extract64(esr, ARM_EL_ISS_SHIFT, ARM_EL_ISS_LENGTH);
+    int esr_iss2 = extract64(esr, ARM_EL_ISS2_SHIFT, ARM_EL_ISS2_LENGTH);
+    int esr_il = extract64(esr, ARM_EL_IL_SHIFT, 1);
+
+    /*
+     * Ensure register state is synchronised
+     *
+     * This sets vcpu->vcpu_dirty which should ensure the registers
+     * are synced back to KVM before we restart.
+     */
+    kvm_cpu_synchronize_state(cs);
+
+    switch (esr_ec) {
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: unhandled EC: %x/%x/%x/%d\n",
+                __func__, esr_ec, esr_iss, esr_iss2, esr_il);
+        return -1;
+    }
+}
+
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     ARMCPU *cpu = ARM_CPU(cs);
@@ -1430,9 +1467,16 @@  int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
         ret = kvm_arm_handle_dabt_nisv(cpu, run->arm_nisv.esr_iss,
                                        run->arm_nisv.fault_ipa);
         break;
+    case KVM_EXIT_ARM_TRAP_HARDER:
+        ret = kvm_arm_handle_hard_trap(cpu,
+                                       run->arm_trap_harder.esr,
+                                       run->arm_trap_harder.elr,
+                                       run->arm_trap_harder.far);
+        break;
     default:
         qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
                       __func__, run->exit_reason);
+        ret = -1;
         break;
     }
     return ret;