GICD_INMIRn marks SPI as NMI. GICR_INMIR0 marks SGI and PPI as NMI. If GICR_INMIR0 or GICD_INMIRn is not migrated, the vNMI state will be lost on the destination side. Additionally, use a subsection to avoid migration failure when the remote QEMU does not have GICR_INMIR0 support. When migrating from a QEMU that saves GICR_INMIR0 or GICD_INMIRn state to one that does not, the migration will fail with a graceful error message. When migrating from a QEMU that does not save GICR_INMIR0 or GICD_INMIRn state to one that does, the migration will succeed, but the vNMI state will be lost on the destination side since the source did not save it. Sign-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- hw/intc/arm_gicv3_common.c | 33 ++++++++++++++++++++++++++++++ hw/intc/arm_gicv3_kvm.c | 27 ++++++++++++++++++++++++ hw/intc/gicv3_internal.h | 4 ++++ include/hw/intc/arm_gicv3_common.h | 4 ++++ 4 files changed, 68 insertions(+) diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 5667d9f40b..9a1fa2ff62 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -164,6 +164,24 @@ const VMStateDescription vmstate_gicv3_gicv4 = { } }; +static bool gicv3_nmi_needed(void *opaque) +{ + GICv3CPUState *cs = opaque; + + return cs->gic->nmi_support; +} + +const VMStateDescription vmstate_gicv3_gicr_nmi = { + .name = "arm_gicv3_cpu/gicr_nmi", + .version_id = 1, + .minimum_version_id = 1, + .needed = gicv3_nmi_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32(gicr_inmir0, GICv3CPUState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_gicv3_cpu = { .name = "arm_gicv3_cpu", .version_id = 1, @@ -196,6 +214,7 @@ static const VMStateDescription vmstate_gicv3_cpu = { &vmstate_gicv3_cpu_virt, &vmstate_gicv3_cpu_sre_el1, &vmstate_gicv3_gicv4, + &vmstate_gicv3_gicr_nmi, NULL } }; @@ -238,6 +257,17 @@ const VMStateDescription vmstate_gicv3_gicd_no_migration_shift_bug = { } }; +const VMStateDescription vmstate_gicv3_gicd_nmi = { + .name = "arm_gicv3/gicd_nmi", + .version_id = 1, + .minimum_version_id = 1, + .needed = gicv3_nmi_needed, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(gicd_inmir, GICv3State, GICV3_BMP_SIZE), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_gicv3 = { .name = "arm_gicv3", .version_id = 1, @@ -266,6 +296,7 @@ static const VMStateDescription vmstate_gicv3 = { }, .subsections = (const VMStateDescription * []) { &vmstate_gicv3_gicd_no_migration_shift_bug, + &vmstate_gicv3_gicd_nmi, NULL } }; @@ -554,6 +585,7 @@ static void arm_gicv3_common_reset_hold(Object *obj) cs->edge_trigger = 0xffff; cs->gicr_igrpmodr0 = 0; cs->gicr_nsacr = 0; + cs->gicr_inmir0 = 0; memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr)); cs->hppi.prio = 0xff; @@ -585,6 +617,7 @@ static void arm_gicv3_common_reset_hold(Object *obj) memset(s->gicd_ipriority, 0, sizeof(s->gicd_ipriority)); memset(s->gicd_irouter, 0, sizeof(s->gicd_irouter)); memset(s->gicd_nsacr, 0, sizeof(s->gicd_nsacr)); + memset(s->gicd_inmir, 0, sizeof(s->gicd_inmir)); /* GICD_IROUTER are UNKNOWN at reset so in theory the guest must * write these to get sane behaviour and we need not populate the * pointer cache here; however having the cache be different for diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index dd2a60fa20..ba6d09a5b9 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -397,6 +397,9 @@ static void kvm_arm_gicv3_put(GICv3State *s) reg = c->gicr_iactiver0; kvm_gicr_access(s, GICR_ISACTIVER0, ncpu, ®, true); + reg = c->gicr_inmir0; + kvm_gicr_access(s, GICR_INMIR0, ncpu, ®, true); + for (i = 0; i < GIC_INTERNAL; i += 4) { reg = c->gicr_ipriorityr[i] | (c->gicr_ipriorityr[i + 1] << 8) | @@ -561,6 +564,8 @@ static void kvm_arm_gicv3_get(GICv3State *s) c->gicr_ipendr0 = reg; kvm_gicr_access(s, GICR_ISACTIVER0, ncpu, ®, false); c->gicr_iactiver0 = reg; + kvm_gicr_access(s, GICR_INMIR0, ncpu, ®, false); + c->gicr_inmir0 = reg; for (i = 0; i < GIC_INTERNAL; i += 4) { kvm_gicr_access(s, GICR_IPRIORITYR + i, ncpu, ®, false); @@ -809,6 +814,22 @@ static void kvm_gicv3_init_cpu_reginfo(CPUState *cs) define_arm_cp_regs(ARM_CPU(cs), gicv3_cpuif_reginfo); } +static bool kvm_gicv3_check_nmi(GICv3State *s) +{ + uint32_t typer = 0; + + if (kvm_device_access(s->dev_fd, + KVM_DEV_ARM_VGIC_GRP_DIST_REGS, + KVM_VGIC_ATTR(GICD_TYPER, 0), + &typer, + false, + NULL)) { + return false; + } + + return (typer & GICD_TYPER_NMI) != 0; +} + static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) { GICv3State *s = KVM_ARM_GICV3(dev); @@ -918,6 +939,12 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES)) { qemu_add_vm_change_state_handler(vm_change_state_handler, s); } + + if (kvm_gicv3_check_nmi(s)) { + s->nmi_support = true; + } else { + s->nmi_support = false; + } } static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h index 0bed0f6e2a..938c7c5472 100644 --- a/hw/intc/gicv3_internal.h +++ b/hw/intc/gicv3_internal.h @@ -52,6 +52,7 @@ #define GICD_SGIR 0x0F00 #define GICD_CPENDSGIR 0x0F10 #define GICD_SPENDSGIR 0x0F20 +#define GICD_INMIR 0x0F80 #define GICD_IROUTER 0x6000 #define GICD_IDREGS 0xFFD0 @@ -68,6 +69,8 @@ #define GICD_CTLR_E1NWF (1U << 7) #define GICD_CTLR_RWP (1U << 31) +#define GICD_TYPER_NMI (1U << 9) + #define GICD_TYPER_LPIS_SHIFT 17 /* 16 bits EventId */ @@ -109,6 +112,7 @@ #define GICR_ICFGR1 (GICR_SGI_OFFSET + 0x0C04) #define GICR_IGRPMODR0 (GICR_SGI_OFFSET + 0x0D00) #define GICR_NSACR (GICR_SGI_OFFSET + 0x0E00) +#define GICR_INMIR0 (GICR_SGI_OFFSET + 0x0F80) /* VLPI redistributor registers, offsets from VLPI_base */ #define GICR_VPROPBASER (GICR_VLPI_OFFSET + 0x70) diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h index b5f8ba17ff..48694fd757 100644 --- a/include/hw/intc/arm_gicv3_common.h +++ b/include/hw/intc/arm_gicv3_common.h @@ -173,6 +173,7 @@ struct GICv3CPUState { uint32_t edge_trigger; /* ICFGR0 and ICFGR1 even bits */ uint32_t gicr_igrpmodr0; uint32_t gicr_nsacr; + uint32_t gicr_inmir0; uint8_t gicr_ipriorityr[GIC_INTERNAL]; /* VLPI_base page registers */ uint64_t gicr_vpropbaser; @@ -279,11 +280,14 @@ struct GICv3State { */ GICv3CPUState *gicd_irouter_target[GICV3_MAXIRQ]; uint32_t gicd_nsacr[DIV_ROUND_UP(GICV3_MAXIRQ, 16)]; + uint32_t gicd_inmir[GICV3_BMP_SIZE]; Notifier cpu_update_notifier; GICv3CPUState *cpu; /* List of all ITSes connected to this GIC */ GPtrArray *itslist; + + bool nmi_support; }; #define GICV3_BITMAP_ACCESSORS(BMP) \ -- 2.33.0
participants (1)
-
Jinqian Yang