aboutsummaryrefslogtreecommitdiffstats
path: root/hw/armv7m_nvic.c
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@google.com>2009-09-14 14:32:27 -0700
committerDavid 'Digit' Turner <digit@google.com>2009-09-14 14:32:27 -0700
commit5d8f37ad78fc66901af50c762029a501561f3b23 (patch)
tree206790f8f21000850a98c4f9590a79e779106278 /hw/armv7m_nvic.c
parentcd059b15f2c7df69f4a087bd66900eb172e41d1c (diff)
downloadexternal_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.zip
external_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.tar.gz
external_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.tar.bz2
Merge upstream QEMU 10.0.50 into the Android source tree.
This change integrates many changes from the upstream QEMU sources. Its main purpose is to enable correct ARMv6 and ARMv7 support to the Android emulator. Due to the nature of the upstream code base, this unfortunately also required changes to many other parts of the source. Note that to ensure easier integrations in the future, some source files and directories that have heavy Android-specific customization have been renamed with an -android suffix. The original files are still there for easier integration tracking, but *never* compiled. For example: net.c net-android.c qemu-char.c qemu-char-android.c slirp/ slirp-android/ etc... Tested on linux-x86, darwin-x86 and windows host machines.
Diffstat (limited to 'hw/armv7m_nvic.c')
-rw-r--r--hw/armv7m_nvic.c125
1 files changed, 63 insertions, 62 deletions
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index c55c958..f789c78 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -10,7 +10,7 @@
* NVIC. Much of that is also implemented here.
*/
-#include "hw.h"
+#include "sysbus.h"
#include "qemu-timer.h"
#include "arm-misc.h"
@@ -33,13 +33,13 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
#include "arm_gic.c"
typedef struct {
+ gic_state gic;
struct {
uint32_t control;
uint32_t reload;
int64_t tick;
QEMUTimer *timer;
} systick;
- gic_state *gic;
} nvic_state;
/* qemu timers run at 1GHz. We want something closer to 1MHz. */
@@ -50,6 +50,8 @@ typedef struct {
#define SYSTICK_CLKSOURCE (1 << 2)
#define SYSTICK_COUNTFLAG (1 << 16)
+int system_clock_scale;
+
/* Conversion factor from qemu timer to SysTick frequencies. */
static inline int64_t systick_scale(nvic_state *s)
{
@@ -89,7 +91,7 @@ void armv7m_nvic_set_pending(void *opaque, int irq)
nvic_state *s = (nvic_state *)opaque;
if (irq >= 16)
irq += 16;
- gic_set_pending_private(s->gic, 0, irq);
+ gic_set_pending_private(&s->gic, 0, irq);
}
/* Make pending IRQ active. */
@@ -98,9 +100,9 @@ int armv7m_nvic_acknowledge_irq(void *opaque)
nvic_state *s = (nvic_state *)opaque;
uint32_t irq;
- irq = gic_acknowledge_irq(s->gic, 0);
+ irq = gic_acknowledge_irq(&s->gic, 0);
if (irq == 1023)
- cpu_abort(cpu_single_env, "Interrupt but no vector\n");
+ hw_error("Interrupt but no vector\n");
if (irq >= 32)
irq -= 16;
return irq;
@@ -111,7 +113,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq)
nvic_state *s = (nvic_state *)opaque;
if (irq >= 16)
irq += 16;
- gic_complete_irq(s->gic, 0, irq);
+ gic_complete_irq(&s->gic, 0, irq);
}
static uint32_t nvic_readl(void *opaque, uint32_t offset)
@@ -151,35 +153,35 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
return cpu_single_env->cp15.c0_cpuid;
case 0xd04: /* Interrypt Control State. */
/* VECTACTIVE */
- val = s->gic->running_irq[0];
+ val = s->gic.running_irq[0];
if (val == 1023) {
val = 0;
} else if (val >= 32) {
val -= 16;
}
/* RETTOBASE */
- if (s->gic->running_irq[0] == 1023
- || s->gic->last_active[s->gic->running_irq[0]][0] == 1023) {
+ if (s->gic.running_irq[0] == 1023
+ || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
val |= (1 << 11);
}
/* VECTPENDING */
- if (s->gic->current_pending[0] != 1023)
- val |= (s->gic->current_pending[0] << 12);
+ if (s->gic.current_pending[0] != 1023)
+ val |= (s->gic.current_pending[0] << 12);
/* ISRPENDING */
for (irq = 32; irq < GIC_NIRQ; irq++) {
- if (s->gic->irq_state[irq].pending) {
+ if (s->gic.irq_state[irq].pending) {
val |= (1 << 22);
break;
}
}
/* PENDSTSET */
- if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending)
+ if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
val |= (1 << 26);
/* PENDSVSET */
- if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending)
+ if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
val |= (1 << 28);
/* NMIPENDSET */
- if (s->gic->irq_state[ARMV7M_EXCP_NMI].pending)
+ if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
val |= (1 << 31);
return val;
case 0xd08: /* Vector Table Offset. */
@@ -195,32 +197,31 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */
irq = offset - 0xd14;
val = 0;
- val = s->gic->priority1[irq++][0];
- val = s->gic->priority1[irq++][0] << 8;
- val = s->gic->priority1[irq++][0] << 16;
- val = s->gic->priority1[irq][0] << 24;
+ val = s->gic.priority1[irq++][0];
+ val = s->gic.priority1[irq++][0] << 8;
+ val = s->gic.priority1[irq++][0] << 16;
+ val = s->gic.priority1[irq][0] << 24;
return val;
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->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);
return val;
case 0xd28: /* Configurable Fault Status. */
/* TODO: Implement Fault Status. */
- cpu_abort(cpu_single_env,
- "Not implemented: Configurable Fault Status.");
+ hw_error("Not implemented: Configurable Fault Status.");
return 0;
case 0xd2c: /* Hard Fault Status. */
case 0xd30: /* Debug Fault Status. */
@@ -258,7 +259,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
/* TODO: Implement debug registers. */
default:
bad_reg:
- cpu_abort(cpu_single_env, "NVIC: Bad read offset 0x%x\n", offset);
+ hw_error("NVIC: Bad read offset 0x%x\n", offset);
}
}
@@ -306,14 +307,14 @@ static void nvic_writel(void *opaque, 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);
+ s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
+ gic_update(&s->gic);
}
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);
+ s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
+ gic_update(&s->gic);
}
break;
case 0xd08: /* Vector Table Offset. */
@@ -322,10 +323,10 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
case 0xd0c: /* Application Interrupt/Reset Control. */
if ((value >> 16) == 0x05fa) {
if (value & 2) {
- cpu_abort(cpu_single_env, "VECTCLRACTIVE not implemented");
+ hw_error("VECTCLRACTIVE not implemented");
}
if (value & 5) {
- cpu_abort(cpu_single_env, "System reset");
+ hw_error("System reset");
}
}
break;
@@ -337,19 +338,19 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
{
int irq;
irq = offset - 0xd14;
- s->gic->priority1[irq++][0] = value & 0xff;
- s->gic->priority1[irq++][0] = (value >> 8) & 0xff;
- s->gic->priority1[irq++][0] = (value >> 16) & 0xff;
- s->gic->priority1[irq][0] = (value >> 24) & 0xff;
- gic_update(s->gic);
+ s->gic.priority1[irq++][0] = value & 0xff;
+ s->gic.priority1[irq++][0] = (value >> 8) & 0xff;
+ s->gic.priority1[irq++][0] = (value >> 16) & 0xff;
+ s->gic.priority1[irq][0] = (value >> 24) & 0xff;
+ gic_update(&s->gic);
}
break;
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->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;
break;
case 0xd28: /* Configurable Fault Status. */
case 0xd2c: /* Hard Fault Status. */
@@ -360,7 +361,7 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
goto bad_reg;
default:
bad_reg:
- cpu_abort(cpu_single_env, "NVIC: Bad write offset 0x%x\n", offset);
+ hw_error("NVIC: Bad write offset 0x%x\n", offset);
}
}
@@ -389,19 +390,19 @@ static int nvic_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-qemu_irq *armv7m_nvic_init(CPUState *env)
+static void armv7m_nvic_init(SysBusDevice *dev)
{
- nvic_state *s;
- qemu_irq *parent;
+ nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
- parent = arm_pic_init_cpu(env);
- s = (nvic_state *)qemu_mallocz(sizeof(nvic_state));
- s->gic = gic_init(0xe000e000, &parent[ARM_PIC_CPU_IRQ]);
- s->gic->nvic = s;
+ gic_init(&s->gic);
+ cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype);
s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s);
- if (env->v7m.nvic)
- cpu_abort(env, "CPU can only have one NVIC\n");
- env->v7m.nvic = s;
register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s);
- return s->gic->in;
}
+
+static void armv7m_nvic_register_devices(void)
+{
+ sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init);
+}
+
+device_init(armv7m_nvic_register_devices)