|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC v3 2/6] xen/arm: Add save/restore support for ARM GIC V2
This patch implements a save/restore support for
ARM guest GIC. Two types of GIC V2 states are saved seperately:
1) VGICD_* contains the GIC distributor state from
guest VM's view; 2) GICH_* is the GIC virtual control
state from hypervisor's persepctive.
Signed-off-by: Evgeny Fedotov <e.fedotov@xxxxxxxxxxx>
Signed-off-by: Wei Huang <w1.huang@xxxxxxxxxxx>
---
xen/arch/arm/vgic.c | 171 ++++++++++++++++++++++++++++++++
xen/include/public/arch-arm/hvm/save.h | 34 ++++++-
2 files changed, 204 insertions(+), 1 deletion(-)
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 4cf6470..505e944 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -24,6 +24,7 @@
#include <xen/softirq.h>
#include <xen/irq.h>
#include <xen/sched.h>
+#include <xen/hvm/save.h>
#include <asm/current.h>
@@ -73,6 +74,110 @@ static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v,
int b, int n)
return NULL;
}
+/* Save guest VM's distributor info into a context to support domains
+ * save/restore. Such info represents guest VM's view of its GIC
+ * distributor (GICD_*).
+ */
+static int hvm_vgicd_save(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_arm_vgicd_v2 ctxt;
+ struct vcpu *v;
+ struct vgic_irq_rank *rank;
+ int rc = 0;
+
+ /* Save the state for each VCPU */
+ for_each_vcpu( d, v )
+ {
+ rank = &v->arch.vgic.private_irqs;
+
+ /* IENABLE, IACTIVE, IPEND, PENDSGI */
+ ctxt.ienable = rank->ienable;
+ ctxt.iactive = rank->iactive;
+ ctxt.ipend = rank->ipend;
+ ctxt.pendsgi = rank->pendsgi;
+
+ /* ICFG */
+ ctxt.icfg[0] = rank->icfg[0];
+ ctxt.icfg[1] = rank->icfg[1];
+
+ /* IPRIORITY */
+ BUILD_BUG_ON(sizeof(rank->ipriority) != sizeof (ctxt.ipriority));
+ memcpy(ctxt.ipriority, rank->ipriority, sizeof(rank->ipriority));
+
+ /* ITARGETS */
+ BUILD_BUG_ON(sizeof(rank->itargets) != sizeof (ctxt.itargets));
+ memcpy(ctxt.itargets, rank->itargets, sizeof(rank->itargets));
+
+ if ( (rc = hvm_save_entry(VGICD_V2, v->vcpu_id, h, &ctxt)) != 0 )
+ return rc;
+ }
+
+ return rc;
+}
+
+/* Load guest VM's distributor info from a context to support domain
+ * save/restore. The info is loaded into vgic_irq_rank.
+ */
+static int hvm_vgicd_load(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_arm_vgicd_v2 ctxt;
+ struct vgic_irq_rank *rank;
+ struct vcpu *v;
+ int vcpuid;
+ unsigned long enable_bits;
+ struct pending_irq *p;
+ unsigned int irq = 0;
+ int rc = 0;
+
+ /* Which vcpu is this? */
+ vcpuid = hvm_load_instance(h);
+ if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
+ {
+ dprintk(XENLOG_ERR, "HVM restore: dom%u has no vcpu%u\n",
+ d->domain_id, vcpuid);
+ return -EINVAL;
+ }
+
+ if ( (rc = hvm_load_entry(VGICD_V2, h, &ctxt)) != 0 )
+ return rc;
+
+ /* Restore PPI states */
+ rank = &v->arch.vgic.private_irqs;
+
+ /* IENABLE, IACTIVE, IPEND, PENDSGI */
+ rank->ienable = ctxt.ienable;
+ rank->iactive = ctxt.iactive;
+ rank->ipend = ctxt.ipend;
+ rank->pendsgi = ctxt.pendsgi;
+
+ /* ICFG */
+ rank->icfg[0] = ctxt.icfg[0];
+ rank->icfg[1] = ctxt.icfg[1];
+
+ /* IPRIORITY */
+ BUILD_BUG_ON(sizeof(rank->ipriority) != sizeof (ctxt.ipriority));
+ memcpy(rank->ipriority, ctxt.ipriority, sizeof(rank->ipriority));
+
+ /* ITARGETS */
+ BUILD_BUG_ON(sizeof(rank->itargets) != sizeof (ctxt.itargets));
+ memcpy(rank->itargets, ctxt.itargets, sizeof(rank->itargets));
+
+ /* Set IRQ status as enabled by iterating through rank->ienable register.
+ * This step is required otherwise events won't be received by the VM
+ * after restore. */
+ enable_bits = ctxt.ienable;
+ while ( (irq = find_next_bit(&enable_bits, 32, irq)) < 32 )
+ {
+ p = irq_to_pending(v, irq);
+ set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+ irq++;
+ }
+
+ return 0;
+}
+HVM_REGISTER_SAVE_RESTORE(VGICD_V2, hvm_vgicd_save, hvm_vgicd_load,
+ 1, HVMSR_PER_VCPU);
+
int domain_vgic_init(struct domain *d)
{
int i;
@@ -759,6 +864,72 @@ out:
smp_send_event_check_mask(cpumask_of(v->processor));
}
+/* Save GIC virtual control state into a context to support save/restore.
+ * The info reprsents most of GICH_* registers. */
+static int hvm_gich_save(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_arm_gich_v2 ctxt;
+ struct vcpu *v;
+ int rc = 0;
+
+ /* Save the state of GICs */
+ for_each_vcpu( d, v )
+ {
+ ctxt.gic_hcr = v->arch.gic_hcr;
+ ctxt.gic_vmcr = v->arch.gic_vmcr;
+ ctxt.gic_apr = v->arch.gic_apr;
+
+ /* Save list registers and masks */
+ BUILD_BUG_ON(sizeof(v->arch.gic_lr) > sizeof (ctxt.gic_lr));
+ memcpy(ctxt.gic_lr, v->arch.gic_lr, sizeof(v->arch.gic_lr));
+
+ ctxt.lr_mask = v->arch.lr_mask;
+ ctxt.event_mask = v->arch.event_mask;
+
+ if ( (rc = hvm_save_entry(GICH_V2, v->vcpu_id, h, &ctxt)) != 0 )
+ return rc;
+ }
+
+ return rc;
+}
+
+/* Restore GIC virtual control state from a context to support save/restore */
+static int hvm_gich_load(struct domain *d, hvm_domain_context_t *h)
+{
+ int vcpuid;
+ struct hvm_arm_gich_v2 ctxt;
+ struct vcpu *v;
+ int rc = 0;
+
+ /* Which vcpu is this? */
+ vcpuid = hvm_load_instance(h);
+ if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
+ {
+ dprintk(XENLOG_ERR, "HVM restore: dom%u has no vcpu%u\n", d->domain_id,
+ vcpuid);
+ return -EINVAL;
+ }
+
+ if ( (rc = hvm_load_entry(GICH_V2, h, &ctxt)) != 0 )
+ return rc;
+
+ v->arch.gic_hcr = ctxt.gic_hcr;
+ v->arch.gic_vmcr = ctxt.gic_vmcr;
+ v->arch.gic_apr = ctxt.gic_apr;
+
+ /* Restore list registers and masks */
+ BUILD_BUG_ON(sizeof(v->arch.gic_lr) > sizeof (ctxt.gic_lr));
+ memcpy(v->arch.gic_lr, ctxt.gic_lr, sizeof(v->arch.gic_lr));
+
+ v->arch.lr_mask = ctxt.lr_mask;
+ v->arch.event_mask = ctxt.event_mask;
+
+ return rc;
+}
+
+HVM_REGISTER_SAVE_RESTORE(GICH_V2, hvm_gich_save, hvm_gich_load, 1,
+ HVMSR_PER_VCPU);
+
/*
* Local variables:
* mode: C
diff --git a/xen/include/public/arch-arm/hvm/save.h
b/xen/include/public/arch-arm/hvm/save.h
index 8312e7b..421a6f6 100644
--- a/xen/include/public/arch-arm/hvm/save.h
+++ b/xen/include/public/arch-arm/hvm/save.h
@@ -40,10 +40,42 @@ struct hvm_save_header
};
DECLARE_HVM_SAVE_TYPE(HEADER, 1, struct hvm_save_header);
+/* Guest's view of GIC distributor (per-vcpu)
+ * - Based on GICv2 (see "struct vgic_irq_rank")
+ * - Store guest's view of GIC distributor
+ * - Only support SGI and PPI for DomU (DomU doesn't handle SPI)
+ */
+struct hvm_arm_vgicd_v2
+{
+ uint32_t ienable;
+ uint32_t iactive;
+ uint32_t ipend;
+ uint32_t pendsgi;
+ uint32_t icfg[2];
+ uint32_t ipriority[8];
+ uint32_t itargets[8];
+};
+DECLARE_HVM_SAVE_TYPE(VGICD_V2, 2, struct hvm_arm_vgicd_v2);
+
+/* Info for hypervisor to manage guests (per-vcpu)
+ * - Based on GICv2
+ * - Mainly store registers of GICH_*
+ */
+struct hvm_arm_gich_v2
+{
+ uint32_t gic_hcr;
+ uint32_t gic_vmcr;
+ uint32_t gic_apr;
+ uint32_t gic_lr[64];
+ uint64_t event_mask;
+ uint64_t lr_mask;
+};
+DECLARE_HVM_SAVE_TYPE(GICH_V2, 3, struct hvm_arm_gich_v2);
+
/*
* Largest type-code in use
*/
-#define HVM_SAVE_CODE_MAX 1
+#define HVM_SAVE_CODE_MAX 3
#endif
--
1.7.9.5
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |