[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-arm] [PATCH 07/18] armv7m: Update NVIC registers
From: |
Michael Davidsaver |
Subject: |
[Qemu-arm] [PATCH 07/18] armv7m: Update NVIC registers |
Date: |
Sun, 8 Nov 2015 20:11:34 -0500 |
Replace use of GIC state/functions with new NVIC.
Signed-off-by: Michael Davidsaver <address@hidden>
---
hw/intc/armv7m_nvic.c | 233 ++++++++++++++++++++++++++++++++++++--------------
1 file changed, 168 insertions(+), 65 deletions(-)
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index ebb4d4e..30e349e 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -394,13 +394,13 @@ void set_irq_level(void *opaque, int n, int level)
static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
{
- ARMCPU *cpu;
+ ARMCPU *cpu = s->cpu;
uint32_t val;
int irq;
switch (offset) {
case 4: /* Interrupt Control Type. */
- return (s->num_irq / 32) - 1;
+ return ((s->num_irq - 16) / 32) - 1;
case 0x10: /* SysTick Control and Status. */
val = s->systick.control;
s->systick.control &= ~SYSTICK_COUNTFLAG;
@@ -426,45 +426,39 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
case 0x1c: /* SysTick Calibration Value. */
return 10000;
case 0xd00: /* CPUID Base. */
- cpu = ARM_CPU(current_cpu);
return cpu->midr;
case 0xd04: /* Interrupt Control State. */
/* VECTACTIVE */
- cpu = ARM_CPU(current_cpu);
val = cpu->env.v7m.exception;
- if (val == 1023) {
- val = 0;
- } else if (val >= 32) {
- val -= 16;
- }
/* VECTPENDING */
- if (s->gic.current_pending[0] != 1023)
- val |= (s->gic.current_pending[0] << 12);
+ val |= (cpu->env.v7m.pending << 12)&0x1ff;
/* ISRPENDING and RETTOBASE */
- for (irq = 32; irq < s->num_irq; irq++) {
- if (s->gic.irq_state[irq].pending) {
+ for (irq = 16; irq < s->num_irq; irq++) {
+ if (s->vectors[irq].pending) {
val |= (1 << 22);
break;
}
- if (irq != cpu->env.v7m.exception && s->gic.irq_state[irq].active)
{
+ if (irq != cpu->env.v7m.exception && s->vectors[irq].active) {
val |= (1 << 11);
}
}
/* PENDSTSET */
- if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
+ if (s->vectors[ARMV7M_EXCP_SYSTICK].pending) {
val |= (1 << 26);
+ }
/* PENDSVSET */
- if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
+ if (s->vectors[ARMV7M_EXCP_PENDSV].pending) {
val |= (1 << 28);
+ }
/* NMIPENDSET */
- if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
+ if (s->vectors[ARMV7M_EXCP_NMI].pending) {
val |= (1 << 31);
+ }
return val;
case 0xd08: /* Vector Table Offset. */
- cpu = ARM_CPU(current_cpu);
return cpu->env.v7m.vecbase;
case 0xd0c: /* Application Interrupt/Reset Control. */
- return 0xfa050000;
+ return 0xfa050000 | (s->prigroup<<8);
case 0xd10: /* System Control. */
/* TODO: Implement SLEEPONEXIT. */
return 0;
@@ -473,20 +467,20 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
return 0;
case 0xd24: /* System Handler Status. */
val = 0;
- if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
- if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
- if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
- if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
- if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
- if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
- if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
- if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
- if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
- if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
- if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
- if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
- if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
- if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
+ if (s->vectors[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
+ 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 (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. */
/* TODO: Implement Fault Status. */
@@ -535,7 +529,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
{
- ARMCPU *cpu;
+ ARMCPU *cpu = s->cpu;
uint32_t oldval;
switch (offset) {
case 0x10: /* SysTick Control and Status. */
@@ -577,18 +571,15 @@ static void nvic_writel(nvic_state *s, uint32_t offset,
uint32_t value)
if (value & (1 << 28)) {
armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
} else if (value & (1 << 27)) {
- s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
- gic_update(&s->gic);
+ armv7m_nvic_clear_pending(s, ARMV7M_EXCP_PENDSV);
}
if (value & (1 << 26)) {
armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
} else if (value & (1 << 25)) {
- s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
- gic_update(&s->gic);
+ armv7m_nvic_clear_pending(s, ARMV7M_EXCP_SYSTICK);
}
break;
case 0xd08: /* Vector Table Offset. */
- cpu = ARM_CPU(current_cpu);
cpu->env.v7m.vecbase = value & 0xffffff80;
break;
case 0xd0c: /* Application Interrupt/Reset Control. */
@@ -603,7 +594,13 @@ static void nvic_writel(nvic_state *s, uint32_t offset,
uint32_t value)
qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
}
if (value & 0x700) {
- qemu_log_mask(LOG_UNIMP, "PRIGROUP unimplemented\n");
+ unsigned i;
+ s->prigroup = (value>>8)&0xf;
+ /* recalculate prio_ord for exceptions w/ configurable prio */
+ for (i = 4; i < s->num_irq; i++) {
+ set_prio(s, i, s->vectors[i].raw_prio);
+ }
+ nvic_irq_update(s, 0);
}
}
break;
@@ -615,9 +612,12 @@ static void nvic_writel(nvic_state *s, uint32_t offset,
uint32_t value)
case 0xd24: /* System Handler Control. */
/* TODO: Real hardware allows you to set/clear the active bits
under some circumstances. We don't implement this. */
- s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
- s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
- s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 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;
+ /* no need to call nvic_irq_update() since any pending while
+ * disabled would have been escalated to HardFault
+ */
break;
case 0xd28: /* Configurable Fault Status. */
case 0xd2c: /* Hard Fault Status. */
@@ -629,8 +629,8 @@ static void nvic_writel(nvic_state *s, uint32_t offset,
uint32_t value)
"NVIC: fault status registers unimplemented\n");
break;
case 0xf00: /* Software Triggered Interrupt Register */
- if ((value & 0x1ff) < s->num_irq) {
- gic_set_pending_private(&s->gic, 0, value & 0x1ff);
+ if ((value & 0x1ff) < NVIC_MAX_IRQ) {
+ armv7m_nvic_set_pending(s, (value&0x1ff)+16);
}
break;
default:
@@ -644,28 +644,81 @@ static uint64_t nvic_sysreg_read(void *opaque, hwaddr
addr,
{
nvic_state *s = (nvic_state *)opaque;
uint32_t offset = addr;
- int i;
+ unsigned i, end;
uint32_t val;
switch (offset) {
+ /* reads of set and clear both return the status */
+ case 0x100 ... 0x13c: /* NVIC Set enable */
+ offset += 0x80;
+ /* fall through */
+ case 0x180 ... 0x1bc: /* NVIC Clear enable */
+ val = 0;
+ offset = offset-0x180+16; /* vector # */
+
+ for (i = 0, end = size*8; i < end && offset+i < s->num_irq; i++) {
+ if (s->vectors[offset+i].enabled) {
+ val |= (1<<i);
+ }
+ }
+ break;
+ case 0x200 ... 0x23c: /* NVIC Set pend */
+ offset += 0x80;
+ /* fall through */
+ case 0x280 ... 0x2bc: /* NVIC Clear pend */
+ val = 0;
+ offset = offset-0x280+16; /* vector # */
+
+ for (i = 0, end = size*8; i < end && offset+i < s->num_irq; i++) {
+ if (s->vectors[offset+i].pending) {
+ val |= (1<<i);
+ }
+ }
+ break;
+ case 0x300 ... 0x37c: /* NVIC Active */
+ val = 0;
+ offset = offset-0x300+16; /* vector # */
+
+ for (i = 0, end = size*8; i < end && offset+i < s->num_irq; i++) {
+ if (s->vectors[offset+i].active) {
+ val |= (1<<i);
+ }
+ }
+ break;
+ case 0x400 ... 0x7ec: /* NVIC Priority */
+ val = 0;
+ offset = offset-0x400+16; /* vector # */
+
+ for (i = 0; i < size && offset+i < s->num_irq; i++) {
+ val |= s->vectors[offset+i].raw_prio<<(8*i);
+ }
+ break;
case 0xd18 ... 0xd23: /* System Handler Priority. */
val = 0;
for (i = 0; i < size; i++) {
- val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
+ val |= s->vectors[(offset - 0xd14) + i].raw_prio << (i * 8);
}
- return val;
+ break;
case 0xfe0 ... 0xfff: /* ID. */
if (offset & 3) {
return 0;
}
- return nvic_id[(offset - 0xfe0) >> 2];
- }
- if (size == 4) {
- return nvic_readl(s, offset);
+ val = nvic_id[(offset - 0xfe0) >> 2];
+ break;
+ default:
+ if (size == 4) {
+ val = nvic_readl(s, offset);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "NVIC: Bad read of size %d at offset 0x%x\n",
+ size, offset);
+ val = 0;
+ }
}
- qemu_log_mask(LOG_GUEST_ERROR,
- "NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
- return 0;
+
+ DPRINTF(0, "sysreg read%u "TARGET_FMT_plx" -> %08x\n",
+ size*8, addr, (unsigned)val);
+ return val;
}
static void nvic_sysreg_write(void *opaque, hwaddr addr,
@@ -673,23 +726,73 @@ static void nvic_sysreg_write(void *opaque, hwaddr addr,
{
nvic_state *s = (nvic_state *)opaque;
uint32_t offset = addr;
- int i;
+ unsigned i, end;
+ unsigned setval = 0;
+
+ DPRINTF(0, "sysreg write%u "TARGET_FMT_plx" <- %08x\n",
+ size*8, addr, (unsigned)value);
switch (offset) {
- case 0xd18 ... 0xd23: /* System Handler Priority. */
+ case 0x100 ... 0x13c: /* NVIC Set enable */
+ offset += 0x80;
+ setval = 1;
+ /* fall through */
+ case 0x180 ... 0x1bc: /* NVIC Clear enable */
+ offset = offset-0x180+16; /* vector # */
+
+ for (i = 0, end = size*8; i < end && offset+i < s->num_irq; i++) {
+ if (value&(1<<i)) {
+ s->vectors[offset+i].enabled = setval;
+ }
+ }
+ nvic_irq_update(s, 0);
+ return;
+ case 0x200 ... 0x23c: /* NVIC Set pend */
+ /* the special logic in armv7m_nvic_set_pending()
+ * is not needed since IRQs are never escalated
+ */
+ offset += 0x80;
+ setval = 1;
+ /* fall through */
+ case 0x280 ... 0x2bc: /* NVIC Clear pend */
+ offset = offset-0x280+16; /* vector # */
+
+ for (i = 0, end = size*8; i < end && offset+i < s->num_irq; i++) {
+ if (value&(1<<i)) {
+ s->vectors[offset+i].pending = setval;
+ }
+ }
+ nvic_irq_update(s, 0);
+ return;
+ case 0x300 ... 0x37c: /* NVIC Active */
+ return; /* R/O */
+ case 0x400 ... 0x7ec: /* NVIC Priority */
+ offset = offset-0x400+16; /* vector # */
+
for (i = 0; i < size; i++) {
- s->gic.priority1[(offset - 0xd14) + i][0] =
- (value >> (i * 8)) & 0xff;
+ set_prio(s, offset+i, (value>>(i*8))&0xff);
}
- gic_update(&s->gic);
+ nvic_irq_update(s, 0);
return;
- }
- if (size == 4) {
- nvic_writel(s, offset, value);
+ case 0xd18 ... 0xd23: /* System Handler Priority. */
+ for (i = 0; i < size; i++) {
+ unsigned hdlidx = (offset - 0xd14) + i;
+ set_prio(s, hdlidx, (value >> (i * 8)) & 0xff);
+ DPRINTF(0, "Set Handler prio %u = %u\n",
+ (unsigned)hdlidx,
+ (unsigned)s->vectors[hdlidx].raw_prio);
+ }
+ nvic_irq_update(s, 0);
return;
+ default:
+ if (size == 4) {
+ nvic_writel(s, offset, value);
+ return;
+ }
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "NVIC: Bad write of size %d at offset 0x%x\n",
+ size, offset);
}
- qemu_log_mask(LOG_GUEST_ERROR,
- "NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
}
static const MemoryRegionOps nvic_sysreg_ops = {
--
2.1.4
- [Qemu-arm] [PATCH 15/18] arm: gic: Remove references to NVIC, (continued)
- [Qemu-arm] [PATCH 15/18] arm: gic: Remove references to NVIC, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 06/18] armv7m: new NVIC utility functions, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 09/18] armv7m: NVIC update vmstate, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 10/18] armv7m: NVIC initialization, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 11/18] armv7m: fix I and F flag handling, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 17/18] armv7m: implement CCR, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 07/18] armv7m: Update NVIC registers,
Michael Davidsaver <=
- [Qemu-arm] [PATCH 04/18] armv7m: Explicit error for bad vector table, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 12/18] armv7m: simpler/faster exception start, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 13/18] armv7m: implement CFSR and HFSR, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 01/18] armv7m: MRS/MSR handle unprivileged access, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 18/18] armv7m: prevent unprivileged write to STIR, Michael Davidsaver, 2015/11/09
- [Qemu-arm] [PATCH 16/18] armv7m: check exception return consistency, Michael Davidsaver, 2015/11/09
- Re: [Qemu-arm] [PATCH 00/18] Fix exception handling and msr/mrs access, Peter Maydell, 2015/11/17