};
void arm_load_kernel(CPUState *env, struct arm_boot_info *info);
-/* armv7m_nvic.c */
-
/* Multiplication factor to convert from system clock ticks to qemu timer
ticks. */
extern int system_clock_scale;
-qemu_irq *armv7m_nvic_init(CPUState *env);
#endif /* !ARM_MISC_H */
#define GIC_BASE_IRQ 0
#endif
+#define FROM_SYSBUSGIC(type, dev) \
+ DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev))
+
typedef struct gic_irq_state
{
/* ??? The documentation seems to imply the enable bits are global, even
typedef struct gic_state
{
+ SysBusDevice busdev;
qemu_irq parent_irq[NCPU];
int enabled;
int cpu_enabled[NCPU];
int running_priority[NCPU];
int current_pending[NCPU];
- qemu_irq *in;
-#ifdef NVIC
- void *nvic;
-#endif
+ int iomemtype;
} gic_state;
/* TODO: Many places that call this routine could be optimized. */
uint32_t addr;
addr = offset;
if (addr < 0x100 || addr > 0xd00)
- return nvic_readl(s->nvic, addr);
+ return nvic_readl(s, addr);
#endif
val = gic_dist_readw(opaque, offset);
val |= gic_dist_readw(opaque, offset + 2) << 16;
uint32_t addr;
addr = offset;
if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
- nvic_writel(s->nvic, addr, value);
+ nvic_writel(s, addr, value);
return;
}
#endif
return 0;
}
-static gic_state *gic_init(uint32_t dist_base, qemu_irq *parent_irq)
+static void gic_init(gic_state *s)
{
- gic_state *s;
- int iomemtype;
int i;
- s = (gic_state *)qemu_mallocz(sizeof(gic_state));
- s->in = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ);
+ qdev_init_irq_sink(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
for (i = 0; i < NCPU; i++) {
- s->parent_irq[i] = parent_irq[i];
+ sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
}
- iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
- gic_dist_writefn, s);
- cpu_register_physical_memory(dist_base, 0x00001000,
- iomemtype);
+ s->iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
+ gic_dist_writefn, s);
gic_reset(s);
register_savevm("arm_gic", -1, 1, gic_save, gic_load, s);
- return s;
}
* This code is licenced under the GPL.
*/
-#include "hw.h"
+#include "sysbus.h"
#include "arm-misc.h"
#include "sysemu.h"
const char *kernel_filename, const char *cpu_model)
{
CPUState *env;
- qemu_irq *pic;
+ DeviceState *nvic;
+ /* FIXME: make this local state. */
+ static qemu_irq pic[64];
+ qemu_irq *cpu_pic;
uint32_t pc;
int image_size;
uint64_t entry;
uint64_t lowaddr;
+ int i;
flash_size *= 1024;
sram_size *= 1024;
qemu_ram_alloc(sram_size) | IO_MEM_RAM);
armv7m_bitband_init();
- pic = armv7m_nvic_init(env);
+ nvic = qdev_create(NULL, "armv7m_nvic");
+ qdev_set_prop_ptr(nvic, "cpu", env);
+ qdev_init(nvic);
+ cpu_pic = arm_pic_init_cpu(env);
+ sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
+ for (i = 0; i < 64; i++) {
+ pic[i] = qdev_get_irq_sink(nvic, i);
+ }
image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
if (image_size < 0) {
* NVIC. Much of that is also implemented here.
*/
-#include "hw.h"
+#include "sysbus.h"
#include "qemu-timer.h"
#include "arm-misc.h"
#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. */
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. */
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)
hw_error("Interrupt but no vector\n");
if (irq >= 32)
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)
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. */
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. */
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. */
{
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. */
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);
+ CPUState *env;
- 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;
+ env = qdev_get_prop_ptr(&dev->qdev, "cpu");
+ 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)
hw_error("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)
* This code is licenced under the GPL.
*/
-#include "hw.h"
+#include "sysbus.h"
#include "qemu-timer.h"
-#include "primecell.h"
#define MPCORE_PRIV_BASE 0x10100000
#define NCPU 4
} mpcore_timer_state;
typedef struct mpcore_priv_state {
- gic_state *gic;
+ gic_state gic;
uint32_t scu_control;
+ int iomemtype;
mpcore_timer_state timer[8];
} mpcore_priv_state;
static inline void mpcore_timer_update_irq(mpcore_timer_state *s)
{
if (s->status & ~s->old_status) {
- gic_set_pending_private(s->mpcore->gic, s->id >> 1, 29 + (s->id & 1));
+ gic_set_pending_private(&s->mpcore->gic, s->id >> 1, 29 + (s->id & 1));
}
s->old_status = s->status;
}
} else {
id = (offset - 0x200) >> 8;
}
- return gic_cpu_read(s->gic, id, offset & 0xff);
+ return gic_cpu_read(&s->gic, id, offset & 0xff);
} else if (offset < 0xb00) {
/* Timers. */
if (offset < 0x700) {
} else {
id = (offset - 0x200) >> 8;
}
- gic_cpu_write(s->gic, id, offset & 0xff, value);
+ gic_cpu_write(&s->gic, id, offset & 0xff, value);
} else if (offset < 0xb00) {
/* Timers. */
if (offset < 0x700) {
mpcore_priv_write
};
+static void mpcore_priv_map(SysBusDevice *dev, target_phys_addr_t base)
+{
+ mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
+ cpu_register_physical_memory(base, 0x1000, s->iomemtype);
+ cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype);
+}
-static qemu_irq *mpcore_priv_init(uint32_t base, qemu_irq *pic_irq)
+static void mpcore_priv_init(SysBusDevice *dev)
{
- mpcore_priv_state *s;
- int iomemtype;
+ mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
int i;
- s = (mpcore_priv_state *)qemu_mallocz(sizeof(mpcore_priv_state));
- s->gic = gic_init(base + 0x1000, pic_irq);
- if (!s->gic)
- return NULL;
- iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn,
- mpcore_priv_writefn, s);
- cpu_register_physical_memory(base, 0x00001000, iomemtype);
+ gic_init(&s->gic);
+ s->iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn,
+ mpcore_priv_writefn, s);
+ sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map);
for (i = 0; i < 8; i++) {
mpcore_timer_init(s, &s->timer[i], i);
}
- return s->gic->in;
}
/* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
controllers. The output of these, plus some of the raw input lines
are fed into a single SMP-aware interrupt controller on the CPU. */
typedef struct {
- qemu_irq *cpuic;
- qemu_irq *rvic[4];
+ SysBusDevice busdev;
+ qemu_irq cpuic[32];
+ qemu_irq rvic[4][64];
} mpcore_rirq_state;
/* Map baseboard IRQs onto CPU IRQ lines. */
}
}
-qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq)
+static void realview_mpcore_init(SysBusDevice *dev)
{
- mpcore_rirq_state *s;
+ mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
+ DeviceState *gic;
+ DeviceState *priv;
int n;
+ int i;
+ priv = sysbus_create_simple("arm11mpcore_priv", MPCORE_PRIV_BASE, NULL);
+ sysbus_pass_irq(dev, sysbus_from_qdev(priv));
+ for (i = 0; i < 32; i++) {
+ s->cpuic[i] = qdev_get_irq_sink(priv, i);
+ }
/* ??? IRQ routing is hardcoded to "normal" mode. */
- s = qemu_mallocz(sizeof(mpcore_rirq_state));
- s->cpuic = mpcore_priv_init(MPCORE_PRIV_BASE, cpu_irq);
for (n = 0; n < 4; n++) {
- s->rvic[n] = realview_gic_init(0x10040000 + n * 0x10000,
- s->cpuic[10 + n]);
+ gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
+ s->cpuic[10 + n]);
+ for (i = 0; i < 64; i++) {
+ s->rvic[n][i] = qdev_get_irq_sink(gic, i);
+ }
}
- return qemu_allocate_irqs(mpcore_rirq_set_irq, s, 64);
+ qdev_init_irq_sink(&dev->qdev, mpcore_rirq_set_irq, 64);
}
+
+static void mpcore_register_devices(void)
+{
+ sysbus_register_dev("realview_mpcore", sizeof(mpcore_rirq_state),
+ realview_mpcore_init);
+ sysbus_register_dev("arm11mpcore_priv", sizeof(mpcore_priv_state),
+ mpcore_priv_init);
+}
+
+device_init(mpcore_register_devices)
/* pl080.c */
void *pl080_init(uint32_t base, qemu_irq irq, int nchannels);
-/* realview_gic.c */
-qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq);
-
-/* mpcore.c */
-extern qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq);
-
/* arm_sysctl.c */
void arm_sysctl_init(uint32_t base, uint32_t sys_id);
{
CPUState *env;
ram_addr_t ram_offset;
- qemu_irq *pic;
DeviceState *dev;
+ qemu_irq *irqp;
+ qemu_irq pic[64];
PCIBus *pci_bus;
NICInfo *nd;
int n;
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- pic = arm_pic_init_cpu(env);
- cpu_irq[n] = pic[ARM_PIC_CPU_IRQ];
+ irqp = arm_pic_init_cpu(env);
+ cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
if (n > 0) {
/* Set entry point for secondary CPUs. This assumes we're using
the init code from arm_boot.c. Real hardware resets all CPUs
/* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3
is nIRQ (there are inconsistencies). However Linux 2.6.17 expects
GIC1 to be nIRQ and ignores all the others, so do that for now. */
- pic = realview_gic_init(0x10040000, cpu_irq[0]);
+ dev = sysbus_create_simple("realview_gic", 0x10040000, cpu_irq[0]);
} else {
- pic = mpcore_irq_init(cpu_irq);
+ dev = sysbus_create_varargs("realview_mpcore", -1,
+ cpu_irq[0], cpu_irq[1], cpu_irq[2],
+ cpu_irq[3], NULL);
+ }
+ for (n = 0; n < 64; n++) {
+ pic[n] = qdev_get_irq_sink(dev, n);
}
sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]);
* This code is licenced under the GPL.
*/
-#include "hw.h"
-#include "primecell.h"
+#include "sysbus.h"
#define GIC_NIRQ 96
#define NCPU 1
#include "arm_gic.c"
+typedef struct {
+ gic_state gic;
+ int iomemtype;
+} RealViewGICState;
+
static uint32_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset)
{
gic_state *s = (gic_state *)opaque;
realview_gic_cpu_write
};
-qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq)
+static void realview_gic_map(SysBusDevice *dev, target_phys_addr_t base)
{
- gic_state *s;
- int iomemtype;
+ RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
+ cpu_register_physical_memory(base, 0x1000, s->iomemtype);
+ cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype);
+}
+
+static void realview_gic_init(SysBusDevice *dev)
+{
+ RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
- s = gic_init(base + 0x1000, &parent_irq);
- if (!s)
- return NULL;
- iomemtype = cpu_register_io_memory(0, realview_gic_cpu_readfn,
- realview_gic_cpu_writefn, s);
- cpu_register_physical_memory(base, 0x00001000, iomemtype);
- return s->in;
+ gic_init(&s->gic);
+ s->iomemtype = cpu_register_io_memory(0, realview_gic_cpu_readfn,
+ realview_gic_cpu_writefn, s);
+ sysbus_init_mmio_cb(dev, 0x2000, realview_gic_map);
}
+
+static void realview_gic_register_devices(void)
+{
+ sysbus_register_dev("realview_gic", sizeof(RealViewGICState),
+ realview_gic_init);
+}
+
+device_init(realview_gic_register_devices)