[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-arm] [PATCH 07/19] nvic: Implement NVIC_ITNS<n> registers
From: |
Peter Maydell |
Subject: |
[Qemu-arm] [PATCH 07/19] nvic: Implement NVIC_ITNS<n> registers |
Date: |
Tue, 12 Sep 2017 19:13:54 +0100 |
For v8M, the NVIC has a new set of registers per interrupt,
NVIC_ITNS<n>. These determine whether the interrupt targets Secure
or Non-secure state. Implement the register read/write code for
these, and make them cause NVIC_IABR, NVIC_ICER, NVIC_ISER,
NVIC_ICPR, NVIC_IPR and NVIC_ISPR to RAZ/WI for non-secure
accesses to fields corresponding to interrupts which are
configured to target secure state.
Signed-off-by: Peter Maydell <address@hidden>
---
include/hw/intc/armv7m_nvic.h | 3 ++
hw/intc/armv7m_nvic.c | 74 +++++++++++++++++++++++++++++++++++++++----
2 files changed, 70 insertions(+), 7 deletions(-)
diff --git a/include/hw/intc/armv7m_nvic.h b/include/hw/intc/armv7m_nvic.h
index e96e488..ac7997c 100644
--- a/include/hw/intc/armv7m_nvic.h
+++ b/include/hw/intc/armv7m_nvic.h
@@ -58,6 +58,9 @@ typedef struct NVICState {
/* The PRIGROUP field in AIRCR is banked */
uint32_t prigroup[M_REG_NUM_BANKS];
+ /* v8M NVIC_ITNS state (stored as a bool per bit) */
+ bool itns[NVIC_MAX_VECTORS];
+
/* The following fields are all cached state that can be recalculated
* from the vectors[] and sec_vectors[] arrays and the prigroup field:
* - vectpending
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index edaf60c..b97dbe3 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -423,6 +423,25 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset,
MemTxAttrs attrs)
switch (offset) {
case 4: /* Interrupt Control Type. */
return ((s->num_irq - NVIC_FIRST_IRQ) / 32) - 1;
+ case 0x380 ... 0x3bf: /* NVIC_ITNS<n> */
+ {
+ int startvec = 32 * (offset - 0x380) + NVIC_FIRST_IRQ;
+ int i;
+
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
+ goto bad_offset;
+ }
+ if (!attrs.secure) {
+ return 0;
+ }
+ val = 0;
+ for (i = 0; i < 32 && startvec + i < s->num_irq; i++) {
+ if (s->itns[startvec + i]) {
+ val |= (1 << i);
+ }
+ }
+ return val;
+ }
case 0xd00: /* CPUID Base. */
return cpu->midr;
case 0xd04: /* Interrupt Control State. */
@@ -658,6 +677,23 @@ static void nvic_writel(NVICState *s, uint32_t offset,
uint32_t value,
ARMCPU *cpu = s->cpu;
switch (offset) {
+ case 0x380 ... 0x3bf: /* NVIC_ITNS<n> */
+ {
+ int startvec = 32 * (offset - 0x380) + NVIC_FIRST_IRQ;
+ int i;
+
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
+ goto bad_offset;
+ }
+ if (!attrs.secure) {
+ break;
+ }
+ for (i = 0; i < 32 && startvec + i < s->num_irq; i++) {
+ s->itns[startvec + i] = value & (1 << i);
+ }
+ nvic_irq_update(s);
+ break;
+ }
case 0xd04: /* Interrupt Control State. */
if (value & (1 << 31)) {
armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
@@ -966,7 +1002,8 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr
addr,
startvec = offset - 0x180 + NVIC_FIRST_IRQ; /* vector # */
for (i = 0, end = size * 8; i < end && startvec + i < s->num_irq; i++)
{
- if (s->vectors[startvec + i].enabled) {
+ if (s->vectors[startvec + i].enabled &&
+ (attrs.secure || s->itns[startvec + i])) {
val |= (1 << i);
}
}
@@ -978,7 +1015,8 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr
addr,
val = 0;
startvec = offset - 0x280 + NVIC_FIRST_IRQ; /* vector # */
for (i = 0, end = size * 8; i < end && startvec + i < s->num_irq; i++)
{
- if (s->vectors[startvec + i].pending) {
+ if (s->vectors[startvec + i].pending &&
+ (attrs.secure || s->itns[startvec + i])) {
val |= (1 << i);
}
}
@@ -988,7 +1026,8 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr
addr,
startvec = offset - 0x300 + NVIC_FIRST_IRQ; /* vector # */
for (i = 0, end = size * 8; i < end && startvec + i < s->num_irq; i++)
{
- if (s->vectors[startvec + i].active) {
+ if (s->vectors[startvec + i].active &&
+ (attrs.secure || s->itns[startvec + i])) {
val |= (1 << i);
}
}
@@ -998,7 +1037,9 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr
addr,
startvec = offset - 0x400 + NVIC_FIRST_IRQ; /* vector # */
for (i = 0; i < size && startvec + i < s->num_irq; i++) {
- val |= s->vectors[startvec + i].prio << (8 * i);
+ if (attrs.secure || s->itns[startvec + i]) {
+ val |= s->vectors[startvec + i].prio << (8 * i);
+ }
}
break;
case 0xd18 ... 0xd23: /* System Handler Priority. */
@@ -1055,7 +1096,8 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr
addr,
startvec = 8 * (offset - 0x180) + NVIC_FIRST_IRQ;
for (i = 0, end = size * 8; i < end && startvec + i < s->num_irq; i++)
{
- if (value & (1 << i)) {
+ if (value & (1 << i) &&
+ (attrs.secure || s->itns[startvec + i])) {
s->vectors[startvec + i].enabled = setval;
}
}
@@ -1072,7 +1114,8 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr
addr,
startvec = 8 * (offset - 0x280) + NVIC_FIRST_IRQ; /* vector # */
for (i = 0, end = size * 8; i < end && startvec + i < s->num_irq; i++)
{
- if (value & (1 << i)) {
+ if (value & (1 << i) &&
+ (attrs.secure || s->itns[startvec + i])) {
s->vectors[startvec + i].pending = setval;
}
}
@@ -1084,7 +1127,9 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr
addr,
startvec = 8 * (offset - 0x400) + NVIC_FIRST_IRQ; /* vector # */
for (i = 0; i < size && startvec + i < s->num_irq; i++) {
- set_prio(s, startvec + i, (value >> (i * 8)) & 0xff);
+ if (attrs.secure || s->itns[startvec + i]) {
+ set_prio(s, startvec + i, (value >> (i * 8)) & 0xff);
+ }
}
nvic_irq_update(s);
return MEMTX_OK;
@@ -1223,6 +1268,7 @@ static const VMStateDescription vmstate_nvic_security = {
VMSTATE_STRUCT_ARRAY(sec_vectors, NVICState, NVIC_INTERNAL_VECTORS, 1,
vmstate_VecInfo, VecInfo),
VMSTATE_UINT32(prigroup[M_REG_S], NVICState),
+ VMSTATE_BOOL_ARRAY(itns, NVICState, NVIC_MAX_VECTORS),
VMSTATE_END_OF_LIST()
}
};
@@ -1284,6 +1330,20 @@ static void armv7m_nvic_reset(DeviceState *dev)
s->vectpending = 0;
s->vectpending_is_s_banked = false;
s->vectpending_prio = NVIC_NOEXC_PRIO;
+
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY)) {
+ memset(s->itns, 0, sizeof(s->itns));
+ } else {
+ /* This state is constant and not guest accessible in a non-security
+ * NVIC; we set the bits to true to avoid having to do a feature
+ * bit check in the NVIC enable/pend/etc register accessors.
+ */
+ int i;
+
+ for (i = NVIC_FIRST_IRQ; i < ARRAY_SIZE(s->itns); i++) {
+ s->itns[i] = true;
+ }
+ }
}
static void nvic_systick_trigger(void *opaque, int n, int level)
--
2.7.4
- [Qemu-arm] [PATCH 02/19] nvic: Add banked exception states, (continued)
- [Qemu-arm] [PATCH 02/19] nvic: Add banked exception states, Peter Maydell, 2017/09/12
- [Qemu-arm] [PATCH 03/19] nvic: Add cached vectpending_is_s_banked state, Peter Maydell, 2017/09/12
- [Qemu-arm] [PATCH 04/19] nvic: Add cached vectpending_prio state, Peter Maydell, 2017/09/12
- [Qemu-arm] [PATCH 06/19] nvic: Make ICSR.RETTOBASE handle banked exceptions, Peter Maydell, 2017/09/12
- [Qemu-arm] [PATCH 05/19] nvic: Implement AIRCR changes for v8M, Peter Maydell, 2017/09/12
- [Qemu-arm] [PATCH 07/19] nvic: Implement NVIC_ITNS<n> registers,
Peter Maydell <=
- [Qemu-arm] [PATCH 12/19] nvic: In escalation to HardFault, support HF not being priority -1, Peter Maydell, 2017/09/12
- [Qemu-arm] [PATCH 10/19] nvic: Make SHPR registers banked, Peter Maydell, 2017/09/12
- [Qemu-arm] [PATCH 09/19] nvic: Make set_pending and clear_pending take a secure parameter, Peter Maydell, 2017/09/12
- [Qemu-arm] [PATCH 01/19] target/arm: Implement MSR/MRS access to NS banked registers, Peter Maydell, 2017/09/12
- [Qemu-arm] [PATCH 15/19] nvic: Handle v8M changes in nvic_exec_prio(), Peter Maydell, 2017/09/12