@@ -71,6 +71,8 @@
#include "hw/mem/pc-dimm.h"
#include "hw/mem/nvdimm.h"
#include "hw/acpi/generic_event_device.h"
+#include "sysemu/hw_accel.h"
+#include "hw/nmi.h"
#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
@@ -690,7 +692,7 @@ static void create_gic(VirtMachineState *vms)
} else if (vms->virt) {
qemu_irq irq = qdev_get_gpio_in(vms->gic,
ppibase + ARCH_GIC_MAINT_IRQ);
- sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq);
+ sysbus_connect_irq(gicbusdev, i + 5 * smp_cpus, irq);
}
qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
@@ -704,6 +706,8 @@ static void create_gic(VirtMachineState *vms)
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+ sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_SERROR));
}
fdt_add_gic_node(vms);
@@ -2026,10 +2030,36 @@ static int virt_kvm_type(MachineState *ms, const char *type_str)
return requested_pa_size > 40 ? requested_pa_size : 0;
}
+
+static void do_inject_serror(CPUState *cpu, run_on_cpu_data data)
+{
+ VirtMachineState *vms = data.host_ptr;
+ GICv3State *gicv3;
+ GICState *gicv2;
+
+ cpu_synchronize_state(cpu);
+
+ if (vms->gic_version == 3) {
+ gicv3 = ARM_GICV3_COMMON(OBJECT(vms->gic));
+ qemu_irq_raise(gicv3->cpu[0].parent_serror);
+ } else {
+ gicv2 = ARM_GIC_COMMON(OBJECT(vms->gic));
+ qemu_irq_raise(gicv2->parent_serror[0]);
+ }
+}
+
+static void virt_inject_serror(NMIState *n, int cpu_index, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(n);
+
+ async_run_on_cpu(first_cpu, do_inject_serror, RUN_ON_CPU_HOST_PTR(vms));
+}
+
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 +2088,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_inject_serror;
}
static void virt_instance_init(Object *obj)
@@ -2141,6 +2172,7 @@ static const TypeInfo virt_machine_info = {
.instance_init = virt_instance_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
+ { TYPE_NMI },
{ }
},
};
@@ -155,6 +155,9 @@ void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->parent_vfiq[i]);
}
+ for (i = 0; i < s->num_cpu; i++) {
+ sysbus_init_irq(sbd, &s->parent_serror[i]);
+ }
if (s->virt_extn) {
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->maintenance_irq[i]);
@@ -288,6 +288,9 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->cpu[i].parent_vfiq);
}
+ for (i = 0; i < s->num_cpu; i++) {
+ sysbus_init_irq(sbd, &s->cpu[i].parent_serror);
+ }
memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s,
"gicv3_dist", 0x10000);
@@ -70,6 +70,7 @@ typedef struct GICState {
qemu_irq parent_fiq[GIC_NCPU];
qemu_irq parent_virq[GIC_NCPU];
qemu_irq parent_vfiq[GIC_NCPU];
+ qemu_irq parent_serror[GIC_NCPU];
qemu_irq maintenance_irq[GIC_NCPU];
/* GICD_CTLR; for a GIC with the security extensions the NS banked version
@@ -152,6 +152,7 @@ struct GICv3CPUState {
qemu_irq parent_fiq;
qemu_irq parent_virq;
qemu_irq parent_vfiq;
+ qemu_irq parent_serror;
qemu_irq maintenance_irq;
/* Redistributor */
This implements the backend to support HMP/QMP "nmi" command, which is used to inject NMI interrupt to crash guest for debugging purpose. As ARM architecture doesn't have NMI supported, so we're simulating the behaviour by injecting SError or data abort to guest for "virt" board. An additonal IRQ line is introduced for SError on each CPU. The IRQ line is connected to SError exception handler. The IRQ line on CPU#0 is raised when HMP/QMP "nmi" is issued to inject SError or data abort to crash guest. Note the IRQ line can be shared with other devices who want to have the capability of reporting errors in future. Signed-off-by: Gavin Shan <gshan@redhat.com> --- hw/arm/virt.c | 34 +++++++++++++++++++++++++++++- hw/intc/arm_gic_common.c | 3 +++ hw/intc/arm_gicv3_common.c | 3 +++ include/hw/intc/arm_gic_common.h | 1 + include/hw/intc/arm_gicv3_common.h | 1 + 5 files changed, 41 insertions(+), 1 deletion(-)