diff options
author | Luc Michel <luc.michel@greensocs.com> | 2018-08-14 17:17:20 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-08-14 17:17:20 +0100 |
commit | 5773c0494ae8045250288a801417270e0ef5de55 (patch) | |
tree | d1d8bdf1cdec530d4a8a47242b66f495bfba6e86 /hw | |
parent | b77473a0f7799f3484a1e483515c8bde7a872248 (diff) | |
download | qemu-5773c0494ae8045250288a801417270e0ef5de55.zip qemu-5773c0494ae8045250288a801417270e0ef5de55.tar.gz qemu-5773c0494ae8045250288a801417270e0ef5de55.tar.bz2 |
intc/arm_gic: Add the virtualization extensions to the GIC state
Add the necessary parts of the virtualization extensions state to the
GIC state. We choose to increase the size of the CPU interfaces state to
add space for the vCPU interfaces (the GIC_NCPU_VCPU macro). This way,
we'll be able to reuse most of the CPU interface code for the vCPUs.
The only exception is the APR value, which is stored in h_apr in the
virtual interface state for vCPUs. This is due to some complications
with the GIC VMState, for which we don't want to break backward
compatibility. APRs being stored in 2D arrays, increasing the second
dimension would lead to some ugly VMState description. To avoid
that, we keep it in h_apr for vCPUs.
The vCPUs are numbered from GIC_NCPU to (GIC_NCPU * 2) - 1. The
`gic_is_vcpu` function help to determine if a given CPU id correspond to
a physical CPU or a virtual one.
For the in-kernel KVM VGIC, since the exposed VGIC does not implement
the virtualization extensions, we report an error if the corresponding
property is set to true.
Signed-off-by: Luc Michel <luc.michel@greensocs.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20180727095421.386-6-luc.michel@greensocs.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/intc/arm_gic.c | 2 | ||||
-rw-r--r-- | hw/intc/arm_gic_common.c | 148 | ||||
-rw-r--r-- | hw/intc/arm_gic_kvm.c | 8 | ||||
-rw-r--r-- | hw/intc/gic_internal.h | 5 |
4 files changed, 137 insertions, 26 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index b8eba6e..5231579 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -1497,7 +1497,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) } /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ - gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); + gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops, NULL); /* Extra core-specific regions for the CPU interfaces. This is * necessary for "franken-GIC" implementations, for example on diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 295ee9c..547dc41 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -46,6 +46,13 @@ static int gic_post_load(void *opaque, int version_id) return 0; } +static bool gic_virt_state_needed(void *opaque) +{ + GICState *s = (GICState *)opaque; + + return s->virt_extn; +} + static const VMStateDescription vmstate_gic_irq_state = { .name = "arm_gic_irq_state", .version_id = 1, @@ -62,6 +69,30 @@ static const VMStateDescription vmstate_gic_irq_state = { } }; +static const VMStateDescription vmstate_gic_virt_state = { + .name = "arm_gic_virt_state", + .version_id = 1, + .minimum_version_id = 1, + .needed = gic_virt_state_needed, + .fields = (VMStateField[]) { + /* Virtual interface */ + VMSTATE_UINT32_ARRAY(h_hcr, GICState, GIC_NCPU), + VMSTATE_UINT32_ARRAY(h_misr, GICState, GIC_NCPU), + VMSTATE_UINT32_2DARRAY(h_lr, GICState, GIC_MAX_LR, GIC_NCPU), + VMSTATE_UINT32_ARRAY(h_apr, GICState, GIC_NCPU), + + /* Virtual CPU interfaces */ + VMSTATE_UINT32_SUB_ARRAY(cpu_ctlr, GICState, GIC_NCPU, GIC_NCPU), + VMSTATE_UINT16_SUB_ARRAY(priority_mask, GICState, GIC_NCPU, GIC_NCPU), + VMSTATE_UINT16_SUB_ARRAY(running_priority, GICState, GIC_NCPU, GIC_NCPU), + VMSTATE_UINT16_SUB_ARRAY(current_pending, GICState, GIC_NCPU, GIC_NCPU), + VMSTATE_UINT8_SUB_ARRAY(bpr, GICState, GIC_NCPU, GIC_NCPU), + VMSTATE_UINT8_SUB_ARRAY(abpr, GICState, GIC_NCPU, GIC_NCPU), + + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_gic = { .name = "arm_gic", .version_id = 12, @@ -70,26 +101,31 @@ static const VMStateDescription vmstate_gic = { .post_load = gic_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32(ctlr, GICState), - VMSTATE_UINT32_ARRAY(cpu_ctlr, GICState, GIC_NCPU), + VMSTATE_UINT32_SUB_ARRAY(cpu_ctlr, GICState, 0, GIC_NCPU), VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1, vmstate_gic_irq_state, gic_irq_state), VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ), VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, GIC_NCPU), VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL), VMSTATE_UINT8_2DARRAY(sgi_pending, GICState, GIC_NR_SGIS, GIC_NCPU), - VMSTATE_UINT16_ARRAY(priority_mask, GICState, GIC_NCPU), - VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU), - VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU), - VMSTATE_UINT8_ARRAY(bpr, GICState, GIC_NCPU), - VMSTATE_UINT8_ARRAY(abpr, GICState, GIC_NCPU), + VMSTATE_UINT16_SUB_ARRAY(priority_mask, GICState, 0, GIC_NCPU), + VMSTATE_UINT16_SUB_ARRAY(running_priority, GICState, 0, GIC_NCPU), + VMSTATE_UINT16_SUB_ARRAY(current_pending, GICState, 0, GIC_NCPU), + VMSTATE_UINT8_SUB_ARRAY(bpr, GICState, 0, GIC_NCPU), + VMSTATE_UINT8_SUB_ARRAY(abpr, GICState, 0, GIC_NCPU), VMSTATE_UINT32_2DARRAY(apr, GICState, GIC_NR_APRS, GIC_NCPU), VMSTATE_UINT32_2DARRAY(nsapr, GICState, GIC_NR_APRS, GIC_NCPU), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &vmstate_gic_virt_state, + NULL } }; void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler, - const MemoryRegionOps *ops) + const MemoryRegionOps *ops, + const MemoryRegionOps *virt_ops) { SysBusDevice *sbd = SYS_BUS_DEVICE(s); int i = s->num_irq - GIC_INTERNAL; @@ -116,6 +152,11 @@ 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]); } + if (s->virt_extn) { + for (i = 0; i < s->num_cpu; i++) { + sysbus_init_irq(sbd, &s->maintenance_irq[i]); + } + } /* Distributor */ memory_region_init_io(&s->iomem, OBJECT(s), ops, s, "gic_dist", 0x1000); @@ -127,6 +168,17 @@ void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler, memory_region_init_io(&s->cpuiomem[0], OBJECT(s), ops ? &ops[1] : NULL, s, "gic_cpu", s->revision == 2 ? 0x2000 : 0x100); sysbus_init_mmio(sbd, &s->cpuiomem[0]); + + if (s->virt_extn) { + memory_region_init_io(&s->vifaceiomem[0], OBJECT(s), virt_ops, + s, "gic_viface", 0x1000); + sysbus_init_mmio(sbd, &s->vifaceiomem[0]); + + memory_region_init_io(&s->vcpuiomem, OBJECT(s), + virt_ops ? &virt_ops[1] : NULL, + s, "gic_vcpu", 0x2000); + sysbus_init_mmio(sbd, &s->vcpuiomem); + } } static void arm_gic_common_realize(DeviceState *dev, Error **errp) @@ -163,6 +215,48 @@ static void arm_gic_common_realize(DeviceState *dev, Error **errp) "the security extensions"); return; } + + if (s->virt_extn) { + if (s->revision != 2) { + error_setg(errp, "GIC virtualization extensions are only " + "supported by revision 2"); + return; + } + + /* For now, set the number of implemented LRs to 4, as found in most + * real GICv2. This could be promoted as a QOM property if we need to + * emulate a variant with another num_lrs. + */ + s->num_lrs = 4; + } +} + +static inline void arm_gic_common_reset_irq_state(GICState *s, int first_cpu, + int resetprio) +{ + int i, j; + + for (i = first_cpu; i < first_cpu + s->num_cpu; i++) { + if (s->revision == REV_11MPCORE) { + s->priority_mask[i] = 0xf0; + } else { + s->priority_mask[i] = resetprio; + } + s->current_pending[i] = 1023; + s->running_priority[i] = 0x100; + s->cpu_ctlr[i] = 0; + s->bpr[i] = gic_is_vcpu(i) ? GIC_VIRT_MIN_BPR : GIC_MIN_BPR; + s->abpr[i] = gic_is_vcpu(i) ? GIC_VIRT_MIN_ABPR : GIC_MIN_ABPR; + + if (!gic_is_vcpu(i)) { + for (j = 0; j < GIC_INTERNAL; j++) { + s->priority1[j][i] = resetprio; + } + for (j = 0; j < GIC_NR_SGIS; j++) { + s->sgi_pending[j][i] = 0; + } + } + } } static void arm_gic_common_reset(DeviceState *dev) @@ -185,24 +279,15 @@ static void arm_gic_common_reset(DeviceState *dev) } memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); - for (i = 0 ; i < s->num_cpu; i++) { - if (s->revision == REV_11MPCORE) { - s->priority_mask[i] = 0xf0; - } else { - s->priority_mask[i] = resetprio; - } - s->current_pending[i] = 1023; - s->running_priority[i] = 0x100; - s->cpu_ctlr[i] = 0; - s->bpr[i] = GIC_MIN_BPR; - s->abpr[i] = GIC_MIN_ABPR; - for (j = 0; j < GIC_INTERNAL; j++) { - s->priority1[j][i] = resetprio; - } - for (j = 0; j < GIC_NR_SGIS; j++) { - s->sgi_pending[j][i] = 0; - } + arm_gic_common_reset_irq_state(s, 0, resetprio); + + if (s->virt_extn) { + /* vCPU states are stored at indexes GIC_NCPU .. GIC_NCPU+num_cpu. + * The exposed vCPU interface does not have security extensions. + */ + arm_gic_common_reset_irq_state(s, GIC_NCPU, 0); } + for (i = 0; i < GIC_NR_SGIS; i++) { GIC_DIST_SET_ENABLED(i, ALL_CPU_MASK); GIC_DIST_SET_EDGE_TRIGGER(i); @@ -226,6 +311,19 @@ static void arm_gic_common_reset(DeviceState *dev) } } + if (s->virt_extn) { + for (i = 0; i < s->num_lrs; i++) { + for (j = 0; j < s->num_cpu; j++) { + s->h_lr[i][j] = 0; + } + } + + for (i = 0; i < s->num_cpu; i++) { + s->h_hcr[i] = 0; + s->h_misr[i] = 0; + } + } + s->ctlr = 0; } @@ -255,6 +353,8 @@ static Property arm_gic_common_properties[] = { DEFINE_PROP_UINT32("revision", GICState, revision, 1), /* True if the GIC should implement the security extensions */ DEFINE_PROP_BOOL("has-security-extensions", GICState, security_extn, 0), + /* True if the GIC should implement the virtualization extensions */ + DEFINE_PROP_BOOL("has-virtualization-extensions", GICState, virt_extn, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 4b611c8..a611e8e 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -511,6 +511,12 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) return; } + if (s->virt_extn) { + error_setg(errp, "the in-kernel VGIC does not implement the " + "virtualization extensions"); + return; + } + if (!kvm_arm_gic_can_save_restore(s)) { error_setg(&s->migration_blocker, "This operating system kernel does " "not support vGICv2 migration"); @@ -522,7 +528,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) } } - gic_init_irqs_and_mmio(s, kvm_arm_gicv2_set_irq, NULL); + gic_init_irqs_and_mmio(s, kvm_arm_gicv2_set_irq, NULL, NULL); for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) { qemu_irq irq = qdev_get_gpio_in(dev, i); diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index a2075a9..c85427c 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -94,4 +94,9 @@ static inline bool gic_test_pending(GICState *s, int irq, int cm) } } +static inline bool gic_is_vcpu(int cpu) +{ + return cpu >= GIC_NCPU; +} + #endif /* QEMU_ARM_GIC_INTERNAL_H */ |