mirror of
https://github.com/qemu/qemu.git
synced 2024-11-29 14:53:35 +08:00
hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers
Implement the registers in the GICv3 CPU interface which generate new SGI interrupts. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org> Tested-by: Shannon Zhao <shannon.zhao@linaro.org> Message-id: 1465915112-29272-18-git-send-email-peter.maydell@linaro.org
This commit is contained in:
parent
f7b9358e2c
commit
b1a0eb777d
@ -331,6 +331,95 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
gicv3_cpuif_update(cs);
|
||||
}
|
||||
|
||||
static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs,
|
||||
uint64_t value, int grp, bool ns)
|
||||
{
|
||||
GICv3State *s = cs->gic;
|
||||
|
||||
/* Extract Aff3/Aff2/Aff1 and shift into the bottom 24 bits */
|
||||
uint64_t aff = extract64(value, 48, 8) << 16 |
|
||||
extract64(value, 32, 8) << 8 |
|
||||
extract64(value, 16, 8);
|
||||
uint32_t targetlist = extract64(value, 0, 16);
|
||||
uint32_t irq = extract64(value, 24, 4);
|
||||
bool irm = extract64(value, 40, 1);
|
||||
int i;
|
||||
|
||||
if (grp == GICV3_G1 && s->gicd_ctlr & GICD_CTLR_DS) {
|
||||
/* If GICD_CTLR.DS == 1, the Distributor treats Secure Group 1
|
||||
* interrupts as Group 0 interrupts and must send Secure Group 0
|
||||
* interrupts to the target CPUs.
|
||||
*/
|
||||
grp = GICV3_G0;
|
||||
}
|
||||
|
||||
trace_gicv3_icc_generate_sgi(gicv3_redist_affid(cs), irq, irm,
|
||||
aff, targetlist);
|
||||
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
GICv3CPUState *ocs = &s->cpu[i];
|
||||
|
||||
if (irm) {
|
||||
/* IRM == 1 : route to all CPUs except self */
|
||||
if (cs == ocs) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
/* IRM == 0 : route to Aff3.Aff2.Aff1.n for all n in [0..15]
|
||||
* where the corresponding bit is set in targetlist
|
||||
*/
|
||||
int aff0;
|
||||
|
||||
if (ocs->gicr_typer >> 40 != aff) {
|
||||
continue;
|
||||
}
|
||||
aff0 = extract64(ocs->gicr_typer, 32, 8);
|
||||
if (aff0 > 15 || extract32(targetlist, aff0, 1) == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* The redistributor will check against its own GICR_NSACR as needed */
|
||||
gicv3_redist_send_sgi(ocs, grp, irq, ns);
|
||||
}
|
||||
}
|
||||
|
||||
static void icc_sgi0r_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
/* Generate Secure Group 0 SGI. */
|
||||
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||
bool ns = !arm_is_secure(env);
|
||||
|
||||
icc_generate_sgi(env, cs, value, GICV3_G0, ns);
|
||||
}
|
||||
|
||||
static void icc_sgi1r_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
/* Generate Group 1 SGI for the current Security state */
|
||||
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||
int grp;
|
||||
bool ns = !arm_is_secure(env);
|
||||
|
||||
grp = ns ? GICV3_G1NS : GICV3_G1;
|
||||
icc_generate_sgi(env, cs, value, grp, ns);
|
||||
}
|
||||
|
||||
static void icc_asgi1r_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
/* Generate Group 1 SGI for the Security state that is not
|
||||
* the current state
|
||||
*/
|
||||
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||
int grp;
|
||||
bool ns = !arm_is_secure(env);
|
||||
|
||||
grp = ns ? GICV3_G1 : GICV3_G1NS;
|
||||
icc_generate_sgi(env, cs, value, grp, ns);
|
||||
}
|
||||
|
||||
static uint64_t icc_igrpen_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||
@ -673,6 +762,42 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
|
||||
.readfn = icc_ap_read,
|
||||
.writefn = icc_ap_write,
|
||||
},
|
||||
{ .name = "ICC_SGI1R_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 5,
|
||||
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||
.access = PL1_W, .accessfn = gicv3_irqfiq_access,
|
||||
.writefn = icc_sgi1r_write,
|
||||
},
|
||||
{ .name = "ICC_SGI1R",
|
||||
.cp = 15, .opc1 = 0, .crm = 12,
|
||||
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_RAW,
|
||||
.access = PL1_W, .accessfn = gicv3_irqfiq_access,
|
||||
.writefn = icc_sgi1r_write,
|
||||
},
|
||||
{ .name = "ICC_ASGI1R_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 6,
|
||||
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||
.access = PL1_W, .accessfn = gicv3_irqfiq_access,
|
||||
.writefn = icc_asgi1r_write,
|
||||
},
|
||||
{ .name = "ICC_ASGI1R",
|
||||
.cp = 15, .opc1 = 1, .crm = 12,
|
||||
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_RAW,
|
||||
.access = PL1_W, .accessfn = gicv3_irqfiq_access,
|
||||
.writefn = icc_asgi1r_write,
|
||||
},
|
||||
{ .name = "ICC_SGI0R_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 7,
|
||||
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||
.access = PL1_W, .accessfn = gicv3_irqfiq_access,
|
||||
.writefn = icc_sgi0r_write,
|
||||
},
|
||||
{ .name = "ICC_SGI0R",
|
||||
.cp = 15, .opc1 = 2, .crm = 12,
|
||||
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_RAW,
|
||||
.access = PL1_W, .accessfn = gicv3_irqfiq_access,
|
||||
.writefn = icc_sgi0r_write,
|
||||
},
|
||||
/* This register is banked */
|
||||
{ .name = "ICC_BPR1_EL1", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 3,
|
||||
|
@ -27,6 +27,13 @@ static uint32_t mask_group(GICv3CPUState *cs, MemTxAttrs attrs)
|
||||
return 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
static int gicr_ns_access(GICv3CPUState *cs, int irq)
|
||||
{
|
||||
/* Return the 2 bit NSACR.NS_access field for this SGI */
|
||||
assert(irq < 16);
|
||||
return extract32(cs->gicr_nsacr, irq * 2, 2);
|
||||
}
|
||||
|
||||
static void gicr_write_set_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
|
||||
uint32_t *reg, uint32_t val)
|
||||
{
|
||||
@ -520,3 +527,36 @@ void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
|
||||
|
||||
gicv3_redist_update(cs);
|
||||
}
|
||||
|
||||
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns)
|
||||
{
|
||||
/* Update redistributor state for a generated SGI */
|
||||
int irqgrp = gicv3_irq_group(cs->gic, cs, irq);
|
||||
|
||||
/* If we are asked for a Secure Group 1 SGI and it's actually
|
||||
* configured as Secure Group 0 this is OK (subject to the usual
|
||||
* NSACR checks).
|
||||
*/
|
||||
if (grp == GICV3_G1 && irqgrp == GICV3_G0) {
|
||||
grp = GICV3_G0;
|
||||
}
|
||||
|
||||
if (grp != irqgrp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ns && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
|
||||
/* If security is enabled we must test the NSACR bits */
|
||||
int nsaccess = gicr_ns_access(cs, irq);
|
||||
|
||||
if ((irqgrp == GICV3_G0 && nsaccess < 1) ||
|
||||
(irqgrp == GICV3_G1 && nsaccess < 2)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* OK, we can accept the SGI */
|
||||
trace_gicv3_redist_send_sgi(gicv3_redist_affid(cs), irq);
|
||||
cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 1);
|
||||
gicv3_redist_update(cs);
|
||||
}
|
||||
|
@ -211,6 +211,7 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
|
||||
unsigned size, MemTxAttrs attrs);
|
||||
void gicv3_dist_set_irq(GICv3State *s, int irq, int level);
|
||||
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level);
|
||||
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns);
|
||||
void gicv3_init_cpuif(GICv3State *s);
|
||||
|
||||
/**
|
||||
|
@ -2183,6 +2183,7 @@ gicv3_icc_ctlr_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 read cpu
|
||||
gicv3_icc_ctlr_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 write cpu %x value 0x%" PRIx64
|
||||
gicv3_cpuif_update(uint32_t cpuid, int irq, int grp, int prio) "GICv3 CPU i/f %x HPPI update: irq %d group %d prio %d"
|
||||
gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f %x HPPI update: setting FIQ %d IRQ %d"
|
||||
gicv3_icc_generate_sgi(uint32_t cpuid, int irq, int irm, uint32_t aff, uint32_t targetlist) "GICv3 CPU i/f %x generating SGI %d IRM %d target affinity 0x%xxx targetlist 0x%x"
|
||||
|
||||
# hw/intc/arm_gicv3_dist.c
|
||||
gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
|
||||
@ -2197,3 +2198,4 @@ gicv3_redist_badread(uint32_t cpu, uint64_t offset, unsigned size, bool secure)
|
||||
gicv3_redist_write(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
|
||||
gicv3_redist_badwrite(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
|
||||
gicv3_redist_set_irq(uint32_t cpu, int irq, int level) "GICv3 redistributor %x interrupt %d level changed to %d"
|
||||
gicv3_redist_send_sgi(uint32_t cpu, int irq) "GICv3 redistributor %x pending SGI %d"
|
||||
|
Loading…
Reference in New Issue
Block a user