diff -Nru qemu-2.8+dfsg/debian/changelog qemu-2.8+dfsg/debian/changelog --- qemu-2.8+dfsg/debian/changelog 2017-05-22 14:49:18.000000000 +0000 +++ qemu-2.8+dfsg/debian/changelog 2017-08-14 17:22:00.000000000 +0000 @@ -1,3 +1,9 @@ +qemu (1:2.8+dfsg-3ubuntu5) UNRELEASED; urgency=medium + + * Backport support for GICv3/vITS save/restore (LP: #1710019). + + -- dann frazier Mon, 14 Aug 2017 11:22:00 -0600 + qemu (1:2.8+dfsg-3ubuntu4) artful; urgency=medium * debian/rules: fix installation of /etc/default/qemu-kvm (LP: #1692530) diff -Nru qemu-2.8+dfsg/debian/patches/series qemu-2.8+dfsg/debian/patches/series --- qemu-2.8+dfsg/debian/patches/series 2017-05-22 14:47:29.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/series 2017-08-10 23:16:29.000000000 +0000 @@ -61,3 +61,14 @@ CVE-2017-7980-7.patch CVE-2017-7980-8.patch CVE-2017-7980-9.patch +ubuntu/kernel-Add-definitions-for-GICv3-attributes.patch +ubuntu/hw-intc-arm_gicv3_kvm-Add-ICC_SRE_EL1-register-to-vm.patch +ubuntu/hw-intc-arm_gicv3_kvm-Implement-get-put-functions.patch +ubuntu/target-arm-Add-GICv3CPUState-in-CPUARMState-struct.patch +ubuntu/hw-intc-arm_gicv3_kvm-Reset-GICv3-cpu-interface-regi.patch +ubuntu/linux-headers-Update-for-vITS-save-restore.patch +ubuntu/kvm-all-Pass-an-error-object-to-kvm_device_access.patch +ubuntu/hw-intc-arm_gicv3_its-Implement-state-save-restore.patch +ubuntu/hw-intc-arm_gicv3_kvm-Implement-pending-table-save.patch +ubuntu/migration-allow-to-prioritize-save-state-entries.patch +ubuntu/hw-intc-arm_gicv3_its-Allow-save-restore.patch diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_its-Allow-save-restore.patch qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_its-Allow-save-restore.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_its-Allow-save-restore.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_its-Allow-save-restore.patch 2017-08-11 01:35:25.000000000 +0000 @@ -0,0 +1,77 @@ +Subject: [PATCH 4/4] hw/intc/arm_gicv3_its: Allow save/restore + We change the restoration priority of both the GICv3 and ITS. The + GICv3 must be restored before the ITS and the ITS needs to be restored + before PCIe devices since it translates their MSI transactions. + . + Signed-off-by: Eric Auger + Reviewed-by: Juan Quintela + Message-id: 1497023553-18411-5-git-send-email-eric.auger@redhat.com + Signed-off-by: Peter Maydell + [ dannf: backported for compat with the migrate_add_blocker() API prior to + 'fe44dc91 migration: disallow migrate_add_blocker during migration' ] +Origin: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commit;h=252a7a6a968c279a4636a86b0559ba3a930a90b5 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Eric Auger +Last-Update: 2017-08-10 + +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_common.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_common.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_common.c +@@ -120,6 +120,7 @@ static const VMStateDescription vmstate_ + .minimum_version_id = 1, + .pre_save = gicv3_pre_save, + .post_load = gicv3_post_load, ++ .priority = MIG_PRI_GICV3, + .fields = (VMStateField[]) { + VMSTATE_UINT32(gicd_ctlr, GICv3State), + VMSTATE_UINT32_ARRAY(gicd_statusr, GICv3State, 2), +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_its_common.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_its_common.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_its_common.c +@@ -48,7 +48,7 @@ static const VMStateDescription vmstate_ + .name = "arm_gicv3_its", + .pre_save = gicv3_its_pre_save, + .post_load = gicv3_its_post_load, +- .unmigratable = true, ++ .priority = MIG_PRI_GICV3_ITS, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ctlr, GICv3ITSState), + VMSTATE_UINT32(iidr, GICv3ITSState), +Index: qemu-2.8+dfsg/include/migration/vmstate.h +=================================================================== +--- qemu-2.8+dfsg.orig/include/migration/vmstate.h ++++ qemu-2.8+dfsg/include/migration/vmstate.h +@@ -188,6 +188,8 @@ enum VMStateFlags { + + typedef enum { + MIG_PRI_DEFAULT = 0, ++ MIG_PRI_GICV3_ITS, /* Must happen before PCI devices */ ++ MIG_PRI_GICV3, /* Must happen before the ITS */ + MIG_PRI_MAX, + } MigrationPriority; + +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_its_kvm.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_its_kvm.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_its_kvm.c +@@ -100,12 +100,12 @@ static void kvm_arm_its_realize(DeviceSt + + gicv3_its_init_mmio(s, NULL); + +- /* +- * Block migration of a KVM GICv3 ITS device: the API for saving and +- * restoring the state in the kernel is not yet available +- */ +- error_setg(&s->migration_blocker, "vITS migration is not implemented"); +- migrate_add_blocker(s->migration_blocker); ++ if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_CTLR)) { ++ error_setg(&s->migration_blocker, "This operating system kernel " ++ "does not support vITS migration"); ++ migrate_add_blocker(s->migration_blocker); ++ } + + kvm_msi_use_devid = true; + kvm_gsi_direct_mapping = false; diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_its-Implement-state-save-restore.patch qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_its-Implement-state-save-restore.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_its-Implement-state-save-restore.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_its-Implement-state-save-restore.patch 2017-08-10 23:07:18.000000000 +0000 @@ -0,0 +1,219 @@ +Subject: [PATCH 2/4] hw/intc/arm_gicv3_its: Implement state save/restore + We need to handle both registers and ITS tables. While + register handling is standard, ITS table handling is more + challenging since the kernel API is devised so that the + tables are flushed into guest RAM and not in vmstate buffers. + . + Flushing the ITS tables on device pre_save() is too late + since the guest RAM is already saved at this point. + . + Table flushing needs to happen when we are sure the vcpus + are stopped and before the last dirty page saving. The + right point is RUN_STATE_FINISH_MIGRATE but sometimes the + VM gets stopped before migration launch so let's simply + flush the tables each time the VM gets stopped. + . + For regular ITS registers we just can use vmstate pre_save() + and post_load() callbacks. + . + Signed-off-by: Eric Auger + Message-id: 1497023553-18411-3-git-send-email-eric.auger@redhat.com + Reviewed-by: Peter Maydell + Signed-off-by: Peter Maydell + [ dannf: backport involved only context adjustments ] +Origin: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commit;h=cddafd8f353d2d251b1a5c6c948a577a85838582 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Eric Auger +Last-Update: 2017-08-10 + +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_its_common.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_its_common.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_its_common.c +@@ -49,6 +49,15 @@ static const VMStateDescription vmstate_ + .pre_save = gicv3_its_pre_save, + .post_load = gicv3_its_post_load, + .unmigratable = true, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT32(ctlr, GICv3ITSState), ++ VMSTATE_UINT32(iidr, GICv3ITSState), ++ VMSTATE_UINT64(cbaser, GICv3ITSState), ++ VMSTATE_UINT64(cwriter, GICv3ITSState), ++ VMSTATE_UINT64(creadr, GICv3ITSState), ++ VMSTATE_UINT64_ARRAY(baser, GICv3ITSState, 8), ++ VMSTATE_END_OF_LIST() ++ }, + }; + + static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset, +@@ -118,6 +127,7 @@ static void gicv3_its_common_reset(Devic + s->cbaser = 0; + s->cwriter = 0; + s->creadr = 0; ++ s->iidr = 0; + memset(&s->baser, 0, sizeof(s->baser)); + + gicv3_its_post_load(s, 0); +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_its_kvm.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_its_kvm.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_its_kvm.c +@@ -53,6 +53,33 @@ static int kvm_its_send_msi(GICv3ITSStat + return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi); + } + ++/** ++ * vm_change_state_handler - VM change state callback aiming at flushing ++ * ITS tables into guest RAM ++ * ++ * The tables get flushed to guest RAM whenever the VM gets stopped. ++ */ ++static void vm_change_state_handler(void *opaque, int running, ++ RunState state) ++{ ++ GICv3ITSState *s = (GICv3ITSState *)opaque; ++ Error *err = NULL; ++ int ret; ++ ++ if (running) { ++ return; ++ } ++ ++ ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, ++ KVM_DEV_ARM_ITS_SAVE_TABLES, NULL, true, &err); ++ if (err) { ++ error_report_err(err); ++ } ++ if (ret < 0 && ret != -EFAULT) { ++ abort(); ++ } ++} ++ + static void kvm_arm_its_realize(DeviceState *dev, Error **errp) + { + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); +@@ -83,6 +110,8 @@ static void kvm_arm_its_realize(DeviceSt + kvm_msi_use_devid = true; + kvm_gsi_direct_mapping = false; + kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); ++ ++ qemu_add_vm_change_state_handler(vm_change_state_handler, s); + } + + static void kvm_arm_its_init(Object *obj) +@@ -96,6 +125,80 @@ static void kvm_arm_its_init(Object *obj + &error_abort); + } + ++/** ++ * kvm_arm_its_pre_save - handles the saving of ITS registers. ++ * ITS tables are flushed into guest RAM separately and earlier, ++ * through the VM change state handler, since at the moment pre_save() ++ * is called, the guest RAM has already been saved. ++ */ ++static void kvm_arm_its_pre_save(GICv3ITSState *s) ++{ ++ int i; ++ ++ for (i = 0; i < 8; i++) { ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_BASER + i * 8, &s->baser[i], false, ++ &error_abort); ++ } ++ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_CTLR, &s->ctlr, false, &error_abort); ++ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_CBASER, &s->cbaser, false, &error_abort); ++ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_CREADR, &s->creadr, false, &error_abort); ++ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_CWRITER, &s->cwriter, false, &error_abort); ++ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_IIDR, &s->iidr, false, &error_abort); ++} ++ ++/** ++ * kvm_arm_its_post_load - Restore both the ITS registers and tables ++ */ ++static void kvm_arm_its_post_load(GICv3ITSState *s) ++{ ++ int i; ++ ++ if (!s->iidr) { ++ return; ++ } ++ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_IIDR, &s->iidr, true, &error_abort); ++ ++ /* ++ * must be written before GITS_CREADR since GITS_CBASER write ++ * access resets GITS_CREADR. ++ */ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_CBASER, &s->cbaser, true, &error_abort); ++ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_CREADR, &s->creadr, true, &error_abort); ++ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_CWRITER, &s->cwriter, true, &error_abort); ++ ++ ++ for (i = 0; i < 8; i++) { ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_BASER + i * 8, &s->baser[i], true, ++ &error_abort); ++ } ++ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, ++ KVM_DEV_ARM_ITS_RESTORE_TABLES, NULL, true, ++ &error_abort); ++ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, ++ GITS_CTLR, &s->ctlr, true, &error_abort); ++} ++ + static void kvm_arm_its_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); +@@ -103,6 +206,8 @@ static void kvm_arm_its_class_init(Objec + + dc->realize = kvm_arm_its_realize; + icc->send_msi = kvm_its_send_msi; ++ icc->pre_save = kvm_arm_its_pre_save; ++ icc->post_load = kvm_arm_its_post_load; + } + + static const TypeInfo kvm_arm_its_info = { +Index: qemu-2.8+dfsg/include/hw/intc/arm_gicv3_its_common.h +=================================================================== +--- qemu-2.8+dfsg.orig/include/hw/intc/arm_gicv3_its_common.h ++++ qemu-2.8+dfsg/include/hw/intc/arm_gicv3_its_common.h +@@ -28,6 +28,13 @@ + #define ITS_TRANS_SIZE 0x10000 + #define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE) + ++#define GITS_CTLR 0x0 ++#define GITS_IIDR 0x4 ++#define GITS_CBASER 0x80 ++#define GITS_CWRITER 0x88 ++#define GITS_CREADR 0x90 ++#define GITS_BASER 0x100 ++ + struct GICv3ITSState { + SysBusDevice parent_obj; + +@@ -43,6 +50,7 @@ struct GICv3ITSState { + + /* Registers */ + uint32_t ctlr; ++ uint32_t iidr; + uint64_t cbaser; + uint64_t cwriter; + uint64_t creadr; diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Add-ICC_SRE_EL1-register-to-vm.patch qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Add-ICC_SRE_EL1-register-to-vm.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Add-ICC_SRE_EL1-register-to-vm.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Add-ICC_SRE_EL1-register-to-vm.patch 2017-08-10 21:58:20.000000000 +0000 @@ -0,0 +1,83 @@ +Subject: [PATCH 1/4] hw/intc/arm_gicv3_kvm: Add ICC_SRE_EL1 register to vmstate + To Save and Restore ICC_SRE_EL1 register introduce vmstate + subsection and load only if non-zero. + Also initialize icc_sre_el1 with to 0x7 in pre_load + function. + . + Signed-off-by: Vijaya Kumar K + Reviewed-by: Peter Maydell + Reviewed-by: Eric Auger + Message-id: 1487850673-26455-3-git-send-email-vijay.kilari@gmail.com + Signed-off-by: Peter Maydell + [ dannf: backport involved only context adjustments ] +Origin: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commit;h=6692aac41119906409dfa634ecbe3ef1634b5e5c +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Vijaya Kumar K +Last-Update: 2017-08-10 + +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_common.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_common.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_common.c +@@ -49,6 +49,38 @@ static int gicv3_post_load(void *opaque, + return 0; + } + ++static int icc_sre_el1_reg_pre_load(void *opaque) ++{ ++ GICv3CPUState *cs = opaque; ++ ++ /* ++ * If the sre_el1 subsection is not transferred this ++ * means SRE_EL1 is 0x7 (which might not be the same as ++ * our reset value). ++ */ ++ cs->icc_sre_el1 = 0x7; ++ return 0; ++} ++ ++static bool icc_sre_el1_reg_needed(void *opaque) ++{ ++ GICv3CPUState *cs = opaque; ++ ++ return cs->icc_sre_el1 != 7; ++} ++ ++const VMStateDescription vmstate_gicv3_cpu_sre_el1 = { ++ .name = "arm_gicv3_cpu/sre_el1", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_load = icc_sre_el1_reg_pre_load, ++ .needed = icc_sre_el1_reg_needed, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT64(icc_sre_el1, GICv3CPUState), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + static const VMStateDescription vmstate_gicv3_cpu = { + .name = "arm_gicv3_cpu", + .version_id = 1, +@@ -75,6 +107,10 @@ static const VMStateDescription vmstate_ + VMSTATE_UINT64_ARRAY(icc_igrpen, GICv3CPUState, 3), + VMSTATE_UINT64(icc_ctlr_el3, GICv3CPUState), + VMSTATE_END_OF_LIST() ++ }, ++ .subsections = (const VMStateDescription * []) { ++ &vmstate_gicv3_cpu_sre_el1, ++ NULL + } + }; + +Index: qemu-2.8+dfsg/include/hw/intc/arm_gicv3_common.h +=================================================================== +--- qemu-2.8+dfsg.orig/include/hw/intc/arm_gicv3_common.h ++++ qemu-2.8+dfsg/include/hw/intc/arm_gicv3_common.h +@@ -166,6 +166,7 @@ struct GICv3CPUState { + uint8_t gicr_ipriorityr[GIC_INTERNAL]; + + /* CPU interface */ ++ uint64_t icc_sre_el1; + uint64_t icc_ctlr_el1[2]; + uint64_t icc_pmr_el1; + uint64_t icc_bpr[3]; diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Implement-get-put-functions.patch qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Implement-get-put-functions.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Implement-get-put-functions.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Implement-get-put-functions.patch 2017-08-10 22:07:12.000000000 +0000 @@ -0,0 +1,663 @@ +Subject: [PATCH 2/4] hw/intc/arm_gicv3_kvm: Implement get/put functions + This actually implements pre_save and post_load methods for in-kernel + vGICv3. + . + Signed-off-by: Pavel Fedin + Signed-off-by: Peter Maydell + Reviewed-by: Peter Maydell + Signed-off-by: Vijaya Kumar K + Message-id: 1487850673-26455-4-git-send-email-vijay.kilari@gmail.com + [PMM: + * use decimal, not 0bnnn + * fixed typo in names of ICC_APR0R_EL1 and ICC_AP1R_EL1 + * completely rearranged the get and put functions to read and write + the state in a natural order, rather than mixing distributor and + redistributor state together] + Signed-off-by: Vijaya Kumar K + [Vijay: + * Update macro KVM_VGIC_ATTR + * Use 32 bit access for gicd and gicr + * GICD_IROUTER, GICD_TYPER, GICR_PROPBASER and GICR_PENDBASER reg + access are changed from 64-bit to 32-bit access + * Add ICC_SRE_EL1 save and restore + * Dropped translate_fn mechanism and coded functions to handle + save and restore of edge_trigger and priority + * Number of APnR register saved/restored based on number of + priority bits supported] + Reviewed-by: Peter Maydell + [ dannf: backported for compat with the migrate_add_blocker() API prior to + 'fe44dc91 migration: disallow migrate_add_blocker during migration' ] +Origin: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commit;h=367b9f527becdd20ddf116e17a3c0c2bbc486920 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Vijaya Kumar K +Last-Update: 2017-08-10 + +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_kvm.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_kvm.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_kvm.c +@@ -23,8 +23,10 @@ + #include "qapi/error.h" + #include "hw/intc/arm_gicv3_common.h" + #include "hw/sysbus.h" ++#include "qemu/error-report.h" + #include "sysemu/kvm.h" + #include "kvm_arm.h" ++#include "gicv3_internal.h" + #include "vgic_common.h" + #include "migration/migration.h" + +@@ -44,6 +46,32 @@ + #define KVM_ARM_GICV3_GET_CLASS(obj) \ + OBJECT_GET_CLASS(KVMARMGICv3Class, (obj), TYPE_KVM_ARM_GICV3) + ++#define KVM_DEV_ARM_VGIC_SYSREG(op0, op1, crn, crm, op2) \ ++ (ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \ ++ ARM64_SYS_REG_SHIFT_MASK(op1, OP1) | \ ++ ARM64_SYS_REG_SHIFT_MASK(crn, CRN) | \ ++ ARM64_SYS_REG_SHIFT_MASK(crm, CRM) | \ ++ ARM64_SYS_REG_SHIFT_MASK(op2, OP2)) ++ ++#define ICC_PMR_EL1 \ ++ KVM_DEV_ARM_VGIC_SYSREG(3, 0, 4, 6, 0) ++#define ICC_BPR0_EL1 \ ++ KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 8, 3) ++#define ICC_AP0R_EL1(n) \ ++ KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 8, 4 | n) ++#define ICC_AP1R_EL1(n) \ ++ KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 9, n) ++#define ICC_BPR1_EL1 \ ++ KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 3) ++#define ICC_CTLR_EL1 \ ++ KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 4) ++#define ICC_SRE_EL1 \ ++ KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 5) ++#define ICC_IGRPEN0_EL1 \ ++ KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 6) ++#define ICC_IGRPEN1_EL1 \ ++ KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 7) ++ + typedef struct KVMARMGICv3Class { + ARMGICv3CommonClass parent_class; + DeviceRealize parent_realize; +@@ -57,16 +85,523 @@ static void kvm_arm_gicv3_set_irq(void * + kvm_arm_gic_set_irq(s->num_irq, irq, level); + } + ++#define KVM_VGIC_ATTR(reg, typer) \ ++ ((typer & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) | (reg)) ++ ++static inline void kvm_gicd_access(GICv3State *s, int offset, ++ uint32_t *val, bool write) ++{ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, ++ KVM_VGIC_ATTR(offset, 0), ++ val, write); ++} ++ ++static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, ++ uint32_t *val, bool write) ++{ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, ++ KVM_VGIC_ATTR(offset, s->cpu[cpu].gicr_typer), ++ val, write); ++} ++ ++static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, ++ uint64_t *val, bool write) ++{ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, ++ KVM_VGIC_ATTR(reg, s->cpu[cpu].gicr_typer), ++ val, write); ++} ++ ++static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, ++ uint32_t *val, bool write) ++{ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO, ++ KVM_VGIC_ATTR(irq, s->cpu[cpu].gicr_typer) | ++ (VGIC_LEVEL_INFO_LINE_LEVEL << ++ KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT), ++ val, write); ++} ++ ++/* Loop through each distributor IRQ related register; since bits ++ * corresponding to SPIs and PPIs are RAZ/WI when affinity routing ++ * is enabled, we skip those. ++ */ ++#define for_each_dist_irq_reg(_irq, _max, _field_width) \ ++ for (_irq = GIC_INTERNAL; _irq < _max; _irq += (32 / _field_width)) ++ ++static void kvm_dist_get_priority(GICv3State *s, uint32_t offset, uint8_t *bmp) ++{ ++ uint32_t reg, *field; ++ int irq; ++ ++ field = (uint32_t *)bmp; ++ for_each_dist_irq_reg(irq, s->num_irq, 8) { ++ kvm_gicd_access(s, offset, ®, false); ++ *field = reg; ++ offset += 4; ++ field++; ++ } ++} ++ ++static void kvm_dist_put_priority(GICv3State *s, uint32_t offset, uint8_t *bmp) ++{ ++ uint32_t reg, *field; ++ int irq; ++ ++ field = (uint32_t *)bmp; ++ for_each_dist_irq_reg(irq, s->num_irq, 8) { ++ reg = *field; ++ kvm_gicd_access(s, offset, ®, true); ++ offset += 4; ++ field++; ++ } ++} ++ ++static void kvm_dist_get_edge_trigger(GICv3State *s, uint32_t offset, ++ uint32_t *bmp) ++{ ++ uint32_t reg; ++ int irq; ++ ++ for_each_dist_irq_reg(irq, s->num_irq, 2) { ++ kvm_gicd_access(s, offset, ®, false); ++ reg = half_unshuffle32(reg >> 1); ++ if (irq % 32 != 0) { ++ reg = (reg << 16); ++ } ++ *gic_bmp_ptr32(bmp, irq) |= reg; ++ offset += 4; ++ } ++} ++ ++static void kvm_dist_put_edge_trigger(GICv3State *s, uint32_t offset, ++ uint32_t *bmp) ++{ ++ uint32_t reg; ++ int irq; ++ ++ for_each_dist_irq_reg(irq, s->num_irq, 2) { ++ reg = *gic_bmp_ptr32(bmp, irq); ++ if (irq % 32 != 0) { ++ reg = (reg & 0xffff0000) >> 16; ++ } else { ++ reg = reg & 0xffff; ++ } ++ reg = half_shuffle32(reg) << 1; ++ kvm_gicd_access(s, offset, ®, true); ++ offset += 4; ++ } ++} ++ ++static void kvm_gic_get_line_level_bmp(GICv3State *s, uint32_t *bmp) ++{ ++ uint32_t reg; ++ int irq; ++ ++ for_each_dist_irq_reg(irq, s->num_irq, 1) { ++ kvm_gic_line_level_access(s, irq, 0, ®, false); ++ *gic_bmp_ptr32(bmp, irq) = reg; ++ } ++} ++ ++static void kvm_gic_put_line_level_bmp(GICv3State *s, uint32_t *bmp) ++{ ++ uint32_t reg; ++ int irq; ++ ++ for_each_dist_irq_reg(irq, s->num_irq, 1) { ++ reg = *gic_bmp_ptr32(bmp, irq); ++ kvm_gic_line_level_access(s, irq, 0, ®, true); ++ } ++} ++ ++/* Read a bitmap register group from the kernel VGIC. */ ++static void kvm_dist_getbmp(GICv3State *s, uint32_t offset, uint32_t *bmp) ++{ ++ uint32_t reg; ++ int irq; ++ ++ for_each_dist_irq_reg(irq, s->num_irq, 1) { ++ kvm_gicd_access(s, offset, ®, false); ++ *gic_bmp_ptr32(bmp, irq) = reg; ++ offset += 4; ++ } ++} ++ ++static void kvm_dist_putbmp(GICv3State *s, uint32_t offset, ++ uint32_t clroffset, uint32_t *bmp) ++{ ++ uint32_t reg; ++ int irq; ++ ++ for_each_dist_irq_reg(irq, s->num_irq, 1) { ++ /* If this bitmap is a set/clear register pair, first write to the ++ * clear-reg to clear all bits before using the set-reg to write ++ * the 1 bits. ++ */ ++ if (clroffset != 0) { ++ reg = 0; ++ kvm_gicd_access(s, clroffset, ®, true); ++ } ++ reg = *gic_bmp_ptr32(bmp, irq); ++ kvm_gicd_access(s, offset, ®, true); ++ offset += 4; ++ } ++} ++ ++static void kvm_arm_gicv3_check(GICv3State *s) ++{ ++ uint32_t reg; ++ uint32_t num_irq; ++ ++ /* Sanity checking s->num_irq */ ++ kvm_gicd_access(s, GICD_TYPER, ®, false); ++ num_irq = ((reg & 0x1f) + 1) * 32; ++ ++ if (num_irq < s->num_irq) { ++ error_report("Model requests %u IRQs, but kernel supports max %u", ++ s->num_irq, num_irq); ++ abort(); ++ } ++} ++ + static void kvm_arm_gicv3_put(GICv3State *s) + { +- /* TODO */ +- DPRINTF("Cannot put kernel gic state, no kernel interface\n"); ++ uint32_t regl, regh, reg; ++ uint64_t reg64, redist_typer; ++ int ncpu, i; ++ ++ kvm_arm_gicv3_check(s); ++ ++ kvm_gicr_access(s, GICR_TYPER, 0, ®l, false); ++ kvm_gicr_access(s, GICR_TYPER + 4, 0, ®h, false); ++ redist_typer = ((uint64_t)regh << 32) | regl; ++ ++ reg = s->gicd_ctlr; ++ kvm_gicd_access(s, GICD_CTLR, ®, true); ++ ++ if (redist_typer & GICR_TYPER_PLPIS) { ++ /* Set base addresses before LPIs are enabled by GICR_CTLR write */ ++ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ GICv3CPUState *c = &s->cpu[ncpu]; ++ ++ reg64 = c->gicr_propbaser; ++ regl = (uint32_t)reg64; ++ kvm_gicr_access(s, GICR_PROPBASER, ncpu, ®l, true); ++ regh = (uint32_t)(reg64 >> 32); ++ kvm_gicr_access(s, GICR_PROPBASER + 4, ncpu, ®h, true); ++ ++ reg64 = c->gicr_pendbaser; ++ if (!c->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) { ++ /* Setting PTZ is advised if LPIs are disabled, to reduce ++ * GIC initialization time. ++ */ ++ reg64 |= GICR_PENDBASER_PTZ; ++ } ++ regl = (uint32_t)reg64; ++ kvm_gicr_access(s, GICR_PENDBASER, ncpu, ®l, true); ++ regh = (uint32_t)(reg64 >> 32); ++ kvm_gicr_access(s, GICR_PENDBASER + 4, ncpu, ®h, true); ++ } ++ } ++ ++ /* Redistributor state (one per CPU) */ ++ ++ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ GICv3CPUState *c = &s->cpu[ncpu]; ++ ++ reg = c->gicr_ctlr; ++ kvm_gicr_access(s, GICR_CTLR, ncpu, ®, true); ++ ++ reg = c->gicr_statusr[GICV3_NS]; ++ kvm_gicr_access(s, GICR_STATUSR, ncpu, ®, true); ++ ++ reg = c->gicr_waker; ++ kvm_gicr_access(s, GICR_WAKER, ncpu, ®, true); ++ ++ reg = c->gicr_igroupr0; ++ kvm_gicr_access(s, GICR_IGROUPR0, ncpu, ®, true); ++ ++ reg = ~0; ++ kvm_gicr_access(s, GICR_ICENABLER0, ncpu, ®, true); ++ reg = c->gicr_ienabler0; ++ kvm_gicr_access(s, GICR_ISENABLER0, ncpu, ®, true); ++ ++ /* Restore config before pending so we treat level/edge correctly */ ++ reg = half_shuffle32(c->edge_trigger >> 16) << 1; ++ kvm_gicr_access(s, GICR_ICFGR1, ncpu, ®, true); ++ ++ reg = c->level; ++ kvm_gic_line_level_access(s, 0, ncpu, ®, true); ++ ++ reg = ~0; ++ kvm_gicr_access(s, GICR_ICPENDR0, ncpu, ®, true); ++ reg = c->gicr_ipendr0; ++ kvm_gicr_access(s, GICR_ISPENDR0, ncpu, ®, true); ++ ++ reg = ~0; ++ kvm_gicr_access(s, GICR_ICACTIVER0, ncpu, ®, true); ++ reg = c->gicr_iactiver0; ++ kvm_gicr_access(s, GICR_ISACTIVER0, ncpu, ®, true); ++ ++ for (i = 0; i < GIC_INTERNAL; i += 4) { ++ reg = c->gicr_ipriorityr[i] | ++ (c->gicr_ipriorityr[i + 1] << 8) | ++ (c->gicr_ipriorityr[i + 2] << 16) | ++ (c->gicr_ipriorityr[i + 3] << 24); ++ kvm_gicr_access(s, GICR_IPRIORITYR + i, ncpu, ®, true); ++ } ++ } ++ ++ /* Distributor state (shared between all CPUs */ ++ reg = s->gicd_statusr[GICV3_NS]; ++ kvm_gicd_access(s, GICD_STATUSR, ®, true); ++ ++ /* s->enable bitmap -> GICD_ISENABLERn */ ++ kvm_dist_putbmp(s, GICD_ISENABLER, GICD_ICENABLER, s->enabled); ++ ++ /* s->group bitmap -> GICD_IGROUPRn */ ++ kvm_dist_putbmp(s, GICD_IGROUPR, 0, s->group); ++ ++ /* Restore targets before pending to ensure the pending state is set on ++ * the appropriate CPU interfaces in the kernel ++ */ ++ ++ /* s->gicd_irouter[irq] -> GICD_IROUTERn ++ * We can't use kvm_dist_put() here because the registers are 64-bit ++ */ ++ for (i = GIC_INTERNAL; i < s->num_irq; i++) { ++ uint32_t offset; ++ ++ offset = GICD_IROUTER + (sizeof(uint32_t) * i); ++ reg = (uint32_t)s->gicd_irouter[i]; ++ kvm_gicd_access(s, offset, ®, true); ++ ++ offset = GICD_IROUTER + (sizeof(uint32_t) * i) + 4; ++ reg = (uint32_t)(s->gicd_irouter[i] >> 32); ++ kvm_gicd_access(s, offset, ®, true); ++ } ++ ++ /* s->trigger bitmap -> GICD_ICFGRn ++ * (restore configuration registers before pending IRQs so we treat ++ * level/edge correctly) ++ */ ++ kvm_dist_put_edge_trigger(s, GICD_ICFGR, s->edge_trigger); ++ ++ /* s->level bitmap -> line_level */ ++ kvm_gic_put_line_level_bmp(s, s->level); ++ ++ /* s->pending bitmap -> GICD_ISPENDRn */ ++ kvm_dist_putbmp(s, GICD_ISPENDR, GICD_ICPENDR, s->pending); ++ ++ /* s->active bitmap -> GICD_ISACTIVERn */ ++ kvm_dist_putbmp(s, GICD_ISACTIVER, GICD_ICACTIVER, s->active); ++ ++ /* s->gicd_ipriority[] -> GICD_IPRIORITYRn */ ++ kvm_dist_put_priority(s, GICD_IPRIORITYR, s->gicd_ipriority); ++ ++ /* CPU Interface state (one per CPU) */ ++ ++ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ GICv3CPUState *c = &s->cpu[ncpu]; ++ int num_pri_bits; ++ ++ kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, true); ++ kvm_gicc_access(s, ICC_CTLR_EL1, ncpu, ++ &c->icc_ctlr_el1[GICV3_NS], true); ++ kvm_gicc_access(s, ICC_IGRPEN0_EL1, ncpu, ++ &c->icc_igrpen[GICV3_G0], true); ++ kvm_gicc_access(s, ICC_IGRPEN1_EL1, ncpu, ++ &c->icc_igrpen[GICV3_G1NS], true); ++ kvm_gicc_access(s, ICC_PMR_EL1, ncpu, &c->icc_pmr_el1, true); ++ kvm_gicc_access(s, ICC_BPR0_EL1, ncpu, &c->icc_bpr[GICV3_G0], true); ++ kvm_gicc_access(s, ICC_BPR1_EL1, ncpu, &c->icc_bpr[GICV3_G1NS], true); ++ ++ num_pri_bits = ((c->icc_ctlr_el1[GICV3_NS] & ++ ICC_CTLR_EL1_PRIBITS_MASK) >> ++ ICC_CTLR_EL1_PRIBITS_SHIFT) + 1; ++ ++ switch (num_pri_bits) { ++ case 7: ++ reg64 = c->icc_apr[GICV3_G0][3]; ++ kvm_gicc_access(s, ICC_AP0R_EL1(3), ncpu, ®64, true); ++ reg64 = c->icc_apr[GICV3_G0][2]; ++ kvm_gicc_access(s, ICC_AP0R_EL1(2), ncpu, ®64, true); ++ case 6: ++ reg64 = c->icc_apr[GICV3_G0][1]; ++ kvm_gicc_access(s, ICC_AP0R_EL1(1), ncpu, ®64, true); ++ default: ++ reg64 = c->icc_apr[GICV3_G0][0]; ++ kvm_gicc_access(s, ICC_AP0R_EL1(0), ncpu, ®64, true); ++ } ++ ++ switch (num_pri_bits) { ++ case 7: ++ reg64 = c->icc_apr[GICV3_G1NS][3]; ++ kvm_gicc_access(s, ICC_AP1R_EL1(3), ncpu, ®64, true); ++ reg64 = c->icc_apr[GICV3_G1NS][2]; ++ kvm_gicc_access(s, ICC_AP1R_EL1(2), ncpu, ®64, true); ++ case 6: ++ reg64 = c->icc_apr[GICV3_G1NS][1]; ++ kvm_gicc_access(s, ICC_AP1R_EL1(1), ncpu, ®64, true); ++ default: ++ reg64 = c->icc_apr[GICV3_G1NS][0]; ++ kvm_gicc_access(s, ICC_AP1R_EL1(0), ncpu, ®64, true); ++ } ++ } + } + + static void kvm_arm_gicv3_get(GICv3State *s) + { +- /* TODO */ +- DPRINTF("Cannot get kernel gic state, no kernel interface\n"); ++ uint32_t regl, regh, reg; ++ uint64_t reg64, redist_typer; ++ int ncpu, i; ++ ++ kvm_arm_gicv3_check(s); ++ ++ kvm_gicr_access(s, GICR_TYPER, 0, ®l, false); ++ kvm_gicr_access(s, GICR_TYPER + 4, 0, ®h, false); ++ redist_typer = ((uint64_t)regh << 32) | regl; ++ ++ kvm_gicd_access(s, GICD_CTLR, ®, false); ++ s->gicd_ctlr = reg; ++ ++ /* Redistributor state (one per CPU) */ ++ ++ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ GICv3CPUState *c = &s->cpu[ncpu]; ++ ++ kvm_gicr_access(s, GICR_CTLR, ncpu, ®, false); ++ c->gicr_ctlr = reg; ++ ++ kvm_gicr_access(s, GICR_STATUSR, ncpu, ®, false); ++ c->gicr_statusr[GICV3_NS] = reg; ++ ++ kvm_gicr_access(s, GICR_WAKER, ncpu, ®, false); ++ c->gicr_waker = reg; ++ ++ kvm_gicr_access(s, GICR_IGROUPR0, ncpu, ®, false); ++ c->gicr_igroupr0 = reg; ++ kvm_gicr_access(s, GICR_ISENABLER0, ncpu, ®, false); ++ c->gicr_ienabler0 = reg; ++ kvm_gicr_access(s, GICR_ICFGR1, ncpu, ®, false); ++ c->edge_trigger = half_unshuffle32(reg >> 1) << 16; ++ kvm_gic_line_level_access(s, 0, ncpu, ®, false); ++ c->level = reg; ++ kvm_gicr_access(s, GICR_ISPENDR0, ncpu, ®, false); ++ c->gicr_ipendr0 = reg; ++ kvm_gicr_access(s, GICR_ISACTIVER0, ncpu, ®, false); ++ c->gicr_iactiver0 = reg; ++ ++ for (i = 0; i < GIC_INTERNAL; i += 4) { ++ kvm_gicr_access(s, GICR_IPRIORITYR + i, ncpu, ®, false); ++ c->gicr_ipriorityr[i] = extract32(reg, 0, 8); ++ c->gicr_ipriorityr[i + 1] = extract32(reg, 8, 8); ++ c->gicr_ipriorityr[i + 2] = extract32(reg, 16, 8); ++ c->gicr_ipriorityr[i + 3] = extract32(reg, 24, 8); ++ } ++ } ++ ++ if (redist_typer & GICR_TYPER_PLPIS) { ++ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ GICv3CPUState *c = &s->cpu[ncpu]; ++ ++ kvm_gicr_access(s, GICR_PROPBASER, ncpu, ®l, false); ++ kvm_gicr_access(s, GICR_PROPBASER + 4, ncpu, ®h, false); ++ c->gicr_propbaser = ((uint64_t)regh << 32) | regl; ++ ++ kvm_gicr_access(s, GICR_PENDBASER, ncpu, ®l, false); ++ kvm_gicr_access(s, GICR_PENDBASER + 4, ncpu, ®h, false); ++ c->gicr_pendbaser = ((uint64_t)regh << 32) | regl; ++ } ++ } ++ ++ /* Distributor state (shared between all CPUs */ ++ ++ kvm_gicd_access(s, GICD_STATUSR, ®, false); ++ s->gicd_statusr[GICV3_NS] = reg; ++ ++ /* GICD_IGROUPRn -> s->group bitmap */ ++ kvm_dist_getbmp(s, GICD_IGROUPR, s->group); ++ ++ /* GICD_ISENABLERn -> s->enabled bitmap */ ++ kvm_dist_getbmp(s, GICD_ISENABLER, s->enabled); ++ ++ /* Line level of irq */ ++ kvm_gic_get_line_level_bmp(s, s->level); ++ /* GICD_ISPENDRn -> s->pending bitmap */ ++ kvm_dist_getbmp(s, GICD_ISPENDR, s->pending); ++ ++ /* GICD_ISACTIVERn -> s->active bitmap */ ++ kvm_dist_getbmp(s, GICD_ISACTIVER, s->active); ++ ++ /* GICD_ICFGRn -> s->trigger bitmap */ ++ kvm_dist_get_edge_trigger(s, GICD_ICFGR, s->edge_trigger); ++ ++ /* GICD_IPRIORITYRn -> s->gicd_ipriority[] */ ++ kvm_dist_get_priority(s, GICD_IPRIORITYR, s->gicd_ipriority); ++ ++ /* GICD_IROUTERn -> s->gicd_irouter[irq] */ ++ for (i = GIC_INTERNAL; i < s->num_irq; i++) { ++ uint32_t offset; ++ ++ offset = GICD_IROUTER + (sizeof(uint32_t) * i); ++ kvm_gicd_access(s, offset, ®l, false); ++ offset = GICD_IROUTER + (sizeof(uint32_t) * i) + 4; ++ kvm_gicd_access(s, offset, ®h, false); ++ s->gicd_irouter[i] = ((uint64_t)regh << 32) | regl; ++ } ++ ++ /***************************************************************** ++ * CPU Interface(s) State ++ */ ++ ++ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ GICv3CPUState *c = &s->cpu[ncpu]; ++ int num_pri_bits; ++ ++ kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, false); ++ kvm_gicc_access(s, ICC_CTLR_EL1, ncpu, ++ &c->icc_ctlr_el1[GICV3_NS], false); ++ kvm_gicc_access(s, ICC_IGRPEN0_EL1, ncpu, ++ &c->icc_igrpen[GICV3_G0], false); ++ kvm_gicc_access(s, ICC_IGRPEN1_EL1, ncpu, ++ &c->icc_igrpen[GICV3_G1NS], false); ++ kvm_gicc_access(s, ICC_PMR_EL1, ncpu, &c->icc_pmr_el1, false); ++ kvm_gicc_access(s, ICC_BPR0_EL1, ncpu, &c->icc_bpr[GICV3_G0], false); ++ kvm_gicc_access(s, ICC_BPR1_EL1, ncpu, &c->icc_bpr[GICV3_G1NS], false); ++ num_pri_bits = ((c->icc_ctlr_el1[GICV3_NS] & ++ ICC_CTLR_EL1_PRIBITS_MASK) >> ++ ICC_CTLR_EL1_PRIBITS_SHIFT) + 1; ++ ++ switch (num_pri_bits) { ++ case 7: ++ kvm_gicc_access(s, ICC_AP0R_EL1(3), ncpu, ®64, false); ++ c->icc_apr[GICV3_G0][3] = reg64; ++ kvm_gicc_access(s, ICC_AP0R_EL1(2), ncpu, ®64, false); ++ c->icc_apr[GICV3_G0][2] = reg64; ++ case 6: ++ kvm_gicc_access(s, ICC_AP0R_EL1(1), ncpu, ®64, false); ++ c->icc_apr[GICV3_G0][1] = reg64; ++ default: ++ kvm_gicc_access(s, ICC_AP0R_EL1(0), ncpu, ®64, false); ++ c->icc_apr[GICV3_G0][0] = reg64; ++ } ++ ++ switch (num_pri_bits) { ++ case 7: ++ kvm_gicc_access(s, ICC_AP1R_EL1(3), ncpu, ®64, false); ++ c->icc_apr[GICV3_G1NS][3] = reg64; ++ kvm_gicc_access(s, ICC_AP1R_EL1(2), ncpu, ®64, false); ++ c->icc_apr[GICV3_G1NS][2] = reg64; ++ case 6: ++ kvm_gicc_access(s, ICC_AP1R_EL1(1), ncpu, ®64, false); ++ c->icc_apr[GICV3_G1NS][1] = reg64; ++ default: ++ kvm_gicc_access(s, ICC_AP1R_EL1(0), ncpu, ®64, false); ++ c->icc_apr[GICV3_G1NS][0] = reg64; ++ } ++ } + } + + static void kvm_arm_gicv3_reset(DeviceState *dev) +@@ -77,6 +612,12 @@ static void kvm_arm_gicv3_reset(DeviceSt + DPRINTF("Reset\n"); + + kgc->parent_reset(dev); ++ ++ if (s->migration_blocker) { ++ DPRINTF("Cannot put kernel gic state, no kernel interface\n"); ++ return; ++ } ++ + kvm_arm_gicv3_put(s); + } + +@@ -122,13 +663,6 @@ static void kvm_arm_gicv3_realize(Device + kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd); + +- /* Block migration of a KVM GICv3 device: the API for saving and restoring +- * the state in the kernel is not yet finalised in the kernel or +- * implemented in QEMU. +- */ +- error_setg(&s->migration_blocker, "vGICv3 migration is not implemented"); +- migrate_add_blocker(s->migration_blocker); +- + if (kvm_has_gsi_routing()) { + /* set up irq routing */ + kvm_init_irq_routing(kvm_state); +@@ -140,6 +674,13 @@ static void kvm_arm_gicv3_realize(Device + + kvm_irqchip_commit_routes(kvm_state); + } ++ ++ if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, ++ GICD_CTLR)) { ++ error_setg(&s->migration_blocker, "This operating system kernel does " ++ "not support vGICv3 migration"); ++ migrate_add_blocker(s->migration_blocker); ++ } + } + + static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) +Index: qemu-2.8+dfsg/hw/intc/gicv3_internal.h +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/gicv3_internal.h ++++ qemu-2.8+dfsg/hw/intc/gicv3_internal.h +@@ -138,6 +138,7 @@ + #define ICC_CTLR_EL1_EOIMODE (1U << 1) + #define ICC_CTLR_EL1_PMHE (1U << 6) + #define ICC_CTLR_EL1_PRIBITS_SHIFT 8 ++#define ICC_CTLR_EL1_PRIBITS_MASK (7U << ICC_CTLR_EL1_PRIBITS_SHIFT) + #define ICC_CTLR_EL1_IDBITS_SHIFT 11 + #define ICC_CTLR_EL1_SEIS (1U << 14) + #define ICC_CTLR_EL1_A3V (1U << 15) diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Implement-pending-table-save.patch qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Implement-pending-table-save.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Implement-pending-table-save.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Implement-pending-table-save.patch 2017-08-10 23:32:16.000000000 +0000 @@ -0,0 +1,77 @@ +Subject: [PATCH 3/4] hw/intc/arm_gicv3_kvm: Implement pending table save + . + This patch adds the flush of the LPI pending bits into the + redistributor pending tables. This happens on VM stop. + . + There is no explicit restore as the tables are implicitly sync'ed + on ITS table restore and on LPI enable at redistributor level. + . + Signed-off-by: Eric Auger + Message-id: 1497023553-18411-4-git-send-email-eric.auger@redhat.com + Reviewed-by: Peter Maydell + Signed-off-by: Peter Maydell + [ dannf: backport involved only context adjustments ] +Origin: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commit;h=d5aa0c229ab5d46c1a4ff497553671cd46486749 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Eric Auger +Last-Update: 2017-08-10 + +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_kvm.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_kvm.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_kvm.c +@@ -25,6 +25,7 @@ + #include "hw/sysbus.h" + #include "qemu/error-report.h" + #include "sysemu/kvm.h" ++#include "sysemu/sysemu.h" + #include "kvm_arm.h" + #include "gicv3_internal.h" + #include "vgic_common.h" +@@ -675,6 +676,35 @@ static const ARMCPRegInfo gicv3_cpuif_re + REGINFO_SENTINEL + }; + ++/** ++ * vm_change_state_handler - VM change state callback aiming at flushing ++ * RDIST pending tables into guest RAM ++ * ++ * The tables get flushed to guest RAM whenever the VM gets stopped. ++ */ ++static void vm_change_state_handler(void *opaque, int running, ++ RunState state) ++{ ++ GICv3State *s = (GICv3State *)opaque; ++ Error *err = NULL; ++ int ret; ++ ++ if (running) { ++ return; ++ } ++ ++ ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, ++ KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES, ++ NULL, true, &err); ++ if (err) { ++ error_report_err(err); ++ } ++ if (ret < 0 && ret != -EFAULT) { ++ abort(); ++ } ++} ++ ++ + static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + { + GICv3State *s = KVM_ARM_GICV3(dev); +@@ -741,6 +771,10 @@ static void kvm_arm_gicv3_realize(Device + "not support vGICv3 migration"); + migrate_add_blocker(s->migration_blocker); + } ++ if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, ++ KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES)) { ++ qemu_add_vm_change_state_handler(vm_change_state_handler, s); ++ } + } + + static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Reset-GICv3-cpu-interface-regi.patch qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Reset-GICv3-cpu-interface-regi.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Reset-GICv3-cpu-interface-regi.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/hw-intc-arm_gicv3_kvm-Reset-GICv3-cpu-interface-regi.patch 2017-08-10 22:42:51.000000000 +0000 @@ -0,0 +1,104 @@ +Subject: [PATCH 4/4] hw/intc/arm_gicv3_kvm: Reset GICv3 cpu interface registers + Reset CPU interface registers of GICv3 when CPU is reset. + For this, ARMCPRegInfo struct is registered with one ICC + register whose resetfn is called when cpu is reset. + . + All the ICC registers are reset under one single register + reset function instead of calling resetfn for each ICC + register. + . + Signed-off-by: Vijaya Kumar K + Reviewed-by: Peter Maydell + Reviewed-by: Eric Auger + Message-id: 1487850673-26455-6-git-send-email-vijay.kilari@gmail.com + Signed-off-by: Peter Maydell +Origin: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commit;h=07a5628cb89f13b98fe526117fd07e5e273b5a52 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Vijaya Kumar K +Last-Update: 2017-08-10 + +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_kvm.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_kvm.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_kvm.c +@@ -604,6 +604,32 @@ static void kvm_arm_gicv3_get(GICv3State + } + } + ++static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) ++{ ++ ARMCPU *cpu; ++ GICv3State *s; ++ GICv3CPUState *c; ++ ++ c = (GICv3CPUState *)env->gicv3state; ++ s = c->gic; ++ cpu = ARM_CPU(c->cpu); ++ ++ /* Initialize to actual HW supported configuration */ ++ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, ++ KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity), ++ &c->icc_ctlr_el1[GICV3_NS], false); ++ ++ c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; ++ c->icc_pmr_el1 = 0; ++ c->icc_bpr[GICV3_G0] = GIC_MIN_BPR; ++ c->icc_bpr[GICV3_G1] = GIC_MIN_BPR; ++ c->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR; ++ ++ c->icc_sre_el1 = 0x7; ++ memset(c->icc_apr, 0, sizeof(c->icc_apr)); ++ memset(c->icc_igrpen, 0, sizeof(c->icc_igrpen)); ++} ++ + static void kvm_arm_gicv3_reset(DeviceState *dev) + { + GICv3State *s = ARM_GICV3_COMMON(dev); +@@ -621,6 +647,34 @@ static void kvm_arm_gicv3_reset(DeviceSt + kvm_arm_gicv3_put(s); + } + ++/* ++ * CPU interface registers of GIC needs to be reset on CPU reset. ++ * For the calling arm_gicv3_icc_reset() on CPU reset, we register ++ * below ARMCPRegInfo. As we reset the whole cpu interface under single ++ * register reset, we define only one register of CPU interface instead ++ * of defining all the registers. ++ */ ++static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { ++ { .name = "ICC_CTLR_EL1", .state = ARM_CP_STATE_BOTH, ++ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 4, ++ /* ++ * If ARM_CP_NOP is used, resetfn is not called, ++ * So ARM_CP_NO_RAW is appropriate type. ++ */ ++ .type = ARM_CP_NO_RAW, ++ .access = PL1_RW, ++ .readfn = arm_cp_read_zero, ++ .writefn = arm_cp_write_ignore, ++ /* ++ * We hang the whole cpu interface reset routine off here ++ * rather than parcelling it out into one little function ++ * per register ++ */ ++ .resetfn = arm_gicv3_icc_reset, ++ }, ++ REGINFO_SENTINEL ++}; ++ + static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + { + GICv3State *s = KVM_ARM_GICV3(dev); +@@ -644,6 +698,12 @@ static void kvm_arm_gicv3_realize(Device + + gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL); + ++ for (i = 0; i < s->num_cpu; i++) { ++ ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); ++ ++ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); ++ } ++ + /* Try to create the device via the device control API */ + s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V3, false); + if (s->dev_fd < 0) { diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/kernel-Add-definitions-for-GICv3-attributes.patch qemu-2.8+dfsg/debian/patches/ubuntu/kernel-Add-definitions-for-GICv3-attributes.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/kernel-Add-definitions-for-GICv3-attributes.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/kernel-Add-definitions-for-GICv3-attributes.patch 2017-08-10 22:56:10.000000000 +0000 @@ -0,0 +1,71 @@ +Description: kernel: Add definitions for GICv3 attributes + This temporary patch adds kernel API definitions. + Use proper header update procedure after these features + are released. + . + Signed-off-by: Pavel Fedin + Signed-off-by: Vijaya Kumar K + [ dannf: This was fixed upstream by syncing the headers + w/ 4.11. For this backport, I'm instead using a patch + from the mailing list that only adds the definitions + required by the following GICv3 save/restore series. ] +Origin: https://patchwork.kernel.org/patch/9578851/ +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Vijaya Kumar K +Last-Update: 2017-08-10 +Applied-Upstream: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commit;h=3a5eb5b4a929397d8678df9415c14c691c5ba969 + +Index: qemu-2.8+dfsg/linux-headers/asm-arm/kvm.h +=================================================================== +--- qemu-2.8+dfsg.orig/linux-headers/asm-arm/kvm.h ++++ qemu-2.8+dfsg/linux-headers/asm-arm/kvm.h +@@ -172,10 +172,22 @@ struct kvm_arch_memory_slot { + #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 + #define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 + #define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) ++#define KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32 ++#define KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \ ++ (0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT) + #define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 + #define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) ++#define KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff) + #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3 + #define KVM_DEV_ARM_VGIC_GRP_CTRL 4 ++#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 ++#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 ++#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 ++#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 ++#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ ++ (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ++#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff ++#define VGIC_LEVEL_INFO_LINE_LEVEL 0 + #define KVM_DEV_ARM_VGIC_CTRL_INIT 0 + + /* KVM_IRQ_LINE irq field index values */ +Index: qemu-2.8+dfsg/linux-headers/asm-arm64/kvm.h +=================================================================== +--- qemu-2.8+dfsg.orig/linux-headers/asm-arm64/kvm.h ++++ qemu-2.8+dfsg/linux-headers/asm-arm64/kvm.h +@@ -201,10 +201,22 @@ struct kvm_arch_memory_slot { + #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 + #define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 + #define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) ++#define KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32 ++#define KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \ ++ (0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT) + #define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 + #define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) ++#define KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff) + #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3 + #define KVM_DEV_ARM_VGIC_GRP_CTRL 4 ++#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 ++#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 ++#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 ++#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 ++#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ ++ (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ++#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff ++#define VGIC_LEVEL_INFO_LINE_LEVEL 0 + #define KVM_DEV_ARM_VGIC_CTRL_INIT 0 + + /* Device Control API on vcpu fd */ diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/kvm-all-Pass-an-error-object-to-kvm_device_access.patch qemu-2.8+dfsg/debian/patches/ubuntu/kvm-all-Pass-an-error-object-to-kvm_device_access.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/kvm-all-Pass-an-error-object-to-kvm_device_access.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/kvm-all-Pass-an-error-object-to-kvm_device_access.patch 2017-08-10 23:03:53.000000000 +0000 @@ -0,0 +1,202 @@ +Subject: [PATCH 1/4] kvm-all: Pass an error object to kvm_device_access + In some circumstances, we don't want to abort if the + kvm_device_access fails. This will be the case during ITS + migration, in case the ITS table save/restore fails because + the guest did not program the vITS correctly. So let's pass an + error object to the function and return the ioctl value. New + callers will be able to make a decision upon this returned + value. + . + Existing callers pass &error_abort which will cause the + function to abort on failure. + . + Signed-off-by: Eric Auger + Reviewed-by: Juan Quintela + Reviewed-by: Peter Xu + Message-id: 1497023553-18411-2-git-send-email-eric.auger@redhat.com + [PMM: wrapped long line] + Signed-off-by: Peter Maydell + [ dannf: backport involved only context adjustments ] +Origin: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commit;h=556969e938a97e98eec9df039944741ed74ce049 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Eric Auger +Last-Update: 2017-08-10 + +Index: qemu-2.8+dfsg/hw/intc/arm_gic_kvm.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gic_kvm.c ++++ qemu-2.8+dfsg/hw/intc/arm_gic_kvm.c +@@ -100,14 +100,14 @@ static void kvm_gicd_access(GICState *s, + uint32_t *val, bool write) + { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, +- KVM_VGIC_ATTR(offset, cpu), val, write); ++ KVM_VGIC_ATTR(offset, cpu), val, write, &error_abort); + } + + static void kvm_gicc_access(GICState *s, int offset, int cpu, + uint32_t *val, bool write) + { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, +- KVM_VGIC_ATTR(offset, cpu), val, write); ++ KVM_VGIC_ATTR(offset, cpu), val, write, &error_abort); + } + + #define for_each_irq_reg(_ctr, _max_irq, _field_width) \ +@@ -527,13 +527,14 @@ static void kvm_arm_gic_realize(DeviceSt + if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) { + uint32_t numirqs = s->num_irq; + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, +- &numirqs, true); ++ &numirqs, true, &error_abort); + } + /* Tell the kernel to complete VGIC initialization now */ + if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT)) { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, +- KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); ++ KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, ++ &error_abort); + } + } else if (ret != -ENODEV && ret != -ENOTSUP) { + error_setg_errno(errp, -ret, "error creating in-kernel VGIC"); +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_its_kvm.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_its_kvm.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_its_kvm.c +@@ -65,7 +65,7 @@ static void kvm_arm_its_realize(DeviceSt + + /* explicit init of the ITS */ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, +- KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); ++ KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); + + /* register the base address */ + kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_kvm.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_kvm.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_kvm.c +@@ -93,7 +93,7 @@ static inline void kvm_gicd_access(GICv3 + { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, + KVM_VGIC_ATTR(offset, 0), +- val, write); ++ val, write, &error_abort); + } + + static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, +@@ -101,7 +101,7 @@ static inline void kvm_gicr_access(GICv3 + { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, + KVM_VGIC_ATTR(offset, s->cpu[cpu].gicr_typer), +- val, write); ++ val, write, &error_abort); + } + + static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, +@@ -109,7 +109,7 @@ static inline void kvm_gicc_access(GICv3 + { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, + KVM_VGIC_ATTR(reg, s->cpu[cpu].gicr_typer), +- val, write); ++ val, write, &error_abort); + } + + static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, +@@ -119,7 +119,7 @@ static inline void kvm_gic_line_level_ac + KVM_VGIC_ATTR(irq, s->cpu[cpu].gicr_typer) | + (VGIC_LEVEL_INFO_LINE_LEVEL << + KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT), +- val, write); ++ val, write, &error_abort); + } + + /* Loop through each distributor IRQ related register; since bits +@@ -617,7 +617,7 @@ static void arm_gicv3_icc_reset(CPUARMSt + /* Initialize to actual HW supported configuration */ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, + KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity), +- &c->icc_ctlr_el1[GICV3_NS], false); ++ &c->icc_ctlr_el1[GICV3_NS], false, &error_abort); + + c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; + c->icc_pmr_el1 = 0; +@@ -712,11 +712,11 @@ static void kvm_arm_gicv3_realize(Device + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, +- 0, &s->num_irq, true); ++ 0, &s->num_irq, true, &error_abort); + + /* Tell the kernel to complete VGIC initialization now */ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, +- KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); ++ KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); + + kvm_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd); +Index: qemu-2.8+dfsg/include/sysemu/kvm.h +=================================================================== +--- qemu-2.8+dfsg.orig/include/sysemu/kvm.h ++++ qemu-2.8+dfsg/include/sysemu/kvm.h +@@ -297,12 +297,15 @@ int kvm_device_check_attr(int fd, uint32 + * @attr: the attribute of that group to set or get + * @val: pointer to a storage area for the value + * @write: true for set and false for get operation ++ * @errp: error object handle + * +- * This function is not allowed to fail. Use kvm_device_check_attr() +- * in order to check for the availability of optional attributes. ++ * Returns: 0 on success ++ * < 0 on error ++ * Use kvm_device_check_attr() in order to check for the availability ++ * of optional attributes. + */ +-void kvm_device_access(int fd, int group, uint64_t attr, +- void *val, bool write); ++int kvm_device_access(int fd, int group, uint64_t attr, ++ void *val, bool write, Error **errp); + + /** + * kvm_create_device - create a KVM device for the device control API +Index: qemu-2.8+dfsg/kvm-all.c +=================================================================== +--- qemu-2.8+dfsg.orig/kvm-all.c ++++ qemu-2.8+dfsg/kvm-all.c +@@ -23,6 +23,7 @@ + #include "qemu/option.h" + #include "qemu/config-file.h" + #include "qemu/error-report.h" ++#include "qapi/error.h" + #include "hw/hw.h" + #include "hw/pci/msi.h" + #include "hw/pci/msix.h" +@@ -2129,8 +2130,8 @@ int kvm_device_check_attr(int dev_fd, ui + return kvm_device_ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attribute) ? 0 : 1; + } + +-void kvm_device_access(int fd, int group, uint64_t attr, +- void *val, bool write) ++int kvm_device_access(int fd, int group, uint64_t attr, ++ void *val, bool write, Error **errp) + { + struct kvm_device_attr kvmattr; + int err; +@@ -2144,11 +2145,12 @@ void kvm_device_access(int fd, int group + write ? KVM_SET_DEVICE_ATTR : KVM_GET_DEVICE_ATTR, + &kvmattr); + if (err < 0) { +- error_report("KVM_%s_DEVICE_ATTR failed: %s", +- write ? "SET" : "GET", strerror(-err)); +- error_printf("Group %d attr 0x%016" PRIx64 "\n", group, attr); +- abort(); ++ error_setg_errno(errp, -err, ++ "KVM_%s_DEVICE_ATTR failed: Group %d " ++ "attr 0x%016" PRIx64, ++ write ? "SET" : "GET", group, attr); + } ++ return err; + } + + /* Return 1 on success, 0 on failure */ diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/linux-headers-Update-for-vITS-save-restore.patch qemu-2.8+dfsg/debian/patches/ubuntu/linux-headers-Update-for-vITS-save-restore.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/linux-headers-Update-for-vITS-save-restore.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/linux-headers-Update-for-vITS-save-restore.patch 2017-08-10 22:56:45.000000000 +0000 @@ -0,0 +1,66 @@ +Description: linux-headers: Update for vITS save/restore + This is a linux header update against 4.11-rc6 plus the non + upstreamed ITS migration series. + . + https://github.com/eauger/linux/tree/v4.11-rc6-its-mig-v5 + . + It aims at enhancing the KVM user API with vITS save/restore + capability. Those are new attributes supported in the + ITS and GICv3 KVM device KVM_DEV_ARM_VGIC_GRP_CTRL groups. + . + Signed-off-by: Eric Auger + [ dannf: This was fixed upstream by syncing the headers + w/ 4.12-rc1. For this backport, I'm instead using a patch + from the mailing list that only adds the definitions + required by the following vITS save/restore series. + Porting only involved context changes. ] +Origin: https://patchwork.kernel.org/patch/9681213/ +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Eric Auger +Last-Update: 2017-08-10 +Applied-Upstream: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commitdiff;h=74c98e20a604b9db58284b8727688df70e9bf643 + +Index: qemu-2.8+dfsg/linux-headers/asm-arm/kvm.h +=================================================================== +--- qemu-2.8+dfsg.orig/linux-headers/asm-arm/kvm.h ++++ qemu-2.8+dfsg/linux-headers/asm-arm/kvm.h +@@ -183,12 +183,16 @@ struct kvm_arch_memory_slot { + #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 + #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 + #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 ++#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8 + #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 + #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ + (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) + #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff + #define VGIC_LEVEL_INFO_LINE_LEVEL 0 +-#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 ++#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 ++#define KVM_DEV_ARM_ITS_SAVE_TABLES 1 ++#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 ++#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 + + /* KVM_IRQ_LINE irq field index values */ + #define KVM_ARM_IRQ_TYPE_SHIFT 24 +Index: qemu-2.8+dfsg/linux-headers/asm-arm64/kvm.h +=================================================================== +--- qemu-2.8+dfsg.orig/linux-headers/asm-arm64/kvm.h ++++ qemu-2.8+dfsg/linux-headers/asm-arm64/kvm.h +@@ -212,12 +212,16 @@ struct kvm_arch_memory_slot { + #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 + #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 + #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 ++#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8 + #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 + #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ + (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) + #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff + #define VGIC_LEVEL_INFO_LINE_LEVEL 0 +-#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 ++#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 ++#define KVM_DEV_ARM_ITS_SAVE_TABLES 1 ++#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 ++#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 + + /* Device Control API on vcpu fd */ + #define KVM_ARM_VCPU_PMU_V3_CTRL 0 diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/migration-allow-to-prioritize-save-state-entries.patch qemu-2.8+dfsg/debian/patches/ubuntu/migration-allow-to-prioritize-save-state-entries.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/migration-allow-to-prioritize-save-state-entries.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/migration-allow-to-prioritize-save-state-entries.patch 2017-08-10 23:14:46.000000000 +0000 @@ -0,0 +1,119 @@ +Subject: [PATCH] migration: allow to prioritize save state entries + During migration, save state entries are saved/loaded without a specific + order - we just traverse the savevm_state.handlers list and do it one by + one. This might not be enough. + . + There are requirements that we need to load specific device's vmstate + first before others. For example, VT-d IOMMU contains DMA address + remapping information, which is required by all the PCI devices to do + address translations. We need to make sure IOMMU's device state is + loaded before the rest of the PCI devices, so that DMA address + translation can work properly. + . + This patch provide a VMStateDescription.priority value to allow specify + the priority of the saved states. The loadvm operation will be done with + those devices with higher vmsd priority. + . + Before this patch, we are possibly achieving the ordering requirement by + an assumption that the ordering will be the same with the ordering that + objects are created. A better way is to mark it out explicitly in the + VMStateDescription table, like what this patch does. + . + Current ordering logic is still naive and slow, but after all that's not + a critical path so IMO it's a workable solution for now. + . + Signed-off-by: Peter Xu + Reviewed-by: Michael S. Tsirkin + Signed-off-by: Michael S. Tsirkin + Reviewed-by: Dr. David Alan Gilbert +Origin: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commit;h=f37bc03623cd22f3934264f50af926b9b63f6598 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Peter Xu +Last-Update: 2017-08-10 + +diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h +index 1638ee57f7..1a228872fa 100644 +--- a/include/migration/vmstate.h ++++ b/include/migration/vmstate.h +@@ -186,6 +186,11 @@ enum VMStateFlags { + VMS_MULTIPLY_ELEMENTS = 0x4000, + }; + ++typedef enum { ++ MIG_PRI_DEFAULT = 0, ++ MIG_PRI_MAX, ++} MigrationPriority; ++ + typedef struct { + const char *name; + size_t offset; +@@ -207,6 +212,7 @@ struct VMStateDescription { + int version_id; + int minimum_version_id; + int minimum_version_id_old; ++ MigrationPriority priority; + LoadStateHandler *load_state_old; + int (*pre_load)(void *opaque); + int (*post_load)(void *opaque, int version_id); +diff --git a/migration/savevm.c b/migration/savevm.c +index 0363372acc..f9c06e9f96 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -532,6 +532,34 @@ static int calculate_compat_instance_id(const char *idstr) + return instance_id; + } + ++static inline MigrationPriority save_state_priority(SaveStateEntry *se) ++{ ++ if (se->vmsd) { ++ return se->vmsd->priority; ++ } ++ return MIG_PRI_DEFAULT; ++} ++ ++static void savevm_state_handler_insert(SaveStateEntry *nse) ++{ ++ MigrationPriority priority = save_state_priority(nse); ++ SaveStateEntry *se; ++ ++ assert(priority <= MIG_PRI_MAX); ++ ++ QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { ++ if (save_state_priority(se) < priority) { ++ break; ++ } ++ } ++ ++ if (se) { ++ QTAILQ_INSERT_BEFORE(se, nse, entry); ++ } else { ++ QTAILQ_INSERT_TAIL(&savevm_state.handlers, nse, entry); ++ } ++} ++ + /* TODO: Individual devices generally have very little idea about the rest + of the system, so instance_id should be removed/replaced. + Meanwhile pass -1 as instance_id if you do not already have a clearly +@@ -578,8 +606,7 @@ int register_savevm_live(DeviceState *dev, + se->instance_id = instance_id; + } + assert(!se->compat || se->instance_id == 0); +- /* add at the end of list */ +- QTAILQ_INSERT_TAIL(&savevm_state.handlers, se, entry); ++ savevm_state_handler_insert(se); + return 0; + } + +@@ -662,8 +689,7 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, + se->instance_id = instance_id; + } + assert(!se->compat || se->instance_id == 0); +- /* add at the end of list */ +- QTAILQ_INSERT_TAIL(&savevm_state.handlers, se, entry); ++ savevm_state_handler_insert(se); + return 0; + } + +-- +2.11.0 + diff -Nru qemu-2.8+dfsg/debian/patches/ubuntu/target-arm-Add-GICv3CPUState-in-CPUARMState-struct.patch qemu-2.8+dfsg/debian/patches/ubuntu/target-arm-Add-GICv3CPUState-in-CPUARMState-struct.patch --- qemu-2.8+dfsg/debian/patches/ubuntu/target-arm-Add-GICv3CPUState-in-CPUARMState-struct.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.8+dfsg/debian/patches/ubuntu/target-arm-Add-GICv3CPUState-in-CPUARMState-struct.patch 2017-08-10 22:36:47.000000000 +0000 @@ -0,0 +1,75 @@ +Subject: [PATCH 3/4] target-arm: Add GICv3CPUState in CPUARMState struct + Add gicv3state void pointer to CPUARMState struct + to store GICv3CPUState. + . + In case of usecase like CPU reset, we need to reset + GICv3CPUState of the CPU. In such scenario, this pointer + becomes handy. + . + Signed-off-by: Vijaya Kumar K + Reviewed-by: Peter Maydell + Reviewed-by: Eric Auger + Message-id: 1487850673-26455-5-git-send-email-vijay.kilari@gmail.com + Signed-off-by: Peter Maydell + [ dannf: backported to deal with target/arm/cpu.h->target-arm +Origin: https://git.qemu.org/gitweb.cgi?p=qemu.git;a=commit;h=d3a3e529626fbee5cf0fb33414a85c9493adc280 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1710019 +Author: Vijaya Kumar K +Last-Update: 2017-08-10 + +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_common.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_common.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_common.c +@@ -221,6 +221,8 @@ static void arm_gicv3_common_realize(Dev + + s->cpu[i].cpu = cpu; + s->cpu[i].gic = s; ++ /* Store GICv3CPUState in CPUARMState gicv3state pointer */ ++ gicv3_set_gicv3state(cpu, &s->cpu[i]); + + /* Pre-construct the GICR_TYPER: + * For our implementation: +Index: qemu-2.8+dfsg/hw/intc/arm_gicv3_cpuif.c +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/arm_gicv3_cpuif.c ++++ qemu-2.8+dfsg/hw/intc/arm_gicv3_cpuif.c +@@ -17,6 +17,14 @@ + #include "gicv3_internal.h" + #include "cpu.h" + ++void gicv3_set_gicv3state(CPUState *cpu, GICv3CPUState *s) ++{ ++ ARMCPU *arm_cpu = ARM_CPU(cpu); ++ CPUARMState *env = &arm_cpu->env; ++ ++ env->gicv3state = (void *)s; ++}; ++ + static GICv3CPUState *icc_cs_from_env(CPUARMState *env) + { + /* Given the CPU, find the right GICv3CPUState struct. +Index: qemu-2.8+dfsg/hw/intc/gicv3_internal.h +=================================================================== +--- qemu-2.8+dfsg.orig/hw/intc/gicv3_internal.h ++++ qemu-2.8+dfsg/hw/intc/gicv3_internal.h +@@ -329,4 +329,6 @@ static inline void gicv3_cache_all_targe + } + } + ++void gicv3_set_gicv3state(CPUState *cpu, GICv3CPUState *s); ++ + #endif /* QEMU_ARM_GICV3_INTERNAL_H */ +Index: qemu-2.8+dfsg/target-arm/cpu.h +=================================================================== +--- qemu-2.8+dfsg.orig/target-arm/cpu.h ++++ qemu-2.8+dfsg/target-arm/cpu.h +@@ -507,6 +507,8 @@ typedef struct CPUARMState { + + void *nvic; + const struct arm_boot_info *boot_info; ++ /* Store GICv3CPUState to access from this struct */ ++ void *gicv3state; + } CPUARMState; + + /**