aboutsummaryrefslogtreecommitdiff
path: root/hw/intc/arm_gic_kvm.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/intc/arm_gic_kvm.c')
-rw-r--r--hw/intc/arm_gic_kvm.c59
1 files changed, 39 insertions, 20 deletions
diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
index e1952ad974..2cb7d255d2 100644
--- a/hw/intc/arm_gic_kvm.c
+++ b/hw/intc/arm_gic_kvm.c
@@ -176,6 +176,20 @@ static void translate_clear(GICState *s, int irq, int cpu,
}
}
+static void translate_group(GICState *s, int irq, int cpu,
+ uint32_t *field, bool to_kernel)
+{
+ int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
+
+ if (to_kernel) {
+ *field = GIC_TEST_GROUP(irq, cm);
+ } else {
+ if (*field & 1) {
+ GIC_SET_GROUP(irq, cm);
+ }
+ }
+}
+
static void translate_enabled(GICState *s, int irq, int cpu,
uint32_t *field, bool to_kernel)
{
@@ -237,7 +251,7 @@ static void translate_priority(GICState *s, int irq, int cpu,
if (to_kernel) {
*field = GIC_GET_PRIORITY(irq, cpu) & 0xff;
} else {
- gic_set_priority(s, cpu, irq, *field & 0xff);
+ gic_set_priority(s, cpu, irq, *field & 0xff, MEMTXATTRS_UNSPECIFIED);
}
}
@@ -339,8 +353,8 @@ static void kvm_arm_gic_put(GICState *s)
* Distributor State
*/
- /* s->enabled -> GICD_CTLR */
- reg = s->enabled;
+ /* s->ctlr -> GICD_CTLR */
+ reg = s->ctlr;
kvm_gicd_access(s, 0x0, 0, &reg, true);
/* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */
@@ -365,6 +379,9 @@ static void kvm_arm_gic_put(GICState *s)
kvm_dist_put(s, 0x180, 1, s->num_irq, translate_clear);
kvm_dist_put(s, 0x100, 1, s->num_irq, translate_enabled);
+ /* irq_state[n].group -> GICD_IGROUPRn */
+ kvm_dist_put(s, 0x80, 1, s->num_irq, translate_group);
+
/* s->irq_target[irq] -> GICD_ITARGETSRn
* (restore targets before pending to ensure the pending state is set on
* the appropriate CPU interfaces in the kernel) */
@@ -397,8 +414,8 @@ static void kvm_arm_gic_put(GICState *s)
*/
for (cpu = 0; cpu < s->num_cpu; cpu++) {
- /* s->cpu_enabled[cpu] -> GICC_CTLR */
- reg = s->cpu_enabled[cpu];
+ /* s->cpu_ctlr[cpu] -> GICC_CTLR */
+ reg = s->cpu_ctlr[cpu];
kvm_gicc_access(s, 0x00, cpu, &reg, true);
/* s->priority_mask[cpu] -> GICC_PMR */
@@ -436,9 +453,9 @@ static void kvm_arm_gic_get(GICState *s)
* Distributor State
*/
- /* GICD_CTLR -> s->enabled */
+ /* GICD_CTLR -> s->ctlr */
kvm_gicd_access(s, 0x0, 0, &reg, false);
- s->enabled = reg & 1;
+ s->ctlr = reg;
/* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */
kvm_gicd_access(s, 0x4, 0, &reg, false);
@@ -454,21 +471,14 @@ static void kvm_arm_gic_get(GICState *s)
/* GICD_IIDR -> ? */
kvm_gicd_access(s, 0x8, 0, &reg, false);
- /* Verify no GROUP 1 interrupts configured in the kernel */
- for_each_irq_reg(i, s->num_irq, 1) {
- kvm_gicd_access(s, 0x80 + (i * 4), 0, &reg, false);
- if (reg != 0) {
- fprintf(stderr, "Unsupported GICD_IGROUPRn value: %08x\n",
- reg);
- abort();
- }
- }
-
/* Clear all the IRQ settings */
for (i = 0; i < s->num_irq; i++) {
memset(&s->irq_state[i], 0, sizeof(s->irq_state[0]));
}
+ /* GICD_IGROUPRn -> irq_state[n].group */
+ kvm_dist_get(s, 0x80, 1, s->num_irq, translate_group);
+
/* GICD_ISENABLERn -> irq_state[n].enabled */
kvm_dist_get(s, 0x100, 1, s->num_irq, translate_enabled);
@@ -496,9 +506,9 @@ static void kvm_arm_gic_get(GICState *s)
*/
for (cpu = 0; cpu < s->num_cpu; cpu++) {
- /* GICC_CTLR -> s->cpu_enabled[cpu] */
+ /* GICC_CTLR -> s->cpu_ctlr[cpu] */
kvm_gicc_access(s, 0x00, cpu, &reg, false);
- s->cpu_enabled[cpu] = (reg & 1);
+ s->cpu_ctlr[cpu] = reg;
/* GICC_PMR -> s->priority_mask[cpu] */
kvm_gicc_access(s, 0x04, cpu, &reg, false);
@@ -544,6 +554,12 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
return;
}
+ if (s->security_extn) {
+ error_setg(errp, "the in-kernel VGIC does not implement the "
+ "security extensions");
+ return;
+ }
+
i = s->num_irq - GIC_INTERNAL;
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
* GPIO array layout is thus:
@@ -554,12 +570,15 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
*/
i += (GIC_INTERNAL * s->num_cpu);
qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
- /* We never use our outbound IRQ lines but provide them so that
+ /* We never use our outbound IRQ/FIQ lines but provide them so that
* we maintain the same interface as the non-KVM GIC.
*/
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->parent_irq[i]);
}
+ for (i = 0; i < s->num_cpu; i++) {
+ sysbus_init_irq(sbd, &s->parent_fiq[i]);
+ }
/* Try to create the device via the device control API */
s->dev_fd = -1;