diff options
Diffstat (limited to 'hw/intc/arm_gic_kvm.c')
-rw-r--r-- | hw/intc/arm_gic_kvm.c | 59 |
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, ®, 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, ®, 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, ®, 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, ®, false); @@ -454,21 +471,14 @@ static void kvm_arm_gic_get(GICState *s) /* GICD_IIDR -> ? */ kvm_gicd_access(s, 0x8, 0, ®, 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, ®, 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, ®, false); - s->cpu_enabled[cpu] = (reg & 1); + s->cpu_ctlr[cpu] = reg; /* GICC_PMR -> s->priority_mask[cpu] */ kvm_gicc_access(s, 0x04, cpu, ®, 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; |