diff options
-rw-r--r-- | hw/arm_gic.c | 28 | ||||
-rw-r--r-- | hw/mpcore.c | 64 | ||||
-rw-r--r-- | hw/realview.c | 84 | ||||
-rw-r--r-- | qemu-doc.texi | 2 |
4 files changed, 131 insertions, 47 deletions
diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 12f5109924..536112bff5 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -48,6 +48,11 @@ typedef struct gic_irq_state } gic_irq_state; #define ALL_CPU_MASK ((1 << NCPU) - 1) +#if NCPU > 1 +#define NUM_CPU(s) ((s)->num_cpu) +#else +#define NUM_CPU(s) 1 +#endif #define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1 #define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0 @@ -95,6 +100,10 @@ typedef struct gic_state int running_priority[NCPU]; int current_pending[NCPU]; +#if NCPU > 1 + int num_cpu; +#endif + int iomemtype; } gic_state; @@ -109,7 +118,7 @@ static void gic_update(gic_state *s) int cpu; int cm; - for (cpu = 0; cpu < NCPU; cpu++) { + for (cpu = 0; cpu < NUM_CPU(s); cpu++) { cm = 1 << cpu; s->current_pending[cpu] = 1023; if (!s->enabled || !s->cpu_enabled[cpu]) { @@ -255,7 +264,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) if (offset == 0) return s->enabled; if (offset == 4) - return ((GIC_NIRQ / 32) - 1) | ((NCPU - 1) << 5); + return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5); if (offset < 0x08) return 0; #endif @@ -620,7 +629,7 @@ static void gic_reset(gic_state *s) { int i; memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state)); - for (i = 0 ; i < NCPU; i++) { + for (i = 0 ; i < NUM_CPU(s); i++) { s->priority_mask[i] = 0xf0; s->current_pending[i] = 1023; s->running_irq[i] = 1023; @@ -651,7 +660,7 @@ static void gic_save(QEMUFile *f, void *opaque) int j; qemu_put_be32(f, s->enabled); - for (i = 0; i < NCPU; i++) { + for (i = 0; i < NUM_CPU(s); i++) { qemu_put_be32(f, s->cpu_enabled[i]); #ifndef NVIC qemu_put_be32(f, s->irq_target[i]); @@ -688,7 +697,7 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) return -EINVAL; s->enabled = qemu_get_be32(f); - for (i = 0; i < NCPU; i++) { + for (i = 0; i < NUM_CPU(s); i++) { s->cpu_enabled[i] = qemu_get_be32(f); #ifndef NVIC s->irq_target[i] = qemu_get_be32(f); @@ -717,12 +726,19 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) return 0; } +#if NCPU > 1 +static void gic_init(gic_state *s, int num_cpu) +#else static void gic_init(gic_state *s) +#endif { int i; +#if NCPU > 1 + s->num_cpu = num_cpu; +#endif qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32); - for (i = 0; i < NCPU; i++) { + for (i = 0; i < NUM_CPU(s); i++) { sysbus_init_irq(&s->busdev, &s->parent_irq[i]); } s->iomemtype = cpu_register_io_memory(gic_dist_readfn, diff --git a/hw/mpcore.c b/hw/mpcore.c index 46c2b9d994..eccb2e188d 100644 --- a/hw/mpcore.c +++ b/hw/mpcore.c @@ -44,6 +44,7 @@ typedef struct mpcore_priv_state { uint32_t scu_control; int iomemtype; mpcore_timer_state timer[8]; + uint32_t num_cpu; } mpcore_priv_state; /* Per-CPU Timers. */ @@ -166,7 +167,8 @@ static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset) case 0x00: /* Control. */ return s->scu_control; case 0x04: /* Configuration. */ - return 0xf3; + id = ((1 << s->num_cpu) - 1) << 4; + return id | (s->num_cpu - 1); case 0x08: /* CPU status. */ return 0; case 0x0c: /* Invalidate all. */ @@ -180,6 +182,9 @@ static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset) id = gic_get_current_cpu(); } else { id = (offset - 0x200) >> 8; + if (id >= s->num_cpu) { + return 0; + } } return gic_cpu_read(&s->gic, id, offset & 0xff); } else if (offset < 0xb00) { @@ -188,6 +193,9 @@ static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset) id = gic_get_current_cpu(); } else { id = (offset - 0x700) >> 8; + if (id >= s->num_cpu) { + return 0; + } } id <<= 1; if (offset & 0x20) @@ -224,7 +232,9 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset, } else { id = (offset - 0x200) >> 8; } - gic_cpu_write(&s->gic, id, offset & 0xff, value); + if (id < s->num_cpu) { + gic_cpu_write(&s->gic, id, offset & 0xff, value); + } } else if (offset < 0xb00) { /* Timers. */ if (offset < 0x700) { @@ -232,10 +242,12 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset, } else { id = (offset - 0x700) >> 8; } - id <<= 1; - if (offset & 0x20) - id++; - mpcore_timer_write(&s->timer[id], offset & 0xf, value); + if (id < s->num_cpu) { + id <<= 1; + if (offset & 0x20) + id++; + mpcore_timer_write(&s->timer[id], offset & 0xf, value); + } return; } return; @@ -267,11 +279,11 @@ static int mpcore_priv_init(SysBusDevice *dev) mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev); int i; - gic_init(&s->gic); + gic_init(&s->gic, s->num_cpu); s->iomemtype = cpu_register_io_memory(mpcore_priv_readfn, mpcore_priv_writefn, s); sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map); - for (i = 0; i < 8; i++) { + for (i = 0; i < s->num_cpu * 2; i++) { mpcore_timer_init(s, &s->timer[i], i); } return 0; @@ -284,6 +296,7 @@ typedef struct { SysBusDevice busdev; qemu_irq cpuic[32]; qemu_irq rvic[4][64]; + uint32_t num_cpu; } mpcore_rirq_state; /* Map baseboard IRQs onto CPU IRQ lines. */ @@ -315,11 +328,16 @@ static int realview_mpcore_init(SysBusDevice *dev) mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev); DeviceState *gic; DeviceState *priv; + SysBusDevice *bus_priv; int n; int i; - priv = sysbus_create_simple("arm11mpcore_priv", MPCORE_PRIV_BASE, NULL); - sysbus_pass_irq(dev, sysbus_from_qdev(priv)); + priv = qdev_create(NULL, "arm11mpcore_priv"); + qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu); + qdev_init_nofail(priv); + bus_priv = sysbus_from_qdev(priv); + sysbus_mmio_map(bus_priv, 0, MPCORE_PRIV_BASE); + sysbus_pass_irq(dev, bus_priv); for (i = 0; i < 32; i++) { s->cpuic[i] = qdev_get_gpio_in(priv, i); } @@ -335,12 +353,30 @@ static int realview_mpcore_init(SysBusDevice *dev) return 0; } +static SysBusDeviceInfo mpcore_rirq_info = { + .init = realview_mpcore_init, + .qdev.name = "realview_mpcore", + .qdev.size = sizeof(mpcore_rirq_state), + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static SysBusDeviceInfo mpcore_priv_info = { + .init = mpcore_priv_init, + .qdev.name = "arm11mpcore_priv", + .qdev.size = sizeof(mpcore_priv_state), + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), + DEFINE_PROP_END_OF_LIST(), + } +}; + 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); + sysbus_register_withprop(&mpcore_rirq_info); + sysbus_register_withprop(&mpcore_priv_info); } device_init(mpcore_register_devices) diff --git a/hw/realview.c b/hw/realview.c index a14c8a08c9..0e57b50854 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -35,14 +35,21 @@ static void secondary_cpu_reset(void *opaque) env->regs[15] = 0x80000000; } +enum realview_board_type { + BOARD_EB, + BOARD_EB_MPCORE +}; + static void realview_init(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) + const char *initrd_filename, const char *cpu_model, + enum realview_board_type board_type) { - CPUState *env; + CPUState *env = NULL; ram_addr_t ram_offset; DeviceState *dev; + SysBusDevice *busdev; qemu_irq *irqp; qemu_irq pic[64]; PCIBus *pci_bus; @@ -50,19 +57,10 @@ static void realview_init(ram_addr_t ram_size, int n; int done_smc = 0; qemu_irq cpu_irq[4]; - int ncpu; + int is_mpcore = (board_type == BOARD_EB_MPCORE); uint32_t proc_id = 0; - if (!cpu_model) - cpu_model = "arm926"; - /* FIXME: obey smp_cpus. */ - if (strcmp(cpu_model, "arm11mpcore") == 0) { - ncpu = 4; - } else { - ncpu = 1; - } - - for (n = 0; n < ncpu; n++) { + for (n = 0; n < smp_cpus; n++) { env = cpu_init(cpu_model); if (!env) { fprintf(stderr, "Unable to find CPU definition\n"); @@ -91,15 +89,16 @@ static void realview_init(ram_addr_t ram_size, arm_sysctl_init(0x10000000, 0xc1400400, proc_id); - if (ncpu == 1) { - /* ??? 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. */ - dev = sysbus_create_simple("realview_gic", 0x10040000, cpu_irq[0]); + if (is_mpcore) { + dev = qdev_create(NULL, "realview_mpcore"); + qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + for (n = 0; n < smp_cpus; n++) { + sysbus_connect_irq(busdev, n, cpu_irq[n]); + } } else { - dev = sysbus_create_varargs("realview_mpcore", -1, - cpu_irq[0], cpu_irq[1], cpu_irq[2], - cpu_irq[3], NULL); + dev = sysbus_create_simple("realview_gic", 0x10040000, cpu_irq[0]); } for (n = 0; n < 64; n++) { pic[n] = qdev_get_gpio_in(dev, n); @@ -210,20 +209,53 @@ static void realview_init(ram_addr_t ram_size, realview_binfo.kernel_filename = kernel_filename; realview_binfo.kernel_cmdline = kernel_cmdline; realview_binfo.initrd_filename = initrd_filename; - realview_binfo.nb_cpus = ncpu; + realview_binfo.nb_cpus = smp_cpus; arm_load_kernel(first_cpu, &realview_binfo); } -static QEMUMachine realview_machine = { - .name = "realview", +static void realview_eb_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + if (!cpu_model) { + cpu_model = "arm926"; + } + realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline, + initrd_filename, cpu_model, BOARD_EB); +} + +static void realview_eb_mpcore_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + if (!cpu_model) { + cpu_model = "arm11mpcore"; + } + realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline, + initrd_filename, cpu_model, BOARD_EB_MPCORE); +} + +static QEMUMachine realview_eb_machine = { + .name = "realview-eb", .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)", - .init = realview_init, + .init = realview_eb_init, + .use_scsi = 1, +}; + +static QEMUMachine realview_eb_mpcore_machine = { + .name = "realview-eb-mpcore", + .desc = "ARM RealView Emulation Baseboard (ARM11MPCore)", + .init = realview_eb_mpcore_init, .use_scsi = 1, + .max_cpus = 4, }; static void realview_machine_init(void) { - qemu_register_machine(&realview_machine); + qemu_register_machine(&realview_eb_machine); + qemu_register_machine(&realview_eb_mpcore_machine); } machine_init(realview_machine_init); diff --git a/qemu-doc.texi b/qemu-doc.texi index 7d3240c63a..38dbda7b24 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1663,7 +1663,7 @@ The ARM RealView Emulation baseboard is emulated with the following devices: @itemize @minus @item -ARM926E, ARM1136, ARM11MPCORE(x4) or Cortex-A8 CPU +ARM926E, ARM1136, ARM11MPCORE or Cortex-A8 CPU @item ARM AMBA Generic/Distributed Interrupt Controller @item |