nvic: Make SHPR registers banked

Make the set_prio() function take a bool indicating
whether to pend the secure or non-secure version of a banked
interrupt, and use this to implement the correct banking
semantics for the SHPR registers.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 1505240046-11454-11-git-send-email-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2017-09-12 19:13:57 +01:00
parent 2fb50a3340
commit e6a0d3500d
2 changed files with 88 additions and 10 deletions

View File

@ -349,15 +349,40 @@ int armv7m_nvic_raw_execution_priority(void *opaque)
return s->exception_prio;
}
/* caller must call nvic_irq_update() after this */
static void set_prio(NVICState *s, unsigned irq, uint8_t prio)
/* caller must call nvic_irq_update() after this.
* secure indicates the bank to use for banked exceptions (we assert if
* we are passed secure=true for a non-banked exception).
*/
static void set_prio(NVICState *s, unsigned irq, bool secure, uint8_t prio)
{
assert(irq > ARMV7M_EXCP_NMI); /* only use for configurable prios */
assert(irq < s->num_irq);
s->vectors[irq].prio = prio;
if (secure) {
assert(exc_is_banked(irq));
s->sec_vectors[irq].prio = prio;
} else {
s->vectors[irq].prio = prio;
}
trace_nvic_set_prio(irq, prio);
trace_nvic_set_prio(irq, secure, prio);
}
/* Return the current raw priority register value.
* secure indicates the bank to use for banked exceptions (we assert if
* we are passed secure=true for a non-banked exception).
*/
static int get_prio(NVICState *s, unsigned irq, bool secure)
{
assert(irq > ARMV7M_EXCP_NMI); /* only use for configurable prios */
assert(irq < s->num_irq);
if (secure) {
assert(exc_is_banked(irq));
return s->sec_vectors[irq].prio;
} else {
return s->vectors[irq].prio;
}
}
/* Recompute state and assert irq line accordingly.
@ -1149,6 +1174,47 @@ static bool nvic_user_access_ok(NVICState *s, hwaddr offset, MemTxAttrs attrs)
}
}
static int shpr_bank(NVICState *s, int exc, MemTxAttrs attrs)
{
/* Behaviour for the SHPR register field for this exception:
* return M_REG_NS to use the nonsecure vector (including for
* non-banked exceptions), M_REG_S for the secure version of
* a banked exception, and -1 if this field should RAZ/WI.
*/
switch (exc) {
case ARMV7M_EXCP_MEM:
case ARMV7M_EXCP_USAGE:
case ARMV7M_EXCP_SVC:
case ARMV7M_EXCP_PENDSV:
case ARMV7M_EXCP_SYSTICK:
/* Banked exceptions */
return attrs.secure;
case ARMV7M_EXCP_BUS:
/* Not banked, RAZ/WI from nonsecure if BFHFNMINS is zero */
if (!attrs.secure &&
!(s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
return -1;
}
return M_REG_NS;
case ARMV7M_EXCP_SECURE:
/* Not banked, RAZ/WI from nonsecure */
if (!attrs.secure) {
return -1;
}
return M_REG_NS;
case ARMV7M_EXCP_DEBUG:
/* Not banked. TODO should RAZ/WI if DEMCR.SDME is set */
return M_REG_NS;
case 8 ... 10:
case 13:
/* RES0 */
return -1;
default:
/* Not reachable due to decode of SHPR register addresses */
g_assert_not_reached();
}
}
static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
uint64_t *data, unsigned size,
MemTxAttrs attrs)
@ -1213,10 +1279,16 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
}
}
break;
case 0xd18 ... 0xd23: /* System Handler Priority. */
case 0xd18 ... 0xd23: /* System Handler Priority (SHPR1, SHPR2, SHPR3) */
val = 0;
for (i = 0; i < size; i++) {
val |= s->vectors[(offset - 0xd14) + i].prio << (i * 8);
unsigned hdlidx = (offset - 0xd14) + i;
int sbank = shpr_bank(s, hdlidx, attrs);
if (sbank < 0) {
continue;
}
val = deposit32(val, i * 8, 8, get_prio(s, hdlidx, sbank));
}
break;
case 0xfe0 ... 0xfff: /* ID. */
@ -1299,15 +1371,21 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
for (i = 0; i < size && startvec + i < s->num_irq; i++) {
if (attrs.secure || s->itns[startvec + i]) {
set_prio(s, startvec + i, (value >> (i * 8)) & 0xff);
set_prio(s, startvec + i, false, (value >> (i * 8)) & 0xff);
}
}
nvic_irq_update(s);
return MEMTX_OK;
case 0xd18 ... 0xd23: /* System Handler Priority. */
case 0xd18 ... 0xd23: /* System Handler Priority (SHPR1, SHPR2, SHPR3) */
for (i = 0; i < size; i++) {
unsigned hdlidx = (offset - 0xd14) + i;
set_prio(s, hdlidx, (value >> (i * 8)) & 0xff);
int newprio = extract32(value, i * 8, 8);
int sbank = shpr_bank(s, hdlidx, attrs);
if (sbank < 0) {
continue;
}
set_prio(s, hdlidx, sbank, newprio);
}
nvic_irq_update(s);
return MEMTX_OK;

View File

@ -169,7 +169,7 @@ gicv3_redist_send_sgi(uint32_t cpu, int irq) "GICv3 redistributor 0x%x pending S
# hw/intc/armv7m_nvic.c
nvic_recompute_state(int vectpending, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d vectpending_prio %d exception_prio %d"
nvic_recompute_state_secure(int vectpending, bool vectpending_is_s_banked, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d is_s_banked %d vectpending_prio %d exception_prio %d"
nvic_set_prio(int irq, uint8_t prio) "NVIC set irq %d priority %d"
nvic_set_prio(int irq, bool secure, uint8_t prio) "NVIC set irq %d secure-bank %d priority %d"
nvic_irq_update(int vectpending, int pendprio, int exception_prio, int level) "NVIC vectpending %d pending prio %d exception_prio %d: setting irq line to %d"
nvic_escalate_prio(int irq, int irqprio, int runprio) "NVIC escalating irq %d to HardFault: insufficient priority %d >= %d"
nvic_escalate_disabled(int irq) "NVIC escalating irq %d to HardFault: disabled"