-/*
+/*
* ARM Integrator CP System emulation.
*
- * Copyright (c) 2005 CodeSourcery, LLC.
+ * Copyright (c) 2005-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL
*/
-#include <vl.h>
-
-#define KERNEL_ARGS_ADDR 0x100
-#define KERNEL_LOAD_ADDR 0x00010000
-#define INITRD_LOAD_ADDR 0x00800000
-
-/* Stub functions for hardware that doesn't exist. */
-void pic_set_irq(int irq, int level)
-{
- cpu_abort (cpu_single_env, "pic_set_irq");
-}
-
-void pic_info(void)
-{
-}
-
-void irq_info(void)
-{
-}
-
-void vga_update_display(void)
-{
-}
-
-void vga_screen_dump(const char *filename)
-{
-}
-
-void vga_invalidate_display(void)
-{
-}
+#include "hw.h"
+#include "primecell.h"
+#include "devices.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "arm-misc.h"
+#include "net.h"
void DMA_run (void)
{
return 0;
default:
cpu_abort (cpu_single_env,
- "integratorcm_read: Unimplemented offset 0x%x\n", offset);
+ "integratorcm_read: Unimplemented offset 0x%x\n", (int)offset);
return 0;
}
}
break;
default:
cpu_abort (cpu_single_env,
- "integratorcm_write: Unimplemented offset 0x%x\n", offset);
+ "integratorcm_write: Unimplemented offset 0x%x\n", (int)offset);
break;
}
}
integratorcm_write
};
-static void integratorcm_init(int memsz, uint32_t flash_offset)
+static void integratorcm_init(int memsz)
{
int iomemtype;
integratorcm_state *s;
}
memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
s->cm_init = 0x00000112;
- s->flash_offset = flash_offset;
+ s->flash_offset = qemu_ram_alloc(0x100000);
iomemtype = cpu_register_io_memory(0, integratorcm_readfn,
integratorcm_writefn, s);
- cpu_register_physical_memory(0x10000000, 0x007fffff, iomemtype);
+ cpu_register_physical_memory(0x10000000, 0x00800000, iomemtype);
integratorcm_do_remap(s, 1);
/* ??? Save/restore. */
}
uint32_t level;
uint32_t irq_enabled;
uint32_t fiq_enabled;
- void *parent;
- /* -1 if parent is a cpu, otherwise IRQ number on parent PIC. */
- int parent_irq;
+ qemu_irq parent_irq;
+ qemu_irq parent_fiq;
} icp_pic_state;
static void icp_pic_update(icp_pic_state *s)
{
- CPUState *env;
- if (s->parent_irq != -1) {
- uint32_t flags;
+ uint32_t flags;
- flags = (s->level & s->irq_enabled);
- pic_set_irq_new(s->parent, s->parent_irq,
- flags != 0);
- return;
- }
- /* Raise CPU interrupt. */
- env = (CPUState *)s->parent;
- if (s->level & s->fiq_enabled) {
- cpu_interrupt (env, CPU_INTERRUPT_FIQ);
- } else {
- cpu_reset_interrupt (env, CPU_INTERRUPT_FIQ);
- }
- if (s->level & s->irq_enabled) {
- cpu_interrupt (env, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt (env, CPU_INTERRUPT_HARD);
- }
+ flags = (s->level & s->irq_enabled);
+ qemu_set_irq(s->parent_irq, flags != 0);
+ flags = (s->level & s->fiq_enabled);
+ qemu_set_irq(s->parent_fiq, flags != 0);
}
-void pic_set_irq_new(void *opaque, int irq, int level)
+static void icp_pic_set_irq(void *opaque, int irq, int level)
{
icp_pic_state *s = (icp_pic_state *)opaque;
if (level)
case 5: /* INT_SOFTCLR */
case 11: /* FRQ_ENABLECLR */
default:
- printf ("icp_pic_read: Bad register offset 0x%x\n", offset);
+ printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
return 0;
}
}
break;
case 4: /* INT_SOFTSET */
if (value & 1)
- pic_set_irq_new(s, 0, 1);
+ icp_pic_set_irq(s, 0, 1);
break;
case 5: /* INT_SOFTCLR */
if (value & 1)
- pic_set_irq_new(s, 0, 0);
+ icp_pic_set_irq(s, 0, 0);
break;
case 10: /* FRQ_ENABLESET */
s->fiq_enabled |= value;
case 8: /* FRQ_STATUS */
case 9: /* FRQ_RAWSTAT */
default:
- printf ("icp_pic_write: Bad register offset 0x%x\n", offset);
+ printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
return;
}
icp_pic_update(s);
icp_pic_write
};
-static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
- int parent_irq)
+static qemu_irq *icp_pic_init(uint32_t base,
+ qemu_irq parent_irq, qemu_irq parent_fiq)
{
icp_pic_state *s;
int iomemtype;
+ qemu_irq *qi;
s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state));
if (!s)
return NULL;
-
+ qi = qemu_allocate_irqs(icp_pic_set_irq, s, 32);
s->base = base;
- s->parent = parent;
s->parent_irq = parent_irq;
+ s->parent_fiq = parent_fiq;
iomemtype = cpu_register_io_memory(0, icp_pic_readfn,
icp_pic_writefn, s);
- cpu_register_physical_memory(base, 0x007fffff, iomemtype);
- /* ??? Save/restore. */
- return s;
-}
-
-/* Timers. */
-
-/* System bus clock speed (40MHz) for timer 0. Not sure about this value. */
-#define ICP_BUS_FREQ 40000000
-
-typedef struct {
- int64_t next_time;
- int64_t expires[3];
- int64_t loaded[3];
- QEMUTimer *timer;
- icp_pic_state *pic;
- uint32_t base;
- uint32_t control[3];
- uint32_t count[3];
- uint32_t limit[3];
- int freq[3];
- int int_level[3];
-} icp_pit_state;
-
-/* Calculate the new expiry time of the given timer. */
-
-static void icp_pit_reload(icp_pit_state *s, int n)
-{
- int64_t delay;
-
- s->loaded[n] = s->expires[n];
- delay = muldiv64(s->count[n], ticks_per_sec, s->freq[n]);
- if (delay == 0)
- delay = 1;
- s->expires[n] += delay;
-}
-
-/* Check all active timers, and schedule the next timer interrupt. */
-
-static void icp_pit_update(icp_pit_state *s, int64_t now)
-{
- int n;
- int64_t next;
-
- next = now;
- for (n = 0; n < 3; n++) {
- /* Ignore disabled timers. */
- if ((s->control[n] & 0x80) == 0)
- continue;
- /* Ignore expired one-shot timers. */
- if (s->count[n] == 0 && s->control[n] & 1)
- continue;
- if (s->expires[n] - now <= 0) {
- /* Timer has expired. */
- s->int_level[n] = 1;
- if (s->control[n] & 1) {
- /* One-shot. */
- s->count[n] = 0;
- } else {
- if ((s->control[n] & 0x40) == 0) {
- /* Free running. */
- if (s->control[n] & 2)
- s->count[n] = 0xffffffff;
- else
- s->count[n] = 0xffff;
- } else {
- /* Periodic. */
- s->count[n] = s->limit[n];
- }
- }
- }
- while (s->expires[n] - now <= 0) {
- icp_pit_reload(s, n);
- }
- }
- /* Update interrupts. */
- for (n = 0; n < 3; n++) {
- if (s->int_level[n] && (s->control[n] & 0x20)) {
- pic_set_irq_new(s->pic, 5 + n, 1);
- } else {
- pic_set_irq_new(s->pic, 5 + n, 0);
- }
- if (next - s->expires[n] < 0)
- next = s->expires[n];
- }
- /* Schedule the next timer interrupt. */
- if (next == now) {
- qemu_del_timer(s->timer);
- s->next_time = 0;
- } else if (next != s->next_time) {
- qemu_mod_timer(s->timer, next);
- s->next_time = next;
- }
-}
-
-/* Return the current value of the timer. */
-static uint32_t icp_pit_getcount(icp_pit_state *s, int n, int64_t now)
-{
- int64_t elapsed;
- int64_t period;
-
- if (s->count[n] == 0)
- return 0;
- if ((s->control[n] & 0x80) == 0)
- return s->count[n];
- elapsed = now - s->loaded[n];
- period = s->expires[n] - s->loaded[n];
- /* If the timer should have expired then return 0. This can happen
- when the host timer signal doesnt occur immediately. It's better to
- have a timer appear to sit at zero for a while than have it wrap
- around before the guest interrupt is raised. */
- /* ??? Could we trigger the interrupt here? */
- if (elapsed > period)
- return 0;
- /* We need to calculate count * elapsed / period without overfowing.
- Scale both elapsed and period so they fit in a 32-bit int. */
- while (period != (int32_t)period) {
- period >>= 1;
- elapsed >>= 1;
- }
- return ((uint64_t)s->count[n] * (uint64_t)(int32_t)elapsed)
- / (int32_t)period;
-}
-
-static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
-{
- int n;
- icp_pit_state *s = (icp_pit_state *)opaque;
-
- offset -= s->base;
- n = offset >> 8;
- if (n > 2)
- cpu_abort (cpu_single_env, "icp_pit_read: Bad timer %x\n", offset);
- switch ((offset & 0xff) >> 2) {
- case 0: /* TimerLoad */
- case 6: /* TimerBGLoad */
- return s->limit[n];
- case 1: /* TimerValue */
- return icp_pit_getcount(s, n, qemu_get_clock(vm_clock));
- case 2: /* TimerControl */
- return s->control[n];
- case 4: /* TimerRIS */
- return s->int_level[n];
- case 5: /* TimerMIS */
- if ((s->control[n] & 0x20) == 0)
- return 0;
- return s->int_level[n];
- default:
- cpu_abort (cpu_single_env, "icp_pit_read: Bad offset %x\n", offset);
- return 0;
- }
-}
-
-static void icp_pit_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- icp_pit_state *s = (icp_pit_state *)opaque;
- int n;
- int64_t now;
-
- now = qemu_get_clock(vm_clock);
- offset -= s->base;
- n = offset >> 8;
- if (n > 2)
- cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset);
-
- switch ((offset & 0xff) >> 2) {
- case 0: /* TimerLoad */
- s->limit[n] = value;
- s->count[n] = value;
- s->expires[n] = now;
- icp_pit_reload(s, n);
- break;
- case 1: /* TimerValue */
- /* ??? Linux seems to want to write to this readonly register.
- Ignore it. */
- break;
- case 2: /* TimerControl */
- if (s->control[n] & 0x80) {
- /* Pause the timer if it is running. This may cause some
- inaccuracy dure to rounding, but avoids a whole lot of other
- messyness. */
- s->count[n] = icp_pit_getcount(s, n, now);
- }
- s->control[n] = value;
- if (n == 0)
- s->freq[n] = ICP_BUS_FREQ;
- else
- s->freq[n] = 1000000;
- /* ??? Need to recalculate expiry time after changing divisor. */
- switch ((value >> 2) & 3) {
- case 1: s->freq[n] >>= 4; break;
- case 2: s->freq[n] >>= 8; break;
- }
- if (s->control[n] & 0x80) {
- /* Restart the timer if still enabled. */
- s->expires[n] = now;
- icp_pit_reload(s, n);
- }
- break;
- case 3: /* TimerIntClr */
- s->int_level[n] = 0;
- break;
- case 6: /* TimerBGLoad */
- s->limit[n] = value;
- break;
- default:
- cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset);
- }
- icp_pit_update(s, now);
-}
-
-static void icp_pit_tick(void *opaque)
-{
- int64_t now;
-
- now = qemu_get_clock(vm_clock);
- icp_pit_update((icp_pit_state *)opaque, now);
-}
-
-static CPUReadMemoryFunc *icp_pit_readfn[] = {
- icp_pit_read,
- icp_pit_read,
- icp_pit_read
-};
-
-static CPUWriteMemoryFunc *icp_pit_writefn[] = {
- icp_pit_write,
- icp_pit_write,
- icp_pit_write
-};
-
-static void icp_pit_init(uint32_t base, icp_pic_state *pic)
-{
- int iomemtype;
- icp_pit_state *s;
- int n;
-
- s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
- s->base = base;
- s->pic = pic;
- s->freq[0] = ICP_BUS_FREQ;
- s->freq[1] = 1000000;
- s->freq[2] = 1000000;
- for (n = 0; n < 3; n++) {
- s->control[n] = 0x20;
- s->count[n] = 0xffffffff;
- }
-
- iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
- icp_pit_writefn, s);
- cpu_register_physical_memory(base, 0x007fffff, iomemtype);
- s->timer = qemu_new_timer(vm_clock, icp_pit_tick, s);
- /* ??? Save/restore. */
-}
-
-/* ARM PrimeCell PL011 UART */
-
-typedef struct {
- uint32_t base;
- uint32_t readbuff;
- uint32_t flags;
- uint32_t lcr;
- uint32_t cr;
- uint32_t dmacr;
- uint32_t int_enabled;
- uint32_t int_level;
- uint32_t read_fifo[16];
- uint32_t ilpr;
- uint32_t ibrd;
- uint32_t fbrd;
- uint32_t ifl;
- int read_pos;
- int read_count;
- int read_trigger;
- CharDriverState *chr;
- icp_pic_state *pic;
- int irq;
-} pl011_state;
-
-#define PL011_INT_TX 0x20
-#define PL011_INT_RX 0x10
-
-#define PL011_FLAG_TXFE 0x80
-#define PL011_FLAG_RXFF 0x40
-#define PL011_FLAG_TXFF 0x20
-#define PL011_FLAG_RXFE 0x10
-
-static const unsigned char pl011_id[] =
-{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl011_update(pl011_state *s)
-{
- uint32_t flags;
-
- flags = s->int_level & s->int_enabled;
- pic_set_irq_new(s->pic, s->irq, flags != 0);
-}
-
-static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
-{
- pl011_state *s = (pl011_state *)opaque;
- uint32_t c;
-
- offset -= s->base;
- if (offset >= 0xfe0 && offset < 0x1000) {
- return pl011_id[(offset - 0xfe0) >> 2];
- }
- switch (offset >> 2) {
- case 0: /* UARTDR */
- s->flags &= ~PL011_FLAG_RXFF;
- c = s->read_fifo[s->read_pos];
- if (s->read_count > 0) {
- s->read_count--;
- if (++s->read_pos == 16)
- s->read_pos = 0;
- }
- if (s->read_count == 0) {
- s->flags |= PL011_FLAG_RXFE;
- }
- if (s->read_count == s->read_trigger - 1)
- s->int_level &= ~ PL011_INT_RX;
- pl011_update(s);
- return c;
- case 1: /* UARTCR */
- return 0;
- case 6: /* UARTFR */
- return s->flags;
- case 8: /* UARTILPR */
- return s->ilpr;
- case 9: /* UARTIBRD */
- return s->ibrd;
- case 10: /* UARTFBRD */
- return s->fbrd;
- case 11: /* UARTLCR_H */
- return s->lcr;
- case 12: /* UARTCR */
- return s->cr;
- case 13: /* UARTIFLS */
- return s->ifl;
- case 14: /* UARTIMSC */
- return s->int_enabled;
- case 15: /* UARTRIS */
- return s->int_level;
- case 16: /* UARTMIS */
- return s->int_level & s->int_enabled;
- case 18: /* UARTDMACR */
- return s->dmacr;
- default:
- cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset);
- return 0;
- }
-}
-
-static void pl011_set_read_trigger(pl011_state *s)
-{
-#if 0
- /* The docs say the RX interrupt is triggered when the FIFO exceeds
- the threshold. However linux only reads the FIFO in response to an
- interrupt. Triggering the interrupt when the FIFO is non-empty seems
- to make things work. */
- if (s->lcr & 0x10)
- s->read_trigger = (s->ifl >> 1) & 0x1c;
- else
-#endif
- s->read_trigger = 1;
-}
-
-static void pl011_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- pl011_state *s = (pl011_state *)opaque;
- unsigned char ch;
-
- offset -= s->base;
- switch (offset >> 2) {
- case 0: /* UARTDR */
- /* ??? Check if transmitter is enabled. */
- ch = value;
- if (s->chr)
- qemu_chr_write(s->chr, &ch, 1);
- s->int_level |= PL011_INT_TX;
- pl011_update(s);
- break;
- case 1: /* UARTCR */
- s->cr = value;
- break;
- case 8: /* UARTUARTILPR */
- s->ilpr = value;
- break;
- case 9: /* UARTIBRD */
- s->ibrd = value;
- break;
- case 10: /* UARTFBRD */
- s->fbrd = value;
- break;
- case 11: /* UARTLCR_H */
- s->lcr = value;
- pl011_set_read_trigger(s);
- break;
- case 12: /* UARTCR */
- /* ??? Need to implement the enable and loopback bits. */
- s->cr = value;
- break;
- case 13: /* UARTIFS */
- s->ifl = value;
- pl011_set_read_trigger(s);
- break;
- case 14: /* UARTIMSC */
- s->int_enabled = value;
- pl011_update(s);
- break;
- case 17: /* UARTICR */
- s->int_level &= ~value;
- pl011_update(s);
- break;
- case 18: /* UARTDMACR */
- s->dmacr = value;
- if (value & 3)
- cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
- break;
- default:
- cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset);
- }
-}
-
-static int pl011_can_recieve(void *opaque)
-{
- pl011_state *s = (pl011_state *)opaque;
-
- if (s->lcr & 0x10)
- return s->read_count < 16;
- else
- return s->read_count < 1;
-}
-
-static void pl011_recieve(void *opaque, const uint8_t *buf, int size)
-{
- pl011_state *s = (pl011_state *)opaque;
- int slot;
-
- slot = s->read_pos + s->read_count;
- if (slot >= 16)
- slot -= 16;
- s->read_fifo[slot] = *buf;
- s->read_count++;
- s->flags &= ~PL011_FLAG_RXFE;
- if (s->cr & 0x10 || s->read_count == 16) {
- s->flags |= PL011_FLAG_RXFF;
- }
- if (s->read_count == s->read_trigger) {
- s->int_level |= PL011_INT_RX;
- pl011_update(s);
- }
-}
-
-static void pl011_event(void *opaque, int event)
-{
- /* ??? Should probably implement break. */
-}
-
-static CPUReadMemoryFunc *pl011_readfn[] = {
- pl011_read,
- pl011_read,
- pl011_read
-};
-
-static CPUWriteMemoryFunc *pl011_writefn[] = {
- pl011_write,
- pl011_write,
- pl011_write
-};
-
-static void pl011_init(uint32_t base, icp_pic_state *pic, int irq,
- CharDriverState *chr)
-{
- int iomemtype;
- pl011_state *s;
-
- s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
- iomemtype = cpu_register_io_memory(0, pl011_readfn,
- pl011_writefn, s);
- cpu_register_physical_memory(base, 0x007fffff, iomemtype);
- s->base = base;
- s->pic = pic;
- s->irq = irq;
- s->chr = chr;
- s->read_trigger = 1;
- s->ifl = 0x12;
- s->cr = 0x300;
- s->flags = 0x90;
- if (chr){
- qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s);
- qemu_chr_add_event_handler(chr, pl011_event);
- }
+ cpu_register_physical_memory(base, 0x00800000, iomemtype);
/* ??? Save/restore. */
+ return qi;
}
/* CP control registers. */
case 3: /* CP_DECODE */
return 0x11;
default:
- cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n", offset);
+ cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n",
+ (int)offset);
return 0;
}
}
/* Nothing interesting implemented yet. */
break;
default:
- cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n", offset);
+ cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n",
+ (int)offset);
}
}
static CPUReadMemoryFunc *icp_control_readfn[] = {
s = (icp_control_state *)qemu_mallocz(sizeof(icp_control_state));
iomemtype = cpu_register_io_memory(0, icp_control_readfn,
icp_control_writefn, s);
- cpu_register_physical_memory(base, 0x007fffff, iomemtype);
+ cpu_register_physical_memory(base, 0x00800000, iomemtype);
s->base = base;
/* ??? Save/restore. */
}
-/* Keyboard/Mouse Interface. */
-
-typedef struct {
- void *dev;
- uint32_t base;
- uint32_t cr;
- uint32_t clk;
- uint32_t last;
- icp_pic_state *pic;
- int pending;
- int irq;
- int is_mouse;
-} icp_kmi_state;
-
-static void icp_kmi_update(void *opaque, int level)
-{
- icp_kmi_state *s = (icp_kmi_state *)opaque;
- int raise;
-
- s->pending = level;
- raise = (s->pending && (s->cr & 0x10) != 0)
- || (s->cr & 0x08) != 0;
- pic_set_irq_new(s->pic, s->irq, raise);
-}
-
-static uint32_t icp_kmi_read(void *opaque, target_phys_addr_t offset)
-{
- icp_kmi_state *s = (icp_kmi_state *)opaque;
- offset -= s->base;
- if (offset >= 0xfe0 && offset < 0x1000)
- return 0;
-
- switch (offset >> 2) {
- case 0: /* KMICR */
- return s->cr;
- case 1: /* KMISTAT */
- /* KMIC and KMID bits not implemented. */
- if (s->pending) {
- return 0x10;
- } else {
- return 0;
- }
- case 2: /* KMIDATA */
- if (s->pending)
- s->last = ps2_read_data(s->dev);
- return s->last;
- case 3: /* KMICLKDIV */
- return s->clk;
- case 4: /* KMIIR */
- return s->pending | 2;
- default:
- cpu_abort (cpu_single_env, "icp_kmi_read: Bad offset %x\n", offset);
- return 0;
- }
-}
-
-static void icp_kmi_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- icp_kmi_state *s = (icp_kmi_state *)opaque;
- offset -= s->base;
- switch (offset >> 2) {
- case 0: /* KMICR */
- s->cr = value;
- icp_kmi_update(s, s->pending);
- /* ??? Need to implement the enable/disable bit. */
- break;
- case 2: /* KMIDATA */
- /* ??? This should toggle the TX interrupt line. */
- /* ??? This means kbd/mouse can block each other. */
- if (s->is_mouse) {
- ps2_write_mouse(s->dev, value);
- } else {
- ps2_write_keyboard(s->dev, value);
- }
- break;
- case 3: /* KMICLKDIV */
- s->clk = value;
- return;
- default:
- cpu_abort (cpu_single_env, "icp_kmi_write: Bad offset %x\n", offset);
- }
-}
-static CPUReadMemoryFunc *icp_kmi_readfn[] = {
- icp_kmi_read,
- icp_kmi_read,
- icp_kmi_read
-};
-
-static CPUWriteMemoryFunc *icp_kmi_writefn[] = {
- icp_kmi_write,
- icp_kmi_write,
- icp_kmi_write
-};
-
-static void icp_kmi_init(uint32_t base, icp_pic_state * pic, int irq,
- int is_mouse)
-{
- int iomemtype;
- icp_kmi_state *s;
-
- s = (icp_kmi_state *)qemu_mallocz(sizeof(icp_kmi_state));
- iomemtype = cpu_register_io_memory(0, icp_kmi_readfn,
- icp_kmi_writefn, s);
- cpu_register_physical_memory(base, 0x007fffff, iomemtype);
- s->base = base;
- s->pic = pic;
- s->irq = irq;
- s->is_mouse = is_mouse;
- if (is_mouse)
- s->dev = ps2_mouse_init(icp_kmi_update, s);
- else
- s->dev = ps2_kbd_init(icp_kmi_update, s);
- /* ??? Save/restore. */
-}
+/* Board init. */
-/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
-static uint32_t bootloader[] = {
- 0xe3a00000, /* mov r0, #0 */
- 0xe3a01013, /* mov r1, #0x13 */
- 0xe3811c01, /* orr r1, r1, #0x100 */
- 0xe59f2000, /* ldr r2, [pc, #0] */
- 0xe59ff000, /* ldr pc, [pc, #0] */
- 0, /* Address of kernel args. Set by integratorcp_init. */
- 0 /* Kernel entry point. Set by integratorcp_init. */
+static struct arm_boot_info integrator_binfo = {
+ .loader_start = 0x0,
+ .board_id = 0x113,
};
-static void set_kernel_args(uint32_t ram_size, int initrd_size,
- const char *kernel_cmdline)
-{
- uint32_t *p;
-
- p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR);
- /* ATAG_CORE */
- *(p++) = 5;
- *(p++) = 0x54410001;
- *(p++) = 1;
- *(p++) = 0x1000;
- *(p++) = 0;
- /* ATAG_MEM */
- *(p++) = 4;
- *(p++) = 0x54410002;
- *(p++) = ram_size;
- *(p++) = 0;
- if (initrd_size) {
- /* ATAG_INITRD2 */
- *(p++) = 4;
- *(p++) = 0x54420005;
- *(p++) = INITRD_LOAD_ADDR;
- *(p++) = initrd_size;
- }
- if (kernel_cmdline && *kernel_cmdline) {
- /* ATAG_CMDLINE */
- int cmdline_size;
-
- cmdline_size = strlen(kernel_cmdline);
- memcpy (p + 2, kernel_cmdline, cmdline_size + 1);
- cmdline_size = (cmdline_size >> 2) + 1;
- *(p++) = cmdline_size + 2;
- *(p++) = 0x54410009;
- p += cmdline_size;
- }
- /* ATAG_END */
- *(p++) = 0;
- *(p++) = 0;
-}
-
-/* Board init. */
-
-static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device,
- DisplayState *ds, const char **fd_filename, int snapshot,
+static void integratorcp_init(ram_addr_t ram_size, int vga_ram_size,
+ const char *boot_device, DisplayState *ds,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
CPUState *env;
- uint32_t bios_offset;
- icp_pic_state *pic;
- int kernel_size;
- int initrd_size;
-
- env = cpu_init();
- bios_offset = ram_size + vga_ram_size;
+ uint32_t ram_offset;
+ qemu_irq *pic;
+ qemu_irq *cpu_pic;
+ int sd;
+
+ if (!cpu_model)
+ cpu_model = "arm926";
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+ ram_offset = qemu_ram_alloc(ram_size);
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
- /* ??? RAM shoud repeat to fill physical memory space. */
+ /* ??? RAM should repeat to fill physical memory space. */
/* SDRAM at address zero*/
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
/* And again at address 0x80000000 */
- cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM);
-
- integratorcm_init(ram_size >> 20, bios_offset);
- pic = icp_pic_init(0x14000000, env, -1);
- icp_pic_init(0xca000000, pic, 26);
- icp_pit_init(0x13000000, pic);
- pl011_init(0x16000000, pic, 1, serial_hds[0]);
- pl011_init(0x17000000, pic, 2, serial_hds[1]);
+ cpu_register_physical_memory(0x80000000, ram_size, ram_offset | IO_MEM_RAM);
+
+ integratorcm_init(ram_size >> 20);
+ cpu_pic = arm_pic_init_cpu(env);
+ pic = icp_pic_init(0x14000000, cpu_pic[ARM_PIC_CPU_IRQ],
+ cpu_pic[ARM_PIC_CPU_FIQ]);
+ icp_pic_init(0xca000000, pic[26], NULL);
+ icp_pit_init(0x13000000, pic, 5);
+ pl031_init(0x15000000, pic[8]);
+ pl011_init(0x16000000, pic[1], serial_hds[0], PL011_ARM);
+ pl011_init(0x17000000, pic[2], serial_hds[1], PL011_ARM);
icp_control_init(0xcb000000);
- icp_kmi_init(0x18000000, pic, 3, 0);
- icp_kmi_init(0x19000000, pic, 4, 1);
+ pl050_init(0x18000000, pic[3], 0);
+ pl050_init(0x19000000, pic[4], 1);
+ sd = drive_get_index(IF_SD, 0, 0);
+ if (sd == -1) {
+ fprintf(stderr, "qemu: missing SecureDigital card\n");
+ exit(1);
+ }
+ pl181_init(0x1c000000, drives_table[sd].bdrv, pic[23], pic[24]);
if (nd_table[0].vlan) {
if (nd_table[0].model == NULL
|| strcmp(nd_table[0].model, "smc91c111") == 0) {
- smc91c111_init(&nd_table[0], 0xc8000000, pic, 27);
+ smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
+ } else if (strcmp(nd_table[0].model, "?") == 0) {
+ fprintf(stderr, "qemu: Supported NICs: smc91c111\n");
+ exit (1);
} else {
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
exit (1);
}
}
+ pl110_init(ds, 0xc0000000, pic[22], 0);
- /* Load the kernel. */
- if (!kernel_filename) {
- fprintf(stderr, "Kernel image must be specified\n");
- exit(1);
- }
- kernel_size = load_image(kernel_filename,
- phys_ram_base + KERNEL_LOAD_ADDR);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
- exit(1);
- }
- if (initrd_filename) {
- initrd_size = load_image(initrd_filename,
- phys_ram_base + INITRD_LOAD_ADDR);
- if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initrd '%s'\n",
- initrd_filename);
- exit(1);
- }
- } else {
- initrd_size = 0;
- }
- bootloader[5] = KERNEL_ARGS_ADDR;
- bootloader[6] = KERNEL_LOAD_ADDR;
- memcpy(phys_ram_base, bootloader, sizeof(bootloader));
- set_kernel_args(ram_size, initrd_size, kernel_cmdline);
+ integrator_binfo.ram_size = ram_size;
+ integrator_binfo.kernel_filename = kernel_filename;
+ integrator_binfo.kernel_cmdline = kernel_cmdline;
+ integrator_binfo.initrd_filename = initrd_filename;
+ arm_load_kernel(env, &integrator_binfo);
}
QEMUMachine integratorcp_machine = {
"integratorcp",
- "ARM Integrator/CP",
+ "ARM Integrator/CP (ARM926EJ-S)",
integratorcp_init,
+ 0x100000,
};