diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 26ed7ea58a..de73dc9f54 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -276,16 +276,23 @@ static void gic_activate_irq(GICState *s, int cpu, int irq) * and update the running priority. */ int prio = gic_get_group_priority(s, cpu, irq); - int preemption_level = prio >> (GIC_MIN_BPR + 1); + int min_bpr = gic_is_vcpu(cpu) ? GIC_VIRT_MIN_BPR : GIC_MIN_BPR; + int preemption_level = prio >> (min_bpr + 1); int regno = preemption_level / 32; int bitno = preemption_level % 32; + uint32_t *papr = NULL; - if (gic_has_groups(s) && gic_test_group(s, irq, cpu)) { - s->nsapr[regno][cpu] |= (1 << bitno); + if (gic_is_vcpu(cpu)) { + assert(regno == 0); + papr = &s->h_apr[gic_get_vcpu_real_id(cpu)]; + } else if (gic_has_groups(s) && gic_test_group(s, irq, cpu)) { + papr = &s->nsapr[regno][cpu]; } else { - s->apr[regno][cpu] |= (1 << bitno); + papr = &s->apr[regno][cpu]; } + *papr |= (1 << bitno); + s->running_priority[cpu] = prio; gic_set_active(s, irq, cpu); } @@ -296,6 +303,16 @@ static int gic_get_prio_from_apr_bits(GICState *s, int cpu) * on the set bits in the Active Priority Registers. */ int i; + + if (gic_is_vcpu(cpu)) { + uint32_t apr = s->h_apr[gic_get_vcpu_real_id(cpu)]; + if (apr) { + return ctz32(apr) << (GIC_VIRT_MIN_BPR + 1); + } else { + return 0x100; + } + } + for (i = 0; i < GIC_NR_APRS; i++) { uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu]; if (!apr) { @@ -324,16 +341,25 @@ static void gic_drop_prio(GICState *s, int cpu, int group) * running priority will be wrong, so interrupts that should preempt * might not do so, and interrupts that should not preempt might do so. */ - int i; + if (gic_is_vcpu(cpu)) { + int rcpu = gic_get_vcpu_real_id(cpu); - for (i = 0; i < GIC_NR_APRS; i++) { - uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu]; - if (!*papr) { - continue; + if (s->h_apr[rcpu]) { + /* Clear lowest set bit */ + s->h_apr[rcpu] &= s->h_apr[rcpu] - 1; + } + } else { + int i; + + for (i = 0; i < GIC_NR_APRS; i++) { + uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu]; + if (!*papr) { + continue; + } + /* Clear lowest set bit */ + *papr &= *papr - 1; + break; } - /* Clear lowest set bit */ - *papr &= *papr - 1; - break; } s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu);