summaryrefslogtreecommitdiffstats
path: root/hw/intc
diff options
context:
space:
mode:
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/arm_gicv3_cpuif.c2
-rw-r--r--hw/intc/armv7m_nvic.c58
2 files changed, 42 insertions, 18 deletions
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index a9ee7fddf9..c25ee03556 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -2430,7 +2430,7 @@ static uint64_t ich_elrsr_read(CPUARMState *env, const ARMCPRegInfo *ri)
uint64_t lr = cs->ich_lr_el2[i];
if ((lr & ICH_LR_EL2_STATE_MASK) == 0 &&
- ((lr & ICH_LR_EL2_HW) == 1 || (lr & ICH_LR_EL2_EOI) == 0)) {
+ ((lr & ICH_LR_EL2_HW) != 0 || (lr & ICH_LR_EL2_EOI) == 0)) {
value |= (1 << i);
}
}
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 06d8db6bd6..fe5c303de9 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -23,6 +23,7 @@
typedef struct {
GICState gic;
+ ARMCPU *cpu;
struct {
uint32_t control;
uint32_t reload;
@@ -155,7 +156,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq)
static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
{
- ARMCPU *cpu;
+ ARMCPU *cpu = s->cpu;
uint32_t val;
int irq;
@@ -187,11 +188,9 @@ 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(qemu_get_cpu(0));
return cpu->midr;
case 0xd04: /* Interrupt Control State. */
/* VECTACTIVE */
- cpu = ARM_CPU(qemu_get_cpu(0));
val = cpu->env.v7m.exception;
if (val == 1023) {
val = 0;
@@ -222,7 +221,6 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
val |= (1 << 31);
return val;
case 0xd08: /* Vector Table Offset. */
- cpu = ARM_CPU(qemu_get_cpu(0));
return cpu->env.v7m.vecbase;
case 0xd0c: /* Application Interrupt/Reset Control. */
return 0xfa050000;
@@ -230,8 +228,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
/* TODO: Implement SLEEPONEXIT. */
return 0;
case 0xd14: /* Configuration Control. */
- /* TODO: Implement Configuration Control bits. */
- return 0;
+ return cpu->env.v7m.ccr;
case 0xd24: /* System Handler Status. */
val = 0;
if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
@@ -250,16 +247,19 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
return val;
case 0xd28: /* Configurable Fault Status. */
- /* TODO: Implement Fault Status. */
- qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
- return 0;
+ return cpu->env.v7m.cfsr;
case 0xd2c: /* Hard Fault Status. */
+ return cpu->env.v7m.hfsr;
case 0xd30: /* Debug Fault Status. */
- case 0xd34: /* Mem Manage Address. */
+ return cpu->env.v7m.dfsr;
+ case 0xd34: /* MMFAR MemManage Fault Address */
+ return cpu->env.v7m.mmfar;
case 0xd38: /* Bus Fault Address. */
+ return cpu->env.v7m.bfar;
case 0xd3c: /* Aux Fault Status. */
/* TODO: Implement fault status registers. */
- qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
+ qemu_log_mask(LOG_UNIMP,
+ "Aux Fault status registers unimplemented\n");
return 0;
case 0xd40: /* PFR0. */
return 0x00000030;
@@ -296,7 +296,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. */
@@ -349,7 +349,6 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
}
break;
case 0xd08: /* Vector Table Offset. */
- cpu = ARM_CPU(qemu_get_cpu(0));
cpu->env.v7m.vecbase = value & 0xffffff80;
break;
case 0xd0c: /* Application Interrupt/Reset Control. */
@@ -369,9 +368,19 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
}
break;
case 0xd10: /* System Control. */
- case 0xd14: /* Configuration Control. */
/* TODO: Implement control registers. */
- qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
+ qemu_log_mask(LOG_UNIMP, "NVIC: SCR unimplemented\n");
+ break;
+ case 0xd14: /* Configuration Control. */
+ /* Enforce RAZ/WI on reserved and must-RAZ/WI bits */
+ value &= (R_V7M_CCR_STKALIGN_MASK |
+ R_V7M_CCR_BFHFNMIGN_MASK |
+ R_V7M_CCR_DIV_0_TRP_MASK |
+ R_V7M_CCR_UNALIGN_TRP_MASK |
+ R_V7M_CCR_USERSETMPEND_MASK |
+ R_V7M_CCR_NONBASETHRDENA_MASK);
+
+ cpu->env.v7m.ccr = value;
break;
case 0xd24: /* System Handler Control. */
/* TODO: Real hardware allows you to set/clear the active bits
@@ -381,16 +390,29 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
break;
case 0xd28: /* Configurable Fault Status. */
+ cpu->env.v7m.cfsr &= ~value; /* W1C */
+ break;
case 0xd2c: /* Hard Fault Status. */
+ cpu->env.v7m.hfsr &= ~value; /* W1C */
+ break;
case 0xd30: /* Debug Fault Status. */
+ cpu->env.v7m.dfsr &= ~value; /* W1C */
+ break;
case 0xd34: /* Mem Manage Address. */
+ cpu->env.v7m.mmfar = value;
+ return;
case 0xd38: /* Bus Fault Address. */
+ cpu->env.v7m.bfar = value;
+ return;
case 0xd3c: /* Aux Fault Status. */
qemu_log_mask(LOG_UNIMP,
- "NVIC: fault status registers unimplemented\n");
+ "NVIC: Aux fault status registers unimplemented\n");
break;
case 0xf00: /* Software Triggered Interrupt Register */
- if ((value & 0x1ff) < s->num_irq) {
+ /* user mode can only write to STIR if CCR.USERSETMPEND permits it */
+ if ((value & 0x1ff) < s->num_irq &&
+ (arm_current_el(&cpu->env) ||
+ (cpu->env.v7m.ccr & R_V7M_CCR_USERSETMPEND_MASK))) {
gic_set_pending_private(&s->gic, 0, value & 0x1ff);
}
break;
@@ -495,6 +517,8 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
NVICClass *nc = NVIC_GET_CLASS(s);
Error *local_err = NULL;
+ s->cpu = ARM_CPU(qemu_get_cpu(0));
+ assert(s->cpu);
/* The NVIC always has only one CPU */
s->gic.num_cpu = 1;
/* Tell the common code we're an NVIC */