diff options
Diffstat (limited to 'hw/intc/gicv3_internal.h')
-rw-r--r-- | hw/intc/gicv3_internal.h | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h index 97c9d758a3..2ee9eebec8 100644 --- a/hw/intc/gicv3_internal.h +++ b/hw/intc/gicv3_internal.h @@ -159,6 +159,63 @@ #define ICC_CTLR_EL3_A3V (1U << 15) #define ICC_CTLR_EL3_NDS (1U << 17) +/* Functions internal to the emulated GICv3 */ + +/** + * gicv3_redist_update: + * @cs: GICv3CPUState for this redistributor + * + * Recalculate the highest priority pending interrupt after a + * change to redistributor state, and inform the CPU accordingly. + */ +void gicv3_redist_update(GICv3CPUState *cs); + +/** + * gicv3_update: + * @s: GICv3State + * @start: first interrupt whose state changed + * @len: length of the range of interrupts whose state changed + * + * Recalculate the highest priority pending interrupts after a + * change to the distributor state affecting @len interrupts + * starting at @start, and inform the CPUs accordingly. + */ +void gicv3_update(GICv3State *s, int start, int len); + +/** + * gicv3_full_update_noirqset: + * @s: GICv3State + * + * Recalculate the cached information about highest priority + * pending interrupts, but don't inform the CPUs. This should be + * called after an incoming migration has loaded new state. + */ +void gicv3_full_update_noirqset(GICv3State *s); + +/** + * gicv3_full_update: + * @s: GICv3State + * + * Recalculate the highest priority pending interrupts after + * a change that could affect the status of all interrupts, + * and inform the CPUs accordingly. + */ +void gicv3_full_update(GICv3State *s); + +/** + * gicv3_cpuif_update: + * @cs: GICv3CPUState for the CPU to update + * + * Recalculate whether to assert the IRQ or FIQ lines after a change + * to the current highest priority pending interrupt, the CPU's + * current running priority or the CPU's current exception level or + * security state. + */ +static inline void gicv3_cpuif_update(GICv3CPUState *cs) +{ + /* This will be implemented in a later commit. */ +} + static inline uint32_t gicv3_iidr(void) { /* Return the Implementer Identification Register value @@ -184,6 +241,32 @@ static inline uint32_t gicv3_idreg(int regoffset) } /** + * gicv3_irq_group: + * + * Return the group which this interrupt is configured as (GICV3_G0, + * GICV3_G1 or GICV3_G1NS). + */ +static inline int gicv3_irq_group(GICv3State *s, GICv3CPUState *cs, int irq) +{ + bool grpbit, grpmodbit; + + if (irq < GIC_INTERNAL) { + grpbit = extract32(cs->gicr_igroupr0, irq, 1); + grpmodbit = extract32(cs->gicr_igrpmodr0, irq, 1); + } else { + grpbit = gicv3_gicd_group_test(s, irq); + grpmodbit = gicv3_gicd_grpmod_test(s, irq); + } + if (grpbit) { + return GICV3_G1NS; + } + if (s->gicd_ctlr & GICD_CTLR_DS) { + return GICV3_G0; + } + return grpmodbit ? GICV3_G1 : GICV3_G0; +} + +/** * gicv3_redist_affid: * * Return the 32-bit affinity ID of the CPU connected to this redistributor @@ -193,4 +276,42 @@ static inline uint32_t gicv3_redist_affid(GICv3CPUState *cs) return cs->gicr_typer >> 32; } +/** + * gicv3_cache_target_cpustate: + * + * Update the cached CPU state corresponding to the target for this interrupt + * (which is kept in s->gicd_irouter_target[]). + */ +static inline void gicv3_cache_target_cpustate(GICv3State *s, int irq) +{ + GICv3CPUState *cs = NULL; + int i; + uint32_t tgtaff = extract64(s->gicd_irouter[irq], 0, 24) | + extract64(s->gicd_irouter[irq], 32, 8) << 24; + + for (i = 0; i < s->num_cpu; i++) { + if (s->cpu[i].gicr_typer >> 32 == tgtaff) { + cs = &s->cpu[i]; + break; + } + } + + s->gicd_irouter_target[irq] = cs; +} + +/** + * gicv3_cache_all_target_cpustates: + * + * Populate the entire cache of CPU state pointers for interrupt targets + * (eg after inbound migration or CPU reset) + */ +static inline void gicv3_cache_all_target_cpustates(GICv3State *s) +{ + int irq; + + for (irq = GIC_INTERNAL; irq < GICV3_MAXIRQ; irq++) { + gicv3_cache_target_cpustate(s, irq); + } +} + #endif /* !QEMU_ARM_GIC_INTERNAL_H */ |