qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RESEND RFC PATCH v2 2/2] target/arm: Support NMI injection


From: Gavin Shan
Subject: [RESEND RFC PATCH v2 2/2] target/arm: Support NMI injection
Date: Wed, 5 Feb 2020 22:05:41 +1100

This supports QMP/HMP "nmi" command by injecting SError interrupt to
guest, which is expected to crash with that. Currently, It's supported
on two CPU models: "host" and "max".

Signed-off-by: Gavin Shan <address@hidden>
---
 hw/arm/virt.c          | 18 ++++++++++++++++
 target/arm/cpu-qom.h   |  1 +
 target/arm/cpu.c       | 48 ++++++++++++++++++++++++++++++++++++++++++
 target/arm/cpu64.c     | 25 ++++++++++++++++++----
 target/arm/internals.h |  8 +++++++
 5 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index f788fe27d6..883861a28a 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -71,6 +71,7 @@
 #include "hw/mem/pc-dimm.h"
 #include "hw/mem/nvdimm.h"
 #include "hw/acpi/generic_event_device.h"
+#include "hw/nmi.h"
 
 #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
     static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
@@ -2026,10 +2027,25 @@ static int virt_kvm_type(MachineState *ms, const char 
*type_str)
     return requested_pa_size > 40 ? requested_pa_size : 0;
 }
 
+static void virt_nmi(NMIState *n, int cpu_index, Error **errp)
+{
+    ARMCPUClass *acc;
+    CPUState *cpu = first_cpu;
+
+    acc = ARM_CPU_GET_CLASS(OBJECT(cpu));
+    if (!acc->inject_nmi) {
+        error_setg(errp, "NMI injection not supported");
+        return;
+    }
+
+    acc->inject_nmi(cpu, errp);
+}
+
 static void virt_machine_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
+    NMIClass *nc = NMI_CLASS(oc);
 
     mc->init = machvirt_init;
     /* Start with max_cpus set to 512, which is the maximum supported by KVM.
@@ -2058,6 +2074,7 @@ static void virt_machine_class_init(ObjectClass *oc, void 
*data)
     hc->unplug_request = virt_machine_device_unplug_request_cb;
     mc->numa_mem_supported = true;
     mc->auto_enable_numa_with_memhp = true;
+    nc->nmi_monitor_handler = virt_nmi;
 }
 
 static void virt_instance_init(Object *obj)
@@ -2141,6 +2158,7 @@ static const TypeInfo virt_machine_info = {
     .instance_init = virt_instance_init,
     .interfaces = (InterfaceInfo[]) {
          { TYPE_HOTPLUG_HANDLER },
+         { TYPE_NMI },
          { }
     },
 };
diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 7f5b244bde..853f0f3ca5 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -52,6 +52,7 @@ typedef struct ARMCPUClass {
     const ARMCPUInfo *info;
     DeviceRealize parent_realize;
     void (*parent_reset)(CPUState *cpu);
+    void (*inject_nmi)(CPUState *cpu, Error **errp);
 } ARMCPUClass;
 
 typedef struct ARMCPU ARMCPU;
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 24fd77437b..f0ef315f3b 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -475,6 +475,44 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int 
interrupt_request)
     return ret;
 }
 
+#ifdef CONFIG_KVM
+static void do_inject_nmi_kvm(CPUState *cpu, run_on_cpu_data data)
+{
+    struct kvm_vcpu_events events;
+    Error **errp = data.host_ptr;
+    int ret;
+
+    if (!kvm_has_vcpu_events()) {
+        error_setg(errp, "vCPU events not supported");
+        return;
+    }
+
+    memset(&events, 0, sizeof(events));
+    events.exception.serror_pending = 1;
+    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_VCPU_EVENTS, &events);
+    if (ret) {
+        error_setg(errp, "Error to inject vCPU events");
+    }
+}
+#endif
+
+/* The guest is expected to crash once receiving the SError interrupt */
+static void do_inject_nmi(CPUState *cpu, run_on_cpu_data data)
+{
+    cpu_synchronize_state(cpu);
+
+#ifdef CONFIG_KVM
+    return do_inject_nmi_kvm(cpu, data);
+#endif
+
+    cpu_interrupt(cpu, CPU_INTERRUPT_SERROR);
+}
+
+void arm_cpu_inject_nmi(CPUState *cpu, Error **errp)
+{
+    async_run_on_cpu(cpu, do_inject_nmi, RUN_ON_CPU_HOST_PTR(errp));
+}
+
 #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
 static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 {
@@ -2759,10 +2797,20 @@ static void arm_host_initfn(Object *obj)
     arm_cpu_post_init(obj);
 }
 
+#ifdef TARGET_AARCH64
+static void arm_host_class_init(ObjectClass *oc, void *data)
+{
+    ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+
+    acc->inject_nmi = arm_cpu_inject_nmi;
+}
+#endif /* TARGET_AARCH64 */
+
 static const TypeInfo host_arm_cpu_type_info = {
     .name = TYPE_ARM_HOST_CPU,
 #ifdef TARGET_AARCH64
     .parent = TYPE_AARCH64_CPU,
+    .class_init = arm_host_class_init,
 #else
     .parent = TYPE_ARM_CPU,
 #endif
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 2d97bf45e1..66e746f66b 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -21,6 +21,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "cpu.h"
+#include "internals.h"
 #include "qemu/module.h"
 #if !defined(CONFIG_USER_ONLY)
 #include "hw/loader.h"
@@ -713,6 +714,14 @@ static void aarch64_max_initfn(Object *obj)
                         cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
 }
 
+static void aarch64_max_class_init(ObjectClass *oc, void *data)
+{
+    ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+
+    acc->inject_nmi = arm_cpu_inject_nmi;
+    acc->info = data;
+}
+
 struct ARMCPUInfo {
     const char *name;
     void (*initfn)(Object *obj);
@@ -720,10 +729,18 @@ struct ARMCPUInfo {
 };
 
 static const ARMCPUInfo aarch64_cpus[] = {
-    { .name = "cortex-a57",         .initfn = aarch64_a57_initfn },
-    { .name = "cortex-a53",         .initfn = aarch64_a53_initfn },
-    { .name = "cortex-a72",         .initfn = aarch64_a72_initfn },
-    { .name = "max",                .initfn = aarch64_max_initfn },
+    { .name = "cortex-a57",
+      .class_init = NULL,
+      .initfn = aarch64_a57_initfn },
+    { .name = "cortex-a53",
+      .class_init = NULL,
+      .initfn = aarch64_a53_initfn },
+    { .name = "cortex-a72",
+      .class_init = NULL,
+      .initfn = aarch64_a72_initfn },
+    { .name = "max",
+      .class_init = aarch64_max_class_init,
+      .initfn = aarch64_max_initfn },
     { .name = NULL }
 };
 
diff --git a/target/arm/internals.h b/target/arm/internals.h
index f5313dd3d4..6a922fbc98 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -949,6 +949,14 @@ void arm_cpu_update_virq(ARMCPU *cpu);
  */
 void arm_cpu_update_vfiq(ARMCPU *cpu);
 
+/**
+ * arm_cpu_inject_nmi: Inject SError exception
+ *
+ * Inject SError exception to trigger kernel panic inside the guest. That's
+ * the simulated behavior as to other architectures like x86.
+ */
+void arm_cpu_inject_nmi(CPUState *cpu, Error **errp);
+
 /**
  * arm_mmu_idx_el:
  * @env: The cpu environment
-- 
2.23.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]