nvic: Make SHCSR banked for v8M

Handle banking of SHCSR: some register bits are banked between
Secure and Non-Secure, and some are only accessible to Secure.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 1505240046-11454-19-git-send-email-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2017-09-12 19:14:05 +01:00
parent 3f1e0eb7c3
commit 437d59c17e
1 changed files with 169 additions and 52 deletions

View File

@ -770,50 +770,117 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
val = cpu->env.v7m.ccr[attrs.secure];
val |= cpu->env.v7m.ccr[M_REG_NS] & R_V7M_CCR_BFHFNMIGN_MASK;
return val;
case 0xd24: /* System Handler Status. */
case 0xd24: /* System Handler Control and State (SHCSR) */
val = 0;
if (s->vectors[ARMV7M_EXCP_MEM].active) {
val |= (1 << 0);
if (attrs.secure) {
if (s->sec_vectors[ARMV7M_EXCP_MEM].active) {
val |= (1 << 0);
}
if (s->sec_vectors[ARMV7M_EXCP_HARD].active) {
val |= (1 << 2);
}
if (s->sec_vectors[ARMV7M_EXCP_USAGE].active) {
val |= (1 << 3);
}
if (s->sec_vectors[ARMV7M_EXCP_SVC].active) {
val |= (1 << 7);
}
if (s->sec_vectors[ARMV7M_EXCP_PENDSV].active) {
val |= (1 << 10);
}
if (s->sec_vectors[ARMV7M_EXCP_SYSTICK].active) {
val |= (1 << 11);
}
if (s->sec_vectors[ARMV7M_EXCP_USAGE].pending) {
val |= (1 << 12);
}
if (s->sec_vectors[ARMV7M_EXCP_MEM].pending) {
val |= (1 << 13);
}
if (s->sec_vectors[ARMV7M_EXCP_SVC].pending) {
val |= (1 << 15);
}
if (s->sec_vectors[ARMV7M_EXCP_MEM].enabled) {
val |= (1 << 16);
}
if (s->sec_vectors[ARMV7M_EXCP_USAGE].enabled) {
val |= (1 << 18);
}
if (s->sec_vectors[ARMV7M_EXCP_HARD].pending) {
val |= (1 << 21);
}
/* SecureFault is not banked but is always RAZ/WI to NS */
if (s->vectors[ARMV7M_EXCP_SECURE].active) {
val |= (1 << 4);
}
if (s->vectors[ARMV7M_EXCP_SECURE].enabled) {
val |= (1 << 19);
}
if (s->vectors[ARMV7M_EXCP_SECURE].pending) {
val |= (1 << 20);
}
} else {
if (s->vectors[ARMV7M_EXCP_MEM].active) {
val |= (1 << 0);
}
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
/* HARDFAULTACT, HARDFAULTPENDED not present in v7M */
if (s->vectors[ARMV7M_EXCP_HARD].active) {
val |= (1 << 2);
}
if (s->vectors[ARMV7M_EXCP_HARD].pending) {
val |= (1 << 21);
}
}
if (s->vectors[ARMV7M_EXCP_USAGE].active) {
val |= (1 << 3);
}
if (s->vectors[ARMV7M_EXCP_SVC].active) {
val |= (1 << 7);
}
if (s->vectors[ARMV7M_EXCP_PENDSV].active) {
val |= (1 << 10);
}
if (s->vectors[ARMV7M_EXCP_SYSTICK].active) {
val |= (1 << 11);
}
if (s->vectors[ARMV7M_EXCP_USAGE].pending) {
val |= (1 << 12);
}
if (s->vectors[ARMV7M_EXCP_MEM].pending) {
val |= (1 << 13);
}
if (s->vectors[ARMV7M_EXCP_SVC].pending) {
val |= (1 << 15);
}
if (s->vectors[ARMV7M_EXCP_MEM].enabled) {
val |= (1 << 16);
}
if (s->vectors[ARMV7M_EXCP_USAGE].enabled) {
val |= (1 << 18);
}
}
if (s->vectors[ARMV7M_EXCP_BUS].active) {
val |= (1 << 1);
}
if (s->vectors[ARMV7M_EXCP_USAGE].active) {
val |= (1 << 3);
}
if (s->vectors[ARMV7M_EXCP_SVC].active) {
val |= (1 << 7);
if (attrs.secure || (cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
if (s->vectors[ARMV7M_EXCP_BUS].active) {
val |= (1 << 1);
}
if (s->vectors[ARMV7M_EXCP_BUS].pending) {
val |= (1 << 14);
}
if (s->vectors[ARMV7M_EXCP_BUS].enabled) {
val |= (1 << 17);
}
if (arm_feature(&cpu->env, ARM_FEATURE_V8) &&
s->vectors[ARMV7M_EXCP_NMI].active) {
/* NMIACT is not present in v7M */
val |= (1 << 5);
}
}
/* TODO: this is RAZ/WI from NS if DEMCR.SDME is set */
if (s->vectors[ARMV7M_EXCP_DEBUG].active) {
val |= (1 << 8);
}
if (s->vectors[ARMV7M_EXCP_PENDSV].active) {
val |= (1 << 10);
}
if (s->vectors[ARMV7M_EXCP_SYSTICK].active) {
val |= (1 << 11);
}
if (s->vectors[ARMV7M_EXCP_USAGE].pending) {
val |= (1 << 12);
}
if (s->vectors[ARMV7M_EXCP_MEM].pending) {
val |= (1 << 13);
}
if (s->vectors[ARMV7M_EXCP_BUS].pending) {
val |= (1 << 14);
}
if (s->vectors[ARMV7M_EXCP_SVC].pending) {
val |= (1 << 15);
}
if (s->vectors[ARMV7M_EXCP_MEM].enabled) {
val |= (1 << 16);
}
if (s->vectors[ARMV7M_EXCP_BUS].enabled) {
val |= (1 << 17);
}
if (s->vectors[ARMV7M_EXCP_USAGE].enabled) {
val |= (1 << 18);
}
return val;
case 0xd28: /* Configurable Fault Status. */
/* The BFSR bits [15:8] are shared between security states
@ -1061,21 +1128,71 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
cpu->env.v7m.ccr[attrs.secure] = value;
break;
case 0xd24: /* System Handler Control. */
s->vectors[ARMV7M_EXCP_MEM].active = (value & (1 << 0)) != 0;
s->vectors[ARMV7M_EXCP_BUS].active = (value & (1 << 1)) != 0;
s->vectors[ARMV7M_EXCP_USAGE].active = (value & (1 << 3)) != 0;
s->vectors[ARMV7M_EXCP_SVC].active = (value & (1 << 7)) != 0;
case 0xd24: /* System Handler Control and State (SHCSR) */
if (attrs.secure) {
s->sec_vectors[ARMV7M_EXCP_MEM].active = (value & (1 << 0)) != 0;
/* Secure HardFault active bit cannot be written */
s->sec_vectors[ARMV7M_EXCP_USAGE].active = (value & (1 << 3)) != 0;
s->sec_vectors[ARMV7M_EXCP_SVC].active = (value & (1 << 7)) != 0;
s->sec_vectors[ARMV7M_EXCP_PENDSV].active =
(value & (1 << 10)) != 0;
s->sec_vectors[ARMV7M_EXCP_SYSTICK].active =
(value & (1 << 11)) != 0;
s->sec_vectors[ARMV7M_EXCP_USAGE].pending =
(value & (1 << 12)) != 0;
s->sec_vectors[ARMV7M_EXCP_MEM].pending = (value & (1 << 13)) != 0;
s->sec_vectors[ARMV7M_EXCP_SVC].pending = (value & (1 << 15)) != 0;
s->sec_vectors[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
s->sec_vectors[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
s->sec_vectors[ARMV7M_EXCP_USAGE].enabled =
(value & (1 << 18)) != 0;
/* SecureFault not banked, but RAZ/WI to NS */
s->vectors[ARMV7M_EXCP_SECURE].active = (value & (1 << 4)) != 0;
s->vectors[ARMV7M_EXCP_SECURE].enabled = (value & (1 << 19)) != 0;
s->vectors[ARMV7M_EXCP_SECURE].pending = (value & (1 << 20)) != 0;
} else {
s->vectors[ARMV7M_EXCP_MEM].active = (value & (1 << 0)) != 0;
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
/* HARDFAULTPENDED is not present in v7M */
s->vectors[ARMV7M_EXCP_HARD].pending = (value & (1 << 21)) != 0;
}
s->vectors[ARMV7M_EXCP_USAGE].active = (value & (1 << 3)) != 0;
s->vectors[ARMV7M_EXCP_SVC].active = (value & (1 << 7)) != 0;
s->vectors[ARMV7M_EXCP_PENDSV].active = (value & (1 << 10)) != 0;
s->vectors[ARMV7M_EXCP_SYSTICK].active = (value & (1 << 11)) != 0;
s->vectors[ARMV7M_EXCP_USAGE].pending = (value & (1 << 12)) != 0;
s->vectors[ARMV7M_EXCP_MEM].pending = (value & (1 << 13)) != 0;
s->vectors[ARMV7M_EXCP_SVC].pending = (value & (1 << 15)) != 0;
s->vectors[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
s->vectors[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
}
if (attrs.secure || (cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
s->vectors[ARMV7M_EXCP_BUS].active = (value & (1 << 1)) != 0;
s->vectors[ARMV7M_EXCP_BUS].pending = (value & (1 << 14)) != 0;
s->vectors[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
}
/* NMIACT can only be written if the write is of a zero, with
* BFHFNMINS 1, and by the CPU in secure state via the NS alias.
*/
if (!attrs.secure && cpu->env.v7m.secure &&
(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) &&
(value & (1 << 5)) == 0) {
s->vectors[ARMV7M_EXCP_NMI].active = 0;
}
/* HARDFAULTACT can only be written if the write is of a zero
* to the non-secure HardFault state by the CPU in secure state.
* The only case where we can be targeting the non-secure HF state
* when in secure state is if this is a write via the NS alias
* and BFHFNMINS is 1.
*/
if (!attrs.secure && cpu->env.v7m.secure &&
(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) &&
(value & (1 << 2)) == 0) {
s->vectors[ARMV7M_EXCP_HARD].active = 0;
}
/* TODO: this is RAZ/WI from NS if DEMCR.SDME is set */
s->vectors[ARMV7M_EXCP_DEBUG].active = (value & (1 << 8)) != 0;
s->vectors[ARMV7M_EXCP_PENDSV].active = (value & (1 << 10)) != 0;
s->vectors[ARMV7M_EXCP_SYSTICK].active = (value & (1 << 11)) != 0;
s->vectors[ARMV7M_EXCP_USAGE].pending = (value & (1 << 12)) != 0;
s->vectors[ARMV7M_EXCP_MEM].pending = (value & (1 << 13)) != 0;
s->vectors[ARMV7M_EXCP_BUS].pending = (value & (1 << 14)) != 0;
s->vectors[ARMV7M_EXCP_SVC].pending = (value & (1 << 15)) != 0;
s->vectors[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
s->vectors[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
s->vectors[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
nvic_irq_update(s);
break;
case 0xd28: /* Configurable Fault Status. */