|
@@ -21,7 +21,7 @@
|
|
#include "hw/intc/arm_gicv3.h"
|
|
#include "hw/intc/arm_gicv3.h"
|
|
#include "gicv3_internal.h"
|
|
#include "gicv3_internal.h"
|
|
|
|
|
|
-static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio)
|
|
|
|
|
|
+static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio, bool nmi)
|
|
{
|
|
{
|
|
/* Return true if this IRQ at this priority should take
|
|
/* Return true if this IRQ at this priority should take
|
|
* precedence over the current recorded highest priority
|
|
* precedence over the current recorded highest priority
|
|
@@ -30,14 +30,23 @@ static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio)
|
|
* is the same as this one (a property which the calling code
|
|
* is the same as this one (a property which the calling code
|
|
* relies on).
|
|
* relies on).
|
|
*/
|
|
*/
|
|
- if (prio < cs->hppi.prio) {
|
|
|
|
- return true;
|
|
|
|
|
|
+ if (prio != cs->hppi.prio) {
|
|
|
|
+ return prio < cs->hppi.prio;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * The same priority IRQ with non-maskable property should signal to
|
|
|
|
+ * the CPU as it have the priority higher than the labelled 0x80 or 0x00.
|
|
|
|
+ */
|
|
|
|
+ if (nmi != cs->hppi.nmi) {
|
|
|
|
+ return nmi;
|
|
}
|
|
}
|
|
|
|
+
|
|
/* If multiple pending interrupts have the same priority then it is an
|
|
/* If multiple pending interrupts have the same priority then it is an
|
|
* IMPDEF choice which of them to signal to the CPU. We choose to
|
|
* IMPDEF choice which of them to signal to the CPU. We choose to
|
|
* signal the one with the lowest interrupt number.
|
|
* signal the one with the lowest interrupt number.
|
|
*/
|
|
*/
|
|
- if (prio == cs->hppi.prio && irq <= cs->hppi.irq) {
|
|
|
|
|
|
+ if (irq <= cs->hppi.irq) {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
return false;
|
|
@@ -129,6 +138,40 @@ static uint32_t gicr_int_pending(GICv3CPUState *cs)
|
|
return pend;
|
|
return pend;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool gicv3_get_priority(GICv3CPUState *cs, bool is_redist, int irq,
|
|
|
|
+ uint8_t *prio)
|
|
|
|
+{
|
|
|
|
+ uint32_t nmi = 0x0;
|
|
|
|
+
|
|
|
|
+ if (is_redist) {
|
|
|
|
+ nmi = extract32(cs->gicr_inmir0, irq, 1);
|
|
|
|
+ } else {
|
|
|
|
+ nmi = *gic_bmp_ptr32(cs->gic->nmi, irq);
|
|
|
|
+ nmi = nmi & (1 << (irq & 0x1f));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (nmi) {
|
|
|
|
+ /* DS = 0 & Non-secure NMI */
|
|
|
|
+ if (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) &&
|
|
|
|
+ ((is_redist && extract32(cs->gicr_igroupr0, irq, 1)) ||
|
|
|
|
+ (!is_redist && gicv3_gicd_group_test(cs->gic, irq)))) {
|
|
|
|
+ *prio = 0x80;
|
|
|
|
+ } else {
|
|
|
|
+ *prio = 0x0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (is_redist) {
|
|
|
|
+ *prio = cs->gicr_ipriorityr[irq];
|
|
|
|
+ } else {
|
|
|
|
+ *prio = cs->gic->gicd_ipriority[irq];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
/* Update the interrupt status after state in a redistributor
|
|
/* Update the interrupt status after state in a redistributor
|
|
* or CPU interface has changed, but don't tell the CPU i/f.
|
|
* or CPU interface has changed, but don't tell the CPU i/f.
|
|
*/
|
|
*/
|
|
@@ -141,6 +184,7 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
|
|
uint8_t prio;
|
|
uint8_t prio;
|
|
int i;
|
|
int i;
|
|
uint32_t pend;
|
|
uint32_t pend;
|
|
|
|
+ bool nmi = false;
|
|
|
|
|
|
/* Find out which redistributor interrupts are eligible to be
|
|
/* Find out which redistributor interrupts are eligible to be
|
|
* signaled to the CPU interface.
|
|
* signaled to the CPU interface.
|
|
@@ -152,10 +196,11 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
|
|
if (!(pend & (1 << i))) {
|
|
if (!(pend & (1 << i))) {
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- prio = cs->gicr_ipriorityr[i];
|
|
|
|
- if (irqbetter(cs, i, prio)) {
|
|
|
|
|
|
+ nmi = gicv3_get_priority(cs, true, i, &prio);
|
|
|
|
+ if (irqbetter(cs, i, prio, nmi)) {
|
|
cs->hppi.irq = i;
|
|
cs->hppi.irq = i;
|
|
cs->hppi.prio = prio;
|
|
cs->hppi.prio = prio;
|
|
|
|
+ cs->hppi.nmi = nmi;
|
|
seenbetter = true;
|
|
seenbetter = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -168,9 +213,10 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
|
|
if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable &&
|
|
if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable &&
|
|
(cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) &&
|
|
(cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) &&
|
|
(cs->hpplpi.prio != 0xff)) {
|
|
(cs->hpplpi.prio != 0xff)) {
|
|
- if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio)) {
|
|
|
|
|
|
+ if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio, cs->hpplpi.nmi)) {
|
|
cs->hppi.irq = cs->hpplpi.irq;
|
|
cs->hppi.irq = cs->hpplpi.irq;
|
|
cs->hppi.prio = cs->hpplpi.prio;
|
|
cs->hppi.prio = cs->hpplpi.prio;
|
|
|
|
+ cs->hppi.nmi = cs->hpplpi.nmi;
|
|
cs->hppi.grp = cs->hpplpi.grp;
|
|
cs->hppi.grp = cs->hpplpi.grp;
|
|
seenbetter = true;
|
|
seenbetter = true;
|
|
}
|
|
}
|
|
@@ -213,6 +259,7 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len)
|
|
int i;
|
|
int i;
|
|
uint8_t prio;
|
|
uint8_t prio;
|
|
uint32_t pend = 0;
|
|
uint32_t pend = 0;
|
|
|
|
+ bool nmi = false;
|
|
|
|
|
|
assert(start >= GIC_INTERNAL);
|
|
assert(start >= GIC_INTERNAL);
|
|
assert(len > 0);
|
|
assert(len > 0);
|
|
@@ -240,10 +287,11 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len)
|
|
*/
|
|
*/
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- prio = s->gicd_ipriority[i];
|
|
|
|
- if (irqbetter(cs, i, prio)) {
|
|
|
|
|
|
+ nmi = gicv3_get_priority(cs, false, i, &prio);
|
|
|
|
+ if (irqbetter(cs, i, prio, nmi)) {
|
|
cs->hppi.irq = i;
|
|
cs->hppi.irq = i;
|
|
cs->hppi.prio = prio;
|
|
cs->hppi.prio = prio;
|
|
|
|
+ cs->hppi.nmi = nmi;
|
|
cs->seenbetter = true;
|
|
cs->seenbetter = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -293,6 +341,7 @@ void gicv3_full_update_noirqset(GICv3State *s)
|
|
|
|
|
|
for (i = 0; i < s->num_cpu; i++) {
|
|
for (i = 0; i < s->num_cpu; i++) {
|
|
s->cpu[i].hppi.prio = 0xff;
|
|
s->cpu[i].hppi.prio = 0xff;
|
|
|
|
+ s->cpu[i].hppi.nmi = false;
|
|
}
|
|
}
|
|
|
|
|
|
/* Note that we can guarantee that these functions will not
|
|
/* Note that we can guarantee that these functions will not
|