@@ -201,7 +201,9 @@ struct kvm_arch_memory_slot {
#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
/* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_TYPE_SHIFT 24
@@ -221,7 +221,9 @@ struct kvm_arch_memory_slot {
#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
/* Device Control API on vcpu fd */
#define KVM_ARM_VCPU_PMU_V3_CTRL 0
@@ -1703,12 +1703,71 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
}
/**
+ * vgic_its_save_device_tables - Save the device table and all ITT
+ * into guest RAM
+ */
+static int vgic_its_save_device_tables(struct vgic_its *its)
+{
+ return -ENXIO;
+}
+
+/**
+ * vgic_its_restore_device_tables - Restore the device table and all ITT
+ * from guest RAM to internal data structs
+ */
+static int vgic_its_restore_device_tables(struct vgic_its *its)
+{
+ return -ENXIO;
+}
+
+/**
+ * vgic_its_save_collection_table - Save the collection table into
+ * guest RAM
+ */
+static int vgic_its_save_collection_table(struct vgic_its *its)
+{
+ return -ENXIO;
+}
+
+/**
+ * vgic_its_restore_collection_table - reads the collection table
+ * in guest memory and restores the ITS internal state. Requires the
+ * BASER registers to be restored before.
+ */
+static int vgic_its_restore_collection_table(struct vgic_its *its)
+{
+ return -ENXIO;
+}
+
+/**
* vgic_its_save_tables_v0 - Save the ITS tables into guest ARM
* according to v0 ABI
*/
static int vgic_its_save_tables_v0(struct vgic_its *its)
{
- return -ENXIO;
+ struct kvm *kvm = its->dev->kvm;
+ int ret;
+
+ mutex_lock(&kvm->lock);
+ mutex_lock(&its->its_lock);
+
+ if (!lock_all_vcpus(kvm)) {
+ mutex_unlock(&its->its_lock);
+ mutex_unlock(&kvm->lock);
+ return -EBUSY;
+ }
+
+ ret = vgic_its_save_device_tables(its);
+ if (ret)
+ goto out;
+
+ ret = vgic_its_save_collection_table(its);
+
+out:
+ unlock_all_vcpus(kvm);
+ mutex_unlock(&its->its_lock);
+ mutex_unlock(&kvm->lock);
+ return ret;
}
/**
@@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
*/
static int vgic_its_restore_tables_v0(struct vgic_its *its)
{
- return -ENXIO;
+ struct kvm *kvm = its->dev->kvm;
+ int ret;
+
+ mutex_lock(&kvm->lock);
+ mutex_lock(&its->its_lock);
+
+ if (!lock_all_vcpus(kvm)) {
+ mutex_unlock(&its->its_lock);
+ mutex_unlock(&kvm->lock);
+ return -EBUSY;
+ }
+
+ ret = vgic_its_restore_collection_table(its);
+ if (ret)
+ goto out;
+
+ ret = vgic_its_restore_device_tables(its);
+
+out:
+ unlock_all_vcpus(kvm);
+ mutex_unlock(&its->its_lock);
+ mutex_unlock(&kvm->lock);
+
+ if (ret)
+ return ret;
+
+ /*
+ * On restore path, MSI injections can happen before the
+ * first VCPU run so let's complete the GIC init here.
+ */
+ return kvm_vgic_map_resources(its->dev->kvm);
}
static int vgic_its_commit_v0(struct vgic_its *its)
@@ -1751,6 +1840,10 @@ static int vgic_its_has_attr(struct kvm_device *dev,
switch (attr->attr) {
case KVM_DEV_ARM_VGIC_CTRL_INIT:
return 0;
+ case KVM_DEV_ARM_ITS_SAVE_TABLES:
+ return 0;
+ case KVM_DEV_ARM_ITS_RESTORE_TABLES:
+ return 0;
}
break;
case KVM_DEV_ARM_VGIC_GRP_ITS_REGS:
@@ -1786,14 +1879,20 @@ static int vgic_its_set_attr(struct kvm_device *dev,
return 0;
}
- case KVM_DEV_ARM_VGIC_GRP_CTRL:
+ case KVM_DEV_ARM_VGIC_GRP_CTRL: {
+ const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+
switch (attr->attr) {
case KVM_DEV_ARM_VGIC_CTRL_INIT:
its->initialized = true;
return 0;
+ case KVM_DEV_ARM_ITS_SAVE_TABLES:
+ return abi->save_tables(its);
+ case KVM_DEV_ARM_ITS_RESTORE_TABLES:
+ return abi->restore_tables(its);
}
- break;
+ }
case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
u64 __user *uaddr = (u64 __user *)(long)attr->addr;
u64 reg;