204 lines
6.8 KiB
Diff
204 lines
6.8 KiB
Diff
From ec2838a7609d8b671bfb44ed90d15c1467cc6f32 Mon Sep 17 00:00:00 2001
|
|
From: Yonattan Louise <yonattan.a.louise.mendoza@intel.com>
|
|
Date: Tue, 14 Apr 2015 16:38:42 -0500
|
|
Subject: [PATCH] armv7m support basepri + primask interrupt locking
|
|
|
|
Interrupt locking is not implemented as part of QEMU for ARM. Until
|
|
we are able to properly upstream a patch to the QEMU project, this
|
|
change provides a partial solution that enables the Cortex-M3 core.
|
|
This has not been tested with other ARM based platforms.
|
|
|
|
This solution is for internal use. It is not ready for QEMU upstream.
|
|
|
|
Solution created by Benjamin Walsh for qemu v1.5, and ported by
|
|
Yonattan Louise for qemu v2.x.
|
|
|
|
Signed-off-by: Yonattan Louise <yonattan.a.louise.mendoza@linux.intel.com>
|
|
Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com>
|
|
---
|
|
cpu-exec.c | 16 +++++++++++++---
|
|
hw/intc/arm_gic.c | 12 ++++++++++++
|
|
hw/intc/armv7m_nvic.c | 12 ++++++++++++
|
|
hw/intc/gic_internal.h | 2 ++
|
|
pixman | 2 +-
|
|
target-arm/cpu-qom.h | 1 +
|
|
target-arm/cpu.h | 2 ++
|
|
target-arm/helper.c | 28 +++++++++++++++++++++++++++-
|
|
8 files changed, 70 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/cpu-exec.c b/cpu-exec.c
|
|
index 38e5f02..2252f85 100644
|
|
--- a/cpu-exec.c
|
|
+++ b/cpu-exec.c
|
|
@@ -492,9 +492,19 @@ int cpu_exec(CPUArchState *env)
|
|
the stack if an interrupt occurred at the wrong time.
|
|
We avoid this by disabling interrupts when
|
|
pc contains a magic address. */
|
|
- if (interrupt_request & CPU_INTERRUPT_HARD
|
|
- && ((IS_M(env) && env->regs[15] < 0xfffffff0)
|
|
- || !(env->daif & PSTATE_I))) {
|
|
+
|
|
+ int is_m_do_irq = !IS_M(env) || (
|
|
+ (env->regs[15] < 0xfffffff0)
|
|
+#if !defined(TARGET_AARCH64) && !defined(CONFIG_USER_ONLY)
|
|
+ && arm_v7m_basepri_check(cpu) );
|
|
+#else
|
|
+ );
|
|
+#endif
|
|
+ int handle_irq = (
|
|
+ (interrupt_request & CPU_INTERRUPT_HARD) &&
|
|
+ is_m_do_irq && !(env->daif & PSTATE_I) );
|
|
+
|
|
+ if (handle_irq) {
|
|
cpu->exception_index = EXCP_IRQ;
|
|
cc->do_interrupt(cpu);
|
|
next_tb = 0;
|
|
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
|
|
index 1532ef9..fabe948 100644
|
|
--- a/hw/intc/arm_gic.c
|
|
+++ b/hw/intc/arm_gic.c
|
|
@@ -177,6 +177,18 @@ static void gic_set_running_irq(GICState *s, int cpu, int irq)
|
|
gic_update(s);
|
|
}
|
|
|
|
+int gic_get_next_irq(GICState *s, int cpu)
|
|
+{
|
|
+ int irq = s->current_pending[cpu];
|
|
+ int prio_check = GIC_GET_PRIORITY(irq, cpu) < s->running_priority[cpu];
|
|
+ return prio_check ? irq : 1023;
|
|
+}
|
|
+
|
|
+int gic_get_priority(GICState *s, int irq, int cpu)
|
|
+{
|
|
+ return GIC_GET_PRIORITY(irq, cpu);
|
|
+}
|
|
+
|
|
uint32_t gic_acknowledge_irq(GICState *s, int cpu)
|
|
{
|
|
int ret, irq, src;
|
|
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
|
|
index 1a7af45..3ce8733 100644
|
|
--- a/hw/intc/armv7m_nvic.c
|
|
+++ b/hw/intc/armv7m_nvic.c
|
|
@@ -116,6 +116,12 @@ void armv7m_nvic_set_pending(void *opaque, int irq)
|
|
gic_set_pending_private(&s->gic, 0, irq);
|
|
}
|
|
|
|
+int armv7m_nvic_get_priority(void *opaque, int irq, int cpu)
|
|
+{
|
|
+ nvic_state *s = (nvic_state *)opaque;
|
|
+ return gic_get_priority(&s->gic, irq, cpu);
|
|
+}
|
|
+
|
|
/* Make pending IRQ active. */
|
|
int armv7m_nvic_acknowledge_irq(void *opaque)
|
|
{
|
|
@@ -138,6 +144,12 @@ void armv7m_nvic_complete_irq(void *opaque, int irq)
|
|
gic_complete_irq(&s->gic, 0, irq);
|
|
}
|
|
|
|
+int armv7m_nvic_get_next_irq(void *opaque, int cpu)
|
|
+{
|
|
+ nvic_state *s = (nvic_state *)opaque;
|
|
+ return gic_get_next_irq(&s->gic, cpu);
|
|
+}
|
|
+
|
|
static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
|
|
{
|
|
ARMCPU *cpu;
|
|
diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h
|
|
index 48a58d7..f1a919f 100644
|
|
--- a/hw/intc/gic_internal.h
|
|
+++ b/hw/intc/gic_internal.h
|
|
@@ -61,6 +61,8 @@ void gic_complete_irq(GICState *s, int cpu, int irq);
|
|
void gic_update(GICState *s);
|
|
void gic_init_irqs_and_distributor(GICState *s, int num_irq);
|
|
void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val);
|
|
+int gic_get_next_irq(GICState *s, int cpu);
|
|
+int gic_get_priority(GICState *s, int irq, int cpu);
|
|
|
|
static inline bool gic_test_pending(GICState *s, int irq, int cm)
|
|
{
|
|
diff --git a/pixman b/pixman
|
|
index 97336fa..87eea99 160000
|
|
--- a/pixman
|
|
+++ b/pixman
|
|
@@ -1 +1 @@
|
|
-Subproject commit 97336fad32acf802003855cd8bd6477fa49a12e3
|
|
+Subproject commit 87eea99e443b389c978cf37efc52788bf03a0ee0
|
|
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
|
|
index ee4fbb1..860fb6d 100644
|
|
--- a/target-arm/cpu-qom.h
|
|
+++ b/target-arm/cpu-qom.h
|
|
@@ -191,6 +191,7 @@ void init_cpreg_list(ARMCPU *cpu);
|
|
|
|
void arm_cpu_do_interrupt(CPUState *cpu);
|
|
void arm_v7m_cpu_do_interrupt(CPUState *cpu);
|
|
+int arm_v7m_basepri_check(CPUState *cs);
|
|
|
|
void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
|
|
int flags);
|
|
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
|
|
index f101880..1c1ed5b 100644
|
|
--- a/target-arm/cpu.h
|
|
+++ b/target-arm/cpu.h
|
|
@@ -683,6 +683,8 @@ void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
|
|
void armv7m_nvic_set_pending(void *opaque, int irq);
|
|
int armv7m_nvic_acknowledge_irq(void *opaque);
|
|
void armv7m_nvic_complete_irq(void *opaque, int irq);
|
|
+int armv7m_nvic_get_priority(void *opaque, int irq, int cpu);
|
|
+int armv7m_nvic_get_next_irq(void *opaque, int cpu);
|
|
|
|
/* Interface for defining coprocessor registers.
|
|
* Registers are defined in tables of arm_cp_reginfo structs
|
|
diff --git a/target-arm/helper.c b/target-arm/helper.c
|
|
index d343856..6a2a907 100644
|
|
--- a/target-arm/helper.c
|
|
+++ b/target-arm/helper.c
|
|
@@ -3243,6 +3243,29 @@ static void switch_v7m_sp(CPUARMState *env, int process)
|
|
}
|
|
}
|
|
|
|
+static inline int _get_cur_basepri(CPUARMState *env)
|
|
+{
|
|
+ return (int)helper_v7m_mrs(env, 0x11);
|
|
+}
|
|
+
|
|
+int arm_v7m_basepri_check(CPUState *cs)
|
|
+{
|
|
+ ARMCPU *cpu = ARM_CPU(cs);
|
|
+ CPUARMState *env = &cpu->env;
|
|
+ int irq = armv7m_nvic_get_next_irq(env->nvic, 0);
|
|
+
|
|
+ if (irq == 1023)
|
|
+ return 0;
|
|
+
|
|
+ int basepri = _get_cur_basepri(env);
|
|
+ int irqpri = armv7m_nvic_get_priority(env->nvic, irq, 0);
|
|
+
|
|
+ if (!basepri || (irqpri < basepri))
|
|
+ return 1;
|
|
+ else
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void do_v7m_exception_exit(CPUARMState *env)
|
|
{
|
|
uint32_t type;
|
|
@@ -3323,8 +3346,11 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG);
|
|
return;
|
|
case EXCP_IRQ:
|
|
- env->v7m.exception = armv7m_nvic_acknowledge_irq(env->nvic);
|
|
+ {
|
|
+ int exc = armv7m_nvic_acknowledge_irq(env->nvic);
|
|
+ env->v7m.exception = exc;
|
|
break;
|
|
+ }
|
|
case EXCP_EXCEPTION_EXIT:
|
|
do_v7m_exception_exit(env);
|
|
return;
|
|
--
|
|
1.9.1
|
|
|