mirror of
https://github.com/qemu/qemu.git
synced 2026-07-09 01:56:21 +00:00
target/arm: GICv5 cpuif: Implement ICC_HPPIR_EL1
Implement ICC_HPPIR_EL1, which the guest can use to read the current highest priority pending interrupt. Like APR, PCR and CR0, this is banked, with the _EL1 register reading the answer for the current logical interrupt domain, and the _EL3 register reading the answer for the EL3 interrupt domain. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Message-id: 20260327111700.795099-47-peter.maydell@linaro.org
This commit is contained in:
@@ -527,6 +527,16 @@ static void irs_recall_hppis(GICv5 *s, GICv5Domain domain)
|
||||
}
|
||||
}
|
||||
|
||||
GICv5PendingIrq gicv5_get_hppi(GICv5Common *cs, GICv5Domain domain,
|
||||
uint32_t iaffid)
|
||||
{
|
||||
GICv5 *s = ARM_GICV5(cs);
|
||||
int cpuidx = irs_cpuidx_from_iaffid(cs, iaffid);
|
||||
|
||||
assert(cpuidx >= 0);
|
||||
return s->hppi[domain][cpuidx];
|
||||
}
|
||||
|
||||
static hwaddr l1_iste_addr(GICv5Common *cs, const GICv5ISTConfig *cfg,
|
||||
uint32_t id)
|
||||
{
|
||||
|
||||
@@ -175,4 +175,17 @@ uint64_t gicv5_request_config(GICv5Common *cs, uint32_t id, GICv5Domain domain,
|
||||
*/
|
||||
void gicv5_forward_interrupt(ARMCPU *cpu, GICv5Domain domain);
|
||||
|
||||
/**
|
||||
* gicv5_get_hppi
|
||||
* @cs: GIC IRS to query
|
||||
* @domain: interrupt domain to act on
|
||||
* @iaffid: IAFFID of this CPU interface
|
||||
*
|
||||
* Ask the IRS for the highest priority pending interrupt that it has
|
||||
* for this CPU. This returns the equivalent of what in the stream
|
||||
* protocol is the outstanding interrupt sent with a Forward packet.
|
||||
*/
|
||||
GICv5PendingIrq gicv5_get_hppi(GICv5Common *cs, GICv5Domain domain,
|
||||
uint32_t iaffid);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -51,6 +51,10 @@ FIELD(ICC_CR0, PID, 38, 1)
|
||||
|
||||
FIELD(ICC_PCR, PRIORITY, 0, 5)
|
||||
|
||||
FIELD(ICC_HPPIR_EL1, ID, 0, 24)
|
||||
FIELD(ICC_HPPIR_EL1, TYPE, 29, 3)
|
||||
FIELD(ICC_HPPIR_EL1, HPPIV, 32, 1)
|
||||
|
||||
/*
|
||||
* We implement 24 bits of interrupt ID, the mandated 5 bits of priority,
|
||||
* and no legacy GICv3.3 vcpu interface (yet)
|
||||
@@ -114,6 +118,51 @@ static uint64_t gic_running_prio(CPUARMState *env, GICv5Domain domain)
|
||||
return hap < 32 ? hap : PRIO_IDLE;
|
||||
}
|
||||
|
||||
static GICv5PendingIrq gic_hppi(CPUARMState *env, GICv5Domain domain)
|
||||
{
|
||||
/*
|
||||
* Return the current highest priority pending interrupt for the
|
||||
* specified domain, if it has sufficient priority to preempt. The
|
||||
* intid field of the return value will be in the format of the
|
||||
* ICC_HPPIR register (and will be zero if and only if there is no
|
||||
* interrupt that can preempt).
|
||||
*/
|
||||
|
||||
GICv5Common *gic = gicv5_get_gic(env);
|
||||
GICv5PendingIrq best, irs_hppi;
|
||||
|
||||
if (!(env->gicv5_cpuif.icc_cr0[domain] & R_ICC_CR0_EN_MASK)) {
|
||||
/* If cpuif is disabled there is no HPPI */
|
||||
return (GICv5PendingIrq) { .intid = 0, .prio = PRIO_IDLE };
|
||||
}
|
||||
|
||||
irs_hppi = gicv5_get_hppi(gic, domain, env->gicv5_iaffid);
|
||||
|
||||
/*
|
||||
* If the best PPI and the best interrupt from the IRS have the
|
||||
* same priority, it's IMPDEF which we pick (R_VVBPS). We choose
|
||||
* the PPI.
|
||||
*/
|
||||
if (env->gicv5_cpuif.ppi_hppi[domain].prio <= irs_hppi.prio) {
|
||||
best = env->gicv5_cpuif.ppi_hppi[domain];
|
||||
} else {
|
||||
best = irs_hppi;
|
||||
}
|
||||
|
||||
/*
|
||||
* D_MSQKF: an interrupt has sufficient priority if its priority
|
||||
* is higher than the current running priority and equal to or
|
||||
* higher than the priority mask.
|
||||
*/
|
||||
if (best.prio == PRIO_IDLE ||
|
||||
best.prio > env->gicv5_cpuif.icc_pcr[domain] ||
|
||||
best.prio >= gic_running_prio(env, domain)) {
|
||||
return (GICv5PendingIrq) { .intid = 0, .prio = PRIO_IDLE };
|
||||
}
|
||||
best.intid |= R_ICC_HPPIR_EL1_HPPIV_MASK;
|
||||
return best;
|
||||
}
|
||||
|
||||
static void gic_recalc_ppi_hppi(CPUARMState *env)
|
||||
{
|
||||
/*
|
||||
@@ -407,6 +456,13 @@ static void gic_icc_pcr_el1_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t gic_icc_hppir_el1_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
GICv5Domain domain = gicv5_logical_domain(env);
|
||||
GICv5PendingIrq hppi = gic_hppi(env, domain);
|
||||
return hppi.intid;
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo gicv5_cpuif_reginfo[] = {
|
||||
/*
|
||||
* Barrier: wait until the effects of a cpuif system register
|
||||
@@ -522,6 +578,11 @@ static const ARMCPRegInfo gicv5_cpuif_reginfo[] = {
|
||||
.fieldoffset = offsetof(CPUARMState, gicv5_cpuif.ppi_hm[1]),
|
||||
.resetvalue = PPI_HMR1_RESET,
|
||||
},
|
||||
{ .name = "ICC_HPPIR_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 10, .opc2 = 3,
|
||||
.access = PL1_R, .type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||
.readfn = gic_icc_hppir_el1_read,
|
||||
},
|
||||
{ .name = "ICC_PPI_ENABLER0_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 10, .opc2 = 6,
|
||||
.access = PL1_RW, .type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||
|
||||
Reference in New Issue
Block a user