]> git.proxmox.com Git - qemu.git/commitdiff
hw: move boards and other isolated files to hw/ARCH
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 5 Feb 2013 11:03:15 +0000 (12:03 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 1 Mar 2013 14:01:19 +0000 (15:01 +0100)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
154 files changed:
hw/Makefile.objs
hw/alpha/Makefile.objs
hw/alpha/dp264.c [new file with mode: 0644]
hw/alpha/pci.c [new file with mode: 0644]
hw/alpha_dp264.c [deleted file]
hw/alpha_pci.c [deleted file]
hw/an5206.c [deleted file]
hw/arm/Makefile.objs
hw/arm/boot.c [new file with mode: 0644]
hw/arm/collie.c [new file with mode: 0644]
hw/arm/exynos4_boards.c [new file with mode: 0644]
hw/arm/gumstix.c [new file with mode: 0644]
hw/arm/highbank.c [new file with mode: 0644]
hw/arm/integratorcp.c [new file with mode: 0644]
hw/arm/kzm.c [new file with mode: 0644]
hw/arm/mainstone.c [new file with mode: 0644]
hw/arm/musicpal.c [new file with mode: 0644]
hw/arm/nseries.c [new file with mode: 0644]
hw/arm/omap_sx1.c [new file with mode: 0644]
hw/arm/palm.c [new file with mode: 0644]
hw/arm/pic_cpu.c [new file with mode: 0644]
hw/arm/realview.c [new file with mode: 0644]
hw/arm/spitz.c [new file with mode: 0644]
hw/arm/stellaris.c [new file with mode: 0644]
hw/arm/tosa.c [new file with mode: 0644]
hw/arm/versatilepb.c [new file with mode: 0644]
hw/arm/vexpress.c [new file with mode: 0644]
hw/arm/xilinx_zynq.c [new file with mode: 0644]
hw/arm/z2.c [new file with mode: 0644]
hw/arm_boot.c [deleted file]
hw/arm_pic.c [deleted file]
hw/axis_dev88.c [deleted file]
hw/collie.c [deleted file]
hw/cris-boot.c [deleted file]
hw/cris/Makefile.objs
hw/cris/axis_dev88.c [new file with mode: 0644]
hw/cris/boot.c [new file with mode: 0644]
hw/cris/pic_cpu.c [new file with mode: 0644]
hw/cris_pic_cpu.c [deleted file]
hw/dummy_m68k.c [deleted file]
hw/exynos4_boards.c [deleted file]
hw/gumstix.c [deleted file]
hw/highbank.c [deleted file]
hw/i386/Makefile.objs
hw/i386/multiboot.c [new file with mode: 0644]
hw/i386/pc.c [new file with mode: 0644]
hw/i386/pc_piix.c [new file with mode: 0644]
hw/i386/pc_q35.c [new file with mode: 0644]
hw/i386/smbios.c [new file with mode: 0644]
hw/i386/xen_domainbuild.c [new file with mode: 0644]
hw/i386/xen_machine_pv.c [new file with mode: 0644]
hw/integratorcp.c [deleted file]
hw/kzm.c [deleted file]
hw/leon3.c [deleted file]
hw/lm32/Makefile.objs
hw/lm32/lm32_boards.c [new file with mode: 0644]
hw/lm32/milkymist.c [new file with mode: 0644]
hw/lm32_boards.c [deleted file]
hw/m68k/Makefile.objs
hw/m68k/an5206.c [new file with mode: 0644]
hw/m68k/dummy_m68k.c [new file with mode: 0644]
hw/m68k/mcf5208.c [new file with mode: 0644]
hw/mainstone.c [deleted file]
hw/mcf5208.c [deleted file]
hw/microblaze/Makefile.objs
hw/microblaze/boot.c [new file with mode: 0644]
hw/microblaze/petalogix_ml605_mmu.c [new file with mode: 0644]
hw/microblaze/petalogix_s3adsp1800_mmu.c [new file with mode: 0644]
hw/microblaze/pic_cpu.c [new file with mode: 0644]
hw/microblaze_boot.c [deleted file]
hw/microblaze_pic_cpu.c [deleted file]
hw/milkymist.c [deleted file]
hw/mips/Makefile.objs
hw/mips/addr.c [new file with mode: 0644]
hw/mips/cputimer.c [new file with mode: 0644]
hw/mips/mips_fulong2e.c [new file with mode: 0644]
hw/mips/mips_int.c [new file with mode: 0644]
hw/mips/mips_jazz.c [new file with mode: 0644]
hw/mips/mips_malta.c [new file with mode: 0644]
hw/mips/mips_mipssim.c [new file with mode: 0644]
hw/mips/mips_r4k.c [new file with mode: 0644]
hw/mips_addr.c [deleted file]
hw/mips_fulong2e.c [deleted file]
hw/mips_int.c [deleted file]
hw/mips_jazz.c [deleted file]
hw/mips_malta.c [deleted file]
hw/mips_mipssim.c [deleted file]
hw/mips_r4k.c [deleted file]
hw/mips_timer.c [deleted file]
hw/multiboot.c [deleted file]
hw/musicpal.c [deleted file]
hw/nseries.c [deleted file]
hw/omap_sx1.c [deleted file]
hw/openrisc/Makefile.objs
hw/openrisc/cputimer.c [new file with mode: 0644]
hw/openrisc/openrisc_sim.c [new file with mode: 0644]
hw/openrisc/pic_cpu.c [new file with mode: 0644]
hw/openrisc_pic.c [deleted file]
hw/openrisc_sim.c [deleted file]
hw/openrisc_timer.c [deleted file]
hw/palm.c [deleted file]
hw/pc.c [deleted file]
hw/pc_piix.c [deleted file]
hw/pc_q35.c [deleted file]
hw/petalogix_ml605_mmu.c [deleted file]
hw/petalogix_s3adsp1800_mmu.c [deleted file]
hw/ppc.c [deleted file]
hw/ppc/Makefile.objs
hw/ppc/ppc.c [new file with mode: 0644]
hw/ppc/ppc405_boards.c [new file with mode: 0644]
hw/ppc/ppc405_uc.c [new file with mode: 0644]
hw/ppc/ppc440_bamboo.c [new file with mode: 0644]
hw/ppc/ppc_booke.c [new file with mode: 0644]
hw/ppc/spapr.c [new file with mode: 0644]
hw/ppc/virtex_ml507.c [new file with mode: 0644]
hw/ppc405_boards.c [deleted file]
hw/ppc405_uc.c [deleted file]
hw/ppc440_bamboo.c [deleted file]
hw/ppc_booke.c [deleted file]
hw/puv3.c [deleted file]
hw/r2d.c [deleted file]
hw/realview.c [deleted file]
hw/sh4/Makefile.objs
hw/sh4/r2d.c [new file with mode: 0644]
hw/sh4/shix.c [new file with mode: 0644]
hw/shix.c [deleted file]
hw/smbios.c [deleted file]
hw/spapr.c [deleted file]
hw/sparc/Makefile.objs
hw/sparc/leon3.c [new file with mode: 0644]
hw/sparc/sun4m.c [new file with mode: 0644]
hw/sparc64/Makefile.objs
hw/sparc64/sun4u.c [new file with mode: 0644]
hw/spitz.c [deleted file]
hw/stellaris.c [deleted file]
hw/sun4m.c [deleted file]
hw/sun4u.c [deleted file]
hw/tosa.c [deleted file]
hw/unicore32/Makefile.objs
hw/unicore32/puv3.c [new file with mode: 0644]
hw/versatilepb.c [deleted file]
hw/vexpress.c [deleted file]
hw/virtex_ml507.c [deleted file]
hw/xen_domainbuild.c [deleted file]
hw/xen_machine_pv.c [deleted file]
hw/xilinx_zynq.c [deleted file]
hw/xtensa/Makefile.objs
hw/xtensa/pic_cpu.c [new file with mode: 0644]
hw/xtensa/xtensa_lx60.c [new file with mode: 0644]
hw/xtensa/xtensa_sim.c [new file with mode: 0644]
hw/xtensa_lx60.c [deleted file]
hw/xtensa_pic.c [deleted file]
hw/xtensa_sim.c [deleted file]
hw/z2.c [deleted file]

index 43f467a1eecb9be3ee75aa54306b1abd7a7392a4..eb7eb31a198eb707ca61c1061216927faea93625 100644 (file)
@@ -206,7 +206,6 @@ obj-$(CONFIG_SOFTMMU) += vhost_net.o
 obj-$(CONFIG_VHOST_NET) += vhost.o
 obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/
 obj-$(CONFIG_VGA) += vga.o
-obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o
 
 # Inter-VM PCI shared memory & VFIO PCI device assignment
 ifeq ($(CONFIG_PCI), y)
index af1c07fa7c9dc42056ea5453c045476c699ce82d..db868d2ea69fc64be34f58127b82994729ed6d7b 100644 (file)
@@ -1,4 +1,6 @@
 obj-y = mc146818rtc.o
-obj-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
+obj-y += alpha_typhoon.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-y += dp264.o pci.o
diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c
new file mode 100644 (file)
index 0000000..13aaa57
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * QEMU Alpha DP264/CLIPPER hardware system emulator.
+ *
+ * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK
+ * variants because CLIPPER doesn't have an SMC669 SuperIO controller
+ * that we need to emulate as well.
+ */
+
+#include "hw/hw.h"
+#include "elf.h"
+#include "hw/loader.h"
+#include "hw/boards.h"
+#include "hw/alpha_sys.h"
+#include "sysemu/sysemu.h"
+#include "hw/mc146818rtc.h"
+#include "hw/ide.h"
+#include "hw/i8254.h"
+#include "hw/serial.h"
+
+#define MAX_IDE_BUS 2
+
+static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
+{
+    if (((addr >> 41) & 3) == 2) {
+        addr &= 0xffffffffffull;
+    }
+    return addr;
+}
+
+/* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
+    (0) The dev_irq_n lines into the cpu, which we totally ignore,
+    (1) The DRIR lines in the typhoon chipset,
+    (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
+    (3) The interrupt number assigned by the kernel.
+   The following function is concerned with (1) only.  */
+
+static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
+{
+    int slot = d->devfn >> 3;
+
+    assert(irq_num >= 0 && irq_num <= 3);
+
+    return (slot + 1) * 4 + irq_num;
+}
+
+static void clipper_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    AlphaCPU *cpus[4];
+    PCIBus *pci_bus;
+    ISABus *isa_bus;
+    qemu_irq rtc_irq;
+    long size, i;
+    const char *palcode_filename;
+    uint64_t palcode_entry, palcode_low, palcode_high;
+    uint64_t kernel_entry, kernel_low, kernel_high;
+
+    /* Create up to 4 cpus.  */
+    memset(cpus, 0, sizeof(cpus));
+    for (i = 0; i < smp_cpus; ++i) {
+        cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67");
+    }
+
+    cpus[0]->env.trap_arg0 = ram_size;
+    cpus[0]->env.trap_arg1 = 0;
+    cpus[0]->env.trap_arg2 = smp_cpus;
+
+    /* Init the chipset.  */
+    pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus,
+                           clipper_pci_map_irq);
+
+    rtc_init(isa_bus, 1980, rtc_irq);
+    pit_init(isa_bus, 0x40, 0, NULL);
+    isa_create_simple(isa_bus, "i8042");
+
+    /* VGA setup.  Don't bother loading the bios.  */
+    pci_vga_init(pci_bus);
+
+    /* Serial code setup.  */
+    for (i = 0; i < MAX_SERIAL_PORTS; ++i) {
+        if (serial_hds[i]) {
+            serial_isa_init(isa_bus, i, serial_hds[i]);
+        }
+    }
+
+    /* Network setup.  e1000 is good enough, failing Tulip support.  */
+    for (i = 0; i < nb_nics; i++) {
+        pci_nic_init_nofail(&nd_table[i], "e1000", NULL);
+    }
+
+    /* IDE disk setup.  */
+    {
+        DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+        ide_drive_get(hd, MAX_IDE_BUS);
+
+        pci_cmd646_ide_init(pci_bus, hd, 0);
+    }
+
+    /* Load PALcode.  Given that this is not "real" cpu palcode,
+       but one explicitly written for the emulation, we might as
+       well load it directly from and ELF image.  */
+    palcode_filename = (bios_name ? bios_name : "palcode-clipper");
+    palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename);
+    if (palcode_filename == NULL) {
+        hw_error("no palcode provided\n");
+        exit(1);
+    }
+    size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys,
+                    NULL, &palcode_entry, &palcode_low, &palcode_high,
+                    0, EM_ALPHA, 0);
+    if (size < 0) {
+        hw_error("could not load palcode '%s'\n", palcode_filename);
+        exit(1);
+    }
+
+    /* Start all cpus at the PALcode RESET entry point.  */
+    for (i = 0; i < smp_cpus; ++i) {
+        cpus[i]->env.pal_mode = 1;
+        cpus[i]->env.pc = palcode_entry;
+        cpus[i]->env.palbr = palcode_entry;
+    }
+
+    /* Load a kernel.  */
+    if (kernel_filename) {
+        uint64_t param_offset;
+
+        size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
+                        NULL, &kernel_entry, &kernel_low, &kernel_high,
+                        0, EM_ALPHA, 0);
+        if (size < 0) {
+            hw_error("could not load kernel '%s'\n", kernel_filename);
+            exit(1);
+        }
+
+        cpus[0]->env.trap_arg1 = kernel_entry;
+
+        param_offset = kernel_low - 0x6000;
+
+        if (kernel_cmdline) {
+            pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
+        }
+
+        if (initrd_filename) {
+            long initrd_base, initrd_size;
+
+            initrd_size = get_image_size(initrd_filename);
+            if (initrd_size < 0) {
+                hw_error("could not load initial ram disk '%s'\n",
+                         initrd_filename);
+                exit(1);
+            }
+
+            /* Put the initrd image as high in memory as possible.  */
+            initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
+            load_image_targphys(initrd_filename, initrd_base,
+                                ram_size - initrd_base);
+
+            stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL);
+            stq_phys(param_offset + 0x108, initrd_size);
+        }
+    }
+}
+
+static QEMUMachine clipper_machine = {
+    .name = "clipper",
+    .desc = "Alpha DP264/CLIPPER",
+    .init = clipper_init,
+    .max_cpus = 4,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void clipper_machine_init(void)
+{
+    qemu_register_machine(&clipper_machine);
+}
+
+machine_init(clipper_machine_init);
diff --git a/hw/alpha/pci.c b/hw/alpha/pci.c
new file mode 100644 (file)
index 0000000..8462868
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * QEMU Alpha PCI support functions.
+ *
+ * Some of this isn't very Alpha specific at all.
+ *
+ * ??? Sparse memory access not implemented.
+ */
+
+#include "config.h"
+#include "hw/alpha_sys.h"
+#include "qemu/log.h"
+#include "sysemu/sysemu.h"
+
+
+/* PCI IO reads/writes, to byte-word addressable memory.  */
+/* ??? Doesn't handle multiple PCI busses.  */
+
+static uint64_t bw_io_read(void *opaque, hwaddr addr, unsigned size)
+{
+    switch (size) {
+    case 1:
+        return cpu_inb(addr);
+    case 2:
+        return cpu_inw(addr);
+    case 4:
+        return cpu_inl(addr);
+    }
+    abort();
+}
+
+static void bw_io_write(void *opaque, hwaddr addr,
+                        uint64_t val, unsigned size)
+{
+    switch (size) {
+    case 1:
+        cpu_outb(addr, val);
+        break;
+    case 2:
+        cpu_outw(addr, val);
+        break;
+    case 4:
+        cpu_outl(addr, val);
+        break;
+    default:
+        abort();
+    }
+}
+
+const MemoryRegionOps alpha_pci_bw_io_ops = {
+    .read = bw_io_read,
+    .write = bw_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+/* PCI config space reads/writes, to byte-word addressable memory.  */
+static uint64_t bw_conf1_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    PCIBus *b = opaque;
+    return pci_data_read(b, addr, size);
+}
+
+static void bw_conf1_write(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned size)
+{
+    PCIBus *b = opaque;
+    pci_data_write(b, addr, val, size);
+}
+
+const MemoryRegionOps alpha_pci_conf1_ops = {
+    .read = bw_conf1_read,
+    .write = bw_conf1_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+/* PCI/EISA Interrupt Acknowledge Cycle.  */
+
+static uint64_t iack_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return pic_read_irq(isa_pic);
+}
+
+static void special_write(void *opaque, hwaddr addr,
+                          uint64_t val, unsigned size)
+{
+    qemu_log("pci: special write cycle");
+}
+
+const MemoryRegionOps alpha_pci_iack_ops = {
+    .read = iack_read,
+    .write = special_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c
deleted file mode 100644 (file)
index 13aaa57..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * QEMU Alpha DP264/CLIPPER hardware system emulator.
- *
- * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK
- * variants because CLIPPER doesn't have an SMC669 SuperIO controller
- * that we need to emulate as well.
- */
-
-#include "hw/hw.h"
-#include "elf.h"
-#include "hw/loader.h"
-#include "hw/boards.h"
-#include "hw/alpha_sys.h"
-#include "sysemu/sysemu.h"
-#include "hw/mc146818rtc.h"
-#include "hw/ide.h"
-#include "hw/i8254.h"
-#include "hw/serial.h"
-
-#define MAX_IDE_BUS 2
-
-static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
-{
-    if (((addr >> 41) & 3) == 2) {
-        addr &= 0xffffffffffull;
-    }
-    return addr;
-}
-
-/* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
-    (0) The dev_irq_n lines into the cpu, which we totally ignore,
-    (1) The DRIR lines in the typhoon chipset,
-    (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
-    (3) The interrupt number assigned by the kernel.
-   The following function is concerned with (1) only.  */
-
-static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
-{
-    int slot = d->devfn >> 3;
-
-    assert(irq_num >= 0 && irq_num <= 3);
-
-    return (slot + 1) * 4 + irq_num;
-}
-
-static void clipper_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    AlphaCPU *cpus[4];
-    PCIBus *pci_bus;
-    ISABus *isa_bus;
-    qemu_irq rtc_irq;
-    long size, i;
-    const char *palcode_filename;
-    uint64_t palcode_entry, palcode_low, palcode_high;
-    uint64_t kernel_entry, kernel_low, kernel_high;
-
-    /* Create up to 4 cpus.  */
-    memset(cpus, 0, sizeof(cpus));
-    for (i = 0; i < smp_cpus; ++i) {
-        cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67");
-    }
-
-    cpus[0]->env.trap_arg0 = ram_size;
-    cpus[0]->env.trap_arg1 = 0;
-    cpus[0]->env.trap_arg2 = smp_cpus;
-
-    /* Init the chipset.  */
-    pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus,
-                           clipper_pci_map_irq);
-
-    rtc_init(isa_bus, 1980, rtc_irq);
-    pit_init(isa_bus, 0x40, 0, NULL);
-    isa_create_simple(isa_bus, "i8042");
-
-    /* VGA setup.  Don't bother loading the bios.  */
-    pci_vga_init(pci_bus);
-
-    /* Serial code setup.  */
-    for (i = 0; i < MAX_SERIAL_PORTS; ++i) {
-        if (serial_hds[i]) {
-            serial_isa_init(isa_bus, i, serial_hds[i]);
-        }
-    }
-
-    /* Network setup.  e1000 is good enough, failing Tulip support.  */
-    for (i = 0; i < nb_nics; i++) {
-        pci_nic_init_nofail(&nd_table[i], "e1000", NULL);
-    }
-
-    /* IDE disk setup.  */
-    {
-        DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
-        ide_drive_get(hd, MAX_IDE_BUS);
-
-        pci_cmd646_ide_init(pci_bus, hd, 0);
-    }
-
-    /* Load PALcode.  Given that this is not "real" cpu palcode,
-       but one explicitly written for the emulation, we might as
-       well load it directly from and ELF image.  */
-    palcode_filename = (bios_name ? bios_name : "palcode-clipper");
-    palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename);
-    if (palcode_filename == NULL) {
-        hw_error("no palcode provided\n");
-        exit(1);
-    }
-    size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys,
-                    NULL, &palcode_entry, &palcode_low, &palcode_high,
-                    0, EM_ALPHA, 0);
-    if (size < 0) {
-        hw_error("could not load palcode '%s'\n", palcode_filename);
-        exit(1);
-    }
-
-    /* Start all cpus at the PALcode RESET entry point.  */
-    for (i = 0; i < smp_cpus; ++i) {
-        cpus[i]->env.pal_mode = 1;
-        cpus[i]->env.pc = palcode_entry;
-        cpus[i]->env.palbr = palcode_entry;
-    }
-
-    /* Load a kernel.  */
-    if (kernel_filename) {
-        uint64_t param_offset;
-
-        size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
-                        NULL, &kernel_entry, &kernel_low, &kernel_high,
-                        0, EM_ALPHA, 0);
-        if (size < 0) {
-            hw_error("could not load kernel '%s'\n", kernel_filename);
-            exit(1);
-        }
-
-        cpus[0]->env.trap_arg1 = kernel_entry;
-
-        param_offset = kernel_low - 0x6000;
-
-        if (kernel_cmdline) {
-            pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
-        }
-
-        if (initrd_filename) {
-            long initrd_base, initrd_size;
-
-            initrd_size = get_image_size(initrd_filename);
-            if (initrd_size < 0) {
-                hw_error("could not load initial ram disk '%s'\n",
-                         initrd_filename);
-                exit(1);
-            }
-
-            /* Put the initrd image as high in memory as possible.  */
-            initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
-            load_image_targphys(initrd_filename, initrd_base,
-                                ram_size - initrd_base);
-
-            stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL);
-            stq_phys(param_offset + 0x108, initrd_size);
-        }
-    }
-}
-
-static QEMUMachine clipper_machine = {
-    .name = "clipper",
-    .desc = "Alpha DP264/CLIPPER",
-    .init = clipper_init,
-    .max_cpus = 4,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void clipper_machine_init(void)
-{
-    qemu_register_machine(&clipper_machine);
-}
-
-machine_init(clipper_machine_init);
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
deleted file mode 100644 (file)
index 8462868..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * QEMU Alpha PCI support functions.
- *
- * Some of this isn't very Alpha specific at all.
- *
- * ??? Sparse memory access not implemented.
- */
-
-#include "config.h"
-#include "hw/alpha_sys.h"
-#include "qemu/log.h"
-#include "sysemu/sysemu.h"
-
-
-/* PCI IO reads/writes, to byte-word addressable memory.  */
-/* ??? Doesn't handle multiple PCI busses.  */
-
-static uint64_t bw_io_read(void *opaque, hwaddr addr, unsigned size)
-{
-    switch (size) {
-    case 1:
-        return cpu_inb(addr);
-    case 2:
-        return cpu_inw(addr);
-    case 4:
-        return cpu_inl(addr);
-    }
-    abort();
-}
-
-static void bw_io_write(void *opaque, hwaddr addr,
-                        uint64_t val, unsigned size)
-{
-    switch (size) {
-    case 1:
-        cpu_outb(addr, val);
-        break;
-    case 2:
-        cpu_outw(addr, val);
-        break;
-    case 4:
-        cpu_outl(addr, val);
-        break;
-    default:
-        abort();
-    }
-}
-
-const MemoryRegionOps alpha_pci_bw_io_ops = {
-    .read = bw_io_read,
-    .write = bw_io_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-    },
-};
-
-/* PCI config space reads/writes, to byte-word addressable memory.  */
-static uint64_t bw_conf1_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    PCIBus *b = opaque;
-    return pci_data_read(b, addr, size);
-}
-
-static void bw_conf1_write(void *opaque, hwaddr addr,
-                           uint64_t val, unsigned size)
-{
-    PCIBus *b = opaque;
-    pci_data_write(b, addr, val, size);
-}
-
-const MemoryRegionOps alpha_pci_conf1_ops = {
-    .read = bw_conf1_read,
-    .write = bw_conf1_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-    },
-};
-
-/* PCI/EISA Interrupt Acknowledge Cycle.  */
-
-static uint64_t iack_read(void *opaque, hwaddr addr, unsigned size)
-{
-    return pic_read_irq(isa_pic);
-}
-
-static void special_write(void *opaque, hwaddr addr,
-                          uint64_t val, unsigned size)
-{
-    qemu_log("pci: special write cycle");
-}
-
-const MemoryRegionOps alpha_pci_iack_ops = {
-    .read = iack_read,
-    .write = special_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
diff --git a/hw/an5206.c b/hw/an5206.c
deleted file mode 100644 (file)
index 7c21c66..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Arnewsh 5206 ColdFire system emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-
-#include "hw/hw.h"
-#include "hw/mcf.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-
-#define KERNEL_LOAD_ADDR 0x10000
-#define AN5206_MBAR_ADDR 0x10000000
-#define AN5206_RAMBAR_ADDR 0x20000000
-
-/* Board init.  */
-
-static void an5206_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    M68kCPU *cpu;
-    CPUM68KState *env;
-    int kernel_size;
-    uint64_t elf_entry;
-    hwaddr entry;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *sram = g_new(MemoryRegion, 1);
-
-    if (!cpu_model) {
-        cpu_model = "m5206";
-    }
-    cpu = cpu_m68k_init(cpu_model);
-    if (!cpu) {
-        hw_error("Unable to find m68k CPU definition\n");
-    }
-    env = &cpu->env;
-
-    /* Initialize CPU registers.  */
-    env->vbr = 0;
-    /* TODO: allow changing MBAR and RAMBAR.  */
-    env->mbar = AN5206_MBAR_ADDR | 1;
-    env->rambar0 = AN5206_RAMBAR_ADDR | 1;
-
-    /* DRAM at address zero */
-    memory_region_init_ram(ram, "an5206.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(address_space_mem, 0, ram);
-
-    /* Internal SRAM.  */
-    memory_region_init_ram(sram, "an5206.sram", 512);
-    vmstate_register_ram_global(sram);
-    memory_region_add_subregion(address_space_mem, AN5206_RAMBAR_ADDR, sram);
-
-    mcf5206_init(address_space_mem, AN5206_MBAR_ADDR, cpu);
-
-    /* Load kernel.  */
-    if (!kernel_filename) {
-        fprintf(stderr, "Kernel image must be specified\n");
-        exit(1);
-    }
-
-    kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
-                           NULL, NULL, 1, ELF_MACHINE, 0);
-    entry = elf_entry;
-    if (kernel_size < 0) {
-        kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
-    }
-    if (kernel_size < 0) {
-        kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
-                                          ram_size - KERNEL_LOAD_ADDR);
-        entry = KERNEL_LOAD_ADDR;
-    }
-    if (kernel_size < 0) {
-        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
-        exit(1);
-    }
-
-    env->pc = entry;
-}
-
-static QEMUMachine an5206_machine = {
-    .name = "an5206",
-    .desc = "Arnewsh 5206",
-    .init = an5206_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void an5206_machine_init(void)
-{
-    qemu_register_machine(&an5206_machine);
-}
-
-machine_init(an5206_machine_init);
index 3eb1366aeeb0615f3d4e2d7feef731d1d4e301e6..c09cc3aae84f0a7796eb9f69a4f571d8c72e24a5 100644 (file)
@@ -1,35 +1,32 @@
-obj-y = integratorcp.o versatilepb.o arm_pic.o
-obj-y += arm_boot.o
-obj-y += xilinx_zynq.o zynq_slcr.o
+obj-y += zynq_slcr.o
 obj-y += xilinx_spips.o
 obj-y += arm_gic.o arm_gic_common.o
 obj-y += a9scu.o
-obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
+obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
-obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
+obj-y += exynos4210_uart.o exynos4210_pwm.o
 obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
 obj-y += exynos4210_rtc.o exynos4210_i2c.o
 obj-y += arm_mptimer.o a15mpcore.o
-obj-y += armv7m.o armv7m_nvic.o stellaris.o stellaris_enet.o
-obj-y += highbank.o
+obj-y += armv7m.o armv7m_nvic.o stellaris_enet.o
 obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
 obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
-obj-y += gumstix.o
-obj-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o
+obj-y += zaurus.o ide/microdrive.o tc6393xb.o
 obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
                 omap_gpio.o omap_intc.o omap_uart.o
 obj-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
                 omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
-obj-y += omap_sx1.o palm.o tsc210x.o
-obj-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o
-obj-y += mst_fpga.o mainstone.o
-obj-y += z2.o
-obj-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
+obj-y += tsc210x.o
+obj-y += blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o
+obj-y += mst_fpga.o
+obj-y += bitbang_i2c.o marvell_88w8618_audio.o
 obj-y += framebuffer.o
-obj-y += vexpress.o
 obj-y += strongarm.o
-obj-y += collie.o
 obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
-obj-y += kzm.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
+obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
+obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o
+obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
new file mode 100644 (file)
index 0000000..43253fd
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * ARM kernel loader.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "config.h"
+#include "hw/hw.h"
+#include "hw/arm-misc.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "sysemu/device_tree.h"
+#include "qemu/config-file.h"
+
+#define KERNEL_ARGS_ADDR 0x100
+#define KERNEL_LOAD_ADDR 0x00010000
+
+/* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
+static uint32_t bootloader[] = {
+  0xe3a00000, /* mov     r0, #0 */
+  0xe59f1004, /* ldr     r1, [pc, #4] */
+  0xe59f2004, /* ldr     r2, [pc, #4] */
+  0xe59ff004, /* ldr     pc, [pc, #4] */
+  0, /* Board ID */
+  0, /* Address of kernel args.  Set by integratorcp_init.  */
+  0  /* Kernel entry point.  Set by integratorcp_init.  */
+};
+
+/* Handling for secondary CPU boot in a multicore system.
+ * Unlike the uniprocessor/primary CPU boot, this is platform
+ * dependent. The default code here is based on the secondary
+ * CPU boot protocol used on realview/vexpress boards, with
+ * some parameterisation to increase its flexibility.
+ * QEMU platform models for which this code is not appropriate
+ * should override write_secondary_boot and secondary_cpu_reset_hook
+ * instead.
+ *
+ * This code enables the interrupt controllers for the secondary
+ * CPUs and then puts all the secondary CPUs into a loop waiting
+ * for an interprocessor interrupt and polling a configurable
+ * location for the kernel secondary CPU entry point.
+ */
+#define DSB_INSN 0xf57ff04f
+#define CP15_DSB_INSN 0xee070f9a /* mcr cp15, 0, r0, c7, c10, 4 */
+
+static uint32_t smpboot[] = {
+  0xe59f2028, /* ldr r2, gic_cpu_if */
+  0xe59f0028, /* ldr r0, startaddr */
+  0xe3a01001, /* mov r1, #1 */
+  0xe5821000, /* str r1, [r2] - set GICC_CTLR.Enable */
+  0xe3a010ff, /* mov r1, #0xff */
+  0xe5821004, /* str r1, [r2, 4] - set GIC_PMR.Priority to 0xff */
+  DSB_INSN,   /* dsb */
+  0xe320f003, /* wfi */
+  0xe5901000, /* ldr     r1, [r0] */
+  0xe1110001, /* tst     r1, r1 */
+  0x0afffffb, /* beq     <wfi> */
+  0xe12fff11, /* bx      r1 */
+  0,          /* gic_cpu_if: base address of GIC CPU interface */
+  0           /* bootreg: Boot register address is held here */
+};
+
+static void default_write_secondary(ARMCPU *cpu,
+                                    const struct arm_boot_info *info)
+{
+    int n;
+    smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
+    smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
+    for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+        /* Replace DSB with the pre-v7 DSB if necessary. */
+        if (!arm_feature(&cpu->env, ARM_FEATURE_V7) &&
+            smpboot[n] == DSB_INSN) {
+            smpboot[n] = CP15_DSB_INSN;
+        }
+        smpboot[n] = tswap32(smpboot[n]);
+    }
+    rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
+                       info->smp_loader_start);
+}
+
+static void default_reset_secondary(ARMCPU *cpu,
+                                    const struct arm_boot_info *info)
+{
+    CPUARMState *env = &cpu->env;
+
+    stl_phys_notdirty(info->smp_bootreg_addr, 0);
+    env->regs[15] = info->smp_loader_start;
+}
+
+#define WRITE_WORD(p, value) do { \
+    stl_phys_notdirty(p, value);  \
+    p += 4;                       \
+} while (0)
+
+static void set_kernel_args(const struct arm_boot_info *info)
+{
+    int initrd_size = info->initrd_size;
+    hwaddr base = info->loader_start;
+    hwaddr p;
+
+    p = base + KERNEL_ARGS_ADDR;
+    /* ATAG_CORE */
+    WRITE_WORD(p, 5);
+    WRITE_WORD(p, 0x54410001);
+    WRITE_WORD(p, 1);
+    WRITE_WORD(p, 0x1000);
+    WRITE_WORD(p, 0);
+    /* ATAG_MEM */
+    /* TODO: handle multiple chips on one ATAG list */
+    WRITE_WORD(p, 4);
+    WRITE_WORD(p, 0x54410002);
+    WRITE_WORD(p, info->ram_size);
+    WRITE_WORD(p, info->loader_start);
+    if (initrd_size) {
+        /* ATAG_INITRD2 */
+        WRITE_WORD(p, 4);
+        WRITE_WORD(p, 0x54420005);
+        WRITE_WORD(p, info->initrd_start);
+        WRITE_WORD(p, initrd_size);
+    }
+    if (info->kernel_cmdline && *info->kernel_cmdline) {
+        /* ATAG_CMDLINE */
+        int cmdline_size;
+
+        cmdline_size = strlen(info->kernel_cmdline);
+        cpu_physical_memory_write(p + 8, (void *)info->kernel_cmdline,
+                                  cmdline_size + 1);
+        cmdline_size = (cmdline_size >> 2) + 1;
+        WRITE_WORD(p, cmdline_size + 2);
+        WRITE_WORD(p, 0x54410009);
+        p += cmdline_size * 4;
+    }
+    if (info->atag_board) {
+        /* ATAG_BOARD */
+        int atag_board_len;
+        uint8_t atag_board_buf[0x1000];
+
+        atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3;
+        WRITE_WORD(p, (atag_board_len + 8) >> 2);
+        WRITE_WORD(p, 0x414f4d50);
+        cpu_physical_memory_write(p, atag_board_buf, atag_board_len);
+        p += atag_board_len;
+    }
+    /* ATAG_END */
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
+}
+
+static void set_kernel_args_old(const struct arm_boot_info *info)
+{
+    hwaddr p;
+    const char *s;
+    int initrd_size = info->initrd_size;
+    hwaddr base = info->loader_start;
+
+    /* see linux/include/asm-arm/setup.h */
+    p = base + KERNEL_ARGS_ADDR;
+    /* page_size */
+    WRITE_WORD(p, 4096);
+    /* nr_pages */
+    WRITE_WORD(p, info->ram_size / 4096);
+    /* ramdisk_size */
+    WRITE_WORD(p, 0);
+#define FLAG_READONLY  1
+#define FLAG_RDLOAD    4
+#define FLAG_RDPROMPT  8
+    /* flags */
+    WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
+    /* rootdev */
+    WRITE_WORD(p, (31 << 8) | 0);      /* /dev/mtdblock0 */
+    /* video_num_cols */
+    WRITE_WORD(p, 0);
+    /* video_num_rows */
+    WRITE_WORD(p, 0);
+    /* video_x */
+    WRITE_WORD(p, 0);
+    /* video_y */
+    WRITE_WORD(p, 0);
+    /* memc_control_reg */
+    WRITE_WORD(p, 0);
+    /* unsigned char sounddefault */
+    /* unsigned char adfsdrives */
+    /* unsigned char bytes_per_char_h */
+    /* unsigned char bytes_per_char_v */
+    WRITE_WORD(p, 0);
+    /* pages_in_bank[4] */
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
+    /* pages_in_vram */
+    WRITE_WORD(p, 0);
+    /* initrd_start */
+    if (initrd_size) {
+        WRITE_WORD(p, info->initrd_start);
+    } else {
+        WRITE_WORD(p, 0);
+    }
+    /* initrd_size */
+    WRITE_WORD(p, initrd_size);
+    /* rd_start */
+    WRITE_WORD(p, 0);
+    /* system_rev */
+    WRITE_WORD(p, 0);
+    /* system_serial_low */
+    WRITE_WORD(p, 0);
+    /* system_serial_high */
+    WRITE_WORD(p, 0);
+    /* mem_fclk_21285 */
+    WRITE_WORD(p, 0);
+    /* zero unused fields */
+    while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) {
+        WRITE_WORD(p, 0);
+    }
+    s = info->kernel_cmdline;
+    if (s) {
+        cpu_physical_memory_write(p, (void *)s, strlen(s) + 1);
+    } else {
+        WRITE_WORD(p, 0);
+    }
+}
+
+static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
+{
+#ifdef CONFIG_FDT
+    uint32_t *mem_reg_property;
+    uint32_t mem_reg_propsize;
+    void *fdt = NULL;
+    char *filename;
+    int size, rc;
+    uint32_t acells, scells, hival;
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename);
+    if (!filename) {
+        fprintf(stderr, "Couldn't open dtb file %s\n", binfo->dtb_filename);
+        return -1;
+    }
+
+    fdt = load_device_tree(filename, &size);
+    if (!fdt) {
+        fprintf(stderr, "Couldn't open dtb file %s\n", filename);
+        g_free(filename);
+        return -1;
+    }
+    g_free(filename);
+
+    acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells");
+    scells = qemu_devtree_getprop_cell(fdt, "/", "#size-cells");
+    if (acells == 0 || scells == 0) {
+        fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n");
+        return -1;
+    }
+
+    mem_reg_propsize = acells + scells;
+    mem_reg_property = g_new0(uint32_t, mem_reg_propsize);
+    mem_reg_property[acells - 1] = cpu_to_be32(binfo->loader_start);
+    hival = cpu_to_be32(binfo->loader_start >> 32);
+    if (acells > 1) {
+        mem_reg_property[acells - 2] = hival;
+    } else if (hival != 0) {
+        fprintf(stderr, "qemu: dtb file not compatible with "
+                "RAM start address > 4GB\n");
+        exit(1);
+    }
+    mem_reg_property[acells + scells - 1] = cpu_to_be32(binfo->ram_size);
+    hival = cpu_to_be32(binfo->ram_size >> 32);
+    if (scells > 1) {
+        mem_reg_property[acells + scells - 2] = hival;
+    } else if (hival != 0) {
+        fprintf(stderr, "qemu: dtb file not compatible with "
+                "RAM size > 4GB\n");
+        exit(1);
+    }
+
+    rc = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
+                              mem_reg_propsize * sizeof(uint32_t));
+    if (rc < 0) {
+        fprintf(stderr, "couldn't set /memory/reg\n");
+    }
+
+    if (binfo->kernel_cmdline && *binfo->kernel_cmdline) {
+        rc = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
+                                          binfo->kernel_cmdline);
+        if (rc < 0) {
+            fprintf(stderr, "couldn't set /chosen/bootargs\n");
+        }
+    }
+
+    if (binfo->initrd_size) {
+        rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+                binfo->initrd_start);
+        if (rc < 0) {
+            fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
+        }
+
+        rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+                    binfo->initrd_start + binfo->initrd_size);
+        if (rc < 0) {
+            fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
+        }
+    }
+
+    cpu_physical_memory_write(addr, fdt, size);
+
+    return 0;
+
+#else
+    fprintf(stderr, "Device tree requested, "
+                "but qemu was compiled without fdt support\n");
+    return -1;
+#endif
+}
+
+static void do_cpu_reset(void *opaque)
+{
+    ARMCPU *cpu = opaque;
+    CPUARMState *env = &cpu->env;
+    const struct arm_boot_info *info = env->boot_info;
+
+    cpu_reset(CPU(cpu));
+    if (info) {
+        if (!info->is_linux) {
+            /* Jump to the entry point.  */
+            env->regs[15] = info->entry & 0xfffffffe;
+            env->thumb = info->entry & 1;
+        } else {
+            if (env == first_cpu) {
+                env->regs[15] = info->loader_start;
+                if (!info->dtb_filename) {
+                    if (old_param) {
+                        set_kernel_args_old(info);
+                    } else {
+                        set_kernel_args(info);
+                    }
+                }
+            } else {
+                info->secondary_cpu_reset_hook(cpu, info);
+            }
+        }
+    }
+}
+
+void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
+{
+    CPUARMState *env = &cpu->env;
+    int kernel_size;
+    int initrd_size;
+    int n;
+    int is_linux = 0;
+    uint64_t elf_entry;
+    hwaddr entry;
+    int big_endian;
+    QemuOpts *machine_opts;
+
+    /* Load the kernel.  */
+    if (!info->kernel_filename) {
+        fprintf(stderr, "Kernel image must be specified\n");
+        exit(1);
+    }
+
+    machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+    if (machine_opts) {
+        info->dtb_filename = qemu_opt_get(machine_opts, "dtb");
+    } else {
+        info->dtb_filename = NULL;
+    }
+
+    if (!info->secondary_cpu_reset_hook) {
+        info->secondary_cpu_reset_hook = default_reset_secondary;
+    }
+    if (!info->write_secondary_boot) {
+        info->write_secondary_boot = default_write_secondary;
+    }
+
+    if (info->nb_cpus == 0)
+        info->nb_cpus = 1;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+
+    /* We want to put the initrd far enough into RAM that when the
+     * kernel is uncompressed it will not clobber the initrd. However
+     * on boards without much RAM we must ensure that we still leave
+     * enough room for a decent sized initrd, and on boards with large
+     * amounts of RAM we must avoid the initrd being so far up in RAM
+     * that it is outside lowmem and inaccessible to the kernel.
+     * So for boards with less  than 256MB of RAM we put the initrd
+     * halfway into RAM, and for boards with 256MB of RAM or more we put
+     * the initrd at 128MB.
+     */
+    info->initrd_start = info->loader_start +
+        MIN(info->ram_size / 2, 128 * 1024 * 1024);
+
+    /* Assume that raw images are linux kernels, and ELF images are not.  */
+    kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry,
+                           NULL, NULL, big_endian, ELF_MACHINE, 1);
+    entry = elf_entry;
+    if (kernel_size < 0) {
+        kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
+                                  &is_linux);
+    }
+    if (kernel_size < 0) {
+        entry = info->loader_start + KERNEL_LOAD_ADDR;
+        kernel_size = load_image_targphys(info->kernel_filename, entry,
+                                          info->ram_size - KERNEL_LOAD_ADDR);
+        is_linux = 1;
+    }
+    if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                info->kernel_filename);
+        exit(1);
+    }
+    info->entry = entry;
+    if (is_linux) {
+        if (info->initrd_filename) {
+            initrd_size = load_image_targphys(info->initrd_filename,
+                                              info->initrd_start,
+                                              info->ram_size -
+                                              info->initrd_start);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initrd '%s'\n",
+                        info->initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_size = 0;
+        }
+        info->initrd_size = initrd_size;
+
+        bootloader[4] = info->board_id;
+
+        /* for device tree boot, we pass the DTB directly in r2. Otherwise
+         * we point to the kernel args.
+         */
+        if (info->dtb_filename) {
+            /* Place the DTB after the initrd in memory. Note that some
+             * kernels will trash anything in the 4K page the initrd
+             * ends in, so make sure the DTB isn't caught up in that.
+             */
+            hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size,
+                                             4096);
+            if (load_dtb(dtb_start, info)) {
+                exit(1);
+            }
+            bootloader[5] = dtb_start;
+        } else {
+            bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
+            if (info->ram_size >= (1ULL << 32)) {
+                fprintf(stderr, "qemu: RAM size must be less than 4GB to boot"
+                        " Linux kernel using ATAGS (try passing a device tree"
+                        " using -dtb)\n");
+                exit(1);
+            }
+        }
+        bootloader[6] = entry;
+        for (n = 0; n < sizeof(bootloader) / 4; n++) {
+            bootloader[n] = tswap32(bootloader[n]);
+        }
+        rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader),
+                           info->loader_start);
+        if (info->nb_cpus > 1) {
+            info->write_secondary_boot(cpu, info);
+        }
+    }
+    info->is_linux = is_linux;
+
+    for (; env; env = env->next_cpu) {
+        cpu = arm_env_get_cpu(env);
+        env->boot_info = info;
+        qemu_register_reset(do_cpu_reset, cpu);
+    }
+}
diff --git a/hw/arm/collie.c b/hw/arm/collie.c
new file mode 100644 (file)
index 0000000..17fddc8
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * SA-1110-based Sharp Zaurus SL-5500 platform.
+ *
+ * Copyright (C) 2011 Dmitry Eremin-Solenikov
+ *
+ * This code is licensed under GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/boards.h"
+#include "hw/devices.h"
+#include "hw/strongarm.h"
+#include "hw/arm-misc.h"
+#include "hw/flash.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+static struct arm_boot_info collie_binfo = {
+    .loader_start = SA_SDCS0,
+    .ram_size = 0x20000000,
+};
+
+static void collie_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    StrongARMState *s;
+    DriveInfo *dinfo;
+    MemoryRegion *sysmem = get_system_memory();
+
+    if (!cpu_model) {
+        cpu_model = "sa1110";
+    }
+
+    s = sa1110_init(sysmem, collie_binfo.ram_size, cpu_model);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000,
+                    dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                    512, 4, 0x00, 0x00, 0x00, 0x00, 0);
+
+    dinfo = drive_get(IF_PFLASH, 0, 1);
+    pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000,
+                    dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                    512, 4, 0x00, 0x00, 0x00, 0x00, 0);
+
+    sysbus_create_simple("scoop", 0x40800000, NULL);
+
+    collie_binfo.kernel_filename = kernel_filename;
+    collie_binfo.kernel_cmdline = kernel_cmdline;
+    collie_binfo.initrd_filename = initrd_filename;
+    collie_binfo.board_id = 0x208;
+    arm_load_kernel(s->cpu, &collie_binfo);
+}
+
+static QEMUMachine collie_machine = {
+    .name = "collie",
+    .desc = "Collie PDA (SA-1110)",
+    .init = collie_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void collie_machine_init(void)
+{
+    qemu_register_machine(&collie_machine);
+}
+
+machine_init(collie_machine_init)
diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c
new file mode 100644 (file)
index 0000000..473da34
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *  Samsung exynos4 SoC based boards emulation
+ *
+ *  Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *    Maksim Kozlov <m.kozlov@samsung.com>
+ *    Evgeny Voevodin <e.voevodin@samsung.com>
+ *    Igor Mitsyanko  <i.mitsyanko@samsung.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/arm-misc.h"
+#include "exec/address-spaces.h"
+#include "hw/exynos4210.h"
+#include "hw/boards.h"
+
+#undef DEBUG
+
+//#define DEBUG
+
+#ifdef DEBUG
+    #undef PRINT_DEBUG
+    #define  PRINT_DEBUG(fmt, args...) \
+        do { \
+            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
+        } while (0)
+#else
+    #define  PRINT_DEBUG(fmt, args...)  do {} while (0)
+#endif
+
+#define SMDK_LAN9118_BASE_ADDR      0x05000000
+
+typedef enum Exynos4BoardType {
+    EXYNOS4_BOARD_NURI,
+    EXYNOS4_BOARD_SMDKC210,
+    EXYNOS4_NUM_OF_BOARDS
+} Exynos4BoardType;
+
+static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = {
+    [EXYNOS4_BOARD_NURI]     = 0xD33,
+    [EXYNOS4_BOARD_SMDKC210] = 0xB16,
+};
+
+static int exynos4_board_smp_bootreg_addr[EXYNOS4_NUM_OF_BOARDS] = {
+    [EXYNOS4_BOARD_NURI]     = EXYNOS4210_SECOND_CPU_BOOTREG,
+    [EXYNOS4_BOARD_SMDKC210] = EXYNOS4210_SECOND_CPU_BOOTREG,
+};
+
+static unsigned long exynos4_board_ram_size[EXYNOS4_NUM_OF_BOARDS] = {
+    [EXYNOS4_BOARD_NURI]     = 0x40000000,
+    [EXYNOS4_BOARD_SMDKC210] = 0x40000000,
+};
+
+static struct arm_boot_info exynos4_board_binfo = {
+    .loader_start     = EXYNOS4210_BASE_BOOT_ADDR,
+    .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
+    .nb_cpus          = EXYNOS4210_NCPUS,
+    .write_secondary_boot = exynos4210_write_secondary,
+};
+
+static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS];
+
+static void lan9215_init(uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    /* This should be a 9215 but the 9118 is close enough */
+    if (nd_table[0].used) {
+        qemu_check_nic_model(&nd_table[0], "lan9118");
+        dev = qdev_create(NULL, "lan9118");
+        qdev_set_nic_properties(dev, &nd_table[0]);
+        qdev_prop_set_uint32(dev, "mode_16bit", 1);
+        qdev_init_nofail(dev);
+        s = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(s, 0, base);
+        sysbus_connect_irq(s, 0, irq);
+    }
+}
+
+static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
+                                                   Exynos4BoardType board_type)
+{
+    if (smp_cpus != EXYNOS4210_NCPUS) {
+        fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus"
+                " value.\n",
+                exynos4_machines[board_type].name,
+                exynos4_machines[board_type].max_cpus);
+    }
+
+    exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type];
+    exynos4_board_binfo.board_id = exynos4_board_id[board_type];
+    exynos4_board_binfo.smp_bootreg_addr =
+            exynos4_board_smp_bootreg_addr[board_type];
+    exynos4_board_binfo.kernel_filename = args->kernel_filename;
+    exynos4_board_binfo.initrd_filename = args->initrd_filename;
+    exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline;
+    exynos4_board_binfo.gic_cpu_if_addr =
+            EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
+
+    PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n"
+            " kernel_filename: %s\n"
+            " kernel_cmdline: %s\n"
+            " initrd_filename: %s\n",
+            exynos4_board_ram_size[board_type] / 1048576,
+            exynos4_board_ram_size[board_type],
+            args->kernel_filename,
+            args->kernel_cmdline,
+            args->initrd_filename);
+
+    return exynos4210_init(get_system_memory(),
+            exynos4_board_ram_size[board_type]);
+}
+
+static void nuri_init(QEMUMachineInitArgs *args)
+{
+    exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI);
+
+    arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo);
+}
+
+static void smdkc210_init(QEMUMachineInitArgs *args)
+{
+    Exynos4210State *s = exynos4_boards_init_common(args,
+                                                    EXYNOS4_BOARD_SMDKC210);
+
+    lan9215_init(SMDK_LAN9118_BASE_ADDR,
+            qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)]));
+    arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo);
+}
+
+static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS] = {
+    [EXYNOS4_BOARD_NURI] = {
+        .name = "nuri",
+        .desc = "Samsung NURI board (Exynos4210)",
+        .init = nuri_init,
+        .max_cpus = EXYNOS4210_NCPUS,
+        DEFAULT_MACHINE_OPTIONS,
+    },
+    [EXYNOS4_BOARD_SMDKC210] = {
+        .name = "smdkc210",
+        .desc = "Samsung SMDKC210 board (Exynos4210)",
+        .init = smdkc210_init,
+        .max_cpus = EXYNOS4210_NCPUS,
+        DEFAULT_MACHINE_OPTIONS,
+    },
+};
+
+static void exynos4_machine_init(void)
+{
+    qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_NURI]);
+    qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_SMDKC210]);
+}
+
+machine_init(exynos4_machine_init);
diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c
new file mode 100644 (file)
index 0000000..8859b73
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Gumstix Platforms
+ *
+ * Copyright (c) 2007 by Thorsten Zitterell <info@bitmux.org>
+ *
+ * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+/* 
+ * Example usage:
+ * 
+ * connex:
+ * =======
+ * create image:
+ * # dd of=flash bs=1k count=16k if=/dev/zero
+ * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
+ * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
+ * start it:
+ * # qemu-system-arm -M connex -pflash flash -monitor null -nographic
+ *
+ * verdex:
+ * =======
+ * create image:
+ * # dd of=flash bs=1k count=32k if=/dev/zero
+ * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
+ * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
+ * # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage
+ * start it:
+ * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289
+ */
+
+#include "hw/hw.h"
+#include "hw/pxa.h"
+#include "net/net.h"
+#include "hw/flash.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+static const int sector_len = 128 * 1024;
+
+static void connex_init(QEMUMachineInitArgs *args)
+{
+    PXA2xxState *cpu;
+    DriveInfo *dinfo;
+    int be;
+    MemoryRegion *address_space_mem = get_system_memory();
+
+    uint32_t connex_rom = 0x01000000;
+    uint32_t connex_ram = 0x04000000;
+
+    cpu = pxa255_init(address_space_mem, connex_ram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (!dinfo) {
+        fprintf(stderr, "A flash image must be given with the "
+                "'pflash' parameter\n");
+        exit(1);
+    }
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom,
+                               dinfo->bdrv, sector_len, connex_rom / sector_len,
+                               2, 0, 0, 0, 0, be)) {
+        fprintf(stderr, "qemu: Error registering flash memory.\n");
+        exit(1);
+    }
+
+    /* Interrupt line of NIC is connected to GPIO line 36 */
+    smc91c111_init(&nd_table[0], 0x04000300,
+                    qdev_get_gpio_in(cpu->gpio, 36));
+}
+
+static void verdex_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    PXA2xxState *cpu;
+    DriveInfo *dinfo;
+    int be;
+    MemoryRegion *address_space_mem = get_system_memory();
+
+    uint32_t verdex_rom = 0x02000000;
+    uint32_t verdex_ram = 0x10000000;
+
+    cpu = pxa270_init(address_space_mem, verdex_ram, cpu_model ?: "pxa270-c0");
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (!dinfo) {
+        fprintf(stderr, "A flash image must be given with the "
+                "'pflash' parameter\n");
+        exit(1);
+    }
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom,
+                               dinfo->bdrv, sector_len, verdex_rom / sector_len,
+                               2, 0, 0, 0, 0, be)) {
+        fprintf(stderr, "qemu: Error registering flash memory.\n");
+        exit(1);
+    }
+
+    /* Interrupt line of NIC is connected to GPIO line 99 */
+    smc91c111_init(&nd_table[0], 0x04000300,
+                    qdev_get_gpio_in(cpu->gpio, 99));
+}
+
+static QEMUMachine connex_machine = {
+    .name = "connex",
+    .desc = "Gumstix Connex (PXA255)",
+    .init = connex_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine verdex_machine = {
+    .name = "verdex",
+    .desc = "Gumstix Verdex (PXA270)",
+    .init = verdex_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void gumstix_machine_init(void)
+{
+    qemu_register_machine(&connex_machine);
+    qemu_register_machine(&verdex_machine);
+}
+
+machine_init(gumstix_machine_init);
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
new file mode 100644 (file)
index 0000000..a622224
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * Calxeda Highbank SoC emulation
+ *
+ * Copyright (c) 2010-2012 Calxeda
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "hw/loader.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/sysbus.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+#define SMP_BOOT_ADDR 0x100
+#define SMP_BOOT_REG  0x40
+#define GIC_BASE_ADDR 0xfff10000
+
+#define NIRQ_GIC      160
+
+/* Board init.  */
+
+static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
+{
+    int n;
+    uint32_t smpboot[] = {
+        0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */
+        0xe210000f, /* ands r0, r0, #0x0f */
+        0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */
+        0xe0830200, /* add r0, r3, r0, lsl #4 */
+        0xe59f2024, /* ldr r2, privbase */
+        0xe3a01001, /* mov r1, #1 */
+        0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */
+        0xe3a010ff, /* mov r1, #0xff */
+        0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */
+        0xf57ff04f, /* dsb */
+        0xe320f003, /* wfi */
+        0xe5901000, /* ldr     r1, [r0] */
+        0xe1110001, /* tst     r1, r1 */
+        0x0afffffb, /* beq     <wfi> */
+        0xe12fff11, /* bx      r1 */
+        GIC_BASE_ADDR      /* privbase: gic address.  */
+    };
+    for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+        smpboot[n] = tswap32(smpboot[n]);
+    }
+    rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR);
+}
+
+static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
+{
+    CPUARMState *env = &cpu->env;
+
+    switch (info->nb_cpus) {
+    case 4:
+        stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0);
+    case 3:
+        stl_phys_notdirty(SMP_BOOT_REG + 0x20, 0);
+    case 2:
+        stl_phys_notdirty(SMP_BOOT_REG + 0x10, 0);
+        env->regs[15] = SMP_BOOT_ADDR;
+        break;
+    default:
+        break;
+    }
+}
+
+#define NUM_REGS      0x200
+static void hb_regs_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    uint32_t *regs = opaque;
+
+    if (offset == 0xf00) {
+        if (value == 1 || value == 2) {
+            qemu_system_reset_request();
+        } else if (value == 3) {
+            qemu_system_shutdown_request();
+        }
+    }
+
+    regs[offset/4] = value;
+}
+
+static uint64_t hb_regs_read(void *opaque, hwaddr offset,
+                             unsigned size)
+{
+    uint32_t *regs = opaque;
+    uint32_t value = regs[offset/4];
+
+    if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) {
+        value |= 0x30000000;
+    }
+
+    return value;
+}
+
+static const MemoryRegionOps hb_mem_ops = {
+    .read = hb_regs_read,
+    .write = hb_regs_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion *iomem;
+    uint32_t regs[NUM_REGS];
+} HighbankRegsState;
+
+static VMStateDescription vmstate_highbank_regs = {
+    .name = "highbank-regs",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static void highbank_regs_reset(DeviceState *dev)
+{
+    SysBusDevice *sys_dev = SYS_BUS_DEVICE(dev);
+    HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, sys_dev);
+
+    s->regs[0x40] = 0x05F20121;
+    s->regs[0x41] = 0x2;
+    s->regs[0x42] = 0x05F30121;
+    s->regs[0x43] = 0x05F40121;
+}
+
+static int highbank_regs_init(SysBusDevice *dev)
+{
+    HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, dev);
+
+    s->iomem = g_new(MemoryRegion, 1);
+    memory_region_init_io(s->iomem, &hb_mem_ops, s->regs, "highbank_regs",
+                          0x1000);
+    sysbus_init_mmio(dev, s->iomem);
+
+    return 0;
+}
+
+static void highbank_regs_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    sbc->init = highbank_regs_init;
+    dc->desc = "Calxeda Highbank registers";
+    dc->vmsd = &vmstate_highbank_regs;
+    dc->reset = highbank_regs_reset;
+}
+
+static const TypeInfo highbank_regs_info = {
+    .name          = "highbank-regs",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(HighbankRegsState),
+    .class_init    = highbank_regs_class_init,
+};
+
+static void highbank_regs_register_types(void)
+{
+    type_register_static(&highbank_regs_info);
+}
+
+type_init(highbank_regs_register_types)
+
+static struct arm_boot_info highbank_binfo;
+
+/* ram_size must be set to match the upper bound of memory in the
+ * device tree (linux/arch/arm/boot/dts/highbank.dts), which is
+ * normally 0xff900000 or -m 4089. When running this board on a
+ * 32-bit host, set the reg value of memory to 0xf7ff00000 in the
+ * device tree and pass -m 2047 to QEMU.
+ */
+static void highbank_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    qemu_irq *irqp;
+    qemu_irq pic[128];
+    int n;
+    qemu_irq cpu_irq[4];
+    MemoryRegion *sysram;
+    MemoryRegion *dram;
+    MemoryRegion *sysmem;
+    char *sysboot_filename;
+
+    if (!cpu_model) {
+        cpu_model = "cortex-a9";
+    }
+
+    for (n = 0; n < smp_cpus; n++) {
+        ARMCPU *cpu;
+        cpu = cpu_arm_init(cpu_model);
+        if (cpu == NULL) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+
+        /* This will become a QOM property eventually */
+        cpu->reset_cbar = GIC_BASE_ADDR;
+        irqp = arm_pic_init_cpu(cpu);
+        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+    }
+
+    sysmem = get_system_memory();
+    dram = g_new(MemoryRegion, 1);
+    memory_region_init_ram(dram, "highbank.dram", ram_size);
+    /* SDRAM at address zero.  */
+    memory_region_add_subregion(sysmem, 0, dram);
+
+    sysram = g_new(MemoryRegion, 1);
+    memory_region_init_ram(sysram, "highbank.sysram", 0x8000);
+    memory_region_add_subregion(sysmem, 0xfff88000, sysram);
+    if (bios_name != NULL) {
+        sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        if (sysboot_filename != NULL) {
+            uint32_t filesize = get_image_size(sysboot_filename);
+            if (load_image_targphys("sysram.bin", 0xfff88000, filesize) < 0) {
+                hw_error("Unable to load %s\n", bios_name);
+            }
+        } else {
+           hw_error("Unable to find %s\n", bios_name);
+        }
+    }
+
+    dev = qdev_create(NULL, "a9mpcore_priv");
+    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+    qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, GIC_BASE_ADDR);
+    for (n = 0; n < smp_cpus; n++) {
+        sysbus_connect_irq(busdev, n, cpu_irq[n]);
+    }
+
+    for (n = 0; n < 128; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    dev = qdev_create(NULL, "l2x0");
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, 0xfff12000);
+
+    dev = qdev_create(NULL, "sp804");
+    qdev_prop_set_uint32(dev, "freq0", 150000000);
+    qdev_prop_set_uint32(dev, "freq1", 150000000);
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, 0xfff34000);
+    sysbus_connect_irq(busdev, 0, pic[18]);
+    sysbus_create_simple("pl011", 0xfff36000, pic[20]);
+
+    dev = qdev_create(NULL, "highbank-regs");
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, 0xfff3c000);
+
+    sysbus_create_simple("pl061", 0xfff30000, pic[14]);
+    sysbus_create_simple("pl061", 0xfff31000, pic[15]);
+    sysbus_create_simple("pl061", 0xfff32000, pic[16]);
+    sysbus_create_simple("pl061", 0xfff33000, pic[17]);
+    sysbus_create_simple("pl031", 0xfff35000, pic[19]);
+    sysbus_create_simple("pl022", 0xfff39000, pic[23]);
+
+    sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]);
+
+    if (nd_table[0].used) {
+        qemu_check_nic_model(&nd_table[0], "xgmac");
+        dev = qdev_create(NULL, "xgmac");
+        qdev_set_nic_properties(dev, &nd_table[0]);
+        qdev_init_nofail(dev);
+        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff50000);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[77]);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[78]);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[79]);
+
+        qemu_check_nic_model(&nd_table[1], "xgmac");
+        dev = qdev_create(NULL, "xgmac");
+        qdev_set_nic_properties(dev, &nd_table[1]);
+        qdev_init_nofail(dev);
+        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff51000);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[80]);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[81]);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[82]);
+    }
+
+    highbank_binfo.ram_size = ram_size;
+    highbank_binfo.kernel_filename = kernel_filename;
+    highbank_binfo.kernel_cmdline = kernel_cmdline;
+    highbank_binfo.initrd_filename = initrd_filename;
+    /* highbank requires a dtb in order to boot, and the dtb will override
+     * the board ID. The following value is ignored, so set it to -1 to be
+     * clear that the value is meaningless.
+     */
+    highbank_binfo.board_id = -1;
+    highbank_binfo.nb_cpus = smp_cpus;
+    highbank_binfo.loader_start = 0;
+    highbank_binfo.write_secondary_boot = hb_write_secondary;
+    highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary;
+    arm_load_kernel(arm_env_get_cpu(first_cpu), &highbank_binfo);
+}
+
+static QEMUMachine highbank_machine = {
+    .name = "highbank",
+    .desc = "Calxeda Highbank (ECX-1000)",
+    .init = highbank_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void highbank_machine_init(void)
+{
+    qemu_register_machine(&highbank_machine);
+}
+
+machine_init(highbank_machine_init);
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
new file mode 100644 (file)
index 0000000..e0ba327
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * ARM Integrator CP System emulation.
+ *
+ * Copyright (c) 2005-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL
+ */
+
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "hw/arm-misc.h"
+#include "net/net.h"
+#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t memsz;
+    MemoryRegion flash;
+    uint32_t cm_osc;
+    uint32_t cm_ctrl;
+    uint32_t cm_lock;
+    uint32_t cm_auxosc;
+    uint32_t cm_sdram;
+    uint32_t cm_init;
+    uint32_t cm_flags;
+    uint32_t cm_nvflags;
+    uint32_t int_level;
+    uint32_t irq_enabled;
+    uint32_t fiq_enabled;
+} integratorcm_state;
+
+static uint8_t integrator_spd[128] = {
+   128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
+   0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
+};
+
+static uint64_t integratorcm_read(void *opaque, hwaddr offset,
+                                  unsigned size)
+{
+    integratorcm_state *s = (integratorcm_state *)opaque;
+    if (offset >= 0x100 && offset < 0x200) {
+        /* CM_SPD */
+        if (offset >= 0x180)
+            return 0;
+        return integrator_spd[offset >> 2];
+    }
+    switch (offset >> 2) {
+    case 0: /* CM_ID */
+        return 0x411a3001;
+    case 1: /* CM_PROC */
+        return 0;
+    case 2: /* CM_OSC */
+        return s->cm_osc;
+    case 3: /* CM_CTRL */
+        return s->cm_ctrl;
+    case 4: /* CM_STAT */
+        return 0x00100000;
+    case 5: /* CM_LOCK */
+        if (s->cm_lock == 0xa05f) {
+            return 0x1a05f;
+        } else {
+            return s->cm_lock;
+        }
+    case 6: /* CM_LMBUSCNT */
+        /* ??? High frequency timer.  */
+        hw_error("integratorcm_read: CM_LMBUSCNT");
+    case 7: /* CM_AUXOSC */
+        return s->cm_auxosc;
+    case 8: /* CM_SDRAM */
+        return s->cm_sdram;
+    case 9: /* CM_INIT */
+        return s->cm_init;
+    case 10: /* CM_REFCT */
+        /* ??? High frequency timer.  */
+        hw_error("integratorcm_read: CM_REFCT");
+    case 12: /* CM_FLAGS */
+        return s->cm_flags;
+    case 14: /* CM_NVFLAGS */
+        return s->cm_nvflags;
+    case 16: /* CM_IRQ_STAT */
+        return s->int_level & s->irq_enabled;
+    case 17: /* CM_IRQ_RSTAT */
+        return s->int_level;
+    case 18: /* CM_IRQ_ENSET */
+        return s->irq_enabled;
+    case 20: /* CM_SOFT_INTSET */
+        return s->int_level & 1;
+    case 24: /* CM_FIQ_STAT */
+        return s->int_level & s->fiq_enabled;
+    case 25: /* CM_FIQ_RSTAT */
+        return s->int_level;
+    case 26: /* CM_FIQ_ENSET */
+        return s->fiq_enabled;
+    case 32: /* CM_VOLTAGE_CTL0 */
+    case 33: /* CM_VOLTAGE_CTL1 */
+    case 34: /* CM_VOLTAGE_CTL2 */
+    case 35: /* CM_VOLTAGE_CTL3 */
+        /* ??? Voltage control unimplemented.  */
+        return 0;
+    default:
+        hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
+                 (int)offset);
+        return 0;
+    }
+}
+
+static void integratorcm_do_remap(integratorcm_state *s)
+{
+    /* Sync memory region state with CM_CTRL REMAP bit:
+     * bit 0 => flash at address 0; bit 1 => RAM
+     */
+    memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
+}
+
+static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value)
+{
+    if (value & 8) {
+        qemu_system_reset_request();
+    }
+    if ((s->cm_ctrl ^ value) & 1) {
+        /* (value & 1) != 0 means the green "MISC LED" is lit.
+         * We don't have any nice place to display LEDs. printf is a bad
+         * idea because Linux uses the LED as a heartbeat and the output
+         * will swamp anything else on the terminal.
+         */
+    }
+    /* Note that the RESET bit [3] always reads as zero */
+    s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
+    integratorcm_do_remap(s);
+}
+
+static void integratorcm_update(integratorcm_state *s)
+{
+    /* ??? The CPU irq/fiq is raised when either the core module or base PIC
+       are active.  */
+    if (s->int_level & (s->irq_enabled | s->fiq_enabled))
+        hw_error("Core module interrupt\n");
+}
+
+static void integratorcm_write(void *opaque, hwaddr offset,
+                               uint64_t value, unsigned size)
+{
+    integratorcm_state *s = (integratorcm_state *)opaque;
+    switch (offset >> 2) {
+    case 2: /* CM_OSC */
+        if (s->cm_lock == 0xa05f)
+            s->cm_osc = value;
+        break;
+    case 3: /* CM_CTRL */
+        integratorcm_set_ctrl(s, value);
+        break;
+    case 5: /* CM_LOCK */
+        s->cm_lock = value & 0xffff;
+        break;
+    case 7: /* CM_AUXOSC */
+        if (s->cm_lock == 0xa05f)
+            s->cm_auxosc = value;
+        break;
+    case 8: /* CM_SDRAM */
+        s->cm_sdram = value;
+        break;
+    case 9: /* CM_INIT */
+        /* ??? This can change the memory bus frequency.  */
+        s->cm_init = value;
+        break;
+    case 12: /* CM_FLAGSS */
+        s->cm_flags |= value;
+        break;
+    case 13: /* CM_FLAGSC */
+        s->cm_flags &= ~value;
+        break;
+    case 14: /* CM_NVFLAGSS */
+        s->cm_nvflags |= value;
+        break;
+    case 15: /* CM_NVFLAGSS */
+        s->cm_nvflags &= ~value;
+        break;
+    case 18: /* CM_IRQ_ENSET */
+        s->irq_enabled |= value;
+        integratorcm_update(s);
+        break;
+    case 19: /* CM_IRQ_ENCLR */
+        s->irq_enabled &= ~value;
+        integratorcm_update(s);
+        break;
+    case 20: /* CM_SOFT_INTSET */
+        s->int_level |= (value & 1);
+        integratorcm_update(s);
+        break;
+    case 21: /* CM_SOFT_INTCLR */
+        s->int_level &= ~(value & 1);
+        integratorcm_update(s);
+        break;
+    case 26: /* CM_FIQ_ENSET */
+        s->fiq_enabled |= value;
+        integratorcm_update(s);
+        break;
+    case 27: /* CM_FIQ_ENCLR */
+        s->fiq_enabled &= ~value;
+        integratorcm_update(s);
+        break;
+    case 32: /* CM_VOLTAGE_CTL0 */
+    case 33: /* CM_VOLTAGE_CTL1 */
+    case 34: /* CM_VOLTAGE_CTL2 */
+    case 35: /* CM_VOLTAGE_CTL3 */
+        /* ??? Voltage control unimplemented.  */
+        break;
+    default:
+        hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
+                 (int)offset);
+        break;
+    }
+}
+
+/* Integrator/CM control registers.  */
+
+static const MemoryRegionOps integratorcm_ops = {
+    .read = integratorcm_read,
+    .write = integratorcm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int integratorcm_init(SysBusDevice *dev)
+{
+    integratorcm_state *s = FROM_SYSBUS(integratorcm_state, dev);
+
+    s->cm_osc = 0x01000048;
+    /* ??? What should the high bits of this value be?  */
+    s->cm_auxosc = 0x0007feff;
+    s->cm_sdram = 0x00011122;
+    if (s->memsz >= 256) {
+        integrator_spd[31] = 64;
+        s->cm_sdram |= 0x10;
+    } else if (s->memsz >= 128) {
+        integrator_spd[31] = 32;
+        s->cm_sdram |= 0x0c;
+    } else if (s->memsz >= 64) {
+        integrator_spd[31] = 16;
+        s->cm_sdram |= 0x08;
+    } else if (s->memsz >= 32) {
+        integrator_spd[31] = 4;
+        s->cm_sdram |= 0x04;
+    } else {
+        integrator_spd[31] = 2;
+    }
+    memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
+    s->cm_init = 0x00000112;
+    memory_region_init_ram(&s->flash, "integrator.flash", 0x100000);
+    vmstate_register_ram_global(&s->flash);
+
+    memory_region_init_io(&s->iomem, &integratorcm_ops, s,
+                          "integratorcm", 0x00800000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    integratorcm_do_remap(s);
+    /* ??? Save/restore.  */
+    return 0;
+}
+
+/* Integrator/CP hardware emulation.  */
+/* Primary interrupt controller.  */
+
+typedef struct icp_pic_state
+{
+  SysBusDevice busdev;
+  MemoryRegion iomem;
+  uint32_t level;
+  uint32_t irq_enabled;
+  uint32_t fiq_enabled;
+  qemu_irq parent_irq;
+  qemu_irq parent_fiq;
+} icp_pic_state;
+
+static void icp_pic_update(icp_pic_state *s)
+{
+    uint32_t flags;
+
+    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);
+}
+
+static void icp_pic_set_irq(void *opaque, int irq, int level)
+{
+    icp_pic_state *s = (icp_pic_state *)opaque;
+    if (level)
+        s->level |= 1 << irq;
+    else
+        s->level &= ~(1 << irq);
+    icp_pic_update(s);
+}
+
+static uint64_t icp_pic_read(void *opaque, hwaddr offset,
+                             unsigned size)
+{
+    icp_pic_state *s = (icp_pic_state *)opaque;
+
+    switch (offset >> 2) {
+    case 0: /* IRQ_STATUS */
+        return s->level & s->irq_enabled;
+    case 1: /* IRQ_RAWSTAT */
+        return s->level;
+    case 2: /* IRQ_ENABLESET */
+        return s->irq_enabled;
+    case 4: /* INT_SOFTSET */
+        return s->level & 1;
+    case 8: /* FRQ_STATUS */
+        return s->level & s->fiq_enabled;
+    case 9: /* FRQ_RAWSTAT */
+        return s->level;
+    case 10: /* FRQ_ENABLESET */
+        return s->fiq_enabled;
+    case 3: /* IRQ_ENABLECLR */
+    case 5: /* INT_SOFTCLR */
+    case 11: /* FRQ_ENABLECLR */
+    default:
+        printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void icp_pic_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    icp_pic_state *s = (icp_pic_state *)opaque;
+
+    switch (offset >> 2) {
+    case 2: /* IRQ_ENABLESET */
+        s->irq_enabled |= value;
+        break;
+    case 3: /* IRQ_ENABLECLR */
+        s->irq_enabled &= ~value;
+        break;
+    case 4: /* INT_SOFTSET */
+        if (value & 1)
+            icp_pic_set_irq(s, 0, 1);
+        break;
+    case 5: /* INT_SOFTCLR */
+        if (value & 1)
+            icp_pic_set_irq(s, 0, 0);
+        break;
+    case 10: /* FRQ_ENABLESET */
+        s->fiq_enabled |= value;
+        break;
+    case 11: /* FRQ_ENABLECLR */
+        s->fiq_enabled &= ~value;
+        break;
+    case 0: /* IRQ_STATUS */
+    case 1: /* IRQ_RAWSTAT */
+    case 8: /* FRQ_STATUS */
+    case 9: /* FRQ_RAWSTAT */
+    default:
+        printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
+        return;
+    }
+    icp_pic_update(s);
+}
+
+static const MemoryRegionOps icp_pic_ops = {
+    .read = icp_pic_read,
+    .write = icp_pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int icp_pic_init(SysBusDevice *dev)
+{
+    icp_pic_state *s = FROM_SYSBUS(icp_pic_state, dev);
+
+    qdev_init_gpio_in(&dev->qdev, icp_pic_set_irq, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+    sysbus_init_irq(dev, &s->parent_fiq);
+    memory_region_init_io(&s->iomem, &icp_pic_ops, s, "icp-pic", 0x00800000);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+/* CP control registers.  */
+
+static uint64_t icp_control_read(void *opaque, hwaddr offset,
+                                 unsigned size)
+{
+    switch (offset >> 2) {
+    case 0: /* CP_IDFIELD */
+        return 0x41034003;
+    case 1: /* CP_FLASHPROG */
+        return 0;
+    case 2: /* CP_INTREG */
+        return 0;
+    case 3: /* CP_DECODE */
+        return 0x11;
+    default:
+        hw_error("icp_control_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void icp_control_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    switch (offset >> 2) {
+    case 1: /* CP_FLASHPROG */
+    case 2: /* CP_INTREG */
+    case 3: /* CP_DECODE */
+        /* Nothing interesting implemented yet.  */
+        break;
+    default:
+        hw_error("icp_control_write: Bad offset %x\n", (int)offset);
+    }
+}
+
+static const MemoryRegionOps icp_control_ops = {
+    .read = icp_control_read,
+    .write = icp_control_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void icp_control_init(hwaddr base)
+{
+    MemoryRegion *io;
+
+    io = (MemoryRegion *)g_malloc0(sizeof(MemoryRegion));
+    memory_region_init_io(io, &icp_control_ops, NULL,
+                          "control", 0x00800000);
+    memory_region_add_subregion(get_system_memory(), base, io);
+    /* ??? Save/restore.  */
+}
+
+
+/* Board init.  */
+
+static struct arm_boot_info integrator_binfo = {
+    .loader_start = 0x0,
+    .board_id = 0x113,
+};
+
+static void integratorcp_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    ARMCPU *cpu;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
+    qemu_irq pic[32];
+    qemu_irq *cpu_pic;
+    DeviceState *dev;
+    int i;
+
+    if (!cpu_model) {
+        cpu_model = "arm926";
+    }
+    cpu = cpu_arm_init(cpu_model);
+    if (!cpu) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+
+    memory_region_init_ram(ram, "integrator.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
+    /* ??? RAM should repeat to fill physical memory space.  */
+    /* SDRAM at address zero*/
+    memory_region_add_subregion(address_space_mem, 0, ram);
+    /* And again at address 0x80000000 */
+    memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size);
+    memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
+
+    dev = qdev_create(NULL, "integrator_core");
+    qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
+
+    cpu_pic = arm_pic_init_cpu(cpu);
+    dev = sysbus_create_varargs("integrator_pic", 0x14000000,
+                                cpu_pic[ARM_PIC_CPU_IRQ],
+                                cpu_pic[ARM_PIC_CPU_FIQ], NULL);
+    for (i = 0; i < 32; i++) {
+        pic[i] = qdev_get_gpio_in(dev, i);
+    }
+    sysbus_create_simple("integrator_pic", 0xca000000, pic[26]);
+    sysbus_create_varargs("integrator_pit", 0x13000000,
+                          pic[5], pic[6], pic[7], NULL);
+    sysbus_create_simple("pl031", 0x15000000, pic[8]);
+    sysbus_create_simple("pl011", 0x16000000, pic[1]);
+    sysbus_create_simple("pl011", 0x17000000, pic[2]);
+    icp_control_init(0xcb000000);
+    sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
+    sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
+    sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
+    if (nd_table[0].used)
+        smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
+
+    sysbus_create_simple("pl110", 0xc0000000, pic[22]);
+
+    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(cpu, &integrator_binfo);
+}
+
+static QEMUMachine integratorcp_machine = {
+    .name = "integratorcp",
+    .desc = "ARM Integrator/CP (ARM926EJ-S)",
+    .init = integratorcp_init,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void integratorcp_machine_init(void)
+{
+    qemu_register_machine(&integratorcp_machine);
+}
+
+machine_init(integratorcp_machine_init);
+
+static Property core_properties[] = {
+    DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void core_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = integratorcm_init;
+    dc->props = core_properties;
+}
+
+static const TypeInfo core_info = {
+    .name          = "integrator_core",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(integratorcm_state),
+    .class_init    = core_class_init,
+};
+
+static void icp_pic_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = icp_pic_init;
+}
+
+static const TypeInfo icp_pic_info = {
+    .name          = "integrator_pic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(icp_pic_state),
+    .class_init    = icp_pic_class_init,
+};
+
+static void integratorcp_register_types(void)
+{
+    type_register_static(&icp_pic_info);
+    type_register_static(&core_info);
+}
+
+type_init(integratorcp_register_types)
diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
new file mode 100644 (file)
index 0000000..ec50a31
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * KZM Board System emulation.
+ *
+ * Copyright (c) 2008 OKL and 2011 NICTA
+ * Written by Hans at OK-Labs
+ * Updated by Peter Chubb.
+ *
+ * This code is licensed under the GPL, version 2 or later.
+ * See the file `COPYING' in the top level directory.
+ *
+ * It (partially) emulates a Kyoto Microcomputer
+ * KZM-ARM11-01 evaluation board, with a Freescale
+ * i.MX31 SoC
+ */
+
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+#include "hw/hw.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/serial.h"
+#include "hw/imx.h"
+
+    /* Memory map for Kzm Emulation Baseboard:
+     * 0x00000000-0x00003fff 16k secure ROM       IGNORED
+     * 0x00004000-0x00407fff Reserved             IGNORED
+     * 0x00404000-0x00407fff ROM                  IGNORED
+     * 0x00408000-0x0fffffff Reserved             IGNORED
+     * 0x10000000-0x1fffbfff RAM aliasing         IGNORED
+     * 0x1fffc000-0x1fffffff RAM                  EMULATED
+     * 0x20000000-0x2fffffff Reserved             IGNORED
+     * 0x30000000-0x7fffffff I.MX31 Internal Register Space
+     *   0x43f00000 IO_AREA0
+     *   0x43f90000 UART1                         EMULATED
+     *   0x43f94000 UART2                         EMULATED
+     *   0x68000000 AVIC                          EMULATED
+     *   0x53f80000 CCM                           EMULATED
+     *   0x53f94000 PIT 1                         EMULATED
+     *   0x53f98000 PIT 2                         EMULATED
+     *   0x53f90000 GPT                           EMULATED
+     * 0x80000000-0x87ffffff RAM                  EMULATED
+     * 0x88000000-0x8fffffff RAM Aliasing         EMULATED
+     * 0xa0000000-0xafffffff NAND Flash           IGNORED
+     * 0xb0000000-0xb3ffffff Unavailable          IGNORED
+     * 0xb4000000-0xb4000fff 8-bit free space     IGNORED
+     * 0xb4001000-0xb400100f Board control        IGNORED
+     *  0xb4001003           DIP switch
+     * 0xb4001010-0xb400101f 7-segment LED        IGNORED
+     * 0xb4001020-0xb400102f LED                  IGNORED
+     * 0xb4001030-0xb400103f LED                  IGNORED
+     * 0xb4001040-0xb400104f FPGA, UART           EMULATED
+     * 0xb4001050-0xb400105f FPGA, UART           EMULATED
+     * 0xb4001060-0xb40fffff FPGA                 IGNORED
+     * 0xb6000000-0xb61fffff LAN controller       EMULATED
+     * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED
+     * 0xb6300000-0xb7ffffff Free                 IGNORED
+     * 0xb8000000-0xb8004fff Memory control registers IGNORED
+     * 0xc0000000-0xc3ffffff PCMCIA/CF            IGNORED
+     * 0xc4000000-0xffffffff Reserved             IGNORED
+     */
+
+#define KZM_RAMADDRESS (0x80000000)
+#define KZM_FPGA       (0xb4001040)
+
+static struct arm_boot_info kzm_binfo = {
+    .loader_start = KZM_RAMADDRESS,
+    .board_id = 1722,
+};
+
+static void kzm_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    ARMCPU *cpu;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
+    qemu_irq *cpu_pic;
+    DeviceState *dev;
+    DeviceState *ccm;
+
+    if (!cpu_model) {
+        cpu_model = "arm1136";
+    }
+
+    cpu = cpu_arm_init(cpu_model);
+    if (!cpu) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+
+    /* On a real system, the first 16k is a `secure boot rom' */
+
+    memory_region_init_ram(ram, "kzm.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram);
+
+    memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size);
+    memory_region_add_subregion(address_space_mem, 0x88000000, ram_alias);
+
+    memory_region_init_ram(sram, "kzm.sram", 0x4000);
+    memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram);
+
+    cpu_pic = arm_pic_init_cpu(cpu);
+    dev = sysbus_create_varargs("imx_avic", 0x68000000,
+                                cpu_pic[ARM_PIC_CPU_IRQ],
+                                cpu_pic[ARM_PIC_CPU_FIQ], NULL);
+
+
+    imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45));
+    imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32));
+
+    ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL);
+
+    imx_timerp_create(0x53f94000, qdev_get_gpio_in(dev, 28), ccm);
+    imx_timerp_create(0x53f98000, qdev_get_gpio_in(dev, 27), ccm);
+    imx_timerg_create(0x53f90000, qdev_get_gpio_in(dev, 29), ccm);
+
+    if (nd_table[0].used) {
+        lan9118_init(&nd_table[0], 0xb6000000, qdev_get_gpio_in(dev, 52));
+    }
+
+    if (serial_hds[2]) { /* touchscreen */
+        serial_mm_init(address_space_mem, KZM_FPGA+0x10, 0,
+                       qdev_get_gpio_in(dev, 52),
+                       14745600, serial_hds[2],
+                       DEVICE_NATIVE_ENDIAN);
+    }
+
+    kzm_binfo.ram_size = ram_size;
+    kzm_binfo.kernel_filename = kernel_filename;
+    kzm_binfo.kernel_cmdline = kernel_cmdline;
+    kzm_binfo.initrd_filename = initrd_filename;
+    kzm_binfo.nb_cpus = 1;
+    arm_load_kernel(cpu, &kzm_binfo);
+}
+
+static QEMUMachine kzm_machine = {
+    .name = "kzm",
+    .desc = "ARM KZM Emulation Baseboard (ARM1136)",
+    .init = kzm_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void kzm_machine_init(void)
+{
+    qemu_register_machine(&kzm_machine);
+}
+
+machine_init(kzm_machine_init)
diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c
new file mode 100644 (file)
index 0000000..aea908f
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * PXA270-based Intel Mainstone platforms.
+ *
+ * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
+ *                                    <akuster@mvista.com>
+ *
+ * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+#include "hw/hw.h"
+#include "hw/pxa.h"
+#include "hw/arm-misc.h"
+#include "net/net.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "hw/flash.h"
+#include "sysemu/blockdev.h"
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+
+/* Device addresses */
+#define MST_FPGA_PHYS  0x08000000
+#define MST_ETH_PHYS   0x10000300
+#define MST_FLASH_0            0x00000000
+#define MST_FLASH_1            0x04000000
+
+/* IRQ definitions */
+#define MMC_IRQ       0
+#define USIM_IRQ      1
+#define USBC_IRQ      2
+#define ETHERNET_IRQ  3
+#define AC97_IRQ      4
+#define PEN_IRQ       5
+#define MSINS_IRQ     6
+#define EXBRD_IRQ     7
+#define S0_CD_IRQ     9
+#define S0_STSCHG_IRQ 10
+#define S0_IRQ        11
+#define S1_CD_IRQ     13
+#define S1_STSCHG_IRQ 14
+#define S1_IRQ        15
+
+static struct keymap map[0xE0] = {
+    [0 ... 0xDF] = { -1, -1 },
+    [0x1e] = {0,0}, /* a */
+    [0x30] = {0,1}, /* b */
+    [0x2e] = {0,2}, /* c */
+    [0x20] = {0,3}, /* d */
+    [0x12] = {0,4}, /* e */
+    [0x21] = {0,5}, /* f */
+    [0x22] = {1,0}, /* g */
+    [0x23] = {1,1}, /* h */
+    [0x17] = {1,2}, /* i */
+    [0x24] = {1,3}, /* j */
+    [0x25] = {1,4}, /* k */
+    [0x26] = {1,5}, /* l */
+    [0x32] = {2,0}, /* m */
+    [0x31] = {2,1}, /* n */
+    [0x18] = {2,2}, /* o */
+    [0x19] = {2,3}, /* p */
+    [0x10] = {2,4}, /* q */
+    [0x13] = {2,5}, /* r */
+    [0x1f] = {3,0}, /* s */
+    [0x14] = {3,1}, /* t */
+    [0x16] = {3,2}, /* u */
+    [0x2f] = {3,3}, /* v */
+    [0x11] = {3,4}, /* w */
+    [0x2d] = {3,5}, /* x */
+    [0x15] = {4,2}, /* y */
+    [0x2c] = {4,3}, /* z */
+    [0xc7] = {5,0}, /* Home */
+    [0x2a] = {5,1}, /* shift */
+    [0x39] = {5,2}, /* space */
+    [0x39] = {5,3}, /* space */
+    [0x1c] = {5,5}, /*  enter */
+    [0xc8] = {6,0}, /* up */
+    [0xd0] = {6,1}, /* down */
+    [0xcb] = {6,2}, /* left */
+    [0xcd] = {6,3}, /* right */
+};
+
+enum mainstone_model_e { mainstone };
+
+#define MAINSTONE_RAM  0x04000000
+#define MAINSTONE_ROM  0x00800000
+#define MAINSTONE_FLASH        0x02000000
+
+static struct arm_boot_info mainstone_binfo = {
+    .loader_start = PXA2XX_SDRAM_BASE,
+    .ram_size = 0x04000000,
+};
+
+static void mainstone_common_init(MemoryRegion *address_space_mem,
+                                  QEMUMachineInitArgs *args,
+                                  enum mainstone_model_e model, int arm_id)
+{
+    uint32_t sector_len = 256 * 1024;
+    hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
+    PXA2xxState *mpu;
+    DeviceState *mst_irq;
+    DriveInfo *dinfo;
+    int i;
+    int be;
+    MemoryRegion *rom = g_new(MemoryRegion, 1);
+    const char *cpu_model = args->cpu_model;
+
+    if (!cpu_model)
+        cpu_model = "pxa270-c5";
+
+    /* Setup CPU & memory */
+    mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model);
+    memory_region_init_ram(rom, "mainstone.rom", MAINSTONE_ROM);
+    vmstate_register_ram_global(rom);
+    memory_region_set_readonly(rom, true);
+    memory_region_add_subregion(address_space_mem, 0, rom);
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    /* There are two 32MiB flash devices on the board */
+    for (i = 0; i < 2; i ++) {
+        dinfo = drive_get(IF_PFLASH, 0, i);
+        if (!dinfo) {
+            fprintf(stderr, "Two flash images must be given with the "
+                    "'pflash' parameter\n");
+            exit(1);
+        }
+
+        if (!pflash_cfi01_register(mainstone_flash_base[i], NULL,
+                                   i ? "mainstone.flash1" : "mainstone.flash0",
+                                   MAINSTONE_FLASH,
+                                   dinfo->bdrv, sector_len,
+                                   MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0,
+                                   be)) {
+            fprintf(stderr, "qemu: Error registering flash memory.\n");
+            exit(1);
+        }
+    }
+
+    mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS,
+                    qdev_get_gpio_in(mpu->gpio, 0));
+
+    /* setup keypad */
+    printf("map addr %p\n", &map);
+    pxa27x_register_keypad(mpu->kp, map, 0xe0);
+
+    /* MMC/SD host */
+    pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ));
+
+    pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[0],
+            qdev_get_gpio_in(mst_irq, S0_IRQ),
+            qdev_get_gpio_in(mst_irq, S0_CD_IRQ));
+    pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1],
+            qdev_get_gpio_in(mst_irq, S1_IRQ),
+            qdev_get_gpio_in(mst_irq, S1_CD_IRQ));
+
+    smc91c111_init(&nd_table[0], MST_ETH_PHYS,
+                    qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
+
+    mainstone_binfo.kernel_filename = args->kernel_filename;
+    mainstone_binfo.kernel_cmdline = args->kernel_cmdline;
+    mainstone_binfo.initrd_filename = args->initrd_filename;
+    mainstone_binfo.board_id = arm_id;
+    arm_load_kernel(mpu->cpu, &mainstone_binfo);
+}
+
+static void mainstone_init(QEMUMachineInitArgs *args)
+{
+    mainstone_common_init(get_system_memory(), args, mainstone, 0x196);
+}
+
+static QEMUMachine mainstone2_machine = {
+    .name = "mainstone",
+    .desc = "Mainstone II (PXA27x)",
+    .init = mainstone_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void mainstone_machine_init(void)
+{
+    qemu_register_machine(&mainstone2_machine);
+}
+
+machine_init(mainstone_machine_init);
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
new file mode 100644 (file)
index 0000000..a37dbd7
--- /dev/null
@@ -0,0 +1,1697 @@
+/*
+ * Marvell MV88W8618 / Freecom MusicPal emulation.
+ *
+ * Copyright (c) 2008 Jan Kiszka
+ *
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/serial.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "block/block.h"
+#include "hw/flash.h"
+#include "ui/console.h"
+#include "hw/i2c.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+#include "ui/pixel_ops.h"
+
+#define MP_MISC_BASE            0x80002000
+#define MP_MISC_SIZE            0x00001000
+
+#define MP_ETH_BASE             0x80008000
+#define MP_ETH_SIZE             0x00001000
+
+#define MP_WLAN_BASE            0x8000C000
+#define MP_WLAN_SIZE            0x00000800
+
+#define MP_UART1_BASE           0x8000C840
+#define MP_UART2_BASE           0x8000C940
+
+#define MP_GPIO_BASE            0x8000D000
+#define MP_GPIO_SIZE            0x00001000
+
+#define MP_FLASHCFG_BASE        0x90006000
+#define MP_FLASHCFG_SIZE        0x00001000
+
+#define MP_AUDIO_BASE           0x90007000
+
+#define MP_PIC_BASE             0x90008000
+#define MP_PIC_SIZE             0x00001000
+
+#define MP_PIT_BASE             0x90009000
+#define MP_PIT_SIZE             0x00001000
+
+#define MP_LCD_BASE             0x9000c000
+#define MP_LCD_SIZE             0x00001000
+
+#define MP_SRAM_BASE            0xC0000000
+#define MP_SRAM_SIZE            0x00020000
+
+#define MP_RAM_DEFAULT_SIZE     32*1024*1024
+#define MP_FLASH_SIZE_MAX       32*1024*1024
+
+#define MP_TIMER1_IRQ           4
+#define MP_TIMER2_IRQ           5
+#define MP_TIMER3_IRQ           6
+#define MP_TIMER4_IRQ           7
+#define MP_EHCI_IRQ             8
+#define MP_ETH_IRQ              9
+#define MP_UART1_IRQ            11
+#define MP_UART2_IRQ            11
+#define MP_GPIO_IRQ             12
+#define MP_RTC_IRQ              28
+#define MP_AUDIO_IRQ            30
+
+/* Wolfson 8750 I2C address */
+#define MP_WM_ADDR              0x1A
+
+/* Ethernet register offsets */
+#define MP_ETH_SMIR             0x010
+#define MP_ETH_PCXR             0x408
+#define MP_ETH_SDCMR            0x448
+#define MP_ETH_ICR              0x450
+#define MP_ETH_IMR              0x458
+#define MP_ETH_FRDP0            0x480
+#define MP_ETH_FRDP1            0x484
+#define MP_ETH_FRDP2            0x488
+#define MP_ETH_FRDP3            0x48C
+#define MP_ETH_CRDP0            0x4A0
+#define MP_ETH_CRDP1            0x4A4
+#define MP_ETH_CRDP2            0x4A8
+#define MP_ETH_CRDP3            0x4AC
+#define MP_ETH_CTDP0            0x4E0
+#define MP_ETH_CTDP1            0x4E4
+#define MP_ETH_CTDP2            0x4E8
+#define MP_ETH_CTDP3            0x4EC
+
+/* MII PHY access */
+#define MP_ETH_SMIR_DATA        0x0000FFFF
+#define MP_ETH_SMIR_ADDR        0x03FF0000
+#define MP_ETH_SMIR_OPCODE      (1 << 26) /* Read value */
+#define MP_ETH_SMIR_RDVALID     (1 << 27)
+
+/* PHY registers */
+#define MP_ETH_PHY1_BMSR        0x00210000
+#define MP_ETH_PHY1_PHYSID1     0x00410000
+#define MP_ETH_PHY1_PHYSID2     0x00610000
+
+#define MP_PHY_BMSR_LINK        0x0004
+#define MP_PHY_BMSR_AUTONEG     0x0008
+
+#define MP_PHY_88E3015          0x01410E20
+
+/* TX descriptor status */
+#define MP_ETH_TX_OWN           (1 << 31)
+
+/* RX descriptor status */
+#define MP_ETH_RX_OWN           (1 << 31)
+
+/* Interrupt cause/mask bits */
+#define MP_ETH_IRQ_RX_BIT       0
+#define MP_ETH_IRQ_RX           (1 << MP_ETH_IRQ_RX_BIT)
+#define MP_ETH_IRQ_TXHI_BIT     2
+#define MP_ETH_IRQ_TXLO_BIT     3
+
+/* Port config bits */
+#define MP_ETH_PCXR_2BSM_BIT    28 /* 2-byte incoming suffix */
+
+/* SDMA command bits */
+#define MP_ETH_CMD_TXHI         (1 << 23)
+#define MP_ETH_CMD_TXLO         (1 << 22)
+
+typedef struct mv88w8618_tx_desc {
+    uint32_t cmdstat;
+    uint16_t res;
+    uint16_t bytes;
+    uint32_t buffer;
+    uint32_t next;
+} mv88w8618_tx_desc;
+
+typedef struct mv88w8618_rx_desc {
+    uint32_t cmdstat;
+    uint16_t bytes;
+    uint16_t buffer_size;
+    uint32_t buffer;
+    uint32_t next;
+} mv88w8618_rx_desc;
+
+typedef struct mv88w8618_eth_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    uint32_t smir;
+    uint32_t icr;
+    uint32_t imr;
+    int mmio_index;
+    uint32_t vlan_header;
+    uint32_t tx_queue[2];
+    uint32_t rx_queue[4];
+    uint32_t frx_queue[4];
+    uint32_t cur_rx[4];
+    NICState *nic;
+    NICConf conf;
+} mv88w8618_eth_state;
+
+static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc)
+{
+    cpu_to_le32s(&desc->cmdstat);
+    cpu_to_le16s(&desc->bytes);
+    cpu_to_le16s(&desc->buffer_size);
+    cpu_to_le32s(&desc->buffer);
+    cpu_to_le32s(&desc->next);
+    cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc));
+}
+
+static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc)
+{
+    cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc));
+    le32_to_cpus(&desc->cmdstat);
+    le16_to_cpus(&desc->bytes);
+    le16_to_cpus(&desc->buffer_size);
+    le32_to_cpus(&desc->buffer);
+    le32_to_cpus(&desc->next);
+}
+
+static int eth_can_receive(NetClientState *nc)
+{
+    return 1;
+}
+
+static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
+    uint32_t desc_addr;
+    mv88w8618_rx_desc desc;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        desc_addr = s->cur_rx[i];
+        if (!desc_addr) {
+            continue;
+        }
+        do {
+            eth_rx_desc_get(desc_addr, &desc);
+            if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) {
+                cpu_physical_memory_write(desc.buffer + s->vlan_header,
+                                          buf, size);
+                desc.bytes = size + s->vlan_header;
+                desc.cmdstat &= ~MP_ETH_RX_OWN;
+                s->cur_rx[i] = desc.next;
+
+                s->icr |= MP_ETH_IRQ_RX;
+                if (s->icr & s->imr) {
+                    qemu_irq_raise(s->irq);
+                }
+                eth_rx_desc_put(desc_addr, &desc);
+                return size;
+            }
+            desc_addr = desc.next;
+        } while (desc_addr != s->rx_queue[i]);
+    }
+    return size;
+}
+
+static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc)
+{
+    cpu_to_le32s(&desc->cmdstat);
+    cpu_to_le16s(&desc->res);
+    cpu_to_le16s(&desc->bytes);
+    cpu_to_le32s(&desc->buffer);
+    cpu_to_le32s(&desc->next);
+    cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc));
+}
+
+static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc)
+{
+    cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc));
+    le32_to_cpus(&desc->cmdstat);
+    le16_to_cpus(&desc->res);
+    le16_to_cpus(&desc->bytes);
+    le32_to_cpus(&desc->buffer);
+    le32_to_cpus(&desc->next);
+}
+
+static void eth_send(mv88w8618_eth_state *s, int queue_index)
+{
+    uint32_t desc_addr = s->tx_queue[queue_index];
+    mv88w8618_tx_desc desc;
+    uint32_t next_desc;
+    uint8_t buf[2048];
+    int len;
+
+    do {
+        eth_tx_desc_get(desc_addr, &desc);
+        next_desc = desc.next;
+        if (desc.cmdstat & MP_ETH_TX_OWN) {
+            len = desc.bytes;
+            if (len < 2048) {
+                cpu_physical_memory_read(desc.buffer, buf, len);
+                qemu_send_packet(qemu_get_queue(s->nic), buf, len);
+            }
+            desc.cmdstat &= ~MP_ETH_TX_OWN;
+            s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
+            eth_tx_desc_put(desc_addr, &desc);
+        }
+        desc_addr = next_desc;
+    } while (desc_addr != s->tx_queue[queue_index]);
+}
+
+static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    mv88w8618_eth_state *s = opaque;
+
+    switch (offset) {
+    case MP_ETH_SMIR:
+        if (s->smir & MP_ETH_SMIR_OPCODE) {
+            switch (s->smir & MP_ETH_SMIR_ADDR) {
+            case MP_ETH_PHY1_BMSR:
+                return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG |
+                       MP_ETH_SMIR_RDVALID;
+            case MP_ETH_PHY1_PHYSID1:
+                return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID;
+            case MP_ETH_PHY1_PHYSID2:
+                return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID;
+            default:
+                return MP_ETH_SMIR_RDVALID;
+            }
+        }
+        return 0;
+
+    case MP_ETH_ICR:
+        return s->icr;
+
+    case MP_ETH_IMR:
+        return s->imr;
+
+    case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
+        return s->frx_queue[(offset - MP_ETH_FRDP0)/4];
+
+    case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
+        return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
+
+    case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
+        return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_eth_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    mv88w8618_eth_state *s = opaque;
+
+    switch (offset) {
+    case MP_ETH_SMIR:
+        s->smir = value;
+        break;
+
+    case MP_ETH_PCXR:
+        s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2;
+        break;
+
+    case MP_ETH_SDCMR:
+        if (value & MP_ETH_CMD_TXHI) {
+            eth_send(s, 1);
+        }
+        if (value & MP_ETH_CMD_TXLO) {
+            eth_send(s, 0);
+        }
+        if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) {
+            qemu_irq_raise(s->irq);
+        }
+        break;
+
+    case MP_ETH_ICR:
+        s->icr &= value;
+        break;
+
+    case MP_ETH_IMR:
+        s->imr = value;
+        if (s->icr & s->imr) {
+            qemu_irq_raise(s->irq);
+        }
+        break;
+
+    case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
+        s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value;
+        break;
+
+    case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
+        s->rx_queue[(offset - MP_ETH_CRDP0)/4] =
+            s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
+        break;
+
+    case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
+        s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
+        break;
+    }
+}
+
+static const MemoryRegionOps mv88w8618_eth_ops = {
+    .read = mv88w8618_eth_read,
+    .write = mv88w8618_eth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void eth_cleanup(NetClientState *nc)
+{
+    mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_mv88w8618_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_receive,
+    .receive = eth_receive,
+    .cleanup = eth_cleanup,
+};
+
+static int mv88w8618_eth_init(SysBusDevice *dev)
+{
+    mv88w8618_eth_state *s = FROM_SYSBUS(mv88w8618_eth_state, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+    s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth",
+                          MP_ETH_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static const VMStateDescription mv88w8618_eth_vmsd = {
+    .name = "mv88w8618_eth",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(smir, mv88w8618_eth_state),
+        VMSTATE_UINT32(icr, mv88w8618_eth_state),
+        VMSTATE_UINT32(imr, mv88w8618_eth_state),
+        VMSTATE_UINT32(vlan_header, mv88w8618_eth_state),
+        VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2),
+        VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4),
+        VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4),
+        VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property mv88w8618_eth_properties[] = {
+    DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mv88w8618_eth_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_eth_init;
+    dc->vmsd = &mv88w8618_eth_vmsd;
+    dc->props = mv88w8618_eth_properties;
+}
+
+static const TypeInfo mv88w8618_eth_info = {
+    .name          = "mv88w8618_eth",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mv88w8618_eth_state),
+    .class_init    = mv88w8618_eth_class_init,
+};
+
+/* LCD register offsets */
+#define MP_LCD_IRQCTRL          0x180
+#define MP_LCD_IRQSTAT          0x184
+#define MP_LCD_SPICTRL          0x1ac
+#define MP_LCD_INST             0x1bc
+#define MP_LCD_DATA             0x1c0
+
+/* Mode magics */
+#define MP_LCD_SPI_DATA         0x00100011
+#define MP_LCD_SPI_CMD          0x00104011
+#define MP_LCD_SPI_INVALID      0x00000000
+
+/* Commmands */
+#define MP_LCD_INST_SETPAGE0    0xB0
+/* ... */
+#define MP_LCD_INST_SETPAGE7    0xB7
+
+#define MP_LCD_TEXTCOLOR        0xe0e0ff /* RRGGBB */
+
+typedef struct musicpal_lcd_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t brightness;
+    uint32_t mode;
+    uint32_t irqctrl;
+    uint32_t page;
+    uint32_t page_off;
+    DisplayState *ds;
+    uint8_t video_ram[128*64/8];
+} musicpal_lcd_state;
+
+static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col)
+{
+    switch (s->brightness) {
+    case 7:
+        return col;
+    case 0:
+        return 0;
+    default:
+        return (col * s->brightness) / 7;
+    }
+}
+
+#define SET_LCD_PIXEL(depth, type) \
+static inline void glue(set_lcd_pixel, depth) \
+        (musicpal_lcd_state *s, int x, int y, type col) \
+{ \
+    int dx, dy; \
+    type *pixel = &((type *) ds_get_data(s->ds))[(y * 128 * 3 + x) * 3]; \
+\
+    for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \
+        for (dx = 0; dx < 3; dx++, pixel++) \
+            *pixel = col; \
+}
+SET_LCD_PIXEL(8, uint8_t)
+SET_LCD_PIXEL(16, uint16_t)
+SET_LCD_PIXEL(32, uint32_t)
+
+static void lcd_refresh(void *opaque)
+{
+    musicpal_lcd_state *s = opaque;
+    int x, y, col;
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        return;
+#define LCD_REFRESH(depth, func) \
+    case depth: \
+        col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \
+                   scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \
+                   scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \
+        for (x = 0; x < 128; x++) { \
+            for (y = 0; y < 64; y++) { \
+                if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \
+                    glue(set_lcd_pixel, depth)(s, x, y, col); \
+                } else { \
+                    glue(set_lcd_pixel, depth)(s, x, y, 0); \
+                } \
+            } \
+        } \
+        break;
+    LCD_REFRESH(8, rgb_to_pixel8)
+    LCD_REFRESH(16, rgb_to_pixel16)
+    LCD_REFRESH(32, (is_surface_bgr(s->ds->surface) ?
+                     rgb_to_pixel32bgr : rgb_to_pixel32))
+    default:
+        hw_error("unsupported colour depth %i\n",
+                  ds_get_bits_per_pixel(s->ds));
+    }
+
+    dpy_gfx_update(s->ds, 0, 0, 128*3, 64*3);
+}
+
+static void lcd_invalidate(void *opaque)
+{
+}
+
+static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level)
+{
+    musicpal_lcd_state *s = opaque;
+    s->brightness &= ~(1 << irq);
+    s->brightness |= level << irq;
+}
+
+static uint64_t musicpal_lcd_read(void *opaque, hwaddr offset,
+                                  unsigned size)
+{
+    musicpal_lcd_state *s = opaque;
+
+    switch (offset) {
+    case MP_LCD_IRQCTRL:
+        return s->irqctrl;
+
+    default:
+        return 0;
+    }
+}
+
+static void musicpal_lcd_write(void *opaque, hwaddr offset,
+                               uint64_t value, unsigned size)
+{
+    musicpal_lcd_state *s = opaque;
+
+    switch (offset) {
+    case MP_LCD_IRQCTRL:
+        s->irqctrl = value;
+        break;
+
+    case MP_LCD_SPICTRL:
+        if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) {
+            s->mode = value;
+        } else {
+            s->mode = MP_LCD_SPI_INVALID;
+        }
+        break;
+
+    case MP_LCD_INST:
+        if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) {
+            s->page = value - MP_LCD_INST_SETPAGE0;
+            s->page_off = 0;
+        }
+        break;
+
+    case MP_LCD_DATA:
+        if (s->mode == MP_LCD_SPI_CMD) {
+            if (value >= MP_LCD_INST_SETPAGE0 &&
+                value <= MP_LCD_INST_SETPAGE7) {
+                s->page = value - MP_LCD_INST_SETPAGE0;
+                s->page_off = 0;
+            }
+        } else if (s->mode == MP_LCD_SPI_DATA) {
+            s->video_ram[s->page*128 + s->page_off] = value;
+            s->page_off = (s->page_off + 1) & 127;
+        }
+        break;
+    }
+}
+
+static const MemoryRegionOps musicpal_lcd_ops = {
+    .read = musicpal_lcd_read,
+    .write = musicpal_lcd_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int musicpal_lcd_init(SysBusDevice *dev)
+{
+    musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev);
+
+    s->brightness = 7;
+
+    memory_region_init_io(&s->iomem, &musicpal_lcd_ops, s,
+                          "musicpal-lcd", MP_LCD_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    s->ds = graphic_console_init(lcd_refresh, lcd_invalidate,
+                                 NULL, NULL, s);
+    qemu_console_resize(s->ds, 128*3, 64*3);
+
+    qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3);
+
+    return 0;
+}
+
+static const VMStateDescription musicpal_lcd_vmsd = {
+    .name = "musicpal_lcd",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(brightness, musicpal_lcd_state),
+        VMSTATE_UINT32(mode, musicpal_lcd_state),
+        VMSTATE_UINT32(irqctrl, musicpal_lcd_state),
+        VMSTATE_UINT32(page, musicpal_lcd_state),
+        VMSTATE_UINT32(page_off, musicpal_lcd_state),
+        VMSTATE_BUFFER(video_ram, musicpal_lcd_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void musicpal_lcd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = musicpal_lcd_init;
+    dc->vmsd = &musicpal_lcd_vmsd;
+}
+
+static const TypeInfo musicpal_lcd_info = {
+    .name          = "musicpal_lcd",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(musicpal_lcd_state),
+    .class_init    = musicpal_lcd_class_init,
+};
+
+/* PIC register offsets */
+#define MP_PIC_STATUS           0x00
+#define MP_PIC_ENABLE_SET       0x08
+#define MP_PIC_ENABLE_CLR       0x0C
+
+typedef struct mv88w8618_pic_state
+{
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t level;
+    uint32_t enabled;
+    qemu_irq parent_irq;
+} mv88w8618_pic_state;
+
+static void mv88w8618_pic_update(mv88w8618_pic_state *s)
+{
+    qemu_set_irq(s->parent_irq, (s->level & s->enabled));
+}
+
+static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
+{
+    mv88w8618_pic_state *s = opaque;
+
+    if (level) {
+        s->level |= 1 << irq;
+    } else {
+        s->level &= ~(1 << irq);
+    }
+    mv88w8618_pic_update(s);
+}
+
+static uint64_t mv88w8618_pic_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    mv88w8618_pic_state *s = opaque;
+
+    switch (offset) {
+    case MP_PIC_STATUS:
+        return s->level & s->enabled;
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_pic_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    mv88w8618_pic_state *s = opaque;
+
+    switch (offset) {
+    case MP_PIC_ENABLE_SET:
+        s->enabled |= value;
+        break;
+
+    case MP_PIC_ENABLE_CLR:
+        s->enabled &= ~value;
+        s->level &= ~value;
+        break;
+    }
+    mv88w8618_pic_update(s);
+}
+
+static void mv88w8618_pic_reset(DeviceState *d)
+{
+    mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state,
+                                         SYS_BUS_DEVICE(d));
+
+    s->level = 0;
+    s->enabled = 0;
+}
+
+static const MemoryRegionOps mv88w8618_pic_ops = {
+    .read = mv88w8618_pic_read,
+    .write = mv88w8618_pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int mv88w8618_pic_init(SysBusDevice *dev)
+{
+    mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev);
+
+    qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+    memory_region_init_io(&s->iomem, &mv88w8618_pic_ops, s,
+                          "musicpal-pic", MP_PIC_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static const VMStateDescription mv88w8618_pic_vmsd = {
+    .name = "mv88w8618_pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(level, mv88w8618_pic_state),
+        VMSTATE_UINT32(enabled, mv88w8618_pic_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_pic_init;
+    dc->reset = mv88w8618_pic_reset;
+    dc->vmsd = &mv88w8618_pic_vmsd;
+}
+
+static const TypeInfo mv88w8618_pic_info = {
+    .name          = "mv88w8618_pic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mv88w8618_pic_state),
+    .class_init    = mv88w8618_pic_class_init,
+};
+
+/* PIT register offsets */
+#define MP_PIT_TIMER1_LENGTH    0x00
+/* ... */
+#define MP_PIT_TIMER4_LENGTH    0x0C
+#define MP_PIT_CONTROL          0x10
+#define MP_PIT_TIMER1_VALUE     0x14
+/* ... */
+#define MP_PIT_TIMER4_VALUE     0x20
+#define MP_BOARD_RESET          0x34
+
+/* Magic board reset value (probably some watchdog behind it) */
+#define MP_BOARD_RESET_MAGIC    0x10000
+
+typedef struct mv88w8618_timer_state {
+    ptimer_state *ptimer;
+    uint32_t limit;
+    int freq;
+    qemu_irq irq;
+} mv88w8618_timer_state;
+
+typedef struct mv88w8618_pit_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    mv88w8618_timer_state timer[4];
+} mv88w8618_pit_state;
+
+static void mv88w8618_timer_tick(void *opaque)
+{
+    mv88w8618_timer_state *s = opaque;
+
+    qemu_irq_raise(s->irq);
+}
+
+static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
+                                 uint32_t freq)
+{
+    QEMUBH *bh;
+
+    sysbus_init_irq(dev, &s->irq);
+    s->freq = freq;
+
+    bh = qemu_bh_new(mv88w8618_timer_tick, s);
+    s->ptimer = ptimer_init(bh);
+}
+
+static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    mv88w8618_pit_state *s = opaque;
+    mv88w8618_timer_state *t;
+
+    switch (offset) {
+    case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE:
+        t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2];
+        return ptimer_get_count(t->ptimer);
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_pit_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    mv88w8618_pit_state *s = opaque;
+    mv88w8618_timer_state *t;
+    int i;
+
+    switch (offset) {
+    case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:
+        t = &s->timer[offset >> 2];
+        t->limit = value;
+        if (t->limit > 0) {
+            ptimer_set_limit(t->ptimer, t->limit, 1);
+        } else {
+            ptimer_stop(t->ptimer);
+        }
+        break;
+
+    case MP_PIT_CONTROL:
+        for (i = 0; i < 4; i++) {
+            t = &s->timer[i];
+            if (value & 0xf && t->limit > 0) {
+                ptimer_set_limit(t->ptimer, t->limit, 0);
+                ptimer_set_freq(t->ptimer, t->freq);
+                ptimer_run(t->ptimer, 0);
+            } else {
+                ptimer_stop(t->ptimer);
+            }
+            value >>= 4;
+        }
+        break;
+
+    case MP_BOARD_RESET:
+        if (value == MP_BOARD_RESET_MAGIC) {
+            qemu_system_reset_request();
+        }
+        break;
+    }
+}
+
+static void mv88w8618_pit_reset(DeviceState *d)
+{
+    mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state,
+                                         SYS_BUS_DEVICE(d));
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        ptimer_stop(s->timer[i].ptimer);
+        s->timer[i].limit = 0;
+    }
+}
+
+static const MemoryRegionOps mv88w8618_pit_ops = {
+    .read = mv88w8618_pit_read,
+    .write = mv88w8618_pit_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int mv88w8618_pit_init(SysBusDevice *dev)
+{
+    mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, dev);
+    int i;
+
+    /* Letting them all run at 1 MHz is likely just a pragmatic
+     * simplification. */
+    for (i = 0; i < 4; i++) {
+        mv88w8618_timer_init(dev, &s->timer[i], 1000000);
+    }
+
+    memory_region_init_io(&s->iomem, &mv88w8618_pit_ops, s,
+                          "musicpal-pit", MP_PIT_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static const VMStateDescription mv88w8618_timer_vmsd = {
+    .name = "timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
+        VMSTATE_UINT32(limit, mv88w8618_timer_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription mv88w8618_pit_vmsd = {
+    .name = "mv88w8618_pit",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
+                             mv88w8618_timer_vmsd, mv88w8618_timer_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_pit_init;
+    dc->reset = mv88w8618_pit_reset;
+    dc->vmsd = &mv88w8618_pit_vmsd;
+}
+
+static const TypeInfo mv88w8618_pit_info = {
+    .name          = "mv88w8618_pit",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mv88w8618_pit_state),
+    .class_init    = mv88w8618_pit_class_init,
+};
+
+/* Flash config register offsets */
+#define MP_FLASHCFG_CFGR0    0x04
+
+typedef struct mv88w8618_flashcfg_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t cfgr0;
+} mv88w8618_flashcfg_state;
+
+static uint64_t mv88w8618_flashcfg_read(void *opaque,
+                                        hwaddr offset,
+                                        unsigned size)
+{
+    mv88w8618_flashcfg_state *s = opaque;
+
+    switch (offset) {
+    case MP_FLASHCFG_CFGR0:
+        return s->cfgr0;
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_flashcfg_write(void *opaque, hwaddr offset,
+                                     uint64_t value, unsigned size)
+{
+    mv88w8618_flashcfg_state *s = opaque;
+
+    switch (offset) {
+    case MP_FLASHCFG_CFGR0:
+        s->cfgr0 = value;
+        break;
+    }
+}
+
+static const MemoryRegionOps mv88w8618_flashcfg_ops = {
+    .read = mv88w8618_flashcfg_read,
+    .write = mv88w8618_flashcfg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int mv88w8618_flashcfg_init(SysBusDevice *dev)
+{
+    mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, dev);
+
+    s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
+    memory_region_init_io(&s->iomem, &mv88w8618_flashcfg_ops, s,
+                          "musicpal-flashcfg", MP_FLASHCFG_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static const VMStateDescription mv88w8618_flashcfg_vmsd = {
+    .name = "mv88w8618_flashcfg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_flashcfg_init;
+    dc->vmsd = &mv88w8618_flashcfg_vmsd;
+}
+
+static const TypeInfo mv88w8618_flashcfg_info = {
+    .name          = "mv88w8618_flashcfg",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mv88w8618_flashcfg_state),
+    .class_init    = mv88w8618_flashcfg_class_init,
+};
+
+/* Misc register offsets */
+#define MP_MISC_BOARD_REVISION  0x18
+
+#define MP_BOARD_REVISION       0x31
+
+static uint64_t musicpal_misc_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    switch (offset) {
+    case MP_MISC_BOARD_REVISION:
+        return MP_BOARD_REVISION;
+
+    default:
+        return 0;
+    }
+}
+
+static void musicpal_misc_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+}
+
+static const MemoryRegionOps musicpal_misc_ops = {
+    .read = musicpal_misc_read,
+    .write = musicpal_misc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void musicpal_misc_init(SysBusDevice *dev)
+{
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
+
+    memory_region_init_io(iomem, &musicpal_misc_ops, NULL,
+                          "musicpal-misc", MP_MISC_SIZE);
+    sysbus_add_memory(dev, MP_MISC_BASE, iomem);
+}
+
+/* WLAN register offsets */
+#define MP_WLAN_MAGIC1          0x11c
+#define MP_WLAN_MAGIC2          0x124
+
+static uint64_t mv88w8618_wlan_read(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    switch (offset) {
+    /* Workaround to allow loading the binary-only wlandrv.ko crap
+     * from the original Freecom firmware. */
+    case MP_WLAN_MAGIC1:
+        return ~3;
+    case MP_WLAN_MAGIC2:
+        return -1;
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_wlan_write(void *opaque, hwaddr offset,
+                                 uint64_t value, unsigned size)
+{
+}
+
+static const MemoryRegionOps mv88w8618_wlan_ops = {
+    .read = mv88w8618_wlan_read,
+    .write =mv88w8618_wlan_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int mv88w8618_wlan_init(SysBusDevice *dev)
+{
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
+
+    memory_region_init_io(iomem, &mv88w8618_wlan_ops, NULL,
+                          "musicpal-wlan", MP_WLAN_SIZE);
+    sysbus_init_mmio(dev, iomem);
+    return 0;
+}
+
+/* GPIO register offsets */
+#define MP_GPIO_OE_LO           0x008
+#define MP_GPIO_OUT_LO          0x00c
+#define MP_GPIO_IN_LO           0x010
+#define MP_GPIO_IER_LO          0x014
+#define MP_GPIO_IMR_LO          0x018
+#define MP_GPIO_ISR_LO          0x020
+#define MP_GPIO_OE_HI           0x508
+#define MP_GPIO_OUT_HI          0x50c
+#define MP_GPIO_IN_HI           0x510
+#define MP_GPIO_IER_HI          0x514
+#define MP_GPIO_IMR_HI          0x518
+#define MP_GPIO_ISR_HI          0x520
+
+/* GPIO bits & masks */
+#define MP_GPIO_LCD_BRIGHTNESS  0x00070000
+#define MP_GPIO_I2C_DATA_BIT    29
+#define MP_GPIO_I2C_CLOCK_BIT   30
+
+/* LCD brightness bits in GPIO_OE_HI */
+#define MP_OE_LCD_BRIGHTNESS    0x0007
+
+typedef struct musicpal_gpio_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t lcd_brightness;
+    uint32_t out_state;
+    uint32_t in_state;
+    uint32_t ier;
+    uint32_t imr;
+    uint32_t isr;
+    qemu_irq irq;
+    qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */
+} musicpal_gpio_state;
+
+static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) {
+    int i;
+    uint32_t brightness;
+
+    /* compute brightness ratio */
+    switch (s->lcd_brightness) {
+    case 0x00000007:
+        brightness = 0;
+        break;
+
+    case 0x00020000:
+        brightness = 1;
+        break;
+
+    case 0x00020001:
+        brightness = 2;
+        break;
+
+    case 0x00040000:
+        brightness = 3;
+        break;
+
+    case 0x00010006:
+        brightness = 4;
+        break;
+
+    case 0x00020005:
+        brightness = 5;
+        break;
+
+    case 0x00040003:
+        brightness = 6;
+        break;
+
+    case 0x00030004:
+    default:
+        brightness = 7;
+    }
+
+    /* set lcd brightness GPIOs  */
+    for (i = 0; i <= 2; i++) {
+        qemu_set_irq(s->out[i], (brightness >> i) & 1);
+    }
+}
+
+static void musicpal_gpio_pin_event(void *opaque, int pin, int level)
+{
+    musicpal_gpio_state *s = opaque;
+    uint32_t mask = 1 << pin;
+    uint32_t delta = level << pin;
+    uint32_t old = s->in_state & mask;
+
+    s->in_state &= ~mask;
+    s->in_state |= delta;
+
+    if ((old ^ delta) &&
+        ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) {
+        s->isr = mask;
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static uint64_t musicpal_gpio_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    musicpal_gpio_state *s = opaque;
+
+    switch (offset) {
+    case MP_GPIO_OE_HI: /* used for LCD brightness control */
+        return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS;
+
+    case MP_GPIO_OUT_LO:
+        return s->out_state & 0xFFFF;
+    case MP_GPIO_OUT_HI:
+        return s->out_state >> 16;
+
+    case MP_GPIO_IN_LO:
+        return s->in_state & 0xFFFF;
+    case MP_GPIO_IN_HI:
+        return s->in_state >> 16;
+
+    case MP_GPIO_IER_LO:
+        return s->ier & 0xFFFF;
+    case MP_GPIO_IER_HI:
+        return s->ier >> 16;
+
+    case MP_GPIO_IMR_LO:
+        return s->imr & 0xFFFF;
+    case MP_GPIO_IMR_HI:
+        return s->imr >> 16;
+
+    case MP_GPIO_ISR_LO:
+        return s->isr & 0xFFFF;
+    case MP_GPIO_ISR_HI:
+        return s->isr >> 16;
+
+    default:
+        return 0;
+    }
+}
+
+static void musicpal_gpio_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    musicpal_gpio_state *s = opaque;
+    switch (offset) {
+    case MP_GPIO_OE_HI: /* used for LCD brightness control */
+        s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) |
+                         (value & MP_OE_LCD_BRIGHTNESS);
+        musicpal_gpio_brightness_update(s);
+        break;
+
+    case MP_GPIO_OUT_LO:
+        s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF);
+        break;
+    case MP_GPIO_OUT_HI:
+        s->out_state = (s->out_state & 0xFFFF) | (value << 16);
+        s->lcd_brightness = (s->lcd_brightness & 0xFFFF) |
+                            (s->out_state & MP_GPIO_LCD_BRIGHTNESS);
+        musicpal_gpio_brightness_update(s);
+        qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1);
+        qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1);
+        break;
+
+    case MP_GPIO_IER_LO:
+        s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF);
+        break;
+    case MP_GPIO_IER_HI:
+        s->ier = (s->ier & 0xFFFF) | (value << 16);
+        break;
+
+    case MP_GPIO_IMR_LO:
+        s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF);
+        break;
+    case MP_GPIO_IMR_HI:
+        s->imr = (s->imr & 0xFFFF) | (value << 16);
+        break;
+    }
+}
+
+static const MemoryRegionOps musicpal_gpio_ops = {
+    .read = musicpal_gpio_read,
+    .write = musicpal_gpio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void musicpal_gpio_reset(DeviceState *d)
+{
+    musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state,
+                                         SYS_BUS_DEVICE(d));
+
+    s->lcd_brightness = 0;
+    s->out_state = 0;
+    s->in_state = 0xffffffff;
+    s->ier = 0;
+    s->imr = 0;
+    s->isr = 0;
+}
+
+static int musicpal_gpio_init(SysBusDevice *dev)
+{
+    musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->iomem, &musicpal_gpio_ops, s,
+                          "musicpal-gpio", MP_GPIO_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
+
+    qdev_init_gpio_in(&dev->qdev, musicpal_gpio_pin_event, 32);
+
+    return 0;
+}
+
+static const VMStateDescription musicpal_gpio_vmsd = {
+    .name = "musicpal_gpio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
+        VMSTATE_UINT32(out_state, musicpal_gpio_state),
+        VMSTATE_UINT32(in_state, musicpal_gpio_state),
+        VMSTATE_UINT32(ier, musicpal_gpio_state),
+        VMSTATE_UINT32(imr, musicpal_gpio_state),
+        VMSTATE_UINT32(isr, musicpal_gpio_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = musicpal_gpio_init;
+    dc->reset = musicpal_gpio_reset;
+    dc->vmsd = &musicpal_gpio_vmsd;
+}
+
+static const TypeInfo musicpal_gpio_info = {
+    .name          = "musicpal_gpio",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(musicpal_gpio_state),
+    .class_init    = musicpal_gpio_class_init,
+};
+
+/* Keyboard codes & masks */
+#define KEY_RELEASED            0x80
+#define KEY_CODE                0x7f
+
+#define KEYCODE_TAB             0x0f
+#define KEYCODE_ENTER           0x1c
+#define KEYCODE_F               0x21
+#define KEYCODE_M               0x32
+
+#define KEYCODE_EXTENDED        0xe0
+#define KEYCODE_UP              0x48
+#define KEYCODE_DOWN            0x50
+#define KEYCODE_LEFT            0x4b
+#define KEYCODE_RIGHT           0x4d
+
+#define MP_KEY_WHEEL_VOL       (1 << 0)
+#define MP_KEY_WHEEL_VOL_INV   (1 << 1)
+#define MP_KEY_WHEEL_NAV       (1 << 2)
+#define MP_KEY_WHEEL_NAV_INV   (1 << 3)
+#define MP_KEY_BTN_FAVORITS    (1 << 4)
+#define MP_KEY_BTN_MENU        (1 << 5)
+#define MP_KEY_BTN_VOLUME      (1 << 6)
+#define MP_KEY_BTN_NAVIGATION  (1 << 7)
+
+typedef struct musicpal_key_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t kbd_extended;
+    uint32_t pressed_keys;
+    qemu_irq out[8];
+} musicpal_key_state;
+
+static void musicpal_key_event(void *opaque, int keycode)
+{
+    musicpal_key_state *s = opaque;
+    uint32_t event = 0;
+    int i;
+
+    if (keycode == KEYCODE_EXTENDED) {
+        s->kbd_extended = 1;
+        return;
+    }
+
+    if (s->kbd_extended) {
+        switch (keycode & KEY_CODE) {
+        case KEYCODE_UP:
+            event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV;
+            break;
+
+        case KEYCODE_DOWN:
+            event = MP_KEY_WHEEL_NAV;
+            break;
+
+        case KEYCODE_LEFT:
+            event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV;
+            break;
+
+        case KEYCODE_RIGHT:
+            event = MP_KEY_WHEEL_VOL;
+            break;
+        }
+    } else {
+        switch (keycode & KEY_CODE) {
+        case KEYCODE_F:
+            event = MP_KEY_BTN_FAVORITS;
+            break;
+
+        case KEYCODE_TAB:
+            event = MP_KEY_BTN_VOLUME;
+            break;
+
+        case KEYCODE_ENTER:
+            event = MP_KEY_BTN_NAVIGATION;
+            break;
+
+        case KEYCODE_M:
+            event = MP_KEY_BTN_MENU;
+            break;
+        }
+        /* Do not repeat already pressed buttons */
+        if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
+            event = 0;
+        }
+    }
+
+    if (event) {
+        /* Raise GPIO pin first if repeating a key */
+        if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
+            for (i = 0; i <= 7; i++) {
+                if (event & (1 << i)) {
+                    qemu_set_irq(s->out[i], 1);
+                }
+            }
+        }
+        for (i = 0; i <= 7; i++) {
+            if (event & (1 << i)) {
+                qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED));
+            }
+        }
+        if (keycode & KEY_RELEASED) {
+            s->pressed_keys &= ~event;
+        } else {
+            s->pressed_keys |= event;
+        }
+    }
+
+    s->kbd_extended = 0;
+}
+
+static int musicpal_key_init(SysBusDevice *dev)
+{
+    musicpal_key_state *s = FROM_SYSBUS(musicpal_key_state, dev);
+
+    memory_region_init(&s->iomem, "dummy", 0);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    s->kbd_extended = 0;
+    s->pressed_keys = 0;
+
+    qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
+
+    qemu_add_kbd_event_handler(musicpal_key_event, s);
+
+    return 0;
+}
+
+static const VMStateDescription musicpal_key_vmsd = {
+    .name = "musicpal_key",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(kbd_extended, musicpal_key_state),
+        VMSTATE_UINT32(pressed_keys, musicpal_key_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void musicpal_key_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = musicpal_key_init;
+    dc->vmsd = &musicpal_key_vmsd;
+}
+
+static const TypeInfo musicpal_key_info = {
+    .name          = "musicpal_key",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(musicpal_key_state),
+    .class_init    = musicpal_key_class_init,
+};
+
+static struct arm_boot_info musicpal_binfo = {
+    .loader_start = 0x0,
+    .board_id = 0x20e,
+};
+
+static void musicpal_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    ARMCPU *cpu;
+    qemu_irq *cpu_pic;
+    qemu_irq pic[32];
+    DeviceState *dev;
+    DeviceState *i2c_dev;
+    DeviceState *lcd_dev;
+    DeviceState *key_dev;
+    DeviceState *wm8750_dev;
+    SysBusDevice *s;
+    i2c_bus *i2c;
+    int i;
+    unsigned long flash_size;
+    DriveInfo *dinfo;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+
+    if (!cpu_model) {
+        cpu_model = "arm926";
+    }
+    cpu = cpu_arm_init(cpu_model);
+    if (!cpu) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    cpu_pic = arm_pic_init_cpu(cpu);
+
+    /* For now we use a fixed - the original - RAM size */
+    memory_region_init_ram(ram, "musicpal.ram", MP_RAM_DEFAULT_SIZE);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(address_space_mem, 0, ram);
+
+    memory_region_init_ram(sram, "musicpal.sram", MP_SRAM_SIZE);
+    vmstate_register_ram_global(sram);
+    memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
+
+    dev = sysbus_create_simple("mv88w8618_pic", MP_PIC_BASE,
+                               cpu_pic[ARM_PIC_CPU_IRQ]);
+    for (i = 0; i < 32; i++) {
+        pic[i] = qdev_get_gpio_in(dev, i);
+    }
+    sysbus_create_varargs("mv88w8618_pit", MP_PIT_BASE, pic[MP_TIMER1_IRQ],
+                          pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ],
+                          pic[MP_TIMER4_IRQ], NULL);
+
+    if (serial_hds[0]) {
+        serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ],
+                       1825000, serial_hds[0], DEVICE_NATIVE_ENDIAN);
+    }
+    if (serial_hds[1]) {
+        serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ],
+                       1825000, serial_hds[1], DEVICE_NATIVE_ENDIAN);
+    }
+
+    /* Register flash */
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (dinfo) {
+        flash_size = bdrv_getlength(dinfo->bdrv);
+        if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&
+            flash_size != 32*1024*1024) {
+            fprintf(stderr, "Invalid flash image size\n");
+            exit(1);
+        }
+
+        /*
+         * The original U-Boot accesses the flash at 0xFE000000 instead of
+         * 0xFF800000 (if there is 8 MB flash). So remap flash access if the
+         * image is smaller than 32 MB.
+         */
+#ifdef TARGET_WORDS_BIGENDIAN
+        pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
+                              "musicpal.flash", flash_size,
+                              dinfo->bdrv, 0x10000,
+                              (flash_size + 0xffff) >> 16,
+                              MP_FLASH_SIZE_MAX / flash_size,
+                              2, 0x00BF, 0x236D, 0x0000, 0x0000,
+                              0x5555, 0x2AAA, 1);
+#else
+        pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
+                              "musicpal.flash", flash_size,
+                              dinfo->bdrv, 0x10000,
+                              (flash_size + 0xffff) >> 16,
+                              MP_FLASH_SIZE_MAX / flash_size,
+                              2, 0x00BF, 0x236D, 0x0000, 0x0000,
+                              0x5555, 0x2AAA, 0);
+#endif
+
+    }
+    sysbus_create_simple("mv88w8618_flashcfg", MP_FLASHCFG_BASE, NULL);
+
+    qemu_check_nic_model(&nd_table[0], "mv88w8618");
+    dev = qdev_create(NULL, "mv88w8618_eth");
+    qdev_set_nic_properties(dev, &nd_table[0]);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]);
+
+    sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
+
+    musicpal_misc_init(SYS_BUS_DEVICE(dev));
+
+    dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]);
+    i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
+    i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c");
+
+    lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL);
+    key_dev = sysbus_create_simple("musicpal_key", -1, NULL);
+
+    /* I2C read data */
+    qdev_connect_gpio_out(i2c_dev, 0,
+                          qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT));
+    /* I2C data */
+    qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0));
+    /* I2C clock */
+    qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1));
+
+    for (i = 0; i < 3; i++) {
+        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i));
+    }
+    for (i = 0; i < 4; i++) {
+        qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8));
+    }
+    for (i = 4; i < 8; i++) {
+        qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15));
+    }
+
+    wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR);
+    dev = qdev_create(NULL, "mv88w8618_audio");
+    s = SYS_BUS_DEVICE(dev);
+    qdev_prop_set_ptr(dev, "wm8750", wm8750_dev);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
+    sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
+
+    musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;
+    musicpal_binfo.kernel_filename = kernel_filename;
+    musicpal_binfo.kernel_cmdline = kernel_cmdline;
+    musicpal_binfo.initrd_filename = initrd_filename;
+    arm_load_kernel(cpu, &musicpal_binfo);
+}
+
+static QEMUMachine musicpal_machine = {
+    .name = "musicpal",
+    .desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)",
+    .init = musicpal_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void musicpal_machine_init(void)
+{
+    qemu_register_machine(&musicpal_machine);
+}
+
+machine_init(musicpal_machine_init);
+
+static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = mv88w8618_wlan_init;
+}
+
+static const TypeInfo mv88w8618_wlan_info = {
+    .name          = "mv88w8618_wlan",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusDevice),
+    .class_init    = mv88w8618_wlan_class_init,
+};
+
+static void musicpal_register_types(void)
+{
+    type_register_static(&mv88w8618_pic_info);
+    type_register_static(&mv88w8618_pit_info);
+    type_register_static(&mv88w8618_flashcfg_info);
+    type_register_static(&mv88w8618_eth_info);
+    type_register_static(&mv88w8618_wlan_info);
+    type_register_static(&musicpal_lcd_info);
+    type_register_static(&musicpal_gpio_info);
+    type_register_static(&musicpal_key_info);
+}
+
+type_init(musicpal_register_types)
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
new file mode 100644 (file)
index 0000000..c5bf9f9
--- /dev/null
@@ -0,0 +1,1430 @@
+/*
+ * Nokia N-series internet tablets.
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "sysemu/sysemu.h"
+#include "hw/omap.h"
+#include "hw/arm-misc.h"
+#include "hw/irq.h"
+#include "ui/console.h"
+#include "hw/boards.h"
+#include "hw/i2c.h"
+#include "hw/devices.h"
+#include "hw/flash.h"
+#include "hw/hw.h"
+#include "hw/bt.h"
+#include "hw/loader.h"
+#include "sysemu/blockdev.h"
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+
+/* Nokia N8x0 support */
+struct n800_s {
+    struct omap_mpu_state_s *mpu;
+
+    struct rfbi_chip_s blizzard;
+    struct {
+        void *opaque;
+        uint32_t (*txrx)(void *opaque, uint32_t value, int len);
+        uWireSlave *chip;
+    } ts;
+
+    int keymap[0x80];
+    DeviceState *kbd;
+
+    DeviceState *usb;
+    void *retu;
+    void *tahvo;
+    DeviceState *nand;
+};
+
+/* GPIO pins */
+#define N8X0_TUSB_ENABLE_GPIO          0
+#define N800_MMC2_WP_GPIO              8
+#define N800_UNKNOWN_GPIO0             9       /* out */
+#define N810_MMC2_VIOSD_GPIO           9
+#define N810_HEADSET_AMP_GPIO          10
+#define N800_CAM_TURN_GPIO             12
+#define N810_GPS_RESET_GPIO            12
+#define N800_BLIZZARD_POWERDOWN_GPIO   15
+#define N800_MMC1_WP_GPIO              23
+#define N810_MMC2_VSD_GPIO             23
+#define N8X0_ONENAND_GPIO              26
+#define N810_BLIZZARD_RESET_GPIO       30
+#define N800_UNKNOWN_GPIO2             53      /* out */
+#define N8X0_TUSB_INT_GPIO             58
+#define N8X0_BT_WKUP_GPIO              61
+#define N8X0_STI_GPIO                  62
+#define N8X0_CBUS_SEL_GPIO             64
+#define N8X0_CBUS_DAT_GPIO             65
+#define N8X0_CBUS_CLK_GPIO             66
+#define N8X0_WLAN_IRQ_GPIO             87
+#define N8X0_BT_RESET_GPIO             92
+#define N8X0_TEA5761_CS_GPIO           93
+#define N800_UNKNOWN_GPIO              94
+#define N810_TSC_RESET_GPIO            94
+#define N800_CAM_ACT_GPIO              95
+#define N810_GPS_WAKEUP_GPIO           95
+#define N8X0_MMC_CS_GPIO               96
+#define N8X0_WLAN_PWR_GPIO             97
+#define N8X0_BT_HOST_WKUP_GPIO         98
+#define N810_SPEAKER_AMP_GPIO          101
+#define N810_KB_LOCK_GPIO              102
+#define N800_TSC_TS_GPIO               103
+#define N810_TSC_TS_GPIO               106
+#define N8X0_HEADPHONE_GPIO            107
+#define N8X0_RETU_GPIO                 108
+#define N800_TSC_KP_IRQ_GPIO           109
+#define N810_KEYBOARD_GPIO             109
+#define N800_BAT_COVER_GPIO            110
+#define N810_SLIDE_GPIO                        110
+#define N8X0_TAHVO_GPIO                        111
+#define N800_UNKNOWN_GPIO4             112     /* out */
+#define N810_SLEEPX_LED_GPIO           112
+#define N800_TSC_RESET_GPIO            118     /* ? */
+#define N810_AIC33_RESET_GPIO          118
+#define N800_TSC_UNKNOWN_GPIO          119     /* out */
+#define N8X0_TMP105_GPIO               125
+
+/* Config */
+#define BT_UART                                0
+#define XLDR_LL_UART                   1
+
+/* Addresses on the I2C bus 0 */
+#define N810_TLV320AIC33_ADDR          0x18    /* Audio CODEC */
+#define N8X0_TCM825x_ADDR              0x29    /* Camera */
+#define N810_LP5521_ADDR               0x32    /* LEDs */
+#define N810_TSL2563_ADDR              0x3d    /* Light sensor */
+#define N810_LM8323_ADDR               0x45    /* Keyboard */
+/* Addresses on the I2C bus 1 */
+#define N8X0_TMP105_ADDR               0x48    /* Temperature sensor */
+#define N8X0_MENELAUS_ADDR             0x72    /* Power management */
+
+/* Chipselects on GPMC NOR interface */
+#define N8X0_ONENAND_CS                        0
+#define N8X0_USB_ASYNC_CS              1
+#define N8X0_USB_SYNC_CS               4
+
+#define N8X0_BD_ADDR                   0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81
+
+static void n800_mmc_cs_cb(void *opaque, int line, int level)
+{
+    /* TODO: this seems to actually be connected to the menelaus, to
+     * which also both MMC slots connect.  */
+    omap_mmc_enable((struct omap_mmc_s *) opaque, !level);
+
+    printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1);
+}
+
+static void n8x0_gpio_setup(struct n800_s *s)
+{
+    qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->mpu->mmc, 1);
+    qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]);
+
+    qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO));
+}
+
+#define MAEMO_CAL_HEADER(...)                          \
+    'C',  'o',  'n',  'F',  0x02, 0x00, 0x04, 0x00,    \
+    __VA_ARGS__,                                       \
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+static const uint8_t n8x0_cal_wlan_mac[] = {
+    MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c')
+    0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3,
+    0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+    0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
+    0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t n8x0_cal_bt_id[] = {
+    MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0)
+    0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96,
+    0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00,
+    N8X0_BD_ADDR,
+};
+
+static void n8x0_nand_setup(struct n800_s *s)
+{
+    char *otp_region;
+    DriveInfo *dinfo;
+
+    s->nand = qdev_create(NULL, "onenand");
+    qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG);
+    /* Either 0x40 or 0x48 are OK for the device ID */
+    qdev_prop_set_uint16(s->nand, "device_id", 0x48);
+    qdev_prop_set_uint16(s->nand, "version_id", 0);
+    qdev_prop_set_int32(s->nand, "shift", 1);
+    dinfo = drive_get(IF_MTD, 0, 0);
+    if (dinfo && dinfo->bdrv) {
+        qdev_prop_set_drive_nofail(s->nand, "drive", dinfo->bdrv);
+    }
+    qdev_init_nofail(s->nand);
+    sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0,
+                       qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO));
+    omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS,
+                     sysbus_mmio_get_region(SYS_BUS_DEVICE(s->nand), 0));
+    otp_region = onenand_raw_otp(s->nand);
+
+    memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
+    memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id));
+    /* XXX: in theory should also update the OOB for both pages */
+}
+
+static qemu_irq n8x0_system_powerdown;
+
+static void n8x0_powerdown_req(Notifier *n, void *opaque)
+{
+    qemu_irq_raise(n8x0_system_powerdown);
+}
+
+static Notifier n8x0_system_powerdown_notifier = {
+    .notify = n8x0_powerdown_req
+};
+
+static void n8x0_i2c_setup(struct n800_s *s)
+{
+    DeviceState *dev;
+    qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO);
+    i2c_bus *i2c = omap_i2c_bus(s->mpu->i2c[0]);
+
+    /* Attach a menelaus PM chip */
+    dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR);
+    qdev_connect_gpio_out(dev, 3,
+                          qdev_get_gpio_in(s->mpu->ih[0],
+                                           OMAP_INT_24XX_SYS_NIRQ));
+
+    n8x0_system_powerdown = qdev_get_gpio_in(dev, 3);
+    qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier);
+
+    /* Attach a TMP105 PM chip (A0 wired to ground) */
+    dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR);
+    qdev_connect_gpio_out(dev, 0, tmp_irq);
+}
+
+/* Touchscreen and keypad controller */
+static MouseTransformInfo n800_pointercal = {
+    .x = 800,
+    .y = 480,
+    .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
+};
+
+static MouseTransformInfo n810_pointercal = {
+    .x = 800,
+    .y = 480,
+    .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
+};
+
+#define RETU_KEYCODE   61      /* F3 */
+
+static void n800_key_event(void *opaque, int keycode)
+{
+    struct n800_s *s = (struct n800_s *) opaque;
+    int code = s->keymap[keycode & 0x7f];
+
+    if (code == -1) {
+        if ((keycode & 0x7f) == RETU_KEYCODE)
+            retu_key_event(s->retu, !(keycode & 0x80));
+        return;
+    }
+
+    tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80));
+}
+
+static const int n800_keys[16] = {
+    -1,
+    72,        /* Up */
+    63,        /* Home (F5) */
+    -1,
+    75,        /* Left */
+    28,        /* Enter */
+    77,        /* Right */
+    -1,
+     1,        /* Cycle (ESC) */
+    80,        /* Down */
+    62,        /* Menu (F4) */
+    -1,
+    66,        /* Zoom- (F8) */
+    64,        /* FullScreen (F6) */
+    65,        /* Zoom+ (F7) */
+    -1,
+};
+
+static void n800_tsc_kbd_setup(struct n800_s *s)
+{
+    int i;
+
+    /* XXX: are the three pins inverted inside the chip between the
+     * tsc and the cpu (N4111)?  */
+    qemu_irq penirq = NULL;    /* NC */
+    qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO);
+    qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO);
+
+    s->ts.chip = tsc2301_init(penirq, kbirq, dav);
+    s->ts.opaque = s->ts.chip->opaque;
+    s->ts.txrx = tsc210x_txrx;
+
+    for (i = 0; i < 0x80; i ++)
+        s->keymap[i] = -1;
+    for (i = 0; i < 0x10; i ++)
+        if (n800_keys[i] >= 0)
+            s->keymap[n800_keys[i]] = i;
+
+    qemu_add_kbd_event_handler(n800_key_event, s);
+
+    tsc210x_set_transform(s->ts.chip, &n800_pointercal);
+}
+
+static void n810_tsc_setup(struct n800_s *s)
+{
+    qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO);
+
+    s->ts.opaque = tsc2005_init(pintdav);
+    s->ts.txrx = tsc2005_txrx;
+
+    tsc2005_set_transform(s->ts.opaque, &n810_pointercal);
+}
+
+/* N810 Keyboard controller */
+static void n810_key_event(void *opaque, int keycode)
+{
+    struct n800_s *s = (struct n800_s *) opaque;
+    int code = s->keymap[keycode & 0x7f];
+
+    if (code == -1) {
+        if ((keycode & 0x7f) == RETU_KEYCODE)
+            retu_key_event(s->retu, !(keycode & 0x80));
+        return;
+    }
+
+    lm832x_key_event(s->kbd, code, !(keycode & 0x80));
+}
+
+#define M      0
+
+static int n810_keys[0x80] = {
+    [0x01] = 16,       /* Q */
+    [0x02] = 37,       /* K */
+    [0x03] = 24,       /* O */
+    [0x04] = 25,       /* P */
+    [0x05] = 14,       /* Backspace */
+    [0x06] = 30,       /* A */
+    [0x07] = 31,       /* S */
+    [0x08] = 32,       /* D */
+    [0x09] = 33,       /* F */
+    [0x0a] = 34,       /* G */
+    [0x0b] = 35,       /* H */
+    [0x0c] = 36,       /* J */
+
+    [0x11] = 17,       /* W */
+    [0x12] = 62,       /* Menu (F4) */
+    [0x13] = 38,       /* L */
+    [0x14] = 40,       /* ' (Apostrophe) */
+    [0x16] = 44,       /* Z */
+    [0x17] = 45,       /* X */
+    [0x18] = 46,       /* C */
+    [0x19] = 47,       /* V */
+    [0x1a] = 48,       /* B */
+    [0x1b] = 49,       /* N */
+    [0x1c] = 42,       /* Shift (Left shift) */
+    [0x1f] = 65,       /* Zoom+ (F7) */
+
+    [0x21] = 18,       /* E */
+    [0x22] = 39,       /* ; (Semicolon) */
+    [0x23] = 12,       /* - (Minus) */
+    [0x24] = 13,       /* = (Equal) */
+    [0x2b] = 56,       /* Fn (Left Alt) */
+    [0x2c] = 50,       /* M */
+    [0x2f] = 66,       /* Zoom- (F8) */
+
+    [0x31] = 19,       /* R */
+    [0x32] = 29 | M,   /* Right Ctrl */
+    [0x34] = 57,       /* Space */
+    [0x35] = 51,       /* , (Comma) */
+    [0x37] = 72 | M,   /* Up */
+    [0x3c] = 82 | M,   /* Compose (Insert) */
+    [0x3f] = 64,       /* FullScreen (F6) */
+
+    [0x41] = 20,       /* T */
+    [0x44] = 52,       /* . (Dot) */
+    [0x46] = 77 | M,   /* Right */
+    [0x4f] = 63,       /* Home (F5) */
+    [0x51] = 21,       /* Y */
+    [0x53] = 80 | M,   /* Down */
+    [0x55] = 28,       /* Enter */
+    [0x5f] =  1,       /* Cycle (ESC) */
+
+    [0x61] = 22,       /* U */
+    [0x64] = 75 | M,   /* Left */
+
+    [0x71] = 23,       /* I */
+#if 0
+    [0x75] = 28 | M,   /* KP Enter (KP Enter) */
+#else
+    [0x75] = 15,       /* KP Enter (Tab) */
+#endif
+};
+
+#undef M
+
+static void n810_kbd_setup(struct n800_s *s)
+{
+    qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO);
+    int i;
+
+    for (i = 0; i < 0x80; i ++)
+        s->keymap[i] = -1;
+    for (i = 0; i < 0x80; i ++)
+        if (n810_keys[i] > 0)
+            s->keymap[n810_keys[i]] = i;
+
+    qemu_add_kbd_event_handler(n810_key_event, s);
+
+    /* Attach the LM8322 keyboard to the I2C bus,
+     * should happen in n8x0_i2c_setup and s->kbd be initialised here.  */
+    s->kbd = i2c_create_slave(omap_i2c_bus(s->mpu->i2c[0]),
+                           "lm8323", N810_LM8323_ADDR);
+    qdev_connect_gpio_out(s->kbd, 0, kbd_irq);
+}
+
+/* LCD MIPI DBI-C controller (URAL) */
+struct mipid_s {
+    int resp[4];
+    int param[4];
+    int p;
+    int pm;
+    int cmd;
+
+    int sleep;
+    int booster;
+    int te;
+    int selfcheck;
+    int partial;
+    int normal;
+    int vscr;
+    int invert;
+    int onoff;
+    int gamma;
+    uint32_t id;
+};
+
+static void mipid_reset(struct mipid_s *s)
+{
+    if (!s->sleep)
+        fprintf(stderr, "%s: Display off\n", __FUNCTION__);
+
+    s->pm = 0;
+    s->cmd = 0;
+
+    s->sleep = 1;
+    s->booster = 0;
+    s->selfcheck =
+            (1 << 7) | /* Register loading OK.  */
+            (1 << 5) | /* The chip is attached.  */
+            (1 << 4);  /* Display glass still in one piece.  */
+    s->te = 0;
+    s->partial = 0;
+    s->normal = 1;
+    s->vscr = 0;
+    s->invert = 0;
+    s->onoff = 1;
+    s->gamma = 0;
+}
+
+static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
+{
+    struct mipid_s *s = (struct mipid_s *) opaque;
+    uint8_t ret;
+
+    if (len > 9)
+        hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len);
+
+    if (s->p >= ARRAY_SIZE(s->resp))
+        ret = 0;
+    else
+        ret = s->resp[s->p ++];
+    if (s->pm --> 0)
+        s->param[s->pm] = cmd;
+    else
+        s->cmd = cmd;
+
+    switch (s->cmd) {
+    case 0x00: /* NOP */
+        break;
+
+    case 0x01: /* SWRESET */
+        mipid_reset(s);
+        break;
+
+    case 0x02: /* BSTROFF */
+        s->booster = 0;
+        break;
+    case 0x03: /* BSTRON */
+        s->booster = 1;
+        break;
+
+    case 0x04: /* RDDID */
+        s->p = 0;
+        s->resp[0] = (s->id >> 16) & 0xff;
+        s->resp[1] = (s->id >>  8) & 0xff;
+        s->resp[2] = (s->id >>  0) & 0xff;
+        break;
+
+    case 0x06: /* RD_RED */
+    case 0x07: /* RD_GREEN */
+        /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so
+         * for the bootloader one needs to change this.  */
+    case 0x08: /* RD_BLUE */
+        s->p = 0;
+        /* TODO: return first pixel components */
+        s->resp[0] = 0x01;
+        break;
+
+    case 0x09: /* RDDST */
+        s->p = 0;
+        s->resp[0] = s->booster << 7;
+        s->resp[1] = (5 << 4) | (s->partial << 2) |
+                (s->sleep << 1) | s->normal;
+        s->resp[2] = (s->vscr << 7) | (s->invert << 5) |
+                (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2);
+        s->resp[3] = s->gamma << 6;
+        break;
+
+    case 0x0a: /* RDDPM */
+        s->p = 0;
+        s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) |
+                (s->partial << 5) | (s->sleep << 6) | (s->booster << 7);
+        break;
+    case 0x0b: /* RDDMADCTR */
+        s->p = 0;
+        s->resp[0] = 0;
+        break;
+    case 0x0c: /* RDDCOLMOD */
+        s->p = 0;
+        s->resp[0] = 5;        /* 65K colours */
+        break;
+    case 0x0d: /* RDDIM */
+        s->p = 0;
+        s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma;
+        break;
+    case 0x0e: /* RDDSM */
+        s->p = 0;
+        s->resp[0] = s->te << 7;
+        break;
+    case 0x0f: /* RDDSDR */
+        s->p = 0;
+        s->resp[0] = s->selfcheck;
+        break;
+
+    case 0x10: /* SLPIN */
+        s->sleep = 1;
+        break;
+    case 0x11: /* SLPOUT */
+        s->sleep = 0;
+        s->selfcheck ^= 1 << 6;        /* POFF self-diagnosis Ok */
+        break;
+
+    case 0x12: /* PTLON */
+        s->partial = 1;
+        s->normal = 0;
+        s->vscr = 0;
+        break;
+    case 0x13: /* NORON */
+        s->partial = 0;
+        s->normal = 1;
+        s->vscr = 0;
+        break;
+
+    case 0x20: /* INVOFF */
+        s->invert = 0;
+        break;
+    case 0x21: /* INVON */
+        s->invert = 1;
+        break;
+
+    case 0x22: /* APOFF */
+    case 0x23: /* APON */
+        goto bad_cmd;
+
+    case 0x25: /* WRCNTR */
+        if (s->pm < 0)
+            s->pm = 1;
+        goto bad_cmd;
+
+    case 0x26: /* GAMSET */
+        if (!s->pm)
+            s->gamma = ffs(s->param[0] & 0xf) - 1;
+        else if (s->pm < 0)
+            s->pm = 1;
+        break;
+
+    case 0x28: /* DISPOFF */
+        s->onoff = 0;
+        fprintf(stderr, "%s: Display off\n", __FUNCTION__);
+        break;
+    case 0x29: /* DISPON */
+        s->onoff = 1;
+        fprintf(stderr, "%s: Display on\n", __FUNCTION__);
+        break;
+
+    case 0x2a: /* CASET */
+    case 0x2b: /* RASET */
+    case 0x2c: /* RAMWR */
+    case 0x2d: /* RGBSET */
+    case 0x2e: /* RAMRD */
+    case 0x30: /* PTLAR */
+    case 0x33: /* SCRLAR */
+        goto bad_cmd;
+
+    case 0x34: /* TEOFF */
+        s->te = 0;
+        break;
+    case 0x35: /* TEON */
+        if (!s->pm)
+            s->te = 1;
+        else if (s->pm < 0)
+            s->pm = 1;
+        break;
+
+    case 0x36: /* MADCTR */
+        goto bad_cmd;
+
+    case 0x37: /* VSCSAD */
+        s->partial = 0;
+        s->normal = 0;
+        s->vscr = 1;
+        break;
+
+    case 0x38: /* IDMOFF */
+    case 0x39: /* IDMON */
+    case 0x3a: /* COLMOD */
+        goto bad_cmd;
+
+    case 0xb0: /* CLKINT / DISCTL */
+    case 0xb1: /* CLKEXT */
+        if (s->pm < 0)
+            s->pm = 2;
+        break;
+
+    case 0xb4: /* FRMSEL */
+        break;
+
+    case 0xb5: /* FRM8SEL */
+    case 0xb6: /* TMPRNG / INIESC */
+    case 0xb7: /* TMPHIS / NOP2 */
+    case 0xb8: /* TMPREAD / MADCTL */
+    case 0xba: /* DISTCTR */
+    case 0xbb: /* EPVOL */
+        goto bad_cmd;
+
+    case 0xbd: /* Unknown */
+        s->p = 0;
+        s->resp[0] = 0;
+        s->resp[1] = 1;
+        break;
+
+    case 0xc2: /* IFMOD */
+        if (s->pm < 0)
+            s->pm = 2;
+        break;
+
+    case 0xc6: /* PWRCTL */
+    case 0xc7: /* PPWRCTL */
+    case 0xd0: /* EPWROUT */
+    case 0xd1: /* EPWRIN */
+    case 0xd4: /* RDEV */
+    case 0xd5: /* RDRR */
+        goto bad_cmd;
+
+    case 0xda: /* RDID1 */
+        s->p = 0;
+        s->resp[0] = (s->id >> 16) & 0xff;
+        break;
+    case 0xdb: /* RDID2 */
+        s->p = 0;
+        s->resp[0] = (s->id >>  8) & 0xff;
+        break;
+    case 0xdc: /* RDID3 */
+        s->p = 0;
+        s->resp[0] = (s->id >>  0) & 0xff;
+        break;
+
+    default:
+    bad_cmd:
+        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd);
+        break;
+    }
+
+    return ret;
+}
+
+static void *mipid_init(void)
+{
+    struct mipid_s *s = (struct mipid_s *) g_malloc0(sizeof(*s));
+
+    s->id = 0x838f03;
+    mipid_reset(s);
+
+    return s;
+}
+
+static void n8x0_spi_setup(struct n800_s *s)
+{
+    void *tsc = s->ts.opaque;
+    void *mipid = mipid_init();
+
+    omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0);
+    omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1);
+}
+
+/* This task is normally performed by the bootloader.  If we're loading
+ * a kernel directly, we need to enable the Blizzard ourselves.  */
+static void n800_dss_init(struct rfbi_chip_s *chip)
+{
+    uint8_t *fb_blank;
+
+    chip->write(chip->opaque, 0, 0x2a);                /* LCD Width register */
+    chip->write(chip->opaque, 1, 0x64);
+    chip->write(chip->opaque, 0, 0x2c);                /* LCD HNDP register */
+    chip->write(chip->opaque, 1, 0x1e);
+    chip->write(chip->opaque, 0, 0x2e);                /* LCD Height 0 register */
+    chip->write(chip->opaque, 1, 0xe0);
+    chip->write(chip->opaque, 0, 0x30);                /* LCD Height 1 register */
+    chip->write(chip->opaque, 1, 0x01);
+    chip->write(chip->opaque, 0, 0x32);                /* LCD VNDP register */
+    chip->write(chip->opaque, 1, 0x06);
+    chip->write(chip->opaque, 0, 0x68);                /* Display Mode register */
+    chip->write(chip->opaque, 1, 1);           /* Enable bit */
+
+    chip->write(chip->opaque, 0, 0x6c);        
+    chip->write(chip->opaque, 1, 0x00);                /* Input X Start Position */
+    chip->write(chip->opaque, 1, 0x00);                /* Input X Start Position */
+    chip->write(chip->opaque, 1, 0x00);                /* Input Y Start Position */
+    chip->write(chip->opaque, 1, 0x00);                /* Input Y Start Position */
+    chip->write(chip->opaque, 1, 0x1f);                /* Input X End Position */
+    chip->write(chip->opaque, 1, 0x03);                /* Input X End Position */
+    chip->write(chip->opaque, 1, 0xdf);                /* Input Y End Position */
+    chip->write(chip->opaque, 1, 0x01);                /* Input Y End Position */
+    chip->write(chip->opaque, 1, 0x00);                /* Output X Start Position */
+    chip->write(chip->opaque, 1, 0x00);                /* Output X Start Position */
+    chip->write(chip->opaque, 1, 0x00);                /* Output Y Start Position */
+    chip->write(chip->opaque, 1, 0x00);                /* Output Y Start Position */
+    chip->write(chip->opaque, 1, 0x1f);                /* Output X End Position */
+    chip->write(chip->opaque, 1, 0x03);                /* Output X End Position */
+    chip->write(chip->opaque, 1, 0xdf);                /* Output Y End Position */
+    chip->write(chip->opaque, 1, 0x01);                /* Output Y End Position */
+    chip->write(chip->opaque, 1, 0x01);                /* Input Data Format */
+    chip->write(chip->opaque, 1, 0x01);                /* Data Source Select */
+
+    fb_blank = memset(g_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
+    /* Display Memory Data Port */
+    chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800);
+    g_free(fb_blank);
+}
+
+static void n8x0_dss_setup(struct n800_s *s)
+{
+    s->blizzard.opaque = s1d13745_init(NULL);
+    s->blizzard.block = s1d13745_write_block;
+    s->blizzard.write = s1d13745_write;
+    s->blizzard.read = s1d13745_read;
+
+    omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard);
+}
+
+static void n8x0_cbus_setup(struct n800_s *s)
+{
+    qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO);
+    qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO);
+    qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO);
+
+    CBus *cbus = cbus_init(dat_out);
+
+    qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk);
+    qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat);
+    qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel);
+
+    cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
+    cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
+}
+
+static void n8x0_uart_setup(struct n800_s *s)
+{
+    CharDriverState *radio = uart_hci_init(
+                    qdev_get_gpio_in(s->mpu->gpio, N8X0_BT_HOST_WKUP_GPIO));
+
+    qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO,
+                    csrhci_pins_get(radio)[csrhci_pin_reset]);
+    qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_WKUP_GPIO,
+                    csrhci_pins_get(radio)[csrhci_pin_wakeup]);
+
+    omap_uart_attach(s->mpu->uart[BT_UART], radio);
+}
+
+static void n8x0_usb_setup(struct n800_s *s)
+{
+    SysBusDevice *dev;
+    s->usb = qdev_create(NULL, "tusb6010");
+    dev = SYS_BUS_DEVICE(s->usb);
+    qdev_init_nofail(s->usb);
+    sysbus_connect_irq(dev, 0,
+                       qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO));
+    /* Using the NOR interface */
+    omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS,
+                     sysbus_mmio_get_region(dev, 0));
+    omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS,
+                     sysbus_mmio_get_region(dev, 1));
+    qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO,
+                          qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */
+}
+
+/* Setup done before the main bootloader starts by some early setup code
+ * - used when we want to run the main bootloader in emulation.  This
+ * isn't documented.  */
+static uint32_t n800_pinout[104] = {
+    0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
+    0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
+    0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
+    0x080800bc, 0x00cc0808, 0x08081818, 0x18180128,
+    0x01241800, 0x18181818, 0x000000f0, 0x01300000,
+    0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b,
+    0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080,
+    0x007c0000, 0x00000000, 0x00000088, 0x00840000,
+    0x00000000, 0x00000094, 0x00980300, 0x0f180003,
+    0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c,
+    0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008,
+    0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f,
+    0x181800f4, 0x00f81818, 0x00000018, 0x000000fc,
+    0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008,
+    0x00000000, 0x00000038, 0x00340000, 0x00000000,
+    0x1a080070, 0x00641a1a, 0x08080808, 0x08080060,
+    0x005c0808, 0x08080808, 0x08080058, 0x00540808,
+    0x08080808, 0x0808006c, 0x00680808, 0x08080808,
+    0x000000a8, 0x00b00000, 0x08080808, 0x000000a0,
+    0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808,
+    0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff,
+    0x000000ac, 0x01040800, 0x08080b0f, 0x18180100,
+    0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a,
+    0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00,
+    0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118,
+    0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b,
+};
+
+static void n800_setup_nolo_tags(void *sram_base)
+{
+    int i;
+    uint32_t *p = sram_base + 0x8000;
+    uint32_t *v = sram_base + 0xa000;
+
+    memset(p, 0, 0x3000);
+
+    strcpy((void *) (p + 0), "QEMU N800");
+
+    strcpy((void *) (p + 8), "F5");
+
+    stl_raw(p + 10, 0x04f70000);
+    strcpy((void *) (p + 9), "RX-34");
+
+    /* RAM size in MB? */
+    stl_raw(p + 12, 0x80);
+
+    /* Pointer to the list of tags */
+    stl_raw(p + 13, OMAP2_SRAM_BASE + 0x9000);
+
+    /* The NOLO tags start here */
+    p = sram_base + 0x9000;
+#define ADD_TAG(tag, len)                              \
+    stw_raw((uint16_t *) p + 0, tag);                  \
+    stw_raw((uint16_t *) p + 1, len); p ++;            \
+    stl_raw(p ++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff));
+
+    /* OMAP STI console? Pin out settings? */
+    ADD_TAG(0x6e01, 414);
+    for (i = 0; i < ARRAY_SIZE(n800_pinout); i ++)
+        stl_raw(v ++, n800_pinout[i]);
+
+    /* Kernel memsize? */
+    ADD_TAG(0x6e05, 1);
+    stl_raw(v ++, 2);
+
+    /* NOLO serial console */
+    ADD_TAG(0x6e02, 4);
+    stl_raw(v ++, XLDR_LL_UART);       /* UART number (1 - 3) */
+
+#if 0
+    /* CBUS settings (Retu/AVilma) */
+    ADD_TAG(0x6e03, 6);
+    stw_raw((uint16_t *) v + 0, 65);   /* CBUS GPIO0 */
+    stw_raw((uint16_t *) v + 1, 66);   /* CBUS GPIO1 */
+    stw_raw((uint16_t *) v + 2, 64);   /* CBUS GPIO2 */
+    v += 2;
+#endif
+
+    /* Nokia ASIC BB5 (Retu/Tahvo) */
+    ADD_TAG(0x6e0a, 4);
+    stw_raw((uint16_t *) v + 0, 111);  /* "Retu" interrupt GPIO */
+    stw_raw((uint16_t *) v + 1, 108);  /* "Tahvo" interrupt GPIO */
+    v ++;
+
+    /* LCD console? */
+    ADD_TAG(0x6e04, 4);
+    stw_raw((uint16_t *) v + 0, 30);   /* ??? */
+    stw_raw((uint16_t *) v + 1, 24);   /* ??? */
+    v ++;
+
+#if 0
+    /* LCD settings */
+    ADD_TAG(0x6e06, 2);
+    stw_raw((uint16_t *) (v ++), 15);  /* ??? */
+#endif
+
+    /* I^2C (Menelaus) */
+    ADD_TAG(0x6e07, 4);
+    stl_raw(v ++, 0x00720000);         /* ??? */
+
+    /* Unknown */
+    ADD_TAG(0x6e0b, 6);
+    stw_raw((uint16_t *) v + 0, 94);   /* ??? */
+    stw_raw((uint16_t *) v + 1, 23);   /* ??? */
+    stw_raw((uint16_t *) v + 2, 0);    /* ??? */
+    v += 2;
+
+    /* OMAP gpio switch info */
+    ADD_TAG(0x6e0c, 80);
+    strcpy((void *) v, "bat_cover");   v += 3;
+    stw_raw((uint16_t *) v + 0, 110);  /* GPIO num ??? */
+    stw_raw((uint16_t *) v + 1, 1);    /* GPIO num ??? */
+    v += 2;
+    strcpy((void *) v, "cam_act");     v += 3;
+    stw_raw((uint16_t *) v + 0, 95);   /* GPIO num ??? */
+    stw_raw((uint16_t *) v + 1, 32);   /* GPIO num ??? */
+    v += 2;
+    strcpy((void *) v, "cam_turn");    v += 3;
+    stw_raw((uint16_t *) v + 0, 12);   /* GPIO num ??? */
+    stw_raw((uint16_t *) v + 1, 33);   /* GPIO num ??? */
+    v += 2;
+    strcpy((void *) v, "headphone");   v += 3;
+    stw_raw((uint16_t *) v + 0, 107);  /* GPIO num ??? */
+    stw_raw((uint16_t *) v + 1, 17);   /* GPIO num ??? */
+    v += 2;
+
+    /* Bluetooth */
+    ADD_TAG(0x6e0e, 12);
+    stl_raw(v ++, 0x5c623d01);         /* ??? */
+    stl_raw(v ++, 0x00000201);         /* ??? */
+    stl_raw(v ++, 0x00000000);         /* ??? */
+
+    /* CX3110x WLAN settings */
+    ADD_TAG(0x6e0f, 8);
+    stl_raw(v ++, 0x00610025);         /* ??? */
+    stl_raw(v ++, 0xffff0057);         /* ??? */
+
+    /* MMC host settings */
+    ADD_TAG(0x6e10, 12);
+    stl_raw(v ++, 0xffff000f);         /* ??? */
+    stl_raw(v ++, 0xffffffff);         /* ??? */
+    stl_raw(v ++, 0x00000060);         /* ??? */
+
+    /* OneNAND chip select */
+    ADD_TAG(0x6e11, 10);
+    stl_raw(v ++, 0x00000401);         /* ??? */
+    stl_raw(v ++, 0x0002003a);         /* ??? */
+    stl_raw(v ++, 0x00000002);         /* ??? */
+
+    /* TEA5761 sensor settings */
+    ADD_TAG(0x6e12, 2);
+    stl_raw(v ++, 93);                 /* GPIO num ??? */
+
+#if 0
+    /* Unknown tag */
+    ADD_TAG(6e09, 0);
+
+    /* Kernel UART / console */
+    ADD_TAG(6e12, 0);
+#endif
+
+    /* End of the list */
+    stl_raw(p ++, 0x00000000);
+    stl_raw(p ++, 0x00000000);
+}
+
+/* This task is normally performed by the bootloader.  If we're loading
+ * a kernel directly, we need to set up GPMC mappings ourselves.  */
+static void n800_gpmc_init(struct n800_s *s)
+{
+    uint32_t config7 =
+            (0xf << 8) |       /* MASKADDRESS */
+            (1 << 6) |         /* CSVALID */
+            (4 << 0);          /* BASEADDRESS */
+
+    cpu_physical_memory_write(0x6800a078,              /* GPMC_CONFIG7_0 */
+                    (void *) &config7, sizeof(config7));
+}
+
+/* Setup sequence done by the bootloader */
+static void n8x0_boot_init(void *opaque)
+{
+    struct n800_s *s = (struct n800_s *) opaque;
+    uint32_t buf;
+
+    /* PRCM setup */
+#define omap_writel(addr, val) \
+    buf = (val);                       \
+    cpu_physical_memory_write(addr, (void *) &buf, sizeof(buf))
+
+    omap_writel(0x48008060, 0x41);             /* PRCM_CLKSRC_CTRL */
+    omap_writel(0x48008070, 1);                        /* PRCM_CLKOUT_CTRL */
+    omap_writel(0x48008078, 0);                        /* PRCM_CLKEMUL_CTRL */
+    omap_writel(0x48008090, 0);                        /* PRCM_VOLTSETUP */
+    omap_writel(0x48008094, 0);                        /* PRCM_CLKSSETUP */
+    omap_writel(0x48008098, 0);                        /* PRCM_POLCTRL */
+    omap_writel(0x48008140, 2);                        /* CM_CLKSEL_MPU */
+    omap_writel(0x48008148, 0);                        /* CM_CLKSTCTRL_MPU */
+    omap_writel(0x48008158, 1);                        /* RM_RSTST_MPU */
+    omap_writel(0x480081c8, 0x15);             /* PM_WKDEP_MPU */
+    omap_writel(0x480081d4, 0x1d4);            /* PM_EVGENCTRL_MPU */
+    omap_writel(0x480081d8, 0);                        /* PM_EVEGENONTIM_MPU */
+    omap_writel(0x480081dc, 0);                        /* PM_EVEGENOFFTIM_MPU */
+    omap_writel(0x480081e0, 0xc);              /* PM_PWSTCTRL_MPU */
+    omap_writel(0x48008200, 0x047e7ff7);       /* CM_FCLKEN1_CORE */
+    omap_writel(0x48008204, 0x00000004);       /* CM_FCLKEN2_CORE */
+    omap_writel(0x48008210, 0x047e7ff1);       /* CM_ICLKEN1_CORE */
+    omap_writel(0x48008214, 0x00000004);       /* CM_ICLKEN2_CORE */
+    omap_writel(0x4800821c, 0x00000000);       /* CM_ICLKEN4_CORE */
+    omap_writel(0x48008230, 0);                        /* CM_AUTOIDLE1_CORE */
+    omap_writel(0x48008234, 0);                        /* CM_AUTOIDLE2_CORE */
+    omap_writel(0x48008238, 7);                        /* CM_AUTOIDLE3_CORE */
+    omap_writel(0x4800823c, 0);                        /* CM_AUTOIDLE4_CORE */
+    omap_writel(0x48008240, 0x04360626);       /* CM_CLKSEL1_CORE */
+    omap_writel(0x48008244, 0x00000014);       /* CM_CLKSEL2_CORE */
+    omap_writel(0x48008248, 0);                        /* CM_CLKSTCTRL_CORE */
+    omap_writel(0x48008300, 0x00000000);       /* CM_FCLKEN_GFX */
+    omap_writel(0x48008310, 0x00000000);       /* CM_ICLKEN_GFX */
+    omap_writel(0x48008340, 0x00000001);       /* CM_CLKSEL_GFX */
+    omap_writel(0x48008400, 0x00000004);       /* CM_FCLKEN_WKUP */
+    omap_writel(0x48008410, 0x00000004);       /* CM_ICLKEN_WKUP */
+    omap_writel(0x48008440, 0x00000000);       /* CM_CLKSEL_WKUP */
+    omap_writel(0x48008500, 0x000000cf);       /* CM_CLKEN_PLL */
+    omap_writel(0x48008530, 0x0000000c);       /* CM_AUTOIDLE_PLL */
+    omap_writel(0x48008540,                    /* CM_CLKSEL1_PLL */
+                    (0x78 << 12) | (6 << 8));
+    omap_writel(0x48008544, 2);                        /* CM_CLKSEL2_PLL */
+
+    /* GPMC setup */
+    n800_gpmc_init(s);
+
+    /* Video setup */
+    n800_dss_init(&s->blizzard);
+
+    /* CPU setup */
+    s->mpu->cpu->env.GE = 0x5;
+
+    /* If the machine has a slided keyboard, open it */
+    if (s->kbd)
+        qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO));
+}
+
+#define OMAP_TAG_NOKIA_BT      0x4e01
+#define OMAP_TAG_WLAN_CX3110X  0x4e02
+#define OMAP_TAG_CBUS          0x4e03
+#define OMAP_TAG_EM_ASIC_BB5   0x4e04
+
+static struct omap_gpiosw_info_s {
+    const char *name;
+    int line;
+    int type;
+} n800_gpiosw_info[] = {
+    {
+        "bat_cover", N800_BAT_COVER_GPIO,
+        OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
+    }, {
+        "cam_act", N800_CAM_ACT_GPIO,
+        OMAP_GPIOSW_TYPE_ACTIVITY,
+    }, {
+        "cam_turn", N800_CAM_TURN_GPIO,
+        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED,
+    }, {
+        "headphone", N8X0_HEADPHONE_GPIO,
+        OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
+    },
+    { NULL }
+}, n810_gpiosw_info[] = {
+    {
+        "gps_reset", N810_GPS_RESET_GPIO,
+        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
+    }, {
+        "gps_wakeup", N810_GPS_WAKEUP_GPIO,
+        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
+    }, {
+        "headphone", N8X0_HEADPHONE_GPIO,
+        OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
+    }, {
+        "kb_lock", N810_KB_LOCK_GPIO,
+        OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
+    }, {
+        "sleepx_led", N810_SLEEPX_LED_GPIO,
+        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT,
+    }, {
+        "slide", N810_SLIDE_GPIO,
+        OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
+    },
+    { NULL }
+};
+
+static struct omap_partition_info_s {
+    uint32_t offset;
+    uint32_t size;
+    int mask;
+    const char *name;
+} n800_part_info[] = {
+    { 0x00000000, 0x00020000, 0x3, "bootloader" },
+    { 0x00020000, 0x00060000, 0x0, "config" },
+    { 0x00080000, 0x00200000, 0x0, "kernel" },
+    { 0x00280000, 0x00200000, 0x3, "initfs" },
+    { 0x00480000, 0x0fb80000, 0x3, "rootfs" },
+
+    { 0, 0, 0, NULL }
+}, n810_part_info[] = {
+    { 0x00000000, 0x00020000, 0x3, "bootloader" },
+    { 0x00020000, 0x00060000, 0x0, "config" },
+    { 0x00080000, 0x00220000, 0x0, "kernel" },
+    { 0x002a0000, 0x00400000, 0x0, "initfs" },
+    { 0x006a0000, 0x0f960000, 0x0, "rootfs" },
+
+    { 0, 0, 0, NULL }
+};
+
+static bdaddr_t n8x0_bd_addr = {{ N8X0_BD_ADDR }};
+
+static int n8x0_atag_setup(void *p, int model)
+{
+    uint8_t *b;
+    uint16_t *w;
+    uint32_t *l;
+    struct omap_gpiosw_info_s *gpiosw;
+    struct omap_partition_info_s *partition;
+    const char *tag;
+
+    w = p;
+
+    stw_raw(w ++, OMAP_TAG_UART);              /* u16 tag */
+    stw_raw(w ++, 4);                          /* u16 len */
+    stw_raw(w ++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */
+    w ++;
+
+#if 0
+    stw_raw(w ++, OMAP_TAG_SERIAL_CONSOLE);    /* u16 tag */
+    stw_raw(w ++, 4);                          /* u16 len */
+    stw_raw(w ++, XLDR_LL_UART + 1);           /* u8 console_uart */
+    stw_raw(w ++, 115200);                     /* u32 console_speed */
+#endif
+
+    stw_raw(w ++, OMAP_TAG_LCD);               /* u16 tag */
+    stw_raw(w ++, 36);                         /* u16 len */
+    strcpy((void *) w, "QEMU LCD panel");      /* char panel_name[16] */
+    w += 8;
+    strcpy((void *) w, "blizzard");            /* char ctrl_name[16] */
+    w += 8;
+    stw_raw(w ++, N810_BLIZZARD_RESET_GPIO);   /* TODO: n800 s16 nreset_gpio */
+    stw_raw(w ++, 24);                         /* u8 data_lines */
+
+    stw_raw(w ++, OMAP_TAG_CBUS);              /* u16 tag */
+    stw_raw(w ++, 8);                          /* u16 len */
+    stw_raw(w ++, N8X0_CBUS_CLK_GPIO);         /* s16 clk_gpio */
+    stw_raw(w ++, N8X0_CBUS_DAT_GPIO);         /* s16 dat_gpio */
+    stw_raw(w ++, N8X0_CBUS_SEL_GPIO);         /* s16 sel_gpio */
+    w ++;
+
+    stw_raw(w ++, OMAP_TAG_EM_ASIC_BB5);       /* u16 tag */
+    stw_raw(w ++, 4);                          /* u16 len */
+    stw_raw(w ++, N8X0_RETU_GPIO);             /* s16 retu_irq_gpio */
+    stw_raw(w ++, N8X0_TAHVO_GPIO);            /* s16 tahvo_irq_gpio */
+
+    gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info;
+    for (; gpiosw->name; gpiosw ++) {
+        stw_raw(w ++, OMAP_TAG_GPIO_SWITCH);   /* u16 tag */
+        stw_raw(w ++, 20);                     /* u16 len */
+        strcpy((void *) w, gpiosw->name);      /* char name[12] */
+        w += 6;
+        stw_raw(w ++, gpiosw->line);           /* u16 gpio */
+        stw_raw(w ++, gpiosw->type);
+        stw_raw(w ++, 0);
+        stw_raw(w ++, 0);
+    }
+
+    stw_raw(w ++, OMAP_TAG_NOKIA_BT);          /* u16 tag */
+    stw_raw(w ++, 12);                         /* u16 len */
+    b = (void *) w;
+    stb_raw(b ++, 0x01);                       /* u8 chip_type (CSR) */
+    stb_raw(b ++, N8X0_BT_WKUP_GPIO);          /* u8 bt_wakeup_gpio */
+    stb_raw(b ++, N8X0_BT_HOST_WKUP_GPIO);     /* u8 host_wakeup_gpio */
+    stb_raw(b ++, N8X0_BT_RESET_GPIO);         /* u8 reset_gpio */
+    stb_raw(b ++, BT_UART + 1);                        /* u8 bt_uart */
+    memcpy(b, &n8x0_bd_addr, 6);               /* u8 bd_addr[6] */
+    b += 6;
+    stb_raw(b ++, 0x02);                       /* u8 bt_sysclk (38.4) */
+    w = (void *) b;
+
+    stw_raw(w ++, OMAP_TAG_WLAN_CX3110X);      /* u16 tag */
+    stw_raw(w ++, 8);                          /* u16 len */
+    stw_raw(w ++, 0x25);                       /* u8 chip_type */
+    stw_raw(w ++, N8X0_WLAN_PWR_GPIO);         /* s16 power_gpio */
+    stw_raw(w ++, N8X0_WLAN_IRQ_GPIO);         /* s16 irq_gpio */
+    stw_raw(w ++, -1);                         /* s16 spi_cs_gpio */
+
+    stw_raw(w ++, OMAP_TAG_MMC);               /* u16 tag */
+    stw_raw(w ++, 16);                         /* u16 len */
+    if (model == 810) {
+        stw_raw(w ++, 0x23f);                  /* unsigned flags */
+        stw_raw(w ++, -1);                     /* s16 power_pin */
+        stw_raw(w ++, -1);                     /* s16 switch_pin */
+        stw_raw(w ++, -1);                     /* s16 wp_pin */
+        stw_raw(w ++, 0x240);                  /* unsigned flags */
+        stw_raw(w ++, 0xc000);                 /* s16 power_pin */
+        stw_raw(w ++, 0x0248);                 /* s16 switch_pin */
+        stw_raw(w ++, 0xc000);                 /* s16 wp_pin */
+    } else {
+        stw_raw(w ++, 0xf);                    /* unsigned flags */
+        stw_raw(w ++, -1);                     /* s16 power_pin */
+        stw_raw(w ++, -1);                     /* s16 switch_pin */
+        stw_raw(w ++, -1);                     /* s16 wp_pin */
+        stw_raw(w ++, 0);                      /* unsigned flags */
+        stw_raw(w ++, 0);                      /* s16 power_pin */
+        stw_raw(w ++, 0);                      /* s16 switch_pin */
+        stw_raw(w ++, 0);                      /* s16 wp_pin */
+    }
+
+    stw_raw(w ++, OMAP_TAG_TEA5761);           /* u16 tag */
+    stw_raw(w ++, 4);                          /* u16 len */
+    stw_raw(w ++, N8X0_TEA5761_CS_GPIO);       /* u16 enable_gpio */
+    w ++;
+
+    partition = (model == 810) ? n810_part_info : n800_part_info;
+    for (; partition->name; partition ++) {
+        stw_raw(w ++, OMAP_TAG_PARTITION);     /* u16 tag */
+        stw_raw(w ++, 28);                     /* u16 len */
+        strcpy((void *) w, partition->name);   /* char name[16] */
+        l = (void *) (w + 8);
+        stl_raw(l ++, partition->size);                /* unsigned int size */
+        stl_raw(l ++, partition->offset);      /* unsigned int offset */
+        stl_raw(l ++, partition->mask);                /* unsigned int mask_flags */
+        w = (void *) l;
+    }
+
+    stw_raw(w ++, OMAP_TAG_BOOT_REASON);       /* u16 tag */
+    stw_raw(w ++, 12);                         /* u16 len */
+#if 0
+    strcpy((void *) w, "por");                 /* char reason_str[12] */
+    strcpy((void *) w, "charger");             /* char reason_str[12] */
+    strcpy((void *) w, "32wd_to");             /* char reason_str[12] */
+    strcpy((void *) w, "sw_rst");              /* char reason_str[12] */
+    strcpy((void *) w, "mbus");                        /* char reason_str[12] */
+    strcpy((void *) w, "unknown");             /* char reason_str[12] */
+    strcpy((void *) w, "swdg_to");             /* char reason_str[12] */
+    strcpy((void *) w, "sec_vio");             /* char reason_str[12] */
+    strcpy((void *) w, "pwr_key");             /* char reason_str[12] */
+    strcpy((void *) w, "rtc_alarm");           /* char reason_str[12] */
+#else
+    strcpy((void *) w, "pwr_key");             /* char reason_str[12] */
+#endif
+    w += 6;
+
+    tag = (model == 810) ? "RX-44" : "RX-34";
+    stw_raw(w ++, OMAP_TAG_VERSION_STR);       /* u16 tag */
+    stw_raw(w ++, 24);                         /* u16 len */
+    strcpy((void *) w, "product");             /* char component[12] */
+    w += 6;
+    strcpy((void *) w, tag);                   /* char version[12] */
+    w += 6;
+
+    stw_raw(w ++, OMAP_TAG_VERSION_STR);       /* u16 tag */
+    stw_raw(w ++, 24);                         /* u16 len */
+    strcpy((void *) w, "hw-build");            /* char component[12] */
+    w += 6;
+    strcpy((void *) w, "QEMU ");
+    pstrcat((void *) w, 12, qemu_get_version()); /* char version[12] */
+    w += 6;
+
+    tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu";
+    stw_raw(w ++, OMAP_TAG_VERSION_STR);       /* u16 tag */
+    stw_raw(w ++, 24);                         /* u16 len */
+    strcpy((void *) w, "nolo");                        /* char component[12] */
+    w += 6;
+    strcpy((void *) w, tag);                   /* char version[12] */
+    w += 6;
+
+    return (void *) w - p;
+}
+
+static int n800_atag_setup(const struct arm_boot_info *info, void *p)
+{
+    return n8x0_atag_setup(p, 800);
+}
+
+static int n810_atag_setup(const struct arm_boot_info *info, void *p)
+{
+    return n8x0_atag_setup(p, 810);
+}
+
+static void n8x0_init(QEMUMachineInitArgs *args,
+                      struct arm_boot_info *binfo, int model)
+{
+    MemoryRegion *sysmem = get_system_memory();
+    struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
+    int sdram_size = binfo->ram_size;
+    DisplayState *ds;
+
+    s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model);
+
+    /* Setup peripherals
+     *
+     * Believed external peripherals layout in the N810:
+     * (spi bus 1)
+     *   tsc2005
+     *   lcd_mipid
+     * (spi bus 2)
+     *   Conexant cx3110x (WLAN)
+     *   optional: pc2400m (WiMAX)
+     * (i2c bus 0)
+     *   TLV320AIC33 (audio codec)
+     *   TCM825x (camera by Toshiba)
+     *   lp5521 (clever LEDs)
+     *   tsl2563 (light sensor, hwmon, model 7, rev. 0)
+     *   lm8323 (keypad, manf 00, rev 04)
+     * (i2c bus 1)
+     *   tmp105 (temperature sensor, hwmon)
+     *   menelaus (pm)
+     * (somewhere on i2c - maybe N800-only)
+     *   tea5761 (FM tuner)
+     * (serial 0)
+     *   GPS
+     * (some serial port)
+     *   csr41814 (Bluetooth)
+     */
+    n8x0_gpio_setup(s);
+    n8x0_nand_setup(s);
+    n8x0_i2c_setup(s);
+    if (model == 800)
+        n800_tsc_kbd_setup(s);
+    else if (model == 810) {
+        n810_tsc_setup(s);
+        n810_kbd_setup(s);
+    }
+    n8x0_spi_setup(s);
+    n8x0_dss_setup(s);
+    n8x0_cbus_setup(s);
+    n8x0_uart_setup(s);
+    if (usb_enabled(false)) {
+        n8x0_usb_setup(s);
+    }
+
+    if (args->kernel_filename) {
+        /* Or at the linux loader.  */
+        binfo->kernel_filename = args->kernel_filename;
+        binfo->kernel_cmdline = args->kernel_cmdline;
+        binfo->initrd_filename = args->initrd_filename;
+        arm_load_kernel(s->mpu->cpu, binfo);
+
+        qemu_register_reset(n8x0_boot_init, s);
+    }
+
+    if (option_rom[0].name &&
+        (args->boot_device[0] == 'n' || !args->kernel_filename)) {
+        int rom_size;
+        uint8_t nolo_tags[0x10000];
+        /* No, wait, better start at the ROM.  */
+        s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
+
+        /* This is intended for loading the `secondary.bin' program from
+         * Nokia images (the NOLO bootloader).  The entry point seems
+         * to be at OMAP2_Q2_BASE + 0x400000.
+         *
+         * The `2nd.bin' files contain some kind of earlier boot code and
+         * for them the entry point needs to be set to OMAP2_SRAM_BASE.
+         *
+         * The code above is for loading the `zImage' file from Nokia
+         * images.  */
+        rom_size = load_image_targphys(option_rom[0].name,
+                                       OMAP2_Q2_BASE + 0x400000,
+                                       sdram_size - 0x400000);
+        printf("%i bytes of image loaded\n", rom_size);
+
+        n800_setup_nolo_tags(nolo_tags);
+        cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
+    }
+    /* FIXME: We shouldn't really be doing this here.  The LCD controller
+       will set the size once configured, so this just sets an initial
+       size until the guest activates the display.  */
+    ds = get_displaystate();
+    ds->surface = qemu_resize_displaysurface(ds, 800, 480);
+    dpy_gfx_resize(ds);
+}
+
+static struct arm_boot_info n800_binfo = {
+    .loader_start = OMAP2_Q2_BASE,
+    /* Actually two chips of 0x4000000 bytes each */
+    .ram_size = 0x08000000,
+    .board_id = 0x4f7,
+    .atag_board = n800_atag_setup,
+};
+
+static struct arm_boot_info n810_binfo = {
+    .loader_start = OMAP2_Q2_BASE,
+    /* Actually two chips of 0x4000000 bytes each */
+    .ram_size = 0x08000000,
+    /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not
+     * used by some older versions of the bootloader and 5555 is used
+     * instead (including versions that shipped with many devices).  */
+    .board_id = 0x60c,
+    .atag_board = n810_atag_setup,
+};
+
+static void n800_init(QEMUMachineInitArgs *args)
+{
+    return n8x0_init(args, &n800_binfo, 800);
+}
+
+static void n810_init(QEMUMachineInitArgs *args)
+{
+    return n8x0_init(args, &n810_binfo, 810);
+}
+
+static QEMUMachine n800_machine = {
+    .name = "n800",
+    .desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)",
+    .init = n800_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine n810_machine = {
+    .name = "n810",
+    .desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)",
+    .init = n810_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void nseries_machine_init(void)
+{
+    qemu_register_machine(&n800_machine);
+    qemu_register_machine(&n810_machine);
+}
+
+machine_init(nseries_machine_init);
diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c
new file mode 100644 (file)
index 0000000..8598233
--- /dev/null
@@ -0,0 +1,238 @@
+/* omap_sx1.c Support for the Siemens SX1 smartphone emulation.
+ *
+ *   Copyright (C) 2008
+ *     Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *   Copyright (C) 2007 Vladimir Ananiev <vovan888@gmail.com>
+ *
+ *   based on PalmOne's (TM) PDAs support (palm.c)
+ */
+
+/*
+ * PalmOne's (TM) PDAs.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "hw/omap.h"
+#include "hw/boards.h"
+#include "hw/arm-misc.h"
+#include "hw/flash.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+/*****************************************************************************/
+/* Siemens SX1 Cellphone V1 */
+/* - ARM OMAP310 processor
+ * - SRAM                192 kB
+ * - SDRAM                32 MB at 0x10000000
+ * - Boot flash           16 MB at 0x00000000
+ * - Application flash     8 MB at 0x04000000
+ * - 3 serial ports
+ * - 1 SecureDigital
+ * - 1 LCD display
+ * - 1 RTC
+ */
+
+/*****************************************************************************/
+/* Siemens SX1 Cellphone V2 */
+/* - ARM OMAP310 processor
+ * - SRAM                192 kB
+ * - SDRAM                32 MB at 0x10000000
+ * - Boot flash           32 MB at 0x00000000
+ * - 3 serial ports
+ * - 1 SecureDigital
+ * - 1 LCD display
+ * - 1 RTC
+ */
+
+static uint64_t static_read(void *opaque, hwaddr offset,
+                            unsigned size)
+{
+    uint32_t *val = (uint32_t *) opaque;
+    uint32_t mask = (4 / size) - 1;
+
+    return *val >> ((offset & mask) << 3);
+}
+
+static void static_write(void *opaque, hwaddr offset,
+                         uint64_t value, unsigned size)
+{
+#ifdef SPY
+    printf("%s: value %" PRIx64 " %u bytes written at 0x%x\n",
+                    __func__, value, size, (int)offset);
+#endif
+}
+
+static const MemoryRegionOps static_ops = {
+    .read = static_read,
+    .write = static_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+#define sdram_size     0x02000000
+#define sector_size    (128 * 1024)
+#define flash0_size    (16 * 1024 * 1024)
+#define flash1_size    ( 8 * 1024 * 1024)
+#define flash2_size    (32 * 1024 * 1024)
+#define total_ram_v1   (sdram_size + flash0_size + flash1_size + OMAP15XX_SRAM_SIZE)
+#define total_ram_v2   (sdram_size + flash2_size + OMAP15XX_SRAM_SIZE)
+
+static struct arm_boot_info sx1_binfo = {
+    .loader_start = OMAP_EMIFF_BASE,
+    .ram_size = sdram_size,
+    .board_id = 0x265,
+};
+
+static void sx1_init(QEMUMachineInitArgs *args, const int version)
+{
+    struct omap_mpu_state_s *mpu;
+    MemoryRegion *address_space = get_system_memory();
+    MemoryRegion *flash = g_new(MemoryRegion, 1);
+    MemoryRegion *flash_1 = g_new(MemoryRegion, 1);
+    MemoryRegion *cs = g_new(MemoryRegion, 4);
+    static uint32_t cs0val = 0x00213090;
+    static uint32_t cs1val = 0x00215070;
+    static uint32_t cs2val = 0x00001139;
+    static uint32_t cs3val = 0x00001139;
+    DriveInfo *dinfo;
+    int fl_idx;
+    uint32_t flash_size = flash0_size;
+    int be;
+
+    if (version == 2) {
+        flash_size = flash2_size;
+    }
+
+    mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model);
+
+    /* External Flash (EMIFS) */
+    memory_region_init_ram(flash, "omap_sx1.flash0-0", flash_size);
+    vmstate_register_ram_global(flash);
+    memory_region_set_readonly(flash, true);
+    memory_region_add_subregion(address_space, OMAP_CS0_BASE, flash);
+
+    memory_region_init_io(&cs[0], &static_ops, &cs0val,
+                          "sx1.cs0", OMAP_CS0_SIZE - flash_size);
+    memory_region_add_subregion(address_space,
+                                OMAP_CS0_BASE + flash_size, &cs[0]);
+
+
+    memory_region_init_io(&cs[2], &static_ops, &cs2val,
+                          "sx1.cs2", OMAP_CS2_SIZE);
+    memory_region_add_subregion(address_space,
+                                OMAP_CS2_BASE, &cs[2]);
+
+    memory_region_init_io(&cs[3], &static_ops, &cs3val,
+                          "sx1.cs3", OMAP_CS3_SIZE);
+    memory_region_add_subregion(address_space,
+                                OMAP_CS2_BASE, &cs[3]);
+
+    fl_idx = 0;
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+
+    if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
+        if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL,
+                                   "omap_sx1.flash0-1", flash_size,
+                                   dinfo->bdrv, sector_size,
+                                   flash_size / sector_size,
+                                   4, 0, 0, 0, 0, be)) {
+            fprintf(stderr, "qemu: Error registering flash memory %d.\n",
+                           fl_idx);
+        }
+        fl_idx++;
+    }
+
+    if ((version == 1) &&
+            (dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
+        memory_region_init_ram(flash_1, "omap_sx1.flash1-0", flash1_size);
+        vmstate_register_ram_global(flash_1);
+        memory_region_set_readonly(flash_1, true);
+        memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1);
+
+        memory_region_init_io(&cs[1], &static_ops, &cs1val,
+                              "sx1.cs1", OMAP_CS1_SIZE - flash1_size);
+        memory_region_add_subregion(address_space,
+                                OMAP_CS1_BASE + flash1_size, &cs[1]);
+
+        if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL,
+                                   "omap_sx1.flash1-1", flash1_size,
+                                   dinfo->bdrv, sector_size,
+                                   flash1_size / sector_size,
+                                   4, 0, 0, 0, 0, be)) {
+            fprintf(stderr, "qemu: Error registering flash memory %d.\n",
+                           fl_idx);
+        }
+        fl_idx++;
+    } else {
+        memory_region_init_io(&cs[1], &static_ops, &cs1val,
+                              "sx1.cs1", OMAP_CS1_SIZE);
+        memory_region_add_subregion(address_space,
+                                OMAP_CS1_BASE, &cs[1]);
+    }
+
+    if (!args->kernel_filename && !fl_idx) {
+        fprintf(stderr, "Kernel or Flash image must be specified\n");
+        exit(1);
+    }
+
+    /* Load the kernel.  */
+    if (args->kernel_filename) {
+        sx1_binfo.kernel_filename = args->kernel_filename;
+        sx1_binfo.kernel_cmdline = args->kernel_cmdline;
+        sx1_binfo.initrd_filename = args->initrd_filename;
+        arm_load_kernel(mpu->cpu, &sx1_binfo);
+    }
+
+    /* TODO: fix next line */
+    //~ qemu_console_resize(ds, 640, 480);
+}
+
+static void sx1_init_v1(QEMUMachineInitArgs *args)
+{
+    sx1_init(args, 1);
+}
+
+static void sx1_init_v2(QEMUMachineInitArgs *args)
+{
+    sx1_init(args, 2);
+}
+
+static QEMUMachine sx1_machine_v2 = {
+    .name = "sx1",
+    .desc = "Siemens SX1 (OMAP310) V2",
+    .init = sx1_init_v2,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine sx1_machine_v1 = {
+    .name = "sx1-v1",
+    .desc = "Siemens SX1 (OMAP310) V1",
+    .init = sx1_init_v1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void sx1_machine_init(void)
+{
+    qemu_register_machine(&sx1_machine_v2);
+    qemu_register_machine(&sx1_machine_v1);
+}
+
+machine_init(sx1_machine_init);
diff --git a/hw/arm/palm.c b/hw/arm/palm.c
new file mode 100644 (file)
index 0000000..91bc74a
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * PalmOne's (TM) PDAs.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw/hw.h"
+#include "audio/audio.h"
+#include "sysemu/sysemu.h"
+#include "ui/console.h"
+#include "hw/omap.h"
+#include "hw/boards.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "hw/loader.h"
+#include "exec/address-spaces.h"
+
+static uint32_t static_readb(void *opaque, hwaddr offset)
+{
+    uint32_t *val = (uint32_t *) opaque;
+    return *val >> ((offset & 3) << 3);
+}
+
+static uint32_t static_readh(void *opaque, hwaddr offset)
+{
+    uint32_t *val = (uint32_t *) opaque;
+    return *val >> ((offset & 1) << 3);
+}
+
+static uint32_t static_readw(void *opaque, hwaddr offset)
+{
+    uint32_t *val = (uint32_t *) opaque;
+    return *val >> ((offset & 0) << 3);
+}
+
+static void static_write(void *opaque, hwaddr offset,
+                uint32_t value)
+{
+#ifdef SPY
+    printf("%s: value %08lx written at " PA_FMT "\n",
+                    __FUNCTION__, value, offset);
+#endif
+}
+
+static const MemoryRegionOps static_ops = {
+    .old_mmio = {
+        .read = { static_readb, static_readh, static_readw, },
+        .write = { static_write, static_write, static_write, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/* Palm Tunsgten|E support */
+
+/* Shared GPIOs */
+#define PALMTE_USBDETECT_GPIO  0
+#define PALMTE_USB_OR_DC_GPIO  1
+#define PALMTE_TSC_GPIO                4
+#define PALMTE_PINTDAV_GPIO    6
+#define PALMTE_MMC_WP_GPIO     8
+#define PALMTE_MMC_POWER_GPIO  9
+#define PALMTE_HDQ_GPIO                11
+#define PALMTE_HEADPHONES_GPIO 14
+#define PALMTE_SPEAKER_GPIO    15
+/* MPU private GPIOs */
+#define PALMTE_DC_GPIO         2
+#define PALMTE_MMC_SWITCH_GPIO 4
+#define PALMTE_MMC1_GPIO       6
+#define PALMTE_MMC2_GPIO       7
+#define PALMTE_MMC3_GPIO       11
+
+static MouseTransformInfo palmte_pointercal = {
+    .x = 320,
+    .y = 320,
+    .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 },
+};
+
+static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
+{
+    uWireSlave *tsc;
+
+    tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO));
+
+    omap_uwire_attach(cpu->microwire, tsc, 0);
+    omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
+
+    tsc210x_set_transform(tsc, &palmte_pointercal);
+}
+
+static struct {
+    int row;
+    int column;
+} palmte_keymap[0x80] = {
+    [0 ... 0x7f] = { -1, -1 },
+    [0x3b] = { 0, 0 }, /* F1   -> Calendar */
+    [0x3c] = { 1, 0 }, /* F2   -> Contacts */
+    [0x3d] = { 2, 0 }, /* F3   -> Tasks List */
+    [0x3e] = { 3, 0 }, /* F4   -> Note Pad */
+    [0x01] = { 4, 0 }, /* Esc  -> Power */
+    [0x4b] = { 0, 1 }, /*         Left */
+    [0x50] = { 1, 1 }, /*         Down */
+    [0x48] = { 2, 1 }, /*         Up */
+    [0x4d] = { 3, 1 }, /*         Right */
+    [0x4c] = { 4, 1 }, /*         Centre */
+    [0x39] = { 4, 1 }, /* Spc  -> Centre */
+};
+
+static void palmte_button_event(void *opaque, int keycode)
+{
+    struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque;
+
+    if (palmte_keymap[keycode & 0x7f].row != -1)
+        omap_mpuio_key(cpu->mpuio,
+                        palmte_keymap[keycode & 0x7f].row,
+                        palmte_keymap[keycode & 0x7f].column,
+                        !(keycode & 0x80));
+}
+
+static void palmte_onoff_gpios(void *opaque, int line, int level)
+{
+    switch (line) {
+    case 0:
+        printf("%s: current to MMC/SD card %sabled.\n",
+                        __FUNCTION__, level ? "dis" : "en");
+        break;
+    case 1:
+        printf("%s: internal speaker amplifier %s.\n",
+                        __FUNCTION__, level ? "down" : "on");
+        break;
+
+    /* These LCD & Audio output signals have not been identified yet.  */
+    case 2:
+    case 3:
+    case 4:
+        printf("%s: LCD GPIO%i %s.\n",
+                        __FUNCTION__, line - 1, level ? "high" : "low");
+        break;
+    case 5:
+    case 6:
+        printf("%s: Audio GPIO%i %s.\n",
+                        __FUNCTION__, line - 4, level ? "high" : "low");
+        break;
+    }
+}
+
+static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
+{
+    qemu_irq *misc_gpio;
+
+    omap_mmc_handlers(cpu->mmc,
+                    qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO),
+                    qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
+                            [PALMTE_MMC_SWITCH_GPIO]));
+
+    misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7);
+    qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO,    misc_gpio[0]);
+    qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO,      misc_gpio[1]);
+    qdev_connect_gpio_out(cpu->gpio, 11,                       misc_gpio[2]);
+    qdev_connect_gpio_out(cpu->gpio, 12,                       misc_gpio[3]);
+    qdev_connect_gpio_out(cpu->gpio, 13,                       misc_gpio[4]);
+    omap_mpuio_out_set(cpu->mpuio, 1,                          misc_gpio[5]);
+    omap_mpuio_out_set(cpu->mpuio, 3,                          misc_gpio[6]);
+
+    /* Reset some inputs to initial state.  */
+    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO));
+    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO));
+    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4));
+    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO));
+    qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
+    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
+    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
+    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]);
+}
+
+static struct arm_boot_info palmte_binfo = {
+    .loader_start = OMAP_EMIFF_BASE,
+    .ram_size = 0x02000000,
+    .board_id = 0x331,
+};
+
+static void palmte_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    MemoryRegion *address_space_mem = get_system_memory();
+    struct omap_mpu_state_s *mpu;
+    int flash_size = 0x00800000;
+    int sdram_size = palmte_binfo.ram_size;
+    static uint32_t cs0val = 0xffffffff;
+    static uint32_t cs1val = 0x0000e1a0;
+    static uint32_t cs2val = 0x0000e1a0;
+    static uint32_t cs3val = 0xe1a0e1a0;
+    int rom_size, rom_loaded = 0;
+    DisplayState *ds = get_displaystate();
+    MemoryRegion *flash = g_new(MemoryRegion, 1);
+    MemoryRegion *cs = g_new(MemoryRegion, 4);
+
+    mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model);
+
+    /* External Flash (EMIFS) */
+    memory_region_init_ram(flash, "palmte.flash", flash_size);
+    vmstate_register_ram_global(flash);
+    memory_region_set_readonly(flash, true);
+    memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);
+
+    memory_region_init_io(&cs[0], &static_ops, &cs0val, "palmte-cs0",
+                          OMAP_CS0_SIZE - flash_size);
+    memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size,
+                                &cs[0]);
+    memory_region_init_io(&cs[1], &static_ops, &cs1val, "palmte-cs1",
+                          OMAP_CS1_SIZE);
+    memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]);
+    memory_region_init_io(&cs[2], &static_ops, &cs2val, "palmte-cs2",
+                          OMAP_CS2_SIZE);
+    memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]);
+    memory_region_init_io(&cs[3], &static_ops, &cs3val, "palmte-cs3",
+                          OMAP_CS3_SIZE);
+    memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]);
+
+    palmte_microwire_setup(mpu);
+
+    qemu_add_kbd_event_handler(palmte_button_event, mpu);
+
+    palmte_gpio_setup(mpu);
+
+    /* Setup initial (reset) machine state */
+    if (nb_option_roms) {
+        rom_size = get_image_size(option_rom[0].name);
+        if (rom_size > flash_size) {
+            fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
+                            __FUNCTION__, rom_size, flash_size);
+            rom_size = 0;
+        }
+        if (rom_size > 0) {
+            rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE,
+                                           flash_size);
+            rom_loaded = 1;
+        }
+        if (rom_size < 0) {
+            fprintf(stderr, "%s: error loading '%s'\n",
+                            __FUNCTION__, option_rom[0].name);
+        }
+    }
+
+    if (!rom_loaded && !kernel_filename) {
+        fprintf(stderr, "Kernel or ROM image must be specified\n");
+        exit(1);
+    }
+
+    /* Load the kernel.  */
+    if (kernel_filename) {
+        palmte_binfo.kernel_filename = kernel_filename;
+        palmte_binfo.kernel_cmdline = kernel_cmdline;
+        palmte_binfo.initrd_filename = initrd_filename;
+        arm_load_kernel(mpu->cpu, &palmte_binfo);
+    }
+
+    /* FIXME: We shouldn't really be doing this here.  The LCD controller
+       will set the size once configured, so this just sets an initial
+       size until the guest activates the display.  */
+    ds->surface = qemu_resize_displaysurface(ds, 320, 320);
+    dpy_gfx_resize(ds);
+}
+
+static QEMUMachine palmte_machine = {
+    .name = "cheetah",
+    .desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)",
+    .init = palmte_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void palmte_machine_init(void)
+{
+    qemu_register_machine(&palmte_machine);
+}
+
+machine_init(palmte_machine_init);
diff --git a/hw/arm/pic_cpu.c b/hw/arm/pic_cpu.c
new file mode 100644 (file)
index 0000000..a7ad893
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Generic ARM Programmable Interrupt Controller support.
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL
+ */
+
+#include "hw/hw.h"
+#include "hw/arm-misc.h"
+
+/* Input 0 is IRQ and input 1 is FIQ.  */
+static void arm_pic_cpu_handler(void *opaque, int irq, int level)
+{
+    ARMCPU *cpu = opaque;
+    CPUARMState *env = &cpu->env;
+
+    switch (irq) {
+    case ARM_PIC_CPU_IRQ:
+        if (level)
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        else
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        break;
+    case ARM_PIC_CPU_FIQ:
+        if (level)
+            cpu_interrupt(env, CPU_INTERRUPT_FIQ);
+        else
+            cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
+        break;
+    default:
+        hw_error("arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
+    }
+}
+
+qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
+{
+    return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2);
+}
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
new file mode 100644 (file)
index 0000000..5fb490c
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * ARM RealView Baseboard System emulation.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm-misc.h"
+#include "hw/primecell.h"
+#include "hw/devices.h"
+#include "hw/pci/pci.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/i2c.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+#define SMP_BOOT_ADDR 0xe0000000
+#define SMP_BOOTREG_ADDR 0x10000030
+
+/* Board init.  */
+
+static struct arm_boot_info realview_binfo = {
+    .smp_loader_start = SMP_BOOT_ADDR,
+    .smp_bootreg_addr = SMP_BOOTREG_ADDR,
+};
+
+/* The following two lists must be consistent.  */
+enum realview_board_type {
+    BOARD_EB,
+    BOARD_EB_MPCORE,
+    BOARD_PB_A8,
+    BOARD_PBX_A9,
+};
+
+static const int realview_board_id[] = {
+    0x33b,
+    0x33b,
+    0x769,
+    0x76d
+};
+
+static void realview_init(QEMUMachineInitArgs *args,
+                          enum realview_board_type board_type)
+{
+    ARMCPU *cpu = NULL;
+    CPUARMState *env;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram_lo = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
+    DeviceState *dev, *sysctl, *gpio2, *pl041;
+    SysBusDevice *busdev;
+    qemu_irq *irqp;
+    qemu_irq pic[64];
+    qemu_irq mmc_irq[2];
+    PCIBus *pci_bus;
+    NICInfo *nd;
+    i2c_bus *i2c;
+    int n;
+    int done_nic = 0;
+    qemu_irq cpu_irq[4];
+    int is_mpcore = 0;
+    int is_pb = 0;
+    uint32_t proc_id = 0;
+    uint32_t sys_id;
+    ram_addr_t low_ram_size;
+    ram_addr_t ram_size = args->ram_size;
+
+    switch (board_type) {
+    case BOARD_EB:
+        break;
+    case BOARD_EB_MPCORE:
+        is_mpcore = 1;
+        break;
+    case BOARD_PB_A8:
+        is_pb = 1;
+        break;
+    case BOARD_PBX_A9:
+        is_mpcore = 1;
+        is_pb = 1;
+        break;
+    }
+    for (n = 0; n < smp_cpus; n++) {
+        cpu = cpu_arm_init(args->cpu_model);
+        if (!cpu) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        irqp = arm_pic_init_cpu(cpu);
+        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+    }
+    env = &cpu->env;
+    if (arm_feature(env, ARM_FEATURE_V7)) {
+        if (is_mpcore) {
+            proc_id = 0x0c000000;
+        } else {
+            proc_id = 0x0e000000;
+        }
+    } else if (arm_feature(env, ARM_FEATURE_V6K)) {
+        proc_id = 0x06000000;
+    } else if (arm_feature(env, ARM_FEATURE_V6)) {
+        proc_id = 0x04000000;
+    } else {
+        proc_id = 0x02000000;
+    }
+
+    if (is_pb && ram_size > 0x20000000) {
+        /* Core tile RAM.  */
+        low_ram_size = ram_size - 0x20000000;
+        ram_size = 0x20000000;
+        memory_region_init_ram(ram_lo, "realview.lowmem", low_ram_size);
+        vmstate_register_ram_global(ram_lo);
+        memory_region_add_subregion(sysmem, 0x20000000, ram_lo);
+    }
+
+    memory_region_init_ram(ram_hi, "realview.highmem", ram_size);
+    vmstate_register_ram_global(ram_hi);
+    low_ram_size = ram_size;
+    if (low_ram_size > 0x10000000)
+      low_ram_size = 0x10000000;
+    /* SDRAM at address zero.  */
+    memory_region_init_alias(ram_alias, "realview.alias",
+                             ram_hi, 0, low_ram_size);
+    memory_region_add_subregion(sysmem, 0, ram_alias);
+    if (is_pb) {
+        /* And again at a high address.  */
+        memory_region_add_subregion(sysmem, 0x70000000, ram_hi);
+    } else {
+        ram_size = low_ram_size;
+    }
+
+    sys_id = is_pb ? 0x01780500 : 0xc1400400;
+    sysctl = qdev_create(NULL, "realview_sysctl");
+    qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
+    qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
+    qdev_init_nofail(sysctl);
+    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
+
+    if (is_mpcore) {
+        hwaddr periphbase;
+        dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
+        qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+        qdev_init_nofail(dev);
+        busdev = SYS_BUS_DEVICE(dev);
+        if (is_pb) {
+            periphbase = 0x1f000000;
+        } else {
+            periphbase = 0x10100000;
+        }
+        sysbus_mmio_map(busdev, 0, periphbase);
+        for (n = 0; n < smp_cpus; n++) {
+            sysbus_connect_irq(busdev, n, cpu_irq[n]);
+        }
+        sysbus_create_varargs("l2x0", periphbase + 0x2000, NULL);
+        /* Both A9 and 11MPCore put the GIC CPU i/f at base + 0x100 */
+        realview_binfo.gic_cpu_if_addr = periphbase + 0x100;
+    } else {
+        uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000;
+        /* For now just create the nIRQ GIC, and ignore the others.  */
+        dev = sysbus_create_simple("realview_gic", gic_addr, cpu_irq[0]);
+    }
+    for (n = 0; n < 64; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    pl041 = qdev_create(NULL, "pl041");
+    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
+    qdev_init_nofail(pl041);
+    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
+    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[19]);
+
+    sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]);
+    sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]);
+
+    sysbus_create_simple("pl011", 0x10009000, pic[12]);
+    sysbus_create_simple("pl011", 0x1000a000, pic[13]);
+    sysbus_create_simple("pl011", 0x1000b000, pic[14]);
+    sysbus_create_simple("pl011", 0x1000c000, pic[15]);
+
+    /* DMA controller is optional, apparently.  */
+    sysbus_create_simple("pl081", 0x10030000, pic[24]);
+
+    sysbus_create_simple("sp804", 0x10011000, pic[4]);
+    sysbus_create_simple("sp804", 0x10012000, pic[5]);
+
+    sysbus_create_simple("pl061", 0x10013000, pic[6]);
+    sysbus_create_simple("pl061", 0x10014000, pic[7]);
+    gpio2 = sysbus_create_simple("pl061", 0x10015000, pic[8]);
+
+    sysbus_create_simple("pl111", 0x10020000, pic[23]);
+
+    dev = sysbus_create_varargs("pl181", 0x10005000, pic[17], pic[18], NULL);
+    /* Wire up MMC card detect and read-only signals. These have
+     * to go to both the PL061 GPIO and the sysctl register.
+     * Note that the PL181 orders these lines (readonly,inserted)
+     * and the PL061 has them the other way about. Also the card
+     * detect line is inverted.
+     */
+    mmc_irq[0] = qemu_irq_split(
+        qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT),
+        qdev_get_gpio_in(gpio2, 1));
+    mmc_irq[1] = qemu_irq_split(
+        qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN),
+        qemu_irq_invert(qdev_get_gpio_in(gpio2, 0)));
+    qdev_connect_gpio_out(dev, 0, mmc_irq[0]);
+    qdev_connect_gpio_out(dev, 1, mmc_irq[1]);
+
+    sysbus_create_simple("pl031", 0x10017000, pic[10]);
+
+    if (!is_pb) {
+        dev = qdev_create(NULL, "realview_pci");
+        busdev = SYS_BUS_DEVICE(dev);
+        qdev_init_nofail(dev);
+        sysbus_mmio_map(busdev, 0, 0x61000000); /* PCI self-config */
+        sysbus_mmio_map(busdev, 1, 0x62000000); /* PCI config */
+        sysbus_mmio_map(busdev, 2, 0x63000000); /* PCI I/O */
+        sysbus_connect_irq(busdev, 0, pic[48]);
+        sysbus_connect_irq(busdev, 1, pic[49]);
+        sysbus_connect_irq(busdev, 2, pic[50]);
+        sysbus_connect_irq(busdev, 3, pic[51]);
+        pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
+        if (usb_enabled(false)) {
+            pci_create_simple(pci_bus, -1, "pci-ohci");
+        }
+        n = drive_get_max_bus(IF_SCSI);
+        while (n >= 0) {
+            pci_create_simple(pci_bus, -1, "lsi53c895a");
+            n--;
+        }
+    }
+    for(n = 0; n < nb_nics; n++) {
+        nd = &nd_table[n];
+
+        if (!done_nic && (!nd->model ||
+                    strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0)) {
+            if (is_pb) {
+                lan9118_init(nd, 0x4e000000, pic[28]);
+            } else {
+                smc91c111_init(nd, 0x4e000000, pic[28]);
+            }
+            done_nic = 1;
+        } else {
+            pci_nic_init_nofail(nd, "rtl8139", NULL);
+        }
+    }
+
+    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
+    i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+    i2c_create_slave(i2c, "ds1338", 0x68);
+
+    /* Memory map for RealView Emulation Baseboard:  */
+    /* 0x10000000 System registers.  */
+    /*  0x10001000 System controller.  */
+    /* 0x10002000 Two-Wire Serial Bus.  */
+    /* 0x10003000 Reserved.  */
+    /*  0x10004000 AACI.  */
+    /*  0x10005000 MCI.  */
+    /* 0x10006000 KMI0.  */
+    /* 0x10007000 KMI1.  */
+    /*  0x10008000 Character LCD. (EB) */
+    /* 0x10009000 UART0.  */
+    /* 0x1000a000 UART1.  */
+    /* 0x1000b000 UART2.  */
+    /* 0x1000c000 UART3.  */
+    /*  0x1000d000 SSPI.  */
+    /*  0x1000e000 SCI.  */
+    /* 0x1000f000 Reserved.  */
+    /*  0x10010000 Watchdog.  */
+    /* 0x10011000 Timer 0+1.  */
+    /* 0x10012000 Timer 2+3.  */
+    /*  0x10013000 GPIO 0.  */
+    /*  0x10014000 GPIO 1.  */
+    /*  0x10015000 GPIO 2.  */
+    /*  0x10002000 Two-Wire Serial Bus - DVI. (PB) */
+    /* 0x10017000 RTC.  */
+    /*  0x10018000 DMC.  */
+    /*  0x10019000 PCI controller config.  */
+    /*  0x10020000 CLCD.  */
+    /* 0x10030000 DMA Controller.  */
+    /* 0x10040000 GIC1. (EB) */
+    /*  0x10050000 GIC2. (EB) */
+    /*  0x10060000 GIC3. (EB) */
+    /*  0x10070000 GIC4. (EB) */
+    /*  0x10080000 SMC.  */
+    /* 0x1e000000 GIC1. (PB) */
+    /*  0x1e001000 GIC2. (PB) */
+    /*  0x1e002000 GIC3. (PB) */
+    /*  0x1e003000 GIC4. (PB) */
+    /*  0x40000000 NOR flash.  */
+    /*  0x44000000 DoC flash.  */
+    /*  0x48000000 SRAM.  */
+    /*  0x4c000000 Configuration flash.  */
+    /* 0x4e000000 Ethernet.  */
+    /*  0x4f000000 USB.  */
+    /*  0x50000000 PISMO.  */
+    /*  0x54000000 PISMO.  */
+    /*  0x58000000 PISMO.  */
+    /*  0x5c000000 PISMO.  */
+    /* 0x60000000 PCI.  */
+    /* 0x61000000 PCI Self Config.  */
+    /* 0x62000000 PCI Config.  */
+    /* 0x63000000 PCI IO.  */
+    /* 0x64000000 PCI mem 0.  */
+    /* 0x68000000 PCI mem 1.  */
+    /* 0x6c000000 PCI mem 2.  */
+
+    /* ??? Hack to map an additional page of ram for the secondary CPU
+       startup code.  I guess this works on real hardware because the
+       BootROM happens to be in ROM/flash or in memory that isn't clobbered
+       until after Linux boots the secondary CPUs.  */
+    memory_region_init_ram(ram_hack, "realview.hack", 0x1000);
+    vmstate_register_ram_global(ram_hack);
+    memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
+
+    realview_binfo.ram_size = ram_size;
+    realview_binfo.kernel_filename = args->kernel_filename;
+    realview_binfo.kernel_cmdline = args->kernel_cmdline;
+    realview_binfo.initrd_filename = args->initrd_filename;
+    realview_binfo.nb_cpus = smp_cpus;
+    realview_binfo.board_id = realview_board_id[board_type];
+    realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
+    arm_load_kernel(arm_env_get_cpu(first_cpu), &realview_binfo);
+}
+
+static void realview_eb_init(QEMUMachineInitArgs *args)
+{
+    if (!args->cpu_model) {
+        args->cpu_model = "arm926";
+    }
+    realview_init(args, BOARD_EB);
+}
+
+static void realview_eb_mpcore_init(QEMUMachineInitArgs *args)
+{
+    if (!args->cpu_model) {
+        args->cpu_model = "arm11mpcore";
+    }
+    realview_init(args, BOARD_EB_MPCORE);
+}
+
+static void realview_pb_a8_init(QEMUMachineInitArgs *args)
+{
+    if (!args->cpu_model) {
+        args->cpu_model = "cortex-a8";
+    }
+    realview_init(args, BOARD_PB_A8);
+}
+
+static void realview_pbx_a9_init(QEMUMachineInitArgs *args)
+{
+    if (!args->cpu_model) {
+        args->cpu_model = "cortex-a9";
+    }
+    realview_init(args, BOARD_PBX_A9);
+}
+
+static QEMUMachine realview_eb_machine = {
+    .name = "realview-eb",
+    .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)",
+    .init = realview_eb_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine realview_eb_mpcore_machine = {
+    .name = "realview-eb-mpcore",
+    .desc = "ARM RealView Emulation Baseboard (ARM11MPCore)",
+    .init = realview_eb_mpcore_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine realview_pb_a8_machine = {
+    .name = "realview-pb-a8",
+    .desc = "ARM RealView Platform Baseboard for Cortex-A8",
+    .init = realview_pb_a8_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine realview_pbx_a9_machine = {
+    .name = "realview-pbx-a9",
+    .desc = "ARM RealView Platform Baseboard Explore for Cortex-A9",
+    .init = realview_pbx_a9_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void realview_machine_init(void)
+{
+    qemu_register_machine(&realview_eb_machine);
+    qemu_register_machine(&realview_eb_mpcore_machine);
+    qemu_register_machine(&realview_pb_a8_machine);
+    qemu_register_machine(&realview_pbx_a9_machine);
+}
+
+machine_init(realview_machine_init);
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
new file mode 100644 (file)
index 0000000..f5832be
--- /dev/null
@@ -0,0 +1,1138 @@
+/*
+ * PXA270-based Clamshell PDA platforms.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "hw/hw.h"
+#include "hw/pxa.h"
+#include "hw/arm-misc.h"
+#include "sysemu/sysemu.h"
+#include "hw/pcmcia.h"
+#include "hw/i2c.h"
+#include "hw/ssi.h"
+#include "hw/flash.h"
+#include "qemu/timer.h"
+#include "hw/devices.h"
+#include "hw/sharpsl.h"
+#include "ui/console.h"
+#include "block/block.h"
+#include "audio/audio.h"
+#include "hw/boards.h"
+#include "sysemu/blockdev.h"
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+
+#undef REG_FMT
+#define REG_FMT                        "0x%02lx"
+
+/* Spitz Flash */
+#define FLASH_BASE             0x0c000000
+#define FLASH_ECCLPLB          0x00    /* Line parity 7 - 0 bit */
+#define FLASH_ECCLPUB          0x04    /* Line parity 15 - 8 bit */
+#define FLASH_ECCCP            0x08    /* Column parity 5 - 0 bit */
+#define FLASH_ECCCNTR          0x0c    /* ECC byte counter */
+#define FLASH_ECCCLRR          0x10    /* Clear ECC */
+#define FLASH_FLASHIO          0x14    /* Flash I/O */
+#define FLASH_FLASHCTL         0x18    /* Flash Control */
+
+#define FLASHCTL_CE0           (1 << 0)
+#define FLASHCTL_CLE           (1 << 1)
+#define FLASHCTL_ALE           (1 << 2)
+#define FLASHCTL_WP            (1 << 3)
+#define FLASHCTL_CE1           (1 << 4)
+#define FLASHCTL_RYBY          (1 << 5)
+#define FLASHCTL_NCE           (FLASHCTL_CE0 | FLASHCTL_CE1)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    DeviceState *nand;
+    uint8_t ctl;
+    uint8_t manf_id;
+    uint8_t chip_id;
+    ECCState ecc;
+} SLNANDState;
+
+static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size)
+{
+    SLNANDState *s = (SLNANDState *) opaque;
+    int ryby;
+
+    switch (addr) {
+#define BSHR(byte, from, to)   ((s->ecc.lp[byte] >> (from - to)) & (1 << to))
+    case FLASH_ECCLPLB:
+        return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) |
+                BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7);
+
+#define BSHL(byte, from, to)   ((s->ecc.lp[byte] << (to - from)) & (1 << to))
+    case FLASH_ECCLPUB:
+        return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) |
+                BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7);
+
+    case FLASH_ECCCP:
+        return s->ecc.cp;
+
+    case FLASH_ECCCNTR:
+        return s->ecc.count & 0xff;
+
+    case FLASH_FLASHCTL:
+        nand_getpins(s->nand, &ryby);
+        if (ryby)
+            return s->ctl | FLASHCTL_RYBY;
+        else
+            return s->ctl;
+
+    case FLASH_FLASHIO:
+        if (size == 4) {
+            return ecc_digest(&s->ecc, nand_getio(s->nand)) |
+                (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
+        }
+        return ecc_digest(&s->ecc, nand_getio(s->nand));
+
+    default:
+        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+    }
+    return 0;
+}
+
+static void sl_write(void *opaque, hwaddr addr,
+                     uint64_t value, unsigned size)
+{
+    SLNANDState *s = (SLNANDState *) opaque;
+
+    switch (addr) {
+    case FLASH_ECCCLRR:
+        /* Value is ignored.  */
+        ecc_reset(&s->ecc);
+        break;
+
+    case FLASH_FLASHCTL:
+        s->ctl = value & 0xff & ~FLASHCTL_RYBY;
+        nand_setpins(s->nand,
+                        s->ctl & FLASHCTL_CLE,
+                        s->ctl & FLASHCTL_ALE,
+                        s->ctl & FLASHCTL_NCE,
+                        s->ctl & FLASHCTL_WP,
+                        0);
+        break;
+
+    case FLASH_FLASHIO:
+        nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff));
+        break;
+
+    default:
+        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+    }
+}
+
+enum {
+    FLASH_128M,
+    FLASH_1024M,
+};
+
+static const MemoryRegionOps sl_ops = {
+    .read = sl_read,
+    .write = sl_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void sl_flash_register(PXA2xxState *cpu, int size)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "sl-nand");
+
+    qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG);
+    if (size == FLASH_128M)
+        qdev_prop_set_uint8(dev, "chip_id", 0x73);
+    else if (size == FLASH_1024M)
+        qdev_prop_set_uint8(dev, "chip_id", 0xf1);
+
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE);
+}
+
+static int sl_nand_init(SysBusDevice *dev) {
+    SLNANDState *s;
+    DriveInfo *nand;
+
+    s = FROM_SYSBUS(SLNANDState, dev);
+
+    s->ctl = 0;
+    nand = drive_get(IF_MTD, 0, 0);
+    s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id);
+
+    memory_region_init_io(&s->iomem, &sl_ops, s, "sl", 0x40);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+/* Spitz Keyboard */
+
+#define SPITZ_KEY_STROBE_NUM   11
+#define SPITZ_KEY_SENSE_NUM    7
+
+static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = {
+    12, 17, 91, 34, 36, 38, 39
+};
+
+static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = {
+    88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114
+};
+
+/* Eighth additional row maps the special keys */
+static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = {
+    { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 },
+    {  -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 },
+    { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25,  -1 ,  -1 ,  -1  },
+    { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26,  -1 , 0x36,  -1  },
+    { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34,  -1 , 0x1c, 0x2a,  -1  },
+    { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33,  -1 , 0x48,  -1 ,  -1 , 0x38 },
+    { 0x37, 0x3d,  -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d,  -1 ,  -1  },
+    { 0x52, 0x43, 0x01, 0x47, 0x49,  -1 ,  -1 ,  -1 ,  -1 ,  -1 ,  -1  },
+};
+
+#define SPITZ_GPIO_AK_INT      13      /* Remote control */
+#define SPITZ_GPIO_SYNC                16      /* Sync button */
+#define SPITZ_GPIO_ON_KEY      95      /* Power button */
+#define SPITZ_GPIO_SWA         97      /* Lid */
+#define SPITZ_GPIO_SWB         96      /* Tablet mode */
+
+/* The special buttons are mapped to unused keys */
+static const int spitz_gpiomap[5] = {
+    SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY,
+    SPITZ_GPIO_SWA, SPITZ_GPIO_SWB,
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq sense[SPITZ_KEY_SENSE_NUM];
+    qemu_irq gpiomap[5];
+    int keymap[0x80];
+    uint16_t keyrow[SPITZ_KEY_SENSE_NUM];
+    uint16_t strobe_state;
+    uint16_t sense_state;
+
+    uint16_t pre_map[0x100];
+    uint16_t modifiers;
+    uint16_t imodifiers;
+    uint8_t fifo[16];
+    int fifopos, fifolen;
+    QEMUTimer *kbdtimer;
+} SpitzKeyboardState;
+
+static void spitz_keyboard_sense_update(SpitzKeyboardState *s)
+{
+    int i;
+    uint16_t strobe, sense = 0;
+    for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) {
+        strobe = s->keyrow[i] & s->strobe_state;
+        if (strobe) {
+            sense |= 1 << i;
+            if (!(s->sense_state & (1 << i)))
+                qemu_irq_raise(s->sense[i]);
+        } else if (s->sense_state & (1 << i))
+            qemu_irq_lower(s->sense[i]);
+    }
+
+    s->sense_state = sense;
+}
+
+static void spitz_keyboard_strobe(void *opaque, int line, int level)
+{
+    SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
+
+    if (level)
+        s->strobe_state |= 1 << line;
+    else
+        s->strobe_state &= ~(1 << line);
+    spitz_keyboard_sense_update(s);
+}
+
+static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
+{
+    int spitz_keycode = s->keymap[keycode & 0x7f];
+    if (spitz_keycode == -1)
+        return;
+
+    /* Handle the additional keys */
+    if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) {
+        qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80));
+        return;
+    }
+
+    if (keycode & 0x80)
+        s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf));
+    else
+        s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf);
+
+    spitz_keyboard_sense_update(s);
+}
+
+#define SHIFT  (1 << 7)
+#define CTRL   (1 << 8)
+#define FN     (1 << 9)
+
+#define QUEUE_KEY(c)   s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
+
+static void spitz_keyboard_handler(void *opaque, int keycode)
+{
+    SpitzKeyboardState *s = opaque;
+    uint16_t code;
+    int mapcode;
+    switch (keycode) {
+    case 0x2a: /* Left Shift */
+        s->modifiers |= 1;
+        break;
+    case 0xaa:
+        s->modifiers &= ~1;
+        break;
+    case 0x36: /* Right Shift */
+        s->modifiers |= 2;
+        break;
+    case 0xb6:
+        s->modifiers &= ~2;
+        break;
+    case 0x1d: /* Control */
+        s->modifiers |= 4;
+        break;
+    case 0x9d:
+        s->modifiers &= ~4;
+        break;
+    case 0x38: /* Alt */
+        s->modifiers |= 8;
+        break;
+    case 0xb8:
+        s->modifiers &= ~8;
+        break;
+    }
+
+    code = s->pre_map[mapcode = ((s->modifiers & 3) ?
+            (keycode | SHIFT) :
+            (keycode & ~SHIFT))];
+
+    if (code != mapcode) {
+#if 0
+        if ((code & SHIFT) && !(s->modifiers & 1))
+            QUEUE_KEY(0x2a | (keycode & 0x80));
+        if ((code & CTRL ) && !(s->modifiers & 4))
+            QUEUE_KEY(0x1d | (keycode & 0x80));
+        if ((code & FN   ) && !(s->modifiers & 8))
+            QUEUE_KEY(0x38 | (keycode & 0x80));
+        if ((code & FN   ) && (s->modifiers & 1))
+            QUEUE_KEY(0x2a | (~keycode & 0x80));
+        if ((code & FN   ) && (s->modifiers & 2))
+            QUEUE_KEY(0x36 | (~keycode & 0x80));
+#else
+        if (keycode & 0x80) {
+            if ((s->imodifiers & 1   ) && !(s->modifiers & 1))
+                QUEUE_KEY(0x2a | 0x80);
+            if ((s->imodifiers & 4   ) && !(s->modifiers & 4))
+                QUEUE_KEY(0x1d | 0x80);
+            if ((s->imodifiers & 8   ) && !(s->modifiers & 8))
+                QUEUE_KEY(0x38 | 0x80);
+            if ((s->imodifiers & 0x10) && (s->modifiers & 1))
+                QUEUE_KEY(0x2a);
+            if ((s->imodifiers & 0x20) && (s->modifiers & 2))
+                QUEUE_KEY(0x36);
+            s->imodifiers = 0;
+        } else {
+            if ((code & SHIFT) && !((s->modifiers | s->imodifiers) & 1)) {
+                QUEUE_KEY(0x2a);
+                s->imodifiers |= 1;
+            }
+            if ((code & CTRL ) && !((s->modifiers | s->imodifiers) & 4)) {
+                QUEUE_KEY(0x1d);
+                s->imodifiers |= 4;
+            }
+            if ((code & FN   ) && !((s->modifiers | s->imodifiers) & 8)) {
+                QUEUE_KEY(0x38);
+                s->imodifiers |= 8;
+            }
+            if ((code & FN   ) && (s->modifiers & 1) &&
+                            !(s->imodifiers & 0x10)) {
+                QUEUE_KEY(0x2a | 0x80);
+                s->imodifiers |= 0x10;
+            }
+            if ((code & FN   ) && (s->modifiers & 2) &&
+                            !(s->imodifiers & 0x20)) {
+                QUEUE_KEY(0x36 | 0x80);
+                s->imodifiers |= 0x20;
+            }
+        }
+#endif
+    }
+
+    QUEUE_KEY((code & 0x7f) | (keycode & 0x80));
+}
+
+static void spitz_keyboard_tick(void *opaque)
+{
+    SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
+
+    if (s->fifolen) {
+        spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]);
+        s->fifolen --;
+        if (s->fifopos >= 16)
+            s->fifopos = 0;
+    }
+
+    qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock) +
+                   get_ticks_per_sec() / 32);
+}
+
+static void spitz_keyboard_pre_map(SpitzKeyboardState *s)
+{
+    int i;
+    for (i = 0; i < 0x100; i ++)
+        s->pre_map[i] = i;
+    s->pre_map[0x02 | SHIFT    ] = 0x02 | SHIFT;       /* exclam */
+    s->pre_map[0x28 | SHIFT    ] = 0x03 | SHIFT;       /* quotedbl */
+    s->pre_map[0x04 | SHIFT    ] = 0x04 | SHIFT;       /* numbersign */
+    s->pre_map[0x05 | SHIFT    ] = 0x05 | SHIFT;       /* dollar */
+    s->pre_map[0x06 | SHIFT    ] = 0x06 | SHIFT;       /* percent */
+    s->pre_map[0x08 | SHIFT    ] = 0x07 | SHIFT;       /* ampersand */
+    s->pre_map[0x28            ] = 0x08 | SHIFT;       /* apostrophe */
+    s->pre_map[0x0a | SHIFT    ] = 0x09 | SHIFT;       /* parenleft */
+    s->pre_map[0x0b | SHIFT    ] = 0x0a | SHIFT;       /* parenright */
+    s->pre_map[0x29 | SHIFT    ] = 0x0b | SHIFT;       /* asciitilde */
+    s->pre_map[0x03 | SHIFT    ] = 0x0c | SHIFT;       /* at */
+    s->pre_map[0xd3            ] = 0x0e | FN;          /* Delete */
+    s->pre_map[0x3a            ] = 0x0f | FN;          /* Caps_Lock */
+    s->pre_map[0x07 | SHIFT    ] = 0x11 | FN;          /* asciicircum */
+    s->pre_map[0x0d            ] = 0x12 | FN;          /* equal */
+    s->pre_map[0x0d | SHIFT    ] = 0x13 | FN;          /* plus */
+    s->pre_map[0x1a            ] = 0x14 | FN;          /* bracketleft */
+    s->pre_map[0x1b            ] = 0x15 | FN;          /* bracketright */
+    s->pre_map[0x1a | SHIFT    ] = 0x16 | FN;          /* braceleft */
+    s->pre_map[0x1b | SHIFT    ] = 0x17 | FN;          /* braceright */
+    s->pre_map[0x27            ] = 0x22 | FN;          /* semicolon */
+    s->pre_map[0x27 | SHIFT    ] = 0x23 | FN;          /* colon */
+    s->pre_map[0x09 | SHIFT    ] = 0x24 | FN;          /* asterisk */
+    s->pre_map[0x2b            ] = 0x25 | FN;          /* backslash */
+    s->pre_map[0x2b | SHIFT    ] = 0x26 | FN;          /* bar */
+    s->pre_map[0x0c | SHIFT    ] = 0x30 | FN;          /* underscore */
+    s->pre_map[0x33 | SHIFT    ] = 0x33 | FN;          /* less */
+    s->pre_map[0x35            ] = 0x33 | SHIFT;       /* slash */
+    s->pre_map[0x34 | SHIFT    ] = 0x34 | FN;          /* greater */
+    s->pre_map[0x35 | SHIFT    ] = 0x34 | SHIFT;       /* question */
+    s->pre_map[0x49            ] = 0x48 | FN;          /* Page_Up */
+    s->pre_map[0x51            ] = 0x50 | FN;          /* Page_Down */
+
+    s->modifiers = 0;
+    s->imodifiers = 0;
+    s->fifopos = 0;
+    s->fifolen = 0;
+}
+
+#undef SHIFT
+#undef CTRL
+#undef FN
+
+static int spitz_keyboard_post_load(void *opaque, int version_id)
+{
+    SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
+
+    /* Release all pressed keys */
+    memset(s->keyrow, 0, sizeof(s->keyrow));
+    spitz_keyboard_sense_update(s);
+    s->modifiers = 0;
+    s->imodifiers = 0;
+    s->fifopos = 0;
+    s->fifolen = 0;
+
+    return 0;
+}
+
+static void spitz_keyboard_register(PXA2xxState *cpu)
+{
+    int i;
+    DeviceState *dev;
+    SpitzKeyboardState *s;
+
+    dev = sysbus_create_simple("spitz-keyboard", -1, NULL);
+    s = FROM_SYSBUS(SpitzKeyboardState, SYS_BUS_DEVICE(dev));
+
+    for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++)
+        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i]));
+
+    for (i = 0; i < 5; i ++)
+        s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]);
+
+    if (!graphic_rotate)
+        s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]);
+
+    for (i = 0; i < 5; i++)
+        qemu_set_irq(s->gpiomap[i], 0);
+
+    for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
+        qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i],
+                qdev_get_gpio_in(dev, i));
+
+    qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock));
+
+    qemu_add_kbd_event_handler(spitz_keyboard_handler, s);
+}
+
+static int spitz_keyboard_init(SysBusDevice *dev)
+{
+    SpitzKeyboardState *s;
+    int i, j;
+
+    s = FROM_SYSBUS(SpitzKeyboardState, dev);
+
+    for (i = 0; i < 0x80; i ++)
+        s->keymap[i] = -1;
+    for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++)
+        for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++)
+            if (spitz_keymap[i][j] != -1)
+                s->keymap[spitz_keymap[i][j]] = (i << 4) | j;
+
+    spitz_keyboard_pre_map(s);
+
+    s->kbdtimer = qemu_new_timer_ns(vm_clock, spitz_keyboard_tick, s);
+    qdev_init_gpio_in(&dev->qdev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM);
+    qdev_init_gpio_out(&dev->qdev, s->sense, SPITZ_KEY_SENSE_NUM);
+
+    return 0;
+}
+
+/* LCD backlight controller */
+
+#define LCDTG_RESCTL   0x00
+#define LCDTG_PHACTRL  0x01
+#define LCDTG_DUTYCTRL 0x02
+#define LCDTG_POWERREG0        0x03
+#define LCDTG_POWERREG1        0x04
+#define LCDTG_GPOR3    0x05
+#define LCDTG_PICTRL   0x06
+#define LCDTG_POLCTRL  0x07
+
+typedef struct {
+    SSISlave ssidev;
+    uint32_t bl_intensity;
+    uint32_t bl_power;
+} SpitzLCDTG;
+
+static void spitz_bl_update(SpitzLCDTG *s)
+{
+    if (s->bl_power && s->bl_intensity)
+        zaurus_printf("LCD Backlight now at %i/63\n", s->bl_intensity);
+    else
+        zaurus_printf("LCD Backlight now off\n");
+}
+
+/* FIXME: Implement GPIO properly and remove this hack.  */
+static SpitzLCDTG *spitz_lcdtg;
+
+static inline void spitz_bl_bit5(void *opaque, int line, int level)
+{
+    SpitzLCDTG *s = spitz_lcdtg;
+    int prev = s->bl_intensity;
+
+    if (level)
+        s->bl_intensity &= ~0x20;
+    else
+        s->bl_intensity |= 0x20;
+
+    if (s->bl_power && prev != s->bl_intensity)
+        spitz_bl_update(s);
+}
+
+static inline void spitz_bl_power(void *opaque, int line, int level)
+{
+    SpitzLCDTG *s = spitz_lcdtg;
+    s->bl_power = !!level;
+    spitz_bl_update(s);
+}
+
+static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
+{
+    SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
+    int addr;
+    addr = value >> 5;
+    value &= 0x1f;
+
+    switch (addr) {
+    case LCDTG_RESCTL:
+        if (value)
+            zaurus_printf("LCD in QVGA mode\n");
+        else
+            zaurus_printf("LCD in VGA mode\n");
+        break;
+
+    case LCDTG_DUTYCTRL:
+        s->bl_intensity &= ~0x1f;
+        s->bl_intensity |= value;
+        if (s->bl_power)
+            spitz_bl_update(s);
+        break;
+
+    case LCDTG_POWERREG0:
+        /* Set common voltage to M62332FP */
+        break;
+    }
+    return 0;
+}
+
+static int spitz_lcdtg_init(SSISlave *dev)
+{
+    SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
+
+    spitz_lcdtg = s;
+    s->bl_power = 0;
+    s->bl_intensity = 0x20;
+
+    return 0;
+}
+
+/* SSP devices */
+
+#define CORGI_SSP_PORT         2
+
+#define SPITZ_GPIO_LCDCON_CS   53
+#define SPITZ_GPIO_ADS7846_CS  14
+#define SPITZ_GPIO_MAX1111_CS  20
+#define SPITZ_GPIO_TP_INT      11
+
+static DeviceState *max1111;
+
+/* "Demux" the signal based on current chipselect */
+typedef struct {
+    SSISlave ssidev;
+    SSIBus *bus[3];
+    uint32_t enable[3];
+} CorgiSSPState;
+
+static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value)
+{
+    CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
+    int i;
+
+    for (i = 0; i < 3; i++) {
+        if (s->enable[i]) {
+            return ssi_transfer(s->bus[i], value);
+        }
+    }
+    return 0;
+}
+
+static void corgi_ssp_gpio_cs(void *opaque, int line, int level)
+{
+    CorgiSSPState *s = (CorgiSSPState *)opaque;
+    assert(line >= 0 && line < 3);
+    s->enable[line] = !level;
+}
+
+#define MAX1111_BATT_VOLT      1
+#define MAX1111_BATT_TEMP      2
+#define MAX1111_ACIN_VOLT      3
+
+#define SPITZ_BATTERY_TEMP     0xe0    /* About 2.9V */
+#define SPITZ_BATTERY_VOLT     0xd0    /* About 4.0V */
+#define SPITZ_CHARGEON_ACIN    0x80    /* About 5.0V */
+
+static void spitz_adc_temp_on(void *opaque, int line, int level)
+{
+    if (!max1111)
+        return;
+
+    if (level)
+        max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP);
+    else
+        max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
+}
+
+static int corgi_ssp_init(SSISlave *dev)
+{
+    CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
+
+    qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3);
+    s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
+    s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
+    s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2");
+
+    return 0;
+}
+
+static void spitz_ssp_attach(PXA2xxState *cpu)
+{
+    DeviceState *mux;
+    DeviceState *dev;
+    void *bus;
+
+    mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp");
+
+    bus = qdev_get_child_bus(mux, "ssi0");
+    ssi_create_slave(bus, "spitz-lcdtg");
+
+    bus = qdev_get_child_bus(mux, "ssi1");
+    dev = ssi_create_slave(bus, "ads7846");
+    qdev_connect_gpio_out(dev, 0,
+                          qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT));
+
+    bus = qdev_get_child_bus(mux, "ssi2");
+    max1111 = ssi_create_slave(bus, "max1111");
+    max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT);
+    max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
+    max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN);
+
+    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS,
+                        qdev_get_gpio_in(mux, 0));
+    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS,
+                        qdev_get_gpio_in(mux, 1));
+    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS,
+                        qdev_get_gpio_in(mux, 2));
+}
+
+/* CF Microdrive */
+
+static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
+{
+    PCMCIACardState *md;
+    DriveInfo *dinfo;
+
+    dinfo = drive_get(IF_IDE, 0, 0);
+    if (!dinfo || dinfo->media_cd)
+        return;
+    md = dscm1xxxx_init(dinfo);
+    pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
+}
+
+/* Wm8750 and Max7310 on I2C */
+
+#define AKITA_MAX_ADDR 0x18
+#define SPITZ_WM_ADDRL 0x1b
+#define SPITZ_WM_ADDRH 0x1a
+
+#define SPITZ_GPIO_WM  5
+
+static void spitz_wm8750_addr(void *opaque, int line, int level)
+{
+    I2CSlave *wm = (I2CSlave *) opaque;
+    if (level)
+        i2c_set_slave_address(wm, SPITZ_WM_ADDRH);
+    else
+        i2c_set_slave_address(wm, SPITZ_WM_ADDRL);
+}
+
+static void spitz_i2c_setup(PXA2xxState *cpu)
+{
+    /* Attach the CPU on one end of our I2C bus.  */
+    i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
+
+    DeviceState *wm;
+
+    /* Attach a WM8750 to the bus */
+    wm = i2c_create_slave(bus, "wm8750", 0);
+
+    spitz_wm8750_addr(wm, 0, 0);
+    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM,
+                    qemu_allocate_irqs(spitz_wm8750_addr, wm, 1)[0]);
+    /* .. and to the sound interface.  */
+    cpu->i2s->opaque = wm;
+    cpu->i2s->codec_out = wm8750_dac_dat;
+    cpu->i2s->codec_in = wm8750_adc_dat;
+    wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
+}
+
+static void spitz_akita_i2c_setup(PXA2xxState *cpu)
+{
+    /* Attach a Max7310 to Akita I2C bus.  */
+    i2c_create_slave(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310",
+                     AKITA_MAX_ADDR);
+}
+
+/* Other peripherals */
+
+static void spitz_out_switch(void *opaque, int line, int level)
+{
+    switch (line) {
+    case 0:
+        zaurus_printf("Charging %s.\n", level ? "off" : "on");
+        break;
+    case 1:
+        zaurus_printf("Discharging %s.\n", level ? "on" : "off");
+        break;
+    case 2:
+        zaurus_printf("Green LED %s.\n", level ? "on" : "off");
+        break;
+    case 3:
+        zaurus_printf("Orange LED %s.\n", level ? "on" : "off");
+        break;
+    case 4:
+        spitz_bl_bit5(opaque, line, level);
+        break;
+    case 5:
+        spitz_bl_power(opaque, line, level);
+        break;
+    case 6:
+        spitz_adc_temp_on(opaque, line, level);
+        break;
+    }
+}
+
+#define SPITZ_SCP_LED_GREEN            1
+#define SPITZ_SCP_JK_B                 2
+#define SPITZ_SCP_CHRG_ON              3
+#define SPITZ_SCP_MUTE_L               4
+#define SPITZ_SCP_MUTE_R               5
+#define SPITZ_SCP_CF_POWER             6
+#define SPITZ_SCP_LED_ORANGE           7
+#define SPITZ_SCP_JK_A                 8
+#define SPITZ_SCP_ADC_TEMP_ON          9
+#define SPITZ_SCP2_IR_ON               1
+#define SPITZ_SCP2_AKIN_PULLUP         2
+#define SPITZ_SCP2_BACKLIGHT_CONT      7
+#define SPITZ_SCP2_BACKLIGHT_ON                8
+#define SPITZ_SCP2_MIC_BIAS            9
+
+static void spitz_scoop_gpio_setup(PXA2xxState *cpu,
+                DeviceState *scp0, DeviceState *scp1)
+{
+    qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8);
+
+    qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]);
+    qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]);
+    qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]);
+    qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]);
+
+    if (scp1) {
+        qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]);
+        qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]);
+    }
+
+    qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]);
+}
+
+#define SPITZ_GPIO_HSYNC               22
+#define SPITZ_GPIO_SD_DETECT           9
+#define SPITZ_GPIO_SD_WP               81
+#define SPITZ_GPIO_ON_RESET            89
+#define SPITZ_GPIO_BAT_COVER           90
+#define SPITZ_GPIO_CF1_IRQ             105
+#define SPITZ_GPIO_CF1_CD              94
+#define SPITZ_GPIO_CF2_IRQ             106
+#define SPITZ_GPIO_CF2_CD              93
+
+static int spitz_hsync;
+
+static void spitz_lcd_hsync_handler(void *opaque, int line, int level)
+{
+    PXA2xxState *cpu = (PXA2xxState *) opaque;
+    qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync);
+    spitz_hsync ^= 1;
+}
+
+static void spitz_gpio_setup(PXA2xxState *cpu, int slots)
+{
+    qemu_irq lcd_hsync;
+    /*
+     * Bad hack: We toggle the LCD hsync GPIO on every GPIO status
+     * read to satisfy broken guests that poll-wait for hsync.
+     * Simulating a real hsync event would be less practical and
+     * wouldn't guarantee that a guest ever exits the loop.
+     */
+    spitz_hsync = 0;
+    lcd_hsync = qemu_allocate_irqs(spitz_lcd_hsync_handler, cpu, 1)[0];
+    pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync);
+    pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync);
+
+    /* MMC/SD host */
+    pxa2xx_mmci_handlers(cpu->mmc,
+                    qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP),
+                    qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT));
+
+    /* Battery lock always closed */
+    qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER));
+
+    /* Handle reset */
+    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset);
+
+    /* PCMCIA signals: card's IRQ and Card-Detect */
+    if (slots >= 1)
+        pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
+                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ),
+                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD));
+    if (slots >= 2)
+        pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
+                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ),
+                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD));
+}
+
+/* Board init.  */
+enum spitz_model_e { spitz, akita, borzoi, terrier };
+
+#define SPITZ_RAM      0x04000000
+#define SPITZ_ROM      0x00800000
+
+static struct arm_boot_info spitz_binfo = {
+    .loader_start = PXA2XX_SDRAM_BASE,
+    .ram_size = 0x04000000,
+};
+
+static void spitz_common_init(QEMUMachineInitArgs *args,
+                              enum spitz_model_e model, int arm_id)
+{
+    PXA2xxState *mpu;
+    DeviceState *scp0, *scp1 = NULL;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *rom = g_new(MemoryRegion, 1);
+    const char *cpu_model = args->cpu_model;
+
+    if (!cpu_model)
+        cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
+
+    /* Setup CPU & memory */
+    mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model);
+
+    sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
+
+    memory_region_init_ram(rom, "spitz.rom", SPITZ_ROM);
+    vmstate_register_ram_global(rom);
+    memory_region_set_readonly(rom, true);
+    memory_region_add_subregion(address_space_mem, 0, rom);
+
+    /* Setup peripherals */
+    spitz_keyboard_register(mpu);
+
+    spitz_ssp_attach(mpu);
+
+    scp0 = sysbus_create_simple("scoop", 0x10800000, NULL);
+    if (model != akita) {
+        scp1 = sysbus_create_simple("scoop", 0x08800040, NULL);
+    }
+
+    spitz_scoop_gpio_setup(mpu, scp0, scp1);
+
+    spitz_gpio_setup(mpu, (model == akita) ? 1 : 2);
+
+    spitz_i2c_setup(mpu);
+
+    if (model == akita)
+        spitz_akita_i2c_setup(mpu);
+
+    if (model == terrier)
+        /* A 6.0 GB microdrive is permanently sitting in CF slot 1.  */
+        spitz_microdrive_attach(mpu, 1);
+    else if (model != akita)
+        /* A 4.0 GB microdrive is permanently sitting in CF slot 0.  */
+        spitz_microdrive_attach(mpu, 0);
+
+    spitz_binfo.kernel_filename = args->kernel_filename;
+    spitz_binfo.kernel_cmdline = args->kernel_cmdline;
+    spitz_binfo.initrd_filename = args->initrd_filename;
+    spitz_binfo.board_id = arm_id;
+    arm_load_kernel(mpu->cpu, &spitz_binfo);
+    sl_bootparam_write(SL_PXA_PARAM_BASE);
+}
+
+static void spitz_init(QEMUMachineInitArgs *args)
+{
+    spitz_common_init(args, spitz, 0x2c9);
+}
+
+static void borzoi_init(QEMUMachineInitArgs *args)
+{
+    spitz_common_init(args, borzoi, 0x33f);
+}
+
+static void akita_init(QEMUMachineInitArgs *args)
+{
+    spitz_common_init(args, akita, 0x2e8);
+}
+
+static void terrier_init(QEMUMachineInitArgs *args)
+{
+    spitz_common_init(args, terrier, 0x33f);
+}
+
+static QEMUMachine akitapda_machine = {
+    .name = "akita",
+    .desc = "Akita PDA (PXA270)",
+    .init = akita_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine spitzpda_machine = {
+    .name = "spitz",
+    .desc = "Spitz PDA (PXA270)",
+    .init = spitz_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine borzoipda_machine = {
+    .name = "borzoi",
+    .desc = "Borzoi PDA (PXA270)",
+    .init = borzoi_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine terrierpda_machine = {
+    .name = "terrier",
+    .desc = "Terrier PDA (PXA270)",
+    .init = terrier_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void spitz_machine_init(void)
+{
+    qemu_register_machine(&akitapda_machine);
+    qemu_register_machine(&spitzpda_machine);
+    qemu_register_machine(&borzoipda_machine);
+    qemu_register_machine(&terrierpda_machine);
+}
+
+machine_init(spitz_machine_init);
+
+static bool is_version_0(void *opaque, int version_id)
+{
+    return version_id == 0;
+}
+
+static VMStateDescription vmstate_sl_nand_info = {
+    .name = "sl-nand",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT8(ctl, SLNANDState),
+        VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static Property sl_nand_properties[] = {
+    DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
+    DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sl_nand_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sl_nand_init;
+    dc->vmsd = &vmstate_sl_nand_info;
+    dc->props = sl_nand_properties;
+}
+
+static const TypeInfo sl_nand_info = {
+    .name          = "sl-nand",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SLNANDState),
+    .class_init    = sl_nand_class_init,
+};
+
+static VMStateDescription vmstate_spitz_kbd = {
+    .name = "spitz-keyboard",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = spitz_keyboard_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT16(sense_state, SpitzKeyboardState),
+        VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
+        VMSTATE_UNUSED_TEST(is_version_0, 5),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static Property spitz_keyboard_properties[] = {
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = spitz_keyboard_init;
+    dc->vmsd = &vmstate_spitz_kbd;
+    dc->props = spitz_keyboard_properties;
+}
+
+static const TypeInfo spitz_keyboard_info = {
+    .name          = "spitz-keyboard",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SpitzKeyboardState),
+    .class_init    = spitz_keyboard_class_init,
+};
+
+static const VMStateDescription vmstate_corgi_ssp_regs = {
+    .name = "corgi-ssp",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField []) {
+        VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState),
+        VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void corgi_ssp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = corgi_ssp_init;
+    k->transfer = corgi_ssp_transfer;
+    dc->vmsd = &vmstate_corgi_ssp_regs;
+}
+
+static const TypeInfo corgi_ssp_info = {
+    .name          = "corgi-ssp",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(CorgiSSPState),
+    .class_init    = corgi_ssp_class_init,
+};
+
+static const VMStateDescription vmstate_spitz_lcdtg_regs = {
+    .name = "spitz-lcdtg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG),
+        VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
+        VMSTATE_UINT32(bl_power, SpitzLCDTG),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = spitz_lcdtg_init;
+    k->transfer = spitz_lcdtg_transfer;
+    dc->vmsd = &vmstate_spitz_lcdtg_regs;
+}
+
+static const TypeInfo spitz_lcdtg_info = {
+    .name          = "spitz-lcdtg",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(SpitzLCDTG),
+    .class_init    = spitz_lcdtg_class_init,
+};
+
+static void spitz_register_types(void)
+{
+    type_register_static(&corgi_ssp_info);
+    type_register_static(&spitz_lcdtg_info);
+    type_register_static(&spitz_keyboard_info);
+    type_register_static(&sl_nand_info);
+}
+
+type_init(spitz_register_types)
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
new file mode 100644 (file)
index 0000000..f4ce794
--- /dev/null
@@ -0,0 +1,1401 @@
+/*
+ * Luminary Micro Stellaris peripherals
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/ssi.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "qemu/timer.h"
+#include "hw/i2c.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "exec/address-spaces.h"
+
+#define GPIO_A 0
+#define GPIO_B 1
+#define GPIO_C 2
+#define GPIO_D 3
+#define GPIO_E 4
+#define GPIO_F 5
+#define GPIO_G 6
+
+#define BP_OLED_I2C  0x01
+#define BP_OLED_SSI  0x02
+#define BP_GAMEPAD   0x04
+
+typedef const struct {
+    const char *name;
+    uint32_t did0;
+    uint32_t did1;
+    uint32_t dc0;
+    uint32_t dc1;
+    uint32_t dc2;
+    uint32_t dc3;
+    uint32_t dc4;
+    uint32_t peripherals;
+} stellaris_board_info;
+
+/* General purpose timer module.  */
+
+typedef struct gptm_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t config;
+    uint32_t mode[2];
+    uint32_t control;
+    uint32_t state;
+    uint32_t mask;
+    uint32_t load[2];
+    uint32_t match[2];
+    uint32_t prescale[2];
+    uint32_t match_prescale[2];
+    uint32_t rtc;
+    int64_t tick[2];
+    struct gptm_state *opaque[2];
+    QEMUTimer *timer[2];
+    /* The timers have an alternate output used to trigger the ADC.  */
+    qemu_irq trigger;
+    qemu_irq irq;
+} gptm_state;
+
+static void gptm_update_irq(gptm_state *s)
+{
+    int level;
+    level = (s->state & s->mask) != 0;
+    qemu_set_irq(s->irq, level);
+}
+
+static void gptm_stop(gptm_state *s, int n)
+{
+    qemu_del_timer(s->timer[n]);
+}
+
+static void gptm_reload(gptm_state *s, int n, int reset)
+{
+    int64_t tick;
+    if (reset)
+        tick = qemu_get_clock_ns(vm_clock);
+    else
+        tick = s->tick[n];
+
+    if (s->config == 0) {
+        /* 32-bit CountDown.  */
+        uint32_t count;
+        count = s->load[0] | (s->load[1] << 16);
+        tick += (int64_t)count * system_clock_scale;
+    } else if (s->config == 1) {
+        /* 32-bit RTC.  1Hz tick.  */
+        tick += get_ticks_per_sec();
+    } else if (s->mode[n] == 0xa) {
+        /* PWM mode.  Not implemented.  */
+    } else {
+        hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
+    }
+    s->tick[n] = tick;
+    qemu_mod_timer(s->timer[n], tick);
+}
+
+static void gptm_tick(void *opaque)
+{
+    gptm_state **p = (gptm_state **)opaque;
+    gptm_state *s;
+    int n;
+
+    s = *p;
+    n = p - s->opaque;
+    if (s->config == 0) {
+        s->state |= 1;
+        if ((s->control & 0x20)) {
+            /* Output trigger.  */
+           qemu_irq_pulse(s->trigger);
+        }
+        if (s->mode[0] & 1) {
+            /* One-shot.  */
+            s->control &= ~1;
+        } else {
+            /* Periodic.  */
+            gptm_reload(s, 0, 0);
+        }
+    } else if (s->config == 1) {
+        /* RTC.  */
+        uint32_t match;
+        s->rtc++;
+        match = s->match[0] | (s->match[1] << 16);
+        if (s->rtc > match)
+            s->rtc = 0;
+        if (s->rtc == 0) {
+            s->state |= 8;
+        }
+        gptm_reload(s, 0, 0);
+    } else if (s->mode[n] == 0xa) {
+        /* PWM mode.  Not implemented.  */
+    } else {
+        hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
+    }
+    gptm_update_irq(s);
+}
+
+static uint64_t gptm_read(void *opaque, hwaddr offset,
+                          unsigned size)
+{
+    gptm_state *s = (gptm_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* CFG */
+        return s->config;
+    case 0x04: /* TAMR */
+        return s->mode[0];
+    case 0x08: /* TBMR */
+        return s->mode[1];
+    case 0x0c: /* CTL */
+        return s->control;
+    case 0x18: /* IMR */
+        return s->mask;
+    case 0x1c: /* RIS */
+        return s->state;
+    case 0x20: /* MIS */
+        return s->state & s->mask;
+    case 0x24: /* CR */
+        return 0;
+    case 0x28: /* TAILR */
+        return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0);
+    case 0x2c: /* TBILR */
+        return s->load[1];
+    case 0x30: /* TAMARCHR */
+        return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0);
+    case 0x34: /* TBMATCHR */
+        return s->match[1];
+    case 0x38: /* TAPR */
+        return s->prescale[0];
+    case 0x3c: /* TBPR */
+        return s->prescale[1];
+    case 0x40: /* TAPMR */
+        return s->match_prescale[0];
+    case 0x44: /* TBPMR */
+        return s->match_prescale[1];
+    case 0x48: /* TAR */
+        if (s->control == 1)
+            return s->rtc;
+    case 0x4c: /* TBR */
+        hw_error("TODO: Timer value read\n");
+    default:
+        hw_error("gptm_read: Bad offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void gptm_write(void *opaque, hwaddr offset,
+                       uint64_t value, unsigned size)
+{
+    gptm_state *s = (gptm_state *)opaque;
+    uint32_t oldval;
+
+    /* The timers should be disabled before changing the configuration.
+       We take advantage of this and defer everything until the timer
+       is enabled.  */
+    switch (offset) {
+    case 0x00: /* CFG */
+        s->config = value;
+        break;
+    case 0x04: /* TAMR */
+        s->mode[0] = value;
+        break;
+    case 0x08: /* TBMR */
+        s->mode[1] = value;
+        break;
+    case 0x0c: /* CTL */
+        oldval = s->control;
+        s->control = value;
+        /* TODO: Implement pause.  */
+        if ((oldval ^ value) & 1) {
+            if (value & 1) {
+                gptm_reload(s, 0, 1);
+            } else {
+                gptm_stop(s, 0);
+            }
+        }
+        if (((oldval ^ value) & 0x100) && s->config >= 4) {
+            if (value & 0x100) {
+                gptm_reload(s, 1, 1);
+            } else {
+                gptm_stop(s, 1);
+            }
+        }
+        break;
+    case 0x18: /* IMR */
+        s->mask = value & 0x77;
+        gptm_update_irq(s);
+        break;
+    case 0x24: /* CR */
+        s->state &= ~value;
+        break;
+    case 0x28: /* TAILR */
+        s->load[0] = value & 0xffff;
+        if (s->config < 4) {
+            s->load[1] = value >> 16;
+        }
+        break;
+    case 0x2c: /* TBILR */
+        s->load[1] = value & 0xffff;
+        break;
+    case 0x30: /* TAMARCHR */
+        s->match[0] = value & 0xffff;
+        if (s->config < 4) {
+            s->match[1] = value >> 16;
+        }
+        break;
+    case 0x34: /* TBMATCHR */
+        s->match[1] = value >> 16;
+        break;
+    case 0x38: /* TAPR */
+        s->prescale[0] = value;
+        break;
+    case 0x3c: /* TBPR */
+        s->prescale[1] = value;
+        break;
+    case 0x40: /* TAPMR */
+        s->match_prescale[0] = value;
+        break;
+    case 0x44: /* TBPMR */
+        s->match_prescale[0] = value;
+        break;
+    default:
+        hw_error("gptm_write: Bad offset 0x%x\n", (int)offset);
+    }
+    gptm_update_irq(s);
+}
+
+static const MemoryRegionOps gptm_ops = {
+    .read = gptm_read,
+    .write = gptm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_stellaris_gptm = {
+    .name = "stellaris_gptm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(config, gptm_state),
+        VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
+        VMSTATE_UINT32(control, gptm_state),
+        VMSTATE_UINT32(state, gptm_state),
+        VMSTATE_UINT32(mask, gptm_state),
+        VMSTATE_UNUSED(8),
+        VMSTATE_UINT32_ARRAY(load, gptm_state, 2),
+        VMSTATE_UINT32_ARRAY(match, gptm_state, 2),
+        VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2),
+        VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2),
+        VMSTATE_UINT32(rtc, gptm_state),
+        VMSTATE_INT64_ARRAY(tick, gptm_state, 2),
+        VMSTATE_TIMER_ARRAY(timer, gptm_state, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int stellaris_gptm_init(SysBusDevice *dev)
+{
+    gptm_state *s = FROM_SYSBUS(gptm_state, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+    qdev_init_gpio_out(&dev->qdev, &s->trigger, 1);
+
+    memory_region_init_io(&s->iomem, &gptm_ops, s,
+                          "gptm", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    s->opaque[0] = s->opaque[1] = s;
+    s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]);
+    s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s);
+    return 0;
+}
+
+
+/* System controller.  */
+
+typedef struct {
+    MemoryRegion iomem;
+    uint32_t pborctl;
+    uint32_t ldopctl;
+    uint32_t int_status;
+    uint32_t int_mask;
+    uint32_t resc;
+    uint32_t rcc;
+    uint32_t rcc2;
+    uint32_t rcgc[3];
+    uint32_t scgc[3];
+    uint32_t dcgc[3];
+    uint32_t clkvclr;
+    uint32_t ldoarst;
+    uint32_t user0;
+    uint32_t user1;
+    qemu_irq irq;
+    stellaris_board_info *board;
+} ssys_state;
+
+static void ssys_update(ssys_state *s)
+{
+  qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
+}
+
+static uint32_t pllcfg_sandstorm[16] = {
+    0x31c0, /* 1 Mhz */
+    0x1ae0, /* 1.8432 Mhz */
+    0x18c0, /* 2 Mhz */
+    0xd573, /* 2.4576 Mhz */
+    0x37a6, /* 3.57954 Mhz */
+    0x1ae2, /* 3.6864 Mhz */
+    0x0c40, /* 4 Mhz */
+    0x98bc, /* 4.906 Mhz */
+    0x935b, /* 4.9152 Mhz */
+    0x09c0, /* 5 Mhz */
+    0x4dee, /* 5.12 Mhz */
+    0x0c41, /* 6 Mhz */
+    0x75db, /* 6.144 Mhz */
+    0x1ae6, /* 7.3728 Mhz */
+    0x0600, /* 8 Mhz */
+    0x585b /* 8.192 Mhz */
+};
+
+static uint32_t pllcfg_fury[16] = {
+    0x3200, /* 1 Mhz */
+    0x1b20, /* 1.8432 Mhz */
+    0x1900, /* 2 Mhz */
+    0xf42b, /* 2.4576 Mhz */
+    0x37e3, /* 3.57954 Mhz */
+    0x1b21, /* 3.6864 Mhz */
+    0x0c80, /* 4 Mhz */
+    0x98ee, /* 4.906 Mhz */
+    0xd5b4, /* 4.9152 Mhz */
+    0x0a00, /* 5 Mhz */
+    0x4e27, /* 5.12 Mhz */
+    0x1902, /* 6 Mhz */
+    0xec1c, /* 6.144 Mhz */
+    0x1b23, /* 7.3728 Mhz */
+    0x0640, /* 8 Mhz */
+    0xb11c /* 8.192 Mhz */
+};
+
+#define DID0_VER_MASK        0x70000000
+#define DID0_VER_0           0x00000000
+#define DID0_VER_1           0x10000000
+
+#define DID0_CLASS_MASK      0x00FF0000
+#define DID0_CLASS_SANDSTORM 0x00000000
+#define DID0_CLASS_FURY      0x00010000
+
+static int ssys_board_class(const ssys_state *s)
+{
+    uint32_t did0 = s->board->did0;
+    switch (did0 & DID0_VER_MASK) {
+    case DID0_VER_0:
+        return DID0_CLASS_SANDSTORM;
+    case DID0_VER_1:
+        switch (did0 & DID0_CLASS_MASK) {
+        case DID0_CLASS_SANDSTORM:
+        case DID0_CLASS_FURY:
+            return did0 & DID0_CLASS_MASK;
+        }
+        /* for unknown classes, fall through */
+    default:
+        hw_error("ssys_board_class: Unknown class 0x%08x\n", did0);
+    }
+}
+
+static uint64_t ssys_read(void *opaque, hwaddr offset,
+                          unsigned size)
+{
+    ssys_state *s = (ssys_state *)opaque;
+
+    switch (offset) {
+    case 0x000: /* DID0 */
+        return s->board->did0;
+    case 0x004: /* DID1 */
+        return s->board->did1;
+    case 0x008: /* DC0 */
+        return s->board->dc0;
+    case 0x010: /* DC1 */
+        return s->board->dc1;
+    case 0x014: /* DC2 */
+        return s->board->dc2;
+    case 0x018: /* DC3 */
+        return s->board->dc3;
+    case 0x01c: /* DC4 */
+        return s->board->dc4;
+    case 0x030: /* PBORCTL */
+        return s->pborctl;
+    case 0x034: /* LDOPCTL */
+        return s->ldopctl;
+    case 0x040: /* SRCR0 */
+        return 0;
+    case 0x044: /* SRCR1 */
+        return 0;
+    case 0x048: /* SRCR2 */
+        return 0;
+    case 0x050: /* RIS */
+        return s->int_status;
+    case 0x054: /* IMC */
+        return s->int_mask;
+    case 0x058: /* MISC */
+        return s->int_status & s->int_mask;
+    case 0x05c: /* RESC */
+        return s->resc;
+    case 0x060: /* RCC */
+        return s->rcc;
+    case 0x064: /* PLLCFG */
+        {
+            int xtal;
+            xtal = (s->rcc >> 6) & 0xf;
+            switch (ssys_board_class(s)) {
+            case DID0_CLASS_FURY:
+                return pllcfg_fury[xtal];
+            case DID0_CLASS_SANDSTORM:
+                return pllcfg_sandstorm[xtal];
+            default:
+                hw_error("ssys_read: Unhandled class for PLLCFG read.\n");
+                return 0;
+            }
+        }
+    case 0x070: /* RCC2 */
+        return s->rcc2;
+    case 0x100: /* RCGC0 */
+        return s->rcgc[0];
+    case 0x104: /* RCGC1 */
+        return s->rcgc[1];
+    case 0x108: /* RCGC2 */
+        return s->rcgc[2];
+    case 0x110: /* SCGC0 */
+        return s->scgc[0];
+    case 0x114: /* SCGC1 */
+        return s->scgc[1];
+    case 0x118: /* SCGC2 */
+        return s->scgc[2];
+    case 0x120: /* DCGC0 */
+        return s->dcgc[0];
+    case 0x124: /* DCGC1 */
+        return s->dcgc[1];
+    case 0x128: /* DCGC2 */
+        return s->dcgc[2];
+    case 0x150: /* CLKVCLR */
+        return s->clkvclr;
+    case 0x160: /* LDOARST */
+        return s->ldoarst;
+    case 0x1e0: /* USER0 */
+        return s->user0;
+    case 0x1e4: /* USER1 */
+        return s->user1;
+    default:
+        hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static bool ssys_use_rcc2(ssys_state *s)
+{
+    return (s->rcc2 >> 31) & 0x1;
+}
+
+/*
+ * Caculate the sys. clock period in ms.
+ */
+static void ssys_calculate_system_clock(ssys_state *s)
+{
+    if (ssys_use_rcc2(s)) {
+        system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
+    } else {
+        system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
+    }
+}
+
+static void ssys_write(void *opaque, hwaddr offset,
+                       uint64_t value, unsigned size)
+{
+    ssys_state *s = (ssys_state *)opaque;
+
+    switch (offset) {
+    case 0x030: /* PBORCTL */
+        s->pborctl = value & 0xffff;
+        break;
+    case 0x034: /* LDOPCTL */
+        s->ldopctl = value & 0x1f;
+        break;
+    case 0x040: /* SRCR0 */
+    case 0x044: /* SRCR1 */
+    case 0x048: /* SRCR2 */
+        fprintf(stderr, "Peripheral reset not implemented\n");
+        break;
+    case 0x054: /* IMC */
+        s->int_mask = value & 0x7f;
+        break;
+    case 0x058: /* MISC */
+        s->int_status &= ~value;
+        break;
+    case 0x05c: /* RESC */
+        s->resc = value & 0x3f;
+        break;
+    case 0x060: /* RCC */
+        if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
+            /* PLL enable.  */
+            s->int_status |= (1 << 6);
+        }
+        s->rcc = value;
+        ssys_calculate_system_clock(s);
+        break;
+    case 0x070: /* RCC2 */
+        if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
+            break;
+        }
+
+        if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
+            /* PLL enable.  */
+            s->int_status |= (1 << 6);
+        }
+        s->rcc2 = value;
+        ssys_calculate_system_clock(s);
+        break;
+    case 0x100: /* RCGC0 */
+        s->rcgc[0] = value;
+        break;
+    case 0x104: /* RCGC1 */
+        s->rcgc[1] = value;
+        break;
+    case 0x108: /* RCGC2 */
+        s->rcgc[2] = value;
+        break;
+    case 0x110: /* SCGC0 */
+        s->scgc[0] = value;
+        break;
+    case 0x114: /* SCGC1 */
+        s->scgc[1] = value;
+        break;
+    case 0x118: /* SCGC2 */
+        s->scgc[2] = value;
+        break;
+    case 0x120: /* DCGC0 */
+        s->dcgc[0] = value;
+        break;
+    case 0x124: /* DCGC1 */
+        s->dcgc[1] = value;
+        break;
+    case 0x128: /* DCGC2 */
+        s->dcgc[2] = value;
+        break;
+    case 0x150: /* CLKVCLR */
+        s->clkvclr = value;
+        break;
+    case 0x160: /* LDOARST */
+        s->ldoarst = value;
+        break;
+    default:
+        hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
+    }
+    ssys_update(s);
+}
+
+static const MemoryRegionOps ssys_ops = {
+    .read = ssys_read,
+    .write = ssys_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void ssys_reset(void *opaque)
+{
+    ssys_state *s = (ssys_state *)opaque;
+
+    s->pborctl = 0x7ffd;
+    s->rcc = 0x078e3ac0;
+
+    if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
+        s->rcc2 = 0;
+    } else {
+        s->rcc2 = 0x07802810;
+    }
+    s->rcgc[0] = 1;
+    s->scgc[0] = 1;
+    s->dcgc[0] = 1;
+    ssys_calculate_system_clock(s);
+}
+
+static int stellaris_sys_post_load(void *opaque, int version_id)
+{
+    ssys_state *s = opaque;
+
+    ssys_calculate_system_clock(s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_stellaris_sys = {
+    .name = "stellaris_sys",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = stellaris_sys_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(pborctl, ssys_state),
+        VMSTATE_UINT32(ldopctl, ssys_state),
+        VMSTATE_UINT32(int_mask, ssys_state),
+        VMSTATE_UINT32(int_status, ssys_state),
+        VMSTATE_UINT32(resc, ssys_state),
+        VMSTATE_UINT32(rcc, ssys_state),
+        VMSTATE_UINT32_V(rcc2, ssys_state, 2),
+        VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3),
+        VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3),
+        VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
+        VMSTATE_UINT32(clkvclr, ssys_state),
+        VMSTATE_UINT32(ldoarst, ssys_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int stellaris_sys_init(uint32_t base, qemu_irq irq,
+                              stellaris_board_info * board,
+                              uint8_t *macaddr)
+{
+    ssys_state *s;
+
+    s = (ssys_state *)g_malloc0(sizeof(ssys_state));
+    s->irq = irq;
+    s->board = board;
+    /* Most devices come preprogrammed with a MAC address in the user data. */
+    s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
+    s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
+
+    memory_region_init_io(&s->iomem, &ssys_ops, s, "ssys", 0x00001000);
+    memory_region_add_subregion(get_system_memory(), base, &s->iomem);
+    ssys_reset(s);
+    vmstate_register(NULL, -1, &vmstate_stellaris_sys, s);
+    return 0;
+}
+
+
+/* I2C controller.  */
+
+typedef struct {
+    SysBusDevice busdev;
+    i2c_bus *bus;
+    qemu_irq irq;
+    MemoryRegion iomem;
+    uint32_t msa;
+    uint32_t mcs;
+    uint32_t mdr;
+    uint32_t mtpr;
+    uint32_t mimr;
+    uint32_t mris;
+    uint32_t mcr;
+} stellaris_i2c_state;
+
+#define STELLARIS_I2C_MCS_BUSY    0x01
+#define STELLARIS_I2C_MCS_ERROR   0x02
+#define STELLARIS_I2C_MCS_ADRACK  0x04
+#define STELLARIS_I2C_MCS_DATACK  0x08
+#define STELLARIS_I2C_MCS_ARBLST  0x10
+#define STELLARIS_I2C_MCS_IDLE    0x20
+#define STELLARIS_I2C_MCS_BUSBSY  0x40
+
+static uint64_t stellaris_i2c_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* MSA */
+        return s->msa;
+    case 0x04: /* MCS */
+        /* We don't emulate timing, so the controller is never busy.  */
+        return s->mcs | STELLARIS_I2C_MCS_IDLE;
+    case 0x08: /* MDR */
+        return s->mdr;
+    case 0x0c: /* MTPR */
+        return s->mtpr;
+    case 0x10: /* MIMR */
+        return s->mimr;
+    case 0x14: /* MRIS */
+        return s->mris;
+    case 0x18: /* MMIS */
+        return s->mris & s->mimr;
+    case 0x20: /* MCR */
+        return s->mcr;
+    default:
+        hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void stellaris_i2c_update(stellaris_i2c_state *s)
+{
+    int level;
+
+    level = (s->mris & s->mimr) != 0;
+    qemu_set_irq(s->irq, level);
+}
+
+static void stellaris_i2c_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* MSA */
+        s->msa = value & 0xff;
+        break;
+    case 0x04: /* MCS */
+        if ((s->mcr & 0x10) == 0) {
+            /* Disabled.  Do nothing.  */
+            break;
+        }
+        /* Grab the bus if this is starting a transfer.  */
+        if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
+            if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
+                s->mcs |= STELLARIS_I2C_MCS_ARBLST;
+            } else {
+                s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
+                s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
+            }
+        }
+        /* If we don't have the bus then indicate an error.  */
+        if (!i2c_bus_busy(s->bus)
+                || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
+            s->mcs |= STELLARIS_I2C_MCS_ERROR;
+            break;
+        }
+        s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
+        if (value & 1) {
+            /* Transfer a byte.  */
+            /* TODO: Handle errors.  */
+            if (s->msa & 1) {
+                /* Recv */
+                s->mdr = i2c_recv(s->bus) & 0xff;
+            } else {
+                /* Send */
+                i2c_send(s->bus, s->mdr);
+            }
+            /* Raise an interrupt.  */
+            s->mris |= 1;
+        }
+        if (value & 4) {
+            /* Finish transfer.  */
+            i2c_end_transfer(s->bus);
+            s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
+        }
+        break;
+    case 0x08: /* MDR */
+        s->mdr = value & 0xff;
+        break;
+    case 0x0c: /* MTPR */
+        s->mtpr = value & 0xff;
+        break;
+    case 0x10: /* MIMR */
+        s->mimr = 1;
+        break;
+    case 0x1c: /* MICR */
+        s->mris &= ~value;
+        break;
+    case 0x20: /* MCR */
+        if (value & 1)
+            hw_error(
+                      "stellaris_i2c_write: Loopback not implemented\n");
+        if (value & 0x20)
+            hw_error(
+                      "stellaris_i2c_write: Slave mode not implemented\n");
+        s->mcr = value & 0x31;
+        break;
+    default:
+        hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
+                  (int)offset);
+    }
+    stellaris_i2c_update(s);
+}
+
+static void stellaris_i2c_reset(stellaris_i2c_state *s)
+{
+    if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
+        i2c_end_transfer(s->bus);
+
+    s->msa = 0;
+    s->mcs = 0;
+    s->mdr = 0;
+    s->mtpr = 1;
+    s->mimr = 0;
+    s->mris = 0;
+    s->mcr = 0;
+    stellaris_i2c_update(s);
+}
+
+static const MemoryRegionOps stellaris_i2c_ops = {
+    .read = stellaris_i2c_read,
+    .write = stellaris_i2c_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_stellaris_i2c = {
+    .name = "stellaris_i2c",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(msa, stellaris_i2c_state),
+        VMSTATE_UINT32(mcs, stellaris_i2c_state),
+        VMSTATE_UINT32(mdr, stellaris_i2c_state),
+        VMSTATE_UINT32(mtpr, stellaris_i2c_state),
+        VMSTATE_UINT32(mimr, stellaris_i2c_state),
+        VMSTATE_UINT32(mris, stellaris_i2c_state),
+        VMSTATE_UINT32(mcr, stellaris_i2c_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int stellaris_i2c_init(SysBusDevice * dev)
+{
+    stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
+    i2c_bus *bus;
+
+    sysbus_init_irq(dev, &s->irq);
+    bus = i2c_init_bus(&dev->qdev, "i2c");
+    s->bus = bus;
+
+    memory_region_init_io(&s->iomem, &stellaris_i2c_ops, s,
+                          "i2c", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    /* ??? For now we only implement the master interface.  */
+    stellaris_i2c_reset(s);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s);
+    return 0;
+}
+
+/* Analogue to Digital Converter.  This is only partially implemented,
+   enough for applications that use a combined ADC and timer tick.  */
+
+#define STELLARIS_ADC_EM_CONTROLLER 0
+#define STELLARIS_ADC_EM_COMP       1
+#define STELLARIS_ADC_EM_EXTERNAL   4
+#define STELLARIS_ADC_EM_TIMER      5
+#define STELLARIS_ADC_EM_PWM0       6
+#define STELLARIS_ADC_EM_PWM1       7
+#define STELLARIS_ADC_EM_PWM2       8
+
+#define STELLARIS_ADC_FIFO_EMPTY    0x0100
+#define STELLARIS_ADC_FIFO_FULL     0x1000
+
+typedef struct
+{
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t actss;
+    uint32_t ris;
+    uint32_t im;
+    uint32_t emux;
+    uint32_t ostat;
+    uint32_t ustat;
+    uint32_t sspri;
+    uint32_t sac;
+    struct {
+        uint32_t state;
+        uint32_t data[16];
+    } fifo[4];
+    uint32_t ssmux[4];
+    uint32_t ssctl[4];
+    uint32_t noise;
+    qemu_irq irq[4];
+} stellaris_adc_state;
+
+static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n)
+{
+    int tail;
+
+    tail = s->fifo[n].state & 0xf;
+    if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
+        s->ustat |= 1 << n;
+    } else {
+        s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
+        s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
+        if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
+            s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
+    }
+    return s->fifo[n].data[tail];
+}
+
+static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n,
+                                     uint32_t value)
+{
+    int head;
+
+    /* TODO: Real hardware has limited size FIFOs.  We have a full 16 entry 
+       FIFO fir each sequencer.  */
+    head = (s->fifo[n].state >> 4) & 0xf;
+    if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
+        s->ostat |= 1 << n;
+        return;
+    }
+    s->fifo[n].data[head] = value;
+    head = (head + 1) & 0xf;
+    s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
+    s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
+    if ((s->fifo[n].state & 0xf) == head)
+        s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
+}
+
+static void stellaris_adc_update(stellaris_adc_state *s)
+{
+    int level;
+    int n;
+
+    for (n = 0; n < 4; n++) {
+        level = (s->ris & s->im & (1 << n)) != 0;
+        qemu_set_irq(s->irq[n], level);
+    }
+}
+
+static void stellaris_adc_trigger(void *opaque, int irq, int level)
+{
+    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
+    int n;
+
+    for (n = 0; n < 4; n++) {
+        if ((s->actss & (1 << n)) == 0) {
+            continue;
+        }
+
+        if (((s->emux >> (n * 4)) & 0xff) != 5) {
+            continue;
+        }
+
+        /* Some applications use the ADC as a random number source, so introduce
+           some variation into the signal.  */
+        s->noise = s->noise * 314159 + 1;
+        /* ??? actual inputs not implemented.  Return an arbitrary value.  */
+        stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
+        s->ris |= (1 << n);
+        stellaris_adc_update(s);
+    }
+}
+
+static void stellaris_adc_reset(stellaris_adc_state *s)
+{
+    int n;
+
+    for (n = 0; n < 4; n++) {
+        s->ssmux[n] = 0;
+        s->ssctl[n] = 0;
+        s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
+    }
+}
+
+static uint64_t stellaris_adc_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
+
+    /* TODO: Implement this.  */
+    if (offset >= 0x40 && offset < 0xc0) {
+        int n;
+        n = (offset - 0x40) >> 5;
+        switch (offset & 0x1f) {
+        case 0x00: /* SSMUX */
+            return s->ssmux[n];
+        case 0x04: /* SSCTL */
+            return s->ssctl[n];
+        case 0x08: /* SSFIFO */
+            return stellaris_adc_fifo_read(s, n);
+        case 0x0c: /* SSFSTAT */
+            return s->fifo[n].state;
+        default:
+            break;
+        }
+    }
+    switch (offset) {
+    case 0x00: /* ACTSS */
+        return s->actss;
+    case 0x04: /* RIS */
+        return s->ris;
+    case 0x08: /* IM */
+        return s->im;
+    case 0x0c: /* ISC */
+        return s->ris & s->im;
+    case 0x10: /* OSTAT */
+        return s->ostat;
+    case 0x14: /* EMUX */
+        return s->emux;
+    case 0x18: /* USTAT */
+        return s->ustat;
+    case 0x20: /* SSPRI */
+        return s->sspri;
+    case 0x30: /* SAC */
+        return s->sac;
+    default:
+        hw_error("strllaris_adc_read: Bad offset 0x%x\n",
+                  (int)offset);
+        return 0;
+    }
+}
+
+static void stellaris_adc_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
+
+    /* TODO: Implement this.  */
+    if (offset >= 0x40 && offset < 0xc0) {
+        int n;
+        n = (offset - 0x40) >> 5;
+        switch (offset & 0x1f) {
+        case 0x00: /* SSMUX */
+            s->ssmux[n] = value & 0x33333333;
+            return;
+        case 0x04: /* SSCTL */
+            if (value != 6) {
+                hw_error("ADC: Unimplemented sequence %" PRIx64 "\n",
+                          value);
+            }
+            s->ssctl[n] = value;
+            return;
+        default:
+            break;
+        }
+    }
+    switch (offset) {
+    case 0x00: /* ACTSS */
+        s->actss = value & 0xf;
+        break;
+    case 0x08: /* IM */
+        s->im = value;
+        break;
+    case 0x0c: /* ISC */
+        s->ris &= ~value;
+        break;
+    case 0x10: /* OSTAT */
+        s->ostat &= ~value;
+        break;
+    case 0x14: /* EMUX */
+        s->emux = value;
+        break;
+    case 0x18: /* USTAT */
+        s->ustat &= ~value;
+        break;
+    case 0x20: /* SSPRI */
+        s->sspri = value;
+        break;
+    case 0x28: /* PSSI */
+        hw_error("Not implemented:  ADC sample initiate\n");
+        break;
+    case 0x30: /* SAC */
+        s->sac = value;
+        break;
+    default:
+        hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
+    }
+    stellaris_adc_update(s);
+}
+
+static const MemoryRegionOps stellaris_adc_ops = {
+    .read = stellaris_adc_read,
+    .write = stellaris_adc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_stellaris_adc = {
+    .name = "stellaris_adc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(actss, stellaris_adc_state),
+        VMSTATE_UINT32(ris, stellaris_adc_state),
+        VMSTATE_UINT32(im, stellaris_adc_state),
+        VMSTATE_UINT32(emux, stellaris_adc_state),
+        VMSTATE_UINT32(ostat, stellaris_adc_state),
+        VMSTATE_UINT32(ustat, stellaris_adc_state),
+        VMSTATE_UINT32(sspri, stellaris_adc_state),
+        VMSTATE_UINT32(sac, stellaris_adc_state),
+        VMSTATE_UINT32(fifo[0].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[0], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[0], stellaris_adc_state),
+        VMSTATE_UINT32(fifo[1].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[1], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[1], stellaris_adc_state),
+        VMSTATE_UINT32(fifo[2].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[2], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[2], stellaris_adc_state),
+        VMSTATE_UINT32(fifo[3].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[3], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[3], stellaris_adc_state),
+        VMSTATE_UINT32(noise, stellaris_adc_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int stellaris_adc_init(SysBusDevice *dev)
+{
+    stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev);
+    int n;
+
+    for (n = 0; n < 4; n++) {
+        sysbus_init_irq(dev, &s->irq[n]);
+    }
+
+    memory_region_init_io(&s->iomem, &stellaris_adc_ops, s,
+                          "adc", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    stellaris_adc_reset(s);
+    qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s);
+    return 0;
+}
+
+/* Board init.  */
+static stellaris_board_info stellaris_boards[] = {
+  { "LM3S811EVB",
+    0,
+    0x0032000e,
+    0x001f001f, /* dc0 */
+    0x001132bf,
+    0x01071013,
+    0x3f0f01ff,
+    0x0000001f,
+    BP_OLED_I2C
+  },
+  { "LM3S6965EVB",
+    0x10010002,
+    0x1073402e,
+    0x00ff007f, /* dc0 */
+    0x001133ff,
+    0x030f5317,
+    0x0f0f87ff,
+    0x5000007f,
+    BP_OLED_SSI | BP_GAMEPAD
+  }
+};
+
+static void stellaris_init(const char *kernel_filename, const char *cpu_model,
+                           stellaris_board_info *board)
+{
+    static const int uart_irq[] = {5, 6, 33, 34};
+    static const int timer_irq[] = {19, 21, 23, 35};
+    static const uint32_t gpio_addr[7] =
+      { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
+        0x40024000, 0x40025000, 0x40026000};
+    static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
+
+    MemoryRegion *address_space_mem = get_system_memory();
+    qemu_irq *pic;
+    DeviceState *gpio_dev[7];
+    qemu_irq gpio_in[7][8];
+    qemu_irq gpio_out[7][8];
+    qemu_irq adc;
+    int sram_size;
+    int flash_size;
+    i2c_bus *i2c;
+    DeviceState *dev;
+    int i;
+    int j;
+
+    flash_size = ((board->dc0 & 0xffff) + 1) << 1;
+    sram_size = (board->dc0 >> 18) + 1;
+    pic = armv7m_init(address_space_mem,
+                      flash_size, sram_size, kernel_filename, cpu_model);
+
+    if (board->dc1 & (1 << 16)) {
+        dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
+                                    pic[14], pic[15], pic[16], pic[17], NULL);
+        adc = qdev_get_gpio_in(dev, 0);
+    } else {
+        adc = NULL;
+    }
+    for (i = 0; i < 4; i++) {
+        if (board->dc2 & (0x10000 << i)) {
+            dev = sysbus_create_simple("stellaris-gptm",
+                                       0x40030000 + i * 0x1000,
+                                       pic[timer_irq[i]]);
+            /* TODO: This is incorrect, but we get away with it because
+               the ADC output is only ever pulsed.  */
+            qdev_connect_gpio_out(dev, 0, adc);
+        }
+    }
+
+    stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a);
+
+    for (i = 0; i < 7; i++) {
+        if (board->dc4 & (1 << i)) {
+            gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
+                                               pic[gpio_irq[i]]);
+            for (j = 0; j < 8; j++) {
+                gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
+                gpio_out[i][j] = NULL;
+            }
+        }
+    }
+
+    if (board->dc2 & (1 << 12)) {
+        dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
+        i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+        if (board->peripherals & BP_OLED_I2C) {
+            i2c_create_slave(i2c, "ssd0303", 0x3d);
+        }
+    }
+
+    for (i = 0; i < 4; i++) {
+        if (board->dc2 & (1 << i)) {
+            sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
+                                 pic[uart_irq[i]]);
+        }
+    }
+    if (board->dc2 & (1 << 4)) {
+        dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
+        if (board->peripherals & BP_OLED_SSI) {
+            void *bus;
+            DeviceState *sddev;
+            DeviceState *ssddev;
+
+            /* Some boards have both an OLED controller and SD card connected to
+             * the same SSI port, with the SD card chip select connected to a
+             * GPIO pin.  Technically the OLED chip select is connected to the
+             * SSI Fss pin.  We do not bother emulating that as both devices
+             * should never be selected simultaneously, and our OLED controller
+             * ignores stray 0xff commands that occur when deselecting the SD
+             * card.
+             */
+            bus = qdev_get_child_bus(dev, "ssi");
+
+            sddev = ssi_create_slave(bus, "ssi-sd");
+            ssddev = ssi_create_slave(bus, "ssd0323");
+            gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0),
+                                                 qdev_get_gpio_in(ssddev, 0));
+            gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1);
+
+            /* Make sure the select pin is high.  */
+            qemu_irq_raise(gpio_out[GPIO_D][0]);
+        }
+    }
+    if (board->dc4 & (1 << 28)) {
+        DeviceState *enet;
+
+        qemu_check_nic_model(&nd_table[0], "stellaris");
+
+        enet = qdev_create(NULL, "stellaris_enet");
+        qdev_set_nic_properties(enet, &nd_table[0]);
+        qdev_init_nofail(enet);
+        sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000);
+        sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, pic[42]);
+    }
+    if (board->peripherals & BP_GAMEPAD) {
+        qemu_irq gpad_irq[5];
+        static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
+
+        gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
+        gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
+        gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
+        gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
+        gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
+
+        stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
+    }
+    for (i = 0; i < 7; i++) {
+        if (board->dc4 & (1 << i)) {
+            for (j = 0; j < 8; j++) {
+                if (gpio_out[i][j]) {
+                    qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
+                }
+            }
+        }
+    }
+}
+
+/* FIXME: Figure out how to generate these from stellaris_boards.  */
+static void lm3s811evb_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
+}
+
+static void lm3s6965evb_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
+}
+
+static QEMUMachine lm3s811evb_machine = {
+    .name = "lm3s811evb",
+    .desc = "Stellaris LM3S811EVB",
+    .init = lm3s811evb_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine lm3s6965evb_machine = {
+    .name = "lm3s6965evb",
+    .desc = "Stellaris LM3S6965EVB",
+    .init = lm3s6965evb_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void stellaris_machine_init(void)
+{
+    qemu_register_machine(&lm3s811evb_machine);
+    qemu_register_machine(&lm3s6965evb_machine);
+}
+
+machine_init(stellaris_machine_init);
+
+static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = stellaris_i2c_init;
+}
+
+static const TypeInfo stellaris_i2c_info = {
+    .name          = "stellaris-i2c",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(stellaris_i2c_state),
+    .class_init    = stellaris_i2c_class_init,
+};
+
+static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = stellaris_gptm_init;
+}
+
+static const TypeInfo stellaris_gptm_info = {
+    .name          = "stellaris-gptm",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(gptm_state),
+    .class_init    = stellaris_gptm_class_init,
+};
+
+static void stellaris_adc_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = stellaris_adc_init;
+}
+
+static const TypeInfo stellaris_adc_info = {
+    .name          = "stellaris-adc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(stellaris_adc_state),
+    .class_init    = stellaris_adc_class_init,
+};
+
+static void stellaris_register_types(void)
+{
+    type_register_static(&stellaris_i2c_info);
+    type_register_static(&stellaris_gptm_info);
+    type_register_static(&stellaris_adc_info);
+}
+
+type_init(stellaris_register_types)
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
new file mode 100644 (file)
index 0000000..747888c
--- /dev/null
@@ -0,0 +1,302 @@
+/* vim:set shiftwidth=4 ts=4 et: */
+/*
+ * PXA255 Sharp Zaurus SL-6000 PDA platform
+ *
+ * Copyright (c) 2008 Dmitry Baryshkov
+ *
+ * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "hw/hw.h"
+#include "hw/pxa.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "hw/sharpsl.h"
+#include "hw/pcmcia.h"
+#include "block/block.h"
+#include "hw/boards.h"
+#include "hw/i2c.h"
+#include "hw/ssi.h"
+#include "sysemu/blockdev.h"
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+
+#define TOSA_RAM    0x04000000
+#define TOSA_ROM       0x00800000
+
+#define TOSA_GPIO_USB_IN               (5)
+#define TOSA_GPIO_nSD_DETECT   (9)
+#define TOSA_GPIO_ON_RESET             (19)
+#define TOSA_GPIO_CF_IRQ               (21)    /* CF slot0 Ready */
+#define TOSA_GPIO_CF_CD                        (13)
+#define TOSA_GPIO_TC6393XB_INT  (15)
+#define TOSA_GPIO_JC_CF_IRQ            (36)    /* CF slot1 Ready */
+
+#define TOSA_SCOOP_GPIO_BASE   1
+#define TOSA_GPIO_IR_POWERDWN  (TOSA_SCOOP_GPIO_BASE + 2)
+#define TOSA_GPIO_SD_WP                        (TOSA_SCOOP_GPIO_BASE + 3)
+#define TOSA_GPIO_PWR_ON               (TOSA_SCOOP_GPIO_BASE + 4)
+
+#define TOSA_SCOOP_JC_GPIO_BASE                1
+#define TOSA_GPIO_BT_LED               (TOSA_SCOOP_JC_GPIO_BASE + 0)
+#define TOSA_GPIO_NOTE_LED             (TOSA_SCOOP_JC_GPIO_BASE + 1)
+#define TOSA_GPIO_CHRG_ERR_LED         (TOSA_SCOOP_JC_GPIO_BASE + 2)
+#define TOSA_GPIO_TC6393XB_L3V_ON      (TOSA_SCOOP_JC_GPIO_BASE + 5)
+#define TOSA_GPIO_WLAN_LED             (TOSA_SCOOP_JC_GPIO_BASE + 7)
+
+#define        DAC_BASE        0x4e
+#define DAC_CH1                0
+#define DAC_CH2                1
+
+static void tosa_microdrive_attach(PXA2xxState *cpu)
+{
+    PCMCIACardState *md;
+    DriveInfo *dinfo;
+
+    dinfo = drive_get(IF_IDE, 0, 0);
+    if (!dinfo || dinfo->media_cd)
+        return;
+    md = dscm1xxxx_init(dinfo);
+    pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
+}
+
+static void tosa_out_switch(void *opaque, int line, int level)
+{
+    switch (line) {
+        case 0:
+            fprintf(stderr, "blue LED %s.\n", level ? "on" : "off");
+            break;
+        case 1:
+            fprintf(stderr, "green LED %s.\n", level ? "on" : "off");
+            break;
+        case 2:
+            fprintf(stderr, "amber LED %s.\n", level ? "on" : "off");
+            break;
+        case 3:
+            fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off");
+            break;
+        default:
+            fprintf(stderr, "Uhandled out event: %d = %d\n", line, level);
+            break;
+    }
+}
+
+
+static void tosa_gpio_setup(PXA2xxState *cpu,
+                DeviceState *scp0,
+                DeviceState *scp1,
+                TC6393xbState *tmio)
+{
+    qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4);
+    /* MMC/SD host */
+    pxa2xx_mmci_handlers(cpu->mmc,
+                    qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP),
+                    qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT)));
+
+    /* Handle reset */
+    qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset);
+
+    /* PCMCIA signals: card's IRQ and Card-Detect */
+    pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
+                        qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ),
+                        qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD));
+
+    pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
+                        qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ),
+                        NULL);
+
+    qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, outsignals[0]);
+    qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]);
+    qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]);
+    qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]);
+
+    qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
+
+    /* UDC Vbus */
+    qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN));
+}
+
+static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value)
+{
+    fprintf(stderr, "TG: %d %02x\n", value >> 5, value & 0x1f);
+    return 0;
+}
+
+static int tosa_ssp_init(SSISlave *dev)
+{
+    /* Nothing to do.  */
+    return 0;
+}
+
+typedef struct {
+    I2CSlave i2c;
+    int len;
+    char buf[3];
+} TosaDACState;
+
+static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
+{
+    TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
+    s->buf[s->len] = data;
+    if (s->len ++ > 2) {
+#ifdef VERBOSE
+        fprintf(stderr, "%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
+#endif
+        return 1;
+    }
+
+    if (s->len == 2) {
+        fprintf(stderr, "dac: channel %d value 0x%02x\n",
+                s->buf[0], s->buf[1]);
+    }
+
+    return 0;
+}
+
+static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
+{
+    TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
+    s->len = 0;
+    switch (event) {
+    case I2C_START_SEND:
+        break;
+    case I2C_START_RECV:
+        printf("%s: recv not supported!!!\n", __FUNCTION__);
+        break;
+    case I2C_FINISH:
+#ifdef VERBOSE
+        if (s->len < 2)
+            printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
+        if (s->len > 2)
+            printf("%s: message too long\n", __FUNCTION__);
+#endif
+        break;
+    default:
+        break;
+    }
+}
+
+static int tosa_dac_recv(I2CSlave *s)
+{
+    printf("%s: recv not supported!!!\n", __FUNCTION__);
+    return -1;
+}
+
+static int tosa_dac_init(I2CSlave *i2c)
+{
+    /* Nothing to do.  */
+    return 0;
+}
+
+static void tosa_tg_init(PXA2xxState *cpu)
+{
+    i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
+    i2c_create_slave(bus, "tosa_dac", DAC_BASE);
+    ssi_create_slave(cpu->ssp[1], "tosa-ssp");
+}
+
+
+static struct arm_boot_info tosa_binfo = {
+    .loader_start = PXA2XX_SDRAM_BASE,
+    .ram_size = 0x04000000,
+};
+
+static void tosa_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *rom = g_new(MemoryRegion, 1);
+    PXA2xxState *mpu;
+    TC6393xbState *tmio;
+    DeviceState *scp0, *scp1;
+
+    if (!cpu_model)
+        cpu_model = "pxa255";
+
+    mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size);
+
+    memory_region_init_ram(rom, "tosa.rom", TOSA_ROM);
+    vmstate_register_ram_global(rom);
+    memory_region_set_readonly(rom, true);
+    memory_region_add_subregion(address_space_mem, 0, rom);
+
+    tmio = tc6393xb_init(address_space_mem, 0x10000000,
+            qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT));
+
+    scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
+    scp1 = sysbus_create_simple("scoop", 0x14800040, NULL);
+
+    tosa_gpio_setup(mpu, scp0, scp1, tmio);
+
+    tosa_microdrive_attach(mpu);
+
+    tosa_tg_init(mpu);
+
+    tosa_binfo.kernel_filename = kernel_filename;
+    tosa_binfo.kernel_cmdline = kernel_cmdline;
+    tosa_binfo.initrd_filename = initrd_filename;
+    tosa_binfo.board_id = 0x208;
+    arm_load_kernel(mpu->cpu, &tosa_binfo);
+    sl_bootparam_write(SL_PXA_PARAM_BASE);
+}
+
+static QEMUMachine tosapda_machine = {
+    .name = "tosa",
+    .desc = "Tosa PDA (PXA255)",
+    .init = tosa_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void tosapda_machine_init(void)
+{
+    qemu_register_machine(&tosapda_machine);
+}
+
+machine_init(tosapda_machine_init);
+
+static void tosa_dac_class_init(ObjectClass *klass, void *data)
+{
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = tosa_dac_init;
+    k->event = tosa_dac_event;
+    k->recv = tosa_dac_recv;
+    k->send = tosa_dac_send;
+}
+
+static const TypeInfo tosa_dac_info = {
+    .name          = "tosa_dac",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(TosaDACState),
+    .class_init    = tosa_dac_class_init,
+};
+
+static void tosa_ssp_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = tosa_ssp_init;
+    k->transfer = tosa_ssp_tansfer;
+}
+
+static const TypeInfo tosa_ssp_info = {
+    .name          = "tosa-ssp",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(SSISlave),
+    .class_init    = tosa_ssp_class_init,
+};
+
+static void tosa_register_types(void)
+{
+    type_register_static(&tosa_dac_info);
+    type_register_static(&tosa_ssp_info);
+}
+
+type_init(tosa_register_types)
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
new file mode 100644 (file)
index 0000000..baaa265
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * ARM Versatile Platform/Application Baseboard System emulation.
+ *
+ * Copyright (c) 2005-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/pci/pci.h"
+#include "hw/i2c.h"
+#include "hw/boards.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+#include "hw/flash.h"
+
+#define VERSATILE_FLASH_ADDR 0x34000000
+#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
+#define VERSATILE_FLASH_SECT_SIZE (256 * 1024)
+
+/* Primary interrupt controller.  */
+
+typedef struct vpb_sic_state
+{
+  SysBusDevice busdev;
+  MemoryRegion iomem;
+  uint32_t level;
+  uint32_t mask;
+  uint32_t pic_enable;
+  qemu_irq parent[32];
+  int irq;
+} vpb_sic_state;
+
+static const VMStateDescription vmstate_vpb_sic = {
+    .name = "versatilepb_sic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(level, vpb_sic_state),
+        VMSTATE_UINT32(mask, vpb_sic_state),
+        VMSTATE_UINT32(pic_enable, vpb_sic_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void vpb_sic_update(vpb_sic_state *s)
+{
+    uint32_t flags;
+
+    flags = s->level & s->mask;
+    qemu_set_irq(s->parent[s->irq], flags != 0);
+}
+
+static void vpb_sic_update_pic(vpb_sic_state *s)
+{
+    int i;
+    uint32_t mask;
+
+    for (i = 21; i <= 30; i++) {
+        mask = 1u << i;
+        if (!(s->pic_enable & mask))
+            continue;
+        qemu_set_irq(s->parent[i], (s->level & mask) != 0);
+    }
+}
+
+static void vpb_sic_set_irq(void *opaque, int irq, int level)
+{
+    vpb_sic_state *s = (vpb_sic_state *)opaque;
+    if (level)
+        s->level |= 1u << irq;
+    else
+        s->level &= ~(1u << irq);
+    if (s->pic_enable & (1u << irq))
+        qemu_set_irq(s->parent[irq], level);
+    vpb_sic_update(s);
+}
+
+static uint64_t vpb_sic_read(void *opaque, hwaddr offset,
+                             unsigned size)
+{
+    vpb_sic_state *s = (vpb_sic_state *)opaque;
+
+    switch (offset >> 2) {
+    case 0: /* STATUS */
+        return s->level & s->mask;
+    case 1: /* RAWSTAT */
+        return s->level;
+    case 2: /* ENABLE */
+        return s->mask;
+    case 4: /* SOFTINT */
+        return s->level & 1;
+    case 8: /* PICENABLE */
+        return s->pic_enable;
+    default:
+        printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void vpb_sic_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    vpb_sic_state *s = (vpb_sic_state *)opaque;
+
+    switch (offset >> 2) {
+    case 2: /* ENSET */
+        s->mask |= value;
+        break;
+    case 3: /* ENCLR */
+        s->mask &= ~value;
+        break;
+    case 4: /* SOFTINTSET */
+        if (value)
+            s->mask |= 1;
+        break;
+    case 5: /* SOFTINTCLR */
+        if (value)
+            s->mask &= ~1u;
+        break;
+    case 8: /* PICENSET */
+        s->pic_enable |= (value & 0x7fe00000);
+        vpb_sic_update_pic(s);
+        break;
+    case 9: /* PICENCLR */
+        s->pic_enable &= ~value;
+        vpb_sic_update_pic(s);
+        break;
+    default:
+        printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
+        return;
+    }
+    vpb_sic_update(s);
+}
+
+static const MemoryRegionOps vpb_sic_ops = {
+    .read = vpb_sic_read,
+    .write = vpb_sic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int vpb_sic_init(SysBusDevice *dev)
+{
+    vpb_sic_state *s = FROM_SYSBUS(vpb_sic_state, dev);
+    int i;
+
+    qdev_init_gpio_in(&dev->qdev, vpb_sic_set_irq, 32);
+    for (i = 0; i < 32; i++) {
+        sysbus_init_irq(dev, &s->parent[i]);
+    }
+    s->irq = 31;
+    memory_region_init_io(&s->iomem, &vpb_sic_ops, s, "vpb-sic", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+/* Board init.  */
+
+/* The AB and PB boards both use the same core, just with different
+   peripherals and expansion busses.  For now we emulate a subset of the
+   PB peripherals and just change the board ID.  */
+
+static struct arm_boot_info versatile_binfo;
+
+static void versatile_init(QEMUMachineInitArgs *args, int board_id)
+{
+    ARMCPU *cpu;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    qemu_irq *cpu_pic;
+    qemu_irq pic[32];
+    qemu_irq sic[32];
+    DeviceState *dev, *sysctl;
+    SysBusDevice *busdev;
+    DeviceState *pl041;
+    PCIBus *pci_bus;
+    NICInfo *nd;
+    i2c_bus *i2c;
+    int n;
+    int done_smc = 0;
+    DriveInfo *dinfo;
+
+    if (!args->cpu_model) {
+        args->cpu_model = "arm926";
+    }
+    cpu = cpu_arm_init(args->cpu_model);
+    if (!cpu) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    memory_region_init_ram(ram, "versatile.ram", args->ram_size);
+    vmstate_register_ram_global(ram);
+    /* ??? RAM should repeat to fill physical memory space.  */
+    /* SDRAM at address zero.  */
+    memory_region_add_subregion(sysmem, 0, ram);
+
+    sysctl = qdev_create(NULL, "realview_sysctl");
+    qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
+    qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
+    qdev_init_nofail(sysctl);
+    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
+
+    cpu_pic = arm_pic_init_cpu(cpu);
+    dev = sysbus_create_varargs("pl190", 0x10140000,
+                                cpu_pic[ARM_PIC_CPU_IRQ],
+                                cpu_pic[ARM_PIC_CPU_FIQ], NULL);
+    for (n = 0; n < 32; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+    dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL);
+    for (n = 0; n < 32; n++) {
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]);
+        sic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]);
+    sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]);
+
+    dev = qdev_create(NULL, "versatile_pci");
+    busdev = SYS_BUS_DEVICE(dev);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(busdev, 0, 0x41000000); /* PCI self-config */
+    sysbus_mmio_map(busdev, 1, 0x42000000); /* PCI config */
+    sysbus_connect_irq(busdev, 0, sic[27]);
+    sysbus_connect_irq(busdev, 1, sic[28]);
+    sysbus_connect_irq(busdev, 2, sic[29]);
+    sysbus_connect_irq(busdev, 3, sic[30]);
+    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
+
+    /* The Versatile PCI bridge does not provide access to PCI IO space,
+       so many of the qemu PCI devices are not useable.  */
+    for(n = 0; n < nb_nics; n++) {
+        nd = &nd_table[n];
+
+        if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
+            smc91c111_init(nd, 0x10010000, sic[25]);
+            done_smc = 1;
+        } else {
+            pci_nic_init_nofail(nd, "rtl8139", NULL);
+        }
+    }
+    if (usb_enabled(false)) {
+        pci_create_simple(pci_bus, -1, "pci-ohci");
+    }
+    n = drive_get_max_bus(IF_SCSI);
+    while (n >= 0) {
+        pci_create_simple(pci_bus, -1, "lsi53c895a");
+        n--;
+    }
+
+    sysbus_create_simple("pl011", 0x101f1000, pic[12]);
+    sysbus_create_simple("pl011", 0x101f2000, pic[13]);
+    sysbus_create_simple("pl011", 0x101f3000, pic[14]);
+    sysbus_create_simple("pl011", 0x10009000, sic[6]);
+
+    sysbus_create_simple("pl080", 0x10130000, pic[17]);
+    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
+    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
+
+    sysbus_create_simple("pl061", 0x101e4000, pic[6]);
+    sysbus_create_simple("pl061", 0x101e5000, pic[7]);
+    sysbus_create_simple("pl061", 0x101e6000, pic[8]);
+    sysbus_create_simple("pl061", 0x101e7000, pic[9]);
+
+    /* The versatile/PB actually has a modified Color LCD controller
+       that includes hardware cursor support from the PL111.  */
+    dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
+    /* Wire up the mux control signals from the SYS_CLCD register */
+    qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0));
+
+    sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
+    sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
+
+    /* Add PL031 Real Time Clock. */
+    sysbus_create_simple("pl031", 0x101e8000, pic[10]);
+
+    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
+    i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+    i2c_create_slave(i2c, "ds1338", 0x68);
+
+    /* Add PL041 AACI Interface to the LM4549 codec */
+    pl041 = qdev_create(NULL, "pl041");
+    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
+    qdev_init_nofail(pl041);
+    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
+    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
+
+    /* Memory map for Versatile/PB:  */
+    /* 0x10000000 System registers.  */
+    /* 0x10001000 PCI controller config registers.  */
+    /* 0x10002000 Serial bus interface.  */
+    /*  0x10003000 Secondary interrupt controller.  */
+    /* 0x10004000 AACI (audio).  */
+    /*  0x10005000 MMCI0.  */
+    /*  0x10006000 KMI0 (keyboard).  */
+    /*  0x10007000 KMI1 (mouse).  */
+    /* 0x10008000 Character LCD Interface.  */
+    /*  0x10009000 UART3.  */
+    /* 0x1000a000 Smart card 1.  */
+    /*  0x1000b000 MMCI1.  */
+    /*  0x10010000 Ethernet.  */
+    /* 0x10020000 USB.  */
+    /* 0x10100000 SSMC.  */
+    /* 0x10110000 MPMC.  */
+    /*  0x10120000 CLCD Controller.  */
+    /*  0x10130000 DMA Controller.  */
+    /*  0x10140000 Vectored interrupt controller.  */
+    /* 0x101d0000 AHB Monitor Interface.  */
+    /* 0x101e0000 System Controller.  */
+    /* 0x101e1000 Watchdog Interface.  */
+    /* 0x101e2000 Timer 0/1.  */
+    /* 0x101e3000 Timer 2/3.  */
+    /* 0x101e4000 GPIO port 0.  */
+    /* 0x101e5000 GPIO port 1.  */
+    /* 0x101e6000 GPIO port 2.  */
+    /* 0x101e7000 GPIO port 3.  */
+    /* 0x101e8000 RTC.  */
+    /* 0x101f0000 Smart card 0.  */
+    /*  0x101f1000 UART0.  */
+    /*  0x101f2000 UART1.  */
+    /*  0x101f3000 UART2.  */
+    /* 0x101f4000 SSPI.  */
+    /* 0x34000000 NOR Flash */
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
+                          VERSATILE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
+                          VERSATILE_FLASH_SECT_SIZE,
+                          VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
+                          4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
+        fprintf(stderr, "qemu: Error registering flash memory.\n");
+    }
+
+    versatile_binfo.ram_size = args->ram_size;
+    versatile_binfo.kernel_filename = args->kernel_filename;
+    versatile_binfo.kernel_cmdline = args->kernel_cmdline;
+    versatile_binfo.initrd_filename = args->initrd_filename;
+    versatile_binfo.board_id = board_id;
+    arm_load_kernel(cpu, &versatile_binfo);
+}
+
+static void vpb_init(QEMUMachineInitArgs *args)
+{
+    versatile_init(args, 0x183);
+}
+
+static void vab_init(QEMUMachineInitArgs *args)
+{
+    versatile_init(args, 0x25e);
+}
+
+static QEMUMachine versatilepb_machine = {
+    .name = "versatilepb",
+    .desc = "ARM Versatile/PB (ARM926EJ-S)",
+    .init = vpb_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine versatileab_machine = {
+    .name = "versatileab",
+    .desc = "ARM Versatile/AB (ARM926EJ-S)",
+    .init = vab_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void versatile_machine_init(void)
+{
+    qemu_register_machine(&versatilepb_machine);
+    qemu_register_machine(&versatileab_machine);
+}
+
+machine_init(versatile_machine_init);
+
+static void vpb_sic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = vpb_sic_init;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_vpb_sic;
+}
+
+static const TypeInfo vpb_sic_info = {
+    .name          = "versatilepb_sic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(vpb_sic_state),
+    .class_init    = vpb_sic_class_init,
+};
+
+static void versatilepb_register_types(void)
+{
+    type_register_static(&vpb_sic_info);
+}
+
+type_init(versatilepb_register_types)
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
new file mode 100644 (file)
index 0000000..02922c3
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * ARM Versatile Express emulation.
+ *
+ * Copyright (c) 2010 - 2011 B Labs Ltd.
+ * Copyright (c) 2011 Linaro Limited
+ * Written by Bahadir Balban, Amit Mahajan, Peter Maydell
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contributions after 2012-01-13 are licensed under the terms of the
+ *  GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm-misc.h"
+#include "hw/primecell.h"
+#include "hw/devices.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "exec/address-spaces.h"
+#include "sysemu/blockdev.h"
+#include "hw/flash.h"
+
+#define VEXPRESS_BOARD_ID 0x8e0
+#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
+#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024)
+
+static struct arm_boot_info vexpress_binfo;
+
+/* Address maps for peripherals:
+ * the Versatile Express motherboard has two possible maps,
+ * the "legacy" one (used for A9) and the "Cortex-A Series"
+ * map (used for newer cores).
+ * Individual daughterboards can also have different maps for
+ * their peripherals.
+ */
+
+enum {
+    VE_SYSREGS,
+    VE_SP810,
+    VE_SERIALPCI,
+    VE_PL041,
+    VE_MMCI,
+    VE_KMI0,
+    VE_KMI1,
+    VE_UART0,
+    VE_UART1,
+    VE_UART2,
+    VE_UART3,
+    VE_WDT,
+    VE_TIMER01,
+    VE_TIMER23,
+    VE_SERIALDVI,
+    VE_RTC,
+    VE_COMPACTFLASH,
+    VE_CLCD,
+    VE_NORFLASH0,
+    VE_NORFLASH1,
+    VE_SRAM,
+    VE_VIDEORAM,
+    VE_ETHERNET,
+    VE_USB,
+    VE_DAPROM,
+};
+
+static hwaddr motherboard_legacy_map[] = {
+    /* CS7: 0x10000000 .. 0x10020000 */
+    [VE_SYSREGS] = 0x10000000,
+    [VE_SP810] = 0x10001000,
+    [VE_SERIALPCI] = 0x10002000,
+    [VE_PL041] = 0x10004000,
+    [VE_MMCI] = 0x10005000,
+    [VE_KMI0] = 0x10006000,
+    [VE_KMI1] = 0x10007000,
+    [VE_UART0] = 0x10009000,
+    [VE_UART1] = 0x1000a000,
+    [VE_UART2] = 0x1000b000,
+    [VE_UART3] = 0x1000c000,
+    [VE_WDT] = 0x1000f000,
+    [VE_TIMER01] = 0x10011000,
+    [VE_TIMER23] = 0x10012000,
+    [VE_SERIALDVI] = 0x10016000,
+    [VE_RTC] = 0x10017000,
+    [VE_COMPACTFLASH] = 0x1001a000,
+    [VE_CLCD] = 0x1001f000,
+    /* CS0: 0x40000000 .. 0x44000000 */
+    [VE_NORFLASH0] = 0x40000000,
+    /* CS1: 0x44000000 .. 0x48000000 */
+    [VE_NORFLASH1] = 0x44000000,
+    /* CS2: 0x48000000 .. 0x4a000000 */
+    [VE_SRAM] = 0x48000000,
+    /* CS3: 0x4c000000 .. 0x50000000 */
+    [VE_VIDEORAM] = 0x4c000000,
+    [VE_ETHERNET] = 0x4e000000,
+    [VE_USB] = 0x4f000000,
+};
+
+static hwaddr motherboard_aseries_map[] = {
+    /* CS0: 0x08000000 .. 0x0c000000 */
+    [VE_NORFLASH0] = 0x08000000,
+    /* CS4: 0x0c000000 .. 0x10000000 */
+    [VE_NORFLASH1] = 0x0c000000,
+    /* CS5: 0x10000000 .. 0x14000000 */
+    /* CS1: 0x14000000 .. 0x18000000 */
+    [VE_SRAM] = 0x14000000,
+    /* CS2: 0x18000000 .. 0x1c000000 */
+    [VE_VIDEORAM] = 0x18000000,
+    [VE_ETHERNET] = 0x1a000000,
+    [VE_USB] = 0x1b000000,
+    /* CS3: 0x1c000000 .. 0x20000000 */
+    [VE_DAPROM] = 0x1c000000,
+    [VE_SYSREGS] = 0x1c010000,
+    [VE_SP810] = 0x1c020000,
+    [VE_SERIALPCI] = 0x1c030000,
+    [VE_PL041] = 0x1c040000,
+    [VE_MMCI] = 0x1c050000,
+    [VE_KMI0] = 0x1c060000,
+    [VE_KMI1] = 0x1c070000,
+    [VE_UART0] = 0x1c090000,
+    [VE_UART1] = 0x1c0a0000,
+    [VE_UART2] = 0x1c0b0000,
+    [VE_UART3] = 0x1c0c0000,
+    [VE_WDT] = 0x1c0f0000,
+    [VE_TIMER01] = 0x1c110000,
+    [VE_TIMER23] = 0x1c120000,
+    [VE_SERIALDVI] = 0x1c160000,
+    [VE_RTC] = 0x1c170000,
+    [VE_COMPACTFLASH] = 0x1c1a0000,
+    [VE_CLCD] = 0x1c1f0000,
+};
+
+/* Structure defining the peculiarities of a specific daughterboard */
+
+typedef struct VEDBoardInfo VEDBoardInfo;
+
+typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
+                          ram_addr_t ram_size,
+                          const char *cpu_model,
+                          qemu_irq *pic, uint32_t *proc_id);
+
+struct VEDBoardInfo {
+    const hwaddr *motherboard_map;
+    hwaddr loader_start;
+    const hwaddr gic_cpu_if_addr;
+    DBoardInitFn *init;
+};
+
+static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
+                                  ram_addr_t ram_size,
+                                  const char *cpu_model,
+                                  qemu_irq *pic, uint32_t *proc_id)
+{
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *lowram = g_new(MemoryRegion, 1);
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    qemu_irq *irqp;
+    int n;
+    qemu_irq cpu_irq[4];
+    ram_addr_t low_ram_size;
+
+    if (!cpu_model) {
+        cpu_model = "cortex-a9";
+    }
+
+    *proc_id = 0x0c000191;
+
+    for (n = 0; n < smp_cpus; n++) {
+        ARMCPU *cpu = cpu_arm_init(cpu_model);
+        if (!cpu) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        irqp = arm_pic_init_cpu(cpu);
+        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+    }
+
+    if (ram_size > 0x40000000) {
+        /* 1GB is the maximum the address space permits */
+        fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n");
+        exit(1);
+    }
+
+    memory_region_init_ram(ram, "vexpress.highmem", ram_size);
+    vmstate_register_ram_global(ram);
+    low_ram_size = ram_size;
+    if (low_ram_size > 0x4000000) {
+        low_ram_size = 0x4000000;
+    }
+    /* RAM is from 0x60000000 upwards. The bottom 64MB of the
+     * address space should in theory be remappable to various
+     * things including ROM or RAM; we always map the RAM there.
+     */
+    memory_region_init_alias(lowram, "vexpress.lowmem", ram, 0, low_ram_size);
+    memory_region_add_subregion(sysmem, 0x0, lowram);
+    memory_region_add_subregion(sysmem, 0x60000000, ram);
+
+    /* 0x1e000000 A9MPCore (SCU) private memory region */
+    dev = qdev_create(NULL, "a9mpcore_priv");
+    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, 0x1e000000);
+    for (n = 0; n < smp_cpus; n++) {
+        sysbus_connect_irq(busdev, n, cpu_irq[n]);
+    }
+    /* Interrupts [42:0] are from the motherboard;
+     * [47:43] are reserved; [63:48] are daughterboard
+     * peripherals. Note that some documentation numbers
+     * external interrupts starting from 32 (because the
+     * A9MP has internal interrupts 0..31).
+     */
+    for (n = 0; n < 64; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
+
+    /* 0x10020000 PL111 CLCD (daughterboard) */
+    sysbus_create_simple("pl111", 0x10020000, pic[44]);
+
+    /* 0x10060000 AXI RAM */
+    /* 0x100e0000 PL341 Dynamic Memory Controller */
+    /* 0x100e1000 PL354 Static Memory Controller */
+    /* 0x100e2000 System Configuration Controller */
+
+    sysbus_create_simple("sp804", 0x100e4000, pic[48]);
+    /* 0x100e5000 SP805 Watchdog module */
+    /* 0x100e6000 BP147 TrustZone Protection Controller */
+    /* 0x100e9000 PL301 'Fast' AXI matrix */
+    /* 0x100ea000 PL301 'Slow' AXI matrix */
+    /* 0x100ec000 TrustZone Address Space Controller */
+    /* 0x10200000 CoreSight debug APB */
+    /* 0x1e00a000 PL310 L2 Cache Controller */
+    sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
+}
+
+static const VEDBoardInfo a9_daughterboard = {
+    .motherboard_map = motherboard_legacy_map,
+    .loader_start = 0x60000000,
+    .gic_cpu_if_addr = 0x1e000100,
+    .init = a9_daughterboard_init,
+};
+
+static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
+                                   ram_addr_t ram_size,
+                                   const char *cpu_model,
+                                   qemu_irq *pic, uint32_t *proc_id)
+{
+    int n;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    qemu_irq cpu_irq[4];
+    DeviceState *dev;
+    SysBusDevice *busdev;
+
+    if (!cpu_model) {
+        cpu_model = "cortex-a15";
+    }
+
+    *proc_id = 0x14000237;
+
+    for (n = 0; n < smp_cpus; n++) {
+        ARMCPU *cpu;
+        qemu_irq *irqp;
+
+        cpu = cpu_arm_init(cpu_model);
+        if (!cpu) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        irqp = arm_pic_init_cpu(cpu);
+        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+    }
+
+    {
+        /* We have to use a separate 64 bit variable here to avoid the gcc
+         * "comparison is always false due to limited range of data type"
+         * warning if we are on a host where ram_addr_t is 32 bits.
+         */
+        uint64_t rsz = ram_size;
+        if (rsz > (30ULL * 1024 * 1024 * 1024)) {
+            fprintf(stderr, "vexpress-a15: cannot model more than 30GB RAM\n");
+            exit(1);
+        }
+    }
+
+    memory_region_init_ram(ram, "vexpress.highmem", ram_size);
+    vmstate_register_ram_global(ram);
+    /* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */
+    memory_region_add_subregion(sysmem, 0x80000000, ram);
+
+    /* 0x2c000000 A15MPCore private memory region (GIC) */
+    dev = qdev_create(NULL, "a15mpcore_priv");
+    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, 0x2c000000);
+    for (n = 0; n < smp_cpus; n++) {
+        sysbus_connect_irq(busdev, n, cpu_irq[n]);
+    }
+    /* Interrupts [42:0] are from the motherboard;
+     * [47:43] are reserved; [63:48] are daughterboard
+     * peripherals. Note that some documentation numbers
+     * external interrupts starting from 32 (because there
+     * are internal interrupts 0..31).
+     */
+    for (n = 0; n < 64; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    /* A15 daughterboard peripherals: */
+
+    /* 0x20000000: CoreSight interfaces: not modelled */
+    /* 0x2a000000: PL301 AXI interconnect: not modelled */
+    /* 0x2a420000: SCC: not modelled */
+    /* 0x2a430000: system counter: not modelled */
+    /* 0x2b000000: HDLCD controller: not modelled */
+    /* 0x2b060000: SP805 watchdog: not modelled */
+    /* 0x2b0a0000: PL341 dynamic memory controller: not modelled */
+    /* 0x2e000000: system SRAM */
+    memory_region_init_ram(sram, "vexpress.a15sram", 0x10000);
+    vmstate_register_ram_global(sram);
+    memory_region_add_subregion(sysmem, 0x2e000000, sram);
+
+    /* 0x7ffb0000: DMA330 DMA controller: not modelled */
+    /* 0x7ffd0000: PL354 static memory controller: not modelled */
+}
+
+static const VEDBoardInfo a15_daughterboard = {
+    .motherboard_map = motherboard_aseries_map,
+    .loader_start = 0x80000000,
+    .gic_cpu_if_addr = 0x2c002000,
+    .init = a15_daughterboard_init,
+};
+
+static void vexpress_common_init(const VEDBoardInfo *daughterboard,
+                                 QEMUMachineInitArgs *args)
+{
+    DeviceState *dev, *sysctl, *pl041;
+    qemu_irq pic[64];
+    uint32_t proc_id;
+    uint32_t sys_id;
+    DriveInfo *dinfo;
+    ram_addr_t vram_size, sram_size;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *vram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    const hwaddr *map = daughterboard->motherboard_map;
+
+    daughterboard->init(daughterboard, args->ram_size, args->cpu_model,
+                        pic, &proc_id);
+
+    /* Motherboard peripherals: the wiring is the same but the
+     * addresses vary between the legacy and A-Series memory maps.
+     */
+
+    sys_id = 0x1190f500;
+
+    sysctl = qdev_create(NULL, "realview_sysctl");
+    qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
+    qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
+    qdev_init_nofail(sysctl);
+    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]);
+
+    /* VE_SP810: not modelled */
+    /* VE_SERIALPCI: not modelled */
+
+    pl041 = qdev_create(NULL, "pl041");
+    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
+    qdev_init_nofail(pl041);
+    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]);
+
+    dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL);
+    /* Wire up MMC card detect and read-only signals */
+    qdev_connect_gpio_out(dev, 0,
+                          qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT));
+    qdev_connect_gpio_out(dev, 1,
+                          qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN));
+
+    sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]);
+    sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]);
+
+    sysbus_create_simple("pl011", map[VE_UART0], pic[5]);
+    sysbus_create_simple("pl011", map[VE_UART1], pic[6]);
+    sysbus_create_simple("pl011", map[VE_UART2], pic[7]);
+    sysbus_create_simple("pl011", map[VE_UART3], pic[8]);
+
+    sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]);
+    sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]);
+
+    /* VE_SERIALDVI: not modelled */
+
+    sysbus_create_simple("pl031", map[VE_RTC], pic[4]); /* RTC */
+
+    /* VE_COMPACTFLASH: not modelled */
+
+    sysbus_create_simple("pl111", map[VE_CLCD], pic[14]);
+
+    dinfo = drive_get_next(IF_PFLASH);
+    if (!pflash_cfi01_register(map[VE_NORFLASH0], NULL, "vexpress.flash0",
+            VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
+            VEXPRESS_FLASH_SECT_SIZE,
+            VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4,
+            0x00, 0x89, 0x00, 0x18, 0)) {
+        fprintf(stderr, "vexpress: error registering flash 0.\n");
+        exit(1);
+    }
+
+    dinfo = drive_get_next(IF_PFLASH);
+    if (!pflash_cfi01_register(map[VE_NORFLASH1], NULL, "vexpress.flash1",
+            VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
+            VEXPRESS_FLASH_SECT_SIZE,
+            VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4,
+            0x00, 0x89, 0x00, 0x18, 0)) {
+        fprintf(stderr, "vexpress: error registering flash 1.\n");
+        exit(1);
+    }
+
+    sram_size = 0x2000000;
+    memory_region_init_ram(sram, "vexpress.sram", sram_size);
+    vmstate_register_ram_global(sram);
+    memory_region_add_subregion(sysmem, map[VE_SRAM], sram);
+
+    vram_size = 0x800000;
+    memory_region_init_ram(vram, "vexpress.vram", vram_size);
+    vmstate_register_ram_global(vram);
+    memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram);
+
+    /* 0x4e000000 LAN9118 Ethernet */
+    if (nd_table[0].used) {
+        lan9118_init(&nd_table[0], map[VE_ETHERNET], pic[15]);
+    }
+
+    /* VE_USB: not modelled */
+
+    /* VE_DAPROM: not modelled */
+
+    vexpress_binfo.ram_size = args->ram_size;
+    vexpress_binfo.kernel_filename = args->kernel_filename;
+    vexpress_binfo.kernel_cmdline = args->kernel_cmdline;
+    vexpress_binfo.initrd_filename = args->initrd_filename;
+    vexpress_binfo.nb_cpus = smp_cpus;
+    vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
+    vexpress_binfo.loader_start = daughterboard->loader_start;
+    vexpress_binfo.smp_loader_start = map[VE_SRAM];
+    vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
+    vexpress_binfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
+    arm_load_kernel(arm_env_get_cpu(first_cpu), &vexpress_binfo);
+}
+
+static void vexpress_a9_init(QEMUMachineInitArgs *args)
+{
+    vexpress_common_init(&a9_daughterboard, args);
+}
+
+static void vexpress_a15_init(QEMUMachineInitArgs *args)
+{
+    vexpress_common_init(&a15_daughterboard, args);
+}
+
+static QEMUMachine vexpress_a9_machine = {
+    .name = "vexpress-a9",
+    .desc = "ARM Versatile Express for Cortex-A9",
+    .init = vexpress_a9_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine vexpress_a15_machine = {
+    .name = "vexpress-a15",
+    .desc = "ARM Versatile Express for Cortex-A15",
+    .init = vexpress_a15_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void vexpress_machine_init(void)
+{
+    qemu_register_machine(&vexpress_a9_machine);
+    qemu_register_machine(&vexpress_a15_machine);
+}
+
+machine_init(vexpress_machine_init);
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
new file mode 100644 (file)
index 0000000..f78c47e
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Xilinx Zynq Baseboard System emulation.
+ *
+ * Copyright (c) 2010 Xilinx.
+ * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com)
+ * Copyright (c) 2012 Petalogix Pty Ltd.
+ * Written by Haibing Ma
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm-misc.h"
+#include "net/net.h"
+#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/flash.h"
+#include "sysemu/blockdev.h"
+#include "hw/loader.h"
+#include "hw/ssi.h"
+
+#define NUM_SPI_FLASHES 4
+#define NUM_QSPI_FLASHES 2
+#define NUM_QSPI_BUSSES 2
+
+#define FLASH_SIZE (64 * 1024 * 1024)
+#define FLASH_SECTOR_SIZE (128 * 1024)
+
+#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
+
+static struct arm_boot_info zynq_binfo = {};
+
+static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    qemu_check_nic_model(nd, "cadence_gem");
+    dev = qdev_create(NULL, "cadence_gem");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(s, 0, base);
+    sysbus_connect_irq(s, 0, irq);
+}
+
+static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
+                                         bool is_qspi)
+{
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    SSIBus *spi;
+    DeviceState *flash_dev;
+    int i, j;
+    int num_busses =  is_qspi ? NUM_QSPI_BUSSES : 1;
+    int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES;
+
+    dev = qdev_create(NULL, "xilinx,spips");
+    qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1);
+    qdev_prop_set_uint8(dev, "num-ss-bits", num_ss);
+    qdev_prop_set_uint8(dev, "num-busses", num_busses);
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, base_addr);
+    if (is_qspi) {
+        sysbus_mmio_map(busdev, 1, 0xFC000000);
+    }
+    sysbus_connect_irq(busdev, 0, irq);
+
+    for (i = 0; i < num_busses; ++i) {
+        char bus_name[16];
+        qemu_irq cs_line;
+
+        snprintf(bus_name, 16, "spi%d", i);
+        spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
+
+        for (j = 0; j < num_ss; ++j) {
+            flash_dev = ssi_create_slave_no_init(spi, "n25q128");
+            qdev_init_nofail(flash_dev);
+
+            cs_line = qdev_get_gpio_in(flash_dev, 0);
+            sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
+        }
+    }
+
+}
+
+static void zynq_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    ARMCPU *cpu;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ext_ram = g_new(MemoryRegion, 1);
+    MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    qemu_irq *irqp;
+    qemu_irq pic[64];
+    NICInfo *nd;
+    int n;
+    qemu_irq cpu_irq;
+
+    if (!cpu_model) {
+        cpu_model = "cortex-a9";
+    }
+
+    cpu = cpu_arm_init(cpu_model);
+    if (!cpu) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    irqp = arm_pic_init_cpu(cpu);
+    cpu_irq = irqp[ARM_PIC_CPU_IRQ];
+
+    /* max 2GB ram */
+    if (ram_size > 0x80000000) {
+        ram_size = 0x80000000;
+    }
+
+    /* DDR remapped to address zero.  */
+    memory_region_init_ram(ext_ram, "zynq.ext_ram", ram_size);
+    vmstate_register_ram_global(ext_ram);
+    memory_region_add_subregion(address_space_mem, 0, ext_ram);
+
+    /* 256K of on-chip memory */
+    memory_region_init_ram(ocm_ram, "zynq.ocm_ram", 256 << 10);
+    vmstate_register_ram_global(ocm_ram);
+    memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
+
+    DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
+
+    /* AMD */
+    pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE,
+                          dinfo ? dinfo->bdrv : NULL, FLASH_SECTOR_SIZE,
+                          FLASH_SIZE/FLASH_SECTOR_SIZE, 1,
+                          1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa,
+                              0);
+
+    dev = qdev_create(NULL, "xilinx,zynq_slcr");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000);
+
+    dev = qdev_create(NULL, "a9mpcore_priv");
+    qdev_prop_set_uint32(dev, "num-cpu", 1);
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, 0xF8F00000);
+    sysbus_connect_irq(busdev, 0, cpu_irq);
+
+    for (n = 0; n < 64; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET], false);
+    zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false);
+    zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true);
+
+    sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]);
+    sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]);
+
+    sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]);
+    sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]);
+
+    sysbus_create_varargs("cadence_ttc", 0xF8001000,
+            pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL);
+    sysbus_create_varargs("cadence_ttc", 0xF8002000,
+            pic[69-IRQ_OFFSET], pic[70-IRQ_OFFSET], pic[71-IRQ_OFFSET], NULL);
+
+    for (n = 0; n < nb_nics; n++) {
+        nd = &nd_table[n];
+        if (n == 0) {
+            gem_init(nd, 0xE000B000, pic[54-IRQ_OFFSET]);
+        } else if (n == 1) {
+            gem_init(nd, 0xE000C000, pic[77-IRQ_OFFSET]);
+        }
+    }
+
+    dev = qdev_create(NULL, "generic-sdhci");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]);
+
+    dev = qdev_create(NULL, "generic-sdhci");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]);
+
+    zynq_binfo.ram_size = ram_size;
+    zynq_binfo.kernel_filename = kernel_filename;
+    zynq_binfo.kernel_cmdline = kernel_cmdline;
+    zynq_binfo.initrd_filename = initrd_filename;
+    zynq_binfo.nb_cpus = 1;
+    zynq_binfo.board_id = 0xd32;
+    zynq_binfo.loader_start = 0;
+    arm_load_kernel(arm_env_get_cpu(first_cpu), &zynq_binfo);
+}
+
+static QEMUMachine zynq_machine = {
+    .name = "xilinx-zynq-a9",
+    .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9",
+    .init = zynq_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 1,
+    .no_sdcard = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void zynq_machine_init(void)
+{
+    qemu_register_machine(&zynq_machine);
+}
+
+machine_init(zynq_machine_init);
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
new file mode 100644 (file)
index 0000000..cbb6d80
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * PXA270-based Zipit Z2 device
+ *
+ * Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Code is based on mainstone platform.
+ *
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "hw/hw.h"
+#include "hw/pxa.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "hw/i2c.h"
+#include "hw/ssi.h"
+#include "hw/boards.h"
+#include "sysemu/sysemu.h"
+#include "hw/flash.h"
+#include "sysemu/blockdev.h"
+#include "ui/console.h"
+#include "audio/audio.h"
+#include "exec/address-spaces.h"
+
+#ifdef DEBUG_Z2
+#define DPRINTF(fmt, ...) \
+        printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+static struct keymap map[0x100] = {
+    [0 ... 0xff] = { -1, -1 },
+    [0x3b] = {0, 0}, /* Option = F1 */
+    [0xc8] = {0, 1}, /* Up */
+    [0xd0] = {0, 2}, /* Down */
+    [0xcb] = {0, 3}, /* Left */
+    [0xcd] = {0, 4}, /* Right */
+    [0xcf] = {0, 5}, /* End */
+    [0x0d] = {0, 6}, /* KPPLUS */
+    [0xc7] = {1, 0}, /* Home */
+    [0x10] = {1, 1}, /* Q */
+    [0x17] = {1, 2}, /* I */
+    [0x22] = {1, 3}, /* G */
+    [0x2d] = {1, 4}, /* X */
+    [0x1c] = {1, 5}, /* Enter */
+    [0x0c] = {1, 6}, /* KPMINUS */
+    [0xc9] = {2, 0}, /* PageUp */
+    [0x11] = {2, 1}, /* W */
+    [0x18] = {2, 2}, /* O */
+    [0x23] = {2, 3}, /* H */
+    [0x2e] = {2, 4}, /* C */
+    [0x38] = {2, 5}, /* LeftAlt */
+    [0xd1] = {3, 0}, /* PageDown */
+    [0x12] = {3, 1}, /* E */
+    [0x19] = {3, 2}, /* P */
+    [0x24] = {3, 3}, /* J */
+    [0x2f] = {3, 4}, /* V */
+    [0x2a] = {3, 5}, /* LeftShift */
+    [0x01] = {4, 0}, /* Esc */
+    [0x13] = {4, 1}, /* R */
+    [0x1e] = {4, 2}, /* A */
+    [0x25] = {4, 3}, /* K */
+    [0x30] = {4, 4}, /* B */
+    [0x1d] = {4, 5}, /* LeftCtrl */
+    [0x0f] = {5, 0}, /* Tab */
+    [0x14] = {5, 1}, /* T */
+    [0x1f] = {5, 2}, /* S */
+    [0x26] = {5, 3}, /* L */
+    [0x31] = {5, 4}, /* N */
+    [0x39] = {5, 5}, /* Space */
+    [0x3c] = {6, 0}, /* Stop = F2 */
+    [0x15] = {6, 1}, /* Y */
+    [0x20] = {6, 2}, /* D */
+    [0x0e] = {6, 3}, /* Backspace */
+    [0x32] = {6, 4}, /* M */
+    [0x33] = {6, 5}, /* Comma */
+    [0x3d] = {7, 0}, /* Play = F3 */
+    [0x16] = {7, 1}, /* U */
+    [0x21] = {7, 2}, /* F */
+    [0x2c] = {7, 3}, /* Z */
+    [0x27] = {7, 4}, /* Semicolon */
+    [0x34] = {7, 5}, /* Dot */
+};
+
+#define Z2_RAM_SIZE     0x02000000
+#define Z2_FLASH_BASE   0x00000000
+#define Z2_FLASH_SIZE   0x00800000
+
+static struct arm_boot_info z2_binfo = {
+    .loader_start   = PXA2XX_SDRAM_BASE,
+    .ram_size       = Z2_RAM_SIZE,
+};
+
+#define Z2_GPIO_SD_DETECT   96
+#define Z2_GPIO_AC_IN       0
+#define Z2_GPIO_KEY_ON      1
+#define Z2_GPIO_LCD_CS      88
+
+typedef struct {
+    SSISlave ssidev;
+    int32_t selected;
+    int32_t enabled;
+    uint8_t buf[3];
+    uint32_t cur_reg;
+    int pos;
+} ZipitLCD;
+
+static uint32_t zipit_lcd_transfer(SSISlave *dev, uint32_t value)
+{
+    ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
+    uint16_t val;
+    if (z->selected) {
+        z->buf[z->pos] = value & 0xff;
+        z->pos++;
+    }
+    if (z->pos == 3) {
+        switch (z->buf[0]) {
+        case 0x74:
+            DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]);
+            z->cur_reg = z->buf[2];
+            break;
+        case 0x76:
+            val = z->buf[1] << 8 | z->buf[2];
+            DPRINTF("%s: value: 0x%.4x\n", __func__, val);
+            if (z->cur_reg == 0x22 && val == 0x0000) {
+                z->enabled = 1;
+                printf("%s: LCD enabled\n", __func__);
+            } else if (z->cur_reg == 0x10 && val == 0x0000) {
+                z->enabled = 0;
+                printf("%s: LCD disabled\n", __func__);
+            }
+            break;
+        default:
+            DPRINTF("%s: unknown command!\n", __func__);
+            break;
+        }
+        z->pos = 0;
+    }
+    return 0;
+}
+
+static void z2_lcd_cs(void *opaque, int line, int level)
+{
+    ZipitLCD *z2_lcd = opaque;
+    z2_lcd->selected = !level;
+}
+
+static int zipit_lcd_init(SSISlave *dev)
+{
+    ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
+    z->selected = 0;
+    z->enabled = 0;
+    z->pos = 0;
+
+    return 0;
+}
+
+static VMStateDescription vmstate_zipit_lcd_state = {
+    .name = "zipit-lcd",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_SSI_SLAVE(ssidev, ZipitLCD),
+        VMSTATE_INT32(selected, ZipitLCD),
+        VMSTATE_INT32(enabled, ZipitLCD),
+        VMSTATE_BUFFER(buf, ZipitLCD),
+        VMSTATE_UINT32(cur_reg, ZipitLCD),
+        VMSTATE_INT32(pos, ZipitLCD),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void zipit_lcd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = zipit_lcd_init;
+    k->transfer = zipit_lcd_transfer;
+    dc->vmsd = &vmstate_zipit_lcd_state;
+}
+
+static const TypeInfo zipit_lcd_info = {
+    .name          = "zipit-lcd",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(ZipitLCD),
+    .class_init    = zipit_lcd_class_init,
+};
+
+typedef struct {
+    I2CSlave i2c;
+    int len;
+    uint8_t buf[3];
+} AER915State;
+
+static int aer915_send(I2CSlave *i2c, uint8_t data)
+{
+    AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
+    s->buf[s->len] = data;
+    if (s->len++ > 2) {
+        DPRINTF("%s: message too long (%i bytes)\n",
+            __func__, s->len);
+        return 1;
+    }
+
+    if (s->len == 2) {
+        DPRINTF("%s: reg %d value 0x%02x\n", __func__,
+                s->buf[0], s->buf[1]);
+    }
+
+    return 0;
+}
+
+static void aer915_event(I2CSlave *i2c, enum i2c_event event)
+{
+    AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
+    switch (event) {
+    case I2C_START_SEND:
+        s->len = 0;
+        break;
+    case I2C_START_RECV:
+        if (s->len != 1) {
+            DPRINTF("%s: short message!?\n", __func__);
+        }
+        break;
+    case I2C_FINISH:
+        break;
+    default:
+        break;
+    }
+}
+
+static int aer915_recv(I2CSlave *slave)
+{
+    int retval = 0x00;
+    AER915State *s = FROM_I2C_SLAVE(AER915State, slave);
+
+    switch (s->buf[0]) {
+    /* Return hardcoded battery voltage,
+     * 0xf0 means ~4.1V
+     */
+    case 0x02:
+        retval = 0xf0;
+        break;
+    /* Return 0x00 for other regs,
+     * we don't know what they are for,
+     * anyway they return 0x00 on real hardware.
+     */
+    default:
+        break;
+    }
+
+    return retval;
+}
+
+static int aer915_init(I2CSlave *i2c)
+{
+    /* Nothing to do.  */
+    return 0;
+}
+
+static VMStateDescription vmstate_aer915_state = {
+    .name = "aer915",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(len, AER915State),
+        VMSTATE_BUFFER(buf, AER915State),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void aer915_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = aer915_init;
+    k->event = aer915_event;
+    k->recv = aer915_recv;
+    k->send = aer915_send;
+    dc->vmsd = &vmstate_aer915_state;
+}
+
+static const TypeInfo aer915_info = {
+    .name          = "aer915",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(AER915State),
+    .class_init    = aer915_class_init,
+};
+
+static void z2_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    MemoryRegion *address_space_mem = get_system_memory();
+    uint32_t sector_len = 0x10000;
+    PXA2xxState *mpu;
+    DriveInfo *dinfo;
+    int be;
+    void *z2_lcd;
+    i2c_bus *bus;
+    DeviceState *wm;
+
+    if (!cpu_model) {
+        cpu_model = "pxa270-c5";
+    }
+
+    /* Setup CPU & memory */
+    mpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model);
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (!dinfo) {
+        fprintf(stderr, "Flash image must be given with the "
+                "'pflash' parameter\n");
+        exit(1);
+    }
+
+    if (!pflash_cfi01_register(Z2_FLASH_BASE,
+                               NULL, "z2.flash0", Z2_FLASH_SIZE,
+                               dinfo->bdrv, sector_len,
+                               Z2_FLASH_SIZE / sector_len, 4, 0, 0, 0, 0,
+                               be)) {
+        fprintf(stderr, "qemu: Error registering flash memory.\n");
+        exit(1);
+    }
+
+    /* setup keypad */
+    pxa27x_register_keypad(mpu->kp, map, 0x100);
+
+    /* MMC/SD host */
+    pxa2xx_mmci_handlers(mpu->mmc,
+        NULL,
+        qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT));
+
+    type_register_static(&zipit_lcd_info);
+    type_register_static(&aer915_info);
+    z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd");
+    bus = pxa2xx_i2c_bus(mpu->i2c[0]);
+    i2c_create_slave(bus, "aer915", 0x55);
+    wm = i2c_create_slave(bus, "wm8750", 0x1b);
+    mpu->i2s->opaque = wm;
+    mpu->i2s->codec_out = wm8750_dac_dat;
+    mpu->i2s->codec_in = wm8750_adc_dat;
+    wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s);
+
+    qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS,
+        qemu_allocate_irqs(z2_lcd_cs, z2_lcd, 1)[0]);
+
+    if (kernel_filename) {
+        z2_binfo.kernel_filename = kernel_filename;
+        z2_binfo.kernel_cmdline = kernel_cmdline;
+        z2_binfo.initrd_filename = initrd_filename;
+        z2_binfo.board_id = 0x6dd;
+        arm_load_kernel(mpu->cpu, &z2_binfo);
+    }
+}
+
+static QEMUMachine z2_machine = {
+    .name = "z2",
+    .desc = "Zipit Z2 (PXA27x)",
+    .init = z2_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void z2_machine_init(void)
+{
+    qemu_register_machine(&z2_machine);
+}
+
+machine_init(z2_machine_init);
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
deleted file mode 100644 (file)
index 43253fd..0000000
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * ARM kernel loader.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "config.h"
-#include "hw/hw.h"
-#include "hw/arm-misc.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/device_tree.h"
-#include "qemu/config-file.h"
-
-#define KERNEL_ARGS_ADDR 0x100
-#define KERNEL_LOAD_ADDR 0x00010000
-
-/* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
-static uint32_t bootloader[] = {
-  0xe3a00000, /* mov     r0, #0 */
-  0xe59f1004, /* ldr     r1, [pc, #4] */
-  0xe59f2004, /* ldr     r2, [pc, #4] */
-  0xe59ff004, /* ldr     pc, [pc, #4] */
-  0, /* Board ID */
-  0, /* Address of kernel args.  Set by integratorcp_init.  */
-  0  /* Kernel entry point.  Set by integratorcp_init.  */
-};
-
-/* Handling for secondary CPU boot in a multicore system.
- * Unlike the uniprocessor/primary CPU boot, this is platform
- * dependent. The default code here is based on the secondary
- * CPU boot protocol used on realview/vexpress boards, with
- * some parameterisation to increase its flexibility.
- * QEMU platform models for which this code is not appropriate
- * should override write_secondary_boot and secondary_cpu_reset_hook
- * instead.
- *
- * This code enables the interrupt controllers for the secondary
- * CPUs and then puts all the secondary CPUs into a loop waiting
- * for an interprocessor interrupt and polling a configurable
- * location for the kernel secondary CPU entry point.
- */
-#define DSB_INSN 0xf57ff04f
-#define CP15_DSB_INSN 0xee070f9a /* mcr cp15, 0, r0, c7, c10, 4 */
-
-static uint32_t smpboot[] = {
-  0xe59f2028, /* ldr r2, gic_cpu_if */
-  0xe59f0028, /* ldr r0, startaddr */
-  0xe3a01001, /* mov r1, #1 */
-  0xe5821000, /* str r1, [r2] - set GICC_CTLR.Enable */
-  0xe3a010ff, /* mov r1, #0xff */
-  0xe5821004, /* str r1, [r2, 4] - set GIC_PMR.Priority to 0xff */
-  DSB_INSN,   /* dsb */
-  0xe320f003, /* wfi */
-  0xe5901000, /* ldr     r1, [r0] */
-  0xe1110001, /* tst     r1, r1 */
-  0x0afffffb, /* beq     <wfi> */
-  0xe12fff11, /* bx      r1 */
-  0,          /* gic_cpu_if: base address of GIC CPU interface */
-  0           /* bootreg: Boot register address is held here */
-};
-
-static void default_write_secondary(ARMCPU *cpu,
-                                    const struct arm_boot_info *info)
-{
-    int n;
-    smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
-    smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
-    for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
-        /* Replace DSB with the pre-v7 DSB if necessary. */
-        if (!arm_feature(&cpu->env, ARM_FEATURE_V7) &&
-            smpboot[n] == DSB_INSN) {
-            smpboot[n] = CP15_DSB_INSN;
-        }
-        smpboot[n] = tswap32(smpboot[n]);
-    }
-    rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
-                       info->smp_loader_start);
-}
-
-static void default_reset_secondary(ARMCPU *cpu,
-                                    const struct arm_boot_info *info)
-{
-    CPUARMState *env = &cpu->env;
-
-    stl_phys_notdirty(info->smp_bootreg_addr, 0);
-    env->regs[15] = info->smp_loader_start;
-}
-
-#define WRITE_WORD(p, value) do { \
-    stl_phys_notdirty(p, value);  \
-    p += 4;                       \
-} while (0)
-
-static void set_kernel_args(const struct arm_boot_info *info)
-{
-    int initrd_size = info->initrd_size;
-    hwaddr base = info->loader_start;
-    hwaddr p;
-
-    p = base + KERNEL_ARGS_ADDR;
-    /* ATAG_CORE */
-    WRITE_WORD(p, 5);
-    WRITE_WORD(p, 0x54410001);
-    WRITE_WORD(p, 1);
-    WRITE_WORD(p, 0x1000);
-    WRITE_WORD(p, 0);
-    /* ATAG_MEM */
-    /* TODO: handle multiple chips on one ATAG list */
-    WRITE_WORD(p, 4);
-    WRITE_WORD(p, 0x54410002);
-    WRITE_WORD(p, info->ram_size);
-    WRITE_WORD(p, info->loader_start);
-    if (initrd_size) {
-        /* ATAG_INITRD2 */
-        WRITE_WORD(p, 4);
-        WRITE_WORD(p, 0x54420005);
-        WRITE_WORD(p, info->initrd_start);
-        WRITE_WORD(p, initrd_size);
-    }
-    if (info->kernel_cmdline && *info->kernel_cmdline) {
-        /* ATAG_CMDLINE */
-        int cmdline_size;
-
-        cmdline_size = strlen(info->kernel_cmdline);
-        cpu_physical_memory_write(p + 8, (void *)info->kernel_cmdline,
-                                  cmdline_size + 1);
-        cmdline_size = (cmdline_size >> 2) + 1;
-        WRITE_WORD(p, cmdline_size + 2);
-        WRITE_WORD(p, 0x54410009);
-        p += cmdline_size * 4;
-    }
-    if (info->atag_board) {
-        /* ATAG_BOARD */
-        int atag_board_len;
-        uint8_t atag_board_buf[0x1000];
-
-        atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3;
-        WRITE_WORD(p, (atag_board_len + 8) >> 2);
-        WRITE_WORD(p, 0x414f4d50);
-        cpu_physical_memory_write(p, atag_board_buf, atag_board_len);
-        p += atag_board_len;
-    }
-    /* ATAG_END */
-    WRITE_WORD(p, 0);
-    WRITE_WORD(p, 0);
-}
-
-static void set_kernel_args_old(const struct arm_boot_info *info)
-{
-    hwaddr p;
-    const char *s;
-    int initrd_size = info->initrd_size;
-    hwaddr base = info->loader_start;
-
-    /* see linux/include/asm-arm/setup.h */
-    p = base + KERNEL_ARGS_ADDR;
-    /* page_size */
-    WRITE_WORD(p, 4096);
-    /* nr_pages */
-    WRITE_WORD(p, info->ram_size / 4096);
-    /* ramdisk_size */
-    WRITE_WORD(p, 0);
-#define FLAG_READONLY  1
-#define FLAG_RDLOAD    4
-#define FLAG_RDPROMPT  8
-    /* flags */
-    WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
-    /* rootdev */
-    WRITE_WORD(p, (31 << 8) | 0);      /* /dev/mtdblock0 */
-    /* video_num_cols */
-    WRITE_WORD(p, 0);
-    /* video_num_rows */
-    WRITE_WORD(p, 0);
-    /* video_x */
-    WRITE_WORD(p, 0);
-    /* video_y */
-    WRITE_WORD(p, 0);
-    /* memc_control_reg */
-    WRITE_WORD(p, 0);
-    /* unsigned char sounddefault */
-    /* unsigned char adfsdrives */
-    /* unsigned char bytes_per_char_h */
-    /* unsigned char bytes_per_char_v */
-    WRITE_WORD(p, 0);
-    /* pages_in_bank[4] */
-    WRITE_WORD(p, 0);
-    WRITE_WORD(p, 0);
-    WRITE_WORD(p, 0);
-    WRITE_WORD(p, 0);
-    /* pages_in_vram */
-    WRITE_WORD(p, 0);
-    /* initrd_start */
-    if (initrd_size) {
-        WRITE_WORD(p, info->initrd_start);
-    } else {
-        WRITE_WORD(p, 0);
-    }
-    /* initrd_size */
-    WRITE_WORD(p, initrd_size);
-    /* rd_start */
-    WRITE_WORD(p, 0);
-    /* system_rev */
-    WRITE_WORD(p, 0);
-    /* system_serial_low */
-    WRITE_WORD(p, 0);
-    /* system_serial_high */
-    WRITE_WORD(p, 0);
-    /* mem_fclk_21285 */
-    WRITE_WORD(p, 0);
-    /* zero unused fields */
-    while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) {
-        WRITE_WORD(p, 0);
-    }
-    s = info->kernel_cmdline;
-    if (s) {
-        cpu_physical_memory_write(p, (void *)s, strlen(s) + 1);
-    } else {
-        WRITE_WORD(p, 0);
-    }
-}
-
-static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
-{
-#ifdef CONFIG_FDT
-    uint32_t *mem_reg_property;
-    uint32_t mem_reg_propsize;
-    void *fdt = NULL;
-    char *filename;
-    int size, rc;
-    uint32_t acells, scells, hival;
-
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename);
-    if (!filename) {
-        fprintf(stderr, "Couldn't open dtb file %s\n", binfo->dtb_filename);
-        return -1;
-    }
-
-    fdt = load_device_tree(filename, &size);
-    if (!fdt) {
-        fprintf(stderr, "Couldn't open dtb file %s\n", filename);
-        g_free(filename);
-        return -1;
-    }
-    g_free(filename);
-
-    acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells");
-    scells = qemu_devtree_getprop_cell(fdt, "/", "#size-cells");
-    if (acells == 0 || scells == 0) {
-        fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n");
-        return -1;
-    }
-
-    mem_reg_propsize = acells + scells;
-    mem_reg_property = g_new0(uint32_t, mem_reg_propsize);
-    mem_reg_property[acells - 1] = cpu_to_be32(binfo->loader_start);
-    hival = cpu_to_be32(binfo->loader_start >> 32);
-    if (acells > 1) {
-        mem_reg_property[acells - 2] = hival;
-    } else if (hival != 0) {
-        fprintf(stderr, "qemu: dtb file not compatible with "
-                "RAM start address > 4GB\n");
-        exit(1);
-    }
-    mem_reg_property[acells + scells - 1] = cpu_to_be32(binfo->ram_size);
-    hival = cpu_to_be32(binfo->ram_size >> 32);
-    if (scells > 1) {
-        mem_reg_property[acells + scells - 2] = hival;
-    } else if (hival != 0) {
-        fprintf(stderr, "qemu: dtb file not compatible with "
-                "RAM size > 4GB\n");
-        exit(1);
-    }
-
-    rc = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
-                              mem_reg_propsize * sizeof(uint32_t));
-    if (rc < 0) {
-        fprintf(stderr, "couldn't set /memory/reg\n");
-    }
-
-    if (binfo->kernel_cmdline && *binfo->kernel_cmdline) {
-        rc = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
-                                          binfo->kernel_cmdline);
-        if (rc < 0) {
-            fprintf(stderr, "couldn't set /chosen/bootargs\n");
-        }
-    }
-
-    if (binfo->initrd_size) {
-        rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
-                binfo->initrd_start);
-        if (rc < 0) {
-            fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
-        }
-
-        rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
-                    binfo->initrd_start + binfo->initrd_size);
-        if (rc < 0) {
-            fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
-        }
-    }
-
-    cpu_physical_memory_write(addr, fdt, size);
-
-    return 0;
-
-#else
-    fprintf(stderr, "Device tree requested, "
-                "but qemu was compiled without fdt support\n");
-    return -1;
-#endif
-}
-
-static void do_cpu_reset(void *opaque)
-{
-    ARMCPU *cpu = opaque;
-    CPUARMState *env = &cpu->env;
-    const struct arm_boot_info *info = env->boot_info;
-
-    cpu_reset(CPU(cpu));
-    if (info) {
-        if (!info->is_linux) {
-            /* Jump to the entry point.  */
-            env->regs[15] = info->entry & 0xfffffffe;
-            env->thumb = info->entry & 1;
-        } else {
-            if (env == first_cpu) {
-                env->regs[15] = info->loader_start;
-                if (!info->dtb_filename) {
-                    if (old_param) {
-                        set_kernel_args_old(info);
-                    } else {
-                        set_kernel_args(info);
-                    }
-                }
-            } else {
-                info->secondary_cpu_reset_hook(cpu, info);
-            }
-        }
-    }
-}
-
-void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
-{
-    CPUARMState *env = &cpu->env;
-    int kernel_size;
-    int initrd_size;
-    int n;
-    int is_linux = 0;
-    uint64_t elf_entry;
-    hwaddr entry;
-    int big_endian;
-    QemuOpts *machine_opts;
-
-    /* Load the kernel.  */
-    if (!info->kernel_filename) {
-        fprintf(stderr, "Kernel image must be specified\n");
-        exit(1);
-    }
-
-    machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
-    if (machine_opts) {
-        info->dtb_filename = qemu_opt_get(machine_opts, "dtb");
-    } else {
-        info->dtb_filename = NULL;
-    }
-
-    if (!info->secondary_cpu_reset_hook) {
-        info->secondary_cpu_reset_hook = default_reset_secondary;
-    }
-    if (!info->write_secondary_boot) {
-        info->write_secondary_boot = default_write_secondary;
-    }
-
-    if (info->nb_cpus == 0)
-        info->nb_cpus = 1;
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    big_endian = 1;
-#else
-    big_endian = 0;
-#endif
-
-    /* We want to put the initrd far enough into RAM that when the
-     * kernel is uncompressed it will not clobber the initrd. However
-     * on boards without much RAM we must ensure that we still leave
-     * enough room for a decent sized initrd, and on boards with large
-     * amounts of RAM we must avoid the initrd being so far up in RAM
-     * that it is outside lowmem and inaccessible to the kernel.
-     * So for boards with less  than 256MB of RAM we put the initrd
-     * halfway into RAM, and for boards with 256MB of RAM or more we put
-     * the initrd at 128MB.
-     */
-    info->initrd_start = info->loader_start +
-        MIN(info->ram_size / 2, 128 * 1024 * 1024);
-
-    /* Assume that raw images are linux kernels, and ELF images are not.  */
-    kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry,
-                           NULL, NULL, big_endian, ELF_MACHINE, 1);
-    entry = elf_entry;
-    if (kernel_size < 0) {
-        kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
-                                  &is_linux);
-    }
-    if (kernel_size < 0) {
-        entry = info->loader_start + KERNEL_LOAD_ADDR;
-        kernel_size = load_image_targphys(info->kernel_filename, entry,
-                                          info->ram_size - KERNEL_LOAD_ADDR);
-        is_linux = 1;
-    }
-    if (kernel_size < 0) {
-        fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                info->kernel_filename);
-        exit(1);
-    }
-    info->entry = entry;
-    if (is_linux) {
-        if (info->initrd_filename) {
-            initrd_size = load_image_targphys(info->initrd_filename,
-                                              info->initrd_start,
-                                              info->ram_size -
-                                              info->initrd_start);
-            if (initrd_size < 0) {
-                fprintf(stderr, "qemu: could not load initrd '%s'\n",
-                        info->initrd_filename);
-                exit(1);
-            }
-        } else {
-            initrd_size = 0;
-        }
-        info->initrd_size = initrd_size;
-
-        bootloader[4] = info->board_id;
-
-        /* for device tree boot, we pass the DTB directly in r2. Otherwise
-         * we point to the kernel args.
-         */
-        if (info->dtb_filename) {
-            /* Place the DTB after the initrd in memory. Note that some
-             * kernels will trash anything in the 4K page the initrd
-             * ends in, so make sure the DTB isn't caught up in that.
-             */
-            hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size,
-                                             4096);
-            if (load_dtb(dtb_start, info)) {
-                exit(1);
-            }
-            bootloader[5] = dtb_start;
-        } else {
-            bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
-            if (info->ram_size >= (1ULL << 32)) {
-                fprintf(stderr, "qemu: RAM size must be less than 4GB to boot"
-                        " Linux kernel using ATAGS (try passing a device tree"
-                        " using -dtb)\n");
-                exit(1);
-            }
-        }
-        bootloader[6] = entry;
-        for (n = 0; n < sizeof(bootloader) / 4; n++) {
-            bootloader[n] = tswap32(bootloader[n]);
-        }
-        rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader),
-                           info->loader_start);
-        if (info->nb_cpus > 1) {
-            info->write_secondary_boot(cpu, info);
-        }
-    }
-    info->is_linux = is_linux;
-
-    for (; env; env = env->next_cpu) {
-        cpu = arm_env_get_cpu(env);
-        env->boot_info = info;
-        qemu_register_reset(do_cpu_reset, cpu);
-    }
-}
diff --git a/hw/arm_pic.c b/hw/arm_pic.c
deleted file mode 100644 (file)
index a7ad893..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Generic ARM Programmable Interrupt Controller support.
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL
- */
-
-#include "hw/hw.h"
-#include "hw/arm-misc.h"
-
-/* Input 0 is IRQ and input 1 is FIQ.  */
-static void arm_pic_cpu_handler(void *opaque, int irq, int level)
-{
-    ARMCPU *cpu = opaque;
-    CPUARMState *env = &cpu->env;
-
-    switch (irq) {
-    case ARM_PIC_CPU_IRQ:
-        if (level)
-            cpu_interrupt(env, CPU_INTERRUPT_HARD);
-        else
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-        break;
-    case ARM_PIC_CPU_FIQ:
-        if (level)
-            cpu_interrupt(env, CPU_INTERRUPT_FIQ);
-        else
-            cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
-        break;
-    default:
-        hw_error("arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
-    }
-}
-
-qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
-{
-    return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2);
-}
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
deleted file mode 100644 (file)
index eccd423..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * QEMU model for the AXIS devboard 88.
- *
- * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/flash.h"
-#include "hw/boards.h"
-#include "hw/etraxfs.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/cris-boot.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-#define D(x)
-#define DNAND(x)
-
-struct nand_state_t
-{
-    DeviceState *nand;
-    MemoryRegion iomem;
-    unsigned int rdy:1;
-    unsigned int ale:1;
-    unsigned int cle:1;
-    unsigned int ce:1;
-};
-
-static struct nand_state_t nand_state;
-static uint64_t nand_read(void *opaque, hwaddr addr, unsigned size)
-{
-    struct nand_state_t *s = opaque;
-    uint32_t r;
-    int rdy;
-
-    r = nand_getio(s->nand);
-    nand_getpins(s->nand, &rdy);
-    s->rdy = rdy;
-
-    DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r));
-    return r;
-}
-
-static void
-nand_write(void *opaque, hwaddr addr, uint64_t value,
-           unsigned size)
-{
-    struct nand_state_t *s = opaque;
-    int rdy;
-
-    DNAND(printf("%s addr=%x v=%x\n", __func__, addr, (unsigned)value));
-    nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0);
-    nand_setio(s->nand, value);
-    nand_getpins(s->nand, &rdy);
-    s->rdy = rdy;
-}
-
-static const MemoryRegionOps nand_ops = {
-    .read = nand_read,
-    .write = nand_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct tempsensor_t
-{
-    unsigned int shiftreg;
-    unsigned int count;
-    enum {
-        ST_OUT, ST_IN, ST_Z
-    } state;
-
-    uint16_t regs[3];
-};
-
-static void tempsensor_clkedge(struct tempsensor_t *s,
-                               unsigned int clk, unsigned int data_in)
-{
-    D(printf("%s clk=%d state=%d sr=%x\n", __func__,
-             clk, s->state, s->shiftreg));
-    if (s->count == 0) {
-        s->count = 16;
-        s->state = ST_OUT;
-    }
-    switch (s->state) {
-        case ST_OUT:
-            /* Output reg is clocked at negedge.  */
-            if (!clk) {
-                s->count--;
-                s->shiftreg <<= 1;
-                if (s->count == 0) {
-                    s->shiftreg = 0;
-                    s->state = ST_IN;
-                    s->count = 16;
-                }
-            }
-            break;
-        case ST_Z:
-            if (clk) {
-                s->count--;
-                if (s->count == 0) {
-                    s->shiftreg = 0;
-                    s->state = ST_OUT;
-                    s->count = 16;
-                }
-            }
-            break;
-        case ST_IN:
-            /* Indata is sampled at posedge.  */
-            if (clk) {
-                s->count--;
-                s->shiftreg <<= 1;
-                s->shiftreg |= data_in & 1;
-                if (s->count == 0) {
-                    D(printf("%s cfgreg=%x\n", __func__, s->shiftreg));
-                    s->regs[0] = s->shiftreg;
-                    s->state = ST_OUT;
-                    s->count = 16;
-
-                    if ((s->regs[0] & 0xff) == 0) {
-                        /* 25 degrees celcius.  */
-                        s->shiftreg = 0x0b9f;
-                    } else if ((s->regs[0] & 0xff) == 0xff) {
-                        /* Sensor ID, 0x8100 LM70.  */
-                        s->shiftreg = 0x8100;
-                    } else
-                        printf("Invalid tempsens state %x\n", s->regs[0]);
-                }
-            }
-            break;
-    }
-}
-
-
-#define RW_PA_DOUT    0x00
-#define R_PA_DIN      0x01
-#define RW_PA_OE      0x02
-#define RW_PD_DOUT    0x10
-#define R_PD_DIN      0x11
-#define RW_PD_OE      0x12
-
-static struct gpio_state_t
-{
-    MemoryRegion iomem;
-    struct nand_state_t *nand;
-    struct tempsensor_t tempsensor;
-    uint32_t regs[0x5c / 4];
-} gpio_state;
-
-static uint64_t gpio_read(void *opaque, hwaddr addr, unsigned size)
-{
-    struct gpio_state_t *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr)
-    {
-        case R_PA_DIN:
-            r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE];
-
-            /* Encode pins from the nand.  */
-            r |= s->nand->rdy << 7;
-            break;
-        case R_PD_DIN:
-            r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE];
-
-            /* Encode temp sensor pins.  */
-            r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4;
-            break;
-
-        default:
-            r = s->regs[addr];
-            break;
-    }
-    return r;
-    D(printf("%s %x=%x\n", __func__, addr, r));
-}
-
-static void gpio_write(void *opaque, hwaddr addr, uint64_t value,
-                       unsigned size)
-{
-    struct gpio_state_t *s = opaque;
-    D(printf("%s %x=%x\n", __func__, addr, (unsigned)value));
-
-    addr >>= 2;
-    switch (addr)
-    {
-        case RW_PA_DOUT:
-            /* Decode nand pins.  */
-            s->nand->ale = !!(value & (1 << 6));
-            s->nand->cle = !!(value & (1 << 5));
-            s->nand->ce  = !!(value & (1 << 4));
-
-            s->regs[addr] = value;
-            break;
-
-        case RW_PD_DOUT:
-            /* Temp sensor clk.  */
-            if ((s->regs[addr] ^ value) & 2)
-                tempsensor_clkedge(&s->tempsensor, !!(value & 2),
-                                   !!(value & 16));
-            s->regs[addr] = value;
-            break;
-
-        default:
-            s->regs[addr] = value;
-            break;
-    }
-}
-
-static const MemoryRegionOps gpio_ops = {
-    .read = gpio_read,
-    .write = gpio_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-#define INTMEM_SIZE (128 * 1024)
-
-static struct cris_load_info li;
-
-static
-void axisdev88_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    CRISCPU *cpu;
-    CPUCRISState *env;
-    DeviceState *dev;
-    SysBusDevice *s;
-    DriveInfo *nand;
-    qemu_irq irq[30], nmi[2], *cpu_irq;
-    void *etraxfs_dmac;
-    struct etraxfs_dma_client *dma_eth;
-    int i;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
-    MemoryRegion *phys_intmem = g_new(MemoryRegion, 1);
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-        cpu_model = "crisv32";
-    }
-    cpu = cpu_cris_init(cpu_model);
-    env = &cpu->env;
-
-    /* allocate RAM */
-    memory_region_init_ram(phys_ram, "axisdev88.ram", ram_size);
-    vmstate_register_ram_global(phys_ram);
-    memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram);
-
-    /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the 
-       internal memory.  */
-    memory_region_init_ram(phys_intmem, "axisdev88.chipram", INTMEM_SIZE);
-    vmstate_register_ram_global(phys_intmem);
-    memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
-
-      /* Attach a NAND flash to CS1.  */
-    nand = drive_get(IF_MTD, 0, 0);
-    nand_state.nand = nand_init(nand ? nand->bdrv : NULL,
-                                NAND_MFR_STMICRO, 0x39);
-    memory_region_init_io(&nand_state.iomem, &nand_ops, &nand_state,
-                          "nand", 0x05000000);
-    memory_region_add_subregion(address_space_mem, 0x10000000,
-                                &nand_state.iomem);
-
-    gpio_state.nand = &nand_state;
-    memory_region_init_io(&gpio_state.iomem, &gpio_ops, &gpio_state,
-                          "gpio", 0x5c);
-    memory_region_add_subregion(address_space_mem, 0x3001a000,
-                                &gpio_state.iomem);
-
-
-    cpu_irq = cris_pic_init_cpu(env);
-    dev = qdev_create(NULL, "etraxfs,pic");
-    /* FIXME: Is there a proper way to signal vectors to the CPU core?  */
-    qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(s, 0, 0x3001c000);
-    sysbus_connect_irq(s, 0, cpu_irq[0]);
-    sysbus_connect_irq(s, 1, cpu_irq[1]);
-    for (i = 0; i < 30; i++) {
-        irq[i] = qdev_get_gpio_in(dev, i);
-    }
-    nmi[0] = qdev_get_gpio_in(dev, 30);
-    nmi[1] = qdev_get_gpio_in(dev, 31);
-
-    etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
-    for (i = 0; i < 10; i++) {
-        /* On ETRAX, odd numbered channels are inputs.  */
-        etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
-    }
-
-    /* Add the two ethernet blocks.  */
-    dma_eth = g_malloc0(sizeof dma_eth[0] * 4); /* Allocate 4 channels.  */
-    etraxfs_eth_init(&nd_table[0], 0x30034000, 1, &dma_eth[0], &dma_eth[1]);
-    if (nb_nics > 1) {
-        etraxfs_eth_init(&nd_table[1], 0x30036000, 2, &dma_eth[2], &dma_eth[3]);
-    }
-
-    /* The DMA Connector block is missing, hardwire things for now.  */
-    etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]);
-    etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]);
-    if (nb_nics > 1) {
-        etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]);
-        etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]);
-    }
-
-    /* 2 timers.  */
-    sysbus_create_varargs("etraxfs,timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
-    sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
-
-    for (i = 0; i < 4; i++) {
-        sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000,
-                             irq[0x14 + i]);
-    }
-
-    if (!kernel_filename) {
-        fprintf(stderr, "Kernel image must be specified\n");
-        exit(1);
-    }
-
-    li.image_filename = kernel_filename;
-    li.cmdline = kernel_cmdline;
-    cris_load_image(cpu, &li);
-}
-
-static QEMUMachine axisdev88_machine = {
-    .name = "axis-dev88",
-    .desc = "AXIS devboard 88",
-    .init = axisdev88_init,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void axisdev88_machine_init(void)
-{
-    qemu_register_machine(&axisdev88_machine);
-}
-
-machine_init(axisdev88_machine_init);
diff --git a/hw/collie.c b/hw/collie.c
deleted file mode 100644 (file)
index 17fddc8..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SA-1110-based Sharp Zaurus SL-5500 platform.
- *
- * Copyright (C) 2011 Dmitry Eremin-Solenikov
- *
- * This code is licensed under GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "hw/boards.h"
-#include "hw/devices.h"
-#include "hw/strongarm.h"
-#include "hw/arm-misc.h"
-#include "hw/flash.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-static struct arm_boot_info collie_binfo = {
-    .loader_start = SA_SDCS0,
-    .ram_size = 0x20000000,
-};
-
-static void collie_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    StrongARMState *s;
-    DriveInfo *dinfo;
-    MemoryRegion *sysmem = get_system_memory();
-
-    if (!cpu_model) {
-        cpu_model = "sa1110";
-    }
-
-    s = sa1110_init(sysmem, collie_binfo.ram_size, cpu_model);
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000,
-                    dinfo ? dinfo->bdrv : NULL, (64 * 1024),
-                    512, 4, 0x00, 0x00, 0x00, 0x00, 0);
-
-    dinfo = drive_get(IF_PFLASH, 0, 1);
-    pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000,
-                    dinfo ? dinfo->bdrv : NULL, (64 * 1024),
-                    512, 4, 0x00, 0x00, 0x00, 0x00, 0);
-
-    sysbus_create_simple("scoop", 0x40800000, NULL);
-
-    collie_binfo.kernel_filename = kernel_filename;
-    collie_binfo.kernel_cmdline = kernel_cmdline;
-    collie_binfo.initrd_filename = initrd_filename;
-    collie_binfo.board_id = 0x208;
-    arm_load_kernel(s->cpu, &collie_binfo);
-}
-
-static QEMUMachine collie_machine = {
-    .name = "collie",
-    .desc = "Collie PDA (SA-1110)",
-    .init = collie_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void collie_machine_init(void)
-{
-    qemu_register_machine(&collie_machine);
-}
-
-machine_init(collie_machine_init)
diff --git a/hw/cris-boot.c b/hw/cris-boot.c
deleted file mode 100644 (file)
index c330e22..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * CRIS image loading.
- *
- * Copyright (c) 2010 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/hw.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/cris-boot.h"
-
-static void main_cpu_reset(void *opaque)
-{
-    CRISCPU *cpu = opaque;
-    CPUCRISState *env = &cpu->env;
-    struct cris_load_info *li;
-
-    li = env->load_info;
-
-    cpu_reset(CPU(cpu));
-
-    if (!li) {
-        /* nothing more to do.  */
-        return;
-    }
-
-    env->pc = li->entry;
-
-    if (li->image_filename) {
-        env->regs[8] = 0x56902387; /* RAM boot magic.  */
-        env->regs[9] = 0x40004000 + li->image_size;
-    }
-
-    if (li->cmdline) {
-        /* Let the kernel know we are modifying the cmdline.  */
-        env->regs[10] = 0x87109563;
-        env->regs[11] = 0x40000000;
-    }
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
-    return addr - 0x80000000LL;
-}
-
-void cris_load_image(CRISCPU *cpu, struct cris_load_info *li)
-{
-    CPUCRISState *env = &cpu->env;
-    uint64_t entry, high;
-    int kcmdline_len;
-    int image_size;
-
-    env->load_info = li;
-    /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis 
-       devboard SDK.  */
-    image_size = load_elf(li->image_filename, translate_kernel_address, NULL,
-                          &entry, NULL, &high, 0, ELF_MACHINE, 0);
-    li->entry = entry;
-    if (image_size < 0) {
-        /* Takes a kimage from the axis devboard SDK.  */
-        image_size = load_image_targphys(li->image_filename, 0x40004000,
-                                         ram_size);
-        li->entry = 0x40004000;
-    }
-
-    if (image_size < 0) {
-        fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                li->image_filename);
-        exit(1);
-    }
-
-    if (li->cmdline && (kcmdline_len = strlen(li->cmdline))) {
-        if (kcmdline_len > 256) {
-            fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n");
-            exit(1);
-        }
-        pstrcpy_targphys("cmdline", 0x40000000, 256, li->cmdline);
-    }
-    qemu_register_reset(main_cpu_reset, cpu);
-}
index aa9298a0ed036d04a61e64f61a21917009feedac..a94c62450d308e8c9b4f654d0105c754877460af 100644 (file)
@@ -1,8 +1,3 @@
-# Boards
-obj-y = cris_pic_cpu.o
-obj-y += cris-boot.o
-obj-y += axis_dev88.o
-
 # IO blocks
 obj-y += etraxfs_dma.o
 obj-y += etraxfs_pic.o
@@ -11,3 +6,8 @@ obj-y += etraxfs_timer.o
 obj-y += etraxfs_ser.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+# Boards
+obj-y += pic_cpu.o
+obj-y += boot.o
+obj-y += axis_dev88.o
diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c
new file mode 100644 (file)
index 0000000..eccd423
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * QEMU model for the AXIS devboard 88.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/flash.h"
+#include "hw/boards.h"
+#include "hw/etraxfs.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/cris-boot.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+#define D(x)
+#define DNAND(x)
+
+struct nand_state_t
+{
+    DeviceState *nand;
+    MemoryRegion iomem;
+    unsigned int rdy:1;
+    unsigned int ale:1;
+    unsigned int cle:1;
+    unsigned int ce:1;
+};
+
+static struct nand_state_t nand_state;
+static uint64_t nand_read(void *opaque, hwaddr addr, unsigned size)
+{
+    struct nand_state_t *s = opaque;
+    uint32_t r;
+    int rdy;
+
+    r = nand_getio(s->nand);
+    nand_getpins(s->nand, &rdy);
+    s->rdy = rdy;
+
+    DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r));
+    return r;
+}
+
+static void
+nand_write(void *opaque, hwaddr addr, uint64_t value,
+           unsigned size)
+{
+    struct nand_state_t *s = opaque;
+    int rdy;
+
+    DNAND(printf("%s addr=%x v=%x\n", __func__, addr, (unsigned)value));
+    nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0);
+    nand_setio(s->nand, value);
+    nand_getpins(s->nand, &rdy);
+    s->rdy = rdy;
+}
+
+static const MemoryRegionOps nand_ops = {
+    .read = nand_read,
+    .write = nand_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct tempsensor_t
+{
+    unsigned int shiftreg;
+    unsigned int count;
+    enum {
+        ST_OUT, ST_IN, ST_Z
+    } state;
+
+    uint16_t regs[3];
+};
+
+static void tempsensor_clkedge(struct tempsensor_t *s,
+                               unsigned int clk, unsigned int data_in)
+{
+    D(printf("%s clk=%d state=%d sr=%x\n", __func__,
+             clk, s->state, s->shiftreg));
+    if (s->count == 0) {
+        s->count = 16;
+        s->state = ST_OUT;
+    }
+    switch (s->state) {
+        case ST_OUT:
+            /* Output reg is clocked at negedge.  */
+            if (!clk) {
+                s->count--;
+                s->shiftreg <<= 1;
+                if (s->count == 0) {
+                    s->shiftreg = 0;
+                    s->state = ST_IN;
+                    s->count = 16;
+                }
+            }
+            break;
+        case ST_Z:
+            if (clk) {
+                s->count--;
+                if (s->count == 0) {
+                    s->shiftreg = 0;
+                    s->state = ST_OUT;
+                    s->count = 16;
+                }
+            }
+            break;
+        case ST_IN:
+            /* Indata is sampled at posedge.  */
+            if (clk) {
+                s->count--;
+                s->shiftreg <<= 1;
+                s->shiftreg |= data_in & 1;
+                if (s->count == 0) {
+                    D(printf("%s cfgreg=%x\n", __func__, s->shiftreg));
+                    s->regs[0] = s->shiftreg;
+                    s->state = ST_OUT;
+                    s->count = 16;
+
+                    if ((s->regs[0] & 0xff) == 0) {
+                        /* 25 degrees celcius.  */
+                        s->shiftreg = 0x0b9f;
+                    } else if ((s->regs[0] & 0xff) == 0xff) {
+                        /* Sensor ID, 0x8100 LM70.  */
+                        s->shiftreg = 0x8100;
+                    } else
+                        printf("Invalid tempsens state %x\n", s->regs[0]);
+                }
+            }
+            break;
+    }
+}
+
+
+#define RW_PA_DOUT    0x00
+#define R_PA_DIN      0x01
+#define RW_PA_OE      0x02
+#define RW_PD_DOUT    0x10
+#define R_PD_DIN      0x11
+#define RW_PD_OE      0x12
+
+static struct gpio_state_t
+{
+    MemoryRegion iomem;
+    struct nand_state_t *nand;
+    struct tempsensor_t tempsensor;
+    uint32_t regs[0x5c / 4];
+} gpio_state;
+
+static uint64_t gpio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    struct gpio_state_t *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr)
+    {
+        case R_PA_DIN:
+            r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE];
+
+            /* Encode pins from the nand.  */
+            r |= s->nand->rdy << 7;
+            break;
+        case R_PD_DIN:
+            r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE];
+
+            /* Encode temp sensor pins.  */
+            r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4;
+            break;
+
+        default:
+            r = s->regs[addr];
+            break;
+    }
+    return r;
+    D(printf("%s %x=%x\n", __func__, addr, r));
+}
+
+static void gpio_write(void *opaque, hwaddr addr, uint64_t value,
+                       unsigned size)
+{
+    struct gpio_state_t *s = opaque;
+    D(printf("%s %x=%x\n", __func__, addr, (unsigned)value));
+
+    addr >>= 2;
+    switch (addr)
+    {
+        case RW_PA_DOUT:
+            /* Decode nand pins.  */
+            s->nand->ale = !!(value & (1 << 6));
+            s->nand->cle = !!(value & (1 << 5));
+            s->nand->ce  = !!(value & (1 << 4));
+
+            s->regs[addr] = value;
+            break;
+
+        case RW_PD_DOUT:
+            /* Temp sensor clk.  */
+            if ((s->regs[addr] ^ value) & 2)
+                tempsensor_clkedge(&s->tempsensor, !!(value & 2),
+                                   !!(value & 16));
+            s->regs[addr] = value;
+            break;
+
+        default:
+            s->regs[addr] = value;
+            break;
+    }
+}
+
+static const MemoryRegionOps gpio_ops = {
+    .read = gpio_read,
+    .write = gpio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+#define INTMEM_SIZE (128 * 1024)
+
+static struct cris_load_info li;
+
+static
+void axisdev88_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    CRISCPU *cpu;
+    CPUCRISState *env;
+    DeviceState *dev;
+    SysBusDevice *s;
+    DriveInfo *nand;
+    qemu_irq irq[30], nmi[2], *cpu_irq;
+    void *etraxfs_dmac;
+    struct etraxfs_dma_client *dma_eth;
+    int i;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    MemoryRegion *phys_intmem = g_new(MemoryRegion, 1);
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "crisv32";
+    }
+    cpu = cpu_cris_init(cpu_model);
+    env = &cpu->env;
+
+    /* allocate RAM */
+    memory_region_init_ram(phys_ram, "axisdev88.ram", ram_size);
+    vmstate_register_ram_global(phys_ram);
+    memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram);
+
+    /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the 
+       internal memory.  */
+    memory_region_init_ram(phys_intmem, "axisdev88.chipram", INTMEM_SIZE);
+    vmstate_register_ram_global(phys_intmem);
+    memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
+
+      /* Attach a NAND flash to CS1.  */
+    nand = drive_get(IF_MTD, 0, 0);
+    nand_state.nand = nand_init(nand ? nand->bdrv : NULL,
+                                NAND_MFR_STMICRO, 0x39);
+    memory_region_init_io(&nand_state.iomem, &nand_ops, &nand_state,
+                          "nand", 0x05000000);
+    memory_region_add_subregion(address_space_mem, 0x10000000,
+                                &nand_state.iomem);
+
+    gpio_state.nand = &nand_state;
+    memory_region_init_io(&gpio_state.iomem, &gpio_ops, &gpio_state,
+                          "gpio", 0x5c);
+    memory_region_add_subregion(address_space_mem, 0x3001a000,
+                                &gpio_state.iomem);
+
+
+    cpu_irq = cris_pic_init_cpu(env);
+    dev = qdev_create(NULL, "etraxfs,pic");
+    /* FIXME: Is there a proper way to signal vectors to the CPU core?  */
+    qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(s, 0, 0x3001c000);
+    sysbus_connect_irq(s, 0, cpu_irq[0]);
+    sysbus_connect_irq(s, 1, cpu_irq[1]);
+    for (i = 0; i < 30; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+    nmi[0] = qdev_get_gpio_in(dev, 30);
+    nmi[1] = qdev_get_gpio_in(dev, 31);
+
+    etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
+    for (i = 0; i < 10; i++) {
+        /* On ETRAX, odd numbered channels are inputs.  */
+        etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
+    }
+
+    /* Add the two ethernet blocks.  */
+    dma_eth = g_malloc0(sizeof dma_eth[0] * 4); /* Allocate 4 channels.  */
+    etraxfs_eth_init(&nd_table[0], 0x30034000, 1, &dma_eth[0], &dma_eth[1]);
+    if (nb_nics > 1) {
+        etraxfs_eth_init(&nd_table[1], 0x30036000, 2, &dma_eth[2], &dma_eth[3]);
+    }
+
+    /* The DMA Connector block is missing, hardwire things for now.  */
+    etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]);
+    etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]);
+    if (nb_nics > 1) {
+        etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]);
+        etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]);
+    }
+
+    /* 2 timers.  */
+    sysbus_create_varargs("etraxfs,timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
+    sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
+
+    for (i = 0; i < 4; i++) {
+        sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000,
+                             irq[0x14 + i]);
+    }
+
+    if (!kernel_filename) {
+        fprintf(stderr, "Kernel image must be specified\n");
+        exit(1);
+    }
+
+    li.image_filename = kernel_filename;
+    li.cmdline = kernel_cmdline;
+    cris_load_image(cpu, &li);
+}
+
+static QEMUMachine axisdev88_machine = {
+    .name = "axis-dev88",
+    .desc = "AXIS devboard 88",
+    .init = axisdev88_init,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void axisdev88_machine_init(void)
+{
+    qemu_register_machine(&axisdev88_machine);
+}
+
+machine_init(axisdev88_machine_init);
diff --git a/hw/cris/boot.c b/hw/cris/boot.c
new file mode 100644 (file)
index 0000000..c330e22
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * CRIS image loading.
+ *
+ * Copyright (c) 2010 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/cris-boot.h"
+
+static void main_cpu_reset(void *opaque)
+{
+    CRISCPU *cpu = opaque;
+    CPUCRISState *env = &cpu->env;
+    struct cris_load_info *li;
+
+    li = env->load_info;
+
+    cpu_reset(CPU(cpu));
+
+    if (!li) {
+        /* nothing more to do.  */
+        return;
+    }
+
+    env->pc = li->entry;
+
+    if (li->image_filename) {
+        env->regs[8] = 0x56902387; /* RAM boot magic.  */
+        env->regs[9] = 0x40004000 + li->image_size;
+    }
+
+    if (li->cmdline) {
+        /* Let the kernel know we are modifying the cmdline.  */
+        env->regs[10] = 0x87109563;
+        env->regs[11] = 0x40000000;
+    }
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return addr - 0x80000000LL;
+}
+
+void cris_load_image(CRISCPU *cpu, struct cris_load_info *li)
+{
+    CPUCRISState *env = &cpu->env;
+    uint64_t entry, high;
+    int kcmdline_len;
+    int image_size;
+
+    env->load_info = li;
+    /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis 
+       devboard SDK.  */
+    image_size = load_elf(li->image_filename, translate_kernel_address, NULL,
+                          &entry, NULL, &high, 0, ELF_MACHINE, 0);
+    li->entry = entry;
+    if (image_size < 0) {
+        /* Takes a kimage from the axis devboard SDK.  */
+        image_size = load_image_targphys(li->image_filename, 0x40004000,
+                                         ram_size);
+        li->entry = 0x40004000;
+    }
+
+    if (image_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                li->image_filename);
+        exit(1);
+    }
+
+    if (li->cmdline && (kcmdline_len = strlen(li->cmdline))) {
+        if (kcmdline_len > 256) {
+            fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n");
+            exit(1);
+        }
+        pstrcpy_targphys("cmdline", 0x40000000, 256, li->cmdline);
+    }
+    qemu_register_reset(main_cpu_reset, cpu);
+}
diff --git a/hw/cris/pic_cpu.c b/hw/cris/pic_cpu.c
new file mode 100644 (file)
index 0000000..7f50471
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * QEMU CRIS CPU interrupt wrapper logic.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "hw/etraxfs.h"
+
+#define D(x)
+
+static void cris_pic_cpu_handler(void *opaque, int irq, int level)
+{
+    CPUCRISState *env = (CPUCRISState *)opaque;
+    int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
+
+    if (level)
+        cpu_interrupt(env, type);
+    else
+        cpu_reset_interrupt(env, type);
+}
+
+qemu_irq *cris_pic_init_cpu(CPUCRISState *env)
+{
+    return qemu_allocate_irqs(cris_pic_cpu_handler, env, 2);
+}
diff --git a/hw/cris_pic_cpu.c b/hw/cris_pic_cpu.c
deleted file mode 100644 (file)
index 7f50471..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * QEMU CRIS CPU interrupt wrapper logic.
- *
- * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/etraxfs.h"
-
-#define D(x)
-
-static void cris_pic_cpu_handler(void *opaque, int irq, int level)
-{
-    CPUCRISState *env = (CPUCRISState *)opaque;
-    int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
-
-    if (level)
-        cpu_interrupt(env, type);
-    else
-        cpu_reset_interrupt(env, type);
-}
-
-qemu_irq *cris_pic_init_cpu(CPUCRISState *env)
-{
-    return qemu_allocate_irqs(cris_pic_cpu_handler, env, 2);
-}
diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c
deleted file mode 100644 (file)
index 544d56b..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Dummy board with just RAM and CPU for use as an ISS.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-
-#include "hw/hw.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-
-#define KERNEL_LOAD_ADDR 0x10000
-
-/* Board init.  */
-
-static void dummy_m68k_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    CPUM68KState *env;
-    MemoryRegion *address_space_mem =  get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    int kernel_size;
-    uint64_t elf_entry;
-    hwaddr entry;
-
-    if (!cpu_model)
-        cpu_model = "cfv4e";
-    env = cpu_init(cpu_model);
-    if (!env) {
-        fprintf(stderr, "Unable to find m68k CPU definition\n");
-        exit(1);
-    }
-
-    /* Initialize CPU registers.  */
-    env->vbr = 0;
-
-    /* RAM at address zero */
-    memory_region_init_ram(ram, "dummy_m68k.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(address_space_mem, 0, ram);
-
-    /* Load kernel.  */
-    if (kernel_filename) {
-        kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
-                               NULL, NULL, 1, ELF_MACHINE, 0);
-        entry = elf_entry;
-        if (kernel_size < 0) {
-            kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
-        }
-        if (kernel_size < 0) {
-            kernel_size = load_image_targphys(kernel_filename,
-                                              KERNEL_LOAD_ADDR,
-                                              ram_size - KERNEL_LOAD_ADDR);
-            entry = KERNEL_LOAD_ADDR;
-        }
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-    } else {
-        entry = 0;
-    }
-    env->pc = entry;
-}
-
-static QEMUMachine dummy_m68k_machine = {
-    .name = "dummy",
-    .desc = "Dummy board",
-    .init = dummy_m68k_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void dummy_m68k_machine_init(void)
-{
-    qemu_register_machine(&dummy_m68k_machine);
-}
-
-machine_init(dummy_m68k_machine_init);
diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c
deleted file mode 100644 (file)
index 473da34..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- *  Samsung exynos4 SoC based boards emulation
- *
- *  Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
- *    Maksim Kozlov <m.kozlov@samsung.com>
- *    Evgeny Voevodin <e.voevodin@samsung.com>
- *    Igor Mitsyanko  <i.mitsyanko@samsung.com>
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the
- *  Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/arm-misc.h"
-#include "exec/address-spaces.h"
-#include "hw/exynos4210.h"
-#include "hw/boards.h"
-
-#undef DEBUG
-
-//#define DEBUG
-
-#ifdef DEBUG
-    #undef PRINT_DEBUG
-    #define  PRINT_DEBUG(fmt, args...) \
-        do { \
-            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
-        } while (0)
-#else
-    #define  PRINT_DEBUG(fmt, args...)  do {} while (0)
-#endif
-
-#define SMDK_LAN9118_BASE_ADDR      0x05000000
-
-typedef enum Exynos4BoardType {
-    EXYNOS4_BOARD_NURI,
-    EXYNOS4_BOARD_SMDKC210,
-    EXYNOS4_NUM_OF_BOARDS
-} Exynos4BoardType;
-
-static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = {
-    [EXYNOS4_BOARD_NURI]     = 0xD33,
-    [EXYNOS4_BOARD_SMDKC210] = 0xB16,
-};
-
-static int exynos4_board_smp_bootreg_addr[EXYNOS4_NUM_OF_BOARDS] = {
-    [EXYNOS4_BOARD_NURI]     = EXYNOS4210_SECOND_CPU_BOOTREG,
-    [EXYNOS4_BOARD_SMDKC210] = EXYNOS4210_SECOND_CPU_BOOTREG,
-};
-
-static unsigned long exynos4_board_ram_size[EXYNOS4_NUM_OF_BOARDS] = {
-    [EXYNOS4_BOARD_NURI]     = 0x40000000,
-    [EXYNOS4_BOARD_SMDKC210] = 0x40000000,
-};
-
-static struct arm_boot_info exynos4_board_binfo = {
-    .loader_start     = EXYNOS4210_BASE_BOOT_ADDR,
-    .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
-    .nb_cpus          = EXYNOS4210_NCPUS,
-    .write_secondary_boot = exynos4210_write_secondary,
-};
-
-static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS];
-
-static void lan9215_init(uint32_t base, qemu_irq irq)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    /* This should be a 9215 but the 9118 is close enough */
-    if (nd_table[0].used) {
-        qemu_check_nic_model(&nd_table[0], "lan9118");
-        dev = qdev_create(NULL, "lan9118");
-        qdev_set_nic_properties(dev, &nd_table[0]);
-        qdev_prop_set_uint32(dev, "mode_16bit", 1);
-        qdev_init_nofail(dev);
-        s = SYS_BUS_DEVICE(dev);
-        sysbus_mmio_map(s, 0, base);
-        sysbus_connect_irq(s, 0, irq);
-    }
-}
-
-static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
-                                                   Exynos4BoardType board_type)
-{
-    if (smp_cpus != EXYNOS4210_NCPUS) {
-        fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus"
-                " value.\n",
-                exynos4_machines[board_type].name,
-                exynos4_machines[board_type].max_cpus);
-    }
-
-    exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type];
-    exynos4_board_binfo.board_id = exynos4_board_id[board_type];
-    exynos4_board_binfo.smp_bootreg_addr =
-            exynos4_board_smp_bootreg_addr[board_type];
-    exynos4_board_binfo.kernel_filename = args->kernel_filename;
-    exynos4_board_binfo.initrd_filename = args->initrd_filename;
-    exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline;
-    exynos4_board_binfo.gic_cpu_if_addr =
-            EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
-
-    PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n"
-            " kernel_filename: %s\n"
-            " kernel_cmdline: %s\n"
-            " initrd_filename: %s\n",
-            exynos4_board_ram_size[board_type] / 1048576,
-            exynos4_board_ram_size[board_type],
-            args->kernel_filename,
-            args->kernel_cmdline,
-            args->initrd_filename);
-
-    return exynos4210_init(get_system_memory(),
-            exynos4_board_ram_size[board_type]);
-}
-
-static void nuri_init(QEMUMachineInitArgs *args)
-{
-    exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI);
-
-    arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo);
-}
-
-static void smdkc210_init(QEMUMachineInitArgs *args)
-{
-    Exynos4210State *s = exynos4_boards_init_common(args,
-                                                    EXYNOS4_BOARD_SMDKC210);
-
-    lan9215_init(SMDK_LAN9118_BASE_ADDR,
-            qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)]));
-    arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo);
-}
-
-static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS] = {
-    [EXYNOS4_BOARD_NURI] = {
-        .name = "nuri",
-        .desc = "Samsung NURI board (Exynos4210)",
-        .init = nuri_init,
-        .max_cpus = EXYNOS4210_NCPUS,
-        DEFAULT_MACHINE_OPTIONS,
-    },
-    [EXYNOS4_BOARD_SMDKC210] = {
-        .name = "smdkc210",
-        .desc = "Samsung SMDKC210 board (Exynos4210)",
-        .init = smdkc210_init,
-        .max_cpus = EXYNOS4210_NCPUS,
-        DEFAULT_MACHINE_OPTIONS,
-    },
-};
-
-static void exynos4_machine_init(void)
-{
-    qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_NURI]);
-    qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_SMDKC210]);
-}
-
-machine_init(exynos4_machine_init);
diff --git a/hw/gumstix.c b/hw/gumstix.c
deleted file mode 100644 (file)
index 8859b73..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Gumstix Platforms
- *
- * Copyright (c) 2007 by Thorsten Zitterell <info@bitmux.org>
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-/* 
- * Example usage:
- * 
- * connex:
- * =======
- * create image:
- * # dd of=flash bs=1k count=16k if=/dev/zero
- * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
- * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
- * start it:
- * # qemu-system-arm -M connex -pflash flash -monitor null -nographic
- *
- * verdex:
- * =======
- * create image:
- * # dd of=flash bs=1k count=32k if=/dev/zero
- * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
- * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
- * # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage
- * start it:
- * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289
- */
-
-#include "hw/hw.h"
-#include "hw/pxa.h"
-#include "net/net.h"
-#include "hw/flash.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-static const int sector_len = 128 * 1024;
-
-static void connex_init(QEMUMachineInitArgs *args)
-{
-    PXA2xxState *cpu;
-    DriveInfo *dinfo;
-    int be;
-    MemoryRegion *address_space_mem = get_system_memory();
-
-    uint32_t connex_rom = 0x01000000;
-    uint32_t connex_ram = 0x04000000;
-
-    cpu = pxa255_init(address_space_mem, connex_ram);
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    if (!dinfo) {
-        fprintf(stderr, "A flash image must be given with the "
-                "'pflash' parameter\n");
-        exit(1);
-    }
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    be = 1;
-#else
-    be = 0;
-#endif
-    if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom,
-                               dinfo->bdrv, sector_len, connex_rom / sector_len,
-                               2, 0, 0, 0, 0, be)) {
-        fprintf(stderr, "qemu: Error registering flash memory.\n");
-        exit(1);
-    }
-
-    /* Interrupt line of NIC is connected to GPIO line 36 */
-    smc91c111_init(&nd_table[0], 0x04000300,
-                    qdev_get_gpio_in(cpu->gpio, 36));
-}
-
-static void verdex_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    PXA2xxState *cpu;
-    DriveInfo *dinfo;
-    int be;
-    MemoryRegion *address_space_mem = get_system_memory();
-
-    uint32_t verdex_rom = 0x02000000;
-    uint32_t verdex_ram = 0x10000000;
-
-    cpu = pxa270_init(address_space_mem, verdex_ram, cpu_model ?: "pxa270-c0");
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    if (!dinfo) {
-        fprintf(stderr, "A flash image must be given with the "
-                "'pflash' parameter\n");
-        exit(1);
-    }
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    be = 1;
-#else
-    be = 0;
-#endif
-    if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom,
-                               dinfo->bdrv, sector_len, verdex_rom / sector_len,
-                               2, 0, 0, 0, 0, be)) {
-        fprintf(stderr, "qemu: Error registering flash memory.\n");
-        exit(1);
-    }
-
-    /* Interrupt line of NIC is connected to GPIO line 99 */
-    smc91c111_init(&nd_table[0], 0x04000300,
-                    qdev_get_gpio_in(cpu->gpio, 99));
-}
-
-static QEMUMachine connex_machine = {
-    .name = "connex",
-    .desc = "Gumstix Connex (PXA255)",
-    .init = connex_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine verdex_machine = {
-    .name = "verdex",
-    .desc = "Gumstix Verdex (PXA270)",
-    .init = verdex_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void gumstix_machine_init(void)
-{
-    qemu_register_machine(&connex_machine);
-    qemu_register_machine(&verdex_machine);
-}
-
-machine_init(gumstix_machine_init);
diff --git a/hw/highbank.c b/hw/highbank.c
deleted file mode 100644 (file)
index a622224..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Calxeda Highbank SoC emulation
- *
- * Copyright (c) 2010-2012 Calxeda
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
-#include "hw/loader.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/sysbus.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-#define SMP_BOOT_ADDR 0x100
-#define SMP_BOOT_REG  0x40
-#define GIC_BASE_ADDR 0xfff10000
-
-#define NIRQ_GIC      160
-
-/* Board init.  */
-
-static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
-{
-    int n;
-    uint32_t smpboot[] = {
-        0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */
-        0xe210000f, /* ands r0, r0, #0x0f */
-        0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */
-        0xe0830200, /* add r0, r3, r0, lsl #4 */
-        0xe59f2024, /* ldr r2, privbase */
-        0xe3a01001, /* mov r1, #1 */
-        0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */
-        0xe3a010ff, /* mov r1, #0xff */
-        0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */
-        0xf57ff04f, /* dsb */
-        0xe320f003, /* wfi */
-        0xe5901000, /* ldr     r1, [r0] */
-        0xe1110001, /* tst     r1, r1 */
-        0x0afffffb, /* beq     <wfi> */
-        0xe12fff11, /* bx      r1 */
-        GIC_BASE_ADDR      /* privbase: gic address.  */
-    };
-    for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
-        smpboot[n] = tswap32(smpboot[n]);
-    }
-    rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR);
-}
-
-static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
-{
-    CPUARMState *env = &cpu->env;
-
-    switch (info->nb_cpus) {
-    case 4:
-        stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0);
-    case 3:
-        stl_phys_notdirty(SMP_BOOT_REG + 0x20, 0);
-    case 2:
-        stl_phys_notdirty(SMP_BOOT_REG + 0x10, 0);
-        env->regs[15] = SMP_BOOT_ADDR;
-        break;
-    default:
-        break;
-    }
-}
-
-#define NUM_REGS      0x200
-static void hb_regs_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
-{
-    uint32_t *regs = opaque;
-
-    if (offset == 0xf00) {
-        if (value == 1 || value == 2) {
-            qemu_system_reset_request();
-        } else if (value == 3) {
-            qemu_system_shutdown_request();
-        }
-    }
-
-    regs[offset/4] = value;
-}
-
-static uint64_t hb_regs_read(void *opaque, hwaddr offset,
-                             unsigned size)
-{
-    uint32_t *regs = opaque;
-    uint32_t value = regs[offset/4];
-
-    if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) {
-        value |= 0x30000000;
-    }
-
-    return value;
-}
-
-static const MemoryRegionOps hb_mem_ops = {
-    .read = hb_regs_read,
-    .write = hb_regs_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion *iomem;
-    uint32_t regs[NUM_REGS];
-} HighbankRegsState;
-
-static VMStateDescription vmstate_highbank_regs = {
-    .name = "highbank-regs",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static void highbank_regs_reset(DeviceState *dev)
-{
-    SysBusDevice *sys_dev = SYS_BUS_DEVICE(dev);
-    HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, sys_dev);
-
-    s->regs[0x40] = 0x05F20121;
-    s->regs[0x41] = 0x2;
-    s->regs[0x42] = 0x05F30121;
-    s->regs[0x43] = 0x05F40121;
-}
-
-static int highbank_regs_init(SysBusDevice *dev)
-{
-    HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, dev);
-
-    s->iomem = g_new(MemoryRegion, 1);
-    memory_region_init_io(s->iomem, &hb_mem_ops, s->regs, "highbank_regs",
-                          0x1000);
-    sysbus_init_mmio(dev, s->iomem);
-
-    return 0;
-}
-
-static void highbank_regs_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    sbc->init = highbank_regs_init;
-    dc->desc = "Calxeda Highbank registers";
-    dc->vmsd = &vmstate_highbank_regs;
-    dc->reset = highbank_regs_reset;
-}
-
-static const TypeInfo highbank_regs_info = {
-    .name          = "highbank-regs",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(HighbankRegsState),
-    .class_init    = highbank_regs_class_init,
-};
-
-static void highbank_regs_register_types(void)
-{
-    type_register_static(&highbank_regs_info);
-}
-
-type_init(highbank_regs_register_types)
-
-static struct arm_boot_info highbank_binfo;
-
-/* ram_size must be set to match the upper bound of memory in the
- * device tree (linux/arch/arm/boot/dts/highbank.dts), which is
- * normally 0xff900000 or -m 4089. When running this board on a
- * 32-bit host, set the reg value of memory to 0xf7ff00000 in the
- * device tree and pass -m 2047 to QEMU.
- */
-static void highbank_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    DeviceState *dev;
-    SysBusDevice *busdev;
-    qemu_irq *irqp;
-    qemu_irq pic[128];
-    int n;
-    qemu_irq cpu_irq[4];
-    MemoryRegion *sysram;
-    MemoryRegion *dram;
-    MemoryRegion *sysmem;
-    char *sysboot_filename;
-
-    if (!cpu_model) {
-        cpu_model = "cortex-a9";
-    }
-
-    for (n = 0; n < smp_cpus; n++) {
-        ARMCPU *cpu;
-        cpu = cpu_arm_init(cpu_model);
-        if (cpu == NULL) {
-            fprintf(stderr, "Unable to find CPU definition\n");
-            exit(1);
-        }
-
-        /* This will become a QOM property eventually */
-        cpu->reset_cbar = GIC_BASE_ADDR;
-        irqp = arm_pic_init_cpu(cpu);
-        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
-    }
-
-    sysmem = get_system_memory();
-    dram = g_new(MemoryRegion, 1);
-    memory_region_init_ram(dram, "highbank.dram", ram_size);
-    /* SDRAM at address zero.  */
-    memory_region_add_subregion(sysmem, 0, dram);
-
-    sysram = g_new(MemoryRegion, 1);
-    memory_region_init_ram(sysram, "highbank.sysram", 0x8000);
-    memory_region_add_subregion(sysmem, 0xfff88000, sysram);
-    if (bios_name != NULL) {
-        sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-        if (sysboot_filename != NULL) {
-            uint32_t filesize = get_image_size(sysboot_filename);
-            if (load_image_targphys("sysram.bin", 0xfff88000, filesize) < 0) {
-                hw_error("Unable to load %s\n", bios_name);
-            }
-        } else {
-           hw_error("Unable to find %s\n", bios_name);
-        }
-    }
-
-    dev = qdev_create(NULL, "a9mpcore_priv");
-    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
-    qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
-    qdev_init_nofail(dev);
-    busdev = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(busdev, 0, GIC_BASE_ADDR);
-    for (n = 0; n < smp_cpus; n++) {
-        sysbus_connect_irq(busdev, n, cpu_irq[n]);
-    }
-
-    for (n = 0; n < 128; n++) {
-        pic[n] = qdev_get_gpio_in(dev, n);
-    }
-
-    dev = qdev_create(NULL, "l2x0");
-    qdev_init_nofail(dev);
-    busdev = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(busdev, 0, 0xfff12000);
-
-    dev = qdev_create(NULL, "sp804");
-    qdev_prop_set_uint32(dev, "freq0", 150000000);
-    qdev_prop_set_uint32(dev, "freq1", 150000000);
-    qdev_init_nofail(dev);
-    busdev = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(busdev, 0, 0xfff34000);
-    sysbus_connect_irq(busdev, 0, pic[18]);
-    sysbus_create_simple("pl011", 0xfff36000, pic[20]);
-
-    dev = qdev_create(NULL, "highbank-regs");
-    qdev_init_nofail(dev);
-    busdev = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(busdev, 0, 0xfff3c000);
-
-    sysbus_create_simple("pl061", 0xfff30000, pic[14]);
-    sysbus_create_simple("pl061", 0xfff31000, pic[15]);
-    sysbus_create_simple("pl061", 0xfff32000, pic[16]);
-    sysbus_create_simple("pl061", 0xfff33000, pic[17]);
-    sysbus_create_simple("pl031", 0xfff35000, pic[19]);
-    sysbus_create_simple("pl022", 0xfff39000, pic[23]);
-
-    sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]);
-
-    if (nd_table[0].used) {
-        qemu_check_nic_model(&nd_table[0], "xgmac");
-        dev = qdev_create(NULL, "xgmac");
-        qdev_set_nic_properties(dev, &nd_table[0]);
-        qdev_init_nofail(dev);
-        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff50000);
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[77]);
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[78]);
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[79]);
-
-        qemu_check_nic_model(&nd_table[1], "xgmac");
-        dev = qdev_create(NULL, "xgmac");
-        qdev_set_nic_properties(dev, &nd_table[1]);
-        qdev_init_nofail(dev);
-        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff51000);
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[80]);
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[81]);
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[82]);
-    }
-
-    highbank_binfo.ram_size = ram_size;
-    highbank_binfo.kernel_filename = kernel_filename;
-    highbank_binfo.kernel_cmdline = kernel_cmdline;
-    highbank_binfo.initrd_filename = initrd_filename;
-    /* highbank requires a dtb in order to boot, and the dtb will override
-     * the board ID. The following value is ignored, so set it to -1 to be
-     * clear that the value is meaningless.
-     */
-    highbank_binfo.board_id = -1;
-    highbank_binfo.nb_cpus = smp_cpus;
-    highbank_binfo.loader_start = 0;
-    highbank_binfo.write_secondary_boot = hb_write_secondary;
-    highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary;
-    arm_load_kernel(arm_env_get_cpu(first_cpu), &highbank_binfo);
-}
-
-static QEMUMachine highbank_machine = {
-    .name = "highbank",
-    .desc = "Calxeda Highbank (ECX-1000)",
-    .init = highbank_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void highbank_machine_init(void)
-{
-    qemu_register_machine(&highbank_machine);
-}
-
-machine_init(highbank_machine_init);
index 025803aa66680929237dfafe18b55055727ec832..5d071f418ec347796b779644916b605860487439 100644 (file)
@@ -1,12 +1,11 @@
-obj-y += mc146818rtc.o pc.o
+obj-y += mc146818rtc.o
 obj-y += apic_common.o apic.o kvmvapic.o
 obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o
 obj-y += vmport.o
-obj-y += pci/pci-hotplug.o smbios.o wdt_ib700.o
-obj-y += debugcon.o debugexit.o multiboot.o
-obj-y += pc_piix.o
+obj-y += pci/pci-hotplug.o wdt_ib700.o
+obj-y += debugcon.o debugexit.o
 obj-y += pc_sysfw.o
-obj-y += lpc_ich9.o q35.o pc_q35.o
+obj-y += lpc_ich9.o q35.o
 obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
@@ -15,3 +14,7 @@ obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 obj-y += pc-testdev.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-y += multiboot.o smbios.o
+obj-y += pc.o pc_piix.o pc_q35.o
+obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c
new file mode 100644 (file)
index 0000000..3cb228f
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/fw_cfg.h"
+#include "hw/multiboot.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "sysemu/sysemu.h"
+
+/* Show multiboot debug output */
+//#define DEBUG_MULTIBOOT
+
+#ifdef DEBUG_MULTIBOOT
+#define mb_debug(a...) fprintf(stderr, ## a)
+#else
+#define mb_debug(a...)
+#endif
+
+#define MULTIBOOT_STRUCT_ADDR 0x9000
+
+#if MULTIBOOT_STRUCT_ADDR > 0xf0000
+#error multiboot struct needs to fit in 16 bit real mode
+#endif
+
+enum {
+    /* Multiboot info */
+    MBI_FLAGS       = 0,
+    MBI_MEM_LOWER   = 4,
+    MBI_MEM_UPPER   = 8,
+    MBI_BOOT_DEVICE = 12,
+    MBI_CMDLINE     = 16,
+    MBI_MODS_COUNT  = 20,
+    MBI_MODS_ADDR   = 24,
+    MBI_MMAP_ADDR   = 48,
+
+    MBI_SIZE        = 88,
+
+    /* Multiboot modules */
+    MB_MOD_START    = 0,
+    MB_MOD_END      = 4,
+    MB_MOD_CMDLINE  = 8,
+
+    MB_MOD_SIZE     = 16,
+
+    /* Region offsets */
+    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
+    ADDR_MBI      = ADDR_E820_MAP + 0x500,
+
+    /* Multiboot flags */
+    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
+    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
+    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
+    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
+    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
+};
+
+typedef struct {
+    /* buffer holding kernel, cmdlines and mb_infos */
+    void *mb_buf;
+    /* address in target */
+    hwaddr mb_buf_phys;
+    /* size of mb_buf in bytes */
+    unsigned mb_buf_size;
+    /* offset of mb-info's in bytes */
+    hwaddr offset_mbinfo;
+    /* offset in buffer for cmdlines in bytes */
+    hwaddr offset_cmdlines;
+    /* offset of modules in bytes */
+    hwaddr offset_mods;
+    /* available slots for mb modules infos */
+    int mb_mods_avail;
+    /* currently used slots of mb modules */
+    int mb_mods_count;
+} MultibootState;
+
+static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
+{
+    hwaddr p = s->offset_cmdlines;
+    char *b = (char *)s->mb_buf + p;
+
+    get_opt_value(b, strlen(cmdline) + 1, cmdline);
+    s->offset_cmdlines += strlen(b) + 1;
+    return s->mb_buf_phys + p;
+}
+
+static void mb_add_mod(MultibootState *s,
+                       hwaddr start, hwaddr end,
+                       hwaddr cmdline_phys)
+{
+    char *p;
+    assert(s->mb_mods_count < s->mb_mods_avail);
+
+    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
+
+    stl_p(p + MB_MOD_START,   start);
+    stl_p(p + MB_MOD_END,     end);
+    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
+
+    mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx"\n",
+             s->mb_mods_count, start, end);
+
+    s->mb_mods_count++;
+}
+
+int load_multiboot(void *fw_cfg,
+                   FILE *f,
+                   const char *kernel_filename,
+                   const char *initrd_filename,
+                   const char *kernel_cmdline,
+                   int kernel_file_size,
+                   uint8_t *header)
+{
+    int i, is_multiboot = 0;
+    uint32_t flags = 0;
+    uint32_t mh_entry_addr;
+    uint32_t mh_load_addr;
+    uint32_t mb_kernel_size;
+    MultibootState mbs;
+    uint8_t bootinfo[MBI_SIZE];
+    uint8_t *mb_bootinfo_data;
+
+    /* Ok, let's see if it is a multiboot image.
+       The header is 12x32bit long, so the latest entry may be 8192 - 48. */
+    for (i = 0; i < (8192 - 48); i += 4) {
+        if (ldl_p(header+i) == 0x1BADB002) {
+            uint32_t checksum = ldl_p(header+i+8);
+            flags = ldl_p(header+i+4);
+            checksum += flags;
+            checksum += (uint32_t)0x1BADB002;
+            if (!checksum) {
+                is_multiboot = 1;
+                break;
+            }
+        }
+    }
+
+    if (!is_multiboot)
+        return 0; /* no multiboot */
+
+    mb_debug("qemu: I believe we found a multiboot image!\n");
+    memset(bootinfo, 0, sizeof(bootinfo));
+    memset(&mbs, 0, sizeof(mbs));
+
+    if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
+        fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
+    }
+    if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
+        uint64_t elf_entry;
+        uint64_t elf_low, elf_high;
+        int kernel_size;
+        fclose(f);
+
+        if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
+            fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n");
+            exit(1);
+        }
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                               &elf_low, &elf_high, 0, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            fprintf(stderr, "Error while loading elf kernel\n");
+            exit(1);
+        }
+        mh_load_addr = elf_low;
+        mb_kernel_size = elf_high - elf_low;
+        mh_entry_addr = elf_entry;
+
+        mbs.mb_buf = g_malloc(mb_kernel_size);
+        if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != mb_kernel_size) {
+            fprintf(stderr, "Error while fetching elf kernel from rom\n");
+            exit(1);
+        }
+
+        mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
+                  mb_kernel_size, (size_t)mh_entry_addr);
+    } else {
+        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
+        uint32_t mh_header_addr = ldl_p(header+i+12);
+        uint32_t mh_load_end_addr = ldl_p(header+i+20);
+        uint32_t mh_bss_end_addr = ldl_p(header+i+24);
+        mh_load_addr = ldl_p(header+i+16);
+        uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
+        uint32_t mb_load_size = 0;
+        mh_entry_addr = ldl_p(header+i+28);
+
+        if (mh_load_end_addr) {
+            mb_kernel_size = mh_bss_end_addr - mh_load_addr;
+            mb_load_size = mh_load_end_addr - mh_load_addr;
+        } else {
+            mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
+            mb_load_size = mb_kernel_size;
+        }
+
+        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
+        uint32_t mh_mode_type = ldl_p(header+i+32);
+        uint32_t mh_width = ldl_p(header+i+36);
+        uint32_t mh_height = ldl_p(header+i+40);
+        uint32_t mh_depth = ldl_p(header+i+44); */
+
+        mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
+        mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
+        mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
+        mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
+        mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
+                 mb_load_size, mh_load_addr);
+
+        mbs.mb_buf = g_malloc(mb_kernel_size);
+        fseek(f, mb_kernel_text_offset, SEEK_SET);
+        if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
+            fprintf(stderr, "fread() failed\n");
+            exit(1);
+        }
+        memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
+        fclose(f);
+    }
+
+    mbs.mb_buf_phys = mh_load_addr;
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
+    mbs.offset_mbinfo = mbs.mb_buf_size;
+
+    /* Calculate space for cmdlines and mb_mods */
+    mbs.mb_buf_size += strlen(kernel_filename) + 1;
+    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
+    if (initrd_filename) {
+        const char *r = initrd_filename;
+        mbs.mb_buf_size += strlen(r) + 1;
+        mbs.mb_mods_avail = 1;
+        while (*(r = get_opt_value(NULL, 0, r))) {
+           mbs.mb_mods_avail++;
+           r++;
+        }
+        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
+    }
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
+
+    /* enlarge mb_buf to hold cmdlines and mb-info structs */
+    mbs.mb_buf          = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
+    mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
+
+    if (initrd_filename) {
+        char *next_initrd, not_last;
+
+        mbs.offset_mods = mbs.mb_buf_size;
+
+        do {
+            char *next_space;
+            int mb_mod_length;
+            uint32_t offs = mbs.mb_buf_size;
+
+            next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename);
+            not_last = *next_initrd;
+            *next_initrd = '\0';
+            /* if a space comes after the module filename, treat everything
+               after that as parameters */
+            hwaddr c = mb_add_cmdline(&mbs, initrd_filename);
+            if ((next_space = strchr(initrd_filename, ' ')))
+                *next_space = '\0';
+            mb_debug("multiboot loading module: %s\n", initrd_filename);
+            mb_mod_length = get_image_size(initrd_filename);
+            if (mb_mod_length < 0) {
+                fprintf(stderr, "Failed to open file '%s'\n", initrd_filename);
+                exit(1);
+            }
+
+            mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
+            mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
+
+            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
+            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
+                       mbs.mb_buf_phys + offs + mb_mod_length, c);
+
+            mb_debug("mod_start: %p\nmod_end:   %p\n  cmdline: "TARGET_FMT_plx"\n",
+                     (char *)mbs.mb_buf + offs,
+                     (char *)mbs.mb_buf + offs + mb_mod_length, c);
+            initrd_filename = next_initrd+1;
+        } while (not_last);
+    }
+
+    /* Commandline support */
+    char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
+    snprintf(kcmdline, sizeof(kcmdline), "%s %s",
+             kernel_filename, kernel_cmdline);
+    stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
+
+    stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
+    stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
+
+    /* the kernel is where we want it to be now */
+    stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
+                                | MULTIBOOT_FLAGS_BOOT_DEVICE
+                                | MULTIBOOT_FLAGS_CMDLINE
+                                | MULTIBOOT_FLAGS_MODULES
+                                | MULTIBOOT_FLAGS_MMAP);
+    stl_p(bootinfo + MBI_MEM_LOWER,   640);
+    stl_p(bootinfo + MBI_MEM_UPPER,   (ram_size / 1024) - 1024);
+    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
+    stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
+
+    mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
+    mb_debug("           mb_buf_phys   = "TARGET_FMT_plx"\n", mbs.mb_buf_phys);
+    mb_debug("           mod_start     = "TARGET_FMT_plx"\n", mbs.mb_buf_phys + mbs.offset_mods);
+    mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
+
+    /* save bootinfo off the stack */
+    mb_bootinfo_data = g_malloc(sizeof(bootinfo));
+    memcpy(mb_bootinfo_data, bootinfo, sizeof(bootinfo));
+
+    /* Pass variables to option rom */
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, mh_entry_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
+                     mbs.mb_buf, mbs.mb_buf_size);
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, sizeof(bootinfo));
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mb_bootinfo_data,
+                     sizeof(bootinfo));
+
+    option_rom[nb_option_roms].name = "multiboot.bin";
+    option_rom[nb_option_roms].bootindex = 0;
+    nb_option_roms++;
+
+    return 1; /* yes, we are multiboot */
+}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
new file mode 100644 (file)
index 0000000..309bb83
--- /dev/null
@@ -0,0 +1,1161 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/serial.h"
+#include "hw/apic.h"
+#include "hw/fdc.h"
+#include "hw/ide.h"
+#include "hw/pci/pci.h"
+#include "monitor/monitor.h"
+#include "hw/fw_cfg.h"
+#include "hw/hpet_emul.h"
+#include "hw/smbios.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/multiboot.h"
+#include "hw/mc146818rtc.h"
+#include "hw/i8254.h"
+#include "hw/pcspk.h"
+#include "hw/pci/msi.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/kvm.h"
+#include "kvm_i386.h"
+#include "hw/xen.h"
+#include "sysemu/blockdev.h"
+#include "hw/block-common.h"
+#include "ui/qemu-spice.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+#include "sysemu/arch_init.h"
+#include "qemu/bitmap.h"
+
+/* debug PC/ISA interrupts */
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
+#define ACPI_DATA_SIZE       0x10000
+#define BIOS_CFG_IOPORT 0x510
+#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
+#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
+#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
+#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
+#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
+
+#define E820_NR_ENTRIES                16
+
+struct e820_entry {
+    uint64_t address;
+    uint64_t length;
+    uint32_t type;
+} QEMU_PACKED __attribute((__aligned__(4)));
+
+struct e820_table {
+    uint32_t count;
+    struct e820_entry entry[E820_NR_ENTRIES];
+} QEMU_PACKED __attribute((__aligned__(4)));
+
+static struct e820_table e820_table;
+struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
+
+void gsi_handler(void *opaque, int n, int level)
+{
+    GSIState *s = opaque;
+
+    DPRINTF("pc: %s GSI %d\n", level ? "raising" : "lowering", n);
+    if (n < ISA_NUM_IRQS) {
+        qemu_set_irq(s->i8259_irq[n], level);
+    }
+    qemu_set_irq(s->ioapic_irq[n], level);
+}
+
+static void ioport80_write(void *opaque, hwaddr addr, uint64_t data,
+                           unsigned size)
+{
+}
+
+static uint64_t ioport80_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return 0xffffffffffffffffULL;
+}
+
+/* MSDOS compatibility mode FPU exception support */
+static qemu_irq ferr_irq;
+
+void pc_register_ferr_irq(qemu_irq irq)
+{
+    ferr_irq = irq;
+}
+
+/* XXX: add IGNNE support */
+void cpu_set_ferr(CPUX86State *s)
+{
+    qemu_irq_raise(ferr_irq);
+}
+
+static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data,
+                           unsigned size)
+{
+    qemu_irq_lower(ferr_irq);
+}
+
+static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return 0xffffffffffffffffULL;
+}
+
+/* TSC handling */
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_ticks();
+}
+
+/* SMM support */
+
+static cpu_set_smm_t smm_set;
+static void *smm_arg;
+
+void cpu_smm_register(cpu_set_smm_t callback, void *arg)
+{
+    assert(smm_set == NULL);
+    assert(smm_arg == NULL);
+    smm_set = callback;
+    smm_arg = arg;
+}
+
+void cpu_smm_update(CPUX86State *env)
+{
+    if (smm_set && smm_arg && env == first_cpu)
+        smm_set(!!(env->hflags & HF_SMM_MASK), smm_arg);
+}
+
+
+/* IRQ handling */
+int cpu_get_pic_interrupt(CPUX86State *env)
+{
+    int intno;
+
+    intno = apic_get_interrupt(env->apic_state);
+    if (intno >= 0) {
+        return intno;
+    }
+    /* read the irq from the PIC */
+    if (!apic_accept_pic_intr(env->apic_state)) {
+        return -1;
+    }
+
+    intno = pic_read_irq(isa_pic);
+    return intno;
+}
+
+static void pic_irq_request(void *opaque, int irq, int level)
+{
+    CPUX86State *env = first_cpu;
+
+    DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq);
+    if (env->apic_state) {
+        while (env) {
+            if (apic_accept_pic_intr(env->apic_state)) {
+                apic_deliver_pic_intr(env->apic_state, level);
+            }
+            env = env->next_cpu;
+        }
+    } else {
+        if (level)
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        else
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+/* PC cmos mappings */
+
+#define REG_EQUIPMENT_BYTE          0x14
+
+static int cmos_get_fd_drive_type(FDriveType fd0)
+{
+    int val;
+
+    switch (fd0) {
+    case FDRIVE_DRV_144:
+        /* 1.44 Mb 3"5 drive */
+        val = 4;
+        break;
+    case FDRIVE_DRV_288:
+        /* 2.88 Mb 3"5 drive */
+        val = 5;
+        break;
+    case FDRIVE_DRV_120:
+        /* 1.2 Mb 5"5 drive */
+        val = 2;
+        break;
+    case FDRIVE_DRV_NONE:
+    default:
+        val = 0;
+        break;
+    }
+    return val;
+}
+
+static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs,
+                         int16_t cylinders, int8_t heads, int8_t sectors)
+{
+    rtc_set_memory(s, type_ofs, 47);
+    rtc_set_memory(s, info_ofs, cylinders);
+    rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
+    rtc_set_memory(s, info_ofs + 2, heads);
+    rtc_set_memory(s, info_ofs + 3, 0xff);
+    rtc_set_memory(s, info_ofs + 4, 0xff);
+    rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
+    rtc_set_memory(s, info_ofs + 6, cylinders);
+    rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
+    rtc_set_memory(s, info_ofs + 8, sectors);
+}
+
+/* convert boot_device letter to something recognizable by the bios */
+static int boot_device2nibble(char boot_device)
+{
+    switch(boot_device) {
+    case 'a':
+    case 'b':
+        return 0x01; /* floppy boot */
+    case 'c':
+        return 0x02; /* hard drive boot */
+    case 'd':
+        return 0x03; /* CD-ROM boot */
+    case 'n':
+        return 0x04; /* Network boot */
+    }
+    return 0;
+}
+
+static int set_boot_dev(ISADevice *s, const char *boot_device, int fd_bootchk)
+{
+#define PC_MAX_BOOT_DEVICES 3
+    int nbds, bds[3] = { 0, };
+    int i;
+
+    nbds = strlen(boot_device);
+    if (nbds > PC_MAX_BOOT_DEVICES) {
+        error_report("Too many boot devices for PC");
+        return(1);
+    }
+    for (i = 0; i < nbds; i++) {
+        bds[i] = boot_device2nibble(boot_device[i]);
+        if (bds[i] == 0) {
+            error_report("Invalid boot device for PC: '%c'",
+                         boot_device[i]);
+            return(1);
+        }
+    }
+    rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
+    rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1));
+    return(0);
+}
+
+static int pc_boot_set(void *opaque, const char *boot_device)
+{
+    return set_boot_dev(opaque, boot_device, 0);
+}
+
+typedef struct pc_cmos_init_late_arg {
+    ISADevice *rtc_state;
+    BusState *idebus[2];
+} pc_cmos_init_late_arg;
+
+static void pc_cmos_init_late(void *opaque)
+{
+    pc_cmos_init_late_arg *arg = opaque;
+    ISADevice *s = arg->rtc_state;
+    int16_t cylinders;
+    int8_t heads, sectors;
+    int val;
+    int i, trans;
+
+    val = 0;
+    if (ide_get_geometry(arg->idebus[0], 0,
+                         &cylinders, &heads, &sectors) >= 0) {
+        cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors);
+        val |= 0xf0;
+    }
+    if (ide_get_geometry(arg->idebus[0], 1,
+                         &cylinders, &heads, &sectors) >= 0) {
+        cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors);
+        val |= 0x0f;
+    }
+    rtc_set_memory(s, 0x12, val);
+
+    val = 0;
+    for (i = 0; i < 4; i++) {
+        /* NOTE: ide_get_geometry() returns the physical
+           geometry.  It is always such that: 1 <= sects <= 63, 1
+           <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
+           geometry can be different if a translation is done. */
+        if (ide_get_geometry(arg->idebus[i / 2], i % 2,
+                             &cylinders, &heads, &sectors) >= 0) {
+            trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1;
+            assert((trans & ~3) == 0);
+            val |= trans << (i * 2);
+        }
+    }
+    rtc_set_memory(s, 0x39, val);
+
+    qemu_unregister_reset(pc_cmos_init_late, opaque);
+}
+
+void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+                  const char *boot_device,
+                  ISADevice *floppy, BusState *idebus0, BusState *idebus1,
+                  ISADevice *s)
+{
+    int val, nb, i;
+    FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
+    static pc_cmos_init_late_arg arg;
+
+    /* various important CMOS locations needed by PC/Bochs bios */
+
+    /* memory size */
+    /* base memory (first MiB) */
+    val = MIN(ram_size / 1024, 640);
+    rtc_set_memory(s, 0x15, val);
+    rtc_set_memory(s, 0x16, val >> 8);
+    /* extended memory (next 64MiB) */
+    if (ram_size > 1024 * 1024) {
+        val = (ram_size - 1024 * 1024) / 1024;
+    } else {
+        val = 0;
+    }
+    if (val > 65535)
+        val = 65535;
+    rtc_set_memory(s, 0x17, val);
+    rtc_set_memory(s, 0x18, val >> 8);
+    rtc_set_memory(s, 0x30, val);
+    rtc_set_memory(s, 0x31, val >> 8);
+    /* memory between 16MiB and 4GiB */
+    if (ram_size > 16 * 1024 * 1024) {
+        val = (ram_size - 16 * 1024 * 1024) / 65536;
+    } else {
+        val = 0;
+    }
+    if (val > 65535)
+        val = 65535;
+    rtc_set_memory(s, 0x34, val);
+    rtc_set_memory(s, 0x35, val >> 8);
+    /* memory above 4GiB */
+    val = above_4g_mem_size / 65536;
+    rtc_set_memory(s, 0x5b, val);
+    rtc_set_memory(s, 0x5c, val >> 8);
+    rtc_set_memory(s, 0x5d, val >> 16);
+
+    /* set the number of CPU */
+    rtc_set_memory(s, 0x5f, smp_cpus - 1);
+
+    /* set boot devices, and disable floppy signature check if requested */
+    if (set_boot_dev(s, boot_device, fd_bootchk)) {
+        exit(1);
+    }
+
+    /* floppy type */
+    if (floppy) {
+        for (i = 0; i < 2; i++) {
+            fd_type[i] = isa_fdc_get_drive_type(floppy, i);
+        }
+    }
+    val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
+        cmos_get_fd_drive_type(fd_type[1]);
+    rtc_set_memory(s, 0x10, val);
+
+    val = 0;
+    nb = 0;
+    if (fd_type[0] < FDRIVE_DRV_NONE) {
+        nb++;
+    }
+    if (fd_type[1] < FDRIVE_DRV_NONE) {
+        nb++;
+    }
+    switch (nb) {
+    case 0:
+        break;
+    case 1:
+        val |= 0x01; /* 1 drive, ready for boot */
+        break;
+    case 2:
+        val |= 0x41; /* 2 drives, ready for boot */
+        break;
+    }
+    val |= 0x02; /* FPU is there */
+    val |= 0x04; /* PS/2 mouse installed */
+    rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
+
+    /* hard drives */
+    arg.rtc_state = s;
+    arg.idebus[0] = idebus0;
+    arg.idebus[1] = idebus1;
+    qemu_register_reset(pc_cmos_init_late, &arg);
+}
+
+/* port 92 stuff: could be split off */
+typedef struct Port92State {
+    ISADevice dev;
+    MemoryRegion io;
+    uint8_t outport;
+    qemu_irq *a20_out;
+} Port92State;
+
+static void port92_write(void *opaque, hwaddr addr, uint64_t val,
+                         unsigned size)
+{
+    Port92State *s = opaque;
+
+    DPRINTF("port92: write 0x%02x\n", val);
+    s->outport = val;
+    qemu_set_irq(*s->a20_out, (val >> 1) & 1);
+    if (val & 1) {
+        qemu_system_reset_request();
+    }
+}
+
+static uint64_t port92_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    Port92State *s = opaque;
+    uint32_t ret;
+
+    ret = s->outport;
+    DPRINTF("port92: read 0x%02x\n", ret);
+    return ret;
+}
+
+static void port92_init(ISADevice *dev, qemu_irq *a20_out)
+{
+    Port92State *s = DO_UPCAST(Port92State, dev, dev);
+
+    s->a20_out = a20_out;
+}
+
+static const VMStateDescription vmstate_port92_isa = {
+    .name = "port92",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(outport, Port92State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void port92_reset(DeviceState *d)
+{
+    Port92State *s = container_of(d, Port92State, dev.qdev);
+
+    s->outport &= ~1;
+}
+
+static const MemoryRegionOps port92_ops = {
+    .read = port92_read,
+    .write = port92_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int port92_initfn(ISADevice *dev)
+{
+    Port92State *s = DO_UPCAST(Port92State, dev, dev);
+
+    memory_region_init_io(&s->io, &port92_ops, s, "port92", 1);
+    isa_register_ioport(dev, &s->io, 0x92);
+
+    s->outport = 0;
+    return 0;
+}
+
+static void port92_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = port92_initfn;
+    dc->no_user = 1;
+    dc->reset = port92_reset;
+    dc->vmsd = &vmstate_port92_isa;
+}
+
+static const TypeInfo port92_info = {
+    .name          = "port92",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(Port92State),
+    .class_init    = port92_class_initfn,
+};
+
+static void port92_register_types(void)
+{
+    type_register_static(&port92_info);
+}
+
+type_init(port92_register_types)
+
+static void handle_a20_line_change(void *opaque, int irq, int level)
+{
+    X86CPU *cpu = opaque;
+
+    /* XXX: send to all CPUs ? */
+    /* XXX: add logic to handle multiple A20 line sources */
+    x86_cpu_set_a20(cpu, level);
+}
+
+int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
+{
+    int index = le32_to_cpu(e820_table.count);
+    struct e820_entry *entry;
+
+    if (index >= E820_NR_ENTRIES)
+        return -EBUSY;
+    entry = &e820_table.entry[index++];
+
+    entry->address = cpu_to_le64(address);
+    entry->length = cpu_to_le64(length);
+    entry->type = cpu_to_le32(type);
+
+    e820_table.count = cpu_to_le32(index);
+    return index;
+}
+
+/* Calculates the limit to CPU APIC ID values
+ *
+ * This function returns the limit for the APIC ID value, so that all
+ * CPU APIC IDs are < pc_apic_id_limit().
+ *
+ * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init().
+ */
+static unsigned int pc_apic_id_limit(unsigned int max_cpus)
+{
+    return x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
+}
+
+static void *bochs_bios_init(void)
+{
+    void *fw_cfg;
+    uint8_t *smbios_table;
+    size_t smbios_len;
+    uint64_t *numa_fw_cfg;
+    int i, j;
+    unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
+
+    fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+    /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
+     *
+     * SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug
+     * QEMU<->SeaBIOS interface is not based on the "CPU index", but on the APIC
+     * ID of hotplugged CPUs[1]. This means that FW_CFG_MAX_CPUS is not the
+     * "maximum number of CPUs", but the "limit to the APIC ID values SeaBIOS
+     * may see".
+     *
+     * So, this means we must not use max_cpus, here, but the maximum possible
+     * APIC ID value, plus one.
+     *
+     * [1] The only kind of "CPU identifier" used between SeaBIOS and QEMU is
+     *     the APIC ID, not the "CPU index"
+     */
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)apic_id_limit);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES,
+                     acpi_tables, acpi_tables_len);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
+
+    smbios_table = smbios_get_table(&smbios_len);
+    if (smbios_table)
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
+                         smbios_table, smbios_len);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
+                     &e820_table, sizeof(e820_table));
+
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_cfg, sizeof(hpet_cfg));
+    /* allocate memory for the NUMA channel: one (64bit) word for the number
+     * of nodes, one word for each VCPU->node and one word for each node to
+     * hold the amount of memory.
+     */
+    numa_fw_cfg = g_new0(uint64_t, 1 + apic_id_limit + nb_numa_nodes);
+    numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes);
+    for (i = 0; i < max_cpus; i++) {
+        unsigned int apic_id = x86_cpu_apic_id_from_index(i);
+        assert(apic_id < apic_id_limit);
+        for (j = 0; j < nb_numa_nodes; j++) {
+            if (test_bit(i, node_cpumask[j])) {
+                numa_fw_cfg[apic_id + 1] = cpu_to_le64(j);
+                break;
+            }
+        }
+    }
+    for (i = 0; i < nb_numa_nodes; i++) {
+        numa_fw_cfg[apic_id_limit + 1 + i] = cpu_to_le64(node_mem[i]);
+    }
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg,
+                     (1 + apic_id_limit + nb_numa_nodes) *
+                     sizeof(*numa_fw_cfg));
+
+    return fw_cfg;
+}
+
+static long get_file_size(FILE *f)
+{
+    long where, size;
+
+    /* XXX: on Unix systems, using fstat() probably makes more sense */
+
+    where = ftell(f);
+    fseek(f, 0, SEEK_END);
+    size = ftell(f);
+    fseek(f, where, SEEK_SET);
+
+    return size;
+}
+
+static void load_linux(void *fw_cfg,
+                       const char *kernel_filename,
+                      const char *initrd_filename,
+                      const char *kernel_cmdline,
+                       hwaddr max_ram_size)
+{
+    uint16_t protocol;
+    int setup_size, kernel_size, initrd_size = 0, cmdline_size;
+    uint32_t initrd_max;
+    uint8_t header[8192], *setup, *kernel, *initrd_data;
+    hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0;
+    FILE *f;
+    char *vmode;
+
+    /* Align to 16 bytes as a paranoia measure */
+    cmdline_size = (strlen(kernel_cmdline)+16) & ~15;
+
+    /* load the kernel header */
+    f = fopen(kernel_filename, "rb");
+    if (!f || !(kernel_size = get_file_size(f)) ||
+       fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) !=
+       MIN(ARRAY_SIZE(header), kernel_size)) {
+       fprintf(stderr, "qemu: could not load kernel '%s': %s\n",
+               kernel_filename, strerror(errno));
+       exit(1);
+    }
+
+    /* kernel protocol version */
+#if 0
+    fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));
+#endif
+    if (ldl_p(header+0x202) == 0x53726448)
+       protocol = lduw_p(header+0x206);
+    else {
+       /* This looks like a multiboot kernel. If it is, let's stop
+          treating it like a Linux kernel. */
+        if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename,
+                           kernel_cmdline, kernel_size, header))
+            return;
+       protocol = 0;
+    }
+
+    if (protocol < 0x200 || !(header[0x211] & 0x01)) {
+       /* Low kernel */
+       real_addr    = 0x90000;
+       cmdline_addr = 0x9a000 - cmdline_size;
+       prot_addr    = 0x10000;
+    } else if (protocol < 0x202) {
+       /* High but ancient kernel */
+       real_addr    = 0x90000;
+       cmdline_addr = 0x9a000 - cmdline_size;
+       prot_addr    = 0x100000;
+    } else {
+       /* High and recent kernel */
+       real_addr    = 0x10000;
+       cmdline_addr = 0x20000;
+       prot_addr    = 0x100000;
+    }
+
+#if 0
+    fprintf(stderr,
+           "qemu: real_addr     = 0x" TARGET_FMT_plx "\n"
+           "qemu: cmdline_addr  = 0x" TARGET_FMT_plx "\n"
+           "qemu: prot_addr     = 0x" TARGET_FMT_plx "\n",
+           real_addr,
+           cmdline_addr,
+           prot_addr);
+#endif
+
+    /* highest address for loading the initrd */
+    if (protocol >= 0x203)
+       initrd_max = ldl_p(header+0x22c);
+    else
+       initrd_max = 0x37ffffff;
+
+    if (initrd_max >= max_ram_size-ACPI_DATA_SIZE)
+       initrd_max = max_ram_size-ACPI_DATA_SIZE-1;
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1);
+    fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
+
+    if (protocol >= 0x202) {
+       stl_p(header+0x228, cmdline_addr);
+    } else {
+       stw_p(header+0x20, 0xA33F);
+       stw_p(header+0x22, cmdline_addr-real_addr);
+    }
+
+    /* handle vga= parameter */
+    vmode = strstr(kernel_cmdline, "vga=");
+    if (vmode) {
+        unsigned int video_mode;
+        /* skip "vga=" */
+        vmode += 4;
+        if (!strncmp(vmode, "normal", 6)) {
+            video_mode = 0xffff;
+        } else if (!strncmp(vmode, "ext", 3)) {
+            video_mode = 0xfffe;
+        } else if (!strncmp(vmode, "ask", 3)) {
+            video_mode = 0xfffd;
+        } else {
+            video_mode = strtol(vmode, NULL, 0);
+        }
+        stw_p(header+0x1fa, video_mode);
+    }
+
+    /* loader type */
+    /* High nybble = B reserved for QEMU; low nybble is revision number.
+       If this code is substantially changed, you may want to consider
+       incrementing the revision. */
+    if (protocol >= 0x200)
+       header[0x210] = 0xB0;
+
+    /* heap */
+    if (protocol >= 0x201) {
+       header[0x211] |= 0x80;  /* CAN_USE_HEAP */
+       stw_p(header+0x224, cmdline_addr-real_addr-0x200);
+    }
+
+    /* load initrd */
+    if (initrd_filename) {
+       if (protocol < 0x200) {
+           fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n");
+           exit(1);
+       }
+
+       initrd_size = get_image_size(initrd_filename);
+        if (initrd_size < 0) {
+            fprintf(stderr, "qemu: error reading initrd %s\n",
+                    initrd_filename);
+            exit(1);
+        }
+
+        initrd_addr = (initrd_max-initrd_size) & ~4095;
+
+        initrd_data = g_malloc(initrd_size);
+        load_image(initrd_filename, initrd_data);
+
+        fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size);
+
+       stl_p(header+0x218, initrd_addr);
+       stl_p(header+0x21c, initrd_size);
+    }
+
+    /* load kernel and setup */
+    setup_size = header[0x1f1];
+    if (setup_size == 0)
+       setup_size = 4;
+    setup_size = (setup_size+1)*512;
+    kernel_size -= setup_size;
+
+    setup  = g_malloc(setup_size);
+    kernel = g_malloc(kernel_size);
+    fseek(f, 0, SEEK_SET);
+    if (fread(setup, 1, setup_size, f) != setup_size) {
+        fprintf(stderr, "fread() failed\n");
+        exit(1);
+    }
+    if (fread(kernel, 1, kernel_size, f) != kernel_size) {
+        fprintf(stderr, "fread() failed\n");
+        exit(1);
+    }
+    fclose(f);
+    memcpy(setup, header, MIN(sizeof(header), setup_size));
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);
+
+    option_rom[nb_option_roms].name = "linuxboot.bin";
+    option_rom[nb_option_roms].bootindex = 0;
+    nb_option_roms++;
+}
+
+#define NE2000_NB_MAX 6
+
+static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360,
+                                              0x280, 0x380 };
+static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
+
+static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
+static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
+
+void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd)
+{
+    static int nb_ne2k = 0;
+
+    if (nb_ne2k == NE2000_NB_MAX)
+        return;
+    isa_ne2000_init(bus, ne2000_io[nb_ne2k],
+                    ne2000_irq[nb_ne2k], nd);
+    nb_ne2k++;
+}
+
+DeviceState *cpu_get_current_apic(void)
+{
+    if (cpu_single_env) {
+        return cpu_single_env->apic_state;
+    } else {
+        return NULL;
+    }
+}
+
+void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
+{
+    CPUX86State *s = opaque;
+
+    if (level) {
+        cpu_interrupt(s, CPU_INTERRUPT_SMI);
+    }
+}
+
+void pc_cpus_init(const char *cpu_model)
+{
+    int i;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+    }
+
+    for (i = 0; i < smp_cpus; i++) {
+        if (!cpu_x86_init(cpu_model)) {
+            exit(1);
+        }
+    }
+}
+
+void pc_acpi_init(const char *default_dsdt)
+{
+    char *filename = NULL, *arg = NULL;
+
+    if (acpi_tables != NULL) {
+        /* manually set via -acpitable, leave it alone */
+        return;
+    }
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt);
+    if (filename == NULL) {
+        fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt);
+        return;
+    }
+
+    arg = g_strdup_printf("file=%s", filename);
+    if (acpi_table_add(arg) != 0) {
+        fprintf(stderr, "WARNING: failed to load %s\n", filename);
+    }
+    g_free(arg);
+    g_free(filename);
+}
+
+void *pc_memory_init(MemoryRegion *system_memory,
+                    const char *kernel_filename,
+                    const char *kernel_cmdline,
+                    const char *initrd_filename,
+                    ram_addr_t below_4g_mem_size,
+                    ram_addr_t above_4g_mem_size,
+                    MemoryRegion *rom_memory,
+                    MemoryRegion **ram_memory)
+{
+    int linux_boot, i;
+    MemoryRegion *ram, *option_rom_mr;
+    MemoryRegion *ram_below_4g, *ram_above_4g;
+    void *fw_cfg;
+
+    linux_boot = (kernel_filename != NULL);
+
+    /* Allocate RAM.  We allocate it as a single memory region and use
+     * aliases to address portions of it, mostly for backwards compatibility
+     * with older qemus that used qemu_ram_alloc().
+     */
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, "pc.ram",
+                           below_4g_mem_size + above_4g_mem_size);
+    vmstate_register_ram_global(ram);
+    *ram_memory = ram;
+    ram_below_4g = g_malloc(sizeof(*ram_below_4g));
+    memory_region_init_alias(ram_below_4g, "ram-below-4g", ram,
+                             0, below_4g_mem_size);
+    memory_region_add_subregion(system_memory, 0, ram_below_4g);
+    if (above_4g_mem_size > 0) {
+        ram_above_4g = g_malloc(sizeof(*ram_above_4g));
+        memory_region_init_alias(ram_above_4g, "ram-above-4g", ram,
+                                 below_4g_mem_size, above_4g_mem_size);
+        memory_region_add_subregion(system_memory, 0x100000000ULL,
+                                    ram_above_4g);
+    }
+
+
+    /* Initialize PC system firmware */
+    pc_system_firmware_init(rom_memory);
+
+    option_rom_mr = g_malloc(sizeof(*option_rom_mr));
+    memory_region_init_ram(option_rom_mr, "pc.rom", PC_ROM_SIZE);
+    vmstate_register_ram_global(option_rom_mr);
+    memory_region_add_subregion_overlap(rom_memory,
+                                        PC_ROM_MIN_VGA,
+                                        option_rom_mr,
+                                        1);
+
+    fw_cfg = bochs_bios_init();
+    rom_set_fw(fw_cfg);
+
+    if (linux_boot) {
+        load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size);
+    }
+
+    for (i = 0; i < nb_option_roms; i++) {
+        rom_add_option(option_rom[i].name, option_rom[i].bootindex);
+    }
+    return fw_cfg;
+}
+
+qemu_irq *pc_allocate_cpu_irq(void)
+{
+    return qemu_allocate_irqs(pic_irq_request, NULL, 1);
+}
+
+DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
+{
+    DeviceState *dev = NULL;
+
+    if (pci_bus) {
+        PCIDevice *pcidev = pci_vga_init(pci_bus);
+        dev = pcidev ? &pcidev->qdev : NULL;
+    } else if (isa_bus) {
+        ISADevice *isadev = isa_vga_init(isa_bus);
+        dev = isadev ? &isadev->qdev : NULL;
+    }
+    return dev;
+}
+
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+    CPUX86State *env = cpu_single_env;
+
+    if (env && level) {
+        cpu_exit(env);
+    }
+}
+
+static const MemoryRegionOps ioport80_io_ops = {
+    .write = ioport80_write,
+    .read = ioport80_read,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps ioportF0_io_ops = {
+    .write = ioportF0_write,
+    .read = ioportF0_read,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
+                          ISADevice **rtc_state,
+                          ISADevice **floppy,
+                          bool no_vmport)
+{
+    int i;
+    DriveInfo *fd[MAX_FD];
+    DeviceState *hpet = NULL;
+    int pit_isa_irq = 0;
+    qemu_irq pit_alt_irq = NULL;
+    qemu_irq rtc_irq = NULL;
+    qemu_irq *a20_line;
+    ISADevice *i8042, *port92, *vmmouse, *pit = NULL;
+    qemu_irq *cpu_exit_irq;
+    MemoryRegion *ioport80_io = g_new(MemoryRegion, 1);
+    MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1);
+
+    memory_region_init_io(ioport80_io, &ioport80_io_ops, NULL, "ioport80", 1);
+    memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io);
+
+    memory_region_init_io(ioportF0_io, &ioportF0_io_ops, NULL, "ioportF0", 1);
+    memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io);
+
+    /*
+     * Check if an HPET shall be created.
+     *
+     * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT
+     * when the HPET wants to take over. Thus we have to disable the latter.
+     */
+    if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) {
+        hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
+
+        if (hpet) {
+            for (i = 0; i < GSI_NUM_PINS; i++) {
+                sysbus_connect_irq(SYS_BUS_DEVICE(hpet), i, gsi[i]);
+            }
+            pit_isa_irq = -1;
+            pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT);
+            rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT);
+        }
+    }
+    *rtc_state = rtc_init(isa_bus, 2000, rtc_irq);
+
+    qemu_register_boot_set(pc_boot_set, *rtc_state);
+
+    if (!xen_enabled()) {
+        if (kvm_irqchip_in_kernel()) {
+            pit = kvm_pit_init(isa_bus, 0x40);
+        } else {
+            pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
+        }
+        if (hpet) {
+            /* connect PIT to output control line of the HPET */
+            qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
+        }
+        pcspk_init(isa_bus, pit);
+    }
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_isa_init(isa_bus, i, serial_hds[i]);
+        }
+    }
+
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        if (parallel_hds[i]) {
+            parallel_init(isa_bus, i, parallel_hds[i]);
+        }
+    }
+
+    a20_line = qemu_allocate_irqs(handle_a20_line_change,
+                                  x86_env_get_cpu(first_cpu), 2);
+    i8042 = isa_create_simple(isa_bus, "i8042");
+    i8042_setup_a20_line(i8042, &a20_line[0]);
+    if (!no_vmport) {
+        vmport_init(isa_bus);
+        vmmouse = isa_try_create(isa_bus, "vmmouse");
+    } else {
+        vmmouse = NULL;
+    }
+    if (vmmouse) {
+        qdev_prop_set_ptr(&vmmouse->qdev, "ps2_mouse", i8042);
+        qdev_init_nofail(&vmmouse->qdev);
+    }
+    port92 = isa_create_simple(isa_bus, "port92");
+    port92_init(port92, &a20_line[1]);
+
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    DMA_init(0, cpu_exit_irq);
+
+    for(i = 0; i < MAX_FD; i++) {
+        fd[i] = drive_get(IF_FLOPPY, 0, i);
+    }
+    *floppy = fdctrl_init_isa(isa_bus, fd);
+}
+
+void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
+{
+    int i;
+
+    for (i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) {
+            pc_init_ne2k_isa(isa_bus, nd);
+        } else {
+            pci_nic_init_nofail(nd, "e1000", NULL);
+        }
+    }
+}
+
+void pc_pci_device_init(PCIBus *pci_bus)
+{
+    int max_bus;
+    int bus;
+
+    max_bus = drive_get_max_bus(IF_SCSI);
+    for (bus = 0; bus <= max_bus; bus++) {
+        pci_create_simple(pci_bus, -1, "lsi53c895a");
+    }
+}
+
+void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+    unsigned int i;
+
+    if (kvm_irqchip_in_kernel()) {
+        dev = qdev_create(NULL, "kvm-ioapic");
+    } else {
+        dev = qdev_create(NULL, "ioapic");
+    }
+    if (parent_name) {
+        object_property_add_child(object_resolve_path(parent_name, NULL),
+                                  "ioapic", OBJECT(dev), NULL);
+    }
+    qdev_init_nofail(dev);
+    d = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(d, 0, 0xfec00000);
+
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
+    }
+}
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
new file mode 100644 (file)
index 0000000..73a8656
--- /dev/null
@@ -0,0 +1,713 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <glib.h>
+
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/apic.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_ids.h"
+#include "hw/usb.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "hw/ide.h"
+#include "sysemu/kvm.h"
+#include "hw/kvm/clock.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "sysemu/arch_init.h"
+#include "sysemu/blockdev.h"
+#include "hw/smbus.h"
+#include "hw/xen.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+#include "cpu.h"
+#ifdef CONFIG_XEN
+#  include <xen/hvm/hvm_info_table.h>
+#endif
+
+#define MAX_IDE_BUS 2
+
+static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
+static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
+static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
+
+/* PC hardware initialisation */
+static void pc_init1(MemoryRegion *system_memory,
+                     MemoryRegion *system_io,
+                     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,
+                     int pci_enabled,
+                     int kvmclock_enabled)
+{
+    int i;
+    ram_addr_t below_4g_mem_size, above_4g_mem_size;
+    PCIBus *pci_bus;
+    ISABus *isa_bus;
+    PCII440FXState *i440fx_state;
+    int piix3_devfn = -1;
+    qemu_irq *cpu_irq;
+    qemu_irq *gsi;
+    qemu_irq *i8259;
+    qemu_irq *smi_irq;
+    GSIState *gsi_state;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    BusState *idebus[MAX_IDE_BUS];
+    ISADevice *rtc_state;
+    ISADevice *floppy;
+    MemoryRegion *ram_memory;
+    MemoryRegion *pci_memory;
+    MemoryRegion *rom_memory;
+    void *fw_cfg = NULL;
+
+    pc_cpus_init(cpu_model);
+    pc_acpi_init("acpi-dsdt.aml");
+
+    if (kvmclock_enabled) {
+        kvmclock_create();
+    }
+
+    if (ram_size >= 0xe0000000 ) {
+        above_4g_mem_size = ram_size - 0xe0000000;
+        below_4g_mem_size = 0xe0000000;
+    } else {
+        above_4g_mem_size = 0;
+        below_4g_mem_size = ram_size;
+    }
+
+    if (pci_enabled) {
+        pci_memory = g_new(MemoryRegion, 1);
+        memory_region_init(pci_memory, "pci", INT64_MAX);
+        rom_memory = pci_memory;
+    } else {
+        pci_memory = NULL;
+        rom_memory = system_memory;
+    }
+
+    /* allocate ram and load rom/bios */
+    if (!xen_enabled()) {
+        fw_cfg = pc_memory_init(system_memory,
+                       kernel_filename, kernel_cmdline, initrd_filename,
+                       below_4g_mem_size, above_4g_mem_size,
+                       rom_memory, &ram_memory);
+    }
+
+    gsi_state = g_malloc0(sizeof(*gsi_state));
+    if (kvm_irqchip_in_kernel()) {
+        kvm_pc_setup_irq_routing(pci_enabled);
+        gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
+                                 GSI_NUM_PINS);
+    } else {
+        gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+    }
+
+    if (pci_enabled) {
+        pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
+                              system_memory, system_io, ram_size,
+                              below_4g_mem_size,
+                              0x100000000ULL - below_4g_mem_size,
+                              0x100000000ULL + above_4g_mem_size,
+                              (sizeof(hwaddr) == 4
+                               ? 0
+                               : ((uint64_t)1 << 62)),
+                              pci_memory, ram_memory);
+    } else {
+        pci_bus = NULL;
+        i440fx_state = NULL;
+        isa_bus = isa_bus_new(NULL, system_io);
+        no_hpet = 1;
+    }
+    isa_bus_irqs(isa_bus, gsi);
+
+    if (kvm_irqchip_in_kernel()) {
+        i8259 = kvm_i8259_init(isa_bus);
+    } else if (xen_enabled()) {
+        i8259 = xen_interrupt_controller_init();
+    } else {
+        cpu_irq = pc_allocate_cpu_irq();
+        i8259 = i8259_init(isa_bus, cpu_irq[0]);
+    }
+
+    for (i = 0; i < ISA_NUM_IRQS; i++) {
+        gsi_state->i8259_irq[i] = i8259[i];
+    }
+    if (pci_enabled) {
+        ioapic_init_gsi(gsi_state, "i440fx");
+    }
+
+    pc_register_ferr_irq(gsi[13]);
+
+    pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
+    if (xen_enabled()) {
+        pci_create_simple(pci_bus, -1, "xen-platform");
+    }
+
+    /* init basic PC hardware */
+    pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled());
+
+    pc_nic_init(isa_bus, pci_bus);
+
+    ide_drive_get(hd, MAX_IDE_BUS);
+    if (pci_enabled) {
+        PCIDevice *dev;
+        if (xen_enabled()) {
+            dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1);
+        } else {
+            dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+        }
+        idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
+        idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
+    } else {
+        for(i = 0; i < MAX_IDE_BUS; i++) {
+            ISADevice *dev;
+            dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
+                               ide_irq[i],
+                               hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
+            idebus[i] = qdev_get_child_bus(&dev->qdev, "ide.0");
+        }
+    }
+
+    audio_init(isa_bus, pci_enabled ? pci_bus : NULL);
+
+    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
+                 floppy, idebus[0], idebus[1], rtc_state);
+
+    if (pci_enabled && usb_enabled(false)) {
+        pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
+    }
+
+    if (pci_enabled && acpi_enabled) {
+        i2c_bus *smbus;
+
+        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
+        /* TODO: Populate SPD eeprom data.  */
+        smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+                              gsi[9], *smi_irq,
+                              kvm_enabled(), fw_cfg);
+        smbus_eeprom_init(smbus, 8, NULL, 0);
+    }
+
+    if (pci_enabled) {
+        pc_pci_device_init(pci_bus);
+    }
+}
+
+static void pc_init_pci(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    pc_init1(get_system_memory(),
+             get_system_io(),
+             ram_size, boot_device,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, cpu_model, 1, 1);
+}
+
+static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
+{
+    enable_compat_apic_id_mode();
+    pc_init_pci(args);
+}
+
+/* PC machine init function for pc-0.14 to pc-1.2 */
+static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
+{
+    disable_kvm_pv_eoi();
+    pc_init_pci_1_3(args);
+}
+
+/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
+static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    disable_kvm_pv_eoi();
+    enable_compat_apic_id_mode();
+    pc_init1(get_system_memory(),
+             get_system_io(),
+             ram_size, boot_device,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, cpu_model, 1, 0);
+}
+
+static void pc_init_isa(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    if (cpu_model == NULL)
+        cpu_model = "486";
+    disable_kvm_pv_eoi();
+    enable_compat_apic_id_mode();
+    pc_init1(get_system_memory(),
+             get_system_io(),
+             ram_size, boot_device,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, cpu_model, 0, 1);
+}
+
+#ifdef CONFIG_XEN
+static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
+{
+    if (xen_hvm_init() != 0) {
+        hw_error("xen hardware virtual machine initialisation failed");
+    }
+    pc_init_pci_no_kvmclock(args);
+    xen_vcpu_init();
+}
+#endif
+
+static QEMUMachine pc_i440fx_machine_v1_5 = {
+    .name = "pc-i440fx-1.5",
+    .alias = "pc",
+    .desc = "Standard PC (i440FX + PIIX, 1996)",
+    .init = pc_init_pci,
+    .max_cpus = 255,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine pc_i440fx_machine_v1_4 = {
+    .name = "pc-i440fx-1.4",
+    .desc = "Standard PC (i440FX + PIIX, 1996)",
+    .init = pc_init_pci,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_1_4,
+        { /* end of list */ }
+    },
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+#define PC_COMPAT_1_3 \
+       PC_COMPAT_1_4, \
+        {\
+            .driver   = "usb-tablet",\
+            .property = "usb_version",\
+            .value    = stringify(1),\
+        },{\
+            .driver   = "virtio-net-pci",\
+            .property = "ctrl_mac_addr",\
+            .value    = "off",      \
+        },{ \
+            .driver   = "virtio-net-pci", \
+            .property = "mq", \
+            .value    = "off", \
+        }
+
+static QEMUMachine pc_machine_v1_3 = {
+    .name = "pc-1.3",
+    .desc = "Standard PC",
+    .init = pc_init_pci_1_3,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_1_3,
+        { /* end of list */ }
+    },
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+#define PC_COMPAT_1_2 \
+        PC_COMPAT_1_3,\
+        {\
+            .driver   = "nec-usb-xhci",\
+            .property = "msi",\
+            .value    = "off",\
+        },{\
+            .driver   = "nec-usb-xhci",\
+            .property = "msix",\
+            .value    = "off",\
+        },{\
+            .driver   = "ivshmem",\
+            .property = "use64",\
+            .value    = "0",\
+        },{\
+            .driver   = "qxl",\
+            .property = "revision",\
+            .value    = stringify(3),\
+        },{\
+            .driver   = "qxl-vga",\
+            .property = "revision",\
+            .value    = stringify(3),\
+        },{\
+            .driver   = "VGA",\
+            .property = "mmio",\
+            .value    = "off",\
+        }
+
+static QEMUMachine pc_machine_v1_2 = {
+    .name = "pc-1.2",
+    .desc = "Standard PC",
+    .init = pc_init_pci_1_2,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_1_2,
+        { /* end of list */ }
+    },
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+#define PC_COMPAT_1_1 \
+        PC_COMPAT_1_2,\
+        {\
+            .driver   = "virtio-scsi-pci",\
+            .property = "hotplug",\
+            .value    = "off",\
+        },{\
+            .driver   = "virtio-scsi-pci",\
+            .property = "param_change",\
+            .value    = "off",\
+        },{\
+            .driver   = "VGA",\
+            .property = "vgamem_mb",\
+            .value    = stringify(8),\
+        },{\
+            .driver   = "vmware-svga",\
+            .property = "vgamem_mb",\
+            .value    = stringify(8),\
+        },{\
+            .driver   = "qxl-vga",\
+            .property = "vgamem_mb",\
+            .value    = stringify(8),\
+        },{\
+            .driver   = "qxl",\
+            .property = "vgamem_mb",\
+            .value    = stringify(8),\
+        },{\
+            .driver   = "virtio-blk-pci",\
+            .property = "config-wce",\
+            .value    = "off",\
+        }
+
+static QEMUMachine pc_machine_v1_1 = {
+    .name = "pc-1.1",
+    .desc = "Standard PC",
+    .init = pc_init_pci_1_2,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_1_1,
+        { /* end of list */ }
+    },
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+#define PC_COMPAT_1_0 \
+        PC_COMPAT_1_1,\
+        {\
+            .driver   = "pc-sysfw",\
+            .property = "rom_only",\
+            .value    = stringify(1),\
+        }, {\
+            .driver   = "isa-fdc",\
+            .property = "check_media_rate",\
+            .value    = "off",\
+        }, {\
+            .driver   = "virtio-balloon-pci",\
+            .property = "class",\
+            .value    = stringify(PCI_CLASS_MEMORY_RAM),\
+        },{\
+            .driver   = "apic",\
+            .property = "vapic",\
+            .value    = "off",\
+        },{\
+            .driver   = TYPE_USB_DEVICE,\
+            .property = "full-path",\
+            .value    = "no",\
+        }
+
+static QEMUMachine pc_machine_v1_0 = {
+    .name = "pc-1.0",
+    .desc = "Standard PC",
+    .init = pc_init_pci_1_2,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_1_0,
+        { /* end of list */ }
+    },
+    .hw_version = "1.0",
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+#define PC_COMPAT_0_15 \
+        PC_COMPAT_1_0
+
+static QEMUMachine pc_machine_v0_15 = {
+    .name = "pc-0.15",
+    .desc = "Standard PC",
+    .init = pc_init_pci_1_2,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_0_15,
+        { /* end of list */ }
+    },
+    .hw_version = "0.15",
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+#define PC_COMPAT_0_14 \
+        PC_COMPAT_0_15,\
+        {\
+            .driver   = "virtio-blk-pci",\
+            .property = "event_idx",\
+            .value    = "off",\
+        },{\
+            .driver   = "virtio-serial-pci",\
+            .property = "event_idx",\
+            .value    = "off",\
+        },{\
+            .driver   = "virtio-net-pci",\
+            .property = "event_idx",\
+            .value    = "off",\
+        },{\
+            .driver   = "virtio-balloon-pci",\
+            .property = "event_idx",\
+            .value    = "off",\
+        }
+
+static QEMUMachine pc_machine_v0_14 = {
+    .name = "pc-0.14",
+    .desc = "Standard PC",
+    .init = pc_init_pci_1_2,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_0_14, 
+        {
+            .driver   = "qxl",
+            .property = "revision",
+            .value    = stringify(2),
+        },{
+            .driver   = "qxl-vga",
+            .property = "revision",
+            .value    = stringify(2),
+        },
+        { /* end of list */ }
+    },
+    .hw_version = "0.14",
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+#define PC_COMPAT_0_13 \
+        PC_COMPAT_0_14,\
+        {\
+            .driver   = TYPE_PCI_DEVICE,\
+            .property = "command_serr_enable",\
+            .value    = "off",\
+        },{\
+            .driver   = "AC97",\
+            .property = "use_broken_id",\
+            .value    = stringify(1),\
+        }
+
+static QEMUMachine pc_machine_v0_13 = {
+    .name = "pc-0.13",
+    .desc = "Standard PC",
+    .init = pc_init_pci_no_kvmclock,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_0_13,
+        {
+            .driver   = "virtio-9p-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
+            .driver   = "VGA",
+            .property = "rombar",
+            .value    = stringify(0),
+        },{
+            .driver   = "vmware-svga",
+            .property = "rombar",
+            .value    = stringify(0),
+        },
+        { /* end of list */ }
+    },
+    .hw_version = "0.13",
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+#define PC_COMPAT_0_12 \
+        PC_COMPAT_0_13,\
+        {\
+            .driver   = "virtio-serial-pci",\
+            .property = "max_ports",\
+            .value    = stringify(1),\
+        },{\
+            .driver   = "virtio-serial-pci",\
+            .property = "vectors",\
+            .value    = stringify(0),\
+        }
+
+static QEMUMachine pc_machine_v0_12 = {
+    .name = "pc-0.12",
+    .desc = "Standard PC",
+    .init = pc_init_pci_no_kvmclock,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_0_12,
+        {
+            .driver   = "VGA",
+            .property = "rombar",
+            .value    = stringify(0),
+        },{
+            .driver   = "vmware-svga",
+            .property = "rombar",
+            .value    = stringify(0),
+        },
+        { /* end of list */ }
+    },
+    .hw_version = "0.12",
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+#define PC_COMPAT_0_11 \
+        PC_COMPAT_0_12,\
+        {\
+            .driver   = "virtio-blk-pci",\
+            .property = "vectors",\
+            .value    = stringify(0),\
+        },{\
+            .driver   = TYPE_PCI_DEVICE,\
+            .property = "rombar",\
+            .value    = stringify(0),\
+        }
+
+static QEMUMachine pc_machine_v0_11 = {
+    .name = "pc-0.11",
+    .desc = "Standard PC, qemu 0.11",
+    .init = pc_init_pci_no_kvmclock,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_0_11,
+        {
+            .driver   = "ide-drive",
+            .property = "ver",
+            .value    = "0.11",
+        },{
+            .driver   = "scsi-disk",
+            .property = "ver",
+            .value    = "0.11",
+        },
+        { /* end of list */ }
+    },
+    .hw_version = "0.11",
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine pc_machine_v0_10 = {
+    .name = "pc-0.10",
+    .desc = "Standard PC, qemu 0.10",
+    .init = pc_init_pci_no_kvmclock,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_0_11,
+        {
+            .driver   = "virtio-blk-pci",
+            .property = "class",
+            .value    = stringify(PCI_CLASS_STORAGE_OTHER),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "class",
+            .value    = stringify(PCI_CLASS_DISPLAY_OTHER),
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
+            .driver   = "ide-drive",
+            .property = "ver",
+            .value    = "0.10",
+        },{
+            .driver   = "scsi-disk",
+            .property = "ver",
+            .value    = "0.10",
+        },
+        { /* end of list */ }
+    },
+    .hw_version = "0.10",
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine isapc_machine = {
+    .name = "isapc",
+    .desc = "ISA-only PC",
+    .init = pc_init_isa,
+    .max_cpus = 1,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "pc-sysfw",
+            .property = "rom_only",
+            .value    = stringify(1),
+        },
+        { /* end of list */ }
+    },
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+#ifdef CONFIG_XEN
+static QEMUMachine xenfv_machine = {
+    .name = "xenfv",
+    .desc = "Xen Fully-virtualized PC",
+    .init = pc_xen_hvm_init,
+    .max_cpus = HVM_MAX_VCPUS,
+    .default_machine_opts = "accel=xen",
+    DEFAULT_MACHINE_OPTIONS,
+};
+#endif
+
+static void pc_machine_init(void)
+{
+    qemu_register_machine(&pc_i440fx_machine_v1_5);
+    qemu_register_machine(&pc_i440fx_machine_v1_4);
+    qemu_register_machine(&pc_machine_v1_3);
+    qemu_register_machine(&pc_machine_v1_2);
+    qemu_register_machine(&pc_machine_v1_1);
+    qemu_register_machine(&pc_machine_v1_0);
+    qemu_register_machine(&pc_machine_v0_15);
+    qemu_register_machine(&pc_machine_v0_14);
+    qemu_register_machine(&pc_machine_v0_13);
+    qemu_register_machine(&pc_machine_v0_12);
+    qemu_register_machine(&pc_machine_v0_11);
+    qemu_register_machine(&pc_machine_v0_10);
+    qemu_register_machine(&isapc_machine);
+#ifdef CONFIG_XEN
+    qemu_register_machine(&xenfv_machine);
+#endif
+}
+
+machine_init(pc_machine_init);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
new file mode 100644 (file)
index 0000000..4f5f347
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Q35 chipset based pc system emulator
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2009, 2010
+ *               Isaku Yamahata <yamahata at valinux co jp>
+ *               VA Linux Systems Japan K.K.
+ * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
+ *
+ * This is based on pc.c, but heavily modified.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "sysemu/arch_init.h"
+#include "hw/smbus.h"
+#include "hw/boards.h"
+#include "hw/mc146818rtc.h"
+#include "hw/xen.h"
+#include "sysemu/kvm.h"
+#include "hw/kvm/clock.h"
+#include "hw/q35.h"
+#include "exec/address-spaces.h"
+#include "hw/ich9.h"
+#include "hw/ide/pci.h"
+#include "hw/ide/ahci.h"
+#include "hw/usb.h"
+
+/* ICH9 AHCI has 6 ports */
+#define MAX_SATA_PORTS     6
+
+/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
+ *    BIOS will read it and start S3 resume at POST Entry */
+static void pc_cmos_set_s3_resume(void *opaque, int irq, int level)
+{
+    ISADevice *s = opaque;
+
+    if (level) {
+        rtc_set_memory(s, 0xF, 0xFE);
+    }
+}
+
+/* PC hardware initialisation */
+static void pc_q35_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    ram_addr_t below_4g_mem_size, above_4g_mem_size;
+    Q35PCIHost *q35_host;
+    PCIBus *host_bus;
+    PCIDevice *lpc;
+    BusState *idebus[MAX_SATA_PORTS];
+    ISADevice *rtc_state;
+    ISADevice *floppy;
+    MemoryRegion *pci_memory;
+    MemoryRegion *rom_memory;
+    MemoryRegion *ram_memory;
+    GSIState *gsi_state;
+    ISABus *isa_bus;
+    int pci_enabled = 1;
+    qemu_irq *cpu_irq;
+    qemu_irq *gsi;
+    qemu_irq *i8259;
+    int i;
+    ICH9LPCState *ich9_lpc;
+    PCIDevice *ahci;
+    qemu_irq *cmos_s3;
+
+    pc_cpus_init(cpu_model);
+    pc_acpi_init("q35-acpi-dsdt.aml");
+
+    kvmclock_create();
+
+    if (ram_size >= 0xb0000000) {
+        above_4g_mem_size = ram_size - 0xb0000000;
+        below_4g_mem_size = 0xb0000000;
+    } else {
+        above_4g_mem_size = 0;
+        below_4g_mem_size = ram_size;
+    }
+
+    /* pci enabled */
+    if (pci_enabled) {
+        pci_memory = g_new(MemoryRegion, 1);
+        memory_region_init(pci_memory, "pci", INT64_MAX);
+        rom_memory = pci_memory;
+    } else {
+        pci_memory = NULL;
+        rom_memory = get_system_memory();
+    }
+
+    /* allocate ram and load rom/bios */
+    if (!xen_enabled()) {
+        pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline,
+                       initrd_filename, below_4g_mem_size, above_4g_mem_size,
+                       rom_memory, &ram_memory);
+    }
+
+    /* irq lines */
+    gsi_state = g_malloc0(sizeof(*gsi_state));
+    if (kvm_irqchip_in_kernel()) {
+        kvm_pc_setup_irq_routing(pci_enabled);
+        gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
+                                 GSI_NUM_PINS);
+    } else {
+        gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+    }
+
+    /* create pci host bus */
+    q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE));
+
+    q35_host->mch.ram_memory = ram_memory;
+    q35_host->mch.pci_address_space = pci_memory;
+    q35_host->mch.system_memory = get_system_memory();
+    q35_host->mch.address_space_io = get_system_io();;
+    q35_host->mch.below_4g_mem_size = below_4g_mem_size;
+    q35_host->mch.above_4g_mem_size = above_4g_mem_size;
+    /* pci */
+    qdev_init_nofail(DEVICE(q35_host));
+    host_bus = q35_host->host.pci.bus;
+    /* create ISA bus */
+    lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,
+                                          ICH9_LPC_FUNC), true,
+                                          TYPE_ICH9_LPC_DEVICE);
+    ich9_lpc = ICH9_LPC_DEVICE(lpc);
+    ich9_lpc->pic = gsi;
+    ich9_lpc->ioapic = gsi_state->ioapic_irq;
+    pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc,
+                 ICH9_LPC_NB_PIRQS);
+    pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq);
+    isa_bus = ich9_lpc->isa_bus;
+
+    /*end early*/
+    isa_bus_irqs(isa_bus, gsi);
+
+    if (kvm_irqchip_in_kernel()) {
+        i8259 = kvm_i8259_init(isa_bus);
+    } else if (xen_enabled()) {
+        i8259 = xen_interrupt_controller_init();
+    } else {
+        cpu_irq = pc_allocate_cpu_irq();
+        i8259 = i8259_init(isa_bus, cpu_irq[0]);
+    }
+
+    for (i = 0; i < ISA_NUM_IRQS; i++) {
+        gsi_state->i8259_irq[i] = i8259[i];
+    }
+    if (pci_enabled) {
+        ioapic_init_gsi(gsi_state, NULL);
+    }
+
+    pc_register_ferr_irq(gsi[13]);
+
+    /* init basic PC hardware */
+    pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false);
+
+    /* connect pm stuff to lpc */
+    cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
+    ich9_lpc_pm_init(lpc, *cmos_s3);
+
+    /* ahci and SATA device, for q35 1 ahci controller is built-in */
+    ahci = pci_create_simple_multifunction(host_bus,
+                                           PCI_DEVFN(ICH9_SATA1_DEV,
+                                                     ICH9_SATA1_FUNC),
+                                           true, "ich9-ahci");
+    idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
+    idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
+
+    if (usb_enabled(false)) {
+        /* Should we create 6 UHCI according to ich9 spec? */
+        ehci_create_ich9_with_companions(host_bus, 0x1d);
+    }
+
+    /* TODO: Populate SPD eeprom data.  */
+    smbus_eeprom_init(ich9_smb_init(host_bus,
+                                    PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
+                                    0xb100),
+                      8, NULL, 0);
+
+    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
+                 floppy, idebus[0], idebus[1], rtc_state);
+
+    /* the rest devices to which pci devfn is automatically assigned */
+    pc_vga_init(isa_bus, host_bus);
+    audio_init(isa_bus, host_bus);
+    pc_nic_init(isa_bus, host_bus);
+    if (pci_enabled) {
+        pc_pci_device_init(host_bus);
+    }
+}
+
+static QEMUMachine pc_q35_machine_v1_5 = {
+    .name = "pc-q35-1.5",
+    .alias = "q35",
+    .desc = "Standard PC (Q35 + ICH9, 2009)",
+    .init = pc_q35_init,
+    .max_cpus = 255,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine pc_q35_machine_v1_4 = {
+    .name = "pc-q35-1.4",
+    .desc = "Standard PC (Q35 + ICH9, 2009)",
+    .init = pc_q35_init,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_1_4,
+        { /* end of list */ }
+    },
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void pc_q35_machine_init(void)
+{
+    qemu_register_machine(&pc_q35_machine_v1_5);
+    qemu_register_machine(&pc_q35_machine_v1_4);
+}
+
+machine_init(pc_q35_machine_init);
diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
new file mode 100644 (file)
index 0000000..672ee9b
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * SMBIOS Support
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Authors:
+ *  Alex Williamson <alex.williamson@hp.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "sysemu/sysemu.h"
+#include "hw/smbios.h"
+#include "hw/loader.h"
+
+/*
+ * Structures shared with the BIOS
+ */
+struct smbios_header {
+    uint16_t length;
+    uint8_t type;
+} QEMU_PACKED;
+
+struct smbios_field {
+    struct smbios_header header;
+    uint8_t type;
+    uint16_t offset;
+    uint8_t data[];
+} QEMU_PACKED;
+
+struct smbios_table {
+    struct smbios_header header;
+    uint8_t data[];
+} QEMU_PACKED;
+
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+
+static uint8_t *smbios_entries;
+static size_t smbios_entries_len;
+static int smbios_type4_count = 0;
+
+static void smbios_validate_table(void)
+{
+    if (smbios_type4_count && smbios_type4_count != smp_cpus) {
+         fprintf(stderr,
+                 "Number of SMBIOS Type 4 tables must match cpu count.\n");
+        exit(1);
+    }
+}
+
+uint8_t *smbios_get_table(size_t *length)
+{
+    smbios_validate_table();
+    *length = smbios_entries_len;
+    return smbios_entries;
+}
+
+/*
+ * To avoid unresolvable overlaps in data, don't allow both
+ * tables and fields for the same smbios type.
+ */
+static void smbios_check_collision(int type, int entry)
+{
+    uint16_t *num_entries = (uint16_t *)smbios_entries;
+    struct smbios_header *header;
+    char *p;
+    int i;
+
+    if (!num_entries)
+        return;
+
+    p = (char *)(num_entries + 1);
+
+    for (i = 0; i < *num_entries; i++) {
+        header = (struct smbios_header *)p;
+        if (entry == SMBIOS_TABLE_ENTRY && header->type == SMBIOS_FIELD_ENTRY) {
+            struct smbios_field *field = (void *)header;
+            if (type == field->type) {
+                fprintf(stderr, "SMBIOS type %d field already defined, "
+                                "cannot add table\n", type);
+                exit(1);
+            }
+        } else if (entry == SMBIOS_FIELD_ENTRY &&
+                   header->type == SMBIOS_TABLE_ENTRY) {
+            struct smbios_structure_header *table = (void *)(header + 1);
+            if (type == table->type) {
+                fprintf(stderr, "SMBIOS type %d table already defined, "
+                                "cannot add field\n", type);
+                exit(1);
+            }
+        }
+        p += le16_to_cpu(header->length);
+    }
+}
+
+void smbios_add_field(int type, int offset, int len, void *data)
+{
+    struct smbios_field *field;
+
+    smbios_check_collision(type, SMBIOS_FIELD_ENTRY);
+
+    if (!smbios_entries) {
+        smbios_entries_len = sizeof(uint16_t);
+        smbios_entries = g_malloc0(smbios_entries_len);
+    }
+    smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
+                                                  sizeof(*field) + len);
+    field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
+    field->header.type = SMBIOS_FIELD_ENTRY;
+    field->header.length = cpu_to_le16(sizeof(*field) + len);
+
+    field->type = type;
+    field->offset = cpu_to_le16(offset);
+    memcpy(field->data, data, len);
+
+    smbios_entries_len += sizeof(*field) + len;
+    (*(uint16_t *)smbios_entries) =
+            cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+}
+
+static void smbios_build_type_0_fields(const char *t)
+{
+    char buf[1024];
+
+    if (get_param_value(buf, sizeof(buf), "vendor", t))
+        smbios_add_field(0, offsetof(struct smbios_type_0, vendor_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "version", t))
+        smbios_add_field(0, offsetof(struct smbios_type_0, bios_version_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "date", t))
+        smbios_add_field(0, offsetof(struct smbios_type_0,
+                                     bios_release_date_str),
+                                     strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "release", t)) {
+        int major, minor;
+        sscanf(buf, "%d.%d", &major, &minor);
+        smbios_add_field(0, offsetof(struct smbios_type_0,
+                                     system_bios_major_release), 1, &major);
+        smbios_add_field(0, offsetof(struct smbios_type_0,
+                                     system_bios_minor_release), 1, &minor);
+    }
+}
+
+static void smbios_build_type_1_fields(const char *t)
+{
+    char buf[1024];
+
+    if (get_param_value(buf, sizeof(buf), "manufacturer", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, manufacturer_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "product", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, product_name_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "version", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, version_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "serial", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, serial_number_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "uuid", t)) {
+        if (qemu_uuid_parse(buf, qemu_uuid) != 0) {
+            fprintf(stderr, "Invalid SMBIOS UUID string\n");
+            exit(1);
+        }
+    }
+    if (get_param_value(buf, sizeof(buf), "sku", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "family", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, family_str),
+                         strlen(buf) + 1, buf);
+}
+
+int smbios_entry_add(const char *t)
+{
+    char buf[1024];
+
+    if (get_param_value(buf, sizeof(buf), "file", t)) {
+        struct smbios_structure_header *header;
+        struct smbios_table *table;
+        int size = get_image_size(buf);
+
+        if (size == -1 || size < sizeof(struct smbios_structure_header)) {
+            fprintf(stderr, "Cannot read smbios file %s\n", buf);
+            exit(1);
+        }
+
+        if (!smbios_entries) {
+            smbios_entries_len = sizeof(uint16_t);
+            smbios_entries = g_malloc0(smbios_entries_len);
+        }
+
+        smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
+                                                      sizeof(*table) + size);
+        table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
+        table->header.type = SMBIOS_TABLE_ENTRY;
+        table->header.length = cpu_to_le16(sizeof(*table) + size);
+
+        if (load_image(buf, table->data) != size) {
+            fprintf(stderr, "Failed to load smbios file %s", buf);
+            exit(1);
+        }
+
+        header = (struct smbios_structure_header *)(table->data);
+        smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY);
+        if (header->type == 4) {
+            smbios_type4_count++;
+        }
+
+        smbios_entries_len += sizeof(*table) + size;
+        (*(uint16_t *)smbios_entries) =
+                cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+        return 0;
+    }
+
+    if (get_param_value(buf, sizeof(buf), "type", t)) {
+        unsigned long type = strtoul(buf, NULL, 0);
+        switch (type) {
+        case 0:
+            smbios_build_type_0_fields(t);
+            return 0;
+        case 1:
+            smbios_build_type_1_fields(t);
+            return 0;
+        default:
+            fprintf(stderr, "Don't know how to build fields for SMBIOS type "
+                    "%ld\n", type);
+            exit(1);
+        }
+    }
+
+    fprintf(stderr, "smbios: must specify type= or file=\n");
+    return -1;
+}
diff --git a/hw/i386/xen_domainbuild.c b/hw/i386/xen_domainbuild.c
new file mode 100644 (file)
index 0000000..d477061
--- /dev/null
@@ -0,0 +1,299 @@
+#include <signal.h>
+#include "hw/xen_backend.h"
+#include "hw/xen_domainbuild.h"
+#include "qemu/timer.h"
+#include "qemu/log.h"
+
+#include <xenguest.h>
+
+static int xenstore_domain_mkdir(char *path)
+{
+    struct xs_permissions perms_ro[] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .id    = xen_domid,
+            .perms = XS_PERM_READ,
+        }};
+    struct xs_permissions perms_rw[] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .id    = xen_domid,
+            .perms = XS_PERM_READ | XS_PERM_WRITE,
+        }};
+    const char *writable[] = { "device", "control", "error", NULL };
+    char subpath[256];
+    int i;
+
+    if (!xs_mkdir(xenstore, 0, path)) {
+        fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path);
+       return -1;
+    }
+    if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
+        fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+       return -1;
+    }
+
+    for (i = 0; writable[i]; i++) {
+        snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
+        if (!xs_mkdir(xenstore, 0, subpath)) {
+            fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, subpath);
+            return -1;
+        }
+        if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
+            fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+                          const char *cmdline)
+{
+    char *dom, uuid_string[42], vm[256], path[256];
+    int i;
+
+    snprintf(uuid_string, sizeof(uuid_string), UUID_FMT,
+             qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3],
+             qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
+             qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11],
+             qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]);
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    snprintf(vm,  sizeof(vm),  "/vm/%s", uuid_string);
+
+    xenstore_domain_mkdir(dom);
+
+    xenstore_write_str(vm, "image/ostype",  "linux");
+    if (kernel)
+        xenstore_write_str(vm, "image/kernel",  kernel);
+    if (ramdisk)
+        xenstore_write_str(vm, "image/ramdisk", ramdisk);
+    if (cmdline)
+        xenstore_write_str(vm, "image/cmdline", cmdline);
+
+    /* name + id */
+    xenstore_write_str(vm,  "name",   qemu_name ? qemu_name : "no-name");
+    xenstore_write_str(vm,  "uuid",   uuid_string);
+    xenstore_write_str(dom, "name",   qemu_name ? qemu_name : "no-name");
+    xenstore_write_int(dom, "domid",  xen_domid);
+    xenstore_write_str(dom, "vm",     vm);
+
+    /* memory */
+    xenstore_write_int(dom, "memory/target", ram_size >> 10);  // kB
+    xenstore_write_int(vm, "memory",         ram_size >> 20);  // MB
+    xenstore_write_int(vm, "maxmem",         ram_size >> 20);  // MB
+
+    /* cpus */
+    for (i = 0; i < smp_cpus; i++) {
+       snprintf(path, sizeof(path), "cpu/%d/availability",i);
+       xenstore_write_str(dom, path, "online");
+    }
+    xenstore_write_int(vm, "vcpu_avail",  smp_cpus);
+    xenstore_write_int(vm, "vcpus",       smp_cpus);
+
+    /* vnc password */
+    xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
+
+    free(dom);
+    return 0;
+}
+
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+                          int console_port, int console_mfn)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+
+    /* signal new domain */
+    xs_introduce_domain(xenstore,
+                        xen_domid,
+                        xenstore_mfn,
+                        xenstore_port);
+
+    /* xenstore */
+    xenstore_write_int(dom, "store/ring-ref",   xenstore_mfn);
+    xenstore_write_int(dom, "store/port",       xenstore_port);
+
+    /* console */
+    xenstore_write_str(dom, "console/type",     "ioemu");
+    xenstore_write_int(dom, "console/limit",    128 * 1024);
+    xenstore_write_int(dom, "console/ring-ref", console_mfn);
+    xenstore_write_int(dom, "console/port",     console_port);
+    xen_config_dev_console(0);
+
+    free(dom);
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static QEMUTimer *xen_poll;
+
+/* check domain state once per second */
+static void xen_domain_poll(void *opaque)
+{
+    struct xc_dominfo info;
+    int rc;
+
+    rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
+    if ((rc != 1) || (info.domid != xen_domid)) {
+        qemu_log("xen: domain %d is gone\n", xen_domid);
+        goto quit;
+    }
+    if (info.dying) {
+        qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid,
+                 info.crashed  ? "crashed"  : "",
+                 info.shutdown ? "shutdown" : "");
+        goto quit;
+    }
+
+    qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000);
+    return;
+
+quit:
+    qemu_system_shutdown_request();
+}
+
+static int xen_domain_watcher(void)
+{
+    int qemu_running = 1;
+    int fd[2], i, n, rc;
+    char byte;
+
+    if (pipe(fd) != 0) {
+        qemu_log("%s: Huh? pipe error: %s\n", __FUNCTION__, strerror(errno));
+        return -1;
+    }
+    if (fork() != 0)
+        return 0; /* not child */
+
+    /* close all file handles, except stdio/out/err,
+     * our watch pipe and the xen interface handle */
+    n = getdtablesize();
+    for (i = 3; i < n; i++) {
+        if (i == fd[0])
+            continue;
+        if (i == xc_fd(xen_xc)) {
+            continue;
+        }
+        close(i);
+    }
+
+    /* ignore term signals */
+    signal(SIGINT,  SIG_IGN);
+    signal(SIGTERM, SIG_IGN);
+
+    /* wait for qemu exiting */
+    while (qemu_running) {
+        rc = read(fd[0], &byte, 1);
+        switch (rc) {
+        case -1:
+            if (errno == EINTR)
+                continue;
+            qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno));
+            qemu_running = 0;
+            break;
+        case 0:
+            /* EOF -> qemu exited */
+            qemu_running = 0;
+            break;
+        default:
+            qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__);
+            break;
+        }
+    }
+
+    /* cleanup */
+    qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid);
+    xc_domain_destroy(xen_xc, xen_domid);
+    _exit(0);
+}
+
+/* normal cleanup */
+static void xen_domain_cleanup(void)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    if (dom) {
+        xs_rm(xenstore, 0, dom);
+        free(dom);
+    }
+    xs_release_domain(xenstore, xen_domid);
+}
+
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+                        const char *cmdline)
+{
+    uint32_t ssidref = 0;
+    uint32_t flags = 0;
+    xen_domain_handle_t uuid;
+    unsigned int xenstore_port = 0, console_port = 0;
+    unsigned long xenstore_mfn = 0, console_mfn = 0;
+    int rc;
+
+    memcpy(uuid, qemu_uuid, sizeof(uuid));
+    rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_create() failed\n");
+        goto err;
+    }
+    qemu_log("xen: created domain %d\n", xen_domid);
+    atexit(xen_domain_cleanup);
+    if (xen_domain_watcher() == -1) {
+        goto err;
+    }
+
+    xenstore_domain_init1(kernel, ramdisk, cmdline);
+
+    rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
+        goto err;
+    }
+
+#if 0
+    rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
+        goto err;
+    }
+#endif
+
+    rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
+        goto err;
+    }
+
+    xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+    console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+
+    rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20,
+                        kernel, ramdisk, cmdline,
+                        0, flags,
+                        xenstore_port, &xenstore_mfn,
+                        console_port, &console_mfn);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_linux_build() failed\n");
+        goto err;
+    }
+
+    xenstore_domain_init2(xenstore_port, xenstore_mfn,
+                          console_port, console_mfn);
+
+    qemu_log("xen: unpausing domain %d\n", xen_domid);
+    rc = xc_domain_unpause(xen_xc, xen_domid);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_unpause() failed\n");
+        goto err;
+    }
+
+    xen_poll = qemu_new_timer_ms(rt_clock, xen_domain_poll, NULL);
+    qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000);
+    return 0;
+
+err:
+    return -1;
+}
diff --git a/hw/i386/xen_machine_pv.c b/hw/i386/xen_machine_pv.c
new file mode 100644 (file)
index 0000000..a8177b6
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * QEMU Xen PV Machine
+ *
+ * Copyright (c) 2007 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/boards.h"
+#include "hw/xen_backend.h"
+#include "hw/xen_domainbuild.h"
+#include "sysemu/blockdev.h"
+
+static void xen_init_pv(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    X86CPU *cpu;
+    CPUX86State *env;
+    DriveInfo *dinfo;
+    int i;
+
+    /* Initialize a dummy CPU */
+    if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+    }
+    cpu = cpu_x86_init(cpu_model);
+    env = &cpu->env;
+    env->halted = 1;
+
+    /* Initialize backend core & drivers */
+    if (xen_be_init() != 0) {
+        fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
+        exit(1);
+    }
+
+    switch (xen_mode) {
+    case XEN_ATTACH:
+        /* nothing to do, xend handles everything */
+        break;
+    case XEN_CREATE:
+        if (xen_domain_build_pv(kernel_filename, initrd_filename,
+                                kernel_cmdline) < 0) {
+            fprintf(stderr, "xen pv domain creation failed\n");
+            exit(1);
+        }
+        break;
+    case XEN_EMULATE:
+        fprintf(stderr, "xen emulation not implemented (yet)\n");
+        exit(1);
+        break;
+    }
+
+    xen_be_register("console", &xen_console_ops);
+    xen_be_register("vkbd", &xen_kbdmouse_ops);
+    xen_be_register("vfb", &xen_framebuffer_ops);
+    xen_be_register("qdisk", &xen_blkdev_ops);
+    xen_be_register("qnic", &xen_netdev_ops);
+
+    /* configure framebuffer */
+    if (xenfb_enabled) {
+        xen_config_dev_vfb(0, "vnc");
+        xen_config_dev_vkbd(0);
+    }
+
+    /* configure disks */
+    for (i = 0; i < 16; i++) {
+        dinfo = drive_get(IF_XEN, 0, i);
+        if (!dinfo)
+            continue;
+        xen_config_dev_blk(dinfo);
+    }
+
+    /* configure nics */
+    for (i = 0; i < nb_nics; i++) {
+        if (!nd_table[i].model || 0 != strcmp(nd_table[i].model, "xen"))
+            continue;
+        xen_config_dev_nic(nd_table + i);
+    }
+
+    /* config cleanup hook */
+    atexit(xen_config_cleanup);
+
+    /* setup framebuffer */
+    xen_init_display(xen_domid);
+}
+
+static QEMUMachine xenpv_machine = {
+    .name = "xenpv",
+    .desc = "Xen Para-virtualized PC",
+    .init = xen_init_pv,
+    .max_cpus = 1,
+    .default_machine_opts = "accel=xen",
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void xenpv_machine_init(void)
+{
+    qemu_register_machine(&xenpv_machine);
+}
+
+machine_init(xenpv_machine_init);
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
deleted file mode 100644 (file)
index e0ba327..0000000
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * ARM Integrator CP System emulation.
- *
- * Copyright (c) 2005-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL
- */
-
-#include "hw/sysbus.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/arm-misc.h"
-#include "net/net.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t memsz;
-    MemoryRegion flash;
-    uint32_t cm_osc;
-    uint32_t cm_ctrl;
-    uint32_t cm_lock;
-    uint32_t cm_auxosc;
-    uint32_t cm_sdram;
-    uint32_t cm_init;
-    uint32_t cm_flags;
-    uint32_t cm_nvflags;
-    uint32_t int_level;
-    uint32_t irq_enabled;
-    uint32_t fiq_enabled;
-} integratorcm_state;
-
-static uint8_t integrator_spd[128] = {
-   128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
-   0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
-};
-
-static uint64_t integratorcm_read(void *opaque, hwaddr offset,
-                                  unsigned size)
-{
-    integratorcm_state *s = (integratorcm_state *)opaque;
-    if (offset >= 0x100 && offset < 0x200) {
-        /* CM_SPD */
-        if (offset >= 0x180)
-            return 0;
-        return integrator_spd[offset >> 2];
-    }
-    switch (offset >> 2) {
-    case 0: /* CM_ID */
-        return 0x411a3001;
-    case 1: /* CM_PROC */
-        return 0;
-    case 2: /* CM_OSC */
-        return s->cm_osc;
-    case 3: /* CM_CTRL */
-        return s->cm_ctrl;
-    case 4: /* CM_STAT */
-        return 0x00100000;
-    case 5: /* CM_LOCK */
-        if (s->cm_lock == 0xa05f) {
-            return 0x1a05f;
-        } else {
-            return s->cm_lock;
-        }
-    case 6: /* CM_LMBUSCNT */
-        /* ??? High frequency timer.  */
-        hw_error("integratorcm_read: CM_LMBUSCNT");
-    case 7: /* CM_AUXOSC */
-        return s->cm_auxosc;
-    case 8: /* CM_SDRAM */
-        return s->cm_sdram;
-    case 9: /* CM_INIT */
-        return s->cm_init;
-    case 10: /* CM_REFCT */
-        /* ??? High frequency timer.  */
-        hw_error("integratorcm_read: CM_REFCT");
-    case 12: /* CM_FLAGS */
-        return s->cm_flags;
-    case 14: /* CM_NVFLAGS */
-        return s->cm_nvflags;
-    case 16: /* CM_IRQ_STAT */
-        return s->int_level & s->irq_enabled;
-    case 17: /* CM_IRQ_RSTAT */
-        return s->int_level;
-    case 18: /* CM_IRQ_ENSET */
-        return s->irq_enabled;
-    case 20: /* CM_SOFT_INTSET */
-        return s->int_level & 1;
-    case 24: /* CM_FIQ_STAT */
-        return s->int_level & s->fiq_enabled;
-    case 25: /* CM_FIQ_RSTAT */
-        return s->int_level;
-    case 26: /* CM_FIQ_ENSET */
-        return s->fiq_enabled;
-    case 32: /* CM_VOLTAGE_CTL0 */
-    case 33: /* CM_VOLTAGE_CTL1 */
-    case 34: /* CM_VOLTAGE_CTL2 */
-    case 35: /* CM_VOLTAGE_CTL3 */
-        /* ??? Voltage control unimplemented.  */
-        return 0;
-    default:
-        hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
-                 (int)offset);
-        return 0;
-    }
-}
-
-static void integratorcm_do_remap(integratorcm_state *s)
-{
-    /* Sync memory region state with CM_CTRL REMAP bit:
-     * bit 0 => flash at address 0; bit 1 => RAM
-     */
-    memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
-}
-
-static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value)
-{
-    if (value & 8) {
-        qemu_system_reset_request();
-    }
-    if ((s->cm_ctrl ^ value) & 1) {
-        /* (value & 1) != 0 means the green "MISC LED" is lit.
-         * We don't have any nice place to display LEDs. printf is a bad
-         * idea because Linux uses the LED as a heartbeat and the output
-         * will swamp anything else on the terminal.
-         */
-    }
-    /* Note that the RESET bit [3] always reads as zero */
-    s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
-    integratorcm_do_remap(s);
-}
-
-static void integratorcm_update(integratorcm_state *s)
-{
-    /* ??? The CPU irq/fiq is raised when either the core module or base PIC
-       are active.  */
-    if (s->int_level & (s->irq_enabled | s->fiq_enabled))
-        hw_error("Core module interrupt\n");
-}
-
-static void integratorcm_write(void *opaque, hwaddr offset,
-                               uint64_t value, unsigned size)
-{
-    integratorcm_state *s = (integratorcm_state *)opaque;
-    switch (offset >> 2) {
-    case 2: /* CM_OSC */
-        if (s->cm_lock == 0xa05f)
-            s->cm_osc = value;
-        break;
-    case 3: /* CM_CTRL */
-        integratorcm_set_ctrl(s, value);
-        break;
-    case 5: /* CM_LOCK */
-        s->cm_lock = value & 0xffff;
-        break;
-    case 7: /* CM_AUXOSC */
-        if (s->cm_lock == 0xa05f)
-            s->cm_auxosc = value;
-        break;
-    case 8: /* CM_SDRAM */
-        s->cm_sdram = value;
-        break;
-    case 9: /* CM_INIT */
-        /* ??? This can change the memory bus frequency.  */
-        s->cm_init = value;
-        break;
-    case 12: /* CM_FLAGSS */
-        s->cm_flags |= value;
-        break;
-    case 13: /* CM_FLAGSC */
-        s->cm_flags &= ~value;
-        break;
-    case 14: /* CM_NVFLAGSS */
-        s->cm_nvflags |= value;
-        break;
-    case 15: /* CM_NVFLAGSS */
-        s->cm_nvflags &= ~value;
-        break;
-    case 18: /* CM_IRQ_ENSET */
-        s->irq_enabled |= value;
-        integratorcm_update(s);
-        break;
-    case 19: /* CM_IRQ_ENCLR */
-        s->irq_enabled &= ~value;
-        integratorcm_update(s);
-        break;
-    case 20: /* CM_SOFT_INTSET */
-        s->int_level |= (value & 1);
-        integratorcm_update(s);
-        break;
-    case 21: /* CM_SOFT_INTCLR */
-        s->int_level &= ~(value & 1);
-        integratorcm_update(s);
-        break;
-    case 26: /* CM_FIQ_ENSET */
-        s->fiq_enabled |= value;
-        integratorcm_update(s);
-        break;
-    case 27: /* CM_FIQ_ENCLR */
-        s->fiq_enabled &= ~value;
-        integratorcm_update(s);
-        break;
-    case 32: /* CM_VOLTAGE_CTL0 */
-    case 33: /* CM_VOLTAGE_CTL1 */
-    case 34: /* CM_VOLTAGE_CTL2 */
-    case 35: /* CM_VOLTAGE_CTL3 */
-        /* ??? Voltage control unimplemented.  */
-        break;
-    default:
-        hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
-                 (int)offset);
-        break;
-    }
-}
-
-/* Integrator/CM control registers.  */
-
-static const MemoryRegionOps integratorcm_ops = {
-    .read = integratorcm_read,
-    .write = integratorcm_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int integratorcm_init(SysBusDevice *dev)
-{
-    integratorcm_state *s = FROM_SYSBUS(integratorcm_state, dev);
-
-    s->cm_osc = 0x01000048;
-    /* ??? What should the high bits of this value be?  */
-    s->cm_auxosc = 0x0007feff;
-    s->cm_sdram = 0x00011122;
-    if (s->memsz >= 256) {
-        integrator_spd[31] = 64;
-        s->cm_sdram |= 0x10;
-    } else if (s->memsz >= 128) {
-        integrator_spd[31] = 32;
-        s->cm_sdram |= 0x0c;
-    } else if (s->memsz >= 64) {
-        integrator_spd[31] = 16;
-        s->cm_sdram |= 0x08;
-    } else if (s->memsz >= 32) {
-        integrator_spd[31] = 4;
-        s->cm_sdram |= 0x04;
-    } else {
-        integrator_spd[31] = 2;
-    }
-    memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
-    s->cm_init = 0x00000112;
-    memory_region_init_ram(&s->flash, "integrator.flash", 0x100000);
-    vmstate_register_ram_global(&s->flash);
-
-    memory_region_init_io(&s->iomem, &integratorcm_ops, s,
-                          "integratorcm", 0x00800000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    integratorcm_do_remap(s);
-    /* ??? Save/restore.  */
-    return 0;
-}
-
-/* Integrator/CP hardware emulation.  */
-/* Primary interrupt controller.  */
-
-typedef struct icp_pic_state
-{
-  SysBusDevice busdev;
-  MemoryRegion iomem;
-  uint32_t level;
-  uint32_t irq_enabled;
-  uint32_t fiq_enabled;
-  qemu_irq parent_irq;
-  qemu_irq parent_fiq;
-} icp_pic_state;
-
-static void icp_pic_update(icp_pic_state *s)
-{
-    uint32_t flags;
-
-    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);
-}
-
-static void icp_pic_set_irq(void *opaque, int irq, int level)
-{
-    icp_pic_state *s = (icp_pic_state *)opaque;
-    if (level)
-        s->level |= 1 << irq;
-    else
-        s->level &= ~(1 << irq);
-    icp_pic_update(s);
-}
-
-static uint64_t icp_pic_read(void *opaque, hwaddr offset,
-                             unsigned size)
-{
-    icp_pic_state *s = (icp_pic_state *)opaque;
-
-    switch (offset >> 2) {
-    case 0: /* IRQ_STATUS */
-        return s->level & s->irq_enabled;
-    case 1: /* IRQ_RAWSTAT */
-        return s->level;
-    case 2: /* IRQ_ENABLESET */
-        return s->irq_enabled;
-    case 4: /* INT_SOFTSET */
-        return s->level & 1;
-    case 8: /* FRQ_STATUS */
-        return s->level & s->fiq_enabled;
-    case 9: /* FRQ_RAWSTAT */
-        return s->level;
-    case 10: /* FRQ_ENABLESET */
-        return s->fiq_enabled;
-    case 3: /* IRQ_ENABLECLR */
-    case 5: /* INT_SOFTCLR */
-    case 11: /* FRQ_ENABLECLR */
-    default:
-        printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void icp_pic_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
-{
-    icp_pic_state *s = (icp_pic_state *)opaque;
-
-    switch (offset >> 2) {
-    case 2: /* IRQ_ENABLESET */
-        s->irq_enabled |= value;
-        break;
-    case 3: /* IRQ_ENABLECLR */
-        s->irq_enabled &= ~value;
-        break;
-    case 4: /* INT_SOFTSET */
-        if (value & 1)
-            icp_pic_set_irq(s, 0, 1);
-        break;
-    case 5: /* INT_SOFTCLR */
-        if (value & 1)
-            icp_pic_set_irq(s, 0, 0);
-        break;
-    case 10: /* FRQ_ENABLESET */
-        s->fiq_enabled |= value;
-        break;
-    case 11: /* FRQ_ENABLECLR */
-        s->fiq_enabled &= ~value;
-        break;
-    case 0: /* IRQ_STATUS */
-    case 1: /* IRQ_RAWSTAT */
-    case 8: /* FRQ_STATUS */
-    case 9: /* FRQ_RAWSTAT */
-    default:
-        printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
-        return;
-    }
-    icp_pic_update(s);
-}
-
-static const MemoryRegionOps icp_pic_ops = {
-    .read = icp_pic_read,
-    .write = icp_pic_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int icp_pic_init(SysBusDevice *dev)
-{
-    icp_pic_state *s = FROM_SYSBUS(icp_pic_state, dev);
-
-    qdev_init_gpio_in(&dev->qdev, icp_pic_set_irq, 32);
-    sysbus_init_irq(dev, &s->parent_irq);
-    sysbus_init_irq(dev, &s->parent_fiq);
-    memory_region_init_io(&s->iomem, &icp_pic_ops, s, "icp-pic", 0x00800000);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-/* CP control registers.  */
-
-static uint64_t icp_control_read(void *opaque, hwaddr offset,
-                                 unsigned size)
-{
-    switch (offset >> 2) {
-    case 0: /* CP_IDFIELD */
-        return 0x41034003;
-    case 1: /* CP_FLASHPROG */
-        return 0;
-    case 2: /* CP_INTREG */
-        return 0;
-    case 3: /* CP_DECODE */
-        return 0x11;
-    default:
-        hw_error("icp_control_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void icp_control_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
-{
-    switch (offset >> 2) {
-    case 1: /* CP_FLASHPROG */
-    case 2: /* CP_INTREG */
-    case 3: /* CP_DECODE */
-        /* Nothing interesting implemented yet.  */
-        break;
-    default:
-        hw_error("icp_control_write: Bad offset %x\n", (int)offset);
-    }
-}
-
-static const MemoryRegionOps icp_control_ops = {
-    .read = icp_control_read,
-    .write = icp_control_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void icp_control_init(hwaddr base)
-{
-    MemoryRegion *io;
-
-    io = (MemoryRegion *)g_malloc0(sizeof(MemoryRegion));
-    memory_region_init_io(io, &icp_control_ops, NULL,
-                          "control", 0x00800000);
-    memory_region_add_subregion(get_system_memory(), base, io);
-    /* ??? Save/restore.  */
-}
-
-
-/* Board init.  */
-
-static struct arm_boot_info integrator_binfo = {
-    .loader_start = 0x0,
-    .board_id = 0x113,
-};
-
-static void integratorcp_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    ARMCPU *cpu;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
-    qemu_irq pic[32];
-    qemu_irq *cpu_pic;
-    DeviceState *dev;
-    int i;
-
-    if (!cpu_model) {
-        cpu_model = "arm926";
-    }
-    cpu = cpu_arm_init(cpu_model);
-    if (!cpu) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-
-    memory_region_init_ram(ram, "integrator.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
-    /* ??? RAM should repeat to fill physical memory space.  */
-    /* SDRAM at address zero*/
-    memory_region_add_subregion(address_space_mem, 0, ram);
-    /* And again at address 0x80000000 */
-    memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size);
-    memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
-
-    dev = qdev_create(NULL, "integrator_core");
-    qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
-
-    cpu_pic = arm_pic_init_cpu(cpu);
-    dev = sysbus_create_varargs("integrator_pic", 0x14000000,
-                                cpu_pic[ARM_PIC_CPU_IRQ],
-                                cpu_pic[ARM_PIC_CPU_FIQ], NULL);
-    for (i = 0; i < 32; i++) {
-        pic[i] = qdev_get_gpio_in(dev, i);
-    }
-    sysbus_create_simple("integrator_pic", 0xca000000, pic[26]);
-    sysbus_create_varargs("integrator_pit", 0x13000000,
-                          pic[5], pic[6], pic[7], NULL);
-    sysbus_create_simple("pl031", 0x15000000, pic[8]);
-    sysbus_create_simple("pl011", 0x16000000, pic[1]);
-    sysbus_create_simple("pl011", 0x17000000, pic[2]);
-    icp_control_init(0xcb000000);
-    sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
-    sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
-    sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
-    if (nd_table[0].used)
-        smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
-
-    sysbus_create_simple("pl110", 0xc0000000, pic[22]);
-
-    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(cpu, &integrator_binfo);
-}
-
-static QEMUMachine integratorcp_machine = {
-    .name = "integratorcp",
-    .desc = "ARM Integrator/CP (ARM926EJ-S)",
-    .init = integratorcp_init,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void integratorcp_machine_init(void)
-{
-    qemu_register_machine(&integratorcp_machine);
-}
-
-machine_init(integratorcp_machine_init);
-
-static Property core_properties[] = {
-    DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void core_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = integratorcm_init;
-    dc->props = core_properties;
-}
-
-static const TypeInfo core_info = {
-    .name          = "integrator_core",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(integratorcm_state),
-    .class_init    = core_class_init,
-};
-
-static void icp_pic_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = icp_pic_init;
-}
-
-static const TypeInfo icp_pic_info = {
-    .name          = "integrator_pic",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(icp_pic_state),
-    .class_init    = icp_pic_class_init,
-};
-
-static void integratorcp_register_types(void)
-{
-    type_register_static(&icp_pic_info);
-    type_register_static(&core_info);
-}
-
-type_init(integratorcp_register_types)
diff --git a/hw/kzm.c b/hw/kzm.c
deleted file mode 100644 (file)
index ec50a31..0000000
--- a/hw/kzm.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * KZM Board System emulation.
- *
- * Copyright (c) 2008 OKL and 2011 NICTA
- * Written by Hans at OK-Labs
- * Updated by Peter Chubb.
- *
- * This code is licensed under the GPL, version 2 or later.
- * See the file `COPYING' in the top level directory.
- *
- * It (partially) emulates a Kyoto Microcomputer
- * KZM-ARM11-01 evaluation board, with a Freescale
- * i.MX31 SoC
- */
-
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-#include "hw/hw.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/serial.h"
-#include "hw/imx.h"
-
-    /* Memory map for Kzm Emulation Baseboard:
-     * 0x00000000-0x00003fff 16k secure ROM       IGNORED
-     * 0x00004000-0x00407fff Reserved             IGNORED
-     * 0x00404000-0x00407fff ROM                  IGNORED
-     * 0x00408000-0x0fffffff Reserved             IGNORED
-     * 0x10000000-0x1fffbfff RAM aliasing         IGNORED
-     * 0x1fffc000-0x1fffffff RAM                  EMULATED
-     * 0x20000000-0x2fffffff Reserved             IGNORED
-     * 0x30000000-0x7fffffff I.MX31 Internal Register Space
-     *   0x43f00000 IO_AREA0
-     *   0x43f90000 UART1                         EMULATED
-     *   0x43f94000 UART2                         EMULATED
-     *   0x68000000 AVIC                          EMULATED
-     *   0x53f80000 CCM                           EMULATED
-     *   0x53f94000 PIT 1                         EMULATED
-     *   0x53f98000 PIT 2                         EMULATED
-     *   0x53f90000 GPT                           EMULATED
-     * 0x80000000-0x87ffffff RAM                  EMULATED
-     * 0x88000000-0x8fffffff RAM Aliasing         EMULATED
-     * 0xa0000000-0xafffffff NAND Flash           IGNORED
-     * 0xb0000000-0xb3ffffff Unavailable          IGNORED
-     * 0xb4000000-0xb4000fff 8-bit free space     IGNORED
-     * 0xb4001000-0xb400100f Board control        IGNORED
-     *  0xb4001003           DIP switch
-     * 0xb4001010-0xb400101f 7-segment LED        IGNORED
-     * 0xb4001020-0xb400102f LED                  IGNORED
-     * 0xb4001030-0xb400103f LED                  IGNORED
-     * 0xb4001040-0xb400104f FPGA, UART           EMULATED
-     * 0xb4001050-0xb400105f FPGA, UART           EMULATED
-     * 0xb4001060-0xb40fffff FPGA                 IGNORED
-     * 0xb6000000-0xb61fffff LAN controller       EMULATED
-     * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED
-     * 0xb6300000-0xb7ffffff Free                 IGNORED
-     * 0xb8000000-0xb8004fff Memory control registers IGNORED
-     * 0xc0000000-0xc3ffffff PCMCIA/CF            IGNORED
-     * 0xc4000000-0xffffffff Reserved             IGNORED
-     */
-
-#define KZM_RAMADDRESS (0x80000000)
-#define KZM_FPGA       (0xb4001040)
-
-static struct arm_boot_info kzm_binfo = {
-    .loader_start = KZM_RAMADDRESS,
-    .board_id = 1722,
-};
-
-static void kzm_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    ARMCPU *cpu;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *sram = g_new(MemoryRegion, 1);
-    MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
-    qemu_irq *cpu_pic;
-    DeviceState *dev;
-    DeviceState *ccm;
-
-    if (!cpu_model) {
-        cpu_model = "arm1136";
-    }
-
-    cpu = cpu_arm_init(cpu_model);
-    if (!cpu) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-
-    /* On a real system, the first 16k is a `secure boot rom' */
-
-    memory_region_init_ram(ram, "kzm.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram);
-
-    memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size);
-    memory_region_add_subregion(address_space_mem, 0x88000000, ram_alias);
-
-    memory_region_init_ram(sram, "kzm.sram", 0x4000);
-    memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram);
-
-    cpu_pic = arm_pic_init_cpu(cpu);
-    dev = sysbus_create_varargs("imx_avic", 0x68000000,
-                                cpu_pic[ARM_PIC_CPU_IRQ],
-                                cpu_pic[ARM_PIC_CPU_FIQ], NULL);
-
-
-    imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45));
-    imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32));
-
-    ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL);
-
-    imx_timerp_create(0x53f94000, qdev_get_gpio_in(dev, 28), ccm);
-    imx_timerp_create(0x53f98000, qdev_get_gpio_in(dev, 27), ccm);
-    imx_timerg_create(0x53f90000, qdev_get_gpio_in(dev, 29), ccm);
-
-    if (nd_table[0].used) {
-        lan9118_init(&nd_table[0], 0xb6000000, qdev_get_gpio_in(dev, 52));
-    }
-
-    if (serial_hds[2]) { /* touchscreen */
-        serial_mm_init(address_space_mem, KZM_FPGA+0x10, 0,
-                       qdev_get_gpio_in(dev, 52),
-                       14745600, serial_hds[2],
-                       DEVICE_NATIVE_ENDIAN);
-    }
-
-    kzm_binfo.ram_size = ram_size;
-    kzm_binfo.kernel_filename = kernel_filename;
-    kzm_binfo.kernel_cmdline = kernel_cmdline;
-    kzm_binfo.initrd_filename = initrd_filename;
-    kzm_binfo.nb_cpus = 1;
-    arm_load_kernel(cpu, &kzm_binfo);
-}
-
-static QEMUMachine kzm_machine = {
-    .name = "kzm",
-    .desc = "ARM KZM Emulation Baseboard (ARM1136)",
-    .init = kzm_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void kzm_machine_init(void)
-{
-    qemu_register_machine(&kzm_machine);
-}
-
-machine_init(kzm_machine_init)
diff --git a/hw/leon3.c b/hw/leon3.c
deleted file mode 100644 (file)
index f58061f..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * QEMU Leon3 System Emulator
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "char/char.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "trace.h"
-#include "exec/address-spaces.h"
-
-#include "hw/grlib.h"
-
-/* Default system clock.  */
-#define CPU_CLK (40 * 1000 * 1000)
-
-#define PROM_FILENAME        "u-boot.bin"
-
-#define MAX_PILS 16
-
-typedef struct ResetData {
-    SPARCCPU *cpu;
-    uint32_t  entry;            /* save kernel entry in case of reset */
-} ResetData;
-
-static void main_cpu_reset(void *opaque)
-{
-    ResetData *s   = (ResetData *)opaque;
-    CPUSPARCState  *env = &s->cpu->env;
-
-    cpu_reset(CPU(s->cpu));
-
-    env->halted = 0;
-    env->pc     = s->entry;
-    env->npc    = s->entry + 4;
-}
-
-void leon3_irq_ack(void *irq_manager, int intno)
-{
-    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
-}
-
-static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
-{
-    CPUSPARCState *env = (CPUSPARCState *)opaque;
-
-    assert(env != NULL);
-
-    env->pil_in = pil_in;
-
-    if (env->pil_in && (env->interrupt_index == 0 ||
-                        (env->interrupt_index & ~15) == TT_EXTINT)) {
-        unsigned int i;
-
-        for (i = 15; i > 0; i--) {
-            if (env->pil_in & (1 << i)) {
-                int old_interrupt = env->interrupt_index;
-
-                env->interrupt_index = TT_EXTINT | i;
-                if (old_interrupt != env->interrupt_index) {
-                    trace_leon3_set_irq(i);
-                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
-                }
-                break;
-            }
-        }
-    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
-        trace_leon3_reset_irq(env->interrupt_index & 15);
-        env->interrupt_index = 0;
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
-}
-
-static void leon3_generic_hw_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    SPARCCPU *cpu;
-    CPUSPARCState   *env;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *prom = g_new(MemoryRegion, 1);
-    int         ret;
-    char       *filename;
-    qemu_irq   *cpu_irqs = NULL;
-    int         bios_size;
-    int         prom_size;
-    ResetData  *reset_info;
-
-    /* Init CPU */
-    if (!cpu_model) {
-        cpu_model = "LEON3";
-    }
-
-    cpu = cpu_sparc_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
-        exit(1);
-    }
-    env = &cpu->env;
-
-    cpu_sparc_set_id(env, 0);
-
-    /* Reset data */
-    reset_info        = g_malloc0(sizeof(ResetData));
-    reset_info->cpu   = cpu;
-    qemu_register_reset(main_cpu_reset, reset_info);
-
-    /* Allocate IRQ manager */
-    grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in);
-
-    env->qemu_irq_ack = leon3_irq_manager;
-
-    /* Allocate RAM */
-    if ((uint64_t)ram_size > (1UL << 30)) {
-        fprintf(stderr,
-                "qemu: Too much memory for this machine: %d, maximum 1G\n",
-                (unsigned int)(ram_size / (1024 * 1024)));
-        exit(1);
-    }
-
-    memory_region_init_ram(ram, "leon3.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(address_space_mem, 0x40000000, ram);
-
-    /* Allocate BIOS */
-    prom_size = 8 * 1024 * 1024; /* 8Mb */
-    memory_region_init_ram(prom, "Leon3.bios", prom_size);
-    vmstate_register_ram_global(prom);
-    memory_region_set_readonly(prom, true);
-    memory_region_add_subregion(address_space_mem, 0x00000000, prom);
-
-    /* Load boot prom */
-    if (bios_name == NULL) {
-        bios_name = PROM_FILENAME;
-    }
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-
-    bios_size = get_image_size(filename);
-
-    if (bios_size > prom_size) {
-        fprintf(stderr, "qemu: could not load prom '%s': file too big\n",
-                filename);
-        exit(1);
-    }
-
-    if (bios_size > 0) {
-        ret = load_image_targphys(filename, 0x00000000, bios_size);
-        if (ret < 0 || ret > prom_size) {
-            fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
-            exit(1);
-        }
-    } else if (kernel_filename == NULL) {
-        fprintf(stderr, "Can't read bios image %s\n", filename);
-        exit(1);
-    }
-
-    /* Can directly load an application. */
-    if (kernel_filename != NULL) {
-        long     kernel_size;
-        uint64_t entry;
-
-        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
-                               1 /* big endian */, ELF_MACHINE, 0);
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-        if (bios_size <= 0) {
-            /* If there is no bios/monitor, start the application.  */
-            env->pc = entry;
-            env->npc = entry + 4;
-            reset_info->entry = entry;
-        }
-    }
-
-    /* Allocate timers */
-    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
-
-    /* Allocate uart */
-    if (serial_hds[0]) {
-        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
-    }
-}
-
-static QEMUMachine leon3_generic_machine = {
-    .name     = "leon3_generic",
-    .desc     = "Leon-3 generic",
-    .init     = leon3_generic_hw_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void leon3_machine_init(void)
-{
-    qemu_register_machine(&leon3_generic_machine);
-}
-
-machine_init(leon3_machine_init);
index 4e1843c11d0fc5b266db73022b1bb5d960de466b..4592fe5fc868826a25098284449d327ffa90b0ca 100644 (file)
@@ -1,7 +1,3 @@
-# LM32 boards
-obj-y += lm32_boards.o
-obj-y += milkymist.o
-
 # LM32 peripherals
 obj-y += lm32_pic.o
 obj-y += lm32_juart.o
@@ -21,3 +17,7 @@ obj-y += milkymist-vgafb.o
 obj-y += framebuffer.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+# LM32 boards
+obj-y += lm32_boards.o
+obj-y += milkymist.o
diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c
new file mode 100644 (file)
index 0000000..1ce466a
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ *  QEMU models for LatticeMico32 uclinux and evr32 boards.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "hw/flash.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "sysemu/blockdev.h"
+#include "elf.h"
+#include "hw/lm32_hwsetup.h"
+#include "hw/lm32.h"
+#include "exec/address-spaces.h"
+
+typedef struct {
+    LM32CPU *cpu;
+    hwaddr bootstrap_pc;
+    hwaddr flash_base;
+    hwaddr hwsetup_base;
+    hwaddr initrd_base;
+    size_t initrd_size;
+    hwaddr cmdline_base;
+} ResetInfo;
+
+static void cpu_irq_handler(void *opaque, int irq, int level)
+{
+    CPULM32State *env = opaque;
+
+    if (level) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetInfo *reset_info = opaque;
+    CPULM32State *env = &reset_info->cpu->env;
+
+    cpu_reset(CPU(reset_info->cpu));
+
+    /* init defaults */
+    env->pc = (uint32_t)reset_info->bootstrap_pc;
+    env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base;
+    env->regs[R_R2] = (uint32_t)reset_info->cmdline_base;
+    env->regs[R_R3] = (uint32_t)reset_info->initrd_base;
+    env->regs[R_R4] = (uint32_t)(reset_info->initrd_base +
+        reset_info->initrd_size);
+    env->eba = reset_info->flash_base;
+    env->deba = reset_info->flash_base;
+}
+
+static void lm32_evr_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    LM32CPU *cpu;
+    CPULM32State *env;
+    DriveInfo *dinfo;
+    MemoryRegion *address_space_mem =  get_system_memory();
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    qemu_irq *cpu_irq, irq[32];
+    ResetInfo *reset_info;
+    int i;
+
+    /* memory map */
+    hwaddr flash_base  = 0x04000000;
+    size_t flash_sector_size       = 256 * 1024;
+    size_t flash_size              = 32 * 1024 * 1024;
+    hwaddr ram_base    = 0x08000000;
+    size_t ram_size                = 64 * 1024 * 1024;
+    hwaddr timer0_base = 0x80002000;
+    hwaddr uart0_base  = 0x80006000;
+    hwaddr timer1_base = 0x8000a000;
+    int uart0_irq                  = 0;
+    int timer0_irq                 = 1;
+    int timer1_irq                 = 3;
+
+    reset_info = g_malloc0(sizeof(ResetInfo));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    cpu = cpu_lm32_init(cpu_model);
+    env = &cpu->env;
+    reset_info->cpu = cpu;
+
+    reset_info->flash_base = flash_base;
+
+    memory_region_init_ram(phys_ram, "lm32_evr.sdram", ram_size);
+    vmstate_register_ram_global(phys_ram);
+    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Spansion S29NS128P */
+    pflash_cfi02_register(flash_base, NULL, "lm32_evr.flash", flash_size,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 1, 2,
+                          0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
+
+    /* create irq lines */
+    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
+    env->pic_state = lm32_pic_init(*cpu_irq);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(env->pic_state, i);
+    }
+
+    sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
+    sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
+    sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
+
+    /* make sure juart isn't the first chardev */
+    env->juart_state = lm32_juart_init();
+
+    reset_info->bootstrap_pc = flash_base;
+
+    if (kernel_filename) {
+        uint64_t entry;
+        int kernel_size;
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
+        reset_info->bootstrap_pc = entry;
+
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, ram_base,
+                                              ram_size);
+            reset_info->bootstrap_pc = ram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static void lm32_uclinux_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    LM32CPU *cpu;
+    CPULM32State *env;
+    DriveInfo *dinfo;
+    MemoryRegion *address_space_mem =  get_system_memory();
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    qemu_irq *cpu_irq, irq[32];
+    HWSetup *hw;
+    ResetInfo *reset_info;
+    int i;
+
+    /* memory map */
+    hwaddr flash_base   = 0x04000000;
+    size_t flash_sector_size        = 256 * 1024;
+    size_t flash_size               = 32 * 1024 * 1024;
+    hwaddr ram_base     = 0x08000000;
+    size_t ram_size                 = 64 * 1024 * 1024;
+    hwaddr uart0_base   = 0x80000000;
+    hwaddr timer0_base  = 0x80002000;
+    hwaddr timer1_base  = 0x80010000;
+    hwaddr timer2_base  = 0x80012000;
+    int uart0_irq                   = 0;
+    int timer0_irq                  = 1;
+    int timer1_irq                  = 20;
+    int timer2_irq                  = 21;
+    hwaddr hwsetup_base = 0x0bffe000;
+    hwaddr cmdline_base = 0x0bfff000;
+    hwaddr initrd_base  = 0x08400000;
+    size_t initrd_max               = 0x01000000;
+
+    reset_info = g_malloc0(sizeof(ResetInfo));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    cpu = cpu_lm32_init(cpu_model);
+    env = &cpu->env;
+    reset_info->cpu = cpu;
+
+    reset_info->flash_base = flash_base;
+
+    memory_region_init_ram(phys_ram, "lm32_uclinux.sdram", ram_size);
+    vmstate_register_ram_global(phys_ram);
+    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Spansion S29NS128P */
+    pflash_cfi02_register(flash_base, NULL, "lm32_uclinux.flash", flash_size,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 1, 2,
+                          0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
+
+    /* create irq lines */
+    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
+    env->pic_state = lm32_pic_init(*cpu_irq);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(env->pic_state, i);
+    }
+
+    sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
+    sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
+    sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
+    sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]);
+
+    /* make sure juart isn't the first chardev */
+    env->juart_state = lm32_juart_init();
+
+    reset_info->bootstrap_pc = flash_base;
+
+    if (kernel_filename) {
+        uint64_t entry;
+        int kernel_size;
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
+        reset_info->bootstrap_pc = entry;
+
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, ram_base,
+                                              ram_size);
+            reset_info->bootstrap_pc = ram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    /* generate a rom with the hardware description */
+    hw = hwsetup_init();
+    hwsetup_add_cpu(hw, "LM32", 75000000);
+    hwsetup_add_flash(hw, "flash", flash_base, flash_size);
+    hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, ram_size);
+    hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq);
+    hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq);
+    hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq);
+    hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq);
+    hwsetup_add_trailer(hw);
+    hwsetup_create_rom(hw, hwsetup_base);
+    hwsetup_free(hw);
+
+    reset_info->hwsetup_base = hwsetup_base;
+
+    if (kernel_cmdline && strlen(kernel_cmdline)) {
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
+                kernel_cmdline);
+        reset_info->cmdline_base = cmdline_base;
+    }
+
+    if (initrd_filename) {
+        size_t initrd_size;
+        initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                initrd_max);
+        reset_info->initrd_base = initrd_base;
+        reset_info->initrd_size = initrd_size;
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static QEMUMachine lm32_evr_machine = {
+    .name = "lm32-evr",
+    .desc = "LatticeMico32 EVR32 eval system",
+    .init = lm32_evr_init,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine lm32_uclinux_machine = {
+    .name = "lm32-uclinux",
+    .desc = "lm32 platform for uClinux and u-boot by Theobroma Systems",
+    .init = lm32_uclinux_init,
+    .is_default = 0,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void lm32_machine_init(void)
+{
+    qemu_register_machine(&lm32_uclinux_machine);
+    qemu_register_machine(&lm32_evr_machine);
+}
+
+machine_init(lm32_machine_init);
diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c
new file mode 100644 (file)
index 0000000..fd36de5
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ *  QEMU model for the Milkymist board.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "hw/flash.h"
+#include "sysemu/sysemu.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "sysemu/blockdev.h"
+#include "hw/milkymist-hw.h"
+#include "hw/lm32.h"
+#include "exec/address-spaces.h"
+
+#define BIOS_FILENAME    "mmone-bios.bin"
+#define BIOS_OFFSET      0x00860000
+#define BIOS_SIZE        (512*1024)
+#define KERNEL_LOAD_ADDR 0x40000000
+
+typedef struct {
+    LM32CPU *cpu;
+    hwaddr bootstrap_pc;
+    hwaddr flash_base;
+    hwaddr initrd_base;
+    size_t initrd_size;
+    hwaddr cmdline_base;
+} ResetInfo;
+
+static void cpu_irq_handler(void *opaque, int irq, int level)
+{
+    CPULM32State *env = opaque;
+
+    if (level) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetInfo *reset_info = opaque;
+    CPULM32State *env = &reset_info->cpu->env;
+
+    cpu_reset(CPU(reset_info->cpu));
+
+    /* init defaults */
+    env->pc = reset_info->bootstrap_pc;
+    env->regs[R_R1] = reset_info->cmdline_base;
+    env->regs[R_R2] = reset_info->initrd_base;
+    env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size;
+    env->eba = reset_info->flash_base;
+    env->deba = reset_info->flash_base;
+}
+
+static void
+milkymist_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    LM32CPU *cpu;
+    CPULM32State *env;
+    int kernel_size;
+    DriveInfo *dinfo;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *phys_sdram = g_new(MemoryRegion, 1);
+    qemu_irq irq[32], *cpu_irq;
+    int i;
+    char *bios_filename;
+    ResetInfo *reset_info;
+
+    /* memory map */
+    hwaddr flash_base   = 0x00000000;
+    size_t flash_sector_size        = 128 * 1024;
+    size_t flash_size               = 32 * 1024 * 1024;
+    hwaddr sdram_base   = 0x40000000;
+    size_t sdram_size               = 128 * 1024 * 1024;
+
+    hwaddr initrd_base  = sdram_base + 0x1002000;
+    hwaddr cmdline_base = sdram_base + 0x1000000;
+    size_t initrd_max = sdram_size - 0x1002000;
+
+    reset_info = g_malloc0(sizeof(ResetInfo));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    cpu = cpu_lm32_init(cpu_model);
+    env = &cpu->env;
+    reset_info->cpu = cpu;
+
+    cpu_lm32_set_phys_msb_ignore(env, 1);
+
+    memory_region_init_ram(phys_sdram, "milkymist.sdram", sdram_size);
+    vmstate_register_ram_global(phys_sdram);
+    memory_region_add_subregion(address_space_mem, sdram_base, phys_sdram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Numonyx JS28F256J3F105 */
+    pflash_cfi01_register(flash_base, NULL, "milkymist.flash", flash_size,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 2,
+                          0x00, 0x89, 0x00, 0x1d, 1);
+
+    /* create irq lines */
+    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
+    env->pic_state = lm32_pic_init(*cpu_irq);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(env->pic_state, i);
+    }
+
+    /* load bios rom */
+    if (bios_name == NULL) {
+        bios_name = BIOS_FILENAME;
+    }
+    bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+    if (bios_filename) {
+        load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE);
+    }
+
+    reset_info->bootstrap_pc = BIOS_OFFSET;
+
+    /* if no kernel is given no valid bios rom is a fatal error */
+    if (!kernel_filename && !dinfo && !bios_filename) {
+        fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n",
+                bios_name);
+        exit(1);
+    }
+
+    milkymist_uart_create(0x60000000, irq[0]);
+    milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3],
+            80000000, 0x10014d31, 0x0000041f, 0x00000001);
+    milkymist_hpdmc_create(0x60002000);
+    milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);
+    milkymist_memcard_create(0x60004000);
+    milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]);
+    milkymist_pfpu_create(0x60006000, irq[8]);
+    milkymist_tmu2_create(0x60007000, irq[9]);
+    milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]);
+    milkymist_softusb_create(0x6000f000, irq[15],
+            0x20000000, 0x1000, 0x20020000, 0x2000);
+
+    /* make sure juart isn't the first chardev */
+    env->juart_state = lm32_juart_init();
+
+    if (kernel_filename) {
+        uint64_t entry;
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
+        reset_info->bootstrap_pc = entry;
+
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, sdram_base,
+                                              sdram_size);
+            reset_info->bootstrap_pc = sdram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    if (kernel_cmdline && strlen(kernel_cmdline)) {
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
+                kernel_cmdline);
+        reset_info->cmdline_base = (uint32_t)cmdline_base;
+    }
+
+    if (initrd_filename) {
+        size_t initrd_size;
+        initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                initrd_max);
+        reset_info->initrd_base = (uint32_t)initrd_base;
+        reset_info->initrd_size = (uint32_t)initrd_size;
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static QEMUMachine milkymist_machine = {
+    .name = "milkymist",
+    .desc = "Milkymist One",
+    .init = milkymist_init,
+    .is_default = 0,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void milkymist_machine_init(void)
+{
+    qemu_register_machine(&milkymist_machine);
+}
+
+machine_init(milkymist_machine_init);
diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c
deleted file mode 100644 (file)
index 1ce466a..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- *  QEMU models for LatticeMico32 uclinux and evr32 boards.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/flash.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "sysemu/blockdev.h"
-#include "elf.h"
-#include "hw/lm32_hwsetup.h"
-#include "hw/lm32.h"
-#include "exec/address-spaces.h"
-
-typedef struct {
-    LM32CPU *cpu;
-    hwaddr bootstrap_pc;
-    hwaddr flash_base;
-    hwaddr hwsetup_base;
-    hwaddr initrd_base;
-    size_t initrd_size;
-    hwaddr cmdline_base;
-} ResetInfo;
-
-static void cpu_irq_handler(void *opaque, int irq, int level)
-{
-    CPULM32State *env = opaque;
-
-    if (level) {
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
-    } else {
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
-}
-
-static void main_cpu_reset(void *opaque)
-{
-    ResetInfo *reset_info = opaque;
-    CPULM32State *env = &reset_info->cpu->env;
-
-    cpu_reset(CPU(reset_info->cpu));
-
-    /* init defaults */
-    env->pc = (uint32_t)reset_info->bootstrap_pc;
-    env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base;
-    env->regs[R_R2] = (uint32_t)reset_info->cmdline_base;
-    env->regs[R_R3] = (uint32_t)reset_info->initrd_base;
-    env->regs[R_R4] = (uint32_t)(reset_info->initrd_base +
-        reset_info->initrd_size);
-    env->eba = reset_info->flash_base;
-    env->deba = reset_info->flash_base;
-}
-
-static void lm32_evr_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    LM32CPU *cpu;
-    CPULM32State *env;
-    DriveInfo *dinfo;
-    MemoryRegion *address_space_mem =  get_system_memory();
-    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
-    qemu_irq *cpu_irq, irq[32];
-    ResetInfo *reset_info;
-    int i;
-
-    /* memory map */
-    hwaddr flash_base  = 0x04000000;
-    size_t flash_sector_size       = 256 * 1024;
-    size_t flash_size              = 32 * 1024 * 1024;
-    hwaddr ram_base    = 0x08000000;
-    size_t ram_size                = 64 * 1024 * 1024;
-    hwaddr timer0_base = 0x80002000;
-    hwaddr uart0_base  = 0x80006000;
-    hwaddr timer1_base = 0x8000a000;
-    int uart0_irq                  = 0;
-    int timer0_irq                 = 1;
-    int timer1_irq                 = 3;
-
-    reset_info = g_malloc0(sizeof(ResetInfo));
-
-    if (cpu_model == NULL) {
-        cpu_model = "lm32-full";
-    }
-    cpu = cpu_lm32_init(cpu_model);
-    env = &cpu->env;
-    reset_info->cpu = cpu;
-
-    reset_info->flash_base = flash_base;
-
-    memory_region_init_ram(phys_ram, "lm32_evr.sdram", ram_size);
-    vmstate_register_ram_global(phys_ram);
-    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    /* Spansion S29NS128P */
-    pflash_cfi02_register(flash_base, NULL, "lm32_evr.flash", flash_size,
-                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
-                          flash_size / flash_sector_size, 1, 2,
-                          0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
-
-    /* create irq lines */
-    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
-    env->pic_state = lm32_pic_init(*cpu_irq);
-    for (i = 0; i < 32; i++) {
-        irq[i] = qdev_get_gpio_in(env->pic_state, i);
-    }
-
-    sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
-    sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
-    sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
-
-    /* make sure juart isn't the first chardev */
-    env->juart_state = lm32_juart_init();
-
-    reset_info->bootstrap_pc = flash_base;
-
-    if (kernel_filename) {
-        uint64_t entry;
-        int kernel_size;
-
-        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
-                               1, ELF_MACHINE, 0);
-        reset_info->bootstrap_pc = entry;
-
-        if (kernel_size < 0) {
-            kernel_size = load_image_targphys(kernel_filename, ram_base,
-                                              ram_size);
-            reset_info->bootstrap_pc = ram_base;
-        }
-
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-    }
-
-    qemu_register_reset(main_cpu_reset, reset_info);
-}
-
-static void lm32_uclinux_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    LM32CPU *cpu;
-    CPULM32State *env;
-    DriveInfo *dinfo;
-    MemoryRegion *address_space_mem =  get_system_memory();
-    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
-    qemu_irq *cpu_irq, irq[32];
-    HWSetup *hw;
-    ResetInfo *reset_info;
-    int i;
-
-    /* memory map */
-    hwaddr flash_base   = 0x04000000;
-    size_t flash_sector_size        = 256 * 1024;
-    size_t flash_size               = 32 * 1024 * 1024;
-    hwaddr ram_base     = 0x08000000;
-    size_t ram_size                 = 64 * 1024 * 1024;
-    hwaddr uart0_base   = 0x80000000;
-    hwaddr timer0_base  = 0x80002000;
-    hwaddr timer1_base  = 0x80010000;
-    hwaddr timer2_base  = 0x80012000;
-    int uart0_irq                   = 0;
-    int timer0_irq                  = 1;
-    int timer1_irq                  = 20;
-    int timer2_irq                  = 21;
-    hwaddr hwsetup_base = 0x0bffe000;
-    hwaddr cmdline_base = 0x0bfff000;
-    hwaddr initrd_base  = 0x08400000;
-    size_t initrd_max               = 0x01000000;
-
-    reset_info = g_malloc0(sizeof(ResetInfo));
-
-    if (cpu_model == NULL) {
-        cpu_model = "lm32-full";
-    }
-    cpu = cpu_lm32_init(cpu_model);
-    env = &cpu->env;
-    reset_info->cpu = cpu;
-
-    reset_info->flash_base = flash_base;
-
-    memory_region_init_ram(phys_ram, "lm32_uclinux.sdram", ram_size);
-    vmstate_register_ram_global(phys_ram);
-    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    /* Spansion S29NS128P */
-    pflash_cfi02_register(flash_base, NULL, "lm32_uclinux.flash", flash_size,
-                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
-                          flash_size / flash_sector_size, 1, 2,
-                          0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
-
-    /* create irq lines */
-    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
-    env->pic_state = lm32_pic_init(*cpu_irq);
-    for (i = 0; i < 32; i++) {
-        irq[i] = qdev_get_gpio_in(env->pic_state, i);
-    }
-
-    sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
-    sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
-    sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
-    sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]);
-
-    /* make sure juart isn't the first chardev */
-    env->juart_state = lm32_juart_init();
-
-    reset_info->bootstrap_pc = flash_base;
-
-    if (kernel_filename) {
-        uint64_t entry;
-        int kernel_size;
-
-        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
-                               1, ELF_MACHINE, 0);
-        reset_info->bootstrap_pc = entry;
-
-        if (kernel_size < 0) {
-            kernel_size = load_image_targphys(kernel_filename, ram_base,
-                                              ram_size);
-            reset_info->bootstrap_pc = ram_base;
-        }
-
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-    }
-
-    /* generate a rom with the hardware description */
-    hw = hwsetup_init();
-    hwsetup_add_cpu(hw, "LM32", 75000000);
-    hwsetup_add_flash(hw, "flash", flash_base, flash_size);
-    hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, ram_size);
-    hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq);
-    hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq);
-    hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq);
-    hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq);
-    hwsetup_add_trailer(hw);
-    hwsetup_create_rom(hw, hwsetup_base);
-    hwsetup_free(hw);
-
-    reset_info->hwsetup_base = hwsetup_base;
-
-    if (kernel_cmdline && strlen(kernel_cmdline)) {
-        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
-                kernel_cmdline);
-        reset_info->cmdline_base = cmdline_base;
-    }
-
-    if (initrd_filename) {
-        size_t initrd_size;
-        initrd_size = load_image_targphys(initrd_filename, initrd_base,
-                initrd_max);
-        reset_info->initrd_base = initrd_base;
-        reset_info->initrd_size = initrd_size;
-    }
-
-    qemu_register_reset(main_cpu_reset, reset_info);
-}
-
-static QEMUMachine lm32_evr_machine = {
-    .name = "lm32-evr",
-    .desc = "LatticeMico32 EVR32 eval system",
-    .init = lm32_evr_init,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine lm32_uclinux_machine = {
-    .name = "lm32-uclinux",
-    .desc = "lm32 platform for uClinux and u-boot by Theobroma Systems",
-    .init = lm32_uclinux_init,
-    .is_default = 0,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void lm32_machine_init(void)
-{
-    qemu_register_machine(&lm32_uclinux_machine);
-    qemu_register_machine(&lm32_evr_machine);
-}
-
-machine_init(lm32_machine_init);
index 93b6d25baf9a6111f848929167caf4e63e7f1e5e..7c033a886c510c519cefc19417c13081faa08ad5 100644 (file)
@@ -1,4 +1,7 @@
-obj-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
-obj-y += dummy_m68k.o
+obj-y = mcf5206.o mcf_uart.o mcf_intc.o mcf_fec.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-y += an5206.o mcf5208.o
+obj-y += dummy_m68k.o
+
diff --git a/hw/m68k/an5206.c b/hw/m68k/an5206.c
new file mode 100644 (file)
index 0000000..7c21c66
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Arnewsh 5206 ColdFire system emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+
+#include "hw/hw.h"
+#include "hw/mcf.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "exec/address-spaces.h"
+
+#define KERNEL_LOAD_ADDR 0x10000
+#define AN5206_MBAR_ADDR 0x10000000
+#define AN5206_RAMBAR_ADDR 0x20000000
+
+/* Board init.  */
+
+static void an5206_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    M68kCPU *cpu;
+    CPUM68KState *env;
+    int kernel_size;
+    uint64_t elf_entry;
+    hwaddr entry;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+
+    if (!cpu_model) {
+        cpu_model = "m5206";
+    }
+    cpu = cpu_m68k_init(cpu_model);
+    if (!cpu) {
+        hw_error("Unable to find m68k CPU definition\n");
+    }
+    env = &cpu->env;
+
+    /* Initialize CPU registers.  */
+    env->vbr = 0;
+    /* TODO: allow changing MBAR and RAMBAR.  */
+    env->mbar = AN5206_MBAR_ADDR | 1;
+    env->rambar0 = AN5206_RAMBAR_ADDR | 1;
+
+    /* DRAM at address zero */
+    memory_region_init_ram(ram, "an5206.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(address_space_mem, 0, ram);
+
+    /* Internal SRAM.  */
+    memory_region_init_ram(sram, "an5206.sram", 512);
+    vmstate_register_ram_global(sram);
+    memory_region_add_subregion(address_space_mem, AN5206_RAMBAR_ADDR, sram);
+
+    mcf5206_init(address_space_mem, AN5206_MBAR_ADDR, cpu);
+
+    /* Load kernel.  */
+    if (!kernel_filename) {
+        fprintf(stderr, "Kernel image must be specified\n");
+        exit(1);
+    }
+
+    kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                           NULL, NULL, 1, ELF_MACHINE, 0);
+    entry = elf_entry;
+    if (kernel_size < 0) {
+        kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
+    }
+    if (kernel_size < 0) {
+        kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
+                                          ram_size - KERNEL_LOAD_ADDR);
+        entry = KERNEL_LOAD_ADDR;
+    }
+    if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
+        exit(1);
+    }
+
+    env->pc = entry;
+}
+
+static QEMUMachine an5206_machine = {
+    .name = "an5206",
+    .desc = "Arnewsh 5206",
+    .init = an5206_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void an5206_machine_init(void)
+{
+    qemu_register_machine(&an5206_machine);
+}
+
+machine_init(an5206_machine_init);
diff --git a/hw/m68k/dummy_m68k.c b/hw/m68k/dummy_m68k.c
new file mode 100644 (file)
index 0000000..544d56b
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Dummy board with just RAM and CPU for use as an ISS.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "exec/address-spaces.h"
+
+#define KERNEL_LOAD_ADDR 0x10000
+
+/* Board init.  */
+
+static void dummy_m68k_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    CPUM68KState *env;
+    MemoryRegion *address_space_mem =  get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    int kernel_size;
+    uint64_t elf_entry;
+    hwaddr entry;
+
+    if (!cpu_model)
+        cpu_model = "cfv4e";
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find m68k CPU definition\n");
+        exit(1);
+    }
+
+    /* Initialize CPU registers.  */
+    env->vbr = 0;
+
+    /* RAM at address zero */
+    memory_region_init_ram(ram, "dummy_m68k.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(address_space_mem, 0, ram);
+
+    /* Load kernel.  */
+    if (kernel_filename) {
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                               NULL, NULL, 1, ELF_MACHINE, 0);
+        entry = elf_entry;
+        if (kernel_size < 0) {
+            kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
+        }
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              ram_size - KERNEL_LOAD_ADDR);
+            entry = KERNEL_LOAD_ADDR;
+        }
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    } else {
+        entry = 0;
+    }
+    env->pc = entry;
+}
+
+static QEMUMachine dummy_m68k_machine = {
+    .name = "dummy",
+    .desc = "Dummy board",
+    .init = dummy_m68k_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void dummy_m68k_machine_init(void)
+{
+    qemu_register_machine(&dummy_m68k_machine);
+}
+
+machine_init(dummy_m68k_machine_init);
diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c
new file mode 100644 (file)
index 0000000..748bf56
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Motorola ColdFire MCF5208 SoC emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+#include "hw/hw.h"
+#include "hw/mcf.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "sysemu/sysemu.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "exec/address-spaces.h"
+
+#define SYS_FREQ 66000000
+
+#define PCSR_EN         0x0001
+#define PCSR_RLD        0x0002
+#define PCSR_PIF        0x0004
+#define PCSR_PIE        0x0008
+#define PCSR_OVW        0x0010
+#define PCSR_DBG        0x0020
+#define PCSR_DOZE       0x0040
+#define PCSR_PRE_SHIFT  8
+#define PCSR_PRE_MASK   0x0f00
+
+typedef struct {
+    MemoryRegion iomem;
+    qemu_irq irq;
+    ptimer_state *timer;
+    uint16_t pcsr;
+    uint16_t pmr;
+    uint16_t pcntr;
+} m5208_timer_state;
+
+static void m5208_timer_update(m5208_timer_state *s)
+{
+    if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF))
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static void m5208_timer_write(void *opaque, hwaddr offset,
+                              uint64_t value, unsigned size)
+{
+    m5208_timer_state *s = (m5208_timer_state *)opaque;
+    int prescale;
+    int limit;
+    switch (offset) {
+    case 0:
+        /* The PIF bit is set-to-clear.  */
+        if (value & PCSR_PIF) {
+            s->pcsr &= ~PCSR_PIF;
+            value &= ~PCSR_PIF;
+        }
+        /* Avoid frobbing the timer if we're just twiddling IRQ bits. */
+        if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) {
+            s->pcsr = value;
+            m5208_timer_update(s);
+            return;
+        }
+
+        if (s->pcsr & PCSR_EN)
+            ptimer_stop(s->timer);
+
+        s->pcsr = value;
+
+        prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT);
+        ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale);
+        if (s->pcsr & PCSR_RLD)
+            limit = s->pmr;
+        else
+            limit = 0xffff;
+        ptimer_set_limit(s->timer, limit, 0);
+
+        if (s->pcsr & PCSR_EN)
+            ptimer_run(s->timer, 0);
+        break;
+    case 2:
+        s->pmr = value;
+        s->pcsr &= ~PCSR_PIF;
+        if ((s->pcsr & PCSR_RLD) == 0) {
+            if (s->pcsr & PCSR_OVW)
+                ptimer_set_count(s->timer, value);
+        } else {
+            ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW);
+        }
+        break;
+    case 4:
+        break;
+    default:
+        hw_error("m5208_timer_write: Bad offset 0x%x\n", (int)offset);
+        break;
+    }
+    m5208_timer_update(s);
+}
+
+static void m5208_timer_trigger(void *opaque)
+{
+    m5208_timer_state *s = (m5208_timer_state *)opaque;
+    s->pcsr |= PCSR_PIF;
+    m5208_timer_update(s);
+}
+
+static uint64_t m5208_timer_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    m5208_timer_state *s = (m5208_timer_state *)opaque;
+    switch (addr) {
+    case 0:
+        return s->pcsr;
+    case 2:
+        return s->pmr;
+    case 4:
+        return ptimer_get_count(s->timer);
+    default:
+        hw_error("m5208_timer_read: Bad offset 0x%x\n", (int)addr);
+        return 0;
+    }
+}
+
+static const MemoryRegionOps m5208_timer_ops = {
+    .read = m5208_timer_read,
+    .write = m5208_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t m5208_sys_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    switch (addr) {
+    case 0x110: /* SDCS0 */
+        {
+            int n;
+            for (n = 0; n < 32; n++) {
+                if (ram_size < (2u << n))
+                    break;
+            }
+            return (n - 1)  | 0x40000000;
+        }
+    case 0x114: /* SDCS1 */
+        return 0;
+
+    default:
+        hw_error("m5208_sys_read: Bad offset 0x%x\n", (int)addr);
+        return 0;
+    }
+}
+
+static void m5208_sys_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr);
+}
+
+static const MemoryRegionOps m5208_sys_ops = {
+    .read = m5208_sys_read,
+    .write = m5208_sys_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic)
+{
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
+    m5208_timer_state *s;
+    QEMUBH *bh;
+    int i;
+
+    /* SDRAMC.  */
+    memory_region_init_io(iomem, &m5208_sys_ops, NULL, "m5208-sys", 0x00004000);
+    memory_region_add_subregion(address_space, 0xfc0a8000, iomem);
+    /* Timers.  */
+    for (i = 0; i < 2; i++) {
+        s = (m5208_timer_state *)g_malloc0(sizeof(m5208_timer_state));
+        bh = qemu_bh_new(m5208_timer_trigger, s);
+        s->timer = ptimer_init(bh);
+        memory_region_init_io(&s->iomem, &m5208_timer_ops, s,
+                              "m5208-timer", 0x00004000);
+        memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i,
+                                    &s->iomem);
+        s->irq = pic[4 + i];
+    }
+}
+
+static void mcf5208evb_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    M68kCPU *cpu;
+    CPUM68KState *env;
+    int kernel_size;
+    uint64_t elf_entry;
+    hwaddr entry;
+    qemu_irq *pic;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+
+    if (!cpu_model) {
+        cpu_model = "m5208";
+    }
+    cpu = cpu_m68k_init(cpu_model);
+    if (!cpu) {
+        fprintf(stderr, "Unable to find m68k CPU definition\n");
+        exit(1);
+    }
+    env = &cpu->env;
+
+    /* Initialize CPU registers.  */
+    env->vbr = 0;
+    /* TODO: Configure BARs.  */
+
+    /* DRAM at 0x40000000 */
+    memory_region_init_ram(ram, "mcf5208.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(address_space_mem, 0x40000000, ram);
+
+    /* Internal SRAM.  */
+    memory_region_init_ram(sram, "mcf5208.sram", 16384);
+    vmstate_register_ram_global(sram);
+    memory_region_add_subregion(address_space_mem, 0x80000000, sram);
+
+    /* Internal peripherals.  */
+    pic = mcf_intc_init(address_space_mem, 0xfc048000, cpu);
+
+    mcf_uart_mm_init(address_space_mem, 0xfc060000, pic[26], serial_hds[0]);
+    mcf_uart_mm_init(address_space_mem, 0xfc064000, pic[27], serial_hds[1]);
+    mcf_uart_mm_init(address_space_mem, 0xfc068000, pic[28], serial_hds[2]);
+
+    mcf5208_sys_init(address_space_mem, pic);
+
+    if (nb_nics > 1) {
+        fprintf(stderr, "Too many NICs\n");
+        exit(1);
+    }
+    if (nd_table[0].used)
+        mcf_fec_init(address_space_mem, &nd_table[0],
+                     0xfc030000, pic + 36);
+
+    /*  0xfc000000 SCM.  */
+    /*  0xfc004000 XBS.  */
+    /*  0xfc008000 FlexBus CS.  */
+    /* 0xfc030000 FEC.  */
+    /*  0xfc040000 SCM + Power management.  */
+    /*  0xfc044000 eDMA.  */
+    /* 0xfc048000 INTC.  */
+    /*  0xfc058000 I2C.  */
+    /*  0xfc05c000 QSPI.  */
+    /* 0xfc060000 UART0.  */
+    /* 0xfc064000 UART0.  */
+    /* 0xfc068000 UART0.  */
+    /*  0xfc070000 DMA timers.  */
+    /* 0xfc080000 PIT0.  */
+    /* 0xfc084000 PIT1.  */
+    /*  0xfc088000 EPORT.  */
+    /*  0xfc08c000 Watchdog.  */
+    /*  0xfc090000 clock module.  */
+    /*  0xfc0a0000 CCM + reset.  */
+    /*  0xfc0a4000 GPIO.  */
+    /* 0xfc0a8000 SDRAM controller.  */
+
+    /* Load kernel.  */
+    if (!kernel_filename) {
+        fprintf(stderr, "Kernel image must be specified\n");
+        exit(1);
+    }
+
+    kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                           NULL, NULL, 1, ELF_MACHINE, 0);
+    entry = elf_entry;
+    if (kernel_size < 0) {
+        kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
+    }
+    if (kernel_size < 0) {
+        kernel_size = load_image_targphys(kernel_filename, 0x40000000,
+                                          ram_size);
+        entry = 0x40000000;
+    }
+    if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
+        exit(1);
+    }
+
+    env->pc = entry;
+}
+
+static QEMUMachine mcf5208evb_machine = {
+    .name = "mcf5208evb",
+    .desc = "MCF5206EVB",
+    .init = mcf5208evb_init,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void mcf5208evb_machine_init(void)
+{
+    qemu_register_machine(&mcf5208evb_machine);
+}
+
+machine_init(mcf5208evb_machine_init);
diff --git a/hw/mainstone.c b/hw/mainstone.c
deleted file mode 100644 (file)
index aea908f..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * PXA270-based Intel Mainstone platforms.
- *
- * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
- *                                    <akuster@mvista.com>
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "hw/hw.h"
-#include "hw/pxa.h"
-#include "hw/arm-misc.h"
-#include "net/net.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/flash.h"
-#include "sysemu/blockdev.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-/* Device addresses */
-#define MST_FPGA_PHYS  0x08000000
-#define MST_ETH_PHYS   0x10000300
-#define MST_FLASH_0            0x00000000
-#define MST_FLASH_1            0x04000000
-
-/* IRQ definitions */
-#define MMC_IRQ       0
-#define USIM_IRQ      1
-#define USBC_IRQ      2
-#define ETHERNET_IRQ  3
-#define AC97_IRQ      4
-#define PEN_IRQ       5
-#define MSINS_IRQ     6
-#define EXBRD_IRQ     7
-#define S0_CD_IRQ     9
-#define S0_STSCHG_IRQ 10
-#define S0_IRQ        11
-#define S1_CD_IRQ     13
-#define S1_STSCHG_IRQ 14
-#define S1_IRQ        15
-
-static struct keymap map[0xE0] = {
-    [0 ... 0xDF] = { -1, -1 },
-    [0x1e] = {0,0}, /* a */
-    [0x30] = {0,1}, /* b */
-    [0x2e] = {0,2}, /* c */
-    [0x20] = {0,3}, /* d */
-    [0x12] = {0,4}, /* e */
-    [0x21] = {0,5}, /* f */
-    [0x22] = {1,0}, /* g */
-    [0x23] = {1,1}, /* h */
-    [0x17] = {1,2}, /* i */
-    [0x24] = {1,3}, /* j */
-    [0x25] = {1,4}, /* k */
-    [0x26] = {1,5}, /* l */
-    [0x32] = {2,0}, /* m */
-    [0x31] = {2,1}, /* n */
-    [0x18] = {2,2}, /* o */
-    [0x19] = {2,3}, /* p */
-    [0x10] = {2,4}, /* q */
-    [0x13] = {2,5}, /* r */
-    [0x1f] = {3,0}, /* s */
-    [0x14] = {3,1}, /* t */
-    [0x16] = {3,2}, /* u */
-    [0x2f] = {3,3}, /* v */
-    [0x11] = {3,4}, /* w */
-    [0x2d] = {3,5}, /* x */
-    [0x15] = {4,2}, /* y */
-    [0x2c] = {4,3}, /* z */
-    [0xc7] = {5,0}, /* Home */
-    [0x2a] = {5,1}, /* shift */
-    [0x39] = {5,2}, /* space */
-    [0x39] = {5,3}, /* space */
-    [0x1c] = {5,5}, /*  enter */
-    [0xc8] = {6,0}, /* up */
-    [0xd0] = {6,1}, /* down */
-    [0xcb] = {6,2}, /* left */
-    [0xcd] = {6,3}, /* right */
-};
-
-enum mainstone_model_e { mainstone };
-
-#define MAINSTONE_RAM  0x04000000
-#define MAINSTONE_ROM  0x00800000
-#define MAINSTONE_FLASH        0x02000000
-
-static struct arm_boot_info mainstone_binfo = {
-    .loader_start = PXA2XX_SDRAM_BASE,
-    .ram_size = 0x04000000,
-};
-
-static void mainstone_common_init(MemoryRegion *address_space_mem,
-                                  QEMUMachineInitArgs *args,
-                                  enum mainstone_model_e model, int arm_id)
-{
-    uint32_t sector_len = 256 * 1024;
-    hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
-    PXA2xxState *mpu;
-    DeviceState *mst_irq;
-    DriveInfo *dinfo;
-    int i;
-    int be;
-    MemoryRegion *rom = g_new(MemoryRegion, 1);
-    const char *cpu_model = args->cpu_model;
-
-    if (!cpu_model)
-        cpu_model = "pxa270-c5";
-
-    /* Setup CPU & memory */
-    mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model);
-    memory_region_init_ram(rom, "mainstone.rom", MAINSTONE_ROM);
-    vmstate_register_ram_global(rom);
-    memory_region_set_readonly(rom, true);
-    memory_region_add_subregion(address_space_mem, 0, rom);
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    be = 1;
-#else
-    be = 0;
-#endif
-    /* There are two 32MiB flash devices on the board */
-    for (i = 0; i < 2; i ++) {
-        dinfo = drive_get(IF_PFLASH, 0, i);
-        if (!dinfo) {
-            fprintf(stderr, "Two flash images must be given with the "
-                    "'pflash' parameter\n");
-            exit(1);
-        }
-
-        if (!pflash_cfi01_register(mainstone_flash_base[i], NULL,
-                                   i ? "mainstone.flash1" : "mainstone.flash0",
-                                   MAINSTONE_FLASH,
-                                   dinfo->bdrv, sector_len,
-                                   MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0,
-                                   be)) {
-            fprintf(stderr, "qemu: Error registering flash memory.\n");
-            exit(1);
-        }
-    }
-
-    mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS,
-                    qdev_get_gpio_in(mpu->gpio, 0));
-
-    /* setup keypad */
-    printf("map addr %p\n", &map);
-    pxa27x_register_keypad(mpu->kp, map, 0xe0);
-
-    /* MMC/SD host */
-    pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ));
-
-    pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[0],
-            qdev_get_gpio_in(mst_irq, S0_IRQ),
-            qdev_get_gpio_in(mst_irq, S0_CD_IRQ));
-    pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1],
-            qdev_get_gpio_in(mst_irq, S1_IRQ),
-            qdev_get_gpio_in(mst_irq, S1_CD_IRQ));
-
-    smc91c111_init(&nd_table[0], MST_ETH_PHYS,
-                    qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
-
-    mainstone_binfo.kernel_filename = args->kernel_filename;
-    mainstone_binfo.kernel_cmdline = args->kernel_cmdline;
-    mainstone_binfo.initrd_filename = args->initrd_filename;
-    mainstone_binfo.board_id = arm_id;
-    arm_load_kernel(mpu->cpu, &mainstone_binfo);
-}
-
-static void mainstone_init(QEMUMachineInitArgs *args)
-{
-    mainstone_common_init(get_system_memory(), args, mainstone, 0x196);
-}
-
-static QEMUMachine mainstone2_machine = {
-    .name = "mainstone",
-    .desc = "Mainstone II (PXA27x)",
-    .init = mainstone_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void mainstone_machine_init(void)
-{
-    qemu_register_machine(&mainstone2_machine);
-}
-
-machine_init(mainstone_machine_init);
diff --git a/hw/mcf5208.c b/hw/mcf5208.c
deleted file mode 100644 (file)
index 748bf56..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Motorola ColdFire MCF5208 SoC emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "hw/hw.h"
-#include "hw/mcf.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "sysemu/sysemu.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-
-#define SYS_FREQ 66000000
-
-#define PCSR_EN         0x0001
-#define PCSR_RLD        0x0002
-#define PCSR_PIF        0x0004
-#define PCSR_PIE        0x0008
-#define PCSR_OVW        0x0010
-#define PCSR_DBG        0x0020
-#define PCSR_DOZE       0x0040
-#define PCSR_PRE_SHIFT  8
-#define PCSR_PRE_MASK   0x0f00
-
-typedef struct {
-    MemoryRegion iomem;
-    qemu_irq irq;
-    ptimer_state *timer;
-    uint16_t pcsr;
-    uint16_t pmr;
-    uint16_t pcntr;
-} m5208_timer_state;
-
-static void m5208_timer_update(m5208_timer_state *s)
-{
-    if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF))
-        qemu_irq_raise(s->irq);
-    else
-        qemu_irq_lower(s->irq);
-}
-
-static void m5208_timer_write(void *opaque, hwaddr offset,
-                              uint64_t value, unsigned size)
-{
-    m5208_timer_state *s = (m5208_timer_state *)opaque;
-    int prescale;
-    int limit;
-    switch (offset) {
-    case 0:
-        /* The PIF bit is set-to-clear.  */
-        if (value & PCSR_PIF) {
-            s->pcsr &= ~PCSR_PIF;
-            value &= ~PCSR_PIF;
-        }
-        /* Avoid frobbing the timer if we're just twiddling IRQ bits. */
-        if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) {
-            s->pcsr = value;
-            m5208_timer_update(s);
-            return;
-        }
-
-        if (s->pcsr & PCSR_EN)
-            ptimer_stop(s->timer);
-
-        s->pcsr = value;
-
-        prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT);
-        ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale);
-        if (s->pcsr & PCSR_RLD)
-            limit = s->pmr;
-        else
-            limit = 0xffff;
-        ptimer_set_limit(s->timer, limit, 0);
-
-        if (s->pcsr & PCSR_EN)
-            ptimer_run(s->timer, 0);
-        break;
-    case 2:
-        s->pmr = value;
-        s->pcsr &= ~PCSR_PIF;
-        if ((s->pcsr & PCSR_RLD) == 0) {
-            if (s->pcsr & PCSR_OVW)
-                ptimer_set_count(s->timer, value);
-        } else {
-            ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW);
-        }
-        break;
-    case 4:
-        break;
-    default:
-        hw_error("m5208_timer_write: Bad offset 0x%x\n", (int)offset);
-        break;
-    }
-    m5208_timer_update(s);
-}
-
-static void m5208_timer_trigger(void *opaque)
-{
-    m5208_timer_state *s = (m5208_timer_state *)opaque;
-    s->pcsr |= PCSR_PIF;
-    m5208_timer_update(s);
-}
-
-static uint64_t m5208_timer_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    m5208_timer_state *s = (m5208_timer_state *)opaque;
-    switch (addr) {
-    case 0:
-        return s->pcsr;
-    case 2:
-        return s->pmr;
-    case 4:
-        return ptimer_get_count(s->timer);
-    default:
-        hw_error("m5208_timer_read: Bad offset 0x%x\n", (int)addr);
-        return 0;
-    }
-}
-
-static const MemoryRegionOps m5208_timer_ops = {
-    .read = m5208_timer_read,
-    .write = m5208_timer_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t m5208_sys_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    switch (addr) {
-    case 0x110: /* SDCS0 */
-        {
-            int n;
-            for (n = 0; n < 32; n++) {
-                if (ram_size < (2u << n))
-                    break;
-            }
-            return (n - 1)  | 0x40000000;
-        }
-    case 0x114: /* SDCS1 */
-        return 0;
-
-    default:
-        hw_error("m5208_sys_read: Bad offset 0x%x\n", (int)addr);
-        return 0;
-    }
-}
-
-static void m5208_sys_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr);
-}
-
-static const MemoryRegionOps m5208_sys_ops = {
-    .read = m5208_sys_read,
-    .write = m5208_sys_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic)
-{
-    MemoryRegion *iomem = g_new(MemoryRegion, 1);
-    m5208_timer_state *s;
-    QEMUBH *bh;
-    int i;
-
-    /* SDRAMC.  */
-    memory_region_init_io(iomem, &m5208_sys_ops, NULL, "m5208-sys", 0x00004000);
-    memory_region_add_subregion(address_space, 0xfc0a8000, iomem);
-    /* Timers.  */
-    for (i = 0; i < 2; i++) {
-        s = (m5208_timer_state *)g_malloc0(sizeof(m5208_timer_state));
-        bh = qemu_bh_new(m5208_timer_trigger, s);
-        s->timer = ptimer_init(bh);
-        memory_region_init_io(&s->iomem, &m5208_timer_ops, s,
-                              "m5208-timer", 0x00004000);
-        memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i,
-                                    &s->iomem);
-        s->irq = pic[4 + i];
-    }
-}
-
-static void mcf5208evb_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    M68kCPU *cpu;
-    CPUM68KState *env;
-    int kernel_size;
-    uint64_t elf_entry;
-    hwaddr entry;
-    qemu_irq *pic;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *sram = g_new(MemoryRegion, 1);
-
-    if (!cpu_model) {
-        cpu_model = "m5208";
-    }
-    cpu = cpu_m68k_init(cpu_model);
-    if (!cpu) {
-        fprintf(stderr, "Unable to find m68k CPU definition\n");
-        exit(1);
-    }
-    env = &cpu->env;
-
-    /* Initialize CPU registers.  */
-    env->vbr = 0;
-    /* TODO: Configure BARs.  */
-
-    /* DRAM at 0x40000000 */
-    memory_region_init_ram(ram, "mcf5208.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(address_space_mem, 0x40000000, ram);
-
-    /* Internal SRAM.  */
-    memory_region_init_ram(sram, "mcf5208.sram", 16384);
-    vmstate_register_ram_global(sram);
-    memory_region_add_subregion(address_space_mem, 0x80000000, sram);
-
-    /* Internal peripherals.  */
-    pic = mcf_intc_init(address_space_mem, 0xfc048000, cpu);
-
-    mcf_uart_mm_init(address_space_mem, 0xfc060000, pic[26], serial_hds[0]);
-    mcf_uart_mm_init(address_space_mem, 0xfc064000, pic[27], serial_hds[1]);
-    mcf_uart_mm_init(address_space_mem, 0xfc068000, pic[28], serial_hds[2]);
-
-    mcf5208_sys_init(address_space_mem, pic);
-
-    if (nb_nics > 1) {
-        fprintf(stderr, "Too many NICs\n");
-        exit(1);
-    }
-    if (nd_table[0].used)
-        mcf_fec_init(address_space_mem, &nd_table[0],
-                     0xfc030000, pic + 36);
-
-    /*  0xfc000000 SCM.  */
-    /*  0xfc004000 XBS.  */
-    /*  0xfc008000 FlexBus CS.  */
-    /* 0xfc030000 FEC.  */
-    /*  0xfc040000 SCM + Power management.  */
-    /*  0xfc044000 eDMA.  */
-    /* 0xfc048000 INTC.  */
-    /*  0xfc058000 I2C.  */
-    /*  0xfc05c000 QSPI.  */
-    /* 0xfc060000 UART0.  */
-    /* 0xfc064000 UART0.  */
-    /* 0xfc068000 UART0.  */
-    /*  0xfc070000 DMA timers.  */
-    /* 0xfc080000 PIT0.  */
-    /* 0xfc084000 PIT1.  */
-    /*  0xfc088000 EPORT.  */
-    /*  0xfc08c000 Watchdog.  */
-    /*  0xfc090000 clock module.  */
-    /*  0xfc0a0000 CCM + reset.  */
-    /*  0xfc0a4000 GPIO.  */
-    /* 0xfc0a8000 SDRAM controller.  */
-
-    /* Load kernel.  */
-    if (!kernel_filename) {
-        fprintf(stderr, "Kernel image must be specified\n");
-        exit(1);
-    }
-
-    kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
-                           NULL, NULL, 1, ELF_MACHINE, 0);
-    entry = elf_entry;
-    if (kernel_size < 0) {
-        kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
-    }
-    if (kernel_size < 0) {
-        kernel_size = load_image_targphys(kernel_filename, 0x40000000,
-                                          ram_size);
-        entry = 0x40000000;
-    }
-    if (kernel_size < 0) {
-        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
-        exit(1);
-    }
-
-    env->pc = entry;
-}
-
-static QEMUMachine mcf5208evb_machine = {
-    .name = "mcf5208evb",
-    .desc = "MCF5206EVB",
-    .init = mcf5208evb_init,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void mcf5208evb_machine_init(void)
-{
-    qemu_register_machine(&mcf5208evb_machine);
-}
-
-machine_init(mcf5208evb_machine_init);
index 2ff8048a986e81ae36a9fbd3e2f1d8efe9994013..9e7f249941a7f6b6e003f61c9986851106ab765a 100644 (file)
@@ -1,9 +1,9 @@
-obj-y = petalogix_s3adsp1800_mmu.o
-obj-y += petalogix_ml605_mmu.o
-obj-y += microblaze_boot.o
 obj-y += xilinx_spi.o
-
-obj-y += microblaze_pic_cpu.o
 obj-y += xilinx_ethlite.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-y += petalogix_s3adsp1800_mmu.o
+obj-y += petalogix_ml605_mmu.o
+obj-y += boot.o
+obj-y += pic_cpu.o
diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c
new file mode 100644 (file)
index 0000000..e13b3e1
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Microblaze kernel loader
+ *
+ * Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@petalogix.com>
+ * Copyright (c) 2012 PetaLogix
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/option.h"
+#include "qemu/config-file.h"
+#include "qemu-common.h"
+#include "sysemu/device_tree.h"
+#include "hw/loader.h"
+#include "elf.h"
+
+#include "hw/microblaze_boot.h"
+
+static struct
+{
+    void (*machine_cpu_reset)(MicroBlazeCPU *);
+    uint32_t bootstrap_pc;
+    uint32_t cmdline;
+    uint32_t fdt;
+} boot_info;
+
+static void main_cpu_reset(void *opaque)
+{
+    MicroBlazeCPU *cpu = opaque;
+    CPUMBState *env = &cpu->env;
+
+    cpu_reset(CPU(cpu));
+    env->regs[5] = boot_info.cmdline;
+    env->regs[7] = boot_info.fdt;
+    env->sregs[SR_PC] = boot_info.bootstrap_pc;
+    if (boot_info.machine_cpu_reset) {
+        boot_info.machine_cpu_reset(cpu);
+    }
+}
+
+static int microblaze_load_dtb(hwaddr addr,
+                                      uint32_t ramsize,
+                                      const char *kernel_cmdline,
+                                      const char *dtb_filename)
+{
+    int fdt_size;
+#ifdef CONFIG_FDT
+    void *fdt = NULL;
+    int r;
+
+    if (dtb_filename) {
+        fdt = load_device_tree(dtb_filename, &fdt_size);
+    }
+    if (!fdt) {
+        return 0;
+    }
+
+    if (kernel_cmdline) {
+        r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
+                                                        kernel_cmdline);
+        if (r < 0) {
+            fprintf(stderr, "couldn't set /chosen/bootargs\n");
+        }
+    }
+
+    cpu_physical_memory_write(addr, (void *)fdt, fdt_size);
+#else
+    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
+       to the kernel.  */
+    if (dtb_filename) {
+        fdt_size = load_image_targphys(dtb_filename, addr, 0x10000);
+    }
+    if (kernel_cmdline) {
+        fprintf(stderr,
+                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
+    }
+#endif
+    return fdt_size;
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return addr - 0x30000000LL;
+}
+
+void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
+                            uint32_t ramsize, const char *dtb_filename,
+                            void (*machine_cpu_reset)(MicroBlazeCPU *))
+{
+    QemuOpts *machine_opts;
+    const char *kernel_filename = NULL;
+    const char *kernel_cmdline = NULL;
+
+    machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+    if (machine_opts) {
+        const char *dtb_arg;
+        kernel_filename = qemu_opt_get(machine_opts, "kernel");
+        kernel_cmdline = qemu_opt_get(machine_opts, "append");
+        dtb_arg = qemu_opt_get(machine_opts, "dtb");
+        if (dtb_arg) { /* Preference a -dtb argument */
+            dtb_filename = dtb_arg;
+        } else { /* default to pcbios dtb as passed by machine_init */
+            dtb_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename);
+        }
+    }
+
+    boot_info.machine_cpu_reset = machine_cpu_reset;
+    qemu_register_reset(main_cpu_reset, cpu);
+
+    if (kernel_filename) {
+        int kernel_size;
+        uint64_t entry, low, high;
+        uint32_t base32;
+        int big_endian = 0;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+        big_endian = 1;
+#endif
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL,
+                               &entry, &low, &high,
+                               big_endian, ELF_MACHINE, 0);
+        base32 = entry;
+        if (base32 == 0xc0000000) {
+            kernel_size = load_elf(kernel_filename, translate_kernel_address,
+                                   NULL, &entry, NULL, NULL,
+                                   big_endian, ELF_MACHINE, 0);
+        }
+        /* Always boot into physical ram.  */
+        boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff);
+
+        /* If it wasn't an ELF image, try an u-boot image.  */
+        if (kernel_size < 0) {
+            hwaddr uentry, loadaddr;
+
+            kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0);
+            boot_info.bootstrap_pc = uentry;
+            high = (loadaddr + kernel_size + 3) & ~3;
+        }
+
+        /* Not an ELF image nor an u-boot image, try a RAW image.  */
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, ddr_base,
+                                              ram_size);
+            boot_info.bootstrap_pc = ddr_base;
+            high = (ddr_base + kernel_size + 3) & ~3;
+        }
+
+        boot_info.cmdline = high + 4096;
+        if (kernel_cmdline && strlen(kernel_cmdline)) {
+            pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline);
+        }
+        /* Provide a device-tree.  */
+        boot_info.fdt = boot_info.cmdline + 4096;
+        microblaze_load_dtb(boot_info.fdt, ram_size, kernel_cmdline,
+                                                     dtb_filename);
+    }
+
+}
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
new file mode 100644 (file)
index 0000000..cfc0220
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Model of Petalogix linux reference design targeting Xilinx Spartan ml605
+ * board.
+ *
+ * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (c) 2011 PetaLogix
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "net/net.h"
+#include "hw/flash.h"
+#include "sysemu/sysemu.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "hw/xilinx.h"
+#include "sysemu/blockdev.h"
+#include "hw/serial.h"
+#include "exec/address-spaces.h"
+#include "hw/ssi.h"
+
+#include "hw/microblaze_boot.h"
+#include "hw/microblaze_pic_cpu.h"
+
+#include "hw/stream.h"
+
+#define LMB_BRAM_SIZE  (128 * 1024)
+#define FLASH_SIZE     (32 * 1024 * 1024)
+
+#define BINARY_DEVICE_TREE_FILE "petalogix-ml605.dtb"
+
+#define NUM_SPI_FLASHES 4
+
+#define MEMORY_BASEADDR 0x50000000
+#define FLASH_BASEADDR 0x86000000
+#define INTC_BASEADDR 0x81800000
+#define TIMER_BASEADDR 0x83c00000
+#define UART16550_BASEADDR 0x83e00000
+#define AXIENET_BASEADDR 0x82780000
+#define AXIDMA_BASEADDR 0x84600000
+
+static void machine_cpu_reset(MicroBlazeCPU *cpu)
+{
+    CPUMBState *env = &cpu->env;
+
+    env->pvr.regs[10] = 0x0e000000; /* virtex 6 */
+    /* setup pvr to match kernel setting */
+    env->pvr.regs[5] |= PVR5_DCACHE_WRITEBACK_MASK;
+    env->pvr.regs[0] |= PVR0_USE_FPU_MASK | PVR0_ENDI;
+    env->pvr.regs[0] = (env->pvr.regs[0] & ~PVR0_VERSION_MASK) | (0x14 << 8);
+    env->pvr.regs[2] ^= PVR2_USE_FPU2_MASK;
+    env->pvr.regs[4] = 0xc56b8000;
+    env->pvr.regs[5] = 0xc56be000;
+}
+
+static void
+petalogix_ml605_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    MemoryRegion *address_space_mem = get_system_memory();
+    DeviceState *dev, *dma, *eth0;
+    MicroBlazeCPU *cpu;
+    SysBusDevice *busdev;
+    CPUMBState *env;
+    DriveInfo *dinfo;
+    int i;
+    hwaddr ddr_base = MEMORY_BASEADDR;
+    MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1);
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    qemu_irq irq[32], *cpu_irq;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "microblaze";
+    }
+    cpu = cpu_mb_init(cpu_model);
+    env = &cpu->env;
+
+    /* Attach emulated BRAM through the LMB.  */
+    memory_region_init_ram(phys_lmb_bram, "petalogix_ml605.lmb_bram",
+                           LMB_BRAM_SIZE);
+    vmstate_register_ram_global(phys_lmb_bram);
+    memory_region_add_subregion(address_space_mem, 0x00000000, phys_lmb_bram);
+
+    memory_region_init_ram(phys_ram, "petalogix_ml605.ram", ram_size);
+    vmstate_register_ram_global(phys_ram);
+    memory_region_add_subregion(address_space_mem, ddr_base, phys_ram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* 5th parameter 2 means bank-width
+     * 10th paremeter 0 means little-endian */
+    pflash_cfi01_register(FLASH_BASEADDR,
+                          NULL, "petalogix_ml605.flash", FLASH_SIZE,
+                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                          FLASH_SIZE >> 16,
+                          2, 0x89, 0x18, 0x0000, 0x0, 0);
+
+
+    cpu_irq = microblaze_pic_init_cpu(env);
+    dev = xilinx_intc_create(INTC_BASEADDR, cpu_irq[0], 4);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    serial_mm_init(address_space_mem, UART16550_BASEADDR + 0x1000, 2,
+                   irq[5], 115200, serial_hds[0], DEVICE_LITTLE_ENDIAN);
+
+    /* 2 timers at irq 2 @ 100 Mhz.  */
+    xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000);
+
+    /* axi ethernet and dma initialization. */
+    qemu_check_nic_model(&nd_table[0], "xlnx.axi-ethernet");
+    eth0 = qdev_create(NULL, "xlnx.axi-ethernet");
+    dma = qdev_create(NULL, "xlnx.axi-dma");
+
+    /* FIXME: attach to the sysbus instead */
+    object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
+                                  "xilinx-dma", OBJECT(dma), NULL);
+
+    xilinx_axiethernet_init(eth0, &nd_table[0], STREAM_SLAVE(dma),
+                                   0x82780000, irq[3], 0x1000, 0x1000);
+
+    xilinx_axidma_init(dma, STREAM_SLAVE(eth0), 0x84600000, irq[1], irq[0],
+                       100 * 1000000);
+
+    {
+        SSIBus *spi;
+
+        dev = qdev_create(NULL, "xlnx.xps-spi");
+        qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES);
+        qdev_init_nofail(dev);
+        busdev = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(busdev, 0, 0x40a00000);
+        sysbus_connect_irq(busdev, 0, irq[4]);
+
+        spi = (SSIBus *)qdev_get_child_bus(dev, "spi");
+
+        for (i = 0; i < NUM_SPI_FLASHES; i++) {
+            qemu_irq cs_line;
+
+            dev = ssi_create_slave_no_init(spi, "n25q128");
+            qdev_init_nofail(dev);
+            cs_line = qdev_get_gpio_in(dev, 0);
+            sysbus_connect_irq(busdev, i+1, cs_line);
+        }
+    }
+
+    microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE,
+                                                            machine_cpu_reset);
+
+}
+
+static QEMUMachine petalogix_ml605_machine = {
+    .name = "petalogix-ml605",
+    .desc = "PetaLogix linux refdesign for xilinx ml605 little endian",
+    .init = petalogix_ml605_init,
+    .is_default = 0,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void petalogix_ml605_machine_init(void)
+{
+    qemu_register_machine(&petalogix_ml605_machine);
+}
+
+machine_init(petalogix_ml605_machine_init);
diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c
new file mode 100644 (file)
index 0000000..2498362
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Model of Petalogix linux reference design targeting Xilinx Spartan 3ADSP-1800
+ * boards.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "net/net.h"
+#include "hw/flash.h"
+#include "sysemu/sysemu.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "hw/xilinx.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+#include "hw/microblaze_boot.h"
+#include "hw/microblaze_pic_cpu.h"
+
+#define LMB_BRAM_SIZE  (128 * 1024)
+#define FLASH_SIZE     (16 * 1024 * 1024)
+
+#define BINARY_DEVICE_TREE_FILE "petalogix-s3adsp1800.dtb"
+
+#define MEMORY_BASEADDR 0x90000000
+#define FLASH_BASEADDR 0xa0000000
+#define INTC_BASEADDR 0x81800000
+#define TIMER_BASEADDR 0x83c00000
+#define UARTLITE_BASEADDR 0x84000000
+#define ETHLITE_BASEADDR 0x81000000
+
+static void machine_cpu_reset(MicroBlazeCPU *cpu)
+{
+    CPUMBState *env = &cpu->env;
+
+    env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family.  */
+}
+
+static void
+petalogix_s3adsp1800_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    DeviceState *dev;
+    MicroBlazeCPU *cpu;
+    CPUMBState *env;
+    DriveInfo *dinfo;
+    int i;
+    hwaddr ddr_base = MEMORY_BASEADDR;
+    MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1);
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    qemu_irq irq[32], *cpu_irq;
+    MemoryRegion *sysmem = get_system_memory();
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "microblaze";
+    }
+    cpu = cpu_mb_init(cpu_model);
+    env = &cpu->env;
+
+    /* Attach emulated BRAM through the LMB.  */
+    memory_region_init_ram(phys_lmb_bram,
+                           "petalogix_s3adsp1800.lmb_bram", LMB_BRAM_SIZE);
+    vmstate_register_ram_global(phys_lmb_bram);
+    memory_region_add_subregion(sysmem, 0x00000000, phys_lmb_bram);
+
+    memory_region_init_ram(phys_ram, "petalogix_s3adsp1800.ram", ram_size);
+    vmstate_register_ram_global(phys_ram);
+    memory_region_add_subregion(sysmem, ddr_base, phys_ram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi01_register(FLASH_BASEADDR,
+                          NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE,
+                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                          FLASH_SIZE >> 16,
+                          1, 0x89, 0x18, 0x0000, 0x0, 1);
+
+    cpu_irq = microblaze_pic_init_cpu(env);
+    dev = xilinx_intc_create(INTC_BASEADDR, cpu_irq[0], 2);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR, irq[3]);
+    /* 2 timers at irq 2 @ 62 Mhz.  */
+    xilinx_timer_create(TIMER_BASEADDR, irq[0], 0, 62 * 1000000);
+    xilinx_ethlite_create(&nd_table[0], ETHLITE_BASEADDR, irq[1], 0, 0);
+
+    microblaze_load_kernel(cpu, ddr_base, ram_size,
+                    BINARY_DEVICE_TREE_FILE, machine_cpu_reset);
+}
+
+static QEMUMachine petalogix_s3adsp1800_machine = {
+    .name = "petalogix-s3adsp1800",
+    .desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800",
+    .init = petalogix_s3adsp1800_init,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void petalogix_s3adsp1800_machine_init(void)
+{
+    qemu_register_machine(&petalogix_s3adsp1800_machine);
+}
+
+machine_init(petalogix_s3adsp1800_machine_init);
diff --git a/hw/microblaze/pic_cpu.c b/hw/microblaze/pic_cpu.c
new file mode 100644 (file)
index 0000000..d4743ab
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * QEMU MicroBlaze CPU interrupt wrapper logic.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/microblaze_pic_cpu.h"
+
+#define D(x)
+
+static void microblaze_pic_cpu_handler(void *opaque, int irq, int level)
+{
+    CPUMBState *env = (CPUMBState *)opaque;
+    int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
+
+    if (level)
+        cpu_interrupt(env, type);
+    else
+        cpu_reset_interrupt(env, type);
+}
+
+qemu_irq *microblaze_pic_init_cpu(CPUMBState *env)
+{
+    return qemu_allocate_irqs(microblaze_pic_cpu_handler, env, 2);
+}
diff --git a/hw/microblaze_boot.c b/hw/microblaze_boot.c
deleted file mode 100644 (file)
index e13b3e1..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Microblaze kernel loader
- *
- * Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@petalogix.com>
- * Copyright (c) 2012 PetaLogix
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/option.h"
-#include "qemu/config-file.h"
-#include "qemu-common.h"
-#include "sysemu/device_tree.h"
-#include "hw/loader.h"
-#include "elf.h"
-
-#include "hw/microblaze_boot.h"
-
-static struct
-{
-    void (*machine_cpu_reset)(MicroBlazeCPU *);
-    uint32_t bootstrap_pc;
-    uint32_t cmdline;
-    uint32_t fdt;
-} boot_info;
-
-static void main_cpu_reset(void *opaque)
-{
-    MicroBlazeCPU *cpu = opaque;
-    CPUMBState *env = &cpu->env;
-
-    cpu_reset(CPU(cpu));
-    env->regs[5] = boot_info.cmdline;
-    env->regs[7] = boot_info.fdt;
-    env->sregs[SR_PC] = boot_info.bootstrap_pc;
-    if (boot_info.machine_cpu_reset) {
-        boot_info.machine_cpu_reset(cpu);
-    }
-}
-
-static int microblaze_load_dtb(hwaddr addr,
-                                      uint32_t ramsize,
-                                      const char *kernel_cmdline,
-                                      const char *dtb_filename)
-{
-    int fdt_size;
-#ifdef CONFIG_FDT
-    void *fdt = NULL;
-    int r;
-
-    if (dtb_filename) {
-        fdt = load_device_tree(dtb_filename, &fdt_size);
-    }
-    if (!fdt) {
-        return 0;
-    }
-
-    if (kernel_cmdline) {
-        r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
-                                                        kernel_cmdline);
-        if (r < 0) {
-            fprintf(stderr, "couldn't set /chosen/bootargs\n");
-        }
-    }
-
-    cpu_physical_memory_write(addr, (void *)fdt, fdt_size);
-#else
-    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
-       to the kernel.  */
-    if (dtb_filename) {
-        fdt_size = load_image_targphys(dtb_filename, addr, 0x10000);
-    }
-    if (kernel_cmdline) {
-        fprintf(stderr,
-                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
-    }
-#endif
-    return fdt_size;
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
-    return addr - 0x30000000LL;
-}
-
-void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
-                            uint32_t ramsize, const char *dtb_filename,
-                            void (*machine_cpu_reset)(MicroBlazeCPU *))
-{
-    QemuOpts *machine_opts;
-    const char *kernel_filename = NULL;
-    const char *kernel_cmdline = NULL;
-
-    machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
-    if (machine_opts) {
-        const char *dtb_arg;
-        kernel_filename = qemu_opt_get(machine_opts, "kernel");
-        kernel_cmdline = qemu_opt_get(machine_opts, "append");
-        dtb_arg = qemu_opt_get(machine_opts, "dtb");
-        if (dtb_arg) { /* Preference a -dtb argument */
-            dtb_filename = dtb_arg;
-        } else { /* default to pcbios dtb as passed by machine_init */
-            dtb_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename);
-        }
-    }
-
-    boot_info.machine_cpu_reset = machine_cpu_reset;
-    qemu_register_reset(main_cpu_reset, cpu);
-
-    if (kernel_filename) {
-        int kernel_size;
-        uint64_t entry, low, high;
-        uint32_t base32;
-        int big_endian = 0;
-
-#ifdef TARGET_WORDS_BIGENDIAN
-        big_endian = 1;
-#endif
-
-        /* Boots a kernel elf binary.  */
-        kernel_size = load_elf(kernel_filename, NULL, NULL,
-                               &entry, &low, &high,
-                               big_endian, ELF_MACHINE, 0);
-        base32 = entry;
-        if (base32 == 0xc0000000) {
-            kernel_size = load_elf(kernel_filename, translate_kernel_address,
-                                   NULL, &entry, NULL, NULL,
-                                   big_endian, ELF_MACHINE, 0);
-        }
-        /* Always boot into physical ram.  */
-        boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff);
-
-        /* If it wasn't an ELF image, try an u-boot image.  */
-        if (kernel_size < 0) {
-            hwaddr uentry, loadaddr;
-
-            kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0);
-            boot_info.bootstrap_pc = uentry;
-            high = (loadaddr + kernel_size + 3) & ~3;
-        }
-
-        /* Not an ELF image nor an u-boot image, try a RAW image.  */
-        if (kernel_size < 0) {
-            kernel_size = load_image_targphys(kernel_filename, ddr_base,
-                                              ram_size);
-            boot_info.bootstrap_pc = ddr_base;
-            high = (ddr_base + kernel_size + 3) & ~3;
-        }
-
-        boot_info.cmdline = high + 4096;
-        if (kernel_cmdline && strlen(kernel_cmdline)) {
-            pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline);
-        }
-        /* Provide a device-tree.  */
-        boot_info.fdt = boot_info.cmdline + 4096;
-        microblaze_load_dtb(boot_info.fdt, ram_size, kernel_cmdline,
-                                                     dtb_filename);
-    }
-
-}
diff --git a/hw/microblaze_pic_cpu.c b/hw/microblaze_pic_cpu.c
deleted file mode 100644 (file)
index d4743ab..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * QEMU MicroBlaze CPU interrupt wrapper logic.
- *
- * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/hw.h"
-#include "hw/microblaze_pic_cpu.h"
-
-#define D(x)
-
-static void microblaze_pic_cpu_handler(void *opaque, int irq, int level)
-{
-    CPUMBState *env = (CPUMBState *)opaque;
-    int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
-
-    if (level)
-        cpu_interrupt(env, type);
-    else
-        cpu_reset_interrupt(env, type);
-}
-
-qemu_irq *microblaze_pic_init_cpu(CPUMBState *env)
-{
-    return qemu_allocate_irqs(microblaze_pic_cpu_handler, env, 2);
-}
diff --git a/hw/milkymist.c b/hw/milkymist.c
deleted file mode 100644 (file)
index fd36de5..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- *  QEMU model for the Milkymist board.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/flash.h"
-#include "sysemu/sysemu.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/blockdev.h"
-#include "hw/milkymist-hw.h"
-#include "hw/lm32.h"
-#include "exec/address-spaces.h"
-
-#define BIOS_FILENAME    "mmone-bios.bin"
-#define BIOS_OFFSET      0x00860000
-#define BIOS_SIZE        (512*1024)
-#define KERNEL_LOAD_ADDR 0x40000000
-
-typedef struct {
-    LM32CPU *cpu;
-    hwaddr bootstrap_pc;
-    hwaddr flash_base;
-    hwaddr initrd_base;
-    size_t initrd_size;
-    hwaddr cmdline_base;
-} ResetInfo;
-
-static void cpu_irq_handler(void *opaque, int irq, int level)
-{
-    CPULM32State *env = opaque;
-
-    if (level) {
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
-    } else {
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
-}
-
-static void main_cpu_reset(void *opaque)
-{
-    ResetInfo *reset_info = opaque;
-    CPULM32State *env = &reset_info->cpu->env;
-
-    cpu_reset(CPU(reset_info->cpu));
-
-    /* init defaults */
-    env->pc = reset_info->bootstrap_pc;
-    env->regs[R_R1] = reset_info->cmdline_base;
-    env->regs[R_R2] = reset_info->initrd_base;
-    env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size;
-    env->eba = reset_info->flash_base;
-    env->deba = reset_info->flash_base;
-}
-
-static void
-milkymist_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    LM32CPU *cpu;
-    CPULM32State *env;
-    int kernel_size;
-    DriveInfo *dinfo;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *phys_sdram = g_new(MemoryRegion, 1);
-    qemu_irq irq[32], *cpu_irq;
-    int i;
-    char *bios_filename;
-    ResetInfo *reset_info;
-
-    /* memory map */
-    hwaddr flash_base   = 0x00000000;
-    size_t flash_sector_size        = 128 * 1024;
-    size_t flash_size               = 32 * 1024 * 1024;
-    hwaddr sdram_base   = 0x40000000;
-    size_t sdram_size               = 128 * 1024 * 1024;
-
-    hwaddr initrd_base  = sdram_base + 0x1002000;
-    hwaddr cmdline_base = sdram_base + 0x1000000;
-    size_t initrd_max = sdram_size - 0x1002000;
-
-    reset_info = g_malloc0(sizeof(ResetInfo));
-
-    if (cpu_model == NULL) {
-        cpu_model = "lm32-full";
-    }
-    cpu = cpu_lm32_init(cpu_model);
-    env = &cpu->env;
-    reset_info->cpu = cpu;
-
-    cpu_lm32_set_phys_msb_ignore(env, 1);
-
-    memory_region_init_ram(phys_sdram, "milkymist.sdram", sdram_size);
-    vmstate_register_ram_global(phys_sdram);
-    memory_region_add_subregion(address_space_mem, sdram_base, phys_sdram);
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    /* Numonyx JS28F256J3F105 */
-    pflash_cfi01_register(flash_base, NULL, "milkymist.flash", flash_size,
-                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
-                          flash_size / flash_sector_size, 2,
-                          0x00, 0x89, 0x00, 0x1d, 1);
-
-    /* create irq lines */
-    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
-    env->pic_state = lm32_pic_init(*cpu_irq);
-    for (i = 0; i < 32; i++) {
-        irq[i] = qdev_get_gpio_in(env->pic_state, i);
-    }
-
-    /* load bios rom */
-    if (bios_name == NULL) {
-        bios_name = BIOS_FILENAME;
-    }
-    bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-
-    if (bios_filename) {
-        load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE);
-    }
-
-    reset_info->bootstrap_pc = BIOS_OFFSET;
-
-    /* if no kernel is given no valid bios rom is a fatal error */
-    if (!kernel_filename && !dinfo && !bios_filename) {
-        fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n",
-                bios_name);
-        exit(1);
-    }
-
-    milkymist_uart_create(0x60000000, irq[0]);
-    milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3],
-            80000000, 0x10014d31, 0x0000041f, 0x00000001);
-    milkymist_hpdmc_create(0x60002000);
-    milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);
-    milkymist_memcard_create(0x60004000);
-    milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]);
-    milkymist_pfpu_create(0x60006000, irq[8]);
-    milkymist_tmu2_create(0x60007000, irq[9]);
-    milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]);
-    milkymist_softusb_create(0x6000f000, irq[15],
-            0x20000000, 0x1000, 0x20020000, 0x2000);
-
-    /* make sure juart isn't the first chardev */
-    env->juart_state = lm32_juart_init();
-
-    if (kernel_filename) {
-        uint64_t entry;
-
-        /* Boots a kernel elf binary.  */
-        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
-                               1, ELF_MACHINE, 0);
-        reset_info->bootstrap_pc = entry;
-
-        if (kernel_size < 0) {
-            kernel_size = load_image_targphys(kernel_filename, sdram_base,
-                                              sdram_size);
-            reset_info->bootstrap_pc = sdram_base;
-        }
-
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-    }
-
-    if (kernel_cmdline && strlen(kernel_cmdline)) {
-        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
-                kernel_cmdline);
-        reset_info->cmdline_base = (uint32_t)cmdline_base;
-    }
-
-    if (initrd_filename) {
-        size_t initrd_size;
-        initrd_size = load_image_targphys(initrd_filename, initrd_base,
-                initrd_max);
-        reset_info->initrd_base = (uint32_t)initrd_base;
-        reset_info->initrd_size = (uint32_t)initrd_size;
-    }
-
-    qemu_register_reset(main_cpu_reset, reset_info);
-}
-
-static QEMUMachine milkymist_machine = {
-    .name = "milkymist",
-    .desc = "Milkymist One",
-    .init = milkymist_init,
-    .is_default = 0,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void milkymist_machine_init(void)
-{
-    qemu_register_machine(&milkymist_machine);
-}
-
-machine_init(milkymist_machine_init);
index 29a5d0db049a88e90b250ee7b757d055d104e0b7..1e3bca1c373785a3bf5542eb99a2e261e5a87080 100644 (file)
@@ -1,6 +1,8 @@
-obj-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
-obj-y += mips_addr.o mips_timer.o mips_int.o
 obj-y += gt64xxx.o mc146818rtc.o
-obj-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
+obj-$(CONFIG_FULONG) += bonito.o vt82c686.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-y += mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
+obj-y += addr.o cputimer.o mips_int.o
+obj-$(CONFIG_FULONG) += mips_fulong2e.o
diff --git a/hw/mips/addr.c b/hw/mips/addr.c
new file mode 100644 (file)
index 0000000..cddc25c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * QEMU MIPS address translation support
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/mips_cpudevs.h"
+
+uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
+{
+    return addr & 0x7fffffffll;
+}
+
+uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr)
+{
+    return addr | ~0x7fffffffll;
+}
diff --git a/hw/mips/cputimer.c b/hw/mips/cputimer.c
new file mode 100644 (file)
index 0000000..9ad13f3
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * QEMU MIPS timer support
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/mips_cpudevs.h"
+#include "qemu/timer.h"
+
+#define TIMER_FREQ     100 * 1000 * 1000
+
+/* XXX: do not use a global */
+uint32_t cpu_mips_get_random (CPUMIPSState *env)
+{
+    static uint32_t lfsr = 1;
+    static uint32_t prev_idx = 0;
+    uint32_t idx;
+    /* Don't return same value twice, so get another value */
+    do {
+        lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u);
+        idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
+    } while (idx == prev_idx);
+    prev_idx = idx;
+    return idx;
+}
+
+/* MIPS R4K timer */
+static void cpu_mips_timer_update(CPUMIPSState *env)
+{
+    uint64_t now, next;
+    uint32_t wait;
+
+    now = qemu_get_clock_ns(vm_clock);
+    wait = env->CP0_Compare - env->CP0_Count -
+           (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
+    next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
+    qemu_mod_timer(env->timer, next);
+}
+
+/* Expire the timer.  */
+static void cpu_mips_timer_expire(CPUMIPSState *env)
+{
+    cpu_mips_timer_update(env);
+    if (env->insn_flags & ISA_MIPS32R2) {
+        env->CP0_Cause |= 1 << CP0Ca_TI;
+    }
+    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+}
+
+uint32_t cpu_mips_get_count (CPUMIPSState *env)
+{
+    if (env->CP0_Cause & (1 << CP0Ca_DC)) {
+        return env->CP0_Count;
+    } else {
+        uint64_t now;
+
+        now = qemu_get_clock_ns(vm_clock);
+        if (qemu_timer_pending(env->timer)
+            && qemu_timer_expired(env->timer, now)) {
+            /* The timer has already expired.  */
+            cpu_mips_timer_expire(env);
+        }
+
+        return env->CP0_Count +
+            (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
+    }
+}
+
+void cpu_mips_store_count (CPUMIPSState *env, uint32_t count)
+{
+    if (env->CP0_Cause & (1 << CP0Ca_DC))
+        env->CP0_Count = count;
+    else {
+        /* Store new count register */
+        env->CP0_Count =
+            count - (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock),
+                                       TIMER_FREQ, get_ticks_per_sec());
+        /* Update timer timer */
+        cpu_mips_timer_update(env);
+    }
+}
+
+void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value)
+{
+    env->CP0_Compare = value;
+    if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
+        cpu_mips_timer_update(env);
+    if (env->insn_flags & ISA_MIPS32R2)
+        env->CP0_Cause &= ~(1 << CP0Ca_TI);
+    qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+}
+
+void cpu_mips_start_count(CPUMIPSState *env)
+{
+    cpu_mips_store_count(env, env->CP0_Count);
+}
+
+void cpu_mips_stop_count(CPUMIPSState *env)
+{
+    /* Store the current value */
+    env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock),
+                                         TIMER_FREQ, get_ticks_per_sec());
+}
+
+static void mips_timer_cb (void *opaque)
+{
+    CPUMIPSState *env;
+
+    env = opaque;
+#if 0
+    qemu_log("%s\n", __func__);
+#endif
+
+    if (env->CP0_Cause & (1 << CP0Ca_DC))
+        return;
+
+    /* ??? This callback should occur when the counter is exactly equal to
+       the comparator value.  Offset the count by one to avoid immediately
+       retriggering the callback before any virtual time has passed.  */
+    env->CP0_Count++;
+    cpu_mips_timer_expire(env);
+    env->CP0_Count--;
+}
+
+void cpu_mips_clock_init (CPUMIPSState *env)
+{
+    env->timer = qemu_new_timer_ns(vm_clock, &mips_timer_cb, env);
+    env->CP0_Compare = 0;
+    cpu_mips_store_count(env, 1);
+}
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c
new file mode 100644 (file)
index 0000000..766aa9d
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * QEMU fulong 2e mini pc support
+ *
+ * Copyright (c) 2008 yajin (yajin@vm-kernel.org)
+ * Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn)
+ * Copyright (c) 2010 Huacai Chen (zltjiangshi@gmail.com)
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+/*
+ * Fulong 2e mini pc is based on ICT/ST Loongson 2e CPU (MIPS III like, 800MHz)
+ * http://www.linux-mips.org/wiki/Fulong
+ *
+ * Loongson 2e user manual:
+ * http://www.loongsondeveloper.com/doc/Loongson2EUserGuide.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/serial.h"
+#include "hw/fdc.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "hw/smbus.h"
+#include "block/block.h"
+#include "hw/flash.h"
+#include "hw/mips.h"
+#include "hw/mips_cpudevs.h"
+#include "hw/pci/pci.h"
+#include "char/char.h"
+#include "sysemu/sysemu.h"
+#include "audio/audio.h"
+#include "qemu/log.h"
+#include "hw/loader.h"
+#include "hw/mips-bios.h"
+#include "hw/ide.h"
+#include "elf.h"
+#include "hw/vt82c686.h"
+#include "hw/mc146818rtc.h"
+#include "hw/i8254.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+#define DEBUG_FULONG2E_INIT
+
+#define ENVP_ADDR       0x80002000l
+#define ENVP_NB_ENTRIES                16
+#define ENVP_ENTRY_SIZE                256
+
+#define MAX_IDE_BUS 2
+
+/*
+ * PMON is not part of qemu and released with BSD license, anyone
+ * who want to build a pmon binary please first git-clone the source
+ * from the git repository at:
+ * http://www.loongson.cn/support/git/pmon
+ * Then follow the "Compile Guide" available at:
+ * http://dev.lemote.com/code/pmon
+ *
+ * Notes:
+ * 1, don't use the source at http://dev.lemote.com/http_git/pmon.git
+ * 2, use "Bonito2edev" to replace "dir_corresponding_to_your_target_hardware"
+ * in the "Compile Guide".
+ */
+#define FULONG_BIOSNAME "pmon_fulong2e.bin"
+
+/* PCI SLOT in fulong 2e */
+#define FULONG2E_VIA_SLOT        5
+#define FULONG2E_ATI_SLOT        6
+#define FULONG2E_RTL8139_SLOT    7
+
+static ISADevice *pit;
+
+static struct _loaderparams {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
+                                        const char *string, ...)
+{
+    va_list ap;
+    int32_t table_addr;
+
+    if (index >= ENVP_NB_ENTRIES)
+        return;
+
+    if (string == NULL) {
+        prom_buf[index] = 0;
+        return;
+    }
+
+    table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
+    prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
+
+    va_start(ap, string);
+    vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
+    va_end(ap);
+}
+
+static int64_t load_kernel (CPUMIPSState *env)
+{
+    int64_t kernel_entry, kernel_low, kernel_high;
+    int index = 0;
+    long initrd_size;
+    ram_addr_t initrd_offset;
+    uint32_t *prom_buf;
+    long prom_size;
+
+    if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
+                 (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
+                 (uint64_t *)&kernel_high, 0, ELF_MACHINE, 1) < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                loaderparams.kernel_filename);
+        exit(1);
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    initrd_offset = 0;
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size (loaderparams.initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+            if (initrd_offset + initrd_size > ram_size) {
+                fprintf(stderr,
+                        "qemu: memory too small for initial ram disk '%s'\n",
+                        loaderparams.initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                                     initrd_offset, ram_size - initrd_offset);
+        }
+        if (initrd_size == (target_ulong) -1) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+
+    /* Setup prom parameters. */
+    prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
+    prom_buf = g_malloc(prom_size);
+
+    prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename);
+    if (initrd_size > 0) {
+        prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
+                 cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
+                 loaderparams.kernel_cmdline);
+    } else {
+        prom_set(prom_buf, index++, "%s", loaderparams.kernel_cmdline);
+    }
+
+    /* Setup minimum environment variables */
+    prom_set(prom_buf, index++, "busclock=33000000");
+    prom_set(prom_buf, index++, "cpuclock=100000000");
+    prom_set(prom_buf, index++, "memsize=%i", loaderparams.ram_size/1024/1024);
+    prom_set(prom_buf, index++, "modetty0=38400n8r");
+    prom_set(prom_buf, index++, NULL);
+
+    rom_add_blob_fixed("prom", prom_buf, prom_size,
+                       cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
+
+    return kernel_entry;
+}
+
+static void write_bootloader (CPUMIPSState *env, uint8_t *base, int64_t kernel_addr)
+{
+    uint32_t *p;
+
+    /* Small bootloader */
+    p = (uint32_t *) base;
+
+    stl_raw(p++, 0x0bf00010);                                      /* j 0x1fc00040 */
+    stl_raw(p++, 0x00000000);                                      /* nop */
+
+    /* Second part of the bootloader */
+    p = (uint32_t *) (base + 0x040);
+
+    stl_raw(p++, 0x3c040000);                                      /* lui a0, 0 */
+    stl_raw(p++, 0x34840002);                                      /* ori a0, a0, 2 */
+    stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
+    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a0, low(ENVP_ADDR) */
+    stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
+    stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
+    stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16));      /* lui a3, high(env->ram_size) */
+    stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff));   /* ori a3, a3, low(env->ram_size) */
+    stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff));     /* lui ra, high(kernel_addr) */;
+    stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff));             /* ori ra, ra, low(kernel_addr) */
+    stl_raw(p++, 0x03e00008);                                      /* jr ra */
+    stl_raw(p++, 0x00000000);                                      /* nop */
+}
+
+
+static void main_cpu_reset(void *opaque)
+{
+    MIPSCPU *cpu = opaque;
+    CPUMIPSState *env = &cpu->env;
+
+    cpu_reset(CPU(cpu));
+    /* TODO: 2E reset stuff */
+    if (loaderparams.kernel_filename) {
+        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
+    }
+}
+
+uint8_t eeprom_spd[0x80] = {
+    0x80,0x08,0x07,0x0d,0x09,0x02,0x40,0x00,0x04,0x70,
+    0x70,0x00,0x82,0x10,0x00,0x01,0x0e,0x04,0x0c,0x01,
+    0x02,0x20,0x80,0x75,0x70,0x00,0x00,0x50,0x3c,0x50,
+    0x2d,0x20,0xb0,0xb0,0x50,0x50,0x00,0x00,0x00,0x00,
+    0x00,0x41,0x48,0x3c,0x32,0x75,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x9c,0x7b,0x07,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x48,0x42,0x35,0x34,0x41,0x32,
+    0x35,0x36,0x38,0x4b,0x4e,0x2d,0x41,0x37,0x35,0x42,
+    0x20,0x30,0x20
+};
+
+/* Audio support */
+static void audio_init (PCIBus *pci_bus)
+{
+    vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5));
+    vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6));
+}
+
+/* Network support */
+static void network_init (void)
+{
+    int i;
+
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+        const char *default_devaddr = NULL;
+
+        if (i == 0 && (!nd->model || strcmp(nd->model, "rtl8139") == 0)) {
+            /* The fulong board has a RTL8139 card using PCI SLOT 7 */
+            default_devaddr = "07";
+        }
+
+        pci_nic_init_nofail(nd, "rtl8139", default_devaddr);
+    }
+}
+
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+    CPUMIPSState *env = cpu_single_env;
+
+    if (env && level) {
+        cpu_exit(env);
+    }
+}
+
+static void mips_fulong2e_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    char *filename;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
+    long bios_size;
+    int64_t kernel_entry;
+    qemu_irq *i8259;
+    qemu_irq *cpu_exit_irq;
+    PCIBus *pci_bus;
+    ISABus *isa_bus;
+    i2c_bus *smbus;
+    int i;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    MIPSCPU *cpu;
+    CPUMIPSState *env;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "Loongson-2E";
+    }
+    cpu = cpu_mips_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    env = &cpu->env;
+
+    qemu_register_reset(main_cpu_reset, cpu);
+
+    /* fulong 2e has 256M ram. */
+    ram_size = 256 * 1024 * 1024;
+
+    /* fulong 2e has a 1M flash.Winbond W39L040AP70Z */
+    bios_size = 1024 * 1024;
+
+    /* allocate RAM */
+    memory_region_init_ram(ram, "fulong2e.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_init_ram(bios, "fulong2e.bios", bios_size);
+    vmstate_register_ram_global(bios);
+    memory_region_set_readonly(bios, true);
+
+    memory_region_add_subregion(address_space_mem, 0, ram);
+    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
+
+    /* We do not support flash operation, just loading pmon.bin as raw BIOS.
+     * Please use -L to set the BIOS path and -bios to set bios name. */
+
+    if (kernel_filename) {
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        kernel_entry = load_kernel (env);
+        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
+    } else {
+        if (bios_name == NULL) {
+                bios_name = FULONG_BIOSNAME;
+        }
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        if (filename) {
+            bios_size = load_image_targphys(filename, 0x1fc00000LL,
+                                            BIOS_SIZE);
+            g_free(filename);
+        } else {
+            bios_size = -1;
+        }
+
+        if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
+            fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", bios_name);
+            exit(1);
+        }
+    }
+
+    /* Init internal devices */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+
+    /* North bridge, Bonito --> IP2 */
+    pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));
+
+    /* South bridge */
+    ide_drive_get(hd, MAX_IDE_BUS);
+
+    isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
+    if (!isa_bus) {
+        fprintf(stderr, "vt82c686b_init error\n");
+        exit(1);
+    }
+
+    /* Interrupt controller */
+    /* The 8259 -> IP5  */
+    i8259 = i8259_init(isa_bus, env->irq[5]);
+    isa_bus_irqs(isa_bus, i8259);
+
+    vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1));
+    pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2),
+                      "vt82c686b-usb-uhci");
+    pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3),
+                      "vt82c686b-usb-uhci");
+
+    smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4),
+                              0xeee1, NULL);
+    /* TODO: Populate SPD eeprom data.  */
+    smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd));
+
+    /* init other devices */
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    DMA_init(0, cpu_exit_irq);
+
+    /* Super I/O */
+    isa_create_simple(isa_bus, "i8042");
+
+    rtc_init(isa_bus, 2000, NULL);
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_isa_init(isa_bus, i, serial_hds[i]);
+        }
+    }
+
+    if (parallel_hds[0]) {
+        parallel_init(isa_bus, 0, parallel_hds[0]);
+    }
+
+    /* Sound card */
+    audio_init(pci_bus);
+    /* Network card */
+    network_init();
+}
+
+static QEMUMachine mips_fulong2e_machine = {
+    .name = "fulong2e",
+    .desc = "Fulong 2e mini pc",
+    .init = mips_fulong2e_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void mips_fulong2e_machine_init(void)
+{
+    qemu_register_machine(&mips_fulong2e_machine);
+}
+
+machine_init(mips_fulong2e_machine_init);
diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c
new file mode 100644 (file)
index 0000000..ddd3b1b
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * QEMU MIPS interrupt support
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/mips_cpudevs.h"
+#include "cpu.h"
+
+static void cpu_mips_irq_request(void *opaque, int irq, int level)
+{
+    CPUMIPSState *env = (CPUMIPSState *)opaque;
+
+    if (irq < 0 || irq > 7)
+        return;
+
+    if (level) {
+        env->CP0_Cause |= 1 << (irq + CP0Ca_IP);
+    } else {
+        env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP));
+    }
+
+    if (env->CP0_Cause & CP0Ca_IP_mask) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+void cpu_mips_irq_init_cpu(CPUMIPSState *env)
+{
+    qemu_irq *qi;
+    int i;
+
+    qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8);
+    for (i = 0; i < 8; i++) {
+        env->irq[i] = qi[i];
+    }
+}
+
+void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level)
+{
+    if (irq < 0 || irq > 2) {
+        return;
+    }
+
+    qemu_set_irq(env->irq[irq], level);
+}
diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c
new file mode 100644 (file)
index 0000000..daeb985
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * QEMU MIPS Jazz support
+ *
+ * Copyright (c) 2007-2008 Hervé Poussineau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/mips.h"
+#include "hw/mips_cpudevs.h"
+#include "hw/pc.h"
+#include "hw/serial.h"
+#include "hw/isa.h"
+#include "hw/fdc.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/arch_init.h"
+#include "hw/boards.h"
+#include "net/net.h"
+#include "hw/esp.h"
+#include "hw/mips-bios.h"
+#include "hw/loader.h"
+#include "hw/mc146818rtc.h"
+#include "hw/i8254.h"
+#include "hw/pcspk.h"
+#include "sysemu/blockdev.h"
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+
+enum jazz_model_e
+{
+    JAZZ_MAGNUM,
+    JAZZ_PICA61,
+};
+
+static void main_cpu_reset(void *opaque)
+{
+    MIPSCPU *cpu = opaque;
+
+    cpu_reset(CPU(cpu));
+}
+
+static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return cpu_inw(0x71);
+}
+
+static void rtc_write(void *opaque, hwaddr addr,
+                      uint64_t val, unsigned size)
+{
+    cpu_outw(0x71, val & 0xff);
+}
+
+static const MemoryRegionOps rtc_ops = {
+    .read = rtc_read,
+    .write = rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t dma_dummy_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    /* Nothing to do. That is only to ensure that
+     * the current DMA acknowledge cycle is completed. */
+    return 0xff;
+}
+
+static void dma_dummy_write(void *opaque, hwaddr addr,
+                            uint64_t val, unsigned size)
+{
+    /* Nothing to do. That is only to ensure that
+     * the current DMA acknowledge cycle is completed. */
+}
+
+static const MemoryRegionOps dma_dummy_ops = {
+    .read = dma_dummy_read,
+    .write = dma_dummy_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+#define MAGNUM_BIOS_SIZE_MAX 0x7e000
+#define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX)
+
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+    CPUMIPSState *env = cpu_single_env;
+
+    if (env && level) {
+        cpu_exit(env);
+    }
+}
+
+static void mips_jazz_init(MemoryRegion *address_space,
+                           MemoryRegion *address_space_io,
+                           ram_addr_t ram_size,
+                           const char *cpu_model,
+                           enum jazz_model_e jazz_model)
+{
+    char *filename;
+    int bios_size, n;
+    MIPSCPU *cpu;
+    CPUMIPSState *env;
+    qemu_irq *rc4030, *i8259;
+    rc4030_dma *dmas;
+    void* rc4030_opaque;
+    MemoryRegion *rtc = g_new(MemoryRegion, 1);
+    MemoryRegion *i8042 = g_new(MemoryRegion, 1);
+    MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
+    NICInfo *nd;
+    DeviceState *dev;
+    SysBusDevice *sysbus;
+    ISABus *isa_bus;
+    ISADevice *pit;
+    DriveInfo *fds[MAX_FD];
+    qemu_irq esp_reset, dma_enable;
+    qemu_irq *cpu_exit_irq;
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
+    MemoryRegion *bios2 = g_new(MemoryRegion, 1);
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "R4000";
+#else
+        /* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */
+        cpu_model = "24Kf";
+#endif
+    }
+    cpu = cpu_mips_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    env = &cpu->env;
+    qemu_register_reset(main_cpu_reset, cpu);
+
+    /* allocate RAM */
+    memory_region_init_ram(ram, "mips_jazz.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(address_space, 0, ram);
+
+    memory_region_init_ram(bios, "mips_jazz.bios", MAGNUM_BIOS_SIZE);
+    vmstate_register_ram_global(bios);
+    memory_region_set_readonly(bios, true);
+    memory_region_init_alias(bios2, "mips_jazz.bios", bios,
+                             0, MAGNUM_BIOS_SIZE);
+    memory_region_add_subregion(address_space, 0x1fc00000LL, bios);
+    memory_region_add_subregion(address_space, 0xfff00000LL, bios2);
+
+    /* load the BIOS image. */
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = load_image_targphys(filename, 0xfff00000LL,
+                                        MAGNUM_BIOS_SIZE);
+        g_free(filename);
+    } else {
+        bios_size = -1;
+    }
+    if (bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) {
+        fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n",
+                bios_name);
+        exit(1);
+    }
+
+    /* Init CPU internal devices */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+
+    /* Chipset */
+    rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas,
+                                address_space);
+    memory_region_init_io(dma_dummy, &dma_dummy_ops, NULL, "dummy_dma", 0x1000);
+    memory_region_add_subregion(address_space, 0x8000d000, dma_dummy);
+
+    /* ISA devices */
+    isa_bus = isa_bus_new(NULL, address_space_io);
+    i8259 = i8259_init(isa_bus, env->irq[4]);
+    isa_bus_irqs(isa_bus, i8259);
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    DMA_init(0, cpu_exit_irq);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
+    pcspk_init(isa_bus, pit);
+
+    /* ISA IO space at 0x90000000 */
+    isa_mmio_init(0x90000000, 0x01000000);
+    isa_mem_base = 0x11000000;
+
+    /* Video card */
+    switch (jazz_model) {
+    case JAZZ_MAGNUM:
+        dev = qdev_create(NULL, "sysbus-g364");
+        qdev_init_nofail(dev);
+        sysbus = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(sysbus, 0, 0x60080000);
+        sysbus_mmio_map(sysbus, 1, 0x40000000);
+        sysbus_connect_irq(sysbus, 0, rc4030[3]);
+        {
+            /* Simple ROM, so user doesn't have to provide one */
+            MemoryRegion *rom_mr = g_new(MemoryRegion, 1);
+            memory_region_init_ram(rom_mr, "g364fb.rom", 0x80000);
+            vmstate_register_ram_global(rom_mr);
+            memory_region_set_readonly(rom_mr, true);
+            uint8_t *rom = memory_region_get_ram_ptr(rom_mr);
+            memory_region_add_subregion(address_space, 0x60000000, rom_mr);
+            rom[0] = 0x10; /* Mips G364 */
+        }
+        break;
+    case JAZZ_PICA61:
+        isa_vga_mm_init(0x40000000, 0x60000000, 0, get_system_memory());
+        break;
+    default:
+        break;
+    }
+
+    /* Network controller */
+    for (n = 0; n < nb_nics; n++) {
+        nd = &nd_table[n];
+        if (!nd->model)
+            nd->model = g_strdup("dp83932");
+        if (strcmp(nd->model, "dp83932") == 0) {
+            dp83932_init(nd, 0x80001000, 2, get_system_memory(), rc4030[4],
+                         rc4030_opaque, rc4030_dma_memory_rw);
+            break;
+        } else if (is_help_option(nd->model)) {
+            fprintf(stderr, "qemu: Supported NICs: dp83932\n");
+            exit(1);
+        } else {
+            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
+            exit(1);
+        }
+    }
+
+    /* SCSI adapter */
+    esp_init(0x80002000, 0,
+             rc4030_dma_read, rc4030_dma_write, dmas[0],
+             rc4030[5], &esp_reset, &dma_enable);
+
+    /* Floppy */
+    if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) {
+        fprintf(stderr, "qemu: too many floppy drives\n");
+        exit(1);
+    }
+    for (n = 0; n < MAX_FD; n++) {
+        fds[n] = drive_get(IF_FLOPPY, 0, n);
+    }
+    fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds);
+
+    /* Real time clock */
+    rtc_init(isa_bus, 1980, NULL);
+    memory_region_init_io(rtc, &rtc_ops, NULL, "rtc", 0x1000);
+    memory_region_add_subregion(address_space, 0x80004000, rtc);
+
+    /* Keyboard (i8042) */
+    i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1);
+    memory_region_add_subregion(address_space, 0x80005000, i8042);
+
+    /* Serial ports */
+    if (serial_hds[0]) {
+        serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16,
+                       serial_hds[0], DEVICE_NATIVE_ENDIAN);
+    }
+    if (serial_hds[1]) {
+        serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16,
+                       serial_hds[1], DEVICE_NATIVE_ENDIAN);
+    }
+
+    /* Parallel port */
+    if (parallel_hds[0])
+        parallel_mm_init(address_space, 0x80008000, 0, rc4030[0],
+                         parallel_hds[0]);
+
+    /* Sound card */
+    /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
+    audio_init(isa_bus, NULL);
+
+    /* NVRAM */
+    dev = qdev_create(NULL, "ds1225y");
+    qdev_init_nofail(dev);
+    sysbus = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(sysbus, 0, 0x80009000);
+
+    /* LED indicator */
+    sysbus_create_simple("jazz-led", 0x8000f000, NULL);
+}
+
+static
+void mips_magnum_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+        mips_jazz_init(get_system_memory(), get_system_io(),
+                       ram_size, cpu_model, JAZZ_MAGNUM);
+}
+
+static
+void mips_pica61_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    mips_jazz_init(get_system_memory(), get_system_io(),
+                   ram_size, cpu_model, JAZZ_PICA61);
+}
+
+static QEMUMachine mips_magnum_machine = {
+    .name = "magnum",
+    .desc = "MIPS Magnum",
+    .init = mips_magnum_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine mips_pica61_machine = {
+    .name = "pica61",
+    .desc = "Acer Pica 61",
+    .init = mips_pica61_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void mips_jazz_machine_init(void)
+{
+    qemu_register_machine(&mips_magnum_machine);
+    qemu_register_machine(&mips_pica61_machine);
+}
+
+machine_init(mips_jazz_machine_init);
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
new file mode 100644 (file)
index 0000000..9a67dce
--- /dev/null
@@ -0,0 +1,1037 @@
+/*
+ * QEMU Malta board support
+ *
+ * Copyright (c) 2006 Aurelien Jarno
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/serial.h"
+#include "hw/fdc.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "hw/smbus.h"
+#include "block/block.h"
+#include "hw/flash.h"
+#include "hw/mips.h"
+#include "hw/mips_cpudevs.h"
+#include "hw/pci/pci.h"
+#include "char/char.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/arch_init.h"
+#include "hw/boards.h"
+#include "qemu/log.h"
+#include "hw/mips-bios.h"
+#include "hw/ide.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/mc146818rtc.h"
+#include "hw/i8254.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+#include "hw/sysbus.h"             /* SysBusDevice */
+
+//#define DEBUG_BOARD_INIT
+
+#define ENVP_ADDR              0x80002000l
+#define ENVP_NB_ENTRIES                16
+#define ENVP_ENTRY_SIZE                256
+
+/* Hardware addresses */
+#define FLASH_ADDRESS 0x1e000000ULL
+#define FPGA_ADDRESS  0x1f000000ULL
+#define RESET_ADDRESS 0x1fc00000ULL
+
+#define FLASH_SIZE    0x400000
+
+#define MAX_IDE_BUS 2
+
+typedef struct {
+    MemoryRegion iomem;
+    MemoryRegion iomem_lo; /* 0 - 0x900 */
+    MemoryRegion iomem_hi; /* 0xa00 - 0x100000 */
+    uint32_t leds;
+    uint32_t brk;
+    uint32_t gpout;
+    uint32_t i2cin;
+    uint32_t i2coe;
+    uint32_t i2cout;
+    uint32_t i2csel;
+    CharDriverState *display;
+    char display_text[9];
+    SerialState *uart;
+} MaltaFPGAState;
+
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq *i8259;
+} MaltaState;
+
+static ISADevice *pit;
+
+static struct _loaderparams {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+/* Malta FPGA */
+static void malta_fpga_update_display(void *opaque)
+{
+    char leds_text[9];
+    int i;
+    MaltaFPGAState *s = opaque;
+
+    for (i = 7 ; i >= 0 ; i--) {
+        if (s->leds & (1 << i))
+            leds_text[i] = '#';
+        else
+            leds_text[i] = ' ';
+    }
+    leds_text[8] = '\0';
+
+    qemu_chr_fe_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
+    qemu_chr_fe_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
+}
+
+/*
+ * EEPROM 24C01 / 24C02 emulation.
+ *
+ * Emulation for serial EEPROMs:
+ * 24C01 - 1024 bit (128 x 8)
+ * 24C02 - 2048 bit (256 x 8)
+ *
+ * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
+ */
+
+//~ #define DEBUG
+
+#if defined(DEBUG)
+#  define logout(fmt, ...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ## __VA_ARGS__)
+#else
+#  define logout(fmt, ...) ((void)0)
+#endif
+
+struct _eeprom24c0x_t {
+  uint8_t tick;
+  uint8_t address;
+  uint8_t command;
+  uint8_t ack;
+  uint8_t scl;
+  uint8_t sda;
+  uint8_t data;
+  //~ uint16_t size;
+  uint8_t contents[256];
+};
+
+typedef struct _eeprom24c0x_t eeprom24c0x_t;
+
+static eeprom24c0x_t eeprom = {
+    .contents = {
+        /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00,
+        /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
+        /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00,
+        /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40,
+        /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
+        /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
+        /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
+    },
+};
+
+static uint8_t eeprom24c0x_read(void)
+{
+    logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
+        eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data);
+    return eeprom.sda;
+}
+
+static void eeprom24c0x_write(int scl, int sda)
+{
+    if (eeprom.scl && scl && (eeprom.sda != sda)) {
+        logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
+                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start");
+        if (!sda) {
+            eeprom.tick = 1;
+            eeprom.command = 0;
+        }
+    } else if (eeprom.tick == 0 && !eeprom.ack) {
+        /* Waiting for start. */
+        logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
+                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+    } else if (!eeprom.scl && scl) {
+        logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
+                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+        if (eeprom.ack) {
+            logout("\ti2c ack bit = 0\n");
+            sda = 0;
+            eeprom.ack = 0;
+        } else if (eeprom.sda == sda) {
+            uint8_t bit = (sda != 0);
+            logout("\ti2c bit = %d\n", bit);
+            if (eeprom.tick < 9) {
+                eeprom.command <<= 1;
+                eeprom.command += bit;
+                eeprom.tick++;
+                if (eeprom.tick == 9) {
+                    logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write");
+                    eeprom.ack = 1;
+                }
+            } else if (eeprom.tick < 17) {
+                if (eeprom.command & 1) {
+                    sda = ((eeprom.data & 0x80) != 0);
+                }
+                eeprom.address <<= 1;
+                eeprom.address += bit;
+                eeprom.tick++;
+                eeprom.data <<= 1;
+                if (eeprom.tick == 17) {
+                    eeprom.data = eeprom.contents[eeprom.address];
+                    logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data);
+                    eeprom.ack = 1;
+                    eeprom.tick = 0;
+                }
+            } else if (eeprom.tick >= 17) {
+                sda = 0;
+            }
+        } else {
+            logout("\tsda changed with raising scl\n");
+        }
+    } else {
+        logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+    }
+    eeprom.scl = scl;
+    eeprom.sda = sda;
+}
+
+static uint64_t malta_fpga_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    MaltaFPGAState *s = opaque;
+    uint32_t val = 0;
+    uint32_t saddr;
+
+    saddr = (addr & 0xfffff);
+
+    switch (saddr) {
+
+    /* SWITCH Register */
+    case 0x00200:
+        val = 0x00000000;              /* All switches closed */
+        break;
+
+    /* STATUS Register */
+    case 0x00208:
+#ifdef TARGET_WORDS_BIGENDIAN
+        val = 0x00000012;
+#else
+        val = 0x00000010;
+#endif
+        break;
+
+    /* JMPRS Register */
+    case 0x00210:
+        val = 0x00;
+        break;
+
+    /* LEDBAR Register */
+    case 0x00408:
+        val = s->leds;
+        break;
+
+    /* BRKRES Register */
+    case 0x00508:
+        val = s->brk;
+        break;
+
+    /* UART Registers are handled directly by the serial device */
+
+    /* GPOUT Register */
+    case 0x00a00:
+        val = s->gpout;
+        break;
+
+    /* XXX: implement a real I2C controller */
+
+    /* GPINP Register */
+    case 0x00a08:
+        /* IN = OUT until a real I2C control is implemented */
+        if (s->i2csel)
+            val = s->i2cout;
+        else
+            val = 0x00;
+        break;
+
+    /* I2CINP Register */
+    case 0x00b00:
+        val = ((s->i2cin & ~1) | eeprom24c0x_read());
+        break;
+
+    /* I2COE Register */
+    case 0x00b08:
+        val = s->i2coe;
+        break;
+
+    /* I2COUT Register */
+    case 0x00b10:
+        val = s->i2cout;
+        break;
+
+    /* I2CSEL Register */
+    case 0x00b18:
+        val = s->i2csel;
+        break;
+
+    default:
+#if 0
+        printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
+                addr);
+#endif
+        break;
+    }
+    return val;
+}
+
+static void malta_fpga_write(void *opaque, hwaddr addr,
+                             uint64_t val, unsigned size)
+{
+    MaltaFPGAState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & 0xfffff);
+
+    switch (saddr) {
+
+    /* SWITCH Register */
+    case 0x00200:
+        break;
+
+    /* JMPRS Register */
+    case 0x00210:
+        break;
+
+    /* LEDBAR Register */
+    case 0x00408:
+        s->leds = val & 0xff;
+        malta_fpga_update_display(s);
+        break;
+
+    /* ASCIIWORD Register */
+    case 0x00410:
+        snprintf(s->display_text, 9, "%08X", (uint32_t)val);
+        malta_fpga_update_display(s);
+        break;
+
+    /* ASCIIPOS0 to ASCIIPOS7 Registers */
+    case 0x00418:
+    case 0x00420:
+    case 0x00428:
+    case 0x00430:
+    case 0x00438:
+    case 0x00440:
+    case 0x00448:
+    case 0x00450:
+        s->display_text[(saddr - 0x00418) >> 3] = (char) val;
+        malta_fpga_update_display(s);
+        break;
+
+    /* SOFTRES Register */
+    case 0x00500:
+        if (val == 0x42)
+            qemu_system_reset_request ();
+        break;
+
+    /* BRKRES Register */
+    case 0x00508:
+        s->brk = val & 0xff;
+        break;
+
+    /* UART Registers are handled directly by the serial device */
+
+    /* GPOUT Register */
+    case 0x00a00:
+        s->gpout = val & 0xff;
+        break;
+
+    /* I2COE Register */
+    case 0x00b08:
+        s->i2coe = val & 0x03;
+        break;
+
+    /* I2COUT Register */
+    case 0x00b10:
+        eeprom24c0x_write(val & 0x02, val & 0x01);
+        s->i2cout = val;
+        break;
+
+    /* I2CSEL Register */
+    case 0x00b18:
+        s->i2csel = val & 0x01;
+        break;
+
+    default:
+#if 0
+        printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
+                addr);
+#endif
+        break;
+    }
+}
+
+static const MemoryRegionOps malta_fpga_ops = {
+    .read = malta_fpga_read,
+    .write = malta_fpga_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void malta_fpga_reset(void *opaque)
+{
+    MaltaFPGAState *s = opaque;
+
+    s->leds   = 0x00;
+    s->brk    = 0x0a;
+    s->gpout  = 0x00;
+    s->i2cin  = 0x3;
+    s->i2coe  = 0x0;
+    s->i2cout = 0x3;
+    s->i2csel = 0x1;
+
+    s->display_text[8] = '\0';
+    snprintf(s->display_text, 9, "        ");
+}
+
+static void malta_fpga_led_init(CharDriverState *chr)
+{
+    qemu_chr_fe_printf(chr, "\e[HMalta LEDBAR\r\n");
+    qemu_chr_fe_printf(chr, "+--------+\r\n");
+    qemu_chr_fe_printf(chr, "+        +\r\n");
+    qemu_chr_fe_printf(chr, "+--------+\r\n");
+    qemu_chr_fe_printf(chr, "\n");
+    qemu_chr_fe_printf(chr, "Malta ASCII\r\n");
+    qemu_chr_fe_printf(chr, "+--------+\r\n");
+    qemu_chr_fe_printf(chr, "+        +\r\n");
+    qemu_chr_fe_printf(chr, "+--------+\r\n");
+}
+
+static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
+         hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr)
+{
+    MaltaFPGAState *s;
+
+    s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState));
+
+    memory_region_init_io(&s->iomem, &malta_fpga_ops, s,
+                          "malta-fpga", 0x100000);
+    memory_region_init_alias(&s->iomem_lo, "malta-fpga",
+                             &s->iomem, 0, 0x900);
+    memory_region_init_alias(&s->iomem_hi, "malta-fpga",
+                             &s->iomem, 0xa00, 0x10000-0xa00);
+
+    memory_region_add_subregion(address_space, base, &s->iomem_lo);
+    memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
+
+    s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
+
+    s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
+                             230400, uart_chr, DEVICE_NATIVE_ENDIAN);
+
+    malta_fpga_reset(s);
+    qemu_register_reset(malta_fpga_reset, s);
+
+    return s;
+}
+
+/* Network support */
+static void network_init(void)
+{
+    int i;
+
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+        const char *default_devaddr = NULL;
+
+        if (i == 0 && (!nd->model || strcmp(nd->model, "pcnet") == 0))
+            /* The malta board has a PCNet card using PCI SLOT 11 */
+            default_devaddr = "0b";
+
+        pci_nic_init_nofail(nd, "pcnet", default_devaddr);
+    }
+}
+
+/* ROM and pseudo bootloader
+
+   The following code implements a very very simple bootloader. It first
+   loads the registers a0 to a3 to the values expected by the OS, and
+   then jump at the kernel address.
+
+   The bootloader should pass the locations of the kernel arguments and
+   environment variables tables. Those tables contain the 32-bit address
+   of NULL terminated strings. The environment variables table should be
+   terminated by a NULL address.
+
+   For a simpler implementation, the number of kernel arguments is fixed
+   to two (the name of the kernel and the command line), and the two
+   tables are actually the same one.
+
+   The registers a0 to a3 should contain the following values:
+     a0 - number of kernel arguments
+     a1 - 32-bit address of the kernel arguments table
+     a2 - 32-bit address of the environment variables table
+     a3 - RAM size in bytes
+*/
+
+static void write_bootloader (CPUMIPSState *env, uint8_t *base,
+                              int64_t kernel_entry)
+{
+    uint32_t *p;
+
+    /* Small bootloader */
+    p = (uint32_t *)base;
+    stl_raw(p++, 0x0bf00160);                                      /* j 0x1fc00580 */
+    stl_raw(p++, 0x00000000);                                      /* nop */
+
+    /* YAMON service vector */
+    stl_raw(base + 0x500, 0xbfc00580);      /* start: */
+    stl_raw(base + 0x504, 0xbfc0083c);      /* print_count: */
+    stl_raw(base + 0x520, 0xbfc00580);      /* start: */
+    stl_raw(base + 0x52c, 0xbfc00800);      /* flush_cache: */
+    stl_raw(base + 0x534, 0xbfc00808);      /* print: */
+    stl_raw(base + 0x538, 0xbfc00800);      /* reg_cpu_isr: */
+    stl_raw(base + 0x53c, 0xbfc00800);      /* unred_cpu_isr: */
+    stl_raw(base + 0x540, 0xbfc00800);      /* reg_ic_isr: */
+    stl_raw(base + 0x544, 0xbfc00800);      /* unred_ic_isr: */
+    stl_raw(base + 0x548, 0xbfc00800);      /* reg_esr: */
+    stl_raw(base + 0x54c, 0xbfc00800);      /* unreg_esr: */
+    stl_raw(base + 0x550, 0xbfc00800);      /* getchar: */
+    stl_raw(base + 0x554, 0xbfc00800);      /* syscon_read: */
+
+
+    /* Second part of the bootloader */
+    p = (uint32_t *) (base + 0x580);
+    stl_raw(p++, 0x24040002);                                      /* addiu a0, zero, 2 */
+    stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
+    stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */
+    stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
+    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a1, low(ENVP_ADDR) */
+    stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
+    stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
+    stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16));     /* lui a3, high(ram_size) */
+    stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff));  /* ori a3, a3, low(ram_size) */
+
+    /* Load BAR registers as done by YAMON */
+    stl_raw(p++, 0x3c09b400);                                      /* lui t1, 0xb400 */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c08df00);                                      /* lui t0, 0xdf00 */
+#else
+    stl_raw(p++, 0x340800df);                                      /* ori t0, r0, 0x00df */
+#endif
+    stl_raw(p++, 0xad280068);                                      /* sw t0, 0x0068(t1) */
+
+    stl_raw(p++, 0x3c09bbe0);                                      /* lui t1, 0xbbe0 */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c08c000);                                      /* lui t0, 0xc000 */
+#else
+    stl_raw(p++, 0x340800c0);                                      /* ori t0, r0, 0x00c0 */
+#endif
+    stl_raw(p++, 0xad280048);                                      /* sw t0, 0x0048(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c084000);                                      /* lui t0, 0x4000 */
+#else
+    stl_raw(p++, 0x34080040);                                      /* ori t0, r0, 0x0040 */
+#endif
+    stl_raw(p++, 0xad280050);                                      /* sw t0, 0x0050(t1) */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c088000);                                      /* lui t0, 0x8000 */
+#else
+    stl_raw(p++, 0x34080080);                                      /* ori t0, r0, 0x0080 */
+#endif
+    stl_raw(p++, 0xad280058);                                      /* sw t0, 0x0058(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c083f00);                                      /* lui t0, 0x3f00 */
+#else
+    stl_raw(p++, 0x3408003f);                                      /* ori t0, r0, 0x003f */
+#endif
+    stl_raw(p++, 0xad280060);                                      /* sw t0, 0x0060(t1) */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c08c100);                                      /* lui t0, 0xc100 */
+#else
+    stl_raw(p++, 0x340800c1);                                      /* ori t0, r0, 0x00c1 */
+#endif
+    stl_raw(p++, 0xad280080);                                      /* sw t0, 0x0080(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c085e00);                                      /* lui t0, 0x5e00 */
+#else
+    stl_raw(p++, 0x3408005e);                                      /* ori t0, r0, 0x005e */
+#endif
+    stl_raw(p++, 0xad280088);                                      /* sw t0, 0x0088(t1) */
+
+    /* Jump to kernel code */
+    stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff));    /* lui ra, high(kernel_entry) */
+    stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff));            /* ori ra, ra, low(kernel_entry) */
+    stl_raw(p++, 0x03e00008);                                      /* jr ra */
+    stl_raw(p++, 0x00000000);                                      /* nop */
+
+    /* YAMON subroutines */
+    p = (uint32_t *) (base + 0x800);
+    stl_raw(p++, 0x03e00008);                                     /* jr ra */
+    stl_raw(p++, 0x24020000);                                     /* li v0,0 */
+   /* 808 YAMON print */
+    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
+    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
+    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
+    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
+    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
+    stl_raw(p++, 0x10800005);                                     /* beqz a0,834 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x08000205);                                     /* j 814 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
+    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
+    /* 0x83c YAMON print_count */
+    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
+    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
+    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
+    stl_raw(p++, 0x00c06021);                                     /* move t4,a2 */
+    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
+    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
+    stl_raw(p++, 0x258cffff);                                     /* addiu t4,t4,-1 */
+    stl_raw(p++, 0x1580fffa);                                     /* bnez t4,84c */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
+    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
+    /* 0x870 */
+    stl_raw(p++, 0x3c08b800);                                     /* lui t0,0xb400 */
+    stl_raw(p++, 0x350803f8);                                     /* ori t0,t0,0x3f8 */
+    stl_raw(p++, 0x91090005);                                     /* lbu t1,5(t0) */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x31290040);                                     /* andi t1,t1,0x40 */
+    stl_raw(p++, 0x1120fffc);                                     /* beqz t1,878 <outch+0x8> */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x03e00008);                                     /* jr ra */
+    stl_raw(p++, 0xa1040000);                                     /* sb a0,0(t0) */
+
+}
+
+static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
+                                        const char *string, ...)
+{
+    va_list ap;
+    int32_t table_addr;
+
+    if (index >= ENVP_NB_ENTRIES)
+        return;
+
+    if (string == NULL) {
+        prom_buf[index] = 0;
+        return;
+    }
+
+    table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
+    prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
+
+    va_start(ap, string);
+    vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
+    va_end(ap);
+}
+
+/* Kernel */
+static int64_t load_kernel (void)
+{
+    int64_t kernel_entry, kernel_high;
+    long initrd_size;
+    ram_addr_t initrd_offset;
+    int big_endian;
+    uint32_t *prom_buf;
+    long prom_size;
+    int prom_index = 0;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+
+    if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
+                 (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
+                 big_endian, ELF_MACHINE, 1) < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                loaderparams.kernel_filename);
+        exit(1);
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    initrd_offset = 0;
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size (loaderparams.initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+            if (initrd_offset + initrd_size > ram_size) {
+                fprintf(stderr,
+                        "qemu: memory too small for initial ram disk '%s'\n",
+                        loaderparams.initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                                              initrd_offset,
+                                              ram_size - initrd_offset);
+        }
+        if (initrd_size == (target_ulong) -1) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+
+    /* Setup prom parameters. */
+    prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
+    prom_buf = g_malloc(prom_size);
+
+    prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
+    if (initrd_size > 0) {
+        prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
+                 cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
+                 loaderparams.kernel_cmdline);
+    } else {
+        prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline);
+    }
+
+    prom_set(prom_buf, prom_index++, "memsize");
+    prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size);
+    prom_set(prom_buf, prom_index++, "modetty0");
+    prom_set(prom_buf, prom_index++, "38400n8r");
+    prom_set(prom_buf, prom_index++, NULL);
+
+    rom_add_blob_fixed("prom", prom_buf, prom_size,
+                       cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
+
+    return kernel_entry;
+}
+
+static void malta_mips_config(MIPSCPU *cpu)
+{
+    CPUMIPSState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
+
+    env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) |
+                         ((smp_cpus * cs->nr_threads - 1) << CP0MVPC0_PTC);
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    MIPSCPU *cpu = opaque;
+    CPUMIPSState *env = &cpu->env;
+
+    cpu_reset(CPU(cpu));
+
+    /* The bootloader does not need to be rewritten as it is located in a
+       read only location. The kernel location and the arguments table
+       location does not change. */
+    if (loaderparams.kernel_filename) {
+        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
+    }
+
+    malta_mips_config(cpu);
+}
+
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+    CPUMIPSState *env = cpu_single_env;
+
+    if (env && level) {
+        cpu_exit(env);
+    }
+}
+
+static
+void mips_malta_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    char *filename;
+    pflash_t *fl;
+    MemoryRegion *system_memory = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1);
+    target_long bios_size = FLASH_SIZE;
+    int64_t kernel_entry;
+    PCIBus *pci_bus;
+    ISABus *isa_bus;
+    MIPSCPU *cpu;
+    CPUMIPSState *env;
+    qemu_irq *isa_irq;
+    qemu_irq *cpu_exit_irq;
+    int piix4_devfn;
+    i2c_bus *smbus;
+    int i;
+    DriveInfo *dinfo;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    DriveInfo *fd[MAX_FD];
+    int fl_idx = 0;
+    int fl_sectors = bios_size >> 16;
+    int be;
+
+    DeviceState *dev = qdev_create(NULL, "mips-malta");
+    MaltaState *s = DO_UPCAST(MaltaState, busdev.qdev, dev);
+
+    qdev_init_nofail(dev);
+
+    /* Make sure the first 3 serial ports are associated with a device. */
+    for(i = 0; i < 3; i++) {
+        if (!serial_hds[i]) {
+            char label[32];
+            snprintf(label, sizeof(label), "serial%d", i);
+            serial_hds[i] = qemu_chr_new(label, "null", NULL);
+        }
+    }
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "20Kc";
+#else
+        cpu_model = "24Kf";
+#endif
+    }
+
+    for (i = 0; i < smp_cpus; i++) {
+        cpu = cpu_mips_init(cpu_model);
+        if (cpu == NULL) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        env = &cpu->env;
+
+        /* Init internal devices */
+        cpu_mips_irq_init_cpu(env);
+        cpu_mips_clock_init(env);
+        qemu_register_reset(main_cpu_reset, cpu);
+    }
+    env = first_cpu;
+
+    /* allocate RAM */
+    if (ram_size > (256 << 20)) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
+                ((unsigned int)ram_size / (1 << 20)));
+        exit(1);
+    }
+    memory_region_init_ram(ram, "mips_malta.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(system_memory, 0, ram);
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    /* FPGA */
+    /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
+    malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]);
+
+    /* Load firmware in flash / BIOS. */
+    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
+#ifdef DEBUG_BOARD_INIT
+    if (dinfo) {
+        printf("Register parallel flash %d size " TARGET_FMT_lx " at "
+               "addr %08llx '%s' %x\n",
+               fl_idx, bios_size, FLASH_ADDRESS,
+               bdrv_get_device_name(dinfo->bdrv), fl_sectors);
+    }
+#endif
+    fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios",
+                               BIOS_SIZE, dinfo ? dinfo->bdrv : NULL,
+                               65536, fl_sectors,
+                               4, 0x0000, 0x0000, 0x0000, 0x0000, be);
+    bios = pflash_cfi01_get_memory(fl);
+    fl_idx++;
+    if (kernel_filename) {
+        /* Write a small bootloader to the flash location. */
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        kernel_entry = load_kernel();
+        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
+    } else {
+        /* Load firmware from flash. */
+        if (!dinfo) {
+            /* Load a BIOS image. */
+            if (bios_name == NULL) {
+                bios_name = BIOS_FILENAME;
+            }
+            filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+            if (filename) {
+                bios_size = load_image_targphys(filename, FLASH_ADDRESS,
+                                                BIOS_SIZE);
+                g_free(filename);
+            } else {
+                bios_size = -1;
+            }
+            if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
+                fprintf(stderr,
+                        "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
+                        bios_name);
+                exit(1);
+            }
+        }
+        /* In little endian mode the 32bit words in the bios are swapped,
+           a neat trick which allows bi-endian firmware. */
+#ifndef TARGET_WORDS_BIGENDIAN
+        {
+            uint32_t *addr = memory_region_get_ram_ptr(bios);
+            uint32_t *end = addr + bios_size;
+            while (addr < end) {
+                bswap32s(addr);
+                addr++;
+            }
+        }
+#endif
+    }
+
+    /* Map the BIOS at a 2nd physical location, as on the real board. */
+    memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE);
+    memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_alias);
+
+    /* Board ID = 0x420 (Malta Board with CoreLV)
+       XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
+       map to the board ID. */
+    stl_p(memory_region_get_ram_ptr(bios) + 0x10, 0x00000420);
+
+    /* Init internal devices */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+
+    /*
+     * We have a circular dependency problem: pci_bus depends on isa_irq,
+     * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
+     * on piix4, and piix4 depends on pci_bus.  To stop the cycle we have
+     * qemu_irq_proxy() adds an extra bit of indirection, allowing us
+     * to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
+     */
+    isa_irq = qemu_irq_proxy(&s->i8259, 16);
+
+    /* Northbridge */
+    pci_bus = gt64120_register(isa_irq);
+
+    /* Southbridge */
+    ide_drive_get(hd, MAX_IDE_BUS);
+
+    piix4_devfn = piix4_init(pci_bus, &isa_bus, 80);
+
+    /* Interrupt controller */
+    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
+    s->i8259 = i8259_init(isa_bus, env->irq[2]);
+
+    isa_bus_irqs(isa_bus, s->i8259);
+    pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
+    pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
+    smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
+                          isa_get_irq(NULL, 9), NULL, 0, NULL);
+    /* TODO: Populate SPD eeprom data.  */
+    smbus_eeprom_init(smbus, 8, NULL, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    DMA_init(0, cpu_exit_irq);
+
+    /* Super I/O */
+    isa_create_simple(isa_bus, "i8042");
+
+    rtc_init(isa_bus, 2000, NULL);
+    serial_isa_init(isa_bus, 0, serial_hds[0]);
+    serial_isa_init(isa_bus, 1, serial_hds[1]);
+    if (parallel_hds[0])
+        parallel_init(isa_bus, 0, parallel_hds[0]);
+    for(i = 0; i < MAX_FD; i++) {
+        fd[i] = drive_get(IF_FLOPPY, 0, i);
+    }
+    fdctrl_init_isa(isa_bus, fd);
+
+    /* Sound card */
+    audio_init(isa_bus, pci_bus);
+
+    /* Network card */
+    network_init();
+
+    /* Optional PCI video card */
+    pci_vga_init(pci_bus);
+}
+
+static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
+{
+    return 0;
+}
+
+static void mips_malta_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mips_malta_sysbus_device_init;
+}
+
+static const TypeInfo mips_malta_device = {
+    .name          = "mips-malta",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MaltaState),
+    .class_init    = mips_malta_class_init,
+};
+
+static QEMUMachine mips_malta_machine = {
+    .name = "malta",
+    .desc = "MIPS Malta Core LV",
+    .init = mips_malta_init,
+    .max_cpus = 16,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void mips_malta_register_types(void)
+{
+    type_register_static(&mips_malta_device);
+}
+
+static void mips_malta_machine_init(void)
+{
+    qemu_register_machine(&mips_malta_machine);
+}
+
+type_init(mips_malta_register_types)
+machine_init(mips_malta_machine_init);
diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c
new file mode 100644 (file)
index 0000000..4935c78
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * QEMU/mipssim emulation
+ *
+ * Emulates a very simple machine model similar to the one used by the
+ * proprietary MIPS emulator.
+ * 
+ * Copyright (c) 2007 Thiemo Seufer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "hw/mips.h"
+#include "hw/mips_cpudevs.h"
+#include "hw/serial.h"
+#include "hw/isa.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/mips-bios.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+
+static struct _loaderparams {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+typedef struct ResetData {
+    MIPSCPU *cpu;
+    uint64_t vector;
+} ResetData;
+
+static int64_t load_kernel(void)
+{
+    int64_t entry, kernel_high;
+    long kernel_size;
+    long initrd_size;
+    ram_addr_t initrd_offset;
+    int big_endian;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+
+    kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
+                           NULL, (uint64_t *)&entry, NULL,
+                           (uint64_t *)&kernel_high, big_endian,
+                           ELF_MACHINE, 1);
+    if (kernel_size >= 0) {
+        if ((entry & ~0x7fffffffULL) == 0x80000000)
+            entry = (int32_t)entry;
+    } else {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                loaderparams.kernel_filename);
+        exit(1);
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    initrd_offset = 0;
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size (loaderparams.initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+            if (initrd_offset + initrd_size > loaderparams.ram_size) {
+                fprintf(stderr,
+                        "qemu: memory too small for initial ram disk '%s'\n",
+                        loaderparams.initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                initrd_offset, loaderparams.ram_size - initrd_offset);
+        }
+        if (initrd_size == (target_ulong) -1) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+    return entry;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *)opaque;
+    CPUMIPSState *env = &s->cpu->env;
+
+    cpu_reset(CPU(s->cpu));
+    env->active_tc.PC = s->vector & ~(target_ulong)1;
+    if (s->vector & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    }
+}
+
+static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "mipsnet");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, irq);
+    memory_region_add_subregion(get_system_io(),
+                                base,
+                                sysbus_mmio_get_region(s, 0));
+}
+
+static void
+mips_mipssim_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    char *filename;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
+    MIPSCPU *cpu;
+    CPUMIPSState *env;
+    ResetData *reset_info;
+    int bios_size;
+
+    /* Init CPUs. */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "5Kf";
+#else
+        cpu_model = "24Kf";
+#endif
+    }
+    cpu = cpu_mips_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    env = &cpu->env;
+
+    reset_info = g_malloc0(sizeof(ResetData));
+    reset_info->cpu = cpu;
+    reset_info->vector = env->active_tc.PC;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    /* Allocate RAM. */
+    memory_region_init_ram(ram, "mips_mipssim.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_init_ram(bios, "mips_mipssim.bios", BIOS_SIZE);
+    vmstate_register_ram_global(bios);
+    memory_region_set_readonly(bios, true);
+
+    memory_region_add_subregion(address_space_mem, 0, ram);
+
+    /* Map the BIOS / boot exception handler. */
+    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
+    /* Load a BIOS / boot exception handler image. */
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE);
+        g_free(filename);
+    } else {
+        bios_size = -1;
+    }
+    if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
+        /* Bail out if we have neither a kernel image nor boot vector code. */
+        fprintf(stderr,
+                "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
+                filename);
+        exit(1);
+    } else {
+        /* We have a boot vector start address. */
+        env->active_tc.PC = (target_long)(int32_t)0xbfc00000;
+    }
+
+    if (kernel_filename) {
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        reset_info->vector = load_kernel();
+    }
+
+    /* Init CPU internal devices. */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+
+    /* Register 64 KB of ISA IO space at 0x1fd00000. */
+    isa_mmio_init(0x1fd00000, 0x00010000);
+
+    /* A single 16450 sits at offset 0x3f8. It is attached to
+       MIPS CPU INT2, which is interrupt 4. */
+    if (serial_hds[0])
+        serial_init(0x3f8, env->irq[4], 115200, serial_hds[0],
+                    get_system_io());
+
+    if (nd_table[0].used)
+        /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
+        mipsnet_init(0x4200, env->irq[2], &nd_table[0]);
+}
+
+static QEMUMachine mips_mipssim_machine = {
+    .name = "mipssim",
+    .desc = "MIPS MIPSsim platform",
+    .init = mips_mipssim_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void mips_mipssim_machine_init(void)
+{
+    qemu_register_machine(&mips_mipssim_machine);
+}
+
+machine_init(mips_mipssim_machine_init);
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
new file mode 100644 (file)
index 0000000..539a562
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * QEMU/MIPS pseudo-board
+ *
+ * emulates a simple machine with ISA-like bus.
+ * ISA IO space mapped to the 0x14000000 (PHYS) and
+ * ISA memory at the 0x10000000 (PHYS, 16Mb in size).
+ * All peripherial devices are attached to this "bus" with
+ * the standard PC ISA addresses.
+*/
+#include "hw/hw.h"
+#include "hw/mips.h"
+#include "hw/mips_cpudevs.h"
+#include "hw/pc.h"
+#include "hw/serial.h"
+#include "hw/isa.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/flash.h"
+#include "qemu/log.h"
+#include "hw/mips-bios.h"
+#include "hw/ide.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/mc146818rtc.h"
+#include "hw/i8254.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+#define MAX_IDE_BUS 2
+
+static const int ide_iobase[2] = { 0x1f0, 0x170 };
+static const int ide_iobase2[2] = { 0x3f6, 0x376 };
+static const int ide_irq[2] = { 14, 15 };
+
+static ISADevice *pit; /* PIT i8254 */
+
+/* i8254 PIT is attached to the IRQ0 at PIC i8259 */
+
+static struct _loaderparams {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+static void mips_qemu_write (void *opaque, hwaddr addr,
+                             uint64_t val, unsigned size)
+{
+    if ((addr & 0xffff) == 0 && val == 42)
+        qemu_system_reset_request ();
+    else if ((addr & 0xffff) == 4 && val == 42)
+        qemu_system_shutdown_request ();
+}
+
+static uint64_t mips_qemu_read (void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    return 0;
+}
+
+static const MemoryRegionOps mips_qemu_ops = {
+    .read = mips_qemu_read,
+    .write = mips_qemu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+typedef struct ResetData {
+    MIPSCPU *cpu;
+    uint64_t vector;
+} ResetData;
+
+static int64_t load_kernel(void)
+{
+    int64_t entry, kernel_high;
+    long kernel_size, initrd_size, params_size;
+    ram_addr_t initrd_offset;
+    uint32_t *params_buf;
+    int big_endian;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+    kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
+                           NULL, (uint64_t *)&entry, NULL,
+                           (uint64_t *)&kernel_high, big_endian,
+                           ELF_MACHINE, 1);
+    if (kernel_size >= 0) {
+        if ((entry & ~0x7fffffffULL) == 0x80000000)
+            entry = (int32_t)entry;
+    } else {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                loaderparams.kernel_filename);
+        exit(1);
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    initrd_offset = 0;
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size (loaderparams.initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+            if (initrd_offset + initrd_size > ram_size) {
+                fprintf(stderr,
+                        "qemu: memory too small for initial ram disk '%s'\n",
+                        loaderparams.initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                                              initrd_offset,
+                                              ram_size - initrd_offset);
+        }
+        if (initrd_size == (target_ulong) -1) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+
+    /* Store command line.  */
+    params_size = 264;
+    params_buf = g_malloc(params_size);
+
+    params_buf[0] = tswap32(ram_size);
+    params_buf[1] = tswap32(0x12345678);
+
+    if (initrd_size > 0) {
+        snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%li %s",
+                 cpu_mips_phys_to_kseg0(NULL, initrd_offset),
+                 initrd_size, loaderparams.kernel_cmdline);
+    } else {
+        snprintf((char *)params_buf + 8, 256, "%s", loaderparams.kernel_cmdline);
+    }
+
+    rom_add_blob_fixed("params", params_buf, params_size,
+                       (16 << 20) - 264);
+
+    return entry;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *)opaque;
+    CPUMIPSState *env = &s->cpu->env;
+
+    cpu_reset(CPU(s->cpu));
+    env->active_tc.PC = s->vector;
+}
+
+static const int sector_len = 32 * 1024;
+static
+void mips_r4k_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    char *filename;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios;
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
+    int bios_size;
+    MIPSCPU *cpu;
+    CPUMIPSState *env;
+    ResetData *reset_info;
+    int i;
+    qemu_irq *i8259;
+    ISABus *isa_bus;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    DriveInfo *dinfo;
+    int be;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "R4000";
+#else
+        cpu_model = "24Kf";
+#endif
+    }
+    cpu = cpu_mips_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    env = &cpu->env;
+
+    reset_info = g_malloc0(sizeof(ResetData));
+    reset_info->cpu = cpu;
+    reset_info->vector = env->active_tc.PC;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    /* allocate RAM */
+    if (ram_size > (256 << 20)) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
+                ((unsigned int)ram_size / (1 << 20)));
+        exit(1);
+    }
+    memory_region_init_ram(ram, "mips_r4k.ram", ram_size);
+    vmstate_register_ram_global(ram);
+
+    memory_region_add_subregion(address_space_mem, 0, ram);
+
+    memory_region_init_io(iomem, &mips_qemu_ops, NULL, "mips-qemu", 0x10000);
+    memory_region_add_subregion(address_space_mem, 0x1fbf0000, iomem);
+
+    /* Try to load a BIOS image. If this fails, we continue regardless,
+       but initialize the hardware ourselves. When a kernel gets
+       preloaded we also initialize the hardware, since the BIOS wasn't
+       run. */
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = get_image_size(filename);
+    } else {
+        bios_size = -1;
+    }
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, "mips_r4k.bios", BIOS_SIZE);
+        vmstate_register_ram_global(bios);
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(get_system_memory(), 0x1fc00000, bios);
+
+        load_image_targphys(filename, 0x1fc00000, BIOS_SIZE);
+    } else if ((dinfo = drive_get(IF_PFLASH, 0, 0)) != NULL) {
+        uint32_t mips_rom = 0x00400000;
+        if (!pflash_cfi01_register(0x1fc00000, NULL, "mips_r4k.bios", mips_rom,
+                                   dinfo->bdrv, sector_len,
+                                   mips_rom / sector_len,
+                                   4, 0, 0, 0, 0, be)) {
+            fprintf(stderr, "qemu: Error registering flash memory.\n");
+       }
+    }
+    else {
+       /* not fatal */
+        fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
+               bios_name);
+    }
+    if (filename) {
+        g_free(filename);
+    }
+
+    if (kernel_filename) {
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        reset_info->vector = load_kernel();
+    }
+
+    /* Init CPU internal devices */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+
+    /* The PIC is attached to the MIPS CPU INT0 pin */
+    isa_bus = isa_bus_new(NULL, get_system_io());
+    i8259 = i8259_init(isa_bus, env->irq[2]);
+    isa_bus_irqs(isa_bus, i8259);
+
+    rtc_init(isa_bus, 2000, NULL);
+
+    /* Register 64 KB of ISA IO space at 0x14000000 */
+    isa_mmio_init(0x14000000, 0x00010000);
+    isa_mem_base = 0x10000000;
+
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_isa_init(isa_bus, i, serial_hds[i]);
+        }
+    }
+
+    isa_vga_init(isa_bus);
+
+    if (nd_table[0].used)
+        isa_ne2000_init(isa_bus, 0x300, 9, &nd_table[0]);
+
+    ide_drive_get(hd, MAX_IDE_BUS);
+    for(i = 0; i < MAX_IDE_BUS; i++)
+        isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i],
+                     hd[MAX_IDE_DEVS * i],
+                    hd[MAX_IDE_DEVS * i + 1]);
+
+    isa_create_simple(isa_bus, "i8042");
+}
+
+static QEMUMachine mips_machine = {
+    .name = "mips",
+    .desc = "mips r4k platform",
+    .init = mips_r4k_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void mips_machine_init(void)
+{
+    qemu_register_machine(&mips_machine);
+}
+
+machine_init(mips_machine_init);
diff --git a/hw/mips_addr.c b/hw/mips_addr.c
deleted file mode 100644 (file)
index cddc25c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * QEMU MIPS address translation support
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/hw.h"
-#include "hw/mips_cpudevs.h"
-
-uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
-{
-    return addr & 0x7fffffffll;
-}
-
-uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr)
-{
-    return addr | ~0x7fffffffll;
-}
diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
deleted file mode 100644 (file)
index 766aa9d..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * QEMU fulong 2e mini pc support
- *
- * Copyright (c) 2008 yajin (yajin@vm-kernel.org)
- * Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn)
- * Copyright (c) 2010 Huacai Chen (zltjiangshi@gmail.com)
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-/*
- * Fulong 2e mini pc is based on ICT/ST Loongson 2e CPU (MIPS III like, 800MHz)
- * http://www.linux-mips.org/wiki/Fulong
- *
- * Loongson 2e user manual:
- * http://www.loongsondeveloper.com/doc/Loongson2EUserGuide.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/fdc.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/smbus.h"
-#include "block/block.h"
-#include "hw/flash.h"
-#include "hw/mips.h"
-#include "hw/mips_cpudevs.h"
-#include "hw/pci/pci.h"
-#include "char/char.h"
-#include "sysemu/sysemu.h"
-#include "audio/audio.h"
-#include "qemu/log.h"
-#include "hw/loader.h"
-#include "hw/mips-bios.h"
-#include "hw/ide.h"
-#include "elf.h"
-#include "hw/vt82c686.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-#define DEBUG_FULONG2E_INIT
-
-#define ENVP_ADDR       0x80002000l
-#define ENVP_NB_ENTRIES                16
-#define ENVP_ENTRY_SIZE                256
-
-#define MAX_IDE_BUS 2
-
-/*
- * PMON is not part of qemu and released with BSD license, anyone
- * who want to build a pmon binary please first git-clone the source
- * from the git repository at:
- * http://www.loongson.cn/support/git/pmon
- * Then follow the "Compile Guide" available at:
- * http://dev.lemote.com/code/pmon
- *
- * Notes:
- * 1, don't use the source at http://dev.lemote.com/http_git/pmon.git
- * 2, use "Bonito2edev" to replace "dir_corresponding_to_your_target_hardware"
- * in the "Compile Guide".
- */
-#define FULONG_BIOSNAME "pmon_fulong2e.bin"
-
-/* PCI SLOT in fulong 2e */
-#define FULONG2E_VIA_SLOT        5
-#define FULONG2E_ATI_SLOT        6
-#define FULONG2E_RTL8139_SLOT    7
-
-static ISADevice *pit;
-
-static struct _loaderparams {
-    int ram_size;
-    const char *kernel_filename;
-    const char *kernel_cmdline;
-    const char *initrd_filename;
-} loaderparams;
-
-static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
-                                        const char *string, ...)
-{
-    va_list ap;
-    int32_t table_addr;
-
-    if (index >= ENVP_NB_ENTRIES)
-        return;
-
-    if (string == NULL) {
-        prom_buf[index] = 0;
-        return;
-    }
-
-    table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
-    prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
-
-    va_start(ap, string);
-    vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
-    va_end(ap);
-}
-
-static int64_t load_kernel (CPUMIPSState *env)
-{
-    int64_t kernel_entry, kernel_low, kernel_high;
-    int index = 0;
-    long initrd_size;
-    ram_addr_t initrd_offset;
-    uint32_t *prom_buf;
-    long prom_size;
-
-    if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
-                 (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
-                 (uint64_t *)&kernel_high, 0, ELF_MACHINE, 1) < 0) {
-        fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                loaderparams.kernel_filename);
-        exit(1);
-    }
-
-    /* load initrd */
-    initrd_size = 0;
-    initrd_offset = 0;
-    if (loaderparams.initrd_filename) {
-        initrd_size = get_image_size (loaderparams.initrd_filename);
-        if (initrd_size > 0) {
-            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
-            if (initrd_offset + initrd_size > ram_size) {
-                fprintf(stderr,
-                        "qemu: memory too small for initial ram disk '%s'\n",
-                        loaderparams.initrd_filename);
-                exit(1);
-            }
-            initrd_size = load_image_targphys(loaderparams.initrd_filename,
-                                     initrd_offset, ram_size - initrd_offset);
-        }
-        if (initrd_size == (target_ulong) -1) {
-            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                    loaderparams.initrd_filename);
-            exit(1);
-        }
-    }
-
-    /* Setup prom parameters. */
-    prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
-    prom_buf = g_malloc(prom_size);
-
-    prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename);
-    if (initrd_size > 0) {
-        prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
-                 cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
-                 loaderparams.kernel_cmdline);
-    } else {
-        prom_set(prom_buf, index++, "%s", loaderparams.kernel_cmdline);
-    }
-
-    /* Setup minimum environment variables */
-    prom_set(prom_buf, index++, "busclock=33000000");
-    prom_set(prom_buf, index++, "cpuclock=100000000");
-    prom_set(prom_buf, index++, "memsize=%i", loaderparams.ram_size/1024/1024);
-    prom_set(prom_buf, index++, "modetty0=38400n8r");
-    prom_set(prom_buf, index++, NULL);
-
-    rom_add_blob_fixed("prom", prom_buf, prom_size,
-                       cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
-
-    return kernel_entry;
-}
-
-static void write_bootloader (CPUMIPSState *env, uint8_t *base, int64_t kernel_addr)
-{
-    uint32_t *p;
-
-    /* Small bootloader */
-    p = (uint32_t *) base;
-
-    stl_raw(p++, 0x0bf00010);                                      /* j 0x1fc00040 */
-    stl_raw(p++, 0x00000000);                                      /* nop */
-
-    /* Second part of the bootloader */
-    p = (uint32_t *) (base + 0x040);
-
-    stl_raw(p++, 0x3c040000);                                      /* lui a0, 0 */
-    stl_raw(p++, 0x34840002);                                      /* ori a0, a0, 2 */
-    stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
-    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a0, low(ENVP_ADDR) */
-    stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
-    stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
-    stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16));      /* lui a3, high(env->ram_size) */
-    stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff));   /* ori a3, a3, low(env->ram_size) */
-    stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff));     /* lui ra, high(kernel_addr) */;
-    stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff));             /* ori ra, ra, low(kernel_addr) */
-    stl_raw(p++, 0x03e00008);                                      /* jr ra */
-    stl_raw(p++, 0x00000000);                                      /* nop */
-}
-
-
-static void main_cpu_reset(void *opaque)
-{
-    MIPSCPU *cpu = opaque;
-    CPUMIPSState *env = &cpu->env;
-
-    cpu_reset(CPU(cpu));
-    /* TODO: 2E reset stuff */
-    if (loaderparams.kernel_filename) {
-        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
-    }
-}
-
-uint8_t eeprom_spd[0x80] = {
-    0x80,0x08,0x07,0x0d,0x09,0x02,0x40,0x00,0x04,0x70,
-    0x70,0x00,0x82,0x10,0x00,0x01,0x0e,0x04,0x0c,0x01,
-    0x02,0x20,0x80,0x75,0x70,0x00,0x00,0x50,0x3c,0x50,
-    0x2d,0x20,0xb0,0xb0,0x50,0x50,0x00,0x00,0x00,0x00,
-    0x00,0x41,0x48,0x3c,0x32,0x75,0x00,0x00,0x00,0x00,
-    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-    0x00,0x00,0x00,0x9c,0x7b,0x07,0x00,0x00,0x00,0x00,
-    0x00,0x00,0x00,0x00,0x48,0x42,0x35,0x34,0x41,0x32,
-    0x35,0x36,0x38,0x4b,0x4e,0x2d,0x41,0x37,0x35,0x42,
-    0x20,0x30,0x20
-};
-
-/* Audio support */
-static void audio_init (PCIBus *pci_bus)
-{
-    vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5));
-    vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6));
-}
-
-/* Network support */
-static void network_init (void)
-{
-    int i;
-
-    for(i = 0; i < nb_nics; i++) {
-        NICInfo *nd = &nd_table[i];
-        const char *default_devaddr = NULL;
-
-        if (i == 0 && (!nd->model || strcmp(nd->model, "rtl8139") == 0)) {
-            /* The fulong board has a RTL8139 card using PCI SLOT 7 */
-            default_devaddr = "07";
-        }
-
-        pci_nic_init_nofail(nd, "rtl8139", default_devaddr);
-    }
-}
-
-static void cpu_request_exit(void *opaque, int irq, int level)
-{
-    CPUMIPSState *env = cpu_single_env;
-
-    if (env && level) {
-        cpu_exit(env);
-    }
-}
-
-static void mips_fulong2e_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    char *filename;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *bios = g_new(MemoryRegion, 1);
-    long bios_size;
-    int64_t kernel_entry;
-    qemu_irq *i8259;
-    qemu_irq *cpu_exit_irq;
-    PCIBus *pci_bus;
-    ISABus *isa_bus;
-    i2c_bus *smbus;
-    int i;
-    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
-    MIPSCPU *cpu;
-    CPUMIPSState *env;
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-        cpu_model = "Loongson-2E";
-    }
-    cpu = cpu_mips_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-    env = &cpu->env;
-
-    qemu_register_reset(main_cpu_reset, cpu);
-
-    /* fulong 2e has 256M ram. */
-    ram_size = 256 * 1024 * 1024;
-
-    /* fulong 2e has a 1M flash.Winbond W39L040AP70Z */
-    bios_size = 1024 * 1024;
-
-    /* allocate RAM */
-    memory_region_init_ram(ram, "fulong2e.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_init_ram(bios, "fulong2e.bios", bios_size);
-    vmstate_register_ram_global(bios);
-    memory_region_set_readonly(bios, true);
-
-    memory_region_add_subregion(address_space_mem, 0, ram);
-    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
-
-    /* We do not support flash operation, just loading pmon.bin as raw BIOS.
-     * Please use -L to set the BIOS path and -bios to set bios name. */
-
-    if (kernel_filename) {
-        loaderparams.ram_size = ram_size;
-        loaderparams.kernel_filename = kernel_filename;
-        loaderparams.kernel_cmdline = kernel_cmdline;
-        loaderparams.initrd_filename = initrd_filename;
-        kernel_entry = load_kernel (env);
-        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
-    } else {
-        if (bios_name == NULL) {
-                bios_name = FULONG_BIOSNAME;
-        }
-        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-        if (filename) {
-            bios_size = load_image_targphys(filename, 0x1fc00000LL,
-                                            BIOS_SIZE);
-            g_free(filename);
-        } else {
-            bios_size = -1;
-        }
-
-        if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
-            fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", bios_name);
-            exit(1);
-        }
-    }
-
-    /* Init internal devices */
-    cpu_mips_irq_init_cpu(env);
-    cpu_mips_clock_init(env);
-
-    /* North bridge, Bonito --> IP2 */
-    pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));
-
-    /* South bridge */
-    ide_drive_get(hd, MAX_IDE_BUS);
-
-    isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
-    if (!isa_bus) {
-        fprintf(stderr, "vt82c686b_init error\n");
-        exit(1);
-    }
-
-    /* Interrupt controller */
-    /* The 8259 -> IP5  */
-    i8259 = i8259_init(isa_bus, env->irq[5]);
-    isa_bus_irqs(isa_bus, i8259);
-
-    vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1));
-    pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2),
-                      "vt82c686b-usb-uhci");
-    pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3),
-                      "vt82c686b-usb-uhci");
-
-    smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4),
-                              0xeee1, NULL);
-    /* TODO: Populate SPD eeprom data.  */
-    smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd));
-
-    /* init other devices */
-    pit = pit_init(isa_bus, 0x40, 0, NULL);
-    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
-    DMA_init(0, cpu_exit_irq);
-
-    /* Super I/O */
-    isa_create_simple(isa_bus, "i8042");
-
-    rtc_init(isa_bus, 2000, NULL);
-
-    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
-        if (serial_hds[i]) {
-            serial_isa_init(isa_bus, i, serial_hds[i]);
-        }
-    }
-
-    if (parallel_hds[0]) {
-        parallel_init(isa_bus, 0, parallel_hds[0]);
-    }
-
-    /* Sound card */
-    audio_init(pci_bus);
-    /* Network card */
-    network_init();
-}
-
-static QEMUMachine mips_fulong2e_machine = {
-    .name = "fulong2e",
-    .desc = "Fulong 2e mini pc",
-    .init = mips_fulong2e_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void mips_fulong2e_machine_init(void)
-{
-    qemu_register_machine(&mips_fulong2e_machine);
-}
-
-machine_init(mips_fulong2e_machine_init);
diff --git a/hw/mips_int.c b/hw/mips_int.c
deleted file mode 100644 (file)
index ddd3b1b..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * QEMU MIPS interrupt support
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/hw.h"
-#include "hw/mips_cpudevs.h"
-#include "cpu.h"
-
-static void cpu_mips_irq_request(void *opaque, int irq, int level)
-{
-    CPUMIPSState *env = (CPUMIPSState *)opaque;
-
-    if (irq < 0 || irq > 7)
-        return;
-
-    if (level) {
-        env->CP0_Cause |= 1 << (irq + CP0Ca_IP);
-    } else {
-        env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP));
-    }
-
-    if (env->CP0_Cause & CP0Ca_IP_mask) {
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
-    } else {
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
-}
-
-void cpu_mips_irq_init_cpu(CPUMIPSState *env)
-{
-    qemu_irq *qi;
-    int i;
-
-    qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8);
-    for (i = 0; i < 8; i++) {
-        env->irq[i] = qi[i];
-    }
-}
-
-void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level)
-{
-    if (irq < 0 || irq > 2) {
-        return;
-    }
-
-    qemu_set_irq(env->irq[irq], level);
-}
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
deleted file mode 100644 (file)
index daeb985..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * QEMU MIPS Jazz support
- *
- * Copyright (c) 2007-2008 Hervé Poussineau
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/hw.h"
-#include "hw/mips.h"
-#include "hw/mips_cpudevs.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/isa.h"
-#include "hw/fdc.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/arch_init.h"
-#include "hw/boards.h"
-#include "net/net.h"
-#include "hw/esp.h"
-#include "hw/mips-bios.h"
-#include "hw/loader.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
-#include "hw/pcspk.h"
-#include "sysemu/blockdev.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-enum jazz_model_e
-{
-    JAZZ_MAGNUM,
-    JAZZ_PICA61,
-};
-
-static void main_cpu_reset(void *opaque)
-{
-    MIPSCPU *cpu = opaque;
-
-    cpu_reset(CPU(cpu));
-}
-
-static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size)
-{
-    return cpu_inw(0x71);
-}
-
-static void rtc_write(void *opaque, hwaddr addr,
-                      uint64_t val, unsigned size)
-{
-    cpu_outw(0x71, val & 0xff);
-}
-
-static const MemoryRegionOps rtc_ops = {
-    .read = rtc_read,
-    .write = rtc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t dma_dummy_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    /* Nothing to do. That is only to ensure that
-     * the current DMA acknowledge cycle is completed. */
-    return 0xff;
-}
-
-static void dma_dummy_write(void *opaque, hwaddr addr,
-                            uint64_t val, unsigned size)
-{
-    /* Nothing to do. That is only to ensure that
-     * the current DMA acknowledge cycle is completed. */
-}
-
-static const MemoryRegionOps dma_dummy_ops = {
-    .read = dma_dummy_read,
-    .write = dma_dummy_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-#define MAGNUM_BIOS_SIZE_MAX 0x7e000
-#define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX)
-
-static void cpu_request_exit(void *opaque, int irq, int level)
-{
-    CPUMIPSState *env = cpu_single_env;
-
-    if (env && level) {
-        cpu_exit(env);
-    }
-}
-
-static void mips_jazz_init(MemoryRegion *address_space,
-                           MemoryRegion *address_space_io,
-                           ram_addr_t ram_size,
-                           const char *cpu_model,
-                           enum jazz_model_e jazz_model)
-{
-    char *filename;
-    int bios_size, n;
-    MIPSCPU *cpu;
-    CPUMIPSState *env;
-    qemu_irq *rc4030, *i8259;
-    rc4030_dma *dmas;
-    void* rc4030_opaque;
-    MemoryRegion *rtc = g_new(MemoryRegion, 1);
-    MemoryRegion *i8042 = g_new(MemoryRegion, 1);
-    MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
-    NICInfo *nd;
-    DeviceState *dev;
-    SysBusDevice *sysbus;
-    ISABus *isa_bus;
-    ISADevice *pit;
-    DriveInfo *fds[MAX_FD];
-    qemu_irq esp_reset, dma_enable;
-    qemu_irq *cpu_exit_irq;
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *bios = g_new(MemoryRegion, 1);
-    MemoryRegion *bios2 = g_new(MemoryRegion, 1);
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-#ifdef TARGET_MIPS64
-        cpu_model = "R4000";
-#else
-        /* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */
-        cpu_model = "24Kf";
-#endif
-    }
-    cpu = cpu_mips_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-    env = &cpu->env;
-    qemu_register_reset(main_cpu_reset, cpu);
-
-    /* allocate RAM */
-    memory_region_init_ram(ram, "mips_jazz.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(address_space, 0, ram);
-
-    memory_region_init_ram(bios, "mips_jazz.bios", MAGNUM_BIOS_SIZE);
-    vmstate_register_ram_global(bios);
-    memory_region_set_readonly(bios, true);
-    memory_region_init_alias(bios2, "mips_jazz.bios", bios,
-                             0, MAGNUM_BIOS_SIZE);
-    memory_region_add_subregion(address_space, 0x1fc00000LL, bios);
-    memory_region_add_subregion(address_space, 0xfff00000LL, bios2);
-
-    /* load the BIOS image. */
-    if (bios_name == NULL)
-        bios_name = BIOS_FILENAME;
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    if (filename) {
-        bios_size = load_image_targphys(filename, 0xfff00000LL,
-                                        MAGNUM_BIOS_SIZE);
-        g_free(filename);
-    } else {
-        bios_size = -1;
-    }
-    if (bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) {
-        fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n",
-                bios_name);
-        exit(1);
-    }
-
-    /* Init CPU internal devices */
-    cpu_mips_irq_init_cpu(env);
-    cpu_mips_clock_init(env);
-
-    /* Chipset */
-    rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas,
-                                address_space);
-    memory_region_init_io(dma_dummy, &dma_dummy_ops, NULL, "dummy_dma", 0x1000);
-    memory_region_add_subregion(address_space, 0x8000d000, dma_dummy);
-
-    /* ISA devices */
-    isa_bus = isa_bus_new(NULL, address_space_io);
-    i8259 = i8259_init(isa_bus, env->irq[4]);
-    isa_bus_irqs(isa_bus, i8259);
-    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
-    DMA_init(0, cpu_exit_irq);
-    pit = pit_init(isa_bus, 0x40, 0, NULL);
-    pcspk_init(isa_bus, pit);
-
-    /* ISA IO space at 0x90000000 */
-    isa_mmio_init(0x90000000, 0x01000000);
-    isa_mem_base = 0x11000000;
-
-    /* Video card */
-    switch (jazz_model) {
-    case JAZZ_MAGNUM:
-        dev = qdev_create(NULL, "sysbus-g364");
-        qdev_init_nofail(dev);
-        sysbus = SYS_BUS_DEVICE(dev);
-        sysbus_mmio_map(sysbus, 0, 0x60080000);
-        sysbus_mmio_map(sysbus, 1, 0x40000000);
-        sysbus_connect_irq(sysbus, 0, rc4030[3]);
-        {
-            /* Simple ROM, so user doesn't have to provide one */
-            MemoryRegion *rom_mr = g_new(MemoryRegion, 1);
-            memory_region_init_ram(rom_mr, "g364fb.rom", 0x80000);
-            vmstate_register_ram_global(rom_mr);
-            memory_region_set_readonly(rom_mr, true);
-            uint8_t *rom = memory_region_get_ram_ptr(rom_mr);
-            memory_region_add_subregion(address_space, 0x60000000, rom_mr);
-            rom[0] = 0x10; /* Mips G364 */
-        }
-        break;
-    case JAZZ_PICA61:
-        isa_vga_mm_init(0x40000000, 0x60000000, 0, get_system_memory());
-        break;
-    default:
-        break;
-    }
-
-    /* Network controller */
-    for (n = 0; n < nb_nics; n++) {
-        nd = &nd_table[n];
-        if (!nd->model)
-            nd->model = g_strdup("dp83932");
-        if (strcmp(nd->model, "dp83932") == 0) {
-            dp83932_init(nd, 0x80001000, 2, get_system_memory(), rc4030[4],
-                         rc4030_opaque, rc4030_dma_memory_rw);
-            break;
-        } else if (is_help_option(nd->model)) {
-            fprintf(stderr, "qemu: Supported NICs: dp83932\n");
-            exit(1);
-        } else {
-            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
-            exit(1);
-        }
-    }
-
-    /* SCSI adapter */
-    esp_init(0x80002000, 0,
-             rc4030_dma_read, rc4030_dma_write, dmas[0],
-             rc4030[5], &esp_reset, &dma_enable);
-
-    /* Floppy */
-    if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) {
-        fprintf(stderr, "qemu: too many floppy drives\n");
-        exit(1);
-    }
-    for (n = 0; n < MAX_FD; n++) {
-        fds[n] = drive_get(IF_FLOPPY, 0, n);
-    }
-    fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds);
-
-    /* Real time clock */
-    rtc_init(isa_bus, 1980, NULL);
-    memory_region_init_io(rtc, &rtc_ops, NULL, "rtc", 0x1000);
-    memory_region_add_subregion(address_space, 0x80004000, rtc);
-
-    /* Keyboard (i8042) */
-    i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1);
-    memory_region_add_subregion(address_space, 0x80005000, i8042);
-
-    /* Serial ports */
-    if (serial_hds[0]) {
-        serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16,
-                       serial_hds[0], DEVICE_NATIVE_ENDIAN);
-    }
-    if (serial_hds[1]) {
-        serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16,
-                       serial_hds[1], DEVICE_NATIVE_ENDIAN);
-    }
-
-    /* Parallel port */
-    if (parallel_hds[0])
-        parallel_mm_init(address_space, 0x80008000, 0, rc4030[0],
-                         parallel_hds[0]);
-
-    /* Sound card */
-    /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
-    audio_init(isa_bus, NULL);
-
-    /* NVRAM */
-    dev = qdev_create(NULL, "ds1225y");
-    qdev_init_nofail(dev);
-    sysbus = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(sysbus, 0, 0x80009000);
-
-    /* LED indicator */
-    sysbus_create_simple("jazz-led", 0x8000f000, NULL);
-}
-
-static
-void mips_magnum_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-        mips_jazz_init(get_system_memory(), get_system_io(),
-                       ram_size, cpu_model, JAZZ_MAGNUM);
-}
-
-static
-void mips_pica61_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    mips_jazz_init(get_system_memory(), get_system_io(),
-                   ram_size, cpu_model, JAZZ_PICA61);
-}
-
-static QEMUMachine mips_magnum_machine = {
-    .name = "magnum",
-    .desc = "MIPS Magnum",
-    .init = mips_magnum_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine mips_pica61_machine = {
-    .name = "pica61",
-    .desc = "Acer Pica 61",
-    .init = mips_pica61_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void mips_jazz_machine_init(void)
-{
-    qemu_register_machine(&mips_magnum_machine);
-    qemu_register_machine(&mips_pica61_machine);
-}
-
-machine_init(mips_jazz_machine_init);
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
deleted file mode 100644 (file)
index 9a67dce..0000000
+++ /dev/null
@@ -1,1037 +0,0 @@
-/*
- * QEMU Malta board support
- *
- * Copyright (c) 2006 Aurelien Jarno
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/fdc.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/smbus.h"
-#include "block/block.h"
-#include "hw/flash.h"
-#include "hw/mips.h"
-#include "hw/mips_cpudevs.h"
-#include "hw/pci/pci.h"
-#include "char/char.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/arch_init.h"
-#include "hw/boards.h"
-#include "qemu/log.h"
-#include "hw/mips-bios.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-#include "hw/sysbus.h"             /* SysBusDevice */
-
-//#define DEBUG_BOARD_INIT
-
-#define ENVP_ADDR              0x80002000l
-#define ENVP_NB_ENTRIES                16
-#define ENVP_ENTRY_SIZE                256
-
-/* Hardware addresses */
-#define FLASH_ADDRESS 0x1e000000ULL
-#define FPGA_ADDRESS  0x1f000000ULL
-#define RESET_ADDRESS 0x1fc00000ULL
-
-#define FLASH_SIZE    0x400000
-
-#define MAX_IDE_BUS 2
-
-typedef struct {
-    MemoryRegion iomem;
-    MemoryRegion iomem_lo; /* 0 - 0x900 */
-    MemoryRegion iomem_hi; /* 0xa00 - 0x100000 */
-    uint32_t leds;
-    uint32_t brk;
-    uint32_t gpout;
-    uint32_t i2cin;
-    uint32_t i2coe;
-    uint32_t i2cout;
-    uint32_t i2csel;
-    CharDriverState *display;
-    char display_text[9];
-    SerialState *uart;
-} MaltaFPGAState;
-
-typedef struct {
-    SysBusDevice busdev;
-    qemu_irq *i8259;
-} MaltaState;
-
-static ISADevice *pit;
-
-static struct _loaderparams {
-    int ram_size;
-    const char *kernel_filename;
-    const char *kernel_cmdline;
-    const char *initrd_filename;
-} loaderparams;
-
-/* Malta FPGA */
-static void malta_fpga_update_display(void *opaque)
-{
-    char leds_text[9];
-    int i;
-    MaltaFPGAState *s = opaque;
-
-    for (i = 7 ; i >= 0 ; i--) {
-        if (s->leds & (1 << i))
-            leds_text[i] = '#';
-        else
-            leds_text[i] = ' ';
-    }
-    leds_text[8] = '\0';
-
-    qemu_chr_fe_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
-    qemu_chr_fe_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
-}
-
-/*
- * EEPROM 24C01 / 24C02 emulation.
- *
- * Emulation for serial EEPROMs:
- * 24C01 - 1024 bit (128 x 8)
- * 24C02 - 2048 bit (256 x 8)
- *
- * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
- */
-
-//~ #define DEBUG
-
-#if defined(DEBUG)
-#  define logout(fmt, ...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ## __VA_ARGS__)
-#else
-#  define logout(fmt, ...) ((void)0)
-#endif
-
-struct _eeprom24c0x_t {
-  uint8_t tick;
-  uint8_t address;
-  uint8_t command;
-  uint8_t ack;
-  uint8_t scl;
-  uint8_t sda;
-  uint8_t data;
-  //~ uint16_t size;
-  uint8_t contents[256];
-};
-
-typedef struct _eeprom24c0x_t eeprom24c0x_t;
-
-static eeprom24c0x_t eeprom = {
-    .contents = {
-        /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00,
-        /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
-        /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00,
-        /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40,
-        /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
-        /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
-        /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
-    },
-};
-
-static uint8_t eeprom24c0x_read(void)
-{
-    logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
-        eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data);
-    return eeprom.sda;
-}
-
-static void eeprom24c0x_write(int scl, int sda)
-{
-    if (eeprom.scl && scl && (eeprom.sda != sda)) {
-        logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
-                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start");
-        if (!sda) {
-            eeprom.tick = 1;
-            eeprom.command = 0;
-        }
-    } else if (eeprom.tick == 0 && !eeprom.ack) {
-        /* Waiting for start. */
-        logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
-                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
-    } else if (!eeprom.scl && scl) {
-        logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
-                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
-        if (eeprom.ack) {
-            logout("\ti2c ack bit = 0\n");
-            sda = 0;
-            eeprom.ack = 0;
-        } else if (eeprom.sda == sda) {
-            uint8_t bit = (sda != 0);
-            logout("\ti2c bit = %d\n", bit);
-            if (eeprom.tick < 9) {
-                eeprom.command <<= 1;
-                eeprom.command += bit;
-                eeprom.tick++;
-                if (eeprom.tick == 9) {
-                    logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write");
-                    eeprom.ack = 1;
-                }
-            } else if (eeprom.tick < 17) {
-                if (eeprom.command & 1) {
-                    sda = ((eeprom.data & 0x80) != 0);
-                }
-                eeprom.address <<= 1;
-                eeprom.address += bit;
-                eeprom.tick++;
-                eeprom.data <<= 1;
-                if (eeprom.tick == 17) {
-                    eeprom.data = eeprom.contents[eeprom.address];
-                    logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data);
-                    eeprom.ack = 1;
-                    eeprom.tick = 0;
-                }
-            } else if (eeprom.tick >= 17) {
-                sda = 0;
-            }
-        } else {
-            logout("\tsda changed with raising scl\n");
-        }
-    } else {
-        logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
-    }
-    eeprom.scl = scl;
-    eeprom.sda = sda;
-}
-
-static uint64_t malta_fpga_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    MaltaFPGAState *s = opaque;
-    uint32_t val = 0;
-    uint32_t saddr;
-
-    saddr = (addr & 0xfffff);
-
-    switch (saddr) {
-
-    /* SWITCH Register */
-    case 0x00200:
-        val = 0x00000000;              /* All switches closed */
-        break;
-
-    /* STATUS Register */
-    case 0x00208:
-#ifdef TARGET_WORDS_BIGENDIAN
-        val = 0x00000012;
-#else
-        val = 0x00000010;
-#endif
-        break;
-
-    /* JMPRS Register */
-    case 0x00210:
-        val = 0x00;
-        break;
-
-    /* LEDBAR Register */
-    case 0x00408:
-        val = s->leds;
-        break;
-
-    /* BRKRES Register */
-    case 0x00508:
-        val = s->brk;
-        break;
-
-    /* UART Registers are handled directly by the serial device */
-
-    /* GPOUT Register */
-    case 0x00a00:
-        val = s->gpout;
-        break;
-
-    /* XXX: implement a real I2C controller */
-
-    /* GPINP Register */
-    case 0x00a08:
-        /* IN = OUT until a real I2C control is implemented */
-        if (s->i2csel)
-            val = s->i2cout;
-        else
-            val = 0x00;
-        break;
-
-    /* I2CINP Register */
-    case 0x00b00:
-        val = ((s->i2cin & ~1) | eeprom24c0x_read());
-        break;
-
-    /* I2COE Register */
-    case 0x00b08:
-        val = s->i2coe;
-        break;
-
-    /* I2COUT Register */
-    case 0x00b10:
-        val = s->i2cout;
-        break;
-
-    /* I2CSEL Register */
-    case 0x00b18:
-        val = s->i2csel;
-        break;
-
-    default:
-#if 0
-        printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
-                addr);
-#endif
-        break;
-    }
-    return val;
-}
-
-static void malta_fpga_write(void *opaque, hwaddr addr,
-                             uint64_t val, unsigned size)
-{
-    MaltaFPGAState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr & 0xfffff);
-
-    switch (saddr) {
-
-    /* SWITCH Register */
-    case 0x00200:
-        break;
-
-    /* JMPRS Register */
-    case 0x00210:
-        break;
-
-    /* LEDBAR Register */
-    case 0x00408:
-        s->leds = val & 0xff;
-        malta_fpga_update_display(s);
-        break;
-
-    /* ASCIIWORD Register */
-    case 0x00410:
-        snprintf(s->display_text, 9, "%08X", (uint32_t)val);
-        malta_fpga_update_display(s);
-        break;
-
-    /* ASCIIPOS0 to ASCIIPOS7 Registers */
-    case 0x00418:
-    case 0x00420:
-    case 0x00428:
-    case 0x00430:
-    case 0x00438:
-    case 0x00440:
-    case 0x00448:
-    case 0x00450:
-        s->display_text[(saddr - 0x00418) >> 3] = (char) val;
-        malta_fpga_update_display(s);
-        break;
-
-    /* SOFTRES Register */
-    case 0x00500:
-        if (val == 0x42)
-            qemu_system_reset_request ();
-        break;
-
-    /* BRKRES Register */
-    case 0x00508:
-        s->brk = val & 0xff;
-        break;
-
-    /* UART Registers are handled directly by the serial device */
-
-    /* GPOUT Register */
-    case 0x00a00:
-        s->gpout = val & 0xff;
-        break;
-
-    /* I2COE Register */
-    case 0x00b08:
-        s->i2coe = val & 0x03;
-        break;
-
-    /* I2COUT Register */
-    case 0x00b10:
-        eeprom24c0x_write(val & 0x02, val & 0x01);
-        s->i2cout = val;
-        break;
-
-    /* I2CSEL Register */
-    case 0x00b18:
-        s->i2csel = val & 0x01;
-        break;
-
-    default:
-#if 0
-        printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
-                addr);
-#endif
-        break;
-    }
-}
-
-static const MemoryRegionOps malta_fpga_ops = {
-    .read = malta_fpga_read,
-    .write = malta_fpga_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void malta_fpga_reset(void *opaque)
-{
-    MaltaFPGAState *s = opaque;
-
-    s->leds   = 0x00;
-    s->brk    = 0x0a;
-    s->gpout  = 0x00;
-    s->i2cin  = 0x3;
-    s->i2coe  = 0x0;
-    s->i2cout = 0x3;
-    s->i2csel = 0x1;
-
-    s->display_text[8] = '\0';
-    snprintf(s->display_text, 9, "        ");
-}
-
-static void malta_fpga_led_init(CharDriverState *chr)
-{
-    qemu_chr_fe_printf(chr, "\e[HMalta LEDBAR\r\n");
-    qemu_chr_fe_printf(chr, "+--------+\r\n");
-    qemu_chr_fe_printf(chr, "+        +\r\n");
-    qemu_chr_fe_printf(chr, "+--------+\r\n");
-    qemu_chr_fe_printf(chr, "\n");
-    qemu_chr_fe_printf(chr, "Malta ASCII\r\n");
-    qemu_chr_fe_printf(chr, "+--------+\r\n");
-    qemu_chr_fe_printf(chr, "+        +\r\n");
-    qemu_chr_fe_printf(chr, "+--------+\r\n");
-}
-
-static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
-         hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr)
-{
-    MaltaFPGAState *s;
-
-    s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState));
-
-    memory_region_init_io(&s->iomem, &malta_fpga_ops, s,
-                          "malta-fpga", 0x100000);
-    memory_region_init_alias(&s->iomem_lo, "malta-fpga",
-                             &s->iomem, 0, 0x900);
-    memory_region_init_alias(&s->iomem_hi, "malta-fpga",
-                             &s->iomem, 0xa00, 0x10000-0xa00);
-
-    memory_region_add_subregion(address_space, base, &s->iomem_lo);
-    memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
-
-    s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
-
-    s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
-                             230400, uart_chr, DEVICE_NATIVE_ENDIAN);
-
-    malta_fpga_reset(s);
-    qemu_register_reset(malta_fpga_reset, s);
-
-    return s;
-}
-
-/* Network support */
-static void network_init(void)
-{
-    int i;
-
-    for(i = 0; i < nb_nics; i++) {
-        NICInfo *nd = &nd_table[i];
-        const char *default_devaddr = NULL;
-
-        if (i == 0 && (!nd->model || strcmp(nd->model, "pcnet") == 0))
-            /* The malta board has a PCNet card using PCI SLOT 11 */
-            default_devaddr = "0b";
-
-        pci_nic_init_nofail(nd, "pcnet", default_devaddr);
-    }
-}
-
-/* ROM and pseudo bootloader
-
-   The following code implements a very very simple bootloader. It first
-   loads the registers a0 to a3 to the values expected by the OS, and
-   then jump at the kernel address.
-
-   The bootloader should pass the locations of the kernel arguments and
-   environment variables tables. Those tables contain the 32-bit address
-   of NULL terminated strings. The environment variables table should be
-   terminated by a NULL address.
-
-   For a simpler implementation, the number of kernel arguments is fixed
-   to two (the name of the kernel and the command line), and the two
-   tables are actually the same one.
-
-   The registers a0 to a3 should contain the following values:
-     a0 - number of kernel arguments
-     a1 - 32-bit address of the kernel arguments table
-     a2 - 32-bit address of the environment variables table
-     a3 - RAM size in bytes
-*/
-
-static void write_bootloader (CPUMIPSState *env, uint8_t *base,
-                              int64_t kernel_entry)
-{
-    uint32_t *p;
-
-    /* Small bootloader */
-    p = (uint32_t *)base;
-    stl_raw(p++, 0x0bf00160);                                      /* j 0x1fc00580 */
-    stl_raw(p++, 0x00000000);                                      /* nop */
-
-    /* YAMON service vector */
-    stl_raw(base + 0x500, 0xbfc00580);      /* start: */
-    stl_raw(base + 0x504, 0xbfc0083c);      /* print_count: */
-    stl_raw(base + 0x520, 0xbfc00580);      /* start: */
-    stl_raw(base + 0x52c, 0xbfc00800);      /* flush_cache: */
-    stl_raw(base + 0x534, 0xbfc00808);      /* print: */
-    stl_raw(base + 0x538, 0xbfc00800);      /* reg_cpu_isr: */
-    stl_raw(base + 0x53c, 0xbfc00800);      /* unred_cpu_isr: */
-    stl_raw(base + 0x540, 0xbfc00800);      /* reg_ic_isr: */
-    stl_raw(base + 0x544, 0xbfc00800);      /* unred_ic_isr: */
-    stl_raw(base + 0x548, 0xbfc00800);      /* reg_esr: */
-    stl_raw(base + 0x54c, 0xbfc00800);      /* unreg_esr: */
-    stl_raw(base + 0x550, 0xbfc00800);      /* getchar: */
-    stl_raw(base + 0x554, 0xbfc00800);      /* syscon_read: */
-
-
-    /* Second part of the bootloader */
-    p = (uint32_t *) (base + 0x580);
-    stl_raw(p++, 0x24040002);                                      /* addiu a0, zero, 2 */
-    stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
-    stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */
-    stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
-    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a1, low(ENVP_ADDR) */
-    stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
-    stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
-    stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16));     /* lui a3, high(ram_size) */
-    stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff));  /* ori a3, a3, low(ram_size) */
-
-    /* Load BAR registers as done by YAMON */
-    stl_raw(p++, 0x3c09b400);                                      /* lui t1, 0xb400 */
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    stl_raw(p++, 0x3c08df00);                                      /* lui t0, 0xdf00 */
-#else
-    stl_raw(p++, 0x340800df);                                      /* ori t0, r0, 0x00df */
-#endif
-    stl_raw(p++, 0xad280068);                                      /* sw t0, 0x0068(t1) */
-
-    stl_raw(p++, 0x3c09bbe0);                                      /* lui t1, 0xbbe0 */
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    stl_raw(p++, 0x3c08c000);                                      /* lui t0, 0xc000 */
-#else
-    stl_raw(p++, 0x340800c0);                                      /* ori t0, r0, 0x00c0 */
-#endif
-    stl_raw(p++, 0xad280048);                                      /* sw t0, 0x0048(t1) */
-#ifdef TARGET_WORDS_BIGENDIAN
-    stl_raw(p++, 0x3c084000);                                      /* lui t0, 0x4000 */
-#else
-    stl_raw(p++, 0x34080040);                                      /* ori t0, r0, 0x0040 */
-#endif
-    stl_raw(p++, 0xad280050);                                      /* sw t0, 0x0050(t1) */
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    stl_raw(p++, 0x3c088000);                                      /* lui t0, 0x8000 */
-#else
-    stl_raw(p++, 0x34080080);                                      /* ori t0, r0, 0x0080 */
-#endif
-    stl_raw(p++, 0xad280058);                                      /* sw t0, 0x0058(t1) */
-#ifdef TARGET_WORDS_BIGENDIAN
-    stl_raw(p++, 0x3c083f00);                                      /* lui t0, 0x3f00 */
-#else
-    stl_raw(p++, 0x3408003f);                                      /* ori t0, r0, 0x003f */
-#endif
-    stl_raw(p++, 0xad280060);                                      /* sw t0, 0x0060(t1) */
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    stl_raw(p++, 0x3c08c100);                                      /* lui t0, 0xc100 */
-#else
-    stl_raw(p++, 0x340800c1);                                      /* ori t0, r0, 0x00c1 */
-#endif
-    stl_raw(p++, 0xad280080);                                      /* sw t0, 0x0080(t1) */
-#ifdef TARGET_WORDS_BIGENDIAN
-    stl_raw(p++, 0x3c085e00);                                      /* lui t0, 0x5e00 */
-#else
-    stl_raw(p++, 0x3408005e);                                      /* ori t0, r0, 0x005e */
-#endif
-    stl_raw(p++, 0xad280088);                                      /* sw t0, 0x0088(t1) */
-
-    /* Jump to kernel code */
-    stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff));    /* lui ra, high(kernel_entry) */
-    stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff));            /* ori ra, ra, low(kernel_entry) */
-    stl_raw(p++, 0x03e00008);                                      /* jr ra */
-    stl_raw(p++, 0x00000000);                                      /* nop */
-
-    /* YAMON subroutines */
-    p = (uint32_t *) (base + 0x800);
-    stl_raw(p++, 0x03e00008);                                     /* jr ra */
-    stl_raw(p++, 0x24020000);                                     /* li v0,0 */
-   /* 808 YAMON print */
-    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
-    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
-    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
-    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
-    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
-    stl_raw(p++, 0x10800005);                                     /* beqz a0,834 */
-    stl_raw(p++, 0x00000000);                                     /* nop */
-    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
-    stl_raw(p++, 0x00000000);                                     /* nop */
-    stl_raw(p++, 0x08000205);                                     /* j 814 */
-    stl_raw(p++, 0x00000000);                                     /* nop */
-    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
-    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
-    /* 0x83c YAMON print_count */
-    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
-    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
-    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
-    stl_raw(p++, 0x00c06021);                                     /* move t4,a2 */
-    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
-    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
-    stl_raw(p++, 0x00000000);                                     /* nop */
-    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
-    stl_raw(p++, 0x258cffff);                                     /* addiu t4,t4,-1 */
-    stl_raw(p++, 0x1580fffa);                                     /* bnez t4,84c */
-    stl_raw(p++, 0x00000000);                                     /* nop */
-    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
-    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
-    /* 0x870 */
-    stl_raw(p++, 0x3c08b800);                                     /* lui t0,0xb400 */
-    stl_raw(p++, 0x350803f8);                                     /* ori t0,t0,0x3f8 */
-    stl_raw(p++, 0x91090005);                                     /* lbu t1,5(t0) */
-    stl_raw(p++, 0x00000000);                                     /* nop */
-    stl_raw(p++, 0x31290040);                                     /* andi t1,t1,0x40 */
-    stl_raw(p++, 0x1120fffc);                                     /* beqz t1,878 <outch+0x8> */
-    stl_raw(p++, 0x00000000);                                     /* nop */
-    stl_raw(p++, 0x03e00008);                                     /* jr ra */
-    stl_raw(p++, 0xa1040000);                                     /* sb a0,0(t0) */
-
-}
-
-static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
-                                        const char *string, ...)
-{
-    va_list ap;
-    int32_t table_addr;
-
-    if (index >= ENVP_NB_ENTRIES)
-        return;
-
-    if (string == NULL) {
-        prom_buf[index] = 0;
-        return;
-    }
-
-    table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
-    prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
-
-    va_start(ap, string);
-    vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
-    va_end(ap);
-}
-
-/* Kernel */
-static int64_t load_kernel (void)
-{
-    int64_t kernel_entry, kernel_high;
-    long initrd_size;
-    ram_addr_t initrd_offset;
-    int big_endian;
-    uint32_t *prom_buf;
-    long prom_size;
-    int prom_index = 0;
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    big_endian = 1;
-#else
-    big_endian = 0;
-#endif
-
-    if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
-                 (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
-                 big_endian, ELF_MACHINE, 1) < 0) {
-        fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                loaderparams.kernel_filename);
-        exit(1);
-    }
-
-    /* load initrd */
-    initrd_size = 0;
-    initrd_offset = 0;
-    if (loaderparams.initrd_filename) {
-        initrd_size = get_image_size (loaderparams.initrd_filename);
-        if (initrd_size > 0) {
-            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
-            if (initrd_offset + initrd_size > ram_size) {
-                fprintf(stderr,
-                        "qemu: memory too small for initial ram disk '%s'\n",
-                        loaderparams.initrd_filename);
-                exit(1);
-            }
-            initrd_size = load_image_targphys(loaderparams.initrd_filename,
-                                              initrd_offset,
-                                              ram_size - initrd_offset);
-        }
-        if (initrd_size == (target_ulong) -1) {
-            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                    loaderparams.initrd_filename);
-            exit(1);
-        }
-    }
-
-    /* Setup prom parameters. */
-    prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
-    prom_buf = g_malloc(prom_size);
-
-    prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
-    if (initrd_size > 0) {
-        prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
-                 cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
-                 loaderparams.kernel_cmdline);
-    } else {
-        prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline);
-    }
-
-    prom_set(prom_buf, prom_index++, "memsize");
-    prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size);
-    prom_set(prom_buf, prom_index++, "modetty0");
-    prom_set(prom_buf, prom_index++, "38400n8r");
-    prom_set(prom_buf, prom_index++, NULL);
-
-    rom_add_blob_fixed("prom", prom_buf, prom_size,
-                       cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
-
-    return kernel_entry;
-}
-
-static void malta_mips_config(MIPSCPU *cpu)
-{
-    CPUMIPSState *env = &cpu->env;
-    CPUState *cs = CPU(cpu);
-
-    env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) |
-                         ((smp_cpus * cs->nr_threads - 1) << CP0MVPC0_PTC);
-}
-
-static void main_cpu_reset(void *opaque)
-{
-    MIPSCPU *cpu = opaque;
-    CPUMIPSState *env = &cpu->env;
-
-    cpu_reset(CPU(cpu));
-
-    /* The bootloader does not need to be rewritten as it is located in a
-       read only location. The kernel location and the arguments table
-       location does not change. */
-    if (loaderparams.kernel_filename) {
-        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
-    }
-
-    malta_mips_config(cpu);
-}
-
-static void cpu_request_exit(void *opaque, int irq, int level)
-{
-    CPUMIPSState *env = cpu_single_env;
-
-    if (env && level) {
-        cpu_exit(env);
-    }
-}
-
-static
-void mips_malta_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    char *filename;
-    pflash_t *fl;
-    MemoryRegion *system_memory = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1);
-    target_long bios_size = FLASH_SIZE;
-    int64_t kernel_entry;
-    PCIBus *pci_bus;
-    ISABus *isa_bus;
-    MIPSCPU *cpu;
-    CPUMIPSState *env;
-    qemu_irq *isa_irq;
-    qemu_irq *cpu_exit_irq;
-    int piix4_devfn;
-    i2c_bus *smbus;
-    int i;
-    DriveInfo *dinfo;
-    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
-    DriveInfo *fd[MAX_FD];
-    int fl_idx = 0;
-    int fl_sectors = bios_size >> 16;
-    int be;
-
-    DeviceState *dev = qdev_create(NULL, "mips-malta");
-    MaltaState *s = DO_UPCAST(MaltaState, busdev.qdev, dev);
-
-    qdev_init_nofail(dev);
-
-    /* Make sure the first 3 serial ports are associated with a device. */
-    for(i = 0; i < 3; i++) {
-        if (!serial_hds[i]) {
-            char label[32];
-            snprintf(label, sizeof(label), "serial%d", i);
-            serial_hds[i] = qemu_chr_new(label, "null", NULL);
-        }
-    }
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-#ifdef TARGET_MIPS64
-        cpu_model = "20Kc";
-#else
-        cpu_model = "24Kf";
-#endif
-    }
-
-    for (i = 0; i < smp_cpus; i++) {
-        cpu = cpu_mips_init(cpu_model);
-        if (cpu == NULL) {
-            fprintf(stderr, "Unable to find CPU definition\n");
-            exit(1);
-        }
-        env = &cpu->env;
-
-        /* Init internal devices */
-        cpu_mips_irq_init_cpu(env);
-        cpu_mips_clock_init(env);
-        qemu_register_reset(main_cpu_reset, cpu);
-    }
-    env = first_cpu;
-
-    /* allocate RAM */
-    if (ram_size > (256 << 20)) {
-        fprintf(stderr,
-                "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
-                ((unsigned int)ram_size / (1 << 20)));
-        exit(1);
-    }
-    memory_region_init_ram(ram, "mips_malta.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(system_memory, 0, ram);
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    be = 1;
-#else
-    be = 0;
-#endif
-    /* FPGA */
-    /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
-    malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]);
-
-    /* Load firmware in flash / BIOS. */
-    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
-#ifdef DEBUG_BOARD_INIT
-    if (dinfo) {
-        printf("Register parallel flash %d size " TARGET_FMT_lx " at "
-               "addr %08llx '%s' %x\n",
-               fl_idx, bios_size, FLASH_ADDRESS,
-               bdrv_get_device_name(dinfo->bdrv), fl_sectors);
-    }
-#endif
-    fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios",
-                               BIOS_SIZE, dinfo ? dinfo->bdrv : NULL,
-                               65536, fl_sectors,
-                               4, 0x0000, 0x0000, 0x0000, 0x0000, be);
-    bios = pflash_cfi01_get_memory(fl);
-    fl_idx++;
-    if (kernel_filename) {
-        /* Write a small bootloader to the flash location. */
-        loaderparams.ram_size = ram_size;
-        loaderparams.kernel_filename = kernel_filename;
-        loaderparams.kernel_cmdline = kernel_cmdline;
-        loaderparams.initrd_filename = initrd_filename;
-        kernel_entry = load_kernel();
-        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
-    } else {
-        /* Load firmware from flash. */
-        if (!dinfo) {
-            /* Load a BIOS image. */
-            if (bios_name == NULL) {
-                bios_name = BIOS_FILENAME;
-            }
-            filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-            if (filename) {
-                bios_size = load_image_targphys(filename, FLASH_ADDRESS,
-                                                BIOS_SIZE);
-                g_free(filename);
-            } else {
-                bios_size = -1;
-            }
-            if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
-                fprintf(stderr,
-                        "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
-                        bios_name);
-                exit(1);
-            }
-        }
-        /* In little endian mode the 32bit words in the bios are swapped,
-           a neat trick which allows bi-endian firmware. */
-#ifndef TARGET_WORDS_BIGENDIAN
-        {
-            uint32_t *addr = memory_region_get_ram_ptr(bios);
-            uint32_t *end = addr + bios_size;
-            while (addr < end) {
-                bswap32s(addr);
-                addr++;
-            }
-        }
-#endif
-    }
-
-    /* Map the BIOS at a 2nd physical location, as on the real board. */
-    memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE);
-    memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_alias);
-
-    /* Board ID = 0x420 (Malta Board with CoreLV)
-       XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
-       map to the board ID. */
-    stl_p(memory_region_get_ram_ptr(bios) + 0x10, 0x00000420);
-
-    /* Init internal devices */
-    cpu_mips_irq_init_cpu(env);
-    cpu_mips_clock_init(env);
-
-    /*
-     * We have a circular dependency problem: pci_bus depends on isa_irq,
-     * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
-     * on piix4, and piix4 depends on pci_bus.  To stop the cycle we have
-     * qemu_irq_proxy() adds an extra bit of indirection, allowing us
-     * to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
-     */
-    isa_irq = qemu_irq_proxy(&s->i8259, 16);
-
-    /* Northbridge */
-    pci_bus = gt64120_register(isa_irq);
-
-    /* Southbridge */
-    ide_drive_get(hd, MAX_IDE_BUS);
-
-    piix4_devfn = piix4_init(pci_bus, &isa_bus, 80);
-
-    /* Interrupt controller */
-    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
-    s->i8259 = i8259_init(isa_bus, env->irq[2]);
-
-    isa_bus_irqs(isa_bus, s->i8259);
-    pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
-    pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
-    smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
-                          isa_get_irq(NULL, 9), NULL, 0, NULL);
-    /* TODO: Populate SPD eeprom data.  */
-    smbus_eeprom_init(smbus, 8, NULL, 0);
-    pit = pit_init(isa_bus, 0x40, 0, NULL);
-    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
-    DMA_init(0, cpu_exit_irq);
-
-    /* Super I/O */
-    isa_create_simple(isa_bus, "i8042");
-
-    rtc_init(isa_bus, 2000, NULL);
-    serial_isa_init(isa_bus, 0, serial_hds[0]);
-    serial_isa_init(isa_bus, 1, serial_hds[1]);
-    if (parallel_hds[0])
-        parallel_init(isa_bus, 0, parallel_hds[0]);
-    for(i = 0; i < MAX_FD; i++) {
-        fd[i] = drive_get(IF_FLOPPY, 0, i);
-    }
-    fdctrl_init_isa(isa_bus, fd);
-
-    /* Sound card */
-    audio_init(isa_bus, pci_bus);
-
-    /* Network card */
-    network_init();
-
-    /* Optional PCI video card */
-    pci_vga_init(pci_bus);
-}
-
-static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
-{
-    return 0;
-}
-
-static void mips_malta_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = mips_malta_sysbus_device_init;
-}
-
-static const TypeInfo mips_malta_device = {
-    .name          = "mips-malta",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(MaltaState),
-    .class_init    = mips_malta_class_init,
-};
-
-static QEMUMachine mips_malta_machine = {
-    .name = "malta",
-    .desc = "MIPS Malta Core LV",
-    .init = mips_malta_init,
-    .max_cpus = 16,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void mips_malta_register_types(void)
-{
-    type_register_static(&mips_malta_device);
-}
-
-static void mips_malta_machine_init(void)
-{
-    qemu_register_machine(&mips_malta_machine);
-}
-
-type_init(mips_malta_register_types)
-machine_init(mips_malta_machine_init);
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
deleted file mode 100644 (file)
index 4935c78..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * QEMU/mipssim emulation
- *
- * Emulates a very simple machine model similar to the one used by the
- * proprietary MIPS emulator.
- * 
- * Copyright (c) 2007 Thiemo Seufer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/hw.h"
-#include "hw/mips.h"
-#include "hw/mips_cpudevs.h"
-#include "hw/serial.h"
-#include "hw/isa.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/mips-bios.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-static struct _loaderparams {
-    int ram_size;
-    const char *kernel_filename;
-    const char *kernel_cmdline;
-    const char *initrd_filename;
-} loaderparams;
-
-typedef struct ResetData {
-    MIPSCPU *cpu;
-    uint64_t vector;
-} ResetData;
-
-static int64_t load_kernel(void)
-{
-    int64_t entry, kernel_high;
-    long kernel_size;
-    long initrd_size;
-    ram_addr_t initrd_offset;
-    int big_endian;
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    big_endian = 1;
-#else
-    big_endian = 0;
-#endif
-
-    kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
-                           NULL, (uint64_t *)&entry, NULL,
-                           (uint64_t *)&kernel_high, big_endian,
-                           ELF_MACHINE, 1);
-    if (kernel_size >= 0) {
-        if ((entry & ~0x7fffffffULL) == 0x80000000)
-            entry = (int32_t)entry;
-    } else {
-        fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                loaderparams.kernel_filename);
-        exit(1);
-    }
-
-    /* load initrd */
-    initrd_size = 0;
-    initrd_offset = 0;
-    if (loaderparams.initrd_filename) {
-        initrd_size = get_image_size (loaderparams.initrd_filename);
-        if (initrd_size > 0) {
-            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
-            if (initrd_offset + initrd_size > loaderparams.ram_size) {
-                fprintf(stderr,
-                        "qemu: memory too small for initial ram disk '%s'\n",
-                        loaderparams.initrd_filename);
-                exit(1);
-            }
-            initrd_size = load_image_targphys(loaderparams.initrd_filename,
-                initrd_offset, loaderparams.ram_size - initrd_offset);
-        }
-        if (initrd_size == (target_ulong) -1) {
-            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                    loaderparams.initrd_filename);
-            exit(1);
-        }
-    }
-    return entry;
-}
-
-static void main_cpu_reset(void *opaque)
-{
-    ResetData *s = (ResetData *)opaque;
-    CPUMIPSState *env = &s->cpu->env;
-
-    cpu_reset(CPU(s->cpu));
-    env->active_tc.PC = s->vector & ~(target_ulong)1;
-    if (s->vector & 1) {
-        env->hflags |= MIPS_HFLAG_M16;
-    }
-}
-
-static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "mipsnet");
-    qdev_set_nic_properties(dev, nd);
-    qdev_init_nofail(dev);
-
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(s, 0, irq);
-    memory_region_add_subregion(get_system_io(),
-                                base,
-                                sysbus_mmio_get_region(s, 0));
-}
-
-static void
-mips_mipssim_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    char *filename;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *bios = g_new(MemoryRegion, 1);
-    MIPSCPU *cpu;
-    CPUMIPSState *env;
-    ResetData *reset_info;
-    int bios_size;
-
-    /* Init CPUs. */
-    if (cpu_model == NULL) {
-#ifdef TARGET_MIPS64
-        cpu_model = "5Kf";
-#else
-        cpu_model = "24Kf";
-#endif
-    }
-    cpu = cpu_mips_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-    env = &cpu->env;
-
-    reset_info = g_malloc0(sizeof(ResetData));
-    reset_info->cpu = cpu;
-    reset_info->vector = env->active_tc.PC;
-    qemu_register_reset(main_cpu_reset, reset_info);
-
-    /* Allocate RAM. */
-    memory_region_init_ram(ram, "mips_mipssim.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_init_ram(bios, "mips_mipssim.bios", BIOS_SIZE);
-    vmstate_register_ram_global(bios);
-    memory_region_set_readonly(bios, true);
-
-    memory_region_add_subregion(address_space_mem, 0, ram);
-
-    /* Map the BIOS / boot exception handler. */
-    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
-    /* Load a BIOS / boot exception handler image. */
-    if (bios_name == NULL)
-        bios_name = BIOS_FILENAME;
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    if (filename) {
-        bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE);
-        g_free(filename);
-    } else {
-        bios_size = -1;
-    }
-    if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
-        /* Bail out if we have neither a kernel image nor boot vector code. */
-        fprintf(stderr,
-                "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
-                filename);
-        exit(1);
-    } else {
-        /* We have a boot vector start address. */
-        env->active_tc.PC = (target_long)(int32_t)0xbfc00000;
-    }
-
-    if (kernel_filename) {
-        loaderparams.ram_size = ram_size;
-        loaderparams.kernel_filename = kernel_filename;
-        loaderparams.kernel_cmdline = kernel_cmdline;
-        loaderparams.initrd_filename = initrd_filename;
-        reset_info->vector = load_kernel();
-    }
-
-    /* Init CPU internal devices. */
-    cpu_mips_irq_init_cpu(env);
-    cpu_mips_clock_init(env);
-
-    /* Register 64 KB of ISA IO space at 0x1fd00000. */
-    isa_mmio_init(0x1fd00000, 0x00010000);
-
-    /* A single 16450 sits at offset 0x3f8. It is attached to
-       MIPS CPU INT2, which is interrupt 4. */
-    if (serial_hds[0])
-        serial_init(0x3f8, env->irq[4], 115200, serial_hds[0],
-                    get_system_io());
-
-    if (nd_table[0].used)
-        /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
-        mipsnet_init(0x4200, env->irq[2], &nd_table[0]);
-}
-
-static QEMUMachine mips_mipssim_machine = {
-    .name = "mipssim",
-    .desc = "MIPS MIPSsim platform",
-    .init = mips_mipssim_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void mips_mipssim_machine_init(void)
-{
-    qemu_register_machine(&mips_mipssim_machine);
-}
-
-machine_init(mips_mipssim_machine_init);
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
deleted file mode 100644 (file)
index 539a562..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * QEMU/MIPS pseudo-board
- *
- * emulates a simple machine with ISA-like bus.
- * ISA IO space mapped to the 0x14000000 (PHYS) and
- * ISA memory at the 0x10000000 (PHYS, 16Mb in size).
- * All peripherial devices are attached to this "bus" with
- * the standard PC ISA addresses.
-*/
-#include "hw/hw.h"
-#include "hw/mips.h"
-#include "hw/mips_cpudevs.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/isa.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/flash.h"
-#include "qemu/log.h"
-#include "hw/mips-bios.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-#define MAX_IDE_BUS 2
-
-static const int ide_iobase[2] = { 0x1f0, 0x170 };
-static const int ide_iobase2[2] = { 0x3f6, 0x376 };
-static const int ide_irq[2] = { 14, 15 };
-
-static ISADevice *pit; /* PIT i8254 */
-
-/* i8254 PIT is attached to the IRQ0 at PIC i8259 */
-
-static struct _loaderparams {
-    int ram_size;
-    const char *kernel_filename;
-    const char *kernel_cmdline;
-    const char *initrd_filename;
-} loaderparams;
-
-static void mips_qemu_write (void *opaque, hwaddr addr,
-                             uint64_t val, unsigned size)
-{
-    if ((addr & 0xffff) == 0 && val == 42)
-        qemu_system_reset_request ();
-    else if ((addr & 0xffff) == 4 && val == 42)
-        qemu_system_shutdown_request ();
-}
-
-static uint64_t mips_qemu_read (void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    return 0;
-}
-
-static const MemoryRegionOps mips_qemu_ops = {
-    .read = mips_qemu_read,
-    .write = mips_qemu_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-typedef struct ResetData {
-    MIPSCPU *cpu;
-    uint64_t vector;
-} ResetData;
-
-static int64_t load_kernel(void)
-{
-    int64_t entry, kernel_high;
-    long kernel_size, initrd_size, params_size;
-    ram_addr_t initrd_offset;
-    uint32_t *params_buf;
-    int big_endian;
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    big_endian = 1;
-#else
-    big_endian = 0;
-#endif
-    kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
-                           NULL, (uint64_t *)&entry, NULL,
-                           (uint64_t *)&kernel_high, big_endian,
-                           ELF_MACHINE, 1);
-    if (kernel_size >= 0) {
-        if ((entry & ~0x7fffffffULL) == 0x80000000)
-            entry = (int32_t)entry;
-    } else {
-        fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                loaderparams.kernel_filename);
-        exit(1);
-    }
-
-    /* load initrd */
-    initrd_size = 0;
-    initrd_offset = 0;
-    if (loaderparams.initrd_filename) {
-        initrd_size = get_image_size (loaderparams.initrd_filename);
-        if (initrd_size > 0) {
-            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
-            if (initrd_offset + initrd_size > ram_size) {
-                fprintf(stderr,
-                        "qemu: memory too small for initial ram disk '%s'\n",
-                        loaderparams.initrd_filename);
-                exit(1);
-            }
-            initrd_size = load_image_targphys(loaderparams.initrd_filename,
-                                              initrd_offset,
-                                              ram_size - initrd_offset);
-        }
-        if (initrd_size == (target_ulong) -1) {
-            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                    loaderparams.initrd_filename);
-            exit(1);
-        }
-    }
-
-    /* Store command line.  */
-    params_size = 264;
-    params_buf = g_malloc(params_size);
-
-    params_buf[0] = tswap32(ram_size);
-    params_buf[1] = tswap32(0x12345678);
-
-    if (initrd_size > 0) {
-        snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%li %s",
-                 cpu_mips_phys_to_kseg0(NULL, initrd_offset),
-                 initrd_size, loaderparams.kernel_cmdline);
-    } else {
-        snprintf((char *)params_buf + 8, 256, "%s", loaderparams.kernel_cmdline);
-    }
-
-    rom_add_blob_fixed("params", params_buf, params_size,
-                       (16 << 20) - 264);
-
-    return entry;
-}
-
-static void main_cpu_reset(void *opaque)
-{
-    ResetData *s = (ResetData *)opaque;
-    CPUMIPSState *env = &s->cpu->env;
-
-    cpu_reset(CPU(s->cpu));
-    env->active_tc.PC = s->vector;
-}
-
-static const int sector_len = 32 * 1024;
-static
-void mips_r4k_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    char *filename;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *bios;
-    MemoryRegion *iomem = g_new(MemoryRegion, 1);
-    int bios_size;
-    MIPSCPU *cpu;
-    CPUMIPSState *env;
-    ResetData *reset_info;
-    int i;
-    qemu_irq *i8259;
-    ISABus *isa_bus;
-    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
-    DriveInfo *dinfo;
-    int be;
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-#ifdef TARGET_MIPS64
-        cpu_model = "R4000";
-#else
-        cpu_model = "24Kf";
-#endif
-    }
-    cpu = cpu_mips_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-    env = &cpu->env;
-
-    reset_info = g_malloc0(sizeof(ResetData));
-    reset_info->cpu = cpu;
-    reset_info->vector = env->active_tc.PC;
-    qemu_register_reset(main_cpu_reset, reset_info);
-
-    /* allocate RAM */
-    if (ram_size > (256 << 20)) {
-        fprintf(stderr,
-                "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
-                ((unsigned int)ram_size / (1 << 20)));
-        exit(1);
-    }
-    memory_region_init_ram(ram, "mips_r4k.ram", ram_size);
-    vmstate_register_ram_global(ram);
-
-    memory_region_add_subregion(address_space_mem, 0, ram);
-
-    memory_region_init_io(iomem, &mips_qemu_ops, NULL, "mips-qemu", 0x10000);
-    memory_region_add_subregion(address_space_mem, 0x1fbf0000, iomem);
-
-    /* Try to load a BIOS image. If this fails, we continue regardless,
-       but initialize the hardware ourselves. When a kernel gets
-       preloaded we also initialize the hardware, since the BIOS wasn't
-       run. */
-    if (bios_name == NULL)
-        bios_name = BIOS_FILENAME;
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    if (filename) {
-        bios_size = get_image_size(filename);
-    } else {
-        bios_size = -1;
-    }
-#ifdef TARGET_WORDS_BIGENDIAN
-    be = 1;
-#else
-    be = 0;
-#endif
-    if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
-        bios = g_new(MemoryRegion, 1);
-        memory_region_init_ram(bios, "mips_r4k.bios", BIOS_SIZE);
-        vmstate_register_ram_global(bios);
-        memory_region_set_readonly(bios, true);
-        memory_region_add_subregion(get_system_memory(), 0x1fc00000, bios);
-
-        load_image_targphys(filename, 0x1fc00000, BIOS_SIZE);
-    } else if ((dinfo = drive_get(IF_PFLASH, 0, 0)) != NULL) {
-        uint32_t mips_rom = 0x00400000;
-        if (!pflash_cfi01_register(0x1fc00000, NULL, "mips_r4k.bios", mips_rom,
-                                   dinfo->bdrv, sector_len,
-                                   mips_rom / sector_len,
-                                   4, 0, 0, 0, 0, be)) {
-            fprintf(stderr, "qemu: Error registering flash memory.\n");
-       }
-    }
-    else {
-       /* not fatal */
-        fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
-               bios_name);
-    }
-    if (filename) {
-        g_free(filename);
-    }
-
-    if (kernel_filename) {
-        loaderparams.ram_size = ram_size;
-        loaderparams.kernel_filename = kernel_filename;
-        loaderparams.kernel_cmdline = kernel_cmdline;
-        loaderparams.initrd_filename = initrd_filename;
-        reset_info->vector = load_kernel();
-    }
-
-    /* Init CPU internal devices */
-    cpu_mips_irq_init_cpu(env);
-    cpu_mips_clock_init(env);
-
-    /* The PIC is attached to the MIPS CPU INT0 pin */
-    isa_bus = isa_bus_new(NULL, get_system_io());
-    i8259 = i8259_init(isa_bus, env->irq[2]);
-    isa_bus_irqs(isa_bus, i8259);
-
-    rtc_init(isa_bus, 2000, NULL);
-
-    /* Register 64 KB of ISA IO space at 0x14000000 */
-    isa_mmio_init(0x14000000, 0x00010000);
-    isa_mem_base = 0x10000000;
-
-    pit = pit_init(isa_bus, 0x40, 0, NULL);
-
-    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
-        if (serial_hds[i]) {
-            serial_isa_init(isa_bus, i, serial_hds[i]);
-        }
-    }
-
-    isa_vga_init(isa_bus);
-
-    if (nd_table[0].used)
-        isa_ne2000_init(isa_bus, 0x300, 9, &nd_table[0]);
-
-    ide_drive_get(hd, MAX_IDE_BUS);
-    for(i = 0; i < MAX_IDE_BUS; i++)
-        isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i],
-                     hd[MAX_IDE_DEVS * i],
-                    hd[MAX_IDE_DEVS * i + 1]);
-
-    isa_create_simple(isa_bus, "i8042");
-}
-
-static QEMUMachine mips_machine = {
-    .name = "mips",
-    .desc = "mips r4k platform",
-    .init = mips_r4k_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void mips_machine_init(void)
-{
-    qemu_register_machine(&mips_machine);
-}
-
-machine_init(mips_machine_init);
diff --git a/hw/mips_timer.c b/hw/mips_timer.c
deleted file mode 100644 (file)
index 9ad13f3..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * QEMU MIPS timer support
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/hw.h"
-#include "hw/mips_cpudevs.h"
-#include "qemu/timer.h"
-
-#define TIMER_FREQ     100 * 1000 * 1000
-
-/* XXX: do not use a global */
-uint32_t cpu_mips_get_random (CPUMIPSState *env)
-{
-    static uint32_t lfsr = 1;
-    static uint32_t prev_idx = 0;
-    uint32_t idx;
-    /* Don't return same value twice, so get another value */
-    do {
-        lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u);
-        idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
-    } while (idx == prev_idx);
-    prev_idx = idx;
-    return idx;
-}
-
-/* MIPS R4K timer */
-static void cpu_mips_timer_update(CPUMIPSState *env)
-{
-    uint64_t now, next;
-    uint32_t wait;
-
-    now = qemu_get_clock_ns(vm_clock);
-    wait = env->CP0_Compare - env->CP0_Count -
-           (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
-    next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
-    qemu_mod_timer(env->timer, next);
-}
-
-/* Expire the timer.  */
-static void cpu_mips_timer_expire(CPUMIPSState *env)
-{
-    cpu_mips_timer_update(env);
-    if (env->insn_flags & ISA_MIPS32R2) {
-        env->CP0_Cause |= 1 << CP0Ca_TI;
-    }
-    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
-}
-
-uint32_t cpu_mips_get_count (CPUMIPSState *env)
-{
-    if (env->CP0_Cause & (1 << CP0Ca_DC)) {
-        return env->CP0_Count;
-    } else {
-        uint64_t now;
-
-        now = qemu_get_clock_ns(vm_clock);
-        if (qemu_timer_pending(env->timer)
-            && qemu_timer_expired(env->timer, now)) {
-            /* The timer has already expired.  */
-            cpu_mips_timer_expire(env);
-        }
-
-        return env->CP0_Count +
-            (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
-    }
-}
-
-void cpu_mips_store_count (CPUMIPSState *env, uint32_t count)
-{
-    if (env->CP0_Cause & (1 << CP0Ca_DC))
-        env->CP0_Count = count;
-    else {
-        /* Store new count register */
-        env->CP0_Count =
-            count - (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock),
-                                       TIMER_FREQ, get_ticks_per_sec());
-        /* Update timer timer */
-        cpu_mips_timer_update(env);
-    }
-}
-
-void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value)
-{
-    env->CP0_Compare = value;
-    if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
-        cpu_mips_timer_update(env);
-    if (env->insn_flags & ISA_MIPS32R2)
-        env->CP0_Cause &= ~(1 << CP0Ca_TI);
-    qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
-}
-
-void cpu_mips_start_count(CPUMIPSState *env)
-{
-    cpu_mips_store_count(env, env->CP0_Count);
-}
-
-void cpu_mips_stop_count(CPUMIPSState *env)
-{
-    /* Store the current value */
-    env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock),
-                                         TIMER_FREQ, get_ticks_per_sec());
-}
-
-static void mips_timer_cb (void *opaque)
-{
-    CPUMIPSState *env;
-
-    env = opaque;
-#if 0
-    qemu_log("%s\n", __func__);
-#endif
-
-    if (env->CP0_Cause & (1 << CP0Ca_DC))
-        return;
-
-    /* ??? This callback should occur when the counter is exactly equal to
-       the comparator value.  Offset the count by one to avoid immediately
-       retriggering the callback before any virtual time has passed.  */
-    env->CP0_Count++;
-    cpu_mips_timer_expire(env);
-    env->CP0_Count--;
-}
-
-void cpu_mips_clock_init (CPUMIPSState *env)
-{
-    env->timer = qemu_new_timer_ns(vm_clock, &mips_timer_cb, env);
-    env->CP0_Compare = 0;
-    cpu_mips_store_count(env, 1);
-}
diff --git a/hw/multiboot.c b/hw/multiboot.c
deleted file mode 100644 (file)
index 3cb228f..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * QEMU PC System Emulator
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/hw.h"
-#include "hw/fw_cfg.h"
-#include "hw/multiboot.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/sysemu.h"
-
-/* Show multiboot debug output */
-//#define DEBUG_MULTIBOOT
-
-#ifdef DEBUG_MULTIBOOT
-#define mb_debug(a...) fprintf(stderr, ## a)
-#else
-#define mb_debug(a...)
-#endif
-
-#define MULTIBOOT_STRUCT_ADDR 0x9000
-
-#if MULTIBOOT_STRUCT_ADDR > 0xf0000
-#error multiboot struct needs to fit in 16 bit real mode
-#endif
-
-enum {
-    /* Multiboot info */
-    MBI_FLAGS       = 0,
-    MBI_MEM_LOWER   = 4,
-    MBI_MEM_UPPER   = 8,
-    MBI_BOOT_DEVICE = 12,
-    MBI_CMDLINE     = 16,
-    MBI_MODS_COUNT  = 20,
-    MBI_MODS_ADDR   = 24,
-    MBI_MMAP_ADDR   = 48,
-
-    MBI_SIZE        = 88,
-
-    /* Multiboot modules */
-    MB_MOD_START    = 0,
-    MB_MOD_END      = 4,
-    MB_MOD_CMDLINE  = 8,
-
-    MB_MOD_SIZE     = 16,
-
-    /* Region offsets */
-    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
-    ADDR_MBI      = ADDR_E820_MAP + 0x500,
-
-    /* Multiboot flags */
-    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
-    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
-    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
-    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
-    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
-};
-
-typedef struct {
-    /* buffer holding kernel, cmdlines and mb_infos */
-    void *mb_buf;
-    /* address in target */
-    hwaddr mb_buf_phys;
-    /* size of mb_buf in bytes */
-    unsigned mb_buf_size;
-    /* offset of mb-info's in bytes */
-    hwaddr offset_mbinfo;
-    /* offset in buffer for cmdlines in bytes */
-    hwaddr offset_cmdlines;
-    /* offset of modules in bytes */
-    hwaddr offset_mods;
-    /* available slots for mb modules infos */
-    int mb_mods_avail;
-    /* currently used slots of mb modules */
-    int mb_mods_count;
-} MultibootState;
-
-static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
-{
-    hwaddr p = s->offset_cmdlines;
-    char *b = (char *)s->mb_buf + p;
-
-    get_opt_value(b, strlen(cmdline) + 1, cmdline);
-    s->offset_cmdlines += strlen(b) + 1;
-    return s->mb_buf_phys + p;
-}
-
-static void mb_add_mod(MultibootState *s,
-                       hwaddr start, hwaddr end,
-                       hwaddr cmdline_phys)
-{
-    char *p;
-    assert(s->mb_mods_count < s->mb_mods_avail);
-
-    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
-
-    stl_p(p + MB_MOD_START,   start);
-    stl_p(p + MB_MOD_END,     end);
-    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
-
-    mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx"\n",
-             s->mb_mods_count, start, end);
-
-    s->mb_mods_count++;
-}
-
-int load_multiboot(void *fw_cfg,
-                   FILE *f,
-                   const char *kernel_filename,
-                   const char *initrd_filename,
-                   const char *kernel_cmdline,
-                   int kernel_file_size,
-                   uint8_t *header)
-{
-    int i, is_multiboot = 0;
-    uint32_t flags = 0;
-    uint32_t mh_entry_addr;
-    uint32_t mh_load_addr;
-    uint32_t mb_kernel_size;
-    MultibootState mbs;
-    uint8_t bootinfo[MBI_SIZE];
-    uint8_t *mb_bootinfo_data;
-
-    /* Ok, let's see if it is a multiboot image.
-       The header is 12x32bit long, so the latest entry may be 8192 - 48. */
-    for (i = 0; i < (8192 - 48); i += 4) {
-        if (ldl_p(header+i) == 0x1BADB002) {
-            uint32_t checksum = ldl_p(header+i+8);
-            flags = ldl_p(header+i+4);
-            checksum += flags;
-            checksum += (uint32_t)0x1BADB002;
-            if (!checksum) {
-                is_multiboot = 1;
-                break;
-            }
-        }
-    }
-
-    if (!is_multiboot)
-        return 0; /* no multiboot */
-
-    mb_debug("qemu: I believe we found a multiboot image!\n");
-    memset(bootinfo, 0, sizeof(bootinfo));
-    memset(&mbs, 0, sizeof(mbs));
-
-    if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
-        fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
-    }
-    if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
-        uint64_t elf_entry;
-        uint64_t elf_low, elf_high;
-        int kernel_size;
-        fclose(f);
-
-        if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
-            fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n");
-            exit(1);
-        }
-
-        kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
-                               &elf_low, &elf_high, 0, ELF_MACHINE, 0);
-        if (kernel_size < 0) {
-            fprintf(stderr, "Error while loading elf kernel\n");
-            exit(1);
-        }
-        mh_load_addr = elf_low;
-        mb_kernel_size = elf_high - elf_low;
-        mh_entry_addr = elf_entry;
-
-        mbs.mb_buf = g_malloc(mb_kernel_size);
-        if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != mb_kernel_size) {
-            fprintf(stderr, "Error while fetching elf kernel from rom\n");
-            exit(1);
-        }
-
-        mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
-                  mb_kernel_size, (size_t)mh_entry_addr);
-    } else {
-        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
-        uint32_t mh_header_addr = ldl_p(header+i+12);
-        uint32_t mh_load_end_addr = ldl_p(header+i+20);
-        uint32_t mh_bss_end_addr = ldl_p(header+i+24);
-        mh_load_addr = ldl_p(header+i+16);
-        uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
-        uint32_t mb_load_size = 0;
-        mh_entry_addr = ldl_p(header+i+28);
-
-        if (mh_load_end_addr) {
-            mb_kernel_size = mh_bss_end_addr - mh_load_addr;
-            mb_load_size = mh_load_end_addr - mh_load_addr;
-        } else {
-            mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
-            mb_load_size = mb_kernel_size;
-        }
-
-        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
-        uint32_t mh_mode_type = ldl_p(header+i+32);
-        uint32_t mh_width = ldl_p(header+i+36);
-        uint32_t mh_height = ldl_p(header+i+40);
-        uint32_t mh_depth = ldl_p(header+i+44); */
-
-        mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
-        mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
-        mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
-        mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
-        mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
-                 mb_load_size, mh_load_addr);
-
-        mbs.mb_buf = g_malloc(mb_kernel_size);
-        fseek(f, mb_kernel_text_offset, SEEK_SET);
-        if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
-            fprintf(stderr, "fread() failed\n");
-            exit(1);
-        }
-        memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
-        fclose(f);
-    }
-
-    mbs.mb_buf_phys = mh_load_addr;
-
-    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
-    mbs.offset_mbinfo = mbs.mb_buf_size;
-
-    /* Calculate space for cmdlines and mb_mods */
-    mbs.mb_buf_size += strlen(kernel_filename) + 1;
-    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
-    if (initrd_filename) {
-        const char *r = initrd_filename;
-        mbs.mb_buf_size += strlen(r) + 1;
-        mbs.mb_mods_avail = 1;
-        while (*(r = get_opt_value(NULL, 0, r))) {
-           mbs.mb_mods_avail++;
-           r++;
-        }
-        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
-    }
-
-    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
-
-    /* enlarge mb_buf to hold cmdlines and mb-info structs */
-    mbs.mb_buf          = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
-    mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
-
-    if (initrd_filename) {
-        char *next_initrd, not_last;
-
-        mbs.offset_mods = mbs.mb_buf_size;
-
-        do {
-            char *next_space;
-            int mb_mod_length;
-            uint32_t offs = mbs.mb_buf_size;
-
-            next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename);
-            not_last = *next_initrd;
-            *next_initrd = '\0';
-            /* if a space comes after the module filename, treat everything
-               after that as parameters */
-            hwaddr c = mb_add_cmdline(&mbs, initrd_filename);
-            if ((next_space = strchr(initrd_filename, ' ')))
-                *next_space = '\0';
-            mb_debug("multiboot loading module: %s\n", initrd_filename);
-            mb_mod_length = get_image_size(initrd_filename);
-            if (mb_mod_length < 0) {
-                fprintf(stderr, "Failed to open file '%s'\n", initrd_filename);
-                exit(1);
-            }
-
-            mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
-            mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
-
-            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
-            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
-                       mbs.mb_buf_phys + offs + mb_mod_length, c);
-
-            mb_debug("mod_start: %p\nmod_end:   %p\n  cmdline: "TARGET_FMT_plx"\n",
-                     (char *)mbs.mb_buf + offs,
-                     (char *)mbs.mb_buf + offs + mb_mod_length, c);
-            initrd_filename = next_initrd+1;
-        } while (not_last);
-    }
-
-    /* Commandline support */
-    char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
-    snprintf(kcmdline, sizeof(kcmdline), "%s %s",
-             kernel_filename, kernel_cmdline);
-    stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
-
-    stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
-    stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
-
-    /* the kernel is where we want it to be now */
-    stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
-                                | MULTIBOOT_FLAGS_BOOT_DEVICE
-                                | MULTIBOOT_FLAGS_CMDLINE
-                                | MULTIBOOT_FLAGS_MODULES
-                                | MULTIBOOT_FLAGS_MMAP);
-    stl_p(bootinfo + MBI_MEM_LOWER,   640);
-    stl_p(bootinfo + MBI_MEM_UPPER,   (ram_size / 1024) - 1024);
-    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
-    stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
-
-    mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
-    mb_debug("           mb_buf_phys   = "TARGET_FMT_plx"\n", mbs.mb_buf_phys);
-    mb_debug("           mod_start     = "TARGET_FMT_plx"\n", mbs.mb_buf_phys + mbs.offset_mods);
-    mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
-
-    /* save bootinfo off the stack */
-    mb_bootinfo_data = g_malloc(sizeof(bootinfo));
-    memcpy(mb_bootinfo_data, bootinfo, sizeof(bootinfo));
-
-    /* Pass variables to option rom */
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, mh_entry_addr);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
-                     mbs.mb_buf, mbs.mb_buf_size);
-
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, sizeof(bootinfo));
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mb_bootinfo_data,
-                     sizeof(bootinfo));
-
-    option_rom[nb_option_roms].name = "multiboot.bin";
-    option_rom[nb_option_roms].bootindex = 0;
-    nb_option_roms++;
-
-    return 1; /* yes, we are multiboot */
-}
diff --git a/hw/musicpal.c b/hw/musicpal.c
deleted file mode 100644 (file)
index a37dbd7..0000000
+++ /dev/null
@@ -1,1697 +0,0 @@
-/*
- * Marvell MV88W8618 / Freecom MusicPal emulation.
- *
- * Copyright (c) 2008 Jan Kiszka
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/serial.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "block/block.h"
-#include "hw/flash.h"
-#include "ui/console.h"
-#include "hw/i2c.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-#include "ui/pixel_ops.h"
-
-#define MP_MISC_BASE            0x80002000
-#define MP_MISC_SIZE            0x00001000
-
-#define MP_ETH_BASE             0x80008000
-#define MP_ETH_SIZE             0x00001000
-
-#define MP_WLAN_BASE            0x8000C000
-#define MP_WLAN_SIZE            0x00000800
-
-#define MP_UART1_BASE           0x8000C840
-#define MP_UART2_BASE           0x8000C940
-
-#define MP_GPIO_BASE            0x8000D000
-#define MP_GPIO_SIZE            0x00001000
-
-#define MP_FLASHCFG_BASE        0x90006000
-#define MP_FLASHCFG_SIZE        0x00001000
-
-#define MP_AUDIO_BASE           0x90007000
-
-#define MP_PIC_BASE             0x90008000
-#define MP_PIC_SIZE             0x00001000
-
-#define MP_PIT_BASE             0x90009000
-#define MP_PIT_SIZE             0x00001000
-
-#define MP_LCD_BASE             0x9000c000
-#define MP_LCD_SIZE             0x00001000
-
-#define MP_SRAM_BASE            0xC0000000
-#define MP_SRAM_SIZE            0x00020000
-
-#define MP_RAM_DEFAULT_SIZE     32*1024*1024
-#define MP_FLASH_SIZE_MAX       32*1024*1024
-
-#define MP_TIMER1_IRQ           4
-#define MP_TIMER2_IRQ           5
-#define MP_TIMER3_IRQ           6
-#define MP_TIMER4_IRQ           7
-#define MP_EHCI_IRQ             8
-#define MP_ETH_IRQ              9
-#define MP_UART1_IRQ            11
-#define MP_UART2_IRQ            11
-#define MP_GPIO_IRQ             12
-#define MP_RTC_IRQ              28
-#define MP_AUDIO_IRQ            30
-
-/* Wolfson 8750 I2C address */
-#define MP_WM_ADDR              0x1A
-
-/* Ethernet register offsets */
-#define MP_ETH_SMIR             0x010
-#define MP_ETH_PCXR             0x408
-#define MP_ETH_SDCMR            0x448
-#define MP_ETH_ICR              0x450
-#define MP_ETH_IMR              0x458
-#define MP_ETH_FRDP0            0x480
-#define MP_ETH_FRDP1            0x484
-#define MP_ETH_FRDP2            0x488
-#define MP_ETH_FRDP3            0x48C
-#define MP_ETH_CRDP0            0x4A0
-#define MP_ETH_CRDP1            0x4A4
-#define MP_ETH_CRDP2            0x4A8
-#define MP_ETH_CRDP3            0x4AC
-#define MP_ETH_CTDP0            0x4E0
-#define MP_ETH_CTDP1            0x4E4
-#define MP_ETH_CTDP2            0x4E8
-#define MP_ETH_CTDP3            0x4EC
-
-/* MII PHY access */
-#define MP_ETH_SMIR_DATA        0x0000FFFF
-#define MP_ETH_SMIR_ADDR        0x03FF0000
-#define MP_ETH_SMIR_OPCODE      (1 << 26) /* Read value */
-#define MP_ETH_SMIR_RDVALID     (1 << 27)
-
-/* PHY registers */
-#define MP_ETH_PHY1_BMSR        0x00210000
-#define MP_ETH_PHY1_PHYSID1     0x00410000
-#define MP_ETH_PHY1_PHYSID2     0x00610000
-
-#define MP_PHY_BMSR_LINK        0x0004
-#define MP_PHY_BMSR_AUTONEG     0x0008
-
-#define MP_PHY_88E3015          0x01410E20
-
-/* TX descriptor status */
-#define MP_ETH_TX_OWN           (1 << 31)
-
-/* RX descriptor status */
-#define MP_ETH_RX_OWN           (1 << 31)
-
-/* Interrupt cause/mask bits */
-#define MP_ETH_IRQ_RX_BIT       0
-#define MP_ETH_IRQ_RX           (1 << MP_ETH_IRQ_RX_BIT)
-#define MP_ETH_IRQ_TXHI_BIT     2
-#define MP_ETH_IRQ_TXLO_BIT     3
-
-/* Port config bits */
-#define MP_ETH_PCXR_2BSM_BIT    28 /* 2-byte incoming suffix */
-
-/* SDMA command bits */
-#define MP_ETH_CMD_TXHI         (1 << 23)
-#define MP_ETH_CMD_TXLO         (1 << 22)
-
-typedef struct mv88w8618_tx_desc {
-    uint32_t cmdstat;
-    uint16_t res;
-    uint16_t bytes;
-    uint32_t buffer;
-    uint32_t next;
-} mv88w8618_tx_desc;
-
-typedef struct mv88w8618_rx_desc {
-    uint32_t cmdstat;
-    uint16_t bytes;
-    uint16_t buffer_size;
-    uint32_t buffer;
-    uint32_t next;
-} mv88w8618_rx_desc;
-
-typedef struct mv88w8618_eth_state {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    uint32_t smir;
-    uint32_t icr;
-    uint32_t imr;
-    int mmio_index;
-    uint32_t vlan_header;
-    uint32_t tx_queue[2];
-    uint32_t rx_queue[4];
-    uint32_t frx_queue[4];
-    uint32_t cur_rx[4];
-    NICState *nic;
-    NICConf conf;
-} mv88w8618_eth_state;
-
-static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc)
-{
-    cpu_to_le32s(&desc->cmdstat);
-    cpu_to_le16s(&desc->bytes);
-    cpu_to_le16s(&desc->buffer_size);
-    cpu_to_le32s(&desc->buffer);
-    cpu_to_le32s(&desc->next);
-    cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc));
-}
-
-static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc)
-{
-    cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc));
-    le32_to_cpus(&desc->cmdstat);
-    le16_to_cpus(&desc->bytes);
-    le16_to_cpus(&desc->buffer_size);
-    le32_to_cpus(&desc->buffer);
-    le32_to_cpus(&desc->next);
-}
-
-static int eth_can_receive(NetClientState *nc)
-{
-    return 1;
-}
-
-static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
-    uint32_t desc_addr;
-    mv88w8618_rx_desc desc;
-    int i;
-
-    for (i = 0; i < 4; i++) {
-        desc_addr = s->cur_rx[i];
-        if (!desc_addr) {
-            continue;
-        }
-        do {
-            eth_rx_desc_get(desc_addr, &desc);
-            if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) {
-                cpu_physical_memory_write(desc.buffer + s->vlan_header,
-                                          buf, size);
-                desc.bytes = size + s->vlan_header;
-                desc.cmdstat &= ~MP_ETH_RX_OWN;
-                s->cur_rx[i] = desc.next;
-
-                s->icr |= MP_ETH_IRQ_RX;
-                if (s->icr & s->imr) {
-                    qemu_irq_raise(s->irq);
-                }
-                eth_rx_desc_put(desc_addr, &desc);
-                return size;
-            }
-            desc_addr = desc.next;
-        } while (desc_addr != s->rx_queue[i]);
-    }
-    return size;
-}
-
-static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc)
-{
-    cpu_to_le32s(&desc->cmdstat);
-    cpu_to_le16s(&desc->res);
-    cpu_to_le16s(&desc->bytes);
-    cpu_to_le32s(&desc->buffer);
-    cpu_to_le32s(&desc->next);
-    cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc));
-}
-
-static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc)
-{
-    cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc));
-    le32_to_cpus(&desc->cmdstat);
-    le16_to_cpus(&desc->res);
-    le16_to_cpus(&desc->bytes);
-    le32_to_cpus(&desc->buffer);
-    le32_to_cpus(&desc->next);
-}
-
-static void eth_send(mv88w8618_eth_state *s, int queue_index)
-{
-    uint32_t desc_addr = s->tx_queue[queue_index];
-    mv88w8618_tx_desc desc;
-    uint32_t next_desc;
-    uint8_t buf[2048];
-    int len;
-
-    do {
-        eth_tx_desc_get(desc_addr, &desc);
-        next_desc = desc.next;
-        if (desc.cmdstat & MP_ETH_TX_OWN) {
-            len = desc.bytes;
-            if (len < 2048) {
-                cpu_physical_memory_read(desc.buffer, buf, len);
-                qemu_send_packet(qemu_get_queue(s->nic), buf, len);
-            }
-            desc.cmdstat &= ~MP_ETH_TX_OWN;
-            s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
-            eth_tx_desc_put(desc_addr, &desc);
-        }
-        desc_addr = next_desc;
-    } while (desc_addr != s->tx_queue[queue_index]);
-}
-
-static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    mv88w8618_eth_state *s = opaque;
-
-    switch (offset) {
-    case MP_ETH_SMIR:
-        if (s->smir & MP_ETH_SMIR_OPCODE) {
-            switch (s->smir & MP_ETH_SMIR_ADDR) {
-            case MP_ETH_PHY1_BMSR:
-                return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG |
-                       MP_ETH_SMIR_RDVALID;
-            case MP_ETH_PHY1_PHYSID1:
-                return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID;
-            case MP_ETH_PHY1_PHYSID2:
-                return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID;
-            default:
-                return MP_ETH_SMIR_RDVALID;
-            }
-        }
-        return 0;
-
-    case MP_ETH_ICR:
-        return s->icr;
-
-    case MP_ETH_IMR:
-        return s->imr;
-
-    case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
-        return s->frx_queue[(offset - MP_ETH_FRDP0)/4];
-
-    case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
-        return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
-
-    case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
-        return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
-
-    default:
-        return 0;
-    }
-}
-
-static void mv88w8618_eth_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-    mv88w8618_eth_state *s = opaque;
-
-    switch (offset) {
-    case MP_ETH_SMIR:
-        s->smir = value;
-        break;
-
-    case MP_ETH_PCXR:
-        s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2;
-        break;
-
-    case MP_ETH_SDCMR:
-        if (value & MP_ETH_CMD_TXHI) {
-            eth_send(s, 1);
-        }
-        if (value & MP_ETH_CMD_TXLO) {
-            eth_send(s, 0);
-        }
-        if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) {
-            qemu_irq_raise(s->irq);
-        }
-        break;
-
-    case MP_ETH_ICR:
-        s->icr &= value;
-        break;
-
-    case MP_ETH_IMR:
-        s->imr = value;
-        if (s->icr & s->imr) {
-            qemu_irq_raise(s->irq);
-        }
-        break;
-
-    case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
-        s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value;
-        break;
-
-    case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
-        s->rx_queue[(offset - MP_ETH_CRDP0)/4] =
-            s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
-        break;
-
-    case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
-        s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
-        break;
-    }
-}
-
-static const MemoryRegionOps mv88w8618_eth_ops = {
-    .read = mv88w8618_eth_read,
-    .write = mv88w8618_eth_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void eth_cleanup(NetClientState *nc)
-{
-    mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static NetClientInfo net_mv88w8618_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = eth_can_receive,
-    .receive = eth_receive,
-    .cleanup = eth_cleanup,
-};
-
-static int mv88w8618_eth_init(SysBusDevice *dev)
-{
-    mv88w8618_eth_state *s = FROM_SYSBUS(mv88w8618_eth_state, dev);
-
-    sysbus_init_irq(dev, &s->irq);
-    s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth",
-                          MP_ETH_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static const VMStateDescription mv88w8618_eth_vmsd = {
-    .name = "mv88w8618_eth",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(smir, mv88w8618_eth_state),
-        VMSTATE_UINT32(icr, mv88w8618_eth_state),
-        VMSTATE_UINT32(imr, mv88w8618_eth_state),
-        VMSTATE_UINT32(vlan_header, mv88w8618_eth_state),
-        VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2),
-        VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4),
-        VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4),
-        VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property mv88w8618_eth_properties[] = {
-    DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mv88w8618_eth_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = mv88w8618_eth_init;
-    dc->vmsd = &mv88w8618_eth_vmsd;
-    dc->props = mv88w8618_eth_properties;
-}
-
-static const TypeInfo mv88w8618_eth_info = {
-    .name          = "mv88w8618_eth",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(mv88w8618_eth_state),
-    .class_init    = mv88w8618_eth_class_init,
-};
-
-/* LCD register offsets */
-#define MP_LCD_IRQCTRL          0x180
-#define MP_LCD_IRQSTAT          0x184
-#define MP_LCD_SPICTRL          0x1ac
-#define MP_LCD_INST             0x1bc
-#define MP_LCD_DATA             0x1c0
-
-/* Mode magics */
-#define MP_LCD_SPI_DATA         0x00100011
-#define MP_LCD_SPI_CMD          0x00104011
-#define MP_LCD_SPI_INVALID      0x00000000
-
-/* Commmands */
-#define MP_LCD_INST_SETPAGE0    0xB0
-/* ... */
-#define MP_LCD_INST_SETPAGE7    0xB7
-
-#define MP_LCD_TEXTCOLOR        0xe0e0ff /* RRGGBB */
-
-typedef struct musicpal_lcd_state {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t brightness;
-    uint32_t mode;
-    uint32_t irqctrl;
-    uint32_t page;
-    uint32_t page_off;
-    DisplayState *ds;
-    uint8_t video_ram[128*64/8];
-} musicpal_lcd_state;
-
-static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col)
-{
-    switch (s->brightness) {
-    case 7:
-        return col;
-    case 0:
-        return 0;
-    default:
-        return (col * s->brightness) / 7;
-    }
-}
-
-#define SET_LCD_PIXEL(depth, type) \
-static inline void glue(set_lcd_pixel, depth) \
-        (musicpal_lcd_state *s, int x, int y, type col) \
-{ \
-    int dx, dy; \
-    type *pixel = &((type *) ds_get_data(s->ds))[(y * 128 * 3 + x) * 3]; \
-\
-    for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \
-        for (dx = 0; dx < 3; dx++, pixel++) \
-            *pixel = col; \
-}
-SET_LCD_PIXEL(8, uint8_t)
-SET_LCD_PIXEL(16, uint16_t)
-SET_LCD_PIXEL(32, uint32_t)
-
-static void lcd_refresh(void *opaque)
-{
-    musicpal_lcd_state *s = opaque;
-    int x, y, col;
-
-    switch (ds_get_bits_per_pixel(s->ds)) {
-    case 0:
-        return;
-#define LCD_REFRESH(depth, func) \
-    case depth: \
-        col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \
-                   scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \
-                   scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \
-        for (x = 0; x < 128; x++) { \
-            for (y = 0; y < 64; y++) { \
-                if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \
-                    glue(set_lcd_pixel, depth)(s, x, y, col); \
-                } else { \
-                    glue(set_lcd_pixel, depth)(s, x, y, 0); \
-                } \
-            } \
-        } \
-        break;
-    LCD_REFRESH(8, rgb_to_pixel8)
-    LCD_REFRESH(16, rgb_to_pixel16)
-    LCD_REFRESH(32, (is_surface_bgr(s->ds->surface) ?
-                     rgb_to_pixel32bgr : rgb_to_pixel32))
-    default:
-        hw_error("unsupported colour depth %i\n",
-                  ds_get_bits_per_pixel(s->ds));
-    }
-
-    dpy_gfx_update(s->ds, 0, 0, 128*3, 64*3);
-}
-
-static void lcd_invalidate(void *opaque)
-{
-}
-
-static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level)
-{
-    musicpal_lcd_state *s = opaque;
-    s->brightness &= ~(1 << irq);
-    s->brightness |= level << irq;
-}
-
-static uint64_t musicpal_lcd_read(void *opaque, hwaddr offset,
-                                  unsigned size)
-{
-    musicpal_lcd_state *s = opaque;
-
-    switch (offset) {
-    case MP_LCD_IRQCTRL:
-        return s->irqctrl;
-
-    default:
-        return 0;
-    }
-}
-
-static void musicpal_lcd_write(void *opaque, hwaddr offset,
-                               uint64_t value, unsigned size)
-{
-    musicpal_lcd_state *s = opaque;
-
-    switch (offset) {
-    case MP_LCD_IRQCTRL:
-        s->irqctrl = value;
-        break;
-
-    case MP_LCD_SPICTRL:
-        if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) {
-            s->mode = value;
-        } else {
-            s->mode = MP_LCD_SPI_INVALID;
-        }
-        break;
-
-    case MP_LCD_INST:
-        if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) {
-            s->page = value - MP_LCD_INST_SETPAGE0;
-            s->page_off = 0;
-        }
-        break;
-
-    case MP_LCD_DATA:
-        if (s->mode == MP_LCD_SPI_CMD) {
-            if (value >= MP_LCD_INST_SETPAGE0 &&
-                value <= MP_LCD_INST_SETPAGE7) {
-                s->page = value - MP_LCD_INST_SETPAGE0;
-                s->page_off = 0;
-            }
-        } else if (s->mode == MP_LCD_SPI_DATA) {
-            s->video_ram[s->page*128 + s->page_off] = value;
-            s->page_off = (s->page_off + 1) & 127;
-        }
-        break;
-    }
-}
-
-static const MemoryRegionOps musicpal_lcd_ops = {
-    .read = musicpal_lcd_read,
-    .write = musicpal_lcd_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int musicpal_lcd_init(SysBusDevice *dev)
-{
-    musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev);
-
-    s->brightness = 7;
-
-    memory_region_init_io(&s->iomem, &musicpal_lcd_ops, s,
-                          "musicpal-lcd", MP_LCD_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    s->ds = graphic_console_init(lcd_refresh, lcd_invalidate,
-                                 NULL, NULL, s);
-    qemu_console_resize(s->ds, 128*3, 64*3);
-
-    qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3);
-
-    return 0;
-}
-
-static const VMStateDescription musicpal_lcd_vmsd = {
-    .name = "musicpal_lcd",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(brightness, musicpal_lcd_state),
-        VMSTATE_UINT32(mode, musicpal_lcd_state),
-        VMSTATE_UINT32(irqctrl, musicpal_lcd_state),
-        VMSTATE_UINT32(page, musicpal_lcd_state),
-        VMSTATE_UINT32(page_off, musicpal_lcd_state),
-        VMSTATE_BUFFER(video_ram, musicpal_lcd_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void musicpal_lcd_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = musicpal_lcd_init;
-    dc->vmsd = &musicpal_lcd_vmsd;
-}
-
-static const TypeInfo musicpal_lcd_info = {
-    .name          = "musicpal_lcd",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(musicpal_lcd_state),
-    .class_init    = musicpal_lcd_class_init,
-};
-
-/* PIC register offsets */
-#define MP_PIC_STATUS           0x00
-#define MP_PIC_ENABLE_SET       0x08
-#define MP_PIC_ENABLE_CLR       0x0C
-
-typedef struct mv88w8618_pic_state
-{
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t level;
-    uint32_t enabled;
-    qemu_irq parent_irq;
-} mv88w8618_pic_state;
-
-static void mv88w8618_pic_update(mv88w8618_pic_state *s)
-{
-    qemu_set_irq(s->parent_irq, (s->level & s->enabled));
-}
-
-static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
-{
-    mv88w8618_pic_state *s = opaque;
-
-    if (level) {
-        s->level |= 1 << irq;
-    } else {
-        s->level &= ~(1 << irq);
-    }
-    mv88w8618_pic_update(s);
-}
-
-static uint64_t mv88w8618_pic_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    mv88w8618_pic_state *s = opaque;
-
-    switch (offset) {
-    case MP_PIC_STATUS:
-        return s->level & s->enabled;
-
-    default:
-        return 0;
-    }
-}
-
-static void mv88w8618_pic_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-    mv88w8618_pic_state *s = opaque;
-
-    switch (offset) {
-    case MP_PIC_ENABLE_SET:
-        s->enabled |= value;
-        break;
-
-    case MP_PIC_ENABLE_CLR:
-        s->enabled &= ~value;
-        s->level &= ~value;
-        break;
-    }
-    mv88w8618_pic_update(s);
-}
-
-static void mv88w8618_pic_reset(DeviceState *d)
-{
-    mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state,
-                                         SYS_BUS_DEVICE(d));
-
-    s->level = 0;
-    s->enabled = 0;
-}
-
-static const MemoryRegionOps mv88w8618_pic_ops = {
-    .read = mv88w8618_pic_read,
-    .write = mv88w8618_pic_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mv88w8618_pic_init(SysBusDevice *dev)
-{
-    mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev);
-
-    qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
-    sysbus_init_irq(dev, &s->parent_irq);
-    memory_region_init_io(&s->iomem, &mv88w8618_pic_ops, s,
-                          "musicpal-pic", MP_PIC_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static const VMStateDescription mv88w8618_pic_vmsd = {
-    .name = "mv88w8618_pic",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(level, mv88w8618_pic_state),
-        VMSTATE_UINT32(enabled, mv88w8618_pic_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = mv88w8618_pic_init;
-    dc->reset = mv88w8618_pic_reset;
-    dc->vmsd = &mv88w8618_pic_vmsd;
-}
-
-static const TypeInfo mv88w8618_pic_info = {
-    .name          = "mv88w8618_pic",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(mv88w8618_pic_state),
-    .class_init    = mv88w8618_pic_class_init,
-};
-
-/* PIT register offsets */
-#define MP_PIT_TIMER1_LENGTH    0x00
-/* ... */
-#define MP_PIT_TIMER4_LENGTH    0x0C
-#define MP_PIT_CONTROL          0x10
-#define MP_PIT_TIMER1_VALUE     0x14
-/* ... */
-#define MP_PIT_TIMER4_VALUE     0x20
-#define MP_BOARD_RESET          0x34
-
-/* Magic board reset value (probably some watchdog behind it) */
-#define MP_BOARD_RESET_MAGIC    0x10000
-
-typedef struct mv88w8618_timer_state {
-    ptimer_state *ptimer;
-    uint32_t limit;
-    int freq;
-    qemu_irq irq;
-} mv88w8618_timer_state;
-
-typedef struct mv88w8618_pit_state {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    mv88w8618_timer_state timer[4];
-} mv88w8618_pit_state;
-
-static void mv88w8618_timer_tick(void *opaque)
-{
-    mv88w8618_timer_state *s = opaque;
-
-    qemu_irq_raise(s->irq);
-}
-
-static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
-                                 uint32_t freq)
-{
-    QEMUBH *bh;
-
-    sysbus_init_irq(dev, &s->irq);
-    s->freq = freq;
-
-    bh = qemu_bh_new(mv88w8618_timer_tick, s);
-    s->ptimer = ptimer_init(bh);
-}
-
-static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    mv88w8618_pit_state *s = opaque;
-    mv88w8618_timer_state *t;
-
-    switch (offset) {
-    case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE:
-        t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2];
-        return ptimer_get_count(t->ptimer);
-
-    default:
-        return 0;
-    }
-}
-
-static void mv88w8618_pit_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-    mv88w8618_pit_state *s = opaque;
-    mv88w8618_timer_state *t;
-    int i;
-
-    switch (offset) {
-    case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:
-        t = &s->timer[offset >> 2];
-        t->limit = value;
-        if (t->limit > 0) {
-            ptimer_set_limit(t->ptimer, t->limit, 1);
-        } else {
-            ptimer_stop(t->ptimer);
-        }
-        break;
-
-    case MP_PIT_CONTROL:
-        for (i = 0; i < 4; i++) {
-            t = &s->timer[i];
-            if (value & 0xf && t->limit > 0) {
-                ptimer_set_limit(t->ptimer, t->limit, 0);
-                ptimer_set_freq(t->ptimer, t->freq);
-                ptimer_run(t->ptimer, 0);
-            } else {
-                ptimer_stop(t->ptimer);
-            }
-            value >>= 4;
-        }
-        break;
-
-    case MP_BOARD_RESET:
-        if (value == MP_BOARD_RESET_MAGIC) {
-            qemu_system_reset_request();
-        }
-        break;
-    }
-}
-
-static void mv88w8618_pit_reset(DeviceState *d)
-{
-    mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state,
-                                         SYS_BUS_DEVICE(d));
-    int i;
-
-    for (i = 0; i < 4; i++) {
-        ptimer_stop(s->timer[i].ptimer);
-        s->timer[i].limit = 0;
-    }
-}
-
-static const MemoryRegionOps mv88w8618_pit_ops = {
-    .read = mv88w8618_pit_read,
-    .write = mv88w8618_pit_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mv88w8618_pit_init(SysBusDevice *dev)
-{
-    mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, dev);
-    int i;
-
-    /* Letting them all run at 1 MHz is likely just a pragmatic
-     * simplification. */
-    for (i = 0; i < 4; i++) {
-        mv88w8618_timer_init(dev, &s->timer[i], 1000000);
-    }
-
-    memory_region_init_io(&s->iomem, &mv88w8618_pit_ops, s,
-                          "musicpal-pit", MP_PIT_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static const VMStateDescription mv88w8618_timer_vmsd = {
-    .name = "timer",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
-        VMSTATE_UINT32(limit, mv88w8618_timer_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription mv88w8618_pit_vmsd = {
-    .name = "mv88w8618_pit",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
-                             mv88w8618_timer_vmsd, mv88w8618_timer_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = mv88w8618_pit_init;
-    dc->reset = mv88w8618_pit_reset;
-    dc->vmsd = &mv88w8618_pit_vmsd;
-}
-
-static const TypeInfo mv88w8618_pit_info = {
-    .name          = "mv88w8618_pit",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(mv88w8618_pit_state),
-    .class_init    = mv88w8618_pit_class_init,
-};
-
-/* Flash config register offsets */
-#define MP_FLASHCFG_CFGR0    0x04
-
-typedef struct mv88w8618_flashcfg_state {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t cfgr0;
-} mv88w8618_flashcfg_state;
-
-static uint64_t mv88w8618_flashcfg_read(void *opaque,
-                                        hwaddr offset,
-                                        unsigned size)
-{
-    mv88w8618_flashcfg_state *s = opaque;
-
-    switch (offset) {
-    case MP_FLASHCFG_CFGR0:
-        return s->cfgr0;
-
-    default:
-        return 0;
-    }
-}
-
-static void mv88w8618_flashcfg_write(void *opaque, hwaddr offset,
-                                     uint64_t value, unsigned size)
-{
-    mv88w8618_flashcfg_state *s = opaque;
-
-    switch (offset) {
-    case MP_FLASHCFG_CFGR0:
-        s->cfgr0 = value;
-        break;
-    }
-}
-
-static const MemoryRegionOps mv88w8618_flashcfg_ops = {
-    .read = mv88w8618_flashcfg_read,
-    .write = mv88w8618_flashcfg_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mv88w8618_flashcfg_init(SysBusDevice *dev)
-{
-    mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, dev);
-
-    s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
-    memory_region_init_io(&s->iomem, &mv88w8618_flashcfg_ops, s,
-                          "musicpal-flashcfg", MP_FLASHCFG_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static const VMStateDescription mv88w8618_flashcfg_vmsd = {
-    .name = "mv88w8618_flashcfg",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = mv88w8618_flashcfg_init;
-    dc->vmsd = &mv88w8618_flashcfg_vmsd;
-}
-
-static const TypeInfo mv88w8618_flashcfg_info = {
-    .name          = "mv88w8618_flashcfg",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(mv88w8618_flashcfg_state),
-    .class_init    = mv88w8618_flashcfg_class_init,
-};
-
-/* Misc register offsets */
-#define MP_MISC_BOARD_REVISION  0x18
-
-#define MP_BOARD_REVISION       0x31
-
-static uint64_t musicpal_misc_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    switch (offset) {
-    case MP_MISC_BOARD_REVISION:
-        return MP_BOARD_REVISION;
-
-    default:
-        return 0;
-    }
-}
-
-static void musicpal_misc_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-}
-
-static const MemoryRegionOps musicpal_misc_ops = {
-    .read = musicpal_misc_read,
-    .write = musicpal_misc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void musicpal_misc_init(SysBusDevice *dev)
-{
-    MemoryRegion *iomem = g_new(MemoryRegion, 1);
-
-    memory_region_init_io(iomem, &musicpal_misc_ops, NULL,
-                          "musicpal-misc", MP_MISC_SIZE);
-    sysbus_add_memory(dev, MP_MISC_BASE, iomem);
-}
-
-/* WLAN register offsets */
-#define MP_WLAN_MAGIC1          0x11c
-#define MP_WLAN_MAGIC2          0x124
-
-static uint64_t mv88w8618_wlan_read(void *opaque, hwaddr offset,
-                                    unsigned size)
-{
-    switch (offset) {
-    /* Workaround to allow loading the binary-only wlandrv.ko crap
-     * from the original Freecom firmware. */
-    case MP_WLAN_MAGIC1:
-        return ~3;
-    case MP_WLAN_MAGIC2:
-        return -1;
-
-    default:
-        return 0;
-    }
-}
-
-static void mv88w8618_wlan_write(void *opaque, hwaddr offset,
-                                 uint64_t value, unsigned size)
-{
-}
-
-static const MemoryRegionOps mv88w8618_wlan_ops = {
-    .read = mv88w8618_wlan_read,
-    .write =mv88w8618_wlan_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mv88w8618_wlan_init(SysBusDevice *dev)
-{
-    MemoryRegion *iomem = g_new(MemoryRegion, 1);
-
-    memory_region_init_io(iomem, &mv88w8618_wlan_ops, NULL,
-                          "musicpal-wlan", MP_WLAN_SIZE);
-    sysbus_init_mmio(dev, iomem);
-    return 0;
-}
-
-/* GPIO register offsets */
-#define MP_GPIO_OE_LO           0x008
-#define MP_GPIO_OUT_LO          0x00c
-#define MP_GPIO_IN_LO           0x010
-#define MP_GPIO_IER_LO          0x014
-#define MP_GPIO_IMR_LO          0x018
-#define MP_GPIO_ISR_LO          0x020
-#define MP_GPIO_OE_HI           0x508
-#define MP_GPIO_OUT_HI          0x50c
-#define MP_GPIO_IN_HI           0x510
-#define MP_GPIO_IER_HI          0x514
-#define MP_GPIO_IMR_HI          0x518
-#define MP_GPIO_ISR_HI          0x520
-
-/* GPIO bits & masks */
-#define MP_GPIO_LCD_BRIGHTNESS  0x00070000
-#define MP_GPIO_I2C_DATA_BIT    29
-#define MP_GPIO_I2C_CLOCK_BIT   30
-
-/* LCD brightness bits in GPIO_OE_HI */
-#define MP_OE_LCD_BRIGHTNESS    0x0007
-
-typedef struct musicpal_gpio_state {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t lcd_brightness;
-    uint32_t out_state;
-    uint32_t in_state;
-    uint32_t ier;
-    uint32_t imr;
-    uint32_t isr;
-    qemu_irq irq;
-    qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */
-} musicpal_gpio_state;
-
-static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) {
-    int i;
-    uint32_t brightness;
-
-    /* compute brightness ratio */
-    switch (s->lcd_brightness) {
-    case 0x00000007:
-        brightness = 0;
-        break;
-
-    case 0x00020000:
-        brightness = 1;
-        break;
-
-    case 0x00020001:
-        brightness = 2;
-        break;
-
-    case 0x00040000:
-        brightness = 3;
-        break;
-
-    case 0x00010006:
-        brightness = 4;
-        break;
-
-    case 0x00020005:
-        brightness = 5;
-        break;
-
-    case 0x00040003:
-        brightness = 6;
-        break;
-
-    case 0x00030004:
-    default:
-        brightness = 7;
-    }
-
-    /* set lcd brightness GPIOs  */
-    for (i = 0; i <= 2; i++) {
-        qemu_set_irq(s->out[i], (brightness >> i) & 1);
-    }
-}
-
-static void musicpal_gpio_pin_event(void *opaque, int pin, int level)
-{
-    musicpal_gpio_state *s = opaque;
-    uint32_t mask = 1 << pin;
-    uint32_t delta = level << pin;
-    uint32_t old = s->in_state & mask;
-
-    s->in_state &= ~mask;
-    s->in_state |= delta;
-
-    if ((old ^ delta) &&
-        ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) {
-        s->isr = mask;
-        qemu_irq_raise(s->irq);
-    }
-}
-
-static uint64_t musicpal_gpio_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    musicpal_gpio_state *s = opaque;
-
-    switch (offset) {
-    case MP_GPIO_OE_HI: /* used for LCD brightness control */
-        return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS;
-
-    case MP_GPIO_OUT_LO:
-        return s->out_state & 0xFFFF;
-    case MP_GPIO_OUT_HI:
-        return s->out_state >> 16;
-
-    case MP_GPIO_IN_LO:
-        return s->in_state & 0xFFFF;
-    case MP_GPIO_IN_HI:
-        return s->in_state >> 16;
-
-    case MP_GPIO_IER_LO:
-        return s->ier & 0xFFFF;
-    case MP_GPIO_IER_HI:
-        return s->ier >> 16;
-
-    case MP_GPIO_IMR_LO:
-        return s->imr & 0xFFFF;
-    case MP_GPIO_IMR_HI:
-        return s->imr >> 16;
-
-    case MP_GPIO_ISR_LO:
-        return s->isr & 0xFFFF;
-    case MP_GPIO_ISR_HI:
-        return s->isr >> 16;
-
-    default:
-        return 0;
-    }
-}
-
-static void musicpal_gpio_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-    musicpal_gpio_state *s = opaque;
-    switch (offset) {
-    case MP_GPIO_OE_HI: /* used for LCD brightness control */
-        s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) |
-                         (value & MP_OE_LCD_BRIGHTNESS);
-        musicpal_gpio_brightness_update(s);
-        break;
-
-    case MP_GPIO_OUT_LO:
-        s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF);
-        break;
-    case MP_GPIO_OUT_HI:
-        s->out_state = (s->out_state & 0xFFFF) | (value << 16);
-        s->lcd_brightness = (s->lcd_brightness & 0xFFFF) |
-                            (s->out_state & MP_GPIO_LCD_BRIGHTNESS);
-        musicpal_gpio_brightness_update(s);
-        qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1);
-        qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1);
-        break;
-
-    case MP_GPIO_IER_LO:
-        s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF);
-        break;
-    case MP_GPIO_IER_HI:
-        s->ier = (s->ier & 0xFFFF) | (value << 16);
-        break;
-
-    case MP_GPIO_IMR_LO:
-        s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF);
-        break;
-    case MP_GPIO_IMR_HI:
-        s->imr = (s->imr & 0xFFFF) | (value << 16);
-        break;
-    }
-}
-
-static const MemoryRegionOps musicpal_gpio_ops = {
-    .read = musicpal_gpio_read,
-    .write = musicpal_gpio_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void musicpal_gpio_reset(DeviceState *d)
-{
-    musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state,
-                                         SYS_BUS_DEVICE(d));
-
-    s->lcd_brightness = 0;
-    s->out_state = 0;
-    s->in_state = 0xffffffff;
-    s->ier = 0;
-    s->imr = 0;
-    s->isr = 0;
-}
-
-static int musicpal_gpio_init(SysBusDevice *dev)
-{
-    musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->iomem, &musicpal_gpio_ops, s,
-                          "musicpal-gpio", MP_GPIO_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
-
-    qdev_init_gpio_in(&dev->qdev, musicpal_gpio_pin_event, 32);
-
-    return 0;
-}
-
-static const VMStateDescription musicpal_gpio_vmsd = {
-    .name = "musicpal_gpio",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
-        VMSTATE_UINT32(out_state, musicpal_gpio_state),
-        VMSTATE_UINT32(in_state, musicpal_gpio_state),
-        VMSTATE_UINT32(ier, musicpal_gpio_state),
-        VMSTATE_UINT32(imr, musicpal_gpio_state),
-        VMSTATE_UINT32(isr, musicpal_gpio_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = musicpal_gpio_init;
-    dc->reset = musicpal_gpio_reset;
-    dc->vmsd = &musicpal_gpio_vmsd;
-}
-
-static const TypeInfo musicpal_gpio_info = {
-    .name          = "musicpal_gpio",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(musicpal_gpio_state),
-    .class_init    = musicpal_gpio_class_init,
-};
-
-/* Keyboard codes & masks */
-#define KEY_RELEASED            0x80
-#define KEY_CODE                0x7f
-
-#define KEYCODE_TAB             0x0f
-#define KEYCODE_ENTER           0x1c
-#define KEYCODE_F               0x21
-#define KEYCODE_M               0x32
-
-#define KEYCODE_EXTENDED        0xe0
-#define KEYCODE_UP              0x48
-#define KEYCODE_DOWN            0x50
-#define KEYCODE_LEFT            0x4b
-#define KEYCODE_RIGHT           0x4d
-
-#define MP_KEY_WHEEL_VOL       (1 << 0)
-#define MP_KEY_WHEEL_VOL_INV   (1 << 1)
-#define MP_KEY_WHEEL_NAV       (1 << 2)
-#define MP_KEY_WHEEL_NAV_INV   (1 << 3)
-#define MP_KEY_BTN_FAVORITS    (1 << 4)
-#define MP_KEY_BTN_MENU        (1 << 5)
-#define MP_KEY_BTN_VOLUME      (1 << 6)
-#define MP_KEY_BTN_NAVIGATION  (1 << 7)
-
-typedef struct musicpal_key_state {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t kbd_extended;
-    uint32_t pressed_keys;
-    qemu_irq out[8];
-} musicpal_key_state;
-
-static void musicpal_key_event(void *opaque, int keycode)
-{
-    musicpal_key_state *s = opaque;
-    uint32_t event = 0;
-    int i;
-
-    if (keycode == KEYCODE_EXTENDED) {
-        s->kbd_extended = 1;
-        return;
-    }
-
-    if (s->kbd_extended) {
-        switch (keycode & KEY_CODE) {
-        case KEYCODE_UP:
-            event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV;
-            break;
-
-        case KEYCODE_DOWN:
-            event = MP_KEY_WHEEL_NAV;
-            break;
-
-        case KEYCODE_LEFT:
-            event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV;
-            break;
-
-        case KEYCODE_RIGHT:
-            event = MP_KEY_WHEEL_VOL;
-            break;
-        }
-    } else {
-        switch (keycode & KEY_CODE) {
-        case KEYCODE_F:
-            event = MP_KEY_BTN_FAVORITS;
-            break;
-
-        case KEYCODE_TAB:
-            event = MP_KEY_BTN_VOLUME;
-            break;
-
-        case KEYCODE_ENTER:
-            event = MP_KEY_BTN_NAVIGATION;
-            break;
-
-        case KEYCODE_M:
-            event = MP_KEY_BTN_MENU;
-            break;
-        }
-        /* Do not repeat already pressed buttons */
-        if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
-            event = 0;
-        }
-    }
-
-    if (event) {
-        /* Raise GPIO pin first if repeating a key */
-        if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
-            for (i = 0; i <= 7; i++) {
-                if (event & (1 << i)) {
-                    qemu_set_irq(s->out[i], 1);
-                }
-            }
-        }
-        for (i = 0; i <= 7; i++) {
-            if (event & (1 << i)) {
-                qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED));
-            }
-        }
-        if (keycode & KEY_RELEASED) {
-            s->pressed_keys &= ~event;
-        } else {
-            s->pressed_keys |= event;
-        }
-    }
-
-    s->kbd_extended = 0;
-}
-
-static int musicpal_key_init(SysBusDevice *dev)
-{
-    musicpal_key_state *s = FROM_SYSBUS(musicpal_key_state, dev);
-
-    memory_region_init(&s->iomem, "dummy", 0);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    s->kbd_extended = 0;
-    s->pressed_keys = 0;
-
-    qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
-
-    qemu_add_kbd_event_handler(musicpal_key_event, s);
-
-    return 0;
-}
-
-static const VMStateDescription musicpal_key_vmsd = {
-    .name = "musicpal_key",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(kbd_extended, musicpal_key_state),
-        VMSTATE_UINT32(pressed_keys, musicpal_key_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void musicpal_key_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = musicpal_key_init;
-    dc->vmsd = &musicpal_key_vmsd;
-}
-
-static const TypeInfo musicpal_key_info = {
-    .name          = "musicpal_key",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(musicpal_key_state),
-    .class_init    = musicpal_key_class_init,
-};
-
-static struct arm_boot_info musicpal_binfo = {
-    .loader_start = 0x0,
-    .board_id = 0x20e,
-};
-
-static void musicpal_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    ARMCPU *cpu;
-    qemu_irq *cpu_pic;
-    qemu_irq pic[32];
-    DeviceState *dev;
-    DeviceState *i2c_dev;
-    DeviceState *lcd_dev;
-    DeviceState *key_dev;
-    DeviceState *wm8750_dev;
-    SysBusDevice *s;
-    i2c_bus *i2c;
-    int i;
-    unsigned long flash_size;
-    DriveInfo *dinfo;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *sram = g_new(MemoryRegion, 1);
-
-    if (!cpu_model) {
-        cpu_model = "arm926";
-    }
-    cpu = cpu_arm_init(cpu_model);
-    if (!cpu) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-    cpu_pic = arm_pic_init_cpu(cpu);
-
-    /* For now we use a fixed - the original - RAM size */
-    memory_region_init_ram(ram, "musicpal.ram", MP_RAM_DEFAULT_SIZE);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(address_space_mem, 0, ram);
-
-    memory_region_init_ram(sram, "musicpal.sram", MP_SRAM_SIZE);
-    vmstate_register_ram_global(sram);
-    memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
-
-    dev = sysbus_create_simple("mv88w8618_pic", MP_PIC_BASE,
-                               cpu_pic[ARM_PIC_CPU_IRQ]);
-    for (i = 0; i < 32; i++) {
-        pic[i] = qdev_get_gpio_in(dev, i);
-    }
-    sysbus_create_varargs("mv88w8618_pit", MP_PIT_BASE, pic[MP_TIMER1_IRQ],
-                          pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ],
-                          pic[MP_TIMER4_IRQ], NULL);
-
-    if (serial_hds[0]) {
-        serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ],
-                       1825000, serial_hds[0], DEVICE_NATIVE_ENDIAN);
-    }
-    if (serial_hds[1]) {
-        serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ],
-                       1825000, serial_hds[1], DEVICE_NATIVE_ENDIAN);
-    }
-
-    /* Register flash */
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    if (dinfo) {
-        flash_size = bdrv_getlength(dinfo->bdrv);
-        if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&
-            flash_size != 32*1024*1024) {
-            fprintf(stderr, "Invalid flash image size\n");
-            exit(1);
-        }
-
-        /*
-         * The original U-Boot accesses the flash at 0xFE000000 instead of
-         * 0xFF800000 (if there is 8 MB flash). So remap flash access if the
-         * image is smaller than 32 MB.
-         */
-#ifdef TARGET_WORDS_BIGENDIAN
-        pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
-                              "musicpal.flash", flash_size,
-                              dinfo->bdrv, 0x10000,
-                              (flash_size + 0xffff) >> 16,
-                              MP_FLASH_SIZE_MAX / flash_size,
-                              2, 0x00BF, 0x236D, 0x0000, 0x0000,
-                              0x5555, 0x2AAA, 1);
-#else
-        pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
-                              "musicpal.flash", flash_size,
-                              dinfo->bdrv, 0x10000,
-                              (flash_size + 0xffff) >> 16,
-                              MP_FLASH_SIZE_MAX / flash_size,
-                              2, 0x00BF, 0x236D, 0x0000, 0x0000,
-                              0x5555, 0x2AAA, 0);
-#endif
-
-    }
-    sysbus_create_simple("mv88w8618_flashcfg", MP_FLASHCFG_BASE, NULL);
-
-    qemu_check_nic_model(&nd_table[0], "mv88w8618");
-    dev = qdev_create(NULL, "mv88w8618_eth");
-    qdev_set_nic_properties(dev, &nd_table[0]);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]);
-
-    sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
-
-    musicpal_misc_init(SYS_BUS_DEVICE(dev));
-
-    dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]);
-    i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
-    i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c");
-
-    lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL);
-    key_dev = sysbus_create_simple("musicpal_key", -1, NULL);
-
-    /* I2C read data */
-    qdev_connect_gpio_out(i2c_dev, 0,
-                          qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT));
-    /* I2C data */
-    qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0));
-    /* I2C clock */
-    qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1));
-
-    for (i = 0; i < 3; i++) {
-        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i));
-    }
-    for (i = 0; i < 4; i++) {
-        qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8));
-    }
-    for (i = 4; i < 8; i++) {
-        qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15));
-    }
-
-    wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR);
-    dev = qdev_create(NULL, "mv88w8618_audio");
-    s = SYS_BUS_DEVICE(dev);
-    qdev_prop_set_ptr(dev, "wm8750", wm8750_dev);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
-    sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
-
-    musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;
-    musicpal_binfo.kernel_filename = kernel_filename;
-    musicpal_binfo.kernel_cmdline = kernel_cmdline;
-    musicpal_binfo.initrd_filename = initrd_filename;
-    arm_load_kernel(cpu, &musicpal_binfo);
-}
-
-static QEMUMachine musicpal_machine = {
-    .name = "musicpal",
-    .desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)",
-    .init = musicpal_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void musicpal_machine_init(void)
-{
-    qemu_register_machine(&musicpal_machine);
-}
-
-machine_init(musicpal_machine_init);
-
-static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = mv88w8618_wlan_init;
-}
-
-static const TypeInfo mv88w8618_wlan_info = {
-    .name          = "mv88w8618_wlan",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SysBusDevice),
-    .class_init    = mv88w8618_wlan_class_init,
-};
-
-static void musicpal_register_types(void)
-{
-    type_register_static(&mv88w8618_pic_info);
-    type_register_static(&mv88w8618_pit_info);
-    type_register_static(&mv88w8618_flashcfg_info);
-    type_register_static(&mv88w8618_eth_info);
-    type_register_static(&mv88w8618_wlan_info);
-    type_register_static(&musicpal_lcd_info);
-    type_register_static(&musicpal_gpio_info);
-    type_register_static(&musicpal_key_info);
-}
-
-type_init(musicpal_register_types)
diff --git a/hw/nseries.c b/hw/nseries.c
deleted file mode 100644 (file)
index c5bf9f9..0000000
+++ /dev/null
@@ -1,1430 +0,0 @@
-/*
- * Nokia N-series internet tablets.
- *
- * Copyright (C) 2007 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu-common.h"
-#include "sysemu/sysemu.h"
-#include "hw/omap.h"
-#include "hw/arm-misc.h"
-#include "hw/irq.h"
-#include "ui/console.h"
-#include "hw/boards.h"
-#include "hw/i2c.h"
-#include "hw/devices.h"
-#include "hw/flash.h"
-#include "hw/hw.h"
-#include "hw/bt.h"
-#include "hw/loader.h"
-#include "sysemu/blockdev.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-/* Nokia N8x0 support */
-struct n800_s {
-    struct omap_mpu_state_s *mpu;
-
-    struct rfbi_chip_s blizzard;
-    struct {
-        void *opaque;
-        uint32_t (*txrx)(void *opaque, uint32_t value, int len);
-        uWireSlave *chip;
-    } ts;
-
-    int keymap[0x80];
-    DeviceState *kbd;
-
-    DeviceState *usb;
-    void *retu;
-    void *tahvo;
-    DeviceState *nand;
-};
-
-/* GPIO pins */
-#define N8X0_TUSB_ENABLE_GPIO          0
-#define N800_MMC2_WP_GPIO              8
-#define N800_UNKNOWN_GPIO0             9       /* out */
-#define N810_MMC2_VIOSD_GPIO           9
-#define N810_HEADSET_AMP_GPIO          10
-#define N800_CAM_TURN_GPIO             12
-#define N810_GPS_RESET_GPIO            12
-#define N800_BLIZZARD_POWERDOWN_GPIO   15
-#define N800_MMC1_WP_GPIO              23
-#define N810_MMC2_VSD_GPIO             23
-#define N8X0_ONENAND_GPIO              26
-#define N810_BLIZZARD_RESET_GPIO       30
-#define N800_UNKNOWN_GPIO2             53      /* out */
-#define N8X0_TUSB_INT_GPIO             58
-#define N8X0_BT_WKUP_GPIO              61
-#define N8X0_STI_GPIO                  62
-#define N8X0_CBUS_SEL_GPIO             64
-#define N8X0_CBUS_DAT_GPIO             65
-#define N8X0_CBUS_CLK_GPIO             66
-#define N8X0_WLAN_IRQ_GPIO             87
-#define N8X0_BT_RESET_GPIO             92
-#define N8X0_TEA5761_CS_GPIO           93
-#define N800_UNKNOWN_GPIO              94
-#define N810_TSC_RESET_GPIO            94
-#define N800_CAM_ACT_GPIO              95
-#define N810_GPS_WAKEUP_GPIO           95
-#define N8X0_MMC_CS_GPIO               96
-#define N8X0_WLAN_PWR_GPIO             97
-#define N8X0_BT_HOST_WKUP_GPIO         98
-#define N810_SPEAKER_AMP_GPIO          101
-#define N810_KB_LOCK_GPIO              102
-#define N800_TSC_TS_GPIO               103
-#define N810_TSC_TS_GPIO               106
-#define N8X0_HEADPHONE_GPIO            107
-#define N8X0_RETU_GPIO                 108
-#define N800_TSC_KP_IRQ_GPIO           109
-#define N810_KEYBOARD_GPIO             109
-#define N800_BAT_COVER_GPIO            110
-#define N810_SLIDE_GPIO                        110
-#define N8X0_TAHVO_GPIO                        111
-#define N800_UNKNOWN_GPIO4             112     /* out */
-#define N810_SLEEPX_LED_GPIO           112
-#define N800_TSC_RESET_GPIO            118     /* ? */
-#define N810_AIC33_RESET_GPIO          118
-#define N800_TSC_UNKNOWN_GPIO          119     /* out */
-#define N8X0_TMP105_GPIO               125
-
-/* Config */
-#define BT_UART                                0
-#define XLDR_LL_UART                   1
-
-/* Addresses on the I2C bus 0 */
-#define N810_TLV320AIC33_ADDR          0x18    /* Audio CODEC */
-#define N8X0_TCM825x_ADDR              0x29    /* Camera */
-#define N810_LP5521_ADDR               0x32    /* LEDs */
-#define N810_TSL2563_ADDR              0x3d    /* Light sensor */
-#define N810_LM8323_ADDR               0x45    /* Keyboard */
-/* Addresses on the I2C bus 1 */
-#define N8X0_TMP105_ADDR               0x48    /* Temperature sensor */
-#define N8X0_MENELAUS_ADDR             0x72    /* Power management */
-
-/* Chipselects on GPMC NOR interface */
-#define N8X0_ONENAND_CS                        0
-#define N8X0_USB_ASYNC_CS              1
-#define N8X0_USB_SYNC_CS               4
-
-#define N8X0_BD_ADDR                   0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81
-
-static void n800_mmc_cs_cb(void *opaque, int line, int level)
-{
-    /* TODO: this seems to actually be connected to the menelaus, to
-     * which also both MMC slots connect.  */
-    omap_mmc_enable((struct omap_mmc_s *) opaque, !level);
-
-    printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1);
-}
-
-static void n8x0_gpio_setup(struct n800_s *s)
-{
-    qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->mpu->mmc, 1);
-    qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]);
-
-    qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO));
-}
-
-#define MAEMO_CAL_HEADER(...)                          \
-    'C',  'o',  'n',  'F',  0x02, 0x00, 0x04, 0x00,    \
-    __VA_ARGS__,                                       \
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-static const uint8_t n8x0_cal_wlan_mac[] = {
-    MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c')
-    0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3,
-    0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
-    0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
-    0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00,
-};
-
-static const uint8_t n8x0_cal_bt_id[] = {
-    MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0)
-    0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96,
-    0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00,
-    N8X0_BD_ADDR,
-};
-
-static void n8x0_nand_setup(struct n800_s *s)
-{
-    char *otp_region;
-    DriveInfo *dinfo;
-
-    s->nand = qdev_create(NULL, "onenand");
-    qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG);
-    /* Either 0x40 or 0x48 are OK for the device ID */
-    qdev_prop_set_uint16(s->nand, "device_id", 0x48);
-    qdev_prop_set_uint16(s->nand, "version_id", 0);
-    qdev_prop_set_int32(s->nand, "shift", 1);
-    dinfo = drive_get(IF_MTD, 0, 0);
-    if (dinfo && dinfo->bdrv) {
-        qdev_prop_set_drive_nofail(s->nand, "drive", dinfo->bdrv);
-    }
-    qdev_init_nofail(s->nand);
-    sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0,
-                       qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO));
-    omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS,
-                     sysbus_mmio_get_region(SYS_BUS_DEVICE(s->nand), 0));
-    otp_region = onenand_raw_otp(s->nand);
-
-    memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
-    memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id));
-    /* XXX: in theory should also update the OOB for both pages */
-}
-
-static qemu_irq n8x0_system_powerdown;
-
-static void n8x0_powerdown_req(Notifier *n, void *opaque)
-{
-    qemu_irq_raise(n8x0_system_powerdown);
-}
-
-static Notifier n8x0_system_powerdown_notifier = {
-    .notify = n8x0_powerdown_req
-};
-
-static void n8x0_i2c_setup(struct n800_s *s)
-{
-    DeviceState *dev;
-    qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO);
-    i2c_bus *i2c = omap_i2c_bus(s->mpu->i2c[0]);
-
-    /* Attach a menelaus PM chip */
-    dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR);
-    qdev_connect_gpio_out(dev, 3,
-                          qdev_get_gpio_in(s->mpu->ih[0],
-                                           OMAP_INT_24XX_SYS_NIRQ));
-
-    n8x0_system_powerdown = qdev_get_gpio_in(dev, 3);
-    qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier);
-
-    /* Attach a TMP105 PM chip (A0 wired to ground) */
-    dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR);
-    qdev_connect_gpio_out(dev, 0, tmp_irq);
-}
-
-/* Touchscreen and keypad controller */
-static MouseTransformInfo n800_pointercal = {
-    .x = 800,
-    .y = 480,
-    .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
-};
-
-static MouseTransformInfo n810_pointercal = {
-    .x = 800,
-    .y = 480,
-    .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
-};
-
-#define RETU_KEYCODE   61      /* F3 */
-
-static void n800_key_event(void *opaque, int keycode)
-{
-    struct n800_s *s = (struct n800_s *) opaque;
-    int code = s->keymap[keycode & 0x7f];
-
-    if (code == -1) {
-        if ((keycode & 0x7f) == RETU_KEYCODE)
-            retu_key_event(s->retu, !(keycode & 0x80));
-        return;
-    }
-
-    tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80));
-}
-
-static const int n800_keys[16] = {
-    -1,
-    72,        /* Up */
-    63,        /* Home (F5) */
-    -1,
-    75,        /* Left */
-    28,        /* Enter */
-    77,        /* Right */
-    -1,
-     1,        /* Cycle (ESC) */
-    80,        /* Down */
-    62,        /* Menu (F4) */
-    -1,
-    66,        /* Zoom- (F8) */
-    64,        /* FullScreen (F6) */
-    65,        /* Zoom+ (F7) */
-    -1,
-};
-
-static void n800_tsc_kbd_setup(struct n800_s *s)
-{
-    int i;
-
-    /* XXX: are the three pins inverted inside the chip between the
-     * tsc and the cpu (N4111)?  */
-    qemu_irq penirq = NULL;    /* NC */
-    qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO);
-    qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO);
-
-    s->ts.chip = tsc2301_init(penirq, kbirq, dav);
-    s->ts.opaque = s->ts.chip->opaque;
-    s->ts.txrx = tsc210x_txrx;
-
-    for (i = 0; i < 0x80; i ++)
-        s->keymap[i] = -1;
-    for (i = 0; i < 0x10; i ++)
-        if (n800_keys[i] >= 0)
-            s->keymap[n800_keys[i]] = i;
-
-    qemu_add_kbd_event_handler(n800_key_event, s);
-
-    tsc210x_set_transform(s->ts.chip, &n800_pointercal);
-}
-
-static void n810_tsc_setup(struct n800_s *s)
-{
-    qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO);
-
-    s->ts.opaque = tsc2005_init(pintdav);
-    s->ts.txrx = tsc2005_txrx;
-
-    tsc2005_set_transform(s->ts.opaque, &n810_pointercal);
-}
-
-/* N810 Keyboard controller */
-static void n810_key_event(void *opaque, int keycode)
-{
-    struct n800_s *s = (struct n800_s *) opaque;
-    int code = s->keymap[keycode & 0x7f];
-
-    if (code == -1) {
-        if ((keycode & 0x7f) == RETU_KEYCODE)
-            retu_key_event(s->retu, !(keycode & 0x80));
-        return;
-    }
-
-    lm832x_key_event(s->kbd, code, !(keycode & 0x80));
-}
-
-#define M      0
-
-static int n810_keys[0x80] = {
-    [0x01] = 16,       /* Q */
-    [0x02] = 37,       /* K */
-    [0x03] = 24,       /* O */
-    [0x04] = 25,       /* P */
-    [0x05] = 14,       /* Backspace */
-    [0x06] = 30,       /* A */
-    [0x07] = 31,       /* S */
-    [0x08] = 32,       /* D */
-    [0x09] = 33,       /* F */
-    [0x0a] = 34,       /* G */
-    [0x0b] = 35,       /* H */
-    [0x0c] = 36,       /* J */
-
-    [0x11] = 17,       /* W */
-    [0x12] = 62,       /* Menu (F4) */
-    [0x13] = 38,       /* L */
-    [0x14] = 40,       /* ' (Apostrophe) */
-    [0x16] = 44,       /* Z */
-    [0x17] = 45,       /* X */
-    [0x18] = 46,       /* C */
-    [0x19] = 47,       /* V */
-    [0x1a] = 48,       /* B */
-    [0x1b] = 49,       /* N */
-    [0x1c] = 42,       /* Shift (Left shift) */
-    [0x1f] = 65,       /* Zoom+ (F7) */
-
-    [0x21] = 18,       /* E */
-    [0x22] = 39,       /* ; (Semicolon) */
-    [0x23] = 12,       /* - (Minus) */
-    [0x24] = 13,       /* = (Equal) */
-    [0x2b] = 56,       /* Fn (Left Alt) */
-    [0x2c] = 50,       /* M */
-    [0x2f] = 66,       /* Zoom- (F8) */
-
-    [0x31] = 19,       /* R */
-    [0x32] = 29 | M,   /* Right Ctrl */
-    [0x34] = 57,       /* Space */
-    [0x35] = 51,       /* , (Comma) */
-    [0x37] = 72 | M,   /* Up */
-    [0x3c] = 82 | M,   /* Compose (Insert) */
-    [0x3f] = 64,       /* FullScreen (F6) */
-
-    [0x41] = 20,       /* T */
-    [0x44] = 52,       /* . (Dot) */
-    [0x46] = 77 | M,   /* Right */
-    [0x4f] = 63,       /* Home (F5) */
-    [0x51] = 21,       /* Y */
-    [0x53] = 80 | M,   /* Down */
-    [0x55] = 28,       /* Enter */
-    [0x5f] =  1,       /* Cycle (ESC) */
-
-    [0x61] = 22,       /* U */
-    [0x64] = 75 | M,   /* Left */
-
-    [0x71] = 23,       /* I */
-#if 0
-    [0x75] = 28 | M,   /* KP Enter (KP Enter) */
-#else
-    [0x75] = 15,       /* KP Enter (Tab) */
-#endif
-};
-
-#undef M
-
-static void n810_kbd_setup(struct n800_s *s)
-{
-    qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO);
-    int i;
-
-    for (i = 0; i < 0x80; i ++)
-        s->keymap[i] = -1;
-    for (i = 0; i < 0x80; i ++)
-        if (n810_keys[i] > 0)
-            s->keymap[n810_keys[i]] = i;
-
-    qemu_add_kbd_event_handler(n810_key_event, s);
-
-    /* Attach the LM8322 keyboard to the I2C bus,
-     * should happen in n8x0_i2c_setup and s->kbd be initialised here.  */
-    s->kbd = i2c_create_slave(omap_i2c_bus(s->mpu->i2c[0]),
-                           "lm8323", N810_LM8323_ADDR);
-    qdev_connect_gpio_out(s->kbd, 0, kbd_irq);
-}
-
-/* LCD MIPI DBI-C controller (URAL) */
-struct mipid_s {
-    int resp[4];
-    int param[4];
-    int p;
-    int pm;
-    int cmd;
-
-    int sleep;
-    int booster;
-    int te;
-    int selfcheck;
-    int partial;
-    int normal;
-    int vscr;
-    int invert;
-    int onoff;
-    int gamma;
-    uint32_t id;
-};
-
-static void mipid_reset(struct mipid_s *s)
-{
-    if (!s->sleep)
-        fprintf(stderr, "%s: Display off\n", __FUNCTION__);
-
-    s->pm = 0;
-    s->cmd = 0;
-
-    s->sleep = 1;
-    s->booster = 0;
-    s->selfcheck =
-            (1 << 7) | /* Register loading OK.  */
-            (1 << 5) | /* The chip is attached.  */
-            (1 << 4);  /* Display glass still in one piece.  */
-    s->te = 0;
-    s->partial = 0;
-    s->normal = 1;
-    s->vscr = 0;
-    s->invert = 0;
-    s->onoff = 1;
-    s->gamma = 0;
-}
-
-static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
-{
-    struct mipid_s *s = (struct mipid_s *) opaque;
-    uint8_t ret;
-
-    if (len > 9)
-        hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len);
-
-    if (s->p >= ARRAY_SIZE(s->resp))
-        ret = 0;
-    else
-        ret = s->resp[s->p ++];
-    if (s->pm --> 0)
-        s->param[s->pm] = cmd;
-    else
-        s->cmd = cmd;
-
-    switch (s->cmd) {
-    case 0x00: /* NOP */
-        break;
-
-    case 0x01: /* SWRESET */
-        mipid_reset(s);
-        break;
-
-    case 0x02: /* BSTROFF */
-        s->booster = 0;
-        break;
-    case 0x03: /* BSTRON */
-        s->booster = 1;
-        break;
-
-    case 0x04: /* RDDID */
-        s->p = 0;
-        s->resp[0] = (s->id >> 16) & 0xff;
-        s->resp[1] = (s->id >>  8) & 0xff;
-        s->resp[2] = (s->id >>  0) & 0xff;
-        break;
-
-    case 0x06: /* RD_RED */
-    case 0x07: /* RD_GREEN */
-        /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so
-         * for the bootloader one needs to change this.  */
-    case 0x08: /* RD_BLUE */
-        s->p = 0;
-        /* TODO: return first pixel components */
-        s->resp[0] = 0x01;
-        break;
-
-    case 0x09: /* RDDST */
-        s->p = 0;
-        s->resp[0] = s->booster << 7;
-        s->resp[1] = (5 << 4) | (s->partial << 2) |
-                (s->sleep << 1) | s->normal;
-        s->resp[2] = (s->vscr << 7) | (s->invert << 5) |
-                (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2);
-        s->resp[3] = s->gamma << 6;
-        break;
-
-    case 0x0a: /* RDDPM */
-        s->p = 0;
-        s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) |
-                (s->partial << 5) | (s->sleep << 6) | (s->booster << 7);
-        break;
-    case 0x0b: /* RDDMADCTR */
-        s->p = 0;
-        s->resp[0] = 0;
-        break;
-    case 0x0c: /* RDDCOLMOD */
-        s->p = 0;
-        s->resp[0] = 5;        /* 65K colours */
-        break;
-    case 0x0d: /* RDDIM */
-        s->p = 0;
-        s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma;
-        break;
-    case 0x0e: /* RDDSM */
-        s->p = 0;
-        s->resp[0] = s->te << 7;
-        break;
-    case 0x0f: /* RDDSDR */
-        s->p = 0;
-        s->resp[0] = s->selfcheck;
-        break;
-
-    case 0x10: /* SLPIN */
-        s->sleep = 1;
-        break;
-    case 0x11: /* SLPOUT */
-        s->sleep = 0;
-        s->selfcheck ^= 1 << 6;        /* POFF self-diagnosis Ok */
-        break;
-
-    case 0x12: /* PTLON */
-        s->partial = 1;
-        s->normal = 0;
-        s->vscr = 0;
-        break;
-    case 0x13: /* NORON */
-        s->partial = 0;
-        s->normal = 1;
-        s->vscr = 0;
-        break;
-
-    case 0x20: /* INVOFF */
-        s->invert = 0;
-        break;
-    case 0x21: /* INVON */
-        s->invert = 1;
-        break;
-
-    case 0x22: /* APOFF */
-    case 0x23: /* APON */
-        goto bad_cmd;
-
-    case 0x25: /* WRCNTR */
-        if (s->pm < 0)
-            s->pm = 1;
-        goto bad_cmd;
-
-    case 0x26: /* GAMSET */
-        if (!s->pm)
-            s->gamma = ffs(s->param[0] & 0xf) - 1;
-        else if (s->pm < 0)
-            s->pm = 1;
-        break;
-
-    case 0x28: /* DISPOFF */
-        s->onoff = 0;
-        fprintf(stderr, "%s: Display off\n", __FUNCTION__);
-        break;
-    case 0x29: /* DISPON */
-        s->onoff = 1;
-        fprintf(stderr, "%s: Display on\n", __FUNCTION__);
-        break;
-
-    case 0x2a: /* CASET */
-    case 0x2b: /* RASET */
-    case 0x2c: /* RAMWR */
-    case 0x2d: /* RGBSET */
-    case 0x2e: /* RAMRD */
-    case 0x30: /* PTLAR */
-    case 0x33: /* SCRLAR */
-        goto bad_cmd;
-
-    case 0x34: /* TEOFF */
-        s->te = 0;
-        break;
-    case 0x35: /* TEON */
-        if (!s->pm)
-            s->te = 1;
-        else if (s->pm < 0)
-            s->pm = 1;
-        break;
-
-    case 0x36: /* MADCTR */
-        goto bad_cmd;
-
-    case 0x37: /* VSCSAD */
-        s->partial = 0;
-        s->normal = 0;
-        s->vscr = 1;
-        break;
-
-    case 0x38: /* IDMOFF */
-    case 0x39: /* IDMON */
-    case 0x3a: /* COLMOD */
-        goto bad_cmd;
-
-    case 0xb0: /* CLKINT / DISCTL */
-    case 0xb1: /* CLKEXT */
-        if (s->pm < 0)
-            s->pm = 2;
-        break;
-
-    case 0xb4: /* FRMSEL */
-        break;
-
-    case 0xb5: /* FRM8SEL */
-    case 0xb6: /* TMPRNG / INIESC */
-    case 0xb7: /* TMPHIS / NOP2 */
-    case 0xb8: /* TMPREAD / MADCTL */
-    case 0xba: /* DISTCTR */
-    case 0xbb: /* EPVOL */
-        goto bad_cmd;
-
-    case 0xbd: /* Unknown */
-        s->p = 0;
-        s->resp[0] = 0;
-        s->resp[1] = 1;
-        break;
-
-    case 0xc2: /* IFMOD */
-        if (s->pm < 0)
-            s->pm = 2;
-        break;
-
-    case 0xc6: /* PWRCTL */
-    case 0xc7: /* PPWRCTL */
-    case 0xd0: /* EPWROUT */
-    case 0xd1: /* EPWRIN */
-    case 0xd4: /* RDEV */
-    case 0xd5: /* RDRR */
-        goto bad_cmd;
-
-    case 0xda: /* RDID1 */
-        s->p = 0;
-        s->resp[0] = (s->id >> 16) & 0xff;
-        break;
-    case 0xdb: /* RDID2 */
-        s->p = 0;
-        s->resp[0] = (s->id >>  8) & 0xff;
-        break;
-    case 0xdc: /* RDID3 */
-        s->p = 0;
-        s->resp[0] = (s->id >>  0) & 0xff;
-        break;
-
-    default:
-    bad_cmd:
-        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd);
-        break;
-    }
-
-    return ret;
-}
-
-static void *mipid_init(void)
-{
-    struct mipid_s *s = (struct mipid_s *) g_malloc0(sizeof(*s));
-
-    s->id = 0x838f03;
-    mipid_reset(s);
-
-    return s;
-}
-
-static void n8x0_spi_setup(struct n800_s *s)
-{
-    void *tsc = s->ts.opaque;
-    void *mipid = mipid_init();
-
-    omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0);
-    omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1);
-}
-
-/* This task is normally performed by the bootloader.  If we're loading
- * a kernel directly, we need to enable the Blizzard ourselves.  */
-static void n800_dss_init(struct rfbi_chip_s *chip)
-{
-    uint8_t *fb_blank;
-
-    chip->write(chip->opaque, 0, 0x2a);                /* LCD Width register */
-    chip->write(chip->opaque, 1, 0x64);
-    chip->write(chip->opaque, 0, 0x2c);                /* LCD HNDP register */
-    chip->write(chip->opaque, 1, 0x1e);
-    chip->write(chip->opaque, 0, 0x2e);                /* LCD Height 0 register */
-    chip->write(chip->opaque, 1, 0xe0);
-    chip->write(chip->opaque, 0, 0x30);                /* LCD Height 1 register */
-    chip->write(chip->opaque, 1, 0x01);
-    chip->write(chip->opaque, 0, 0x32);                /* LCD VNDP register */
-    chip->write(chip->opaque, 1, 0x06);
-    chip->write(chip->opaque, 0, 0x68);                /* Display Mode register */
-    chip->write(chip->opaque, 1, 1);           /* Enable bit */
-
-    chip->write(chip->opaque, 0, 0x6c);        
-    chip->write(chip->opaque, 1, 0x00);                /* Input X Start Position */
-    chip->write(chip->opaque, 1, 0x00);                /* Input X Start Position */
-    chip->write(chip->opaque, 1, 0x00);                /* Input Y Start Position */
-    chip->write(chip->opaque, 1, 0x00);                /* Input Y Start Position */
-    chip->write(chip->opaque, 1, 0x1f);                /* Input X End Position */
-    chip->write(chip->opaque, 1, 0x03);                /* Input X End Position */
-    chip->write(chip->opaque, 1, 0xdf);                /* Input Y End Position */
-    chip->write(chip->opaque, 1, 0x01);                /* Input Y End Position */
-    chip->write(chip->opaque, 1, 0x00);                /* Output X Start Position */
-    chip->write(chip->opaque, 1, 0x00);                /* Output X Start Position */
-    chip->write(chip->opaque, 1, 0x00);                /* Output Y Start Position */
-    chip->write(chip->opaque, 1, 0x00);                /* Output Y Start Position */
-    chip->write(chip->opaque, 1, 0x1f);                /* Output X End Position */
-    chip->write(chip->opaque, 1, 0x03);                /* Output X End Position */
-    chip->write(chip->opaque, 1, 0xdf);                /* Output Y End Position */
-    chip->write(chip->opaque, 1, 0x01);                /* Output Y End Position */
-    chip->write(chip->opaque, 1, 0x01);                /* Input Data Format */
-    chip->write(chip->opaque, 1, 0x01);                /* Data Source Select */
-
-    fb_blank = memset(g_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
-    /* Display Memory Data Port */
-    chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800);
-    g_free(fb_blank);
-}
-
-static void n8x0_dss_setup(struct n800_s *s)
-{
-    s->blizzard.opaque = s1d13745_init(NULL);
-    s->blizzard.block = s1d13745_write_block;
-    s->blizzard.write = s1d13745_write;
-    s->blizzard.read = s1d13745_read;
-
-    omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard);
-}
-
-static void n8x0_cbus_setup(struct n800_s *s)
-{
-    qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO);
-    qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO);
-    qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO);
-
-    CBus *cbus = cbus_init(dat_out);
-
-    qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk);
-    qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat);
-    qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel);
-
-    cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
-    cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
-}
-
-static void n8x0_uart_setup(struct n800_s *s)
-{
-    CharDriverState *radio = uart_hci_init(
-                    qdev_get_gpio_in(s->mpu->gpio, N8X0_BT_HOST_WKUP_GPIO));
-
-    qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO,
-                    csrhci_pins_get(radio)[csrhci_pin_reset]);
-    qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_WKUP_GPIO,
-                    csrhci_pins_get(radio)[csrhci_pin_wakeup]);
-
-    omap_uart_attach(s->mpu->uart[BT_UART], radio);
-}
-
-static void n8x0_usb_setup(struct n800_s *s)
-{
-    SysBusDevice *dev;
-    s->usb = qdev_create(NULL, "tusb6010");
-    dev = SYS_BUS_DEVICE(s->usb);
-    qdev_init_nofail(s->usb);
-    sysbus_connect_irq(dev, 0,
-                       qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO));
-    /* Using the NOR interface */
-    omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS,
-                     sysbus_mmio_get_region(dev, 0));
-    omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS,
-                     sysbus_mmio_get_region(dev, 1));
-    qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO,
-                          qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */
-}
-
-/* Setup done before the main bootloader starts by some early setup code
- * - used when we want to run the main bootloader in emulation.  This
- * isn't documented.  */
-static uint32_t n800_pinout[104] = {
-    0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
-    0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
-    0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
-    0x080800bc, 0x00cc0808, 0x08081818, 0x18180128,
-    0x01241800, 0x18181818, 0x000000f0, 0x01300000,
-    0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b,
-    0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080,
-    0x007c0000, 0x00000000, 0x00000088, 0x00840000,
-    0x00000000, 0x00000094, 0x00980300, 0x0f180003,
-    0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c,
-    0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008,
-    0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f,
-    0x181800f4, 0x00f81818, 0x00000018, 0x000000fc,
-    0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008,
-    0x00000000, 0x00000038, 0x00340000, 0x00000000,
-    0x1a080070, 0x00641a1a, 0x08080808, 0x08080060,
-    0x005c0808, 0x08080808, 0x08080058, 0x00540808,
-    0x08080808, 0x0808006c, 0x00680808, 0x08080808,
-    0x000000a8, 0x00b00000, 0x08080808, 0x000000a0,
-    0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808,
-    0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff,
-    0x000000ac, 0x01040800, 0x08080b0f, 0x18180100,
-    0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a,
-    0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00,
-    0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118,
-    0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b,
-};
-
-static void n800_setup_nolo_tags(void *sram_base)
-{
-    int i;
-    uint32_t *p = sram_base + 0x8000;
-    uint32_t *v = sram_base + 0xa000;
-
-    memset(p, 0, 0x3000);
-
-    strcpy((void *) (p + 0), "QEMU N800");
-
-    strcpy((void *) (p + 8), "F5");
-
-    stl_raw(p + 10, 0x04f70000);
-    strcpy((void *) (p + 9), "RX-34");
-
-    /* RAM size in MB? */
-    stl_raw(p + 12, 0x80);
-
-    /* Pointer to the list of tags */
-    stl_raw(p + 13, OMAP2_SRAM_BASE + 0x9000);
-
-    /* The NOLO tags start here */
-    p = sram_base + 0x9000;
-#define ADD_TAG(tag, len)                              \
-    stw_raw((uint16_t *) p + 0, tag);                  \
-    stw_raw((uint16_t *) p + 1, len); p ++;            \
-    stl_raw(p ++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff));
-
-    /* OMAP STI console? Pin out settings? */
-    ADD_TAG(0x6e01, 414);
-    for (i = 0; i < ARRAY_SIZE(n800_pinout); i ++)
-        stl_raw(v ++, n800_pinout[i]);
-
-    /* Kernel memsize? */
-    ADD_TAG(0x6e05, 1);
-    stl_raw(v ++, 2);
-
-    /* NOLO serial console */
-    ADD_TAG(0x6e02, 4);
-    stl_raw(v ++, XLDR_LL_UART);       /* UART number (1 - 3) */
-
-#if 0
-    /* CBUS settings (Retu/AVilma) */
-    ADD_TAG(0x6e03, 6);
-    stw_raw((uint16_t *) v + 0, 65);   /* CBUS GPIO0 */
-    stw_raw((uint16_t *) v + 1, 66);   /* CBUS GPIO1 */
-    stw_raw((uint16_t *) v + 2, 64);   /* CBUS GPIO2 */
-    v += 2;
-#endif
-
-    /* Nokia ASIC BB5 (Retu/Tahvo) */
-    ADD_TAG(0x6e0a, 4);
-    stw_raw((uint16_t *) v + 0, 111);  /* "Retu" interrupt GPIO */
-    stw_raw((uint16_t *) v + 1, 108);  /* "Tahvo" interrupt GPIO */
-    v ++;
-
-    /* LCD console? */
-    ADD_TAG(0x6e04, 4);
-    stw_raw((uint16_t *) v + 0, 30);   /* ??? */
-    stw_raw((uint16_t *) v + 1, 24);   /* ??? */
-    v ++;
-
-#if 0
-    /* LCD settings */
-    ADD_TAG(0x6e06, 2);
-    stw_raw((uint16_t *) (v ++), 15);  /* ??? */
-#endif
-
-    /* I^2C (Menelaus) */
-    ADD_TAG(0x6e07, 4);
-    stl_raw(v ++, 0x00720000);         /* ??? */
-
-    /* Unknown */
-    ADD_TAG(0x6e0b, 6);
-    stw_raw((uint16_t *) v + 0, 94);   /* ??? */
-    stw_raw((uint16_t *) v + 1, 23);   /* ??? */
-    stw_raw((uint16_t *) v + 2, 0);    /* ??? */
-    v += 2;
-
-    /* OMAP gpio switch info */
-    ADD_TAG(0x6e0c, 80);
-    strcpy((void *) v, "bat_cover");   v += 3;
-    stw_raw((uint16_t *) v + 0, 110);  /* GPIO num ??? */
-    stw_raw((uint16_t *) v + 1, 1);    /* GPIO num ??? */
-    v += 2;
-    strcpy((void *) v, "cam_act");     v += 3;
-    stw_raw((uint16_t *) v + 0, 95);   /* GPIO num ??? */
-    stw_raw((uint16_t *) v + 1, 32);   /* GPIO num ??? */
-    v += 2;
-    strcpy((void *) v, "cam_turn");    v += 3;
-    stw_raw((uint16_t *) v + 0, 12);   /* GPIO num ??? */
-    stw_raw((uint16_t *) v + 1, 33);   /* GPIO num ??? */
-    v += 2;
-    strcpy((void *) v, "headphone");   v += 3;
-    stw_raw((uint16_t *) v + 0, 107);  /* GPIO num ??? */
-    stw_raw((uint16_t *) v + 1, 17);   /* GPIO num ??? */
-    v += 2;
-
-    /* Bluetooth */
-    ADD_TAG(0x6e0e, 12);
-    stl_raw(v ++, 0x5c623d01);         /* ??? */
-    stl_raw(v ++, 0x00000201);         /* ??? */
-    stl_raw(v ++, 0x00000000);         /* ??? */
-
-    /* CX3110x WLAN settings */
-    ADD_TAG(0x6e0f, 8);
-    stl_raw(v ++, 0x00610025);         /* ??? */
-    stl_raw(v ++, 0xffff0057);         /* ??? */
-
-    /* MMC host settings */
-    ADD_TAG(0x6e10, 12);
-    stl_raw(v ++, 0xffff000f);         /* ??? */
-    stl_raw(v ++, 0xffffffff);         /* ??? */
-    stl_raw(v ++, 0x00000060);         /* ??? */
-
-    /* OneNAND chip select */
-    ADD_TAG(0x6e11, 10);
-    stl_raw(v ++, 0x00000401);         /* ??? */
-    stl_raw(v ++, 0x0002003a);         /* ??? */
-    stl_raw(v ++, 0x00000002);         /* ??? */
-
-    /* TEA5761 sensor settings */
-    ADD_TAG(0x6e12, 2);
-    stl_raw(v ++, 93);                 /* GPIO num ??? */
-
-#if 0
-    /* Unknown tag */
-    ADD_TAG(6e09, 0);
-
-    /* Kernel UART / console */
-    ADD_TAG(6e12, 0);
-#endif
-
-    /* End of the list */
-    stl_raw(p ++, 0x00000000);
-    stl_raw(p ++, 0x00000000);
-}
-
-/* This task is normally performed by the bootloader.  If we're loading
- * a kernel directly, we need to set up GPMC mappings ourselves.  */
-static void n800_gpmc_init(struct n800_s *s)
-{
-    uint32_t config7 =
-            (0xf << 8) |       /* MASKADDRESS */
-            (1 << 6) |         /* CSVALID */
-            (4 << 0);          /* BASEADDRESS */
-
-    cpu_physical_memory_write(0x6800a078,              /* GPMC_CONFIG7_0 */
-                    (void *) &config7, sizeof(config7));
-}
-
-/* Setup sequence done by the bootloader */
-static void n8x0_boot_init(void *opaque)
-{
-    struct n800_s *s = (struct n800_s *) opaque;
-    uint32_t buf;
-
-    /* PRCM setup */
-#define omap_writel(addr, val) \
-    buf = (val);                       \
-    cpu_physical_memory_write(addr, (void *) &buf, sizeof(buf))
-
-    omap_writel(0x48008060, 0x41);             /* PRCM_CLKSRC_CTRL */
-    omap_writel(0x48008070, 1);                        /* PRCM_CLKOUT_CTRL */
-    omap_writel(0x48008078, 0);                        /* PRCM_CLKEMUL_CTRL */
-    omap_writel(0x48008090, 0);                        /* PRCM_VOLTSETUP */
-    omap_writel(0x48008094, 0);                        /* PRCM_CLKSSETUP */
-    omap_writel(0x48008098, 0);                        /* PRCM_POLCTRL */
-    omap_writel(0x48008140, 2);                        /* CM_CLKSEL_MPU */
-    omap_writel(0x48008148, 0);                        /* CM_CLKSTCTRL_MPU */
-    omap_writel(0x48008158, 1);                        /* RM_RSTST_MPU */
-    omap_writel(0x480081c8, 0x15);             /* PM_WKDEP_MPU */
-    omap_writel(0x480081d4, 0x1d4);            /* PM_EVGENCTRL_MPU */
-    omap_writel(0x480081d8, 0);                        /* PM_EVEGENONTIM_MPU */
-    omap_writel(0x480081dc, 0);                        /* PM_EVEGENOFFTIM_MPU */
-    omap_writel(0x480081e0, 0xc);              /* PM_PWSTCTRL_MPU */
-    omap_writel(0x48008200, 0x047e7ff7);       /* CM_FCLKEN1_CORE */
-    omap_writel(0x48008204, 0x00000004);       /* CM_FCLKEN2_CORE */
-    omap_writel(0x48008210, 0x047e7ff1);       /* CM_ICLKEN1_CORE */
-    omap_writel(0x48008214, 0x00000004);       /* CM_ICLKEN2_CORE */
-    omap_writel(0x4800821c, 0x00000000);       /* CM_ICLKEN4_CORE */
-    omap_writel(0x48008230, 0);                        /* CM_AUTOIDLE1_CORE */
-    omap_writel(0x48008234, 0);                        /* CM_AUTOIDLE2_CORE */
-    omap_writel(0x48008238, 7);                        /* CM_AUTOIDLE3_CORE */
-    omap_writel(0x4800823c, 0);                        /* CM_AUTOIDLE4_CORE */
-    omap_writel(0x48008240, 0x04360626);       /* CM_CLKSEL1_CORE */
-    omap_writel(0x48008244, 0x00000014);       /* CM_CLKSEL2_CORE */
-    omap_writel(0x48008248, 0);                        /* CM_CLKSTCTRL_CORE */
-    omap_writel(0x48008300, 0x00000000);       /* CM_FCLKEN_GFX */
-    omap_writel(0x48008310, 0x00000000);       /* CM_ICLKEN_GFX */
-    omap_writel(0x48008340, 0x00000001);       /* CM_CLKSEL_GFX */
-    omap_writel(0x48008400, 0x00000004);       /* CM_FCLKEN_WKUP */
-    omap_writel(0x48008410, 0x00000004);       /* CM_ICLKEN_WKUP */
-    omap_writel(0x48008440, 0x00000000);       /* CM_CLKSEL_WKUP */
-    omap_writel(0x48008500, 0x000000cf);       /* CM_CLKEN_PLL */
-    omap_writel(0x48008530, 0x0000000c);       /* CM_AUTOIDLE_PLL */
-    omap_writel(0x48008540,                    /* CM_CLKSEL1_PLL */
-                    (0x78 << 12) | (6 << 8));
-    omap_writel(0x48008544, 2);                        /* CM_CLKSEL2_PLL */
-
-    /* GPMC setup */
-    n800_gpmc_init(s);
-
-    /* Video setup */
-    n800_dss_init(&s->blizzard);
-
-    /* CPU setup */
-    s->mpu->cpu->env.GE = 0x5;
-
-    /* If the machine has a slided keyboard, open it */
-    if (s->kbd)
-        qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO));
-}
-
-#define OMAP_TAG_NOKIA_BT      0x4e01
-#define OMAP_TAG_WLAN_CX3110X  0x4e02
-#define OMAP_TAG_CBUS          0x4e03
-#define OMAP_TAG_EM_ASIC_BB5   0x4e04
-
-static struct omap_gpiosw_info_s {
-    const char *name;
-    int line;
-    int type;
-} n800_gpiosw_info[] = {
-    {
-        "bat_cover", N800_BAT_COVER_GPIO,
-        OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
-    }, {
-        "cam_act", N800_CAM_ACT_GPIO,
-        OMAP_GPIOSW_TYPE_ACTIVITY,
-    }, {
-        "cam_turn", N800_CAM_TURN_GPIO,
-        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED,
-    }, {
-        "headphone", N8X0_HEADPHONE_GPIO,
-        OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
-    },
-    { NULL }
-}, n810_gpiosw_info[] = {
-    {
-        "gps_reset", N810_GPS_RESET_GPIO,
-        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
-    }, {
-        "gps_wakeup", N810_GPS_WAKEUP_GPIO,
-        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
-    }, {
-        "headphone", N8X0_HEADPHONE_GPIO,
-        OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
-    }, {
-        "kb_lock", N810_KB_LOCK_GPIO,
-        OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
-    }, {
-        "sleepx_led", N810_SLEEPX_LED_GPIO,
-        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT,
-    }, {
-        "slide", N810_SLIDE_GPIO,
-        OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
-    },
-    { NULL }
-};
-
-static struct omap_partition_info_s {
-    uint32_t offset;
-    uint32_t size;
-    int mask;
-    const char *name;
-} n800_part_info[] = {
-    { 0x00000000, 0x00020000, 0x3, "bootloader" },
-    { 0x00020000, 0x00060000, 0x0, "config" },
-    { 0x00080000, 0x00200000, 0x0, "kernel" },
-    { 0x00280000, 0x00200000, 0x3, "initfs" },
-    { 0x00480000, 0x0fb80000, 0x3, "rootfs" },
-
-    { 0, 0, 0, NULL }
-}, n810_part_info[] = {
-    { 0x00000000, 0x00020000, 0x3, "bootloader" },
-    { 0x00020000, 0x00060000, 0x0, "config" },
-    { 0x00080000, 0x00220000, 0x0, "kernel" },
-    { 0x002a0000, 0x00400000, 0x0, "initfs" },
-    { 0x006a0000, 0x0f960000, 0x0, "rootfs" },
-
-    { 0, 0, 0, NULL }
-};
-
-static bdaddr_t n8x0_bd_addr = {{ N8X0_BD_ADDR }};
-
-static int n8x0_atag_setup(void *p, int model)
-{
-    uint8_t *b;
-    uint16_t *w;
-    uint32_t *l;
-    struct omap_gpiosw_info_s *gpiosw;
-    struct omap_partition_info_s *partition;
-    const char *tag;
-
-    w = p;
-
-    stw_raw(w ++, OMAP_TAG_UART);              /* u16 tag */
-    stw_raw(w ++, 4);                          /* u16 len */
-    stw_raw(w ++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */
-    w ++;
-
-#if 0
-    stw_raw(w ++, OMAP_TAG_SERIAL_CONSOLE);    /* u16 tag */
-    stw_raw(w ++, 4);                          /* u16 len */
-    stw_raw(w ++, XLDR_LL_UART + 1);           /* u8 console_uart */
-    stw_raw(w ++, 115200);                     /* u32 console_speed */
-#endif
-
-    stw_raw(w ++, OMAP_TAG_LCD);               /* u16 tag */
-    stw_raw(w ++, 36);                         /* u16 len */
-    strcpy((void *) w, "QEMU LCD panel");      /* char panel_name[16] */
-    w += 8;
-    strcpy((void *) w, "blizzard");            /* char ctrl_name[16] */
-    w += 8;
-    stw_raw(w ++, N810_BLIZZARD_RESET_GPIO);   /* TODO: n800 s16 nreset_gpio */
-    stw_raw(w ++, 24);                         /* u8 data_lines */
-
-    stw_raw(w ++, OMAP_TAG_CBUS);              /* u16 tag */
-    stw_raw(w ++, 8);                          /* u16 len */
-    stw_raw(w ++, N8X0_CBUS_CLK_GPIO);         /* s16 clk_gpio */
-    stw_raw(w ++, N8X0_CBUS_DAT_GPIO);         /* s16 dat_gpio */
-    stw_raw(w ++, N8X0_CBUS_SEL_GPIO);         /* s16 sel_gpio */
-    w ++;
-
-    stw_raw(w ++, OMAP_TAG_EM_ASIC_BB5);       /* u16 tag */
-    stw_raw(w ++, 4);                          /* u16 len */
-    stw_raw(w ++, N8X0_RETU_GPIO);             /* s16 retu_irq_gpio */
-    stw_raw(w ++, N8X0_TAHVO_GPIO);            /* s16 tahvo_irq_gpio */
-
-    gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info;
-    for (; gpiosw->name; gpiosw ++) {
-        stw_raw(w ++, OMAP_TAG_GPIO_SWITCH);   /* u16 tag */
-        stw_raw(w ++, 20);                     /* u16 len */
-        strcpy((void *) w, gpiosw->name);      /* char name[12] */
-        w += 6;
-        stw_raw(w ++, gpiosw->line);           /* u16 gpio */
-        stw_raw(w ++, gpiosw->type);
-        stw_raw(w ++, 0);
-        stw_raw(w ++, 0);
-    }
-
-    stw_raw(w ++, OMAP_TAG_NOKIA_BT);          /* u16 tag */
-    stw_raw(w ++, 12);                         /* u16 len */
-    b = (void *) w;
-    stb_raw(b ++, 0x01);                       /* u8 chip_type (CSR) */
-    stb_raw(b ++, N8X0_BT_WKUP_GPIO);          /* u8 bt_wakeup_gpio */
-    stb_raw(b ++, N8X0_BT_HOST_WKUP_GPIO);     /* u8 host_wakeup_gpio */
-    stb_raw(b ++, N8X0_BT_RESET_GPIO);         /* u8 reset_gpio */
-    stb_raw(b ++, BT_UART + 1);                        /* u8 bt_uart */
-    memcpy(b, &n8x0_bd_addr, 6);               /* u8 bd_addr[6] */
-    b += 6;
-    stb_raw(b ++, 0x02);                       /* u8 bt_sysclk (38.4) */
-    w = (void *) b;
-
-    stw_raw(w ++, OMAP_TAG_WLAN_CX3110X);      /* u16 tag */
-    stw_raw(w ++, 8);                          /* u16 len */
-    stw_raw(w ++, 0x25);                       /* u8 chip_type */
-    stw_raw(w ++, N8X0_WLAN_PWR_GPIO);         /* s16 power_gpio */
-    stw_raw(w ++, N8X0_WLAN_IRQ_GPIO);         /* s16 irq_gpio */
-    stw_raw(w ++, -1);                         /* s16 spi_cs_gpio */
-
-    stw_raw(w ++, OMAP_TAG_MMC);               /* u16 tag */
-    stw_raw(w ++, 16);                         /* u16 len */
-    if (model == 810) {
-        stw_raw(w ++, 0x23f);                  /* unsigned flags */
-        stw_raw(w ++, -1);                     /* s16 power_pin */
-        stw_raw(w ++, -1);                     /* s16 switch_pin */
-        stw_raw(w ++, -1);                     /* s16 wp_pin */
-        stw_raw(w ++, 0x240);                  /* unsigned flags */
-        stw_raw(w ++, 0xc000);                 /* s16 power_pin */
-        stw_raw(w ++, 0x0248);                 /* s16 switch_pin */
-        stw_raw(w ++, 0xc000);                 /* s16 wp_pin */
-    } else {
-        stw_raw(w ++, 0xf);                    /* unsigned flags */
-        stw_raw(w ++, -1);                     /* s16 power_pin */
-        stw_raw(w ++, -1);                     /* s16 switch_pin */
-        stw_raw(w ++, -1);                     /* s16 wp_pin */
-        stw_raw(w ++, 0);                      /* unsigned flags */
-        stw_raw(w ++, 0);                      /* s16 power_pin */
-        stw_raw(w ++, 0);                      /* s16 switch_pin */
-        stw_raw(w ++, 0);                      /* s16 wp_pin */
-    }
-
-    stw_raw(w ++, OMAP_TAG_TEA5761);           /* u16 tag */
-    stw_raw(w ++, 4);                          /* u16 len */
-    stw_raw(w ++, N8X0_TEA5761_CS_GPIO);       /* u16 enable_gpio */
-    w ++;
-
-    partition = (model == 810) ? n810_part_info : n800_part_info;
-    for (; partition->name; partition ++) {
-        stw_raw(w ++, OMAP_TAG_PARTITION);     /* u16 tag */
-        stw_raw(w ++, 28);                     /* u16 len */
-        strcpy((void *) w, partition->name);   /* char name[16] */
-        l = (void *) (w + 8);
-        stl_raw(l ++, partition->size);                /* unsigned int size */
-        stl_raw(l ++, partition->offset);      /* unsigned int offset */
-        stl_raw(l ++, partition->mask);                /* unsigned int mask_flags */
-        w = (void *) l;
-    }
-
-    stw_raw(w ++, OMAP_TAG_BOOT_REASON);       /* u16 tag */
-    stw_raw(w ++, 12);                         /* u16 len */
-#if 0
-    strcpy((void *) w, "por");                 /* char reason_str[12] */
-    strcpy((void *) w, "charger");             /* char reason_str[12] */
-    strcpy((void *) w, "32wd_to");             /* char reason_str[12] */
-    strcpy((void *) w, "sw_rst");              /* char reason_str[12] */
-    strcpy((void *) w, "mbus");                        /* char reason_str[12] */
-    strcpy((void *) w, "unknown");             /* char reason_str[12] */
-    strcpy((void *) w, "swdg_to");             /* char reason_str[12] */
-    strcpy((void *) w, "sec_vio");             /* char reason_str[12] */
-    strcpy((void *) w, "pwr_key");             /* char reason_str[12] */
-    strcpy((void *) w, "rtc_alarm");           /* char reason_str[12] */
-#else
-    strcpy((void *) w, "pwr_key");             /* char reason_str[12] */
-#endif
-    w += 6;
-
-    tag = (model == 810) ? "RX-44" : "RX-34";
-    stw_raw(w ++, OMAP_TAG_VERSION_STR);       /* u16 tag */
-    stw_raw(w ++, 24);                         /* u16 len */
-    strcpy((void *) w, "product");             /* char component[12] */
-    w += 6;
-    strcpy((void *) w, tag);                   /* char version[12] */
-    w += 6;
-
-    stw_raw(w ++, OMAP_TAG_VERSION_STR);       /* u16 tag */
-    stw_raw(w ++, 24);                         /* u16 len */
-    strcpy((void *) w, "hw-build");            /* char component[12] */
-    w += 6;
-    strcpy((void *) w, "QEMU ");
-    pstrcat((void *) w, 12, qemu_get_version()); /* char version[12] */
-    w += 6;
-
-    tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu";
-    stw_raw(w ++, OMAP_TAG_VERSION_STR);       /* u16 tag */
-    stw_raw(w ++, 24);                         /* u16 len */
-    strcpy((void *) w, "nolo");                        /* char component[12] */
-    w += 6;
-    strcpy((void *) w, tag);                   /* char version[12] */
-    w += 6;
-
-    return (void *) w - p;
-}
-
-static int n800_atag_setup(const struct arm_boot_info *info, void *p)
-{
-    return n8x0_atag_setup(p, 800);
-}
-
-static int n810_atag_setup(const struct arm_boot_info *info, void *p)
-{
-    return n8x0_atag_setup(p, 810);
-}
-
-static void n8x0_init(QEMUMachineInitArgs *args,
-                      struct arm_boot_info *binfo, int model)
-{
-    MemoryRegion *sysmem = get_system_memory();
-    struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
-    int sdram_size = binfo->ram_size;
-    DisplayState *ds;
-
-    s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model);
-
-    /* Setup peripherals
-     *
-     * Believed external peripherals layout in the N810:
-     * (spi bus 1)
-     *   tsc2005
-     *   lcd_mipid
-     * (spi bus 2)
-     *   Conexant cx3110x (WLAN)
-     *   optional: pc2400m (WiMAX)
-     * (i2c bus 0)
-     *   TLV320AIC33 (audio codec)
-     *   TCM825x (camera by Toshiba)
-     *   lp5521 (clever LEDs)
-     *   tsl2563 (light sensor, hwmon, model 7, rev. 0)
-     *   lm8323 (keypad, manf 00, rev 04)
-     * (i2c bus 1)
-     *   tmp105 (temperature sensor, hwmon)
-     *   menelaus (pm)
-     * (somewhere on i2c - maybe N800-only)
-     *   tea5761 (FM tuner)
-     * (serial 0)
-     *   GPS
-     * (some serial port)
-     *   csr41814 (Bluetooth)
-     */
-    n8x0_gpio_setup(s);
-    n8x0_nand_setup(s);
-    n8x0_i2c_setup(s);
-    if (model == 800)
-        n800_tsc_kbd_setup(s);
-    else if (model == 810) {
-        n810_tsc_setup(s);
-        n810_kbd_setup(s);
-    }
-    n8x0_spi_setup(s);
-    n8x0_dss_setup(s);
-    n8x0_cbus_setup(s);
-    n8x0_uart_setup(s);
-    if (usb_enabled(false)) {
-        n8x0_usb_setup(s);
-    }
-
-    if (args->kernel_filename) {
-        /* Or at the linux loader.  */
-        binfo->kernel_filename = args->kernel_filename;
-        binfo->kernel_cmdline = args->kernel_cmdline;
-        binfo->initrd_filename = args->initrd_filename;
-        arm_load_kernel(s->mpu->cpu, binfo);
-
-        qemu_register_reset(n8x0_boot_init, s);
-    }
-
-    if (option_rom[0].name &&
-        (args->boot_device[0] == 'n' || !args->kernel_filename)) {
-        int rom_size;
-        uint8_t nolo_tags[0x10000];
-        /* No, wait, better start at the ROM.  */
-        s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
-
-        /* This is intended for loading the `secondary.bin' program from
-         * Nokia images (the NOLO bootloader).  The entry point seems
-         * to be at OMAP2_Q2_BASE + 0x400000.
-         *
-         * The `2nd.bin' files contain some kind of earlier boot code and
-         * for them the entry point needs to be set to OMAP2_SRAM_BASE.
-         *
-         * The code above is for loading the `zImage' file from Nokia
-         * images.  */
-        rom_size = load_image_targphys(option_rom[0].name,
-                                       OMAP2_Q2_BASE + 0x400000,
-                                       sdram_size - 0x400000);
-        printf("%i bytes of image loaded\n", rom_size);
-
-        n800_setup_nolo_tags(nolo_tags);
-        cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
-    }
-    /* FIXME: We shouldn't really be doing this here.  The LCD controller
-       will set the size once configured, so this just sets an initial
-       size until the guest activates the display.  */
-    ds = get_displaystate();
-    ds->surface = qemu_resize_displaysurface(ds, 800, 480);
-    dpy_gfx_resize(ds);
-}
-
-static struct arm_boot_info n800_binfo = {
-    .loader_start = OMAP2_Q2_BASE,
-    /* Actually two chips of 0x4000000 bytes each */
-    .ram_size = 0x08000000,
-    .board_id = 0x4f7,
-    .atag_board = n800_atag_setup,
-};
-
-static struct arm_boot_info n810_binfo = {
-    .loader_start = OMAP2_Q2_BASE,
-    /* Actually two chips of 0x4000000 bytes each */
-    .ram_size = 0x08000000,
-    /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not
-     * used by some older versions of the bootloader and 5555 is used
-     * instead (including versions that shipped with many devices).  */
-    .board_id = 0x60c,
-    .atag_board = n810_atag_setup,
-};
-
-static void n800_init(QEMUMachineInitArgs *args)
-{
-    return n8x0_init(args, &n800_binfo, 800);
-}
-
-static void n810_init(QEMUMachineInitArgs *args)
-{
-    return n8x0_init(args, &n810_binfo, 810);
-}
-
-static QEMUMachine n800_machine = {
-    .name = "n800",
-    .desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)",
-    .init = n800_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine n810_machine = {
-    .name = "n810",
-    .desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)",
-    .init = n810_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void nseries_machine_init(void)
-{
-    qemu_register_machine(&n800_machine);
-    qemu_register_machine(&n810_machine);
-}
-
-machine_init(nseries_machine_init);
diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c
deleted file mode 100644 (file)
index 8598233..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/* omap_sx1.c Support for the Siemens SX1 smartphone emulation.
- *
- *   Copyright (C) 2008
- *     Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *   Copyright (C) 2007 Vladimir Ananiev <vovan888@gmail.com>
- *
- *   based on PalmOne's (TM) PDAs support (palm.c)
- */
-
-/*
- * PalmOne's (TM) PDAs.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/omap.h"
-#include "hw/boards.h"
-#include "hw/arm-misc.h"
-#include "hw/flash.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-/*****************************************************************************/
-/* Siemens SX1 Cellphone V1 */
-/* - ARM OMAP310 processor
- * - SRAM                192 kB
- * - SDRAM                32 MB at 0x10000000
- * - Boot flash           16 MB at 0x00000000
- * - Application flash     8 MB at 0x04000000
- * - 3 serial ports
- * - 1 SecureDigital
- * - 1 LCD display
- * - 1 RTC
- */
-
-/*****************************************************************************/
-/* Siemens SX1 Cellphone V2 */
-/* - ARM OMAP310 processor
- * - SRAM                192 kB
- * - SDRAM                32 MB at 0x10000000
- * - Boot flash           32 MB at 0x00000000
- * - 3 serial ports
- * - 1 SecureDigital
- * - 1 LCD display
- * - 1 RTC
- */
-
-static uint64_t static_read(void *opaque, hwaddr offset,
-                            unsigned size)
-{
-    uint32_t *val = (uint32_t *) opaque;
-    uint32_t mask = (4 / size) - 1;
-
-    return *val >> ((offset & mask) << 3);
-}
-
-static void static_write(void *opaque, hwaddr offset,
-                         uint64_t value, unsigned size)
-{
-#ifdef SPY
-    printf("%s: value %" PRIx64 " %u bytes written at 0x%x\n",
-                    __func__, value, size, (int)offset);
-#endif
-}
-
-static const MemoryRegionOps static_ops = {
-    .read = static_read,
-    .write = static_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-#define sdram_size     0x02000000
-#define sector_size    (128 * 1024)
-#define flash0_size    (16 * 1024 * 1024)
-#define flash1_size    ( 8 * 1024 * 1024)
-#define flash2_size    (32 * 1024 * 1024)
-#define total_ram_v1   (sdram_size + flash0_size + flash1_size + OMAP15XX_SRAM_SIZE)
-#define total_ram_v2   (sdram_size + flash2_size + OMAP15XX_SRAM_SIZE)
-
-static struct arm_boot_info sx1_binfo = {
-    .loader_start = OMAP_EMIFF_BASE,
-    .ram_size = sdram_size,
-    .board_id = 0x265,
-};
-
-static void sx1_init(QEMUMachineInitArgs *args, const int version)
-{
-    struct omap_mpu_state_s *mpu;
-    MemoryRegion *address_space = get_system_memory();
-    MemoryRegion *flash = g_new(MemoryRegion, 1);
-    MemoryRegion *flash_1 = g_new(MemoryRegion, 1);
-    MemoryRegion *cs = g_new(MemoryRegion, 4);
-    static uint32_t cs0val = 0x00213090;
-    static uint32_t cs1val = 0x00215070;
-    static uint32_t cs2val = 0x00001139;
-    static uint32_t cs3val = 0x00001139;
-    DriveInfo *dinfo;
-    int fl_idx;
-    uint32_t flash_size = flash0_size;
-    int be;
-
-    if (version == 2) {
-        flash_size = flash2_size;
-    }
-
-    mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model);
-
-    /* External Flash (EMIFS) */
-    memory_region_init_ram(flash, "omap_sx1.flash0-0", flash_size);
-    vmstate_register_ram_global(flash);
-    memory_region_set_readonly(flash, true);
-    memory_region_add_subregion(address_space, OMAP_CS0_BASE, flash);
-
-    memory_region_init_io(&cs[0], &static_ops, &cs0val,
-                          "sx1.cs0", OMAP_CS0_SIZE - flash_size);
-    memory_region_add_subregion(address_space,
-                                OMAP_CS0_BASE + flash_size, &cs[0]);
-
-
-    memory_region_init_io(&cs[2], &static_ops, &cs2val,
-                          "sx1.cs2", OMAP_CS2_SIZE);
-    memory_region_add_subregion(address_space,
-                                OMAP_CS2_BASE, &cs[2]);
-
-    memory_region_init_io(&cs[3], &static_ops, &cs3val,
-                          "sx1.cs3", OMAP_CS3_SIZE);
-    memory_region_add_subregion(address_space,
-                                OMAP_CS2_BASE, &cs[3]);
-
-    fl_idx = 0;
-#ifdef TARGET_WORDS_BIGENDIAN
-    be = 1;
-#else
-    be = 0;
-#endif
-
-    if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
-        if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL,
-                                   "omap_sx1.flash0-1", flash_size,
-                                   dinfo->bdrv, sector_size,
-                                   flash_size / sector_size,
-                                   4, 0, 0, 0, 0, be)) {
-            fprintf(stderr, "qemu: Error registering flash memory %d.\n",
-                           fl_idx);
-        }
-        fl_idx++;
-    }
-
-    if ((version == 1) &&
-            (dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
-        memory_region_init_ram(flash_1, "omap_sx1.flash1-0", flash1_size);
-        vmstate_register_ram_global(flash_1);
-        memory_region_set_readonly(flash_1, true);
-        memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1);
-
-        memory_region_init_io(&cs[1], &static_ops, &cs1val,
-                              "sx1.cs1", OMAP_CS1_SIZE - flash1_size);
-        memory_region_add_subregion(address_space,
-                                OMAP_CS1_BASE + flash1_size, &cs[1]);
-
-        if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL,
-                                   "omap_sx1.flash1-1", flash1_size,
-                                   dinfo->bdrv, sector_size,
-                                   flash1_size / sector_size,
-                                   4, 0, 0, 0, 0, be)) {
-            fprintf(stderr, "qemu: Error registering flash memory %d.\n",
-                           fl_idx);
-        }
-        fl_idx++;
-    } else {
-        memory_region_init_io(&cs[1], &static_ops, &cs1val,
-                              "sx1.cs1", OMAP_CS1_SIZE);
-        memory_region_add_subregion(address_space,
-                                OMAP_CS1_BASE, &cs[1]);
-    }
-
-    if (!args->kernel_filename && !fl_idx) {
-        fprintf(stderr, "Kernel or Flash image must be specified\n");
-        exit(1);
-    }
-
-    /* Load the kernel.  */
-    if (args->kernel_filename) {
-        sx1_binfo.kernel_filename = args->kernel_filename;
-        sx1_binfo.kernel_cmdline = args->kernel_cmdline;
-        sx1_binfo.initrd_filename = args->initrd_filename;
-        arm_load_kernel(mpu->cpu, &sx1_binfo);
-    }
-
-    /* TODO: fix next line */
-    //~ qemu_console_resize(ds, 640, 480);
-}
-
-static void sx1_init_v1(QEMUMachineInitArgs *args)
-{
-    sx1_init(args, 1);
-}
-
-static void sx1_init_v2(QEMUMachineInitArgs *args)
-{
-    sx1_init(args, 2);
-}
-
-static QEMUMachine sx1_machine_v2 = {
-    .name = "sx1",
-    .desc = "Siemens SX1 (OMAP310) V2",
-    .init = sx1_init_v2,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine sx1_machine_v1 = {
-    .name = "sx1-v1",
-    .desc = "Siemens SX1 (OMAP310) V1",
-    .init = sx1_init_v1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void sx1_machine_init(void)
-{
-    qemu_register_machine(&sx1_machine_v2);
-    qemu_register_machine(&sx1_machine_v1);
-}
-
-machine_init(sx1_machine_init);
index 38ff8f5d6d2fc50e9881ef14585f72f2b4caefb9..61246b149b7ed733d5756eea2bdf93029a57ea09 100644 (file)
@@ -1,3 +1,2 @@
-obj-y = openrisc_pic.o openrisc_sim.o openrisc_timer.o
-
-obj-y := $(addprefix ../,$(obj-y))
+obj-y = pic_cpu.o cputimer.o
+obj-y += openrisc_sim.o 
diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c
new file mode 100644 (file)
index 0000000..f6c877f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * QEMU OpenRISC timer support
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *                         Zhizhou Zhang <etouzh@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "hw/hw.h"
+#include "qemu/timer.h"
+
+#define TIMER_FREQ    (20 * 1000 * 1000)    /* 20MHz */
+
+/* The time when TTCR changes */
+static uint64_t last_clk;
+static int is_counting;
+
+void cpu_openrisc_count_update(OpenRISCCPU *cpu)
+{
+    uint64_t now, next;
+    uint32_t wait;
+
+    now = qemu_get_clock_ns(vm_clock);
+    if (!is_counting) {
+        qemu_del_timer(cpu->env.timer);
+        last_clk = now;
+        return;
+    }
+
+    cpu->env.ttcr += (uint32_t)muldiv64(now - last_clk, TIMER_FREQ,
+                                        get_ticks_per_sec());
+    last_clk = now;
+
+    if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) {
+        wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1;
+        wait += cpu->env.ttmr & TTMR_TP;
+    } else {
+        wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP);
+    }
+
+    next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
+    qemu_mod_timer(cpu->env.timer, next);
+}
+
+void cpu_openrisc_count_start(OpenRISCCPU *cpu)
+{
+    is_counting = 1;
+    cpu_openrisc_count_update(cpu);
+}
+
+void cpu_openrisc_count_stop(OpenRISCCPU *cpu)
+{
+    is_counting = 0;
+    cpu_openrisc_count_update(cpu);
+}
+
+static void openrisc_timer_cb(void *opaque)
+{
+    OpenRISCCPU *cpu = opaque;
+
+    if ((cpu->env.ttmr & TTMR_IE) &&
+         qemu_timer_expired(cpu->env.timer, qemu_get_clock_ns(vm_clock))) {
+        cpu->env.ttmr |= TTMR_IP;
+        cpu->env.interrupt_request |= CPU_INTERRUPT_TIMER;
+    }
+
+    switch (cpu->env.ttmr & TTMR_M) {
+    case TIMER_NONE:
+        break;
+    case TIMER_INTR:
+        cpu->env.ttcr = 0;
+        cpu_openrisc_count_start(cpu);
+        break;
+    case TIMER_SHOT:
+        cpu_openrisc_count_stop(cpu);
+        break;
+    case TIMER_CONT:
+        cpu_openrisc_count_start(cpu);
+        break;
+    }
+}
+
+void cpu_openrisc_clock_init(OpenRISCCPU *cpu)
+{
+    cpu->env.timer = qemu_new_timer_ns(vm_clock, &openrisc_timer_cb, cpu);
+    cpu->env.ttmr = 0x00000000;
+    cpu->env.ttcr = 0x00000000;
+}
diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c
new file mode 100644 (file)
index 0000000..db2aac8
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * OpenRISC simulator for use as an IIS.
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *                         Feng Gao <gf91597@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "elf.h"
+#include "hw/serial.h"
+#include "net/net.h"
+#include "hw/loader.h"
+#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "sysemu/qtest.h"
+
+#define KERNEL_LOAD_ADDR 0x100
+
+static void main_cpu_reset(void *opaque)
+{
+    OpenRISCCPU *cpu = opaque;
+
+    cpu_reset(CPU(cpu));
+}
+
+static void openrisc_sim_net_init(MemoryRegion *address_space,
+                                  hwaddr base,
+                                  hwaddr descriptors,
+                                  qemu_irq irq, NICInfo *nd)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "open_eth");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, irq);
+    memory_region_add_subregion(address_space, base,
+                                sysbus_mmio_get_region(s, 0));
+    memory_region_add_subregion(address_space, descriptors,
+                                sysbus_mmio_get_region(s, 1));
+}
+
+static void cpu_openrisc_load_kernel(ram_addr_t ram_size,
+                                     const char *kernel_filename,
+                                     OpenRISCCPU *cpu)
+{
+    long kernel_size;
+    uint64_t elf_entry;
+    hwaddr entry;
+
+    if (kernel_filename && !qtest_enabled()) {
+        kernel_size = load_elf(kernel_filename, NULL, NULL,
+                               &elf_entry, NULL, NULL, 1, ELF_MACHINE, 1);
+        entry = elf_entry;
+        if (kernel_size < 0) {
+            kernel_size = load_uimage(kernel_filename,
+                                      &entry, NULL, NULL);
+        }
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              ram_size - KERNEL_LOAD_ADDR);
+            entry = KERNEL_LOAD_ADDR;
+        }
+
+        if (kernel_size < 0) {
+            qemu_log("QEMU: couldn't load the kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    cpu->env.pc = entry;
+}
+
+static void openrisc_sim_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+   OpenRISCCPU *cpu = NULL;
+    MemoryRegion *ram;
+    int n;
+
+    if (!cpu_model) {
+        cpu_model = "or1200";
+    }
+
+    for (n = 0; n < smp_cpus; n++) {
+        cpu = cpu_openrisc_init(cpu_model);
+        if (cpu == NULL) {
+            qemu_log("Unable to find CPU definition!\n");
+            exit(1);
+        }
+        qemu_register_reset(main_cpu_reset, cpu);
+        main_cpu_reset(cpu);
+    }
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, "openrisc.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(get_system_memory(), 0, ram);
+
+    cpu_openrisc_pic_init(cpu);
+    cpu_openrisc_clock_init(cpu);
+
+    serial_mm_init(get_system_memory(), 0x90000000, 0, cpu->env.irq[2],
+                   115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
+
+    if (nd_table[0].used) {
+        openrisc_sim_net_init(get_system_memory(), 0x92000000,
+                              0x92000400, cpu->env.irq[4], nd_table);
+    }
+
+    cpu_openrisc_load_kernel(ram_size, kernel_filename, cpu);
+}
+
+static QEMUMachine openrisc_sim_machine = {
+    .name = "or32-sim",
+    .desc = "or32 simulation",
+    .init = openrisc_sim_init,
+    .max_cpus = 1,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void openrisc_sim_machine_init(void)
+{
+    qemu_register_machine(&openrisc_sim_machine);
+}
+
+machine_init(openrisc_sim_machine_init);
diff --git a/hw/openrisc/pic_cpu.c b/hw/openrisc/pic_cpu.c
new file mode 100644 (file)
index 0000000..931511e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * OpenRISC Programmable Interrupt Controller support.
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *                         Feng Gao <gf91597@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "cpu.h"
+
+/* OpenRISC pic handler */
+static void openrisc_pic_cpu_handler(void *opaque, int irq, int level)
+{
+    OpenRISCCPU *cpu = (OpenRISCCPU *)opaque;
+    int i;
+    uint32_t irq_bit = 1 << irq;
+
+    if (irq > 31 || irq < 0) {
+        return;
+    }
+
+    if (level) {
+        cpu->env.picsr |= irq_bit;
+    } else {
+        cpu->env.picsr &= ~irq_bit;
+    }
+
+    for (i = 0; i < 32; i++) {
+        if ((cpu->env.picsr && (1 << i)) && (cpu->env.picmr && (1 << i))) {
+            cpu_interrupt(&cpu->env, CPU_INTERRUPT_HARD);
+        } else {
+            cpu_reset_interrupt(&cpu->env, CPU_INTERRUPT_HARD);
+            cpu->env.picsr &= ~(1 << i);
+        }
+    }
+}
+
+void cpu_openrisc_pic_init(OpenRISCCPU *cpu)
+{
+    int i;
+    qemu_irq *qi;
+    qi = qemu_allocate_irqs(openrisc_pic_cpu_handler, cpu, NR_IRQS);
+
+    for (i = 0; i < NR_IRQS; i++) {
+        cpu->env.irq[i] = qi[i];
+    }
+}
diff --git a/hw/openrisc_pic.c b/hw/openrisc_pic.c
deleted file mode 100644 (file)
index 931511e..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * OpenRISC Programmable Interrupt Controller support.
- *
- * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- *                         Feng Gao <gf91597@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/hw.h"
-#include "cpu.h"
-
-/* OpenRISC pic handler */
-static void openrisc_pic_cpu_handler(void *opaque, int irq, int level)
-{
-    OpenRISCCPU *cpu = (OpenRISCCPU *)opaque;
-    int i;
-    uint32_t irq_bit = 1 << irq;
-
-    if (irq > 31 || irq < 0) {
-        return;
-    }
-
-    if (level) {
-        cpu->env.picsr |= irq_bit;
-    } else {
-        cpu->env.picsr &= ~irq_bit;
-    }
-
-    for (i = 0; i < 32; i++) {
-        if ((cpu->env.picsr && (1 << i)) && (cpu->env.picmr && (1 << i))) {
-            cpu_interrupt(&cpu->env, CPU_INTERRUPT_HARD);
-        } else {
-            cpu_reset_interrupt(&cpu->env, CPU_INTERRUPT_HARD);
-            cpu->env.picsr &= ~(1 << i);
-        }
-    }
-}
-
-void cpu_openrisc_pic_init(OpenRISCCPU *cpu)
-{
-    int i;
-    qemu_irq *qi;
-    qi = qemu_allocate_irqs(openrisc_pic_cpu_handler, cpu, NR_IRQS);
-
-    for (i = 0; i < NR_IRQS; i++) {
-        cpu->env.irq[i] = qi[i];
-    }
-}
diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c
deleted file mode 100644 (file)
index db2aac8..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * OpenRISC simulator for use as an IIS.
- *
- * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- *                         Feng Gao <gf91597@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/hw.h"
-#include "hw/boards.h"
-#include "elf.h"
-#include "hw/serial.h"
-#include "net/net.h"
-#include "hw/loader.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "sysemu/qtest.h"
-
-#define KERNEL_LOAD_ADDR 0x100
-
-static void main_cpu_reset(void *opaque)
-{
-    OpenRISCCPU *cpu = opaque;
-
-    cpu_reset(CPU(cpu));
-}
-
-static void openrisc_sim_net_init(MemoryRegion *address_space,
-                                  hwaddr base,
-                                  hwaddr descriptors,
-                                  qemu_irq irq, NICInfo *nd)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "open_eth");
-    qdev_set_nic_properties(dev, nd);
-    qdev_init_nofail(dev);
-
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(s, 0, irq);
-    memory_region_add_subregion(address_space, base,
-                                sysbus_mmio_get_region(s, 0));
-    memory_region_add_subregion(address_space, descriptors,
-                                sysbus_mmio_get_region(s, 1));
-}
-
-static void cpu_openrisc_load_kernel(ram_addr_t ram_size,
-                                     const char *kernel_filename,
-                                     OpenRISCCPU *cpu)
-{
-    long kernel_size;
-    uint64_t elf_entry;
-    hwaddr entry;
-
-    if (kernel_filename && !qtest_enabled()) {
-        kernel_size = load_elf(kernel_filename, NULL, NULL,
-                               &elf_entry, NULL, NULL, 1, ELF_MACHINE, 1);
-        entry = elf_entry;
-        if (kernel_size < 0) {
-            kernel_size = load_uimage(kernel_filename,
-                                      &entry, NULL, NULL);
-        }
-        if (kernel_size < 0) {
-            kernel_size = load_image_targphys(kernel_filename,
-                                              KERNEL_LOAD_ADDR,
-                                              ram_size - KERNEL_LOAD_ADDR);
-            entry = KERNEL_LOAD_ADDR;
-        }
-
-        if (kernel_size < 0) {
-            qemu_log("QEMU: couldn't load the kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-    }
-
-    cpu->env.pc = entry;
-}
-
-static void openrisc_sim_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-   OpenRISCCPU *cpu = NULL;
-    MemoryRegion *ram;
-    int n;
-
-    if (!cpu_model) {
-        cpu_model = "or1200";
-    }
-
-    for (n = 0; n < smp_cpus; n++) {
-        cpu = cpu_openrisc_init(cpu_model);
-        if (cpu == NULL) {
-            qemu_log("Unable to find CPU definition!\n");
-            exit(1);
-        }
-        qemu_register_reset(main_cpu_reset, cpu);
-        main_cpu_reset(cpu);
-    }
-
-    ram = g_malloc(sizeof(*ram));
-    memory_region_init_ram(ram, "openrisc.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(get_system_memory(), 0, ram);
-
-    cpu_openrisc_pic_init(cpu);
-    cpu_openrisc_clock_init(cpu);
-
-    serial_mm_init(get_system_memory(), 0x90000000, 0, cpu->env.irq[2],
-                   115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
-
-    if (nd_table[0].used) {
-        openrisc_sim_net_init(get_system_memory(), 0x92000000,
-                              0x92000400, cpu->env.irq[4], nd_table);
-    }
-
-    cpu_openrisc_load_kernel(ram_size, kernel_filename, cpu);
-}
-
-static QEMUMachine openrisc_sim_machine = {
-    .name = "or32-sim",
-    .desc = "or32 simulation",
-    .init = openrisc_sim_init,
-    .max_cpus = 1,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void openrisc_sim_machine_init(void)
-{
-    qemu_register_machine(&openrisc_sim_machine);
-}
-
-machine_init(openrisc_sim_machine_init);
diff --git a/hw/openrisc_timer.c b/hw/openrisc_timer.c
deleted file mode 100644 (file)
index f6c877f..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * QEMU OpenRISC timer support
- *
- * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- *                         Zhizhou Zhang <etouzh@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "cpu.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-
-#define TIMER_FREQ    (20 * 1000 * 1000)    /* 20MHz */
-
-/* The time when TTCR changes */
-static uint64_t last_clk;
-static int is_counting;
-
-void cpu_openrisc_count_update(OpenRISCCPU *cpu)
-{
-    uint64_t now, next;
-    uint32_t wait;
-
-    now = qemu_get_clock_ns(vm_clock);
-    if (!is_counting) {
-        qemu_del_timer(cpu->env.timer);
-        last_clk = now;
-        return;
-    }
-
-    cpu->env.ttcr += (uint32_t)muldiv64(now - last_clk, TIMER_FREQ,
-                                        get_ticks_per_sec());
-    last_clk = now;
-
-    if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) {
-        wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1;
-        wait += cpu->env.ttmr & TTMR_TP;
-    } else {
-        wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP);
-    }
-
-    next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
-    qemu_mod_timer(cpu->env.timer, next);
-}
-
-void cpu_openrisc_count_start(OpenRISCCPU *cpu)
-{
-    is_counting = 1;
-    cpu_openrisc_count_update(cpu);
-}
-
-void cpu_openrisc_count_stop(OpenRISCCPU *cpu)
-{
-    is_counting = 0;
-    cpu_openrisc_count_update(cpu);
-}
-
-static void openrisc_timer_cb(void *opaque)
-{
-    OpenRISCCPU *cpu = opaque;
-
-    if ((cpu->env.ttmr & TTMR_IE) &&
-         qemu_timer_expired(cpu->env.timer, qemu_get_clock_ns(vm_clock))) {
-        cpu->env.ttmr |= TTMR_IP;
-        cpu->env.interrupt_request |= CPU_INTERRUPT_TIMER;
-    }
-
-    switch (cpu->env.ttmr & TTMR_M) {
-    case TIMER_NONE:
-        break;
-    case TIMER_INTR:
-        cpu->env.ttcr = 0;
-        cpu_openrisc_count_start(cpu);
-        break;
-    case TIMER_SHOT:
-        cpu_openrisc_count_stop(cpu);
-        break;
-    case TIMER_CONT:
-        cpu_openrisc_count_start(cpu);
-        break;
-    }
-}
-
-void cpu_openrisc_clock_init(OpenRISCCPU *cpu)
-{
-    cpu->env.timer = qemu_new_timer_ns(vm_clock, &openrisc_timer_cb, cpu);
-    cpu->env.ttmr = 0x00000000;
-    cpu->env.ttcr = 0x00000000;
-}
diff --git a/hw/palm.c b/hw/palm.c
deleted file mode 100644 (file)
index 91bc74a..0000000
--- a/hw/palm.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * PalmOne's (TM) PDAs.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "hw/hw.h"
-#include "audio/audio.h"
-#include "sysemu/sysemu.h"
-#include "ui/console.h"
-#include "hw/omap.h"
-#include "hw/boards.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
-#include "hw/loader.h"
-#include "exec/address-spaces.h"
-
-static uint32_t static_readb(void *opaque, hwaddr offset)
-{
-    uint32_t *val = (uint32_t *) opaque;
-    return *val >> ((offset & 3) << 3);
-}
-
-static uint32_t static_readh(void *opaque, hwaddr offset)
-{
-    uint32_t *val = (uint32_t *) opaque;
-    return *val >> ((offset & 1) << 3);
-}
-
-static uint32_t static_readw(void *opaque, hwaddr offset)
-{
-    uint32_t *val = (uint32_t *) opaque;
-    return *val >> ((offset & 0) << 3);
-}
-
-static void static_write(void *opaque, hwaddr offset,
-                uint32_t value)
-{
-#ifdef SPY
-    printf("%s: value %08lx written at " PA_FMT "\n",
-                    __FUNCTION__, value, offset);
-#endif
-}
-
-static const MemoryRegionOps static_ops = {
-    .old_mmio = {
-        .read = { static_readb, static_readh, static_readw, },
-        .write = { static_write, static_write, static_write, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* Palm Tunsgten|E support */
-
-/* Shared GPIOs */
-#define PALMTE_USBDETECT_GPIO  0
-#define PALMTE_USB_OR_DC_GPIO  1
-#define PALMTE_TSC_GPIO                4
-#define PALMTE_PINTDAV_GPIO    6
-#define PALMTE_MMC_WP_GPIO     8
-#define PALMTE_MMC_POWER_GPIO  9
-#define PALMTE_HDQ_GPIO                11
-#define PALMTE_HEADPHONES_GPIO 14
-#define PALMTE_SPEAKER_GPIO    15
-/* MPU private GPIOs */
-#define PALMTE_DC_GPIO         2
-#define PALMTE_MMC_SWITCH_GPIO 4
-#define PALMTE_MMC1_GPIO       6
-#define PALMTE_MMC2_GPIO       7
-#define PALMTE_MMC3_GPIO       11
-
-static MouseTransformInfo palmte_pointercal = {
-    .x = 320,
-    .y = 320,
-    .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 },
-};
-
-static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
-{
-    uWireSlave *tsc;
-
-    tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO));
-
-    omap_uwire_attach(cpu->microwire, tsc, 0);
-    omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
-
-    tsc210x_set_transform(tsc, &palmte_pointercal);
-}
-
-static struct {
-    int row;
-    int column;
-} palmte_keymap[0x80] = {
-    [0 ... 0x7f] = { -1, -1 },
-    [0x3b] = { 0, 0 }, /* F1   -> Calendar */
-    [0x3c] = { 1, 0 }, /* F2   -> Contacts */
-    [0x3d] = { 2, 0 }, /* F3   -> Tasks List */
-    [0x3e] = { 3, 0 }, /* F4   -> Note Pad */
-    [0x01] = { 4, 0 }, /* Esc  -> Power */
-    [0x4b] = { 0, 1 }, /*         Left */
-    [0x50] = { 1, 1 }, /*         Down */
-    [0x48] = { 2, 1 }, /*         Up */
-    [0x4d] = { 3, 1 }, /*         Right */
-    [0x4c] = { 4, 1 }, /*         Centre */
-    [0x39] = { 4, 1 }, /* Spc  -> Centre */
-};
-
-static void palmte_button_event(void *opaque, int keycode)
-{
-    struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque;
-
-    if (palmte_keymap[keycode & 0x7f].row != -1)
-        omap_mpuio_key(cpu->mpuio,
-                        palmte_keymap[keycode & 0x7f].row,
-                        palmte_keymap[keycode & 0x7f].column,
-                        !(keycode & 0x80));
-}
-
-static void palmte_onoff_gpios(void *opaque, int line, int level)
-{
-    switch (line) {
-    case 0:
-        printf("%s: current to MMC/SD card %sabled.\n",
-                        __FUNCTION__, level ? "dis" : "en");
-        break;
-    case 1:
-        printf("%s: internal speaker amplifier %s.\n",
-                        __FUNCTION__, level ? "down" : "on");
-        break;
-
-    /* These LCD & Audio output signals have not been identified yet.  */
-    case 2:
-    case 3:
-    case 4:
-        printf("%s: LCD GPIO%i %s.\n",
-                        __FUNCTION__, line - 1, level ? "high" : "low");
-        break;
-    case 5:
-    case 6:
-        printf("%s: Audio GPIO%i %s.\n",
-                        __FUNCTION__, line - 4, level ? "high" : "low");
-        break;
-    }
-}
-
-static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
-{
-    qemu_irq *misc_gpio;
-
-    omap_mmc_handlers(cpu->mmc,
-                    qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO),
-                    qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
-                            [PALMTE_MMC_SWITCH_GPIO]));
-
-    misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7);
-    qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO,    misc_gpio[0]);
-    qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO,      misc_gpio[1]);
-    qdev_connect_gpio_out(cpu->gpio, 11,                       misc_gpio[2]);
-    qdev_connect_gpio_out(cpu->gpio, 12,                       misc_gpio[3]);
-    qdev_connect_gpio_out(cpu->gpio, 13,                       misc_gpio[4]);
-    omap_mpuio_out_set(cpu->mpuio, 1,                          misc_gpio[5]);
-    omap_mpuio_out_set(cpu->mpuio, 3,                          misc_gpio[6]);
-
-    /* Reset some inputs to initial state.  */
-    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO));
-    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO));
-    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4));
-    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO));
-    qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
-    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
-    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
-    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]);
-}
-
-static struct arm_boot_info palmte_binfo = {
-    .loader_start = OMAP_EMIFF_BASE,
-    .ram_size = 0x02000000,
-    .board_id = 0x331,
-};
-
-static void palmte_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    MemoryRegion *address_space_mem = get_system_memory();
-    struct omap_mpu_state_s *mpu;
-    int flash_size = 0x00800000;
-    int sdram_size = palmte_binfo.ram_size;
-    static uint32_t cs0val = 0xffffffff;
-    static uint32_t cs1val = 0x0000e1a0;
-    static uint32_t cs2val = 0x0000e1a0;
-    static uint32_t cs3val = 0xe1a0e1a0;
-    int rom_size, rom_loaded = 0;
-    DisplayState *ds = get_displaystate();
-    MemoryRegion *flash = g_new(MemoryRegion, 1);
-    MemoryRegion *cs = g_new(MemoryRegion, 4);
-
-    mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model);
-
-    /* External Flash (EMIFS) */
-    memory_region_init_ram(flash, "palmte.flash", flash_size);
-    vmstate_register_ram_global(flash);
-    memory_region_set_readonly(flash, true);
-    memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);
-
-    memory_region_init_io(&cs[0], &static_ops, &cs0val, "palmte-cs0",
-                          OMAP_CS0_SIZE - flash_size);
-    memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size,
-                                &cs[0]);
-    memory_region_init_io(&cs[1], &static_ops, &cs1val, "palmte-cs1",
-                          OMAP_CS1_SIZE);
-    memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]);
-    memory_region_init_io(&cs[2], &static_ops, &cs2val, "palmte-cs2",
-                          OMAP_CS2_SIZE);
-    memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]);
-    memory_region_init_io(&cs[3], &static_ops, &cs3val, "palmte-cs3",
-                          OMAP_CS3_SIZE);
-    memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]);
-
-    palmte_microwire_setup(mpu);
-
-    qemu_add_kbd_event_handler(palmte_button_event, mpu);
-
-    palmte_gpio_setup(mpu);
-
-    /* Setup initial (reset) machine state */
-    if (nb_option_roms) {
-        rom_size = get_image_size(option_rom[0].name);
-        if (rom_size > flash_size) {
-            fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
-                            __FUNCTION__, rom_size, flash_size);
-            rom_size = 0;
-        }
-        if (rom_size > 0) {
-            rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE,
-                                           flash_size);
-            rom_loaded = 1;
-        }
-        if (rom_size < 0) {
-            fprintf(stderr, "%s: error loading '%s'\n",
-                            __FUNCTION__, option_rom[0].name);
-        }
-    }
-
-    if (!rom_loaded && !kernel_filename) {
-        fprintf(stderr, "Kernel or ROM image must be specified\n");
-        exit(1);
-    }
-
-    /* Load the kernel.  */
-    if (kernel_filename) {
-        palmte_binfo.kernel_filename = kernel_filename;
-        palmte_binfo.kernel_cmdline = kernel_cmdline;
-        palmte_binfo.initrd_filename = initrd_filename;
-        arm_load_kernel(mpu->cpu, &palmte_binfo);
-    }
-
-    /* FIXME: We shouldn't really be doing this here.  The LCD controller
-       will set the size once configured, so this just sets an initial
-       size until the guest activates the display.  */
-    ds->surface = qemu_resize_displaysurface(ds, 320, 320);
-    dpy_gfx_resize(ds);
-}
-
-static QEMUMachine palmte_machine = {
-    .name = "cheetah",
-    .desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)",
-    .init = palmte_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void palmte_machine_init(void)
-{
-    qemu_register_machine(&palmte_machine);
-}
-
-machine_init(palmte_machine_init);
diff --git a/hw/pc.c b/hw/pc.c
deleted file mode 100644 (file)
index 309bb83..0000000
--- a/hw/pc.c
+++ /dev/null
@@ -1,1161 +0,0 @@
-/*
- * QEMU PC System Emulator
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/apic.h"
-#include "hw/fdc.h"
-#include "hw/ide.h"
-#include "hw/pci/pci.h"
-#include "monitor/monitor.h"
-#include "hw/fw_cfg.h"
-#include "hw/hpet_emul.h"
-#include "hw/smbios.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/multiboot.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
-#include "hw/pcspk.h"
-#include "hw/pci/msi.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
-#include "kvm_i386.h"
-#include "hw/xen.h"
-#include "sysemu/blockdev.h"
-#include "hw/block-common.h"
-#include "ui/qemu-spice.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "sysemu/arch_init.h"
-#include "qemu/bitmap.h"
-
-/* debug PC/ISA interrupts */
-//#define DEBUG_IRQ
-
-#ifdef DEBUG_IRQ
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
-#define ACPI_DATA_SIZE       0x10000
-#define BIOS_CFG_IOPORT 0x510
-#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
-#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
-#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
-#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
-#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
-
-#define E820_NR_ENTRIES                16
-
-struct e820_entry {
-    uint64_t address;
-    uint64_t length;
-    uint32_t type;
-} QEMU_PACKED __attribute((__aligned__(4)));
-
-struct e820_table {
-    uint32_t count;
-    struct e820_entry entry[E820_NR_ENTRIES];
-} QEMU_PACKED __attribute((__aligned__(4)));
-
-static struct e820_table e820_table;
-struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
-
-void gsi_handler(void *opaque, int n, int level)
-{
-    GSIState *s = opaque;
-
-    DPRINTF("pc: %s GSI %d\n", level ? "raising" : "lowering", n);
-    if (n < ISA_NUM_IRQS) {
-        qemu_set_irq(s->i8259_irq[n], level);
-    }
-    qemu_set_irq(s->ioapic_irq[n], level);
-}
-
-static void ioport80_write(void *opaque, hwaddr addr, uint64_t data,
-                           unsigned size)
-{
-}
-
-static uint64_t ioport80_read(void *opaque, hwaddr addr, unsigned size)
-{
-    return 0xffffffffffffffffULL;
-}
-
-/* MSDOS compatibility mode FPU exception support */
-static qemu_irq ferr_irq;
-
-void pc_register_ferr_irq(qemu_irq irq)
-{
-    ferr_irq = irq;
-}
-
-/* XXX: add IGNNE support */
-void cpu_set_ferr(CPUX86State *s)
-{
-    qemu_irq_raise(ferr_irq);
-}
-
-static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data,
-                           unsigned size)
-{
-    qemu_irq_lower(ferr_irq);
-}
-
-static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size)
-{
-    return 0xffffffffffffffffULL;
-}
-
-/* TSC handling */
-uint64_t cpu_get_tsc(CPUX86State *env)
-{
-    return cpu_get_ticks();
-}
-
-/* SMM support */
-
-static cpu_set_smm_t smm_set;
-static void *smm_arg;
-
-void cpu_smm_register(cpu_set_smm_t callback, void *arg)
-{
-    assert(smm_set == NULL);
-    assert(smm_arg == NULL);
-    smm_set = callback;
-    smm_arg = arg;
-}
-
-void cpu_smm_update(CPUX86State *env)
-{
-    if (smm_set && smm_arg && env == first_cpu)
-        smm_set(!!(env->hflags & HF_SMM_MASK), smm_arg);
-}
-
-
-/* IRQ handling */
-int cpu_get_pic_interrupt(CPUX86State *env)
-{
-    int intno;
-
-    intno = apic_get_interrupt(env->apic_state);
-    if (intno >= 0) {
-        return intno;
-    }
-    /* read the irq from the PIC */
-    if (!apic_accept_pic_intr(env->apic_state)) {
-        return -1;
-    }
-
-    intno = pic_read_irq(isa_pic);
-    return intno;
-}
-
-static void pic_irq_request(void *opaque, int irq, int level)
-{
-    CPUX86State *env = first_cpu;
-
-    DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq);
-    if (env->apic_state) {
-        while (env) {
-            if (apic_accept_pic_intr(env->apic_state)) {
-                apic_deliver_pic_intr(env->apic_state, level);
-            }
-            env = env->next_cpu;
-        }
-    } else {
-        if (level)
-            cpu_interrupt(env, CPU_INTERRUPT_HARD);
-        else
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
-}
-
-/* PC cmos mappings */
-
-#define REG_EQUIPMENT_BYTE          0x14
-
-static int cmos_get_fd_drive_type(FDriveType fd0)
-{
-    int val;
-
-    switch (fd0) {
-    case FDRIVE_DRV_144:
-        /* 1.44 Mb 3"5 drive */
-        val = 4;
-        break;
-    case FDRIVE_DRV_288:
-        /* 2.88 Mb 3"5 drive */
-        val = 5;
-        break;
-    case FDRIVE_DRV_120:
-        /* 1.2 Mb 5"5 drive */
-        val = 2;
-        break;
-    case FDRIVE_DRV_NONE:
-    default:
-        val = 0;
-        break;
-    }
-    return val;
-}
-
-static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs,
-                         int16_t cylinders, int8_t heads, int8_t sectors)
-{
-    rtc_set_memory(s, type_ofs, 47);
-    rtc_set_memory(s, info_ofs, cylinders);
-    rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
-    rtc_set_memory(s, info_ofs + 2, heads);
-    rtc_set_memory(s, info_ofs + 3, 0xff);
-    rtc_set_memory(s, info_ofs + 4, 0xff);
-    rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
-    rtc_set_memory(s, info_ofs + 6, cylinders);
-    rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
-    rtc_set_memory(s, info_ofs + 8, sectors);
-}
-
-/* convert boot_device letter to something recognizable by the bios */
-static int boot_device2nibble(char boot_device)
-{
-    switch(boot_device) {
-    case 'a':
-    case 'b':
-        return 0x01; /* floppy boot */
-    case 'c':
-        return 0x02; /* hard drive boot */
-    case 'd':
-        return 0x03; /* CD-ROM boot */
-    case 'n':
-        return 0x04; /* Network boot */
-    }
-    return 0;
-}
-
-static int set_boot_dev(ISADevice *s, const char *boot_device, int fd_bootchk)
-{
-#define PC_MAX_BOOT_DEVICES 3
-    int nbds, bds[3] = { 0, };
-    int i;
-
-    nbds = strlen(boot_device);
-    if (nbds > PC_MAX_BOOT_DEVICES) {
-        error_report("Too many boot devices for PC");
-        return(1);
-    }
-    for (i = 0; i < nbds; i++) {
-        bds[i] = boot_device2nibble(boot_device[i]);
-        if (bds[i] == 0) {
-            error_report("Invalid boot device for PC: '%c'",
-                         boot_device[i]);
-            return(1);
-        }
-    }
-    rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
-    rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1));
-    return(0);
-}
-
-static int pc_boot_set(void *opaque, const char *boot_device)
-{
-    return set_boot_dev(opaque, boot_device, 0);
-}
-
-typedef struct pc_cmos_init_late_arg {
-    ISADevice *rtc_state;
-    BusState *idebus[2];
-} pc_cmos_init_late_arg;
-
-static void pc_cmos_init_late(void *opaque)
-{
-    pc_cmos_init_late_arg *arg = opaque;
-    ISADevice *s = arg->rtc_state;
-    int16_t cylinders;
-    int8_t heads, sectors;
-    int val;
-    int i, trans;
-
-    val = 0;
-    if (ide_get_geometry(arg->idebus[0], 0,
-                         &cylinders, &heads, &sectors) >= 0) {
-        cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors);
-        val |= 0xf0;
-    }
-    if (ide_get_geometry(arg->idebus[0], 1,
-                         &cylinders, &heads, &sectors) >= 0) {
-        cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors);
-        val |= 0x0f;
-    }
-    rtc_set_memory(s, 0x12, val);
-
-    val = 0;
-    for (i = 0; i < 4; i++) {
-        /* NOTE: ide_get_geometry() returns the physical
-           geometry.  It is always such that: 1 <= sects <= 63, 1
-           <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
-           geometry can be different if a translation is done. */
-        if (ide_get_geometry(arg->idebus[i / 2], i % 2,
-                             &cylinders, &heads, &sectors) >= 0) {
-            trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1;
-            assert((trans & ~3) == 0);
-            val |= trans << (i * 2);
-        }
-    }
-    rtc_set_memory(s, 0x39, val);
-
-    qemu_unregister_reset(pc_cmos_init_late, opaque);
-}
-
-void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
-                  const char *boot_device,
-                  ISADevice *floppy, BusState *idebus0, BusState *idebus1,
-                  ISADevice *s)
-{
-    int val, nb, i;
-    FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
-    static pc_cmos_init_late_arg arg;
-
-    /* various important CMOS locations needed by PC/Bochs bios */
-
-    /* memory size */
-    /* base memory (first MiB) */
-    val = MIN(ram_size / 1024, 640);
-    rtc_set_memory(s, 0x15, val);
-    rtc_set_memory(s, 0x16, val >> 8);
-    /* extended memory (next 64MiB) */
-    if (ram_size > 1024 * 1024) {
-        val = (ram_size - 1024 * 1024) / 1024;
-    } else {
-        val = 0;
-    }
-    if (val > 65535)
-        val = 65535;
-    rtc_set_memory(s, 0x17, val);
-    rtc_set_memory(s, 0x18, val >> 8);
-    rtc_set_memory(s, 0x30, val);
-    rtc_set_memory(s, 0x31, val >> 8);
-    /* memory between 16MiB and 4GiB */
-    if (ram_size > 16 * 1024 * 1024) {
-        val = (ram_size - 16 * 1024 * 1024) / 65536;
-    } else {
-        val = 0;
-    }
-    if (val > 65535)
-        val = 65535;
-    rtc_set_memory(s, 0x34, val);
-    rtc_set_memory(s, 0x35, val >> 8);
-    /* memory above 4GiB */
-    val = above_4g_mem_size / 65536;
-    rtc_set_memory(s, 0x5b, val);
-    rtc_set_memory(s, 0x5c, val >> 8);
-    rtc_set_memory(s, 0x5d, val >> 16);
-
-    /* set the number of CPU */
-    rtc_set_memory(s, 0x5f, smp_cpus - 1);
-
-    /* set boot devices, and disable floppy signature check if requested */
-    if (set_boot_dev(s, boot_device, fd_bootchk)) {
-        exit(1);
-    }
-
-    /* floppy type */
-    if (floppy) {
-        for (i = 0; i < 2; i++) {
-            fd_type[i] = isa_fdc_get_drive_type(floppy, i);
-        }
-    }
-    val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
-        cmos_get_fd_drive_type(fd_type[1]);
-    rtc_set_memory(s, 0x10, val);
-
-    val = 0;
-    nb = 0;
-    if (fd_type[0] < FDRIVE_DRV_NONE) {
-        nb++;
-    }
-    if (fd_type[1] < FDRIVE_DRV_NONE) {
-        nb++;
-    }
-    switch (nb) {
-    case 0:
-        break;
-    case 1:
-        val |= 0x01; /* 1 drive, ready for boot */
-        break;
-    case 2:
-        val |= 0x41; /* 2 drives, ready for boot */
-        break;
-    }
-    val |= 0x02; /* FPU is there */
-    val |= 0x04; /* PS/2 mouse installed */
-    rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
-
-    /* hard drives */
-    arg.rtc_state = s;
-    arg.idebus[0] = idebus0;
-    arg.idebus[1] = idebus1;
-    qemu_register_reset(pc_cmos_init_late, &arg);
-}
-
-/* port 92 stuff: could be split off */
-typedef struct Port92State {
-    ISADevice dev;
-    MemoryRegion io;
-    uint8_t outport;
-    qemu_irq *a20_out;
-} Port92State;
-
-static void port92_write(void *opaque, hwaddr addr, uint64_t val,
-                         unsigned size)
-{
-    Port92State *s = opaque;
-
-    DPRINTF("port92: write 0x%02x\n", val);
-    s->outport = val;
-    qemu_set_irq(*s->a20_out, (val >> 1) & 1);
-    if (val & 1) {
-        qemu_system_reset_request();
-    }
-}
-
-static uint64_t port92_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    Port92State *s = opaque;
-    uint32_t ret;
-
-    ret = s->outport;
-    DPRINTF("port92: read 0x%02x\n", ret);
-    return ret;
-}
-
-static void port92_init(ISADevice *dev, qemu_irq *a20_out)
-{
-    Port92State *s = DO_UPCAST(Port92State, dev, dev);
-
-    s->a20_out = a20_out;
-}
-
-static const VMStateDescription vmstate_port92_isa = {
-    .name = "port92",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8(outport, Port92State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void port92_reset(DeviceState *d)
-{
-    Port92State *s = container_of(d, Port92State, dev.qdev);
-
-    s->outport &= ~1;
-}
-
-static const MemoryRegionOps port92_ops = {
-    .read = port92_read,
-    .write = port92_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int port92_initfn(ISADevice *dev)
-{
-    Port92State *s = DO_UPCAST(Port92State, dev, dev);
-
-    memory_region_init_io(&s->io, &port92_ops, s, "port92", 1);
-    isa_register_ioport(dev, &s->io, 0x92);
-
-    s->outport = 0;
-    return 0;
-}
-
-static void port92_class_initfn(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
-    ic->init = port92_initfn;
-    dc->no_user = 1;
-    dc->reset = port92_reset;
-    dc->vmsd = &vmstate_port92_isa;
-}
-
-static const TypeInfo port92_info = {
-    .name          = "port92",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(Port92State),
-    .class_init    = port92_class_initfn,
-};
-
-static void port92_register_types(void)
-{
-    type_register_static(&port92_info);
-}
-
-type_init(port92_register_types)
-
-static void handle_a20_line_change(void *opaque, int irq, int level)
-{
-    X86CPU *cpu = opaque;
-
-    /* XXX: send to all CPUs ? */
-    /* XXX: add logic to handle multiple A20 line sources */
-    x86_cpu_set_a20(cpu, level);
-}
-
-int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
-{
-    int index = le32_to_cpu(e820_table.count);
-    struct e820_entry *entry;
-
-    if (index >= E820_NR_ENTRIES)
-        return -EBUSY;
-    entry = &e820_table.entry[index++];
-
-    entry->address = cpu_to_le64(address);
-    entry->length = cpu_to_le64(length);
-    entry->type = cpu_to_le32(type);
-
-    e820_table.count = cpu_to_le32(index);
-    return index;
-}
-
-/* Calculates the limit to CPU APIC ID values
- *
- * This function returns the limit for the APIC ID value, so that all
- * CPU APIC IDs are < pc_apic_id_limit().
- *
- * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init().
- */
-static unsigned int pc_apic_id_limit(unsigned int max_cpus)
-{
-    return x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
-}
-
-static void *bochs_bios_init(void)
-{
-    void *fw_cfg;
-    uint8_t *smbios_table;
-    size_t smbios_len;
-    uint64_t *numa_fw_cfg;
-    int i, j;
-    unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
-
-    fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
-    /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
-     *
-     * SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug
-     * QEMU<->SeaBIOS interface is not based on the "CPU index", but on the APIC
-     * ID of hotplugged CPUs[1]. This means that FW_CFG_MAX_CPUS is not the
-     * "maximum number of CPUs", but the "limit to the APIC ID values SeaBIOS
-     * may see".
-     *
-     * So, this means we must not use max_cpus, here, but the maximum possible
-     * APIC ID value, plus one.
-     *
-     * [1] The only kind of "CPU identifier" used between SeaBIOS and QEMU is
-     *     the APIC ID, not the "CPU index"
-     */
-    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)apic_id_limit);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
-    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES,
-                     acpi_tables, acpi_tables_len);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
-
-    smbios_table = smbios_get_table(&smbios_len);
-    if (smbios_table)
-        fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
-                         smbios_table, smbios_len);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
-                     &e820_table, sizeof(e820_table));
-
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_cfg, sizeof(hpet_cfg));
-    /* allocate memory for the NUMA channel: one (64bit) word for the number
-     * of nodes, one word for each VCPU->node and one word for each node to
-     * hold the amount of memory.
-     */
-    numa_fw_cfg = g_new0(uint64_t, 1 + apic_id_limit + nb_numa_nodes);
-    numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes);
-    for (i = 0; i < max_cpus; i++) {
-        unsigned int apic_id = x86_cpu_apic_id_from_index(i);
-        assert(apic_id < apic_id_limit);
-        for (j = 0; j < nb_numa_nodes; j++) {
-            if (test_bit(i, node_cpumask[j])) {
-                numa_fw_cfg[apic_id + 1] = cpu_to_le64(j);
-                break;
-            }
-        }
-    }
-    for (i = 0; i < nb_numa_nodes; i++) {
-        numa_fw_cfg[apic_id_limit + 1 + i] = cpu_to_le64(node_mem[i]);
-    }
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg,
-                     (1 + apic_id_limit + nb_numa_nodes) *
-                     sizeof(*numa_fw_cfg));
-
-    return fw_cfg;
-}
-
-static long get_file_size(FILE *f)
-{
-    long where, size;
-
-    /* XXX: on Unix systems, using fstat() probably makes more sense */
-
-    where = ftell(f);
-    fseek(f, 0, SEEK_END);
-    size = ftell(f);
-    fseek(f, where, SEEK_SET);
-
-    return size;
-}
-
-static void load_linux(void *fw_cfg,
-                       const char *kernel_filename,
-                      const char *initrd_filename,
-                      const char *kernel_cmdline,
-                       hwaddr max_ram_size)
-{
-    uint16_t protocol;
-    int setup_size, kernel_size, initrd_size = 0, cmdline_size;
-    uint32_t initrd_max;
-    uint8_t header[8192], *setup, *kernel, *initrd_data;
-    hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0;
-    FILE *f;
-    char *vmode;
-
-    /* Align to 16 bytes as a paranoia measure */
-    cmdline_size = (strlen(kernel_cmdline)+16) & ~15;
-
-    /* load the kernel header */
-    f = fopen(kernel_filename, "rb");
-    if (!f || !(kernel_size = get_file_size(f)) ||
-       fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) !=
-       MIN(ARRAY_SIZE(header), kernel_size)) {
-       fprintf(stderr, "qemu: could not load kernel '%s': %s\n",
-               kernel_filename, strerror(errno));
-       exit(1);
-    }
-
-    /* kernel protocol version */
-#if 0
-    fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));
-#endif
-    if (ldl_p(header+0x202) == 0x53726448)
-       protocol = lduw_p(header+0x206);
-    else {
-       /* This looks like a multiboot kernel. If it is, let's stop
-          treating it like a Linux kernel. */
-        if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename,
-                           kernel_cmdline, kernel_size, header))
-            return;
-       protocol = 0;
-    }
-
-    if (protocol < 0x200 || !(header[0x211] & 0x01)) {
-       /* Low kernel */
-       real_addr    = 0x90000;
-       cmdline_addr = 0x9a000 - cmdline_size;
-       prot_addr    = 0x10000;
-    } else if (protocol < 0x202) {
-       /* High but ancient kernel */
-       real_addr    = 0x90000;
-       cmdline_addr = 0x9a000 - cmdline_size;
-       prot_addr    = 0x100000;
-    } else {
-       /* High and recent kernel */
-       real_addr    = 0x10000;
-       cmdline_addr = 0x20000;
-       prot_addr    = 0x100000;
-    }
-
-#if 0
-    fprintf(stderr,
-           "qemu: real_addr     = 0x" TARGET_FMT_plx "\n"
-           "qemu: cmdline_addr  = 0x" TARGET_FMT_plx "\n"
-           "qemu: prot_addr     = 0x" TARGET_FMT_plx "\n",
-           real_addr,
-           cmdline_addr,
-           prot_addr);
-#endif
-
-    /* highest address for loading the initrd */
-    if (protocol >= 0x203)
-       initrd_max = ldl_p(header+0x22c);
-    else
-       initrd_max = 0x37ffffff;
-
-    if (initrd_max >= max_ram_size-ACPI_DATA_SIZE)
-       initrd_max = max_ram_size-ACPI_DATA_SIZE-1;
-
-    fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1);
-    fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
-
-    if (protocol >= 0x202) {
-       stl_p(header+0x228, cmdline_addr);
-    } else {
-       stw_p(header+0x20, 0xA33F);
-       stw_p(header+0x22, cmdline_addr-real_addr);
-    }
-
-    /* handle vga= parameter */
-    vmode = strstr(kernel_cmdline, "vga=");
-    if (vmode) {
-        unsigned int video_mode;
-        /* skip "vga=" */
-        vmode += 4;
-        if (!strncmp(vmode, "normal", 6)) {
-            video_mode = 0xffff;
-        } else if (!strncmp(vmode, "ext", 3)) {
-            video_mode = 0xfffe;
-        } else if (!strncmp(vmode, "ask", 3)) {
-            video_mode = 0xfffd;
-        } else {
-            video_mode = strtol(vmode, NULL, 0);
-        }
-        stw_p(header+0x1fa, video_mode);
-    }
-
-    /* loader type */
-    /* High nybble = B reserved for QEMU; low nybble is revision number.
-       If this code is substantially changed, you may want to consider
-       incrementing the revision. */
-    if (protocol >= 0x200)
-       header[0x210] = 0xB0;
-
-    /* heap */
-    if (protocol >= 0x201) {
-       header[0x211] |= 0x80;  /* CAN_USE_HEAP */
-       stw_p(header+0x224, cmdline_addr-real_addr-0x200);
-    }
-
-    /* load initrd */
-    if (initrd_filename) {
-       if (protocol < 0x200) {
-           fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n");
-           exit(1);
-       }
-
-       initrd_size = get_image_size(initrd_filename);
-        if (initrd_size < 0) {
-            fprintf(stderr, "qemu: error reading initrd %s\n",
-                    initrd_filename);
-            exit(1);
-        }
-
-        initrd_addr = (initrd_max-initrd_size) & ~4095;
-
-        initrd_data = g_malloc(initrd_size);
-        load_image(initrd_filename, initrd_data);
-
-        fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
-        fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
-        fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size);
-
-       stl_p(header+0x218, initrd_addr);
-       stl_p(header+0x21c, initrd_size);
-    }
-
-    /* load kernel and setup */
-    setup_size = header[0x1f1];
-    if (setup_size == 0)
-       setup_size = 4;
-    setup_size = (setup_size+1)*512;
-    kernel_size -= setup_size;
-
-    setup  = g_malloc(setup_size);
-    kernel = g_malloc(kernel_size);
-    fseek(f, 0, SEEK_SET);
-    if (fread(setup, 1, setup_size, f) != setup_size) {
-        fprintf(stderr, "fread() failed\n");
-        exit(1);
-    }
-    if (fread(kernel, 1, kernel_size, f) != kernel_size) {
-        fprintf(stderr, "fread() failed\n");
-        exit(1);
-    }
-    fclose(f);
-    memcpy(setup, header, MIN(sizeof(header), setup_size));
-
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
-
-    fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);
-
-    option_rom[nb_option_roms].name = "linuxboot.bin";
-    option_rom[nb_option_roms].bootindex = 0;
-    nb_option_roms++;
-}
-
-#define NE2000_NB_MAX 6
-
-static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360,
-                                              0x280, 0x380 };
-static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
-
-static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
-static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
-
-void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd)
-{
-    static int nb_ne2k = 0;
-
-    if (nb_ne2k == NE2000_NB_MAX)
-        return;
-    isa_ne2000_init(bus, ne2000_io[nb_ne2k],
-                    ne2000_irq[nb_ne2k], nd);
-    nb_ne2k++;
-}
-
-DeviceState *cpu_get_current_apic(void)
-{
-    if (cpu_single_env) {
-        return cpu_single_env->apic_state;
-    } else {
-        return NULL;
-    }
-}
-
-void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
-{
-    CPUX86State *s = opaque;
-
-    if (level) {
-        cpu_interrupt(s, CPU_INTERRUPT_SMI);
-    }
-}
-
-void pc_cpus_init(const char *cpu_model)
-{
-    int i;
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-#ifdef TARGET_X86_64
-        cpu_model = "qemu64";
-#else
-        cpu_model = "qemu32";
-#endif
-    }
-
-    for (i = 0; i < smp_cpus; i++) {
-        if (!cpu_x86_init(cpu_model)) {
-            exit(1);
-        }
-    }
-}
-
-void pc_acpi_init(const char *default_dsdt)
-{
-    char *filename = NULL, *arg = NULL;
-
-    if (acpi_tables != NULL) {
-        /* manually set via -acpitable, leave it alone */
-        return;
-    }
-
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt);
-    if (filename == NULL) {
-        fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt);
-        return;
-    }
-
-    arg = g_strdup_printf("file=%s", filename);
-    if (acpi_table_add(arg) != 0) {
-        fprintf(stderr, "WARNING: failed to load %s\n", filename);
-    }
-    g_free(arg);
-    g_free(filename);
-}
-
-void *pc_memory_init(MemoryRegion *system_memory,
-                    const char *kernel_filename,
-                    const char *kernel_cmdline,
-                    const char *initrd_filename,
-                    ram_addr_t below_4g_mem_size,
-                    ram_addr_t above_4g_mem_size,
-                    MemoryRegion *rom_memory,
-                    MemoryRegion **ram_memory)
-{
-    int linux_boot, i;
-    MemoryRegion *ram, *option_rom_mr;
-    MemoryRegion *ram_below_4g, *ram_above_4g;
-    void *fw_cfg;
-
-    linux_boot = (kernel_filename != NULL);
-
-    /* Allocate RAM.  We allocate it as a single memory region and use
-     * aliases to address portions of it, mostly for backwards compatibility
-     * with older qemus that used qemu_ram_alloc().
-     */
-    ram = g_malloc(sizeof(*ram));
-    memory_region_init_ram(ram, "pc.ram",
-                           below_4g_mem_size + above_4g_mem_size);
-    vmstate_register_ram_global(ram);
-    *ram_memory = ram;
-    ram_below_4g = g_malloc(sizeof(*ram_below_4g));
-    memory_region_init_alias(ram_below_4g, "ram-below-4g", ram,
-                             0, below_4g_mem_size);
-    memory_region_add_subregion(system_memory, 0, ram_below_4g);
-    if (above_4g_mem_size > 0) {
-        ram_above_4g = g_malloc(sizeof(*ram_above_4g));
-        memory_region_init_alias(ram_above_4g, "ram-above-4g", ram,
-                                 below_4g_mem_size, above_4g_mem_size);
-        memory_region_add_subregion(system_memory, 0x100000000ULL,
-                                    ram_above_4g);
-    }
-
-
-    /* Initialize PC system firmware */
-    pc_system_firmware_init(rom_memory);
-
-    option_rom_mr = g_malloc(sizeof(*option_rom_mr));
-    memory_region_init_ram(option_rom_mr, "pc.rom", PC_ROM_SIZE);
-    vmstate_register_ram_global(option_rom_mr);
-    memory_region_add_subregion_overlap(rom_memory,
-                                        PC_ROM_MIN_VGA,
-                                        option_rom_mr,
-                                        1);
-
-    fw_cfg = bochs_bios_init();
-    rom_set_fw(fw_cfg);
-
-    if (linux_boot) {
-        load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size);
-    }
-
-    for (i = 0; i < nb_option_roms; i++) {
-        rom_add_option(option_rom[i].name, option_rom[i].bootindex);
-    }
-    return fw_cfg;
-}
-
-qemu_irq *pc_allocate_cpu_irq(void)
-{
-    return qemu_allocate_irqs(pic_irq_request, NULL, 1);
-}
-
-DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
-{
-    DeviceState *dev = NULL;
-
-    if (pci_bus) {
-        PCIDevice *pcidev = pci_vga_init(pci_bus);
-        dev = pcidev ? &pcidev->qdev : NULL;
-    } else if (isa_bus) {
-        ISADevice *isadev = isa_vga_init(isa_bus);
-        dev = isadev ? &isadev->qdev : NULL;
-    }
-    return dev;
-}
-
-static void cpu_request_exit(void *opaque, int irq, int level)
-{
-    CPUX86State *env = cpu_single_env;
-
-    if (env && level) {
-        cpu_exit(env);
-    }
-}
-
-static const MemoryRegionOps ioport80_io_ops = {
-    .write = ioport80_write,
-    .read = ioport80_read,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static const MemoryRegionOps ioportF0_io_ops = {
-    .write = ioportF0_write,
-    .read = ioportF0_read,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
-                          ISADevice **rtc_state,
-                          ISADevice **floppy,
-                          bool no_vmport)
-{
-    int i;
-    DriveInfo *fd[MAX_FD];
-    DeviceState *hpet = NULL;
-    int pit_isa_irq = 0;
-    qemu_irq pit_alt_irq = NULL;
-    qemu_irq rtc_irq = NULL;
-    qemu_irq *a20_line;
-    ISADevice *i8042, *port92, *vmmouse, *pit = NULL;
-    qemu_irq *cpu_exit_irq;
-    MemoryRegion *ioport80_io = g_new(MemoryRegion, 1);
-    MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1);
-
-    memory_region_init_io(ioport80_io, &ioport80_io_ops, NULL, "ioport80", 1);
-    memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io);
-
-    memory_region_init_io(ioportF0_io, &ioportF0_io_ops, NULL, "ioportF0", 1);
-    memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io);
-
-    /*
-     * Check if an HPET shall be created.
-     *
-     * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT
-     * when the HPET wants to take over. Thus we have to disable the latter.
-     */
-    if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) {
-        hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
-
-        if (hpet) {
-            for (i = 0; i < GSI_NUM_PINS; i++) {
-                sysbus_connect_irq(SYS_BUS_DEVICE(hpet), i, gsi[i]);
-            }
-            pit_isa_irq = -1;
-            pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT);
-            rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT);
-        }
-    }
-    *rtc_state = rtc_init(isa_bus, 2000, rtc_irq);
-
-    qemu_register_boot_set(pc_boot_set, *rtc_state);
-
-    if (!xen_enabled()) {
-        if (kvm_irqchip_in_kernel()) {
-            pit = kvm_pit_init(isa_bus, 0x40);
-        } else {
-            pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
-        }
-        if (hpet) {
-            /* connect PIT to output control line of the HPET */
-            qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
-        }
-        pcspk_init(isa_bus, pit);
-    }
-
-    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
-        if (serial_hds[i]) {
-            serial_isa_init(isa_bus, i, serial_hds[i]);
-        }
-    }
-
-    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
-        if (parallel_hds[i]) {
-            parallel_init(isa_bus, i, parallel_hds[i]);
-        }
-    }
-
-    a20_line = qemu_allocate_irqs(handle_a20_line_change,
-                                  x86_env_get_cpu(first_cpu), 2);
-    i8042 = isa_create_simple(isa_bus, "i8042");
-    i8042_setup_a20_line(i8042, &a20_line[0]);
-    if (!no_vmport) {
-        vmport_init(isa_bus);
-        vmmouse = isa_try_create(isa_bus, "vmmouse");
-    } else {
-        vmmouse = NULL;
-    }
-    if (vmmouse) {
-        qdev_prop_set_ptr(&vmmouse->qdev, "ps2_mouse", i8042);
-        qdev_init_nofail(&vmmouse->qdev);
-    }
-    port92 = isa_create_simple(isa_bus, "port92");
-    port92_init(port92, &a20_line[1]);
-
-    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
-    DMA_init(0, cpu_exit_irq);
-
-    for(i = 0; i < MAX_FD; i++) {
-        fd[i] = drive_get(IF_FLOPPY, 0, i);
-    }
-    *floppy = fdctrl_init_isa(isa_bus, fd);
-}
-
-void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
-{
-    int i;
-
-    for (i = 0; i < nb_nics; i++) {
-        NICInfo *nd = &nd_table[i];
-
-        if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) {
-            pc_init_ne2k_isa(isa_bus, nd);
-        } else {
-            pci_nic_init_nofail(nd, "e1000", NULL);
-        }
-    }
-}
-
-void pc_pci_device_init(PCIBus *pci_bus)
-{
-    int max_bus;
-    int bus;
-
-    max_bus = drive_get_max_bus(IF_SCSI);
-    for (bus = 0; bus <= max_bus; bus++) {
-        pci_create_simple(pci_bus, -1, "lsi53c895a");
-    }
-}
-
-void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
-{
-    DeviceState *dev;
-    SysBusDevice *d;
-    unsigned int i;
-
-    if (kvm_irqchip_in_kernel()) {
-        dev = qdev_create(NULL, "kvm-ioapic");
-    } else {
-        dev = qdev_create(NULL, "ioapic");
-    }
-    if (parent_name) {
-        object_property_add_child(object_resolve_path(parent_name, NULL),
-                                  "ioapic", OBJECT(dev), NULL);
-    }
-    qdev_init_nofail(dev);
-    d = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(d, 0, 0xfec00000);
-
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
-    }
-}
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
deleted file mode 100644 (file)
index 73a8656..0000000
+++ /dev/null
@@ -1,713 +0,0 @@
-/*
- * QEMU PC System Emulator
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <glib.h>
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/apic.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_ids.h"
-#include "hw/usb.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/ide.h"
-#include "sysemu/kvm.h"
-#include "hw/kvm/clock.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "sysemu/arch_init.h"
-#include "sysemu/blockdev.h"
-#include "hw/smbus.h"
-#include "hw/xen.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "cpu.h"
-#ifdef CONFIG_XEN
-#  include <xen/hvm/hvm_info_table.h>
-#endif
-
-#define MAX_IDE_BUS 2
-
-static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
-static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
-static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
-
-/* PC hardware initialisation */
-static void pc_init1(MemoryRegion *system_memory,
-                     MemoryRegion *system_io,
-                     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,
-                     int pci_enabled,
-                     int kvmclock_enabled)
-{
-    int i;
-    ram_addr_t below_4g_mem_size, above_4g_mem_size;
-    PCIBus *pci_bus;
-    ISABus *isa_bus;
-    PCII440FXState *i440fx_state;
-    int piix3_devfn = -1;
-    qemu_irq *cpu_irq;
-    qemu_irq *gsi;
-    qemu_irq *i8259;
-    qemu_irq *smi_irq;
-    GSIState *gsi_state;
-    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
-    BusState *idebus[MAX_IDE_BUS];
-    ISADevice *rtc_state;
-    ISADevice *floppy;
-    MemoryRegion *ram_memory;
-    MemoryRegion *pci_memory;
-    MemoryRegion *rom_memory;
-    void *fw_cfg = NULL;
-
-    pc_cpus_init(cpu_model);
-    pc_acpi_init("acpi-dsdt.aml");
-
-    if (kvmclock_enabled) {
-        kvmclock_create();
-    }
-
-    if (ram_size >= 0xe0000000 ) {
-        above_4g_mem_size = ram_size - 0xe0000000;
-        below_4g_mem_size = 0xe0000000;
-    } else {
-        above_4g_mem_size = 0;
-        below_4g_mem_size = ram_size;
-    }
-
-    if (pci_enabled) {
-        pci_memory = g_new(MemoryRegion, 1);
-        memory_region_init(pci_memory, "pci", INT64_MAX);
-        rom_memory = pci_memory;
-    } else {
-        pci_memory = NULL;
-        rom_memory = system_memory;
-    }
-
-    /* allocate ram and load rom/bios */
-    if (!xen_enabled()) {
-        fw_cfg = pc_memory_init(system_memory,
-                       kernel_filename, kernel_cmdline, initrd_filename,
-                       below_4g_mem_size, above_4g_mem_size,
-                       rom_memory, &ram_memory);
-    }
-
-    gsi_state = g_malloc0(sizeof(*gsi_state));
-    if (kvm_irqchip_in_kernel()) {
-        kvm_pc_setup_irq_routing(pci_enabled);
-        gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
-                                 GSI_NUM_PINS);
-    } else {
-        gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
-    }
-
-    if (pci_enabled) {
-        pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
-                              system_memory, system_io, ram_size,
-                              below_4g_mem_size,
-                              0x100000000ULL - below_4g_mem_size,
-                              0x100000000ULL + above_4g_mem_size,
-                              (sizeof(hwaddr) == 4
-                               ? 0
-                               : ((uint64_t)1 << 62)),
-                              pci_memory, ram_memory);
-    } else {
-        pci_bus = NULL;
-        i440fx_state = NULL;
-        isa_bus = isa_bus_new(NULL, system_io);
-        no_hpet = 1;
-    }
-    isa_bus_irqs(isa_bus, gsi);
-
-    if (kvm_irqchip_in_kernel()) {
-        i8259 = kvm_i8259_init(isa_bus);
-    } else if (xen_enabled()) {
-        i8259 = xen_interrupt_controller_init();
-    } else {
-        cpu_irq = pc_allocate_cpu_irq();
-        i8259 = i8259_init(isa_bus, cpu_irq[0]);
-    }
-
-    for (i = 0; i < ISA_NUM_IRQS; i++) {
-        gsi_state->i8259_irq[i] = i8259[i];
-    }
-    if (pci_enabled) {
-        ioapic_init_gsi(gsi_state, "i440fx");
-    }
-
-    pc_register_ferr_irq(gsi[13]);
-
-    pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
-    if (xen_enabled()) {
-        pci_create_simple(pci_bus, -1, "xen-platform");
-    }
-
-    /* init basic PC hardware */
-    pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled());
-
-    pc_nic_init(isa_bus, pci_bus);
-
-    ide_drive_get(hd, MAX_IDE_BUS);
-    if (pci_enabled) {
-        PCIDevice *dev;
-        if (xen_enabled()) {
-            dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1);
-        } else {
-            dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
-        }
-        idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
-        idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
-    } else {
-        for(i = 0; i < MAX_IDE_BUS; i++) {
-            ISADevice *dev;
-            dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
-                               ide_irq[i],
-                               hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
-            idebus[i] = qdev_get_child_bus(&dev->qdev, "ide.0");
-        }
-    }
-
-    audio_init(isa_bus, pci_enabled ? pci_bus : NULL);
-
-    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
-                 floppy, idebus[0], idebus[1], rtc_state);
-
-    if (pci_enabled && usb_enabled(false)) {
-        pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
-    }
-
-    if (pci_enabled && acpi_enabled) {
-        i2c_bus *smbus;
-
-        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
-        /* TODO: Populate SPD eeprom data.  */
-        smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
-                              gsi[9], *smi_irq,
-                              kvm_enabled(), fw_cfg);
-        smbus_eeprom_init(smbus, 8, NULL, 0);
-    }
-
-    if (pci_enabled) {
-        pc_pci_device_init(pci_bus);
-    }
-}
-
-static void pc_init_pci(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    pc_init1(get_system_memory(),
-             get_system_io(),
-             ram_size, boot_device,
-             kernel_filename, kernel_cmdline,
-             initrd_filename, cpu_model, 1, 1);
-}
-
-static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
-{
-    enable_compat_apic_id_mode();
-    pc_init_pci(args);
-}
-
-/* PC machine init function for pc-0.14 to pc-1.2 */
-static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
-{
-    disable_kvm_pv_eoi();
-    pc_init_pci_1_3(args);
-}
-
-/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
-static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    disable_kvm_pv_eoi();
-    enable_compat_apic_id_mode();
-    pc_init1(get_system_memory(),
-             get_system_io(),
-             ram_size, boot_device,
-             kernel_filename, kernel_cmdline,
-             initrd_filename, cpu_model, 1, 0);
-}
-
-static void pc_init_isa(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    if (cpu_model == NULL)
-        cpu_model = "486";
-    disable_kvm_pv_eoi();
-    enable_compat_apic_id_mode();
-    pc_init1(get_system_memory(),
-             get_system_io(),
-             ram_size, boot_device,
-             kernel_filename, kernel_cmdline,
-             initrd_filename, cpu_model, 0, 1);
-}
-
-#ifdef CONFIG_XEN
-static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
-{
-    if (xen_hvm_init() != 0) {
-        hw_error("xen hardware virtual machine initialisation failed");
-    }
-    pc_init_pci_no_kvmclock(args);
-    xen_vcpu_init();
-}
-#endif
-
-static QEMUMachine pc_i440fx_machine_v1_5 = {
-    .name = "pc-i440fx-1.5",
-    .alias = "pc",
-    .desc = "Standard PC (i440FX + PIIX, 1996)",
-    .init = pc_init_pci,
-    .max_cpus = 255,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine pc_i440fx_machine_v1_4 = {
-    .name = "pc-i440fx-1.4",
-    .desc = "Standard PC (i440FX + PIIX, 1996)",
-    .init = pc_init_pci,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_1_4,
-        { /* end of list */ }
-    },
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-#define PC_COMPAT_1_3 \
-       PC_COMPAT_1_4, \
-        {\
-            .driver   = "usb-tablet",\
-            .property = "usb_version",\
-            .value    = stringify(1),\
-        },{\
-            .driver   = "virtio-net-pci",\
-            .property = "ctrl_mac_addr",\
-            .value    = "off",      \
-        },{ \
-            .driver   = "virtio-net-pci", \
-            .property = "mq", \
-            .value    = "off", \
-        }
-
-static QEMUMachine pc_machine_v1_3 = {
-    .name = "pc-1.3",
-    .desc = "Standard PC",
-    .init = pc_init_pci_1_3,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_1_3,
-        { /* end of list */ }
-    },
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-#define PC_COMPAT_1_2 \
-        PC_COMPAT_1_3,\
-        {\
-            .driver   = "nec-usb-xhci",\
-            .property = "msi",\
-            .value    = "off",\
-        },{\
-            .driver   = "nec-usb-xhci",\
-            .property = "msix",\
-            .value    = "off",\
-        },{\
-            .driver   = "ivshmem",\
-            .property = "use64",\
-            .value    = "0",\
-        },{\
-            .driver   = "qxl",\
-            .property = "revision",\
-            .value    = stringify(3),\
-        },{\
-            .driver   = "qxl-vga",\
-            .property = "revision",\
-            .value    = stringify(3),\
-        },{\
-            .driver   = "VGA",\
-            .property = "mmio",\
-            .value    = "off",\
-        }
-
-static QEMUMachine pc_machine_v1_2 = {
-    .name = "pc-1.2",
-    .desc = "Standard PC",
-    .init = pc_init_pci_1_2,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_1_2,
-        { /* end of list */ }
-    },
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-#define PC_COMPAT_1_1 \
-        PC_COMPAT_1_2,\
-        {\
-            .driver   = "virtio-scsi-pci",\
-            .property = "hotplug",\
-            .value    = "off",\
-        },{\
-            .driver   = "virtio-scsi-pci",\
-            .property = "param_change",\
-            .value    = "off",\
-        },{\
-            .driver   = "VGA",\
-            .property = "vgamem_mb",\
-            .value    = stringify(8),\
-        },{\
-            .driver   = "vmware-svga",\
-            .property = "vgamem_mb",\
-            .value    = stringify(8),\
-        },{\
-            .driver   = "qxl-vga",\
-            .property = "vgamem_mb",\
-            .value    = stringify(8),\
-        },{\
-            .driver   = "qxl",\
-            .property = "vgamem_mb",\
-            .value    = stringify(8),\
-        },{\
-            .driver   = "virtio-blk-pci",\
-            .property = "config-wce",\
-            .value    = "off",\
-        }
-
-static QEMUMachine pc_machine_v1_1 = {
-    .name = "pc-1.1",
-    .desc = "Standard PC",
-    .init = pc_init_pci_1_2,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_1_1,
-        { /* end of list */ }
-    },
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-#define PC_COMPAT_1_0 \
-        PC_COMPAT_1_1,\
-        {\
-            .driver   = "pc-sysfw",\
-            .property = "rom_only",\
-            .value    = stringify(1),\
-        }, {\
-            .driver   = "isa-fdc",\
-            .property = "check_media_rate",\
-            .value    = "off",\
-        }, {\
-            .driver   = "virtio-balloon-pci",\
-            .property = "class",\
-            .value    = stringify(PCI_CLASS_MEMORY_RAM),\
-        },{\
-            .driver   = "apic",\
-            .property = "vapic",\
-            .value    = "off",\
-        },{\
-            .driver   = TYPE_USB_DEVICE,\
-            .property = "full-path",\
-            .value    = "no",\
-        }
-
-static QEMUMachine pc_machine_v1_0 = {
-    .name = "pc-1.0",
-    .desc = "Standard PC",
-    .init = pc_init_pci_1_2,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_1_0,
-        { /* end of list */ }
-    },
-    .hw_version = "1.0",
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-#define PC_COMPAT_0_15 \
-        PC_COMPAT_1_0
-
-static QEMUMachine pc_machine_v0_15 = {
-    .name = "pc-0.15",
-    .desc = "Standard PC",
-    .init = pc_init_pci_1_2,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_0_15,
-        { /* end of list */ }
-    },
-    .hw_version = "0.15",
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-#define PC_COMPAT_0_14 \
-        PC_COMPAT_0_15,\
-        {\
-            .driver   = "virtio-blk-pci",\
-            .property = "event_idx",\
-            .value    = "off",\
-        },{\
-            .driver   = "virtio-serial-pci",\
-            .property = "event_idx",\
-            .value    = "off",\
-        },{\
-            .driver   = "virtio-net-pci",\
-            .property = "event_idx",\
-            .value    = "off",\
-        },{\
-            .driver   = "virtio-balloon-pci",\
-            .property = "event_idx",\
-            .value    = "off",\
-        }
-
-static QEMUMachine pc_machine_v0_14 = {
-    .name = "pc-0.14",
-    .desc = "Standard PC",
-    .init = pc_init_pci_1_2,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_0_14, 
-        {
-            .driver   = "qxl",
-            .property = "revision",
-            .value    = stringify(2),
-        },{
-            .driver   = "qxl-vga",
-            .property = "revision",
-            .value    = stringify(2),
-        },
-        { /* end of list */ }
-    },
-    .hw_version = "0.14",
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-#define PC_COMPAT_0_13 \
-        PC_COMPAT_0_14,\
-        {\
-            .driver   = TYPE_PCI_DEVICE,\
-            .property = "command_serr_enable",\
-            .value    = "off",\
-        },{\
-            .driver   = "AC97",\
-            .property = "use_broken_id",\
-            .value    = stringify(1),\
-        }
-
-static QEMUMachine pc_machine_v0_13 = {
-    .name = "pc-0.13",
-    .desc = "Standard PC",
-    .init = pc_init_pci_no_kvmclock,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_0_13,
-        {
-            .driver   = "virtio-9p-pci",
-            .property = "vectors",
-            .value    = stringify(0),
-        },{
-            .driver   = "VGA",
-            .property = "rombar",
-            .value    = stringify(0),
-        },{
-            .driver   = "vmware-svga",
-            .property = "rombar",
-            .value    = stringify(0),
-        },
-        { /* end of list */ }
-    },
-    .hw_version = "0.13",
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-#define PC_COMPAT_0_12 \
-        PC_COMPAT_0_13,\
-        {\
-            .driver   = "virtio-serial-pci",\
-            .property = "max_ports",\
-            .value    = stringify(1),\
-        },{\
-            .driver   = "virtio-serial-pci",\
-            .property = "vectors",\
-            .value    = stringify(0),\
-        }
-
-static QEMUMachine pc_machine_v0_12 = {
-    .name = "pc-0.12",
-    .desc = "Standard PC",
-    .init = pc_init_pci_no_kvmclock,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_0_12,
-        {
-            .driver   = "VGA",
-            .property = "rombar",
-            .value    = stringify(0),
-        },{
-            .driver   = "vmware-svga",
-            .property = "rombar",
-            .value    = stringify(0),
-        },
-        { /* end of list */ }
-    },
-    .hw_version = "0.12",
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-#define PC_COMPAT_0_11 \
-        PC_COMPAT_0_12,\
-        {\
-            .driver   = "virtio-blk-pci",\
-            .property = "vectors",\
-            .value    = stringify(0),\
-        },{\
-            .driver   = TYPE_PCI_DEVICE,\
-            .property = "rombar",\
-            .value    = stringify(0),\
-        }
-
-static QEMUMachine pc_machine_v0_11 = {
-    .name = "pc-0.11",
-    .desc = "Standard PC, qemu 0.11",
-    .init = pc_init_pci_no_kvmclock,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_0_11,
-        {
-            .driver   = "ide-drive",
-            .property = "ver",
-            .value    = "0.11",
-        },{
-            .driver   = "scsi-disk",
-            .property = "ver",
-            .value    = "0.11",
-        },
-        { /* end of list */ }
-    },
-    .hw_version = "0.11",
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine pc_machine_v0_10 = {
-    .name = "pc-0.10",
-    .desc = "Standard PC, qemu 0.10",
-    .init = pc_init_pci_no_kvmclock,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_0_11,
-        {
-            .driver   = "virtio-blk-pci",
-            .property = "class",
-            .value    = stringify(PCI_CLASS_STORAGE_OTHER),
-        },{
-            .driver   = "virtio-serial-pci",
-            .property = "class",
-            .value    = stringify(PCI_CLASS_DISPLAY_OTHER),
-        },{
-            .driver   = "virtio-net-pci",
-            .property = "vectors",
-            .value    = stringify(0),
-        },{
-            .driver   = "ide-drive",
-            .property = "ver",
-            .value    = "0.10",
-        },{
-            .driver   = "scsi-disk",
-            .property = "ver",
-            .value    = "0.10",
-        },
-        { /* end of list */ }
-    },
-    .hw_version = "0.10",
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine isapc_machine = {
-    .name = "isapc",
-    .desc = "ISA-only PC",
-    .init = pc_init_isa,
-    .max_cpus = 1,
-    .compat_props = (GlobalProperty[]) {
-        {
-            .driver   = "pc-sysfw",
-            .property = "rom_only",
-            .value    = stringify(1),
-        },
-        { /* end of list */ }
-    },
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-#ifdef CONFIG_XEN
-static QEMUMachine xenfv_machine = {
-    .name = "xenfv",
-    .desc = "Xen Fully-virtualized PC",
-    .init = pc_xen_hvm_init,
-    .max_cpus = HVM_MAX_VCPUS,
-    .default_machine_opts = "accel=xen",
-    DEFAULT_MACHINE_OPTIONS,
-};
-#endif
-
-static void pc_machine_init(void)
-{
-    qemu_register_machine(&pc_i440fx_machine_v1_5);
-    qemu_register_machine(&pc_i440fx_machine_v1_4);
-    qemu_register_machine(&pc_machine_v1_3);
-    qemu_register_machine(&pc_machine_v1_2);
-    qemu_register_machine(&pc_machine_v1_1);
-    qemu_register_machine(&pc_machine_v1_0);
-    qemu_register_machine(&pc_machine_v0_15);
-    qemu_register_machine(&pc_machine_v0_14);
-    qemu_register_machine(&pc_machine_v0_13);
-    qemu_register_machine(&pc_machine_v0_12);
-    qemu_register_machine(&pc_machine_v0_11);
-    qemu_register_machine(&pc_machine_v0_10);
-    qemu_register_machine(&isapc_machine);
-#ifdef CONFIG_XEN
-    qemu_register_machine(&xenfv_machine);
-#endif
-}
-
-machine_init(pc_machine_init);
diff --git a/hw/pc_q35.c b/hw/pc_q35.c
deleted file mode 100644 (file)
index 4f5f347..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Q35 chipset based pc system emulator
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2009, 2010
- *               Isaku Yamahata <yamahata at valinux co jp>
- *               VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This is based on pc.c, but heavily modified.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/hw.h"
-#include "sysemu/arch_init.h"
-#include "hw/smbus.h"
-#include "hw/boards.h"
-#include "hw/mc146818rtc.h"
-#include "hw/xen.h"
-#include "sysemu/kvm.h"
-#include "hw/kvm/clock.h"
-#include "hw/q35.h"
-#include "exec/address-spaces.h"
-#include "hw/ich9.h"
-#include "hw/ide/pci.h"
-#include "hw/ide/ahci.h"
-#include "hw/usb.h"
-
-/* ICH9 AHCI has 6 ports */
-#define MAX_SATA_PORTS     6
-
-/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
- *    BIOS will read it and start S3 resume at POST Entry */
-static void pc_cmos_set_s3_resume(void *opaque, int irq, int level)
-{
-    ISADevice *s = opaque;
-
-    if (level) {
-        rtc_set_memory(s, 0xF, 0xFE);
-    }
-}
-
-/* PC hardware initialisation */
-static void pc_q35_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    ram_addr_t below_4g_mem_size, above_4g_mem_size;
-    Q35PCIHost *q35_host;
-    PCIBus *host_bus;
-    PCIDevice *lpc;
-    BusState *idebus[MAX_SATA_PORTS];
-    ISADevice *rtc_state;
-    ISADevice *floppy;
-    MemoryRegion *pci_memory;
-    MemoryRegion *rom_memory;
-    MemoryRegion *ram_memory;
-    GSIState *gsi_state;
-    ISABus *isa_bus;
-    int pci_enabled = 1;
-    qemu_irq *cpu_irq;
-    qemu_irq *gsi;
-    qemu_irq *i8259;
-    int i;
-    ICH9LPCState *ich9_lpc;
-    PCIDevice *ahci;
-    qemu_irq *cmos_s3;
-
-    pc_cpus_init(cpu_model);
-    pc_acpi_init("q35-acpi-dsdt.aml");
-
-    kvmclock_create();
-
-    if (ram_size >= 0xb0000000) {
-        above_4g_mem_size = ram_size - 0xb0000000;
-        below_4g_mem_size = 0xb0000000;
-    } else {
-        above_4g_mem_size = 0;
-        below_4g_mem_size = ram_size;
-    }
-
-    /* pci enabled */
-    if (pci_enabled) {
-        pci_memory = g_new(MemoryRegion, 1);
-        memory_region_init(pci_memory, "pci", INT64_MAX);
-        rom_memory = pci_memory;
-    } else {
-        pci_memory = NULL;
-        rom_memory = get_system_memory();
-    }
-
-    /* allocate ram and load rom/bios */
-    if (!xen_enabled()) {
-        pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline,
-                       initrd_filename, below_4g_mem_size, above_4g_mem_size,
-                       rom_memory, &ram_memory);
-    }
-
-    /* irq lines */
-    gsi_state = g_malloc0(sizeof(*gsi_state));
-    if (kvm_irqchip_in_kernel()) {
-        kvm_pc_setup_irq_routing(pci_enabled);
-        gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
-                                 GSI_NUM_PINS);
-    } else {
-        gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
-    }
-
-    /* create pci host bus */
-    q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE));
-
-    q35_host->mch.ram_memory = ram_memory;
-    q35_host->mch.pci_address_space = pci_memory;
-    q35_host->mch.system_memory = get_system_memory();
-    q35_host->mch.address_space_io = get_system_io();;
-    q35_host->mch.below_4g_mem_size = below_4g_mem_size;
-    q35_host->mch.above_4g_mem_size = above_4g_mem_size;
-    /* pci */
-    qdev_init_nofail(DEVICE(q35_host));
-    host_bus = q35_host->host.pci.bus;
-    /* create ISA bus */
-    lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,
-                                          ICH9_LPC_FUNC), true,
-                                          TYPE_ICH9_LPC_DEVICE);
-    ich9_lpc = ICH9_LPC_DEVICE(lpc);
-    ich9_lpc->pic = gsi;
-    ich9_lpc->ioapic = gsi_state->ioapic_irq;
-    pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc,
-                 ICH9_LPC_NB_PIRQS);
-    pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq);
-    isa_bus = ich9_lpc->isa_bus;
-
-    /*end early*/
-    isa_bus_irqs(isa_bus, gsi);
-
-    if (kvm_irqchip_in_kernel()) {
-        i8259 = kvm_i8259_init(isa_bus);
-    } else if (xen_enabled()) {
-        i8259 = xen_interrupt_controller_init();
-    } else {
-        cpu_irq = pc_allocate_cpu_irq();
-        i8259 = i8259_init(isa_bus, cpu_irq[0]);
-    }
-
-    for (i = 0; i < ISA_NUM_IRQS; i++) {
-        gsi_state->i8259_irq[i] = i8259[i];
-    }
-    if (pci_enabled) {
-        ioapic_init_gsi(gsi_state, NULL);
-    }
-
-    pc_register_ferr_irq(gsi[13]);
-
-    /* init basic PC hardware */
-    pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false);
-
-    /* connect pm stuff to lpc */
-    cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
-    ich9_lpc_pm_init(lpc, *cmos_s3);
-
-    /* ahci and SATA device, for q35 1 ahci controller is built-in */
-    ahci = pci_create_simple_multifunction(host_bus,
-                                           PCI_DEVFN(ICH9_SATA1_DEV,
-                                                     ICH9_SATA1_FUNC),
-                                           true, "ich9-ahci");
-    idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
-    idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
-
-    if (usb_enabled(false)) {
-        /* Should we create 6 UHCI according to ich9 spec? */
-        ehci_create_ich9_with_companions(host_bus, 0x1d);
-    }
-
-    /* TODO: Populate SPD eeprom data.  */
-    smbus_eeprom_init(ich9_smb_init(host_bus,
-                                    PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
-                                    0xb100),
-                      8, NULL, 0);
-
-    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
-                 floppy, idebus[0], idebus[1], rtc_state);
-
-    /* the rest devices to which pci devfn is automatically assigned */
-    pc_vga_init(isa_bus, host_bus);
-    audio_init(isa_bus, host_bus);
-    pc_nic_init(isa_bus, host_bus);
-    if (pci_enabled) {
-        pc_pci_device_init(host_bus);
-    }
-}
-
-static QEMUMachine pc_q35_machine_v1_5 = {
-    .name = "pc-q35-1.5",
-    .alias = "q35",
-    .desc = "Standard PC (Q35 + ICH9, 2009)",
-    .init = pc_q35_init,
-    .max_cpus = 255,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine pc_q35_machine_v1_4 = {
-    .name = "pc-q35-1.4",
-    .desc = "Standard PC (Q35 + ICH9, 2009)",
-    .init = pc_q35_init,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        PC_COMPAT_1_4,
-        { /* end of list */ }
-    },
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void pc_q35_machine_init(void)
-{
-    qemu_register_machine(&pc_q35_machine_v1_5);
-    qemu_register_machine(&pc_q35_machine_v1_4);
-}
-
-machine_init(pc_q35_machine_init);
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
deleted file mode 100644 (file)
index cfc0220..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Model of Petalogix linux reference design targeting Xilinx Spartan ml605
- * board.
- *
- * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
- * Copyright (c) 2011 PetaLogix
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "net/net.h"
-#include "hw/flash.h"
-#include "sysemu/sysemu.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/xilinx.h"
-#include "sysemu/blockdev.h"
-#include "hw/serial.h"
-#include "exec/address-spaces.h"
-#include "hw/ssi.h"
-
-#include "hw/microblaze_boot.h"
-#include "hw/microblaze_pic_cpu.h"
-
-#include "hw/stream.h"
-
-#define LMB_BRAM_SIZE  (128 * 1024)
-#define FLASH_SIZE     (32 * 1024 * 1024)
-
-#define BINARY_DEVICE_TREE_FILE "petalogix-ml605.dtb"
-
-#define NUM_SPI_FLASHES 4
-
-#define MEMORY_BASEADDR 0x50000000
-#define FLASH_BASEADDR 0x86000000
-#define INTC_BASEADDR 0x81800000
-#define TIMER_BASEADDR 0x83c00000
-#define UART16550_BASEADDR 0x83e00000
-#define AXIENET_BASEADDR 0x82780000
-#define AXIDMA_BASEADDR 0x84600000
-
-static void machine_cpu_reset(MicroBlazeCPU *cpu)
-{
-    CPUMBState *env = &cpu->env;
-
-    env->pvr.regs[10] = 0x0e000000; /* virtex 6 */
-    /* setup pvr to match kernel setting */
-    env->pvr.regs[5] |= PVR5_DCACHE_WRITEBACK_MASK;
-    env->pvr.regs[0] |= PVR0_USE_FPU_MASK | PVR0_ENDI;
-    env->pvr.regs[0] = (env->pvr.regs[0] & ~PVR0_VERSION_MASK) | (0x14 << 8);
-    env->pvr.regs[2] ^= PVR2_USE_FPU2_MASK;
-    env->pvr.regs[4] = 0xc56b8000;
-    env->pvr.regs[5] = 0xc56be000;
-}
-
-static void
-petalogix_ml605_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    MemoryRegion *address_space_mem = get_system_memory();
-    DeviceState *dev, *dma, *eth0;
-    MicroBlazeCPU *cpu;
-    SysBusDevice *busdev;
-    CPUMBState *env;
-    DriveInfo *dinfo;
-    int i;
-    hwaddr ddr_base = MEMORY_BASEADDR;
-    MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1);
-    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
-    qemu_irq irq[32], *cpu_irq;
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-        cpu_model = "microblaze";
-    }
-    cpu = cpu_mb_init(cpu_model);
-    env = &cpu->env;
-
-    /* Attach emulated BRAM through the LMB.  */
-    memory_region_init_ram(phys_lmb_bram, "petalogix_ml605.lmb_bram",
-                           LMB_BRAM_SIZE);
-    vmstate_register_ram_global(phys_lmb_bram);
-    memory_region_add_subregion(address_space_mem, 0x00000000, phys_lmb_bram);
-
-    memory_region_init_ram(phys_ram, "petalogix_ml605.ram", ram_size);
-    vmstate_register_ram_global(phys_ram);
-    memory_region_add_subregion(address_space_mem, ddr_base, phys_ram);
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    /* 5th parameter 2 means bank-width
-     * 10th paremeter 0 means little-endian */
-    pflash_cfi01_register(FLASH_BASEADDR,
-                          NULL, "petalogix_ml605.flash", FLASH_SIZE,
-                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
-                          FLASH_SIZE >> 16,
-                          2, 0x89, 0x18, 0x0000, 0x0, 0);
-
-
-    cpu_irq = microblaze_pic_init_cpu(env);
-    dev = xilinx_intc_create(INTC_BASEADDR, cpu_irq[0], 4);
-    for (i = 0; i < 32; i++) {
-        irq[i] = qdev_get_gpio_in(dev, i);
-    }
-
-    serial_mm_init(address_space_mem, UART16550_BASEADDR + 0x1000, 2,
-                   irq[5], 115200, serial_hds[0], DEVICE_LITTLE_ENDIAN);
-
-    /* 2 timers at irq 2 @ 100 Mhz.  */
-    xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000);
-
-    /* axi ethernet and dma initialization. */
-    qemu_check_nic_model(&nd_table[0], "xlnx.axi-ethernet");
-    eth0 = qdev_create(NULL, "xlnx.axi-ethernet");
-    dma = qdev_create(NULL, "xlnx.axi-dma");
-
-    /* FIXME: attach to the sysbus instead */
-    object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
-                                  "xilinx-dma", OBJECT(dma), NULL);
-
-    xilinx_axiethernet_init(eth0, &nd_table[0], STREAM_SLAVE(dma),
-                                   0x82780000, irq[3], 0x1000, 0x1000);
-
-    xilinx_axidma_init(dma, STREAM_SLAVE(eth0), 0x84600000, irq[1], irq[0],
-                       100 * 1000000);
-
-    {
-        SSIBus *spi;
-
-        dev = qdev_create(NULL, "xlnx.xps-spi");
-        qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES);
-        qdev_init_nofail(dev);
-        busdev = SYS_BUS_DEVICE(dev);
-        sysbus_mmio_map(busdev, 0, 0x40a00000);
-        sysbus_connect_irq(busdev, 0, irq[4]);
-
-        spi = (SSIBus *)qdev_get_child_bus(dev, "spi");
-
-        for (i = 0; i < NUM_SPI_FLASHES; i++) {
-            qemu_irq cs_line;
-
-            dev = ssi_create_slave_no_init(spi, "n25q128");
-            qdev_init_nofail(dev);
-            cs_line = qdev_get_gpio_in(dev, 0);
-            sysbus_connect_irq(busdev, i+1, cs_line);
-        }
-    }
-
-    microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE,
-                                                            machine_cpu_reset);
-
-}
-
-static QEMUMachine petalogix_ml605_machine = {
-    .name = "petalogix-ml605",
-    .desc = "PetaLogix linux refdesign for xilinx ml605 little endian",
-    .init = petalogix_ml605_init,
-    .is_default = 0,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void petalogix_ml605_machine_init(void)
-{
-    qemu_register_machine(&petalogix_ml605_machine);
-}
-
-machine_init(petalogix_ml605_machine_init);
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
deleted file mode 100644 (file)
index 2498362..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Model of Petalogix linux reference design targeting Xilinx Spartan 3ADSP-1800
- * boards.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "net/net.h"
-#include "hw/flash.h"
-#include "sysemu/sysemu.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/xilinx.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-#include "hw/microblaze_boot.h"
-#include "hw/microblaze_pic_cpu.h"
-
-#define LMB_BRAM_SIZE  (128 * 1024)
-#define FLASH_SIZE     (16 * 1024 * 1024)
-
-#define BINARY_DEVICE_TREE_FILE "petalogix-s3adsp1800.dtb"
-
-#define MEMORY_BASEADDR 0x90000000
-#define FLASH_BASEADDR 0xa0000000
-#define INTC_BASEADDR 0x81800000
-#define TIMER_BASEADDR 0x83c00000
-#define UARTLITE_BASEADDR 0x84000000
-#define ETHLITE_BASEADDR 0x81000000
-
-static void machine_cpu_reset(MicroBlazeCPU *cpu)
-{
-    CPUMBState *env = &cpu->env;
-
-    env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family.  */
-}
-
-static void
-petalogix_s3adsp1800_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    DeviceState *dev;
-    MicroBlazeCPU *cpu;
-    CPUMBState *env;
-    DriveInfo *dinfo;
-    int i;
-    hwaddr ddr_base = MEMORY_BASEADDR;
-    MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1);
-    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
-    qemu_irq irq[32], *cpu_irq;
-    MemoryRegion *sysmem = get_system_memory();
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-        cpu_model = "microblaze";
-    }
-    cpu = cpu_mb_init(cpu_model);
-    env = &cpu->env;
-
-    /* Attach emulated BRAM through the LMB.  */
-    memory_region_init_ram(phys_lmb_bram,
-                           "petalogix_s3adsp1800.lmb_bram", LMB_BRAM_SIZE);
-    vmstate_register_ram_global(phys_lmb_bram);
-    memory_region_add_subregion(sysmem, 0x00000000, phys_lmb_bram);
-
-    memory_region_init_ram(phys_ram, "petalogix_s3adsp1800.ram", ram_size);
-    vmstate_register_ram_global(phys_ram);
-    memory_region_add_subregion(sysmem, ddr_base, phys_ram);
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi01_register(FLASH_BASEADDR,
-                          NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE,
-                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
-                          FLASH_SIZE >> 16,
-                          1, 0x89, 0x18, 0x0000, 0x0, 1);
-
-    cpu_irq = microblaze_pic_init_cpu(env);
-    dev = xilinx_intc_create(INTC_BASEADDR, cpu_irq[0], 2);
-    for (i = 0; i < 32; i++) {
-        irq[i] = qdev_get_gpio_in(dev, i);
-    }
-
-    sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR, irq[3]);
-    /* 2 timers at irq 2 @ 62 Mhz.  */
-    xilinx_timer_create(TIMER_BASEADDR, irq[0], 0, 62 * 1000000);
-    xilinx_ethlite_create(&nd_table[0], ETHLITE_BASEADDR, irq[1], 0, 0);
-
-    microblaze_load_kernel(cpu, ddr_base, ram_size,
-                    BINARY_DEVICE_TREE_FILE, machine_cpu_reset);
-}
-
-static QEMUMachine petalogix_s3adsp1800_machine = {
-    .name = "petalogix-s3adsp1800",
-    .desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800",
-    .init = petalogix_s3adsp1800_init,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void petalogix_s3adsp1800_machine_init(void)
-{
-    qemu_register_machine(&petalogix_s3adsp1800_machine);
-}
-
-machine_init(petalogix_s3adsp1800_machine_init);
diff --git a/hw/ppc.c b/hw/ppc.c
deleted file mode 100644 (file)
index c9437fc..0000000
--- a/hw/ppc.c
+++ /dev/null
@@ -1,1356 +0,0 @@
-/*
- * QEMU generic PowerPC hardware System Emulator
- *
- * Copyright (c) 2003-2007 Jocelyn Mayer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/hw.h"
-#include "hw/ppc.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/nvram.h"
-#include "qemu/log.h"
-#include "hw/loader.h"
-#include "sysemu/kvm.h"
-#include "kvm_ppc.h"
-
-//#define PPC_DEBUG_IRQ
-//#define PPC_DEBUG_TB
-
-#ifdef PPC_DEBUG_IRQ
-#  define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
-#else
-#  define LOG_IRQ(...) do { } while (0)
-#endif
-
-
-#ifdef PPC_DEBUG_TB
-#  define LOG_TB(...) qemu_log(__VA_ARGS__)
-#else
-#  define LOG_TB(...) do { } while (0)
-#endif
-
-static void cpu_ppc_tb_stop (CPUPPCState *env);
-static void cpu_ppc_tb_start (CPUPPCState *env);
-
-void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
-{
-    CPUPPCState *env = &cpu->env;
-    unsigned int old_pending = env->pending_interrupts;
-
-    if (level) {
-        env->pending_interrupts |= 1 << n_IRQ;
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
-    } else {
-        env->pending_interrupts &= ~(1 << n_IRQ);
-        if (env->pending_interrupts == 0)
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
-
-    if (old_pending != env->pending_interrupts) {
-#ifdef CONFIG_KVM
-        kvmppc_set_interrupt(cpu, n_IRQ, level);
-#endif
-    }
-
-    LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
-                "req %08x\n", __func__, env, n_IRQ, level,
-                env->pending_interrupts, env->interrupt_request);
-}
-
-/* PowerPC 6xx / 7xx internal IRQ controller */
-static void ppc6xx_set_irq(void *opaque, int pin, int level)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-    int cur_level;
-
-    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
-                env, pin, level);
-    cur_level = (env->irq_input_state >> pin) & 1;
-    /* Don't generate spurious events */
-    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
-        switch (pin) {
-        case PPC6xx_INPUT_TBEN:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: %s the time base\n",
-                        __func__, level ? "start" : "stop");
-            if (level) {
-                cpu_ppc_tb_start(env);
-            } else {
-                cpu_ppc_tb_stop(env);
-            }
-        case PPC6xx_INPUT_INT:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: set the external IRQ state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
-            break;
-        case PPC6xx_INPUT_SMI:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: set the SMI IRQ state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level);
-            break;
-        case PPC6xx_INPUT_MCP:
-            /* Negative edge sensitive */
-            /* XXX: TODO: actual reaction may depends on HID0 status
-             *            603/604/740/750: check HID0[EMCP]
-             */
-            if (cur_level == 1 && level == 0) {
-                LOG_IRQ("%s: raise machine check state\n",
-                            __func__);
-                ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
-            }
-            break;
-        case PPC6xx_INPUT_CKSTP_IN:
-            /* Level sensitive - active low */
-            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
-            /* XXX: Note that the only way to restart the CPU is to reset it */
-            if (level) {
-                LOG_IRQ("%s: stop the CPU\n", __func__);
-                env->halted = 1;
-            }
-            break;
-        case PPC6xx_INPUT_HRESET:
-            /* Level sensitive - active low */
-            if (level) {
-                LOG_IRQ("%s: reset the CPU\n", __func__);
-                cpu_interrupt(env, CPU_INTERRUPT_RESET);
-            }
-            break;
-        case PPC6xx_INPUT_SRESET:
-            LOG_IRQ("%s: set the RESET IRQ state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
-            break;
-        default:
-            /* Unknown pin - do nothing */
-            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
-            return;
-        }
-        if (level)
-            env->irq_input_state |= 1 << pin;
-        else
-            env->irq_input_state &= ~(1 << pin);
-    }
-}
-
-void ppc6xx_irq_init(CPUPPCState *env)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
-    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu,
-                                                  PPC6xx_INPUT_NB);
-}
-
-#if defined(TARGET_PPC64)
-/* PowerPC 970 internal IRQ controller */
-static void ppc970_set_irq(void *opaque, int pin, int level)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-    int cur_level;
-
-    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
-                env, pin, level);
-    cur_level = (env->irq_input_state >> pin) & 1;
-    /* Don't generate spurious events */
-    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
-        switch (pin) {
-        case PPC970_INPUT_INT:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: set the external IRQ state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
-            break;
-        case PPC970_INPUT_THINT:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__,
-                        level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level);
-            break;
-        case PPC970_INPUT_MCP:
-            /* Negative edge sensitive */
-            /* XXX: TODO: actual reaction may depends on HID0 status
-             *            603/604/740/750: check HID0[EMCP]
-             */
-            if (cur_level == 1 && level == 0) {
-                LOG_IRQ("%s: raise machine check state\n",
-                            __func__);
-                ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
-            }
-            break;
-        case PPC970_INPUT_CKSTP:
-            /* Level sensitive - active low */
-            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
-            if (level) {
-                LOG_IRQ("%s: stop the CPU\n", __func__);
-                env->halted = 1;
-            } else {
-                LOG_IRQ("%s: restart the CPU\n", __func__);
-                env->halted = 0;
-                qemu_cpu_kick(CPU(cpu));
-            }
-            break;
-        case PPC970_INPUT_HRESET:
-            /* Level sensitive - active low */
-            if (level) {
-                cpu_interrupt(env, CPU_INTERRUPT_RESET);
-            }
-            break;
-        case PPC970_INPUT_SRESET:
-            LOG_IRQ("%s: set the RESET IRQ state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
-            break;
-        case PPC970_INPUT_TBEN:
-            LOG_IRQ("%s: set the TBEN state to %d\n", __func__,
-                        level);
-            /* XXX: TODO */
-            break;
-        default:
-            /* Unknown pin - do nothing */
-            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
-            return;
-        }
-        if (level)
-            env->irq_input_state |= 1 << pin;
-        else
-            env->irq_input_state &= ~(1 << pin);
-    }
-}
-
-void ppc970_irq_init(CPUPPCState *env)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
-    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu,
-                                                  PPC970_INPUT_NB);
-}
-
-/* POWER7 internal IRQ controller */
-static void power7_set_irq(void *opaque, int pin, int level)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-
-    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
-                env, pin, level);
-
-    switch (pin) {
-    case POWER7_INPUT_INT:
-        /* Level sensitive - active high */
-        LOG_IRQ("%s: set the external IRQ state to %d\n",
-                __func__, level);
-        ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
-        break;
-    default:
-        /* Unknown pin - do nothing */
-        LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
-        return;
-    }
-    if (level) {
-        env->irq_input_state |= 1 << pin;
-    } else {
-        env->irq_input_state &= ~(1 << pin);
-    }
-}
-
-void ppcPOWER7_irq_init(CPUPPCState *env)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
-    env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu,
-                                                  POWER7_INPUT_NB);
-}
-#endif /* defined(TARGET_PPC64) */
-
-/* PowerPC 40x internal IRQ controller */
-static void ppc40x_set_irq(void *opaque, int pin, int level)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-    int cur_level;
-
-    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
-                env, pin, level);
-    cur_level = (env->irq_input_state >> pin) & 1;
-    /* Don't generate spurious events */
-    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
-        switch (pin) {
-        case PPC40x_INPUT_RESET_SYS:
-            if (level) {
-                LOG_IRQ("%s: reset the PowerPC system\n",
-                            __func__);
-                ppc40x_system_reset(cpu);
-            }
-            break;
-        case PPC40x_INPUT_RESET_CHIP:
-            if (level) {
-                LOG_IRQ("%s: reset the PowerPC chip\n", __func__);
-                ppc40x_chip_reset(cpu);
-            }
-            break;
-        case PPC40x_INPUT_RESET_CORE:
-            /* XXX: TODO: update DBSR[MRR] */
-            if (level) {
-                LOG_IRQ("%s: reset the PowerPC core\n", __func__);
-                ppc40x_core_reset(cpu);
-            }
-            break;
-        case PPC40x_INPUT_CINT:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: set the critical IRQ state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
-            break;
-        case PPC40x_INPUT_INT:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: set the external IRQ state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
-            break;
-        case PPC40x_INPUT_HALT:
-            /* Level sensitive - active low */
-            if (level) {
-                LOG_IRQ("%s: stop the CPU\n", __func__);
-                env->halted = 1;
-            } else {
-                LOG_IRQ("%s: restart the CPU\n", __func__);
-                env->halted = 0;
-                qemu_cpu_kick(CPU(cpu));
-            }
-            break;
-        case PPC40x_INPUT_DEBUG:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: set the debug pin state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
-            break;
-        default:
-            /* Unknown pin - do nothing */
-            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
-            return;
-        }
-        if (level)
-            env->irq_input_state |= 1 << pin;
-        else
-            env->irq_input_state &= ~(1 << pin);
-    }
-}
-
-void ppc40x_irq_init(CPUPPCState *env)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
-    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
-                                                  cpu, PPC40x_INPUT_NB);
-}
-
-/* PowerPC E500 internal IRQ controller */
-static void ppce500_set_irq(void *opaque, int pin, int level)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-    int cur_level;
-
-    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
-                env, pin, level);
-    cur_level = (env->irq_input_state >> pin) & 1;
-    /* Don't generate spurious events */
-    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
-        switch (pin) {
-        case PPCE500_INPUT_MCK:
-            if (level) {
-                LOG_IRQ("%s: reset the PowerPC system\n",
-                            __func__);
-                qemu_system_reset_request();
-            }
-            break;
-        case PPCE500_INPUT_RESET_CORE:
-            if (level) {
-                LOG_IRQ("%s: reset the PowerPC core\n", __func__);
-                ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level);
-            }
-            break;
-        case PPCE500_INPUT_CINT:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: set the critical IRQ state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
-            break;
-        case PPCE500_INPUT_INT:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: set the core IRQ state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
-            break;
-        case PPCE500_INPUT_DEBUG:
-            /* Level sensitive - active high */
-            LOG_IRQ("%s: set the debug pin state to %d\n",
-                        __func__, level);
-            ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
-            break;
-        default:
-            /* Unknown pin - do nothing */
-            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
-            return;
-        }
-        if (level)
-            env->irq_input_state |= 1 << pin;
-        else
-            env->irq_input_state &= ~(1 << pin);
-    }
-}
-
-void ppce500_irq_init(CPUPPCState *env)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
-    env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq,
-                                                  cpu, PPCE500_INPUT_NB);
-}
-
-/* Enable or Disable the E500 EPR capability */
-void ppce500_set_mpic_proxy(bool enabled)
-{
-    CPUPPCState *env;
-
-    for (env = first_cpu; env != NULL; env = env->next_cpu) {
-        PowerPCCPU *cpu = ppc_env_get_cpu(env);
-        CPUState *cs = CPU(cpu);
-
-        env->mpic_proxy = enabled;
-        if (kvm_enabled()) {
-            kvmppc_set_mpic_proxy(POWERPC_CPU(cs), enabled);
-        }
-    }
-}
-
-/*****************************************************************************/
-/* PowerPC time base and decrementer emulation */
-
-uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
-{
-    /* TB time in tb periods */
-    return muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()) + tb_offset;
-}
-
-uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t tb;
-
-    if (kvm_enabled()) {
-        return env->spr[SPR_TBL];
-    }
-
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
-    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
-
-    return tb;
-}
-
-static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t tb;
-
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
-    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
-
-    return tb >> 32;
-}
-
-uint32_t cpu_ppc_load_tbu (CPUPPCState *env)
-{
-    if (kvm_enabled()) {
-        return env->spr[SPR_TBU];
-    }
-
-    return _cpu_ppc_load_tbu(env);
-}
-
-static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
-                                    int64_t *tb_offsetp, uint64_t value)
-{
-    *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec());
-    LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n",
-                __func__, value, *tb_offsetp);
-}
-
-void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t tb;
-
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
-    tb &= 0xFFFFFFFF00000000ULL;
-    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
-                     &tb_env->tb_offset, tb | (uint64_t)value);
-}
-
-static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t tb;
-
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
-    tb &= 0x00000000FFFFFFFFULL;
-    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
-                     &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
-}
-
-void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value)
-{
-    _cpu_ppc_store_tbu(env, value);
-}
-
-uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t tb;
-
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
-    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
-
-    return tb;
-}
-
-uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t tb;
-
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
-    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
-
-    return tb >> 32;
-}
-
-void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t tb;
-
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
-    tb &= 0xFFFFFFFF00000000ULL;
-    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
-                     &tb_env->atb_offset, tb | (uint64_t)value);
-}
-
-void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t tb;
-
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
-    tb &= 0x00000000FFFFFFFFULL;
-    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
-                     &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
-}
-
-static void cpu_ppc_tb_stop (CPUPPCState *env)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t tb, atb, vmclk;
-
-    /* If the time base is already frozen, do nothing */
-    if (tb_env->tb_freq != 0) {
-        vmclk = qemu_get_clock_ns(vm_clock);
-        /* Get the time base */
-        tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
-        /* Get the alternate time base */
-        atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
-        /* Store the time base value (ie compute the current offset) */
-        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
-        /* Store the alternate time base value (compute the current offset) */
-        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
-        /* Set the time base frequency to zero */
-        tb_env->tb_freq = 0;
-        /* Now, the time bases are frozen to tb_offset / atb_offset value */
-    }
-}
-
-static void cpu_ppc_tb_start (CPUPPCState *env)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t tb, atb, vmclk;
-
-    /* If the time base is not frozen, do nothing */
-    if (tb_env->tb_freq == 0) {
-        vmclk = qemu_get_clock_ns(vm_clock);
-        /* Get the time base from tb_offset */
-        tb = tb_env->tb_offset;
-        /* Get the alternate time base from atb_offset */
-        atb = tb_env->atb_offset;
-        /* Restore the tb frequency from the decrementer frequency */
-        tb_env->tb_freq = tb_env->decr_freq;
-        /* Store the time base value */
-        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
-        /* Store the alternate time base value */
-        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
-    }
-}
-
-static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint32_t decr;
-    int64_t diff;
-
-    diff = next - qemu_get_clock_ns(vm_clock);
-    if (diff >= 0) {
-        decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec());
-    } else if (tb_env->flags & PPC_TIMER_BOOKE) {
-        decr = 0;
-    }  else {
-        decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec());
-    }
-    LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
-
-    return decr;
-}
-
-uint32_t cpu_ppc_load_decr (CPUPPCState *env)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-
-    if (kvm_enabled()) {
-        return env->spr[SPR_DECR];
-    }
-
-    return _cpu_ppc_load_decr(env, tb_env->decr_next);
-}
-
-uint32_t cpu_ppc_load_hdecr (CPUPPCState *env)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-
-    return _cpu_ppc_load_decr(env, tb_env->hdecr_next);
-}
-
-uint64_t cpu_ppc_load_purr (CPUPPCState *env)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t diff;
-
-    diff = qemu_get_clock_ns(vm_clock) - tb_env->purr_start;
-
-    return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, get_ticks_per_sec());
-}
-
-/* When decrementer expires,
- * all we need to do is generate or queue a CPU exception
- */
-static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
-{
-    /* Raise it */
-    LOG_TB("raise decrementer exception\n");
-    ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
-}
-
-static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
-{
-    /* Raise it */
-    LOG_TB("raise decrementer exception\n");
-    ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
-}
-
-static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
-                                 struct QEMUTimer *timer,
-                                 void (*raise_excp)(PowerPCCPU *),
-                                 uint32_t decr, uint32_t value,
-                                 int is_excp)
-{
-    CPUPPCState *env = &cpu->env;
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t now, next;
-
-    LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
-                decr, value);
-
-    if (kvm_enabled()) {
-        /* KVM handles decrementer exceptions, we don't need our own timer */
-        return;
-    }
-
-    now = qemu_get_clock_ns(vm_clock);
-    next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
-    if (is_excp) {
-        next += *nextp - now;
-    }
-    if (next == now) {
-        next++;
-    }
-    *nextp = next;
-    /* Adjust timer */
-    qemu_mod_timer(timer, next);
-
-    /* If we set a negative value and the decrementer was positive, raise an
-     * exception.
-     */
-    if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED)
-        && (value & 0x80000000)
-        && !(decr & 0x80000000)) {
-        (*raise_excp)(cpu);
-    }
-}
-
-static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
-                                       uint32_t value, int is_excp)
-{
-    ppc_tb_t *tb_env = cpu->env.tb_env;
-
-    __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
-                         &cpu_ppc_decr_excp, decr, value, is_excp);
-}
-
-void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
-    _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0);
-}
-
-static void cpu_ppc_decr_cb(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-
-    _cpu_ppc_store_decr(cpu, 0x00000000, 0xFFFFFFFF, 1);
-}
-
-static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
-                                        uint32_t value, int is_excp)
-{
-    ppc_tb_t *tb_env = cpu->env.tb_env;
-
-    if (tb_env->hdecr_timer != NULL) {
-        __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
-                             &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
-    }
-}
-
-void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
-    _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0);
-}
-
-static void cpu_ppc_hdecr_cb(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-
-    _cpu_ppc_store_hdecr(cpu, 0x00000000, 0xFFFFFFFF, 1);
-}
-
-static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
-{
-    ppc_tb_t *tb_env = cpu->env.tb_env;
-
-    tb_env->purr_load = value;
-    tb_env->purr_start = qemu_get_clock_ns(vm_clock);
-}
-
-static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
-{
-    CPUPPCState *env = opaque;
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-    ppc_tb_t *tb_env = env->tb_env;
-
-    tb_env->tb_freq = freq;
-    tb_env->decr_freq = freq;
-    /* There is a bug in Linux 2.4 kernels:
-     * if a decrementer exception is pending when it enables msr_ee at startup,
-     * it's not ready to handle it...
-     */
-    _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0);
-    _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0);
-    cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
-}
-
-/* Set up (once) timebase frequency (in Hz) */
-clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-    ppc_tb_t *tb_env;
-
-    tb_env = g_malloc0(sizeof(ppc_tb_t));
-    env->tb_env = tb_env;
-    tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
-    /* Create new timer */
-    tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, cpu);
-    if (0) {
-        /* XXX: find a suitable condition to enable the hypervisor decrementer
-         */
-        tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb,
-                                                cpu);
-    } else {
-        tb_env->hdecr_timer = NULL;
-    }
-    cpu_ppc_set_tb_clk(env, freq);
-
-    return &cpu_ppc_set_tb_clk;
-}
-
-/* Specific helpers for POWER & PowerPC 601 RTC */
-#if 0
-static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env)
-{
-    return cpu_ppc_tb_init(env, 7812500);
-}
-#endif
-
-void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value)
-{
-    _cpu_ppc_store_tbu(env, value);
-}
-
-uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env)
-{
-    return _cpu_ppc_load_tbu(env);
-}
-
-void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value)
-{
-    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
-}
-
-uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env)
-{
-    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
-}
-
-/*****************************************************************************/
-/* PowerPC 40x timers */
-
-/* PIT, FIT & WDT */
-typedef struct ppc40x_timer_t ppc40x_timer_t;
-struct ppc40x_timer_t {
-    uint64_t pit_reload;  /* PIT auto-reload value        */
-    uint64_t fit_next;    /* Tick for next FIT interrupt  */
-    struct QEMUTimer *fit_timer;
-    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
-    struct QEMUTimer *wdt_timer;
-
-    /* 405 have the PIT, 440 have a DECR.  */
-    unsigned int decr_excp;
-};
-
-/* Fixed interval timer */
-static void cpu_4xx_fit_cb (void *opaque)
-{
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-    ppc_tb_t *tb_env;
-    ppc40x_timer_t *ppc40x_timer;
-    uint64_t now, next;
-
-    env = opaque;
-    cpu = ppc_env_get_cpu(env);
-    tb_env = env->tb_env;
-    ppc40x_timer = tb_env->opaque;
-    now = qemu_get_clock_ns(vm_clock);
-    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
-    case 0:
-        next = 1 << 9;
-        break;
-    case 1:
-        next = 1 << 13;
-        break;
-    case 2:
-        next = 1 << 17;
-        break;
-    case 3:
-        next = 1 << 21;
-        break;
-    default:
-        /* Cannot occur, but makes gcc happy */
-        return;
-    }
-    next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq);
-    if (next == now)
-        next++;
-    qemu_mod_timer(ppc40x_timer->fit_timer, next);
-    env->spr[SPR_40x_TSR] |= 1 << 26;
-    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
-        ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1);
-    }
-    LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
-           (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
-           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
-}
-
-/* Programmable interval timer */
-static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
-{
-    ppc40x_timer_t *ppc40x_timer;
-    uint64_t now, next;
-
-    ppc40x_timer = tb_env->opaque;
-    if (ppc40x_timer->pit_reload <= 1 ||
-        !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
-        (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
-        /* Stop PIT */
-        LOG_TB("%s: stop PIT\n", __func__);
-        qemu_del_timer(tb_env->decr_timer);
-    } else {
-        LOG_TB("%s: start PIT %016" PRIx64 "\n",
-                    __func__, ppc40x_timer->pit_reload);
-        now = qemu_get_clock_ns(vm_clock);
-        next = now + muldiv64(ppc40x_timer->pit_reload,
-                              get_ticks_per_sec(), tb_env->decr_freq);
-        if (is_excp)
-            next += tb_env->decr_next - now;
-        if (next == now)
-            next++;
-        qemu_mod_timer(tb_env->decr_timer, next);
-        tb_env->decr_next = next;
-    }
-}
-
-static void cpu_4xx_pit_cb (void *opaque)
-{
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-    ppc_tb_t *tb_env;
-    ppc40x_timer_t *ppc40x_timer;
-
-    env = opaque;
-    cpu = ppc_env_get_cpu(env);
-    tb_env = env->tb_env;
-    ppc40x_timer = tb_env->opaque;
-    env->spr[SPR_40x_TSR] |= 1 << 27;
-    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) {
-        ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1);
-    }
-    start_stop_pit(env, tb_env, 1);
-    LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
-           "%016" PRIx64 "\n", __func__,
-           (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
-           (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
-           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
-           ppc40x_timer->pit_reload);
-}
-
-/* Watchdog timer */
-static void cpu_4xx_wdt_cb (void *opaque)
-{
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-    ppc_tb_t *tb_env;
-    ppc40x_timer_t *ppc40x_timer;
-    uint64_t now, next;
-
-    env = opaque;
-    cpu = ppc_env_get_cpu(env);
-    tb_env = env->tb_env;
-    ppc40x_timer = tb_env->opaque;
-    now = qemu_get_clock_ns(vm_clock);
-    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
-    case 0:
-        next = 1 << 17;
-        break;
-    case 1:
-        next = 1 << 21;
-        break;
-    case 2:
-        next = 1 << 25;
-        break;
-    case 3:
-        next = 1 << 29;
-        break;
-    default:
-        /* Cannot occur, but makes gcc happy */
-        return;
-    }
-    next = now + muldiv64(next, get_ticks_per_sec(), tb_env->decr_freq);
-    if (next == now)
-        next++;
-    LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
-           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
-    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
-    case 0x0:
-    case 0x1:
-        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
-        ppc40x_timer->wdt_next = next;
-        env->spr[SPR_40x_TSR] |= 1 << 31;
-        break;
-    case 0x2:
-        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
-        ppc40x_timer->wdt_next = next;
-        env->spr[SPR_40x_TSR] |= 1 << 30;
-        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) {
-            ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1);
-        }
-        break;
-    case 0x3:
-        env->spr[SPR_40x_TSR] &= ~0x30000000;
-        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
-        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
-        case 0x0:
-            /* No reset */
-            break;
-        case 0x1: /* Core reset */
-            ppc40x_core_reset(cpu);
-            break;
-        case 0x2: /* Chip reset */
-            ppc40x_chip_reset(cpu);
-            break;
-        case 0x3: /* System reset */
-            ppc40x_system_reset(cpu);
-            break;
-        }
-    }
-}
-
-void store_40x_pit (CPUPPCState *env, target_ulong val)
-{
-    ppc_tb_t *tb_env;
-    ppc40x_timer_t *ppc40x_timer;
-
-    tb_env = env->tb_env;
-    ppc40x_timer = tb_env->opaque;
-    LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val);
-    ppc40x_timer->pit_reload = val;
-    start_stop_pit(env, tb_env, 0);
-}
-
-target_ulong load_40x_pit (CPUPPCState *env)
-{
-    return cpu_ppc_load_decr(env);
-}
-
-static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
-{
-    CPUPPCState *env = opaque;
-    ppc_tb_t *tb_env = env->tb_env;
-
-    LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__,
-                freq);
-    tb_env->tb_freq = freq;
-    tb_env->decr_freq = freq;
-    /* XXX: we should also update all timers */
-}
-
-clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
-                                  unsigned int decr_excp)
-{
-    ppc_tb_t *tb_env;
-    ppc40x_timer_t *ppc40x_timer;
-
-    tb_env = g_malloc0(sizeof(ppc_tb_t));
-    env->tb_env = tb_env;
-    tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
-    ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t));
-    tb_env->tb_freq = freq;
-    tb_env->decr_freq = freq;
-    tb_env->opaque = ppc40x_timer;
-    LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
-    if (ppc40x_timer != NULL) {
-        /* We use decr timer for PIT */
-        tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env);
-        ppc40x_timer->fit_timer =
-            qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env);
-        ppc40x_timer->wdt_timer =
-            qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env);
-        ppc40x_timer->decr_excp = decr_excp;
-    }
-
-    return &ppc_40x_set_tb_clk;
-}
-
-/*****************************************************************************/
-/* Embedded PowerPC Device Control Registers */
-typedef struct ppc_dcrn_t ppc_dcrn_t;
-struct ppc_dcrn_t {
-    dcr_read_cb dcr_read;
-    dcr_write_cb dcr_write;
-    void *opaque;
-};
-
-/* XXX: on 460, DCR addresses are 32 bits wide,
- *      using DCRIPR to get the 22 upper bits of the DCR address
- */
-#define DCRN_NB 1024
-struct ppc_dcr_t {
-    ppc_dcrn_t dcrn[DCRN_NB];
-    int (*read_error)(int dcrn);
-    int (*write_error)(int dcrn);
-};
-
-int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
-{
-    ppc_dcrn_t *dcr;
-
-    if (dcrn < 0 || dcrn >= DCRN_NB)
-        goto error;
-    dcr = &dcr_env->dcrn[dcrn];
-    if (dcr->dcr_read == NULL)
-        goto error;
-    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
-
-    return 0;
-
- error:
-    if (dcr_env->read_error != NULL)
-        return (*dcr_env->read_error)(dcrn);
-
-    return -1;
-}
-
-int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
-{
-    ppc_dcrn_t *dcr;
-
-    if (dcrn < 0 || dcrn >= DCRN_NB)
-        goto error;
-    dcr = &dcr_env->dcrn[dcrn];
-    if (dcr->dcr_write == NULL)
-        goto error;
-    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
-
-    return 0;
-
- error:
-    if (dcr_env->write_error != NULL)
-        return (*dcr_env->write_error)(dcrn);
-
-    return -1;
-}
-
-int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
-                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
-{
-    ppc_dcr_t *dcr_env;
-    ppc_dcrn_t *dcr;
-
-    dcr_env = env->dcr_env;
-    if (dcr_env == NULL)
-        return -1;
-    if (dcrn < 0 || dcrn >= DCRN_NB)
-        return -1;
-    dcr = &dcr_env->dcrn[dcrn];
-    if (dcr->opaque != NULL ||
-        dcr->dcr_read != NULL ||
-        dcr->dcr_write != NULL)
-        return -1;
-    dcr->opaque = opaque;
-    dcr->dcr_read = dcr_read;
-    dcr->dcr_write = dcr_write;
-
-    return 0;
-}
-
-int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn),
-                  int (*write_error)(int dcrn))
-{
-    ppc_dcr_t *dcr_env;
-
-    dcr_env = g_malloc0(sizeof(ppc_dcr_t));
-    dcr_env->read_error = read_error;
-    dcr_env->write_error = write_error;
-    env->dcr_env = dcr_env;
-
-    return 0;
-}
-
-/*****************************************************************************/
-/* Debug port */
-void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
-{
-    addr &= 0xF;
-    switch (addr) {
-    case 0:
-        printf("%c", val);
-        break;
-    case 1:
-        printf("\n");
-        fflush(stdout);
-        break;
-    case 2:
-        printf("Set loglevel to %04" PRIx32 "\n", val);
-        qemu_set_log(val | 0x100);
-        break;
-    }
-}
-
-/*****************************************************************************/
-/* NVRAM helpers */
-static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr)
-{
-    return (*nvram->read_fn)(nvram->opaque, addr);
-}
-
-static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val)
-{
-    (*nvram->write_fn)(nvram->opaque, addr, val);
-}
-
-static void NVRAM_set_byte(nvram_t *nvram, uint32_t addr, uint8_t value)
-{
-    nvram_write(nvram, addr, value);
-}
-
-static uint8_t NVRAM_get_byte(nvram_t *nvram, uint32_t addr)
-{
-    return nvram_read(nvram, addr);
-}
-
-static void NVRAM_set_word(nvram_t *nvram, uint32_t addr, uint16_t value)
-{
-    nvram_write(nvram, addr, value >> 8);
-    nvram_write(nvram, addr + 1, value & 0xFF);
-}
-
-static uint16_t NVRAM_get_word(nvram_t *nvram, uint32_t addr)
-{
-    uint16_t tmp;
-
-    tmp = nvram_read(nvram, addr) << 8;
-    tmp |= nvram_read(nvram, addr + 1);
-
-    return tmp;
-}
-
-static void NVRAM_set_lword(nvram_t *nvram, uint32_t addr, uint32_t value)
-{
-    nvram_write(nvram, addr, value >> 24);
-    nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
-    nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
-    nvram_write(nvram, addr + 3, value & 0xFF);
-}
-
-uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr)
-{
-    uint32_t tmp;
-
-    tmp = nvram_read(nvram, addr) << 24;
-    tmp |= nvram_read(nvram, addr + 1) << 16;
-    tmp |= nvram_read(nvram, addr + 2) << 8;
-    tmp |= nvram_read(nvram, addr + 3);
-
-    return tmp;
-}
-
-static void NVRAM_set_string(nvram_t *nvram, uint32_t addr, const char *str,
-                             uint32_t max)
-{
-    int i;
-
-    for (i = 0; i < max && str[i] != '\0'; i++) {
-        nvram_write(nvram, addr + i, str[i]);
-    }
-    nvram_write(nvram, addr + i, str[i]);
-    nvram_write(nvram, addr + max - 1, '\0');
-}
-
-int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max)
-{
-    int i;
-
-    memset(dst, 0, max);
-    for (i = 0; i < max; i++) {
-        dst[i] = NVRAM_get_byte(nvram, addr + i);
-        if (dst[i] == '\0')
-            break;
-    }
-
-    return i;
-}
-
-static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
-{
-    uint16_t tmp;
-    uint16_t pd, pd1, pd2;
-
-    tmp = prev >> 8;
-    pd = prev ^ value;
-    pd1 = pd & 0x000F;
-    pd2 = ((pd >> 4) & 0x000F) ^ pd1;
-    tmp ^= (pd1 << 3) | (pd1 << 8);
-    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
-
-    return tmp;
-}
-
-static uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count)
-{
-    uint32_t i;
-    uint16_t crc = 0xFFFF;
-    int odd;
-
-    odd = count & 1;
-    count &= ~1;
-    for (i = 0; i != count; i++) {
-        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
-    }
-    if (odd) {
-        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
-    }
-
-    return crc;
-}
-
-#define CMDLINE_ADDR 0x017ff000
-
-int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
-                          const char *arch,
-                          uint32_t RAM_size, int boot_device,
-                          uint32_t kernel_image, uint32_t kernel_size,
-                          const char *cmdline,
-                          uint32_t initrd_image, uint32_t initrd_size,
-                          uint32_t NVRAM_image,
-                          int width, int height, int depth)
-{
-    uint16_t crc;
-
-    /* Set parameters for Open Hack'Ware BIOS */
-    NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
-    NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
-    NVRAM_set_word(nvram,   0x14, NVRAM_size);
-    NVRAM_set_string(nvram, 0x20, arch, 16);
-    NVRAM_set_lword(nvram,  0x30, RAM_size);
-    NVRAM_set_byte(nvram,   0x34, boot_device);
-    NVRAM_set_lword(nvram,  0x38, kernel_image);
-    NVRAM_set_lword(nvram,  0x3C, kernel_size);
-    if (cmdline) {
-        /* XXX: put the cmdline in NVRAM too ? */
-        pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline);
-        NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
-        NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
-    } else {
-        NVRAM_set_lword(nvram,  0x40, 0);
-        NVRAM_set_lword(nvram,  0x44, 0);
-    }
-    NVRAM_set_lword(nvram,  0x48, initrd_image);
-    NVRAM_set_lword(nvram,  0x4C, initrd_size);
-    NVRAM_set_lword(nvram,  0x50, NVRAM_image);
-
-    NVRAM_set_word(nvram,   0x54, width);
-    NVRAM_set_word(nvram,   0x56, height);
-    NVRAM_set_word(nvram,   0x58, depth);
-    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
-    NVRAM_set_word(nvram,   0xFC, crc);
-
-    return 0;
-}
index 9141373f40a2243af82d46ec407bd5d3f66a5cdb..294d0de2119c3c4341acf5213ecdee4782e9d1f9 100644 (file)
@@ -1,19 +1,14 @@
-# shared objects
-obj-y = ppc.o ppc_booke.o
 # PREP target
 obj-y += mc146818rtc.o
 # IBM pSeries (sPAPR)
-obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
+obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o spapr_vio.o
 obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
 obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o
 obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o
 # PowerPC 4xx boards
-obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
-obj-y += ppc440_bamboo.o
+obj-y += ppc4xx_devs.o ppc4xx_pci.o
 # PowerPC E500 boards
 obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o
-# PowerPC 440 Xilinx ML507 reference board.
-obj-y += virtex_ml507.o
 # PowerPC OpenPIC
 obj-y += openpic.o
 
@@ -22,6 +17,12 @@ obj-y += xilinx_ethlite.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
+# shared objects
+obj-y += ppc.o ppc_booke.o
+# IBM pSeries (sPAPR)
+obj-$(CONFIG_PSERIES) += spapr.o
+# PowerPC 4xx boards
+obj-y += ppc405_boards.o ppc405_uc.o ppc440_bamboo.o
 # PReP
 obj-y += prep.o
 # OldWorld PowerMac
@@ -30,3 +31,5 @@ obj-y += mac_oldworld.o
 obj-y += mac_newworld.o
 # e500
 obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
+# PowerPC 440 Xilinx ML507 reference board.
+obj-y += virtex_ml507.o
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
new file mode 100644 (file)
index 0000000..c9437fc
--- /dev/null
@@ -0,0 +1,1356 @@
+/*
+ * QEMU generic PowerPC hardware System Emulator
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "hw/ppc.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "hw/nvram.h"
+#include "qemu/log.h"
+#include "hw/loader.h"
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+
+//#define PPC_DEBUG_IRQ
+//#define PPC_DEBUG_TB
+
+#ifdef PPC_DEBUG_IRQ
+#  define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
+#else
+#  define LOG_IRQ(...) do { } while (0)
+#endif
+
+
+#ifdef PPC_DEBUG_TB
+#  define LOG_TB(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_TB(...) do { } while (0)
+#endif
+
+static void cpu_ppc_tb_stop (CPUPPCState *env);
+static void cpu_ppc_tb_start (CPUPPCState *env);
+
+void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
+{
+    CPUPPCState *env = &cpu->env;
+    unsigned int old_pending = env->pending_interrupts;
+
+    if (level) {
+        env->pending_interrupts |= 1 << n_IRQ;
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        env->pending_interrupts &= ~(1 << n_IRQ);
+        if (env->pending_interrupts == 0)
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+
+    if (old_pending != env->pending_interrupts) {
+#ifdef CONFIG_KVM
+        kvmppc_set_interrupt(cpu, n_IRQ, level);
+#endif
+    }
+
+    LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
+                "req %08x\n", __func__, env, n_IRQ, level,
+                env->pending_interrupts, env->interrupt_request);
+}
+
+/* PowerPC 6xx / 7xx internal IRQ controller */
+static void ppc6xx_set_irq(void *opaque, int pin, int level)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    int cur_level;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPC6xx_INPUT_TBEN:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: %s the time base\n",
+                        __func__, level ? "start" : "stop");
+            if (level) {
+                cpu_ppc_tb_start(env);
+            } else {
+                cpu_ppc_tb_stop(env);
+            }
+        case PPC6xx_INPUT_INT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the external IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPC6xx_INPUT_SMI:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the SMI IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level);
+            break;
+        case PPC6xx_INPUT_MCP:
+            /* Negative edge sensitive */
+            /* XXX: TODO: actual reaction may depends on HID0 status
+             *            603/604/740/750: check HID0[EMCP]
+             */
+            if (cur_level == 1 && level == 0) {
+                LOG_IRQ("%s: raise machine check state\n",
+                            __func__);
+                ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
+            }
+            break;
+        case PPC6xx_INPUT_CKSTP_IN:
+            /* Level sensitive - active low */
+            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
+            /* XXX: Note that the only way to restart the CPU is to reset it */
+            if (level) {
+                LOG_IRQ("%s: stop the CPU\n", __func__);
+                env->halted = 1;
+            }
+            break;
+        case PPC6xx_INPUT_HRESET:
+            /* Level sensitive - active low */
+            if (level) {
+                LOG_IRQ("%s: reset the CPU\n", __func__);
+                cpu_interrupt(env, CPU_INTERRUPT_RESET);
+            }
+            break;
+        case PPC6xx_INPUT_SRESET:
+            LOG_IRQ("%s: set the RESET IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
+            break;
+        default:
+            /* Unknown pin - do nothing */
+            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppc6xx_irq_init(CPUPPCState *env)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu,
+                                                  PPC6xx_INPUT_NB);
+}
+
+#if defined(TARGET_PPC64)
+/* PowerPC 970 internal IRQ controller */
+static void ppc970_set_irq(void *opaque, int pin, int level)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    int cur_level;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPC970_INPUT_INT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the external IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPC970_INPUT_THINT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__,
+                        level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level);
+            break;
+        case PPC970_INPUT_MCP:
+            /* Negative edge sensitive */
+            /* XXX: TODO: actual reaction may depends on HID0 status
+             *            603/604/740/750: check HID0[EMCP]
+             */
+            if (cur_level == 1 && level == 0) {
+                LOG_IRQ("%s: raise machine check state\n",
+                            __func__);
+                ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
+            }
+            break;
+        case PPC970_INPUT_CKSTP:
+            /* Level sensitive - active low */
+            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
+            if (level) {
+                LOG_IRQ("%s: stop the CPU\n", __func__);
+                env->halted = 1;
+            } else {
+                LOG_IRQ("%s: restart the CPU\n", __func__);
+                env->halted = 0;
+                qemu_cpu_kick(CPU(cpu));
+            }
+            break;
+        case PPC970_INPUT_HRESET:
+            /* Level sensitive - active low */
+            if (level) {
+                cpu_interrupt(env, CPU_INTERRUPT_RESET);
+            }
+            break;
+        case PPC970_INPUT_SRESET:
+            LOG_IRQ("%s: set the RESET IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
+            break;
+        case PPC970_INPUT_TBEN:
+            LOG_IRQ("%s: set the TBEN state to %d\n", __func__,
+                        level);
+            /* XXX: TODO */
+            break;
+        default:
+            /* Unknown pin - do nothing */
+            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppc970_irq_init(CPUPPCState *env)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu,
+                                                  PPC970_INPUT_NB);
+}
+
+/* POWER7 internal IRQ controller */
+static void power7_set_irq(void *opaque, int pin, int level)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+
+    switch (pin) {
+    case POWER7_INPUT_INT:
+        /* Level sensitive - active high */
+        LOG_IRQ("%s: set the external IRQ state to %d\n",
+                __func__, level);
+        ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
+        break;
+    default:
+        /* Unknown pin - do nothing */
+        LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+        return;
+    }
+    if (level) {
+        env->irq_input_state |= 1 << pin;
+    } else {
+        env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppcPOWER7_irq_init(CPUPPCState *env)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+    env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu,
+                                                  POWER7_INPUT_NB);
+}
+#endif /* defined(TARGET_PPC64) */
+
+/* PowerPC 40x internal IRQ controller */
+static void ppc40x_set_irq(void *opaque, int pin, int level)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    int cur_level;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPC40x_INPUT_RESET_SYS:
+            if (level) {
+                LOG_IRQ("%s: reset the PowerPC system\n",
+                            __func__);
+                ppc40x_system_reset(cpu);
+            }
+            break;
+        case PPC40x_INPUT_RESET_CHIP:
+            if (level) {
+                LOG_IRQ("%s: reset the PowerPC chip\n", __func__);
+                ppc40x_chip_reset(cpu);
+            }
+            break;
+        case PPC40x_INPUT_RESET_CORE:
+            /* XXX: TODO: update DBSR[MRR] */
+            if (level) {
+                LOG_IRQ("%s: reset the PowerPC core\n", __func__);
+                ppc40x_core_reset(cpu);
+            }
+            break;
+        case PPC40x_INPUT_CINT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the critical IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
+            break;
+        case PPC40x_INPUT_INT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the external IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPC40x_INPUT_HALT:
+            /* Level sensitive - active low */
+            if (level) {
+                LOG_IRQ("%s: stop the CPU\n", __func__);
+                env->halted = 1;
+            } else {
+                LOG_IRQ("%s: restart the CPU\n", __func__);
+                env->halted = 0;
+                qemu_cpu_kick(CPU(cpu));
+            }
+            break;
+        case PPC40x_INPUT_DEBUG:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the debug pin state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
+            break;
+        default:
+            /* Unknown pin - do nothing */
+            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppc40x_irq_init(CPUPPCState *env)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
+                                                  cpu, PPC40x_INPUT_NB);
+}
+
+/* PowerPC E500 internal IRQ controller */
+static void ppce500_set_irq(void *opaque, int pin, int level)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    int cur_level;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPCE500_INPUT_MCK:
+            if (level) {
+                LOG_IRQ("%s: reset the PowerPC system\n",
+                            __func__);
+                qemu_system_reset_request();
+            }
+            break;
+        case PPCE500_INPUT_RESET_CORE:
+            if (level) {
+                LOG_IRQ("%s: reset the PowerPC core\n", __func__);
+                ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level);
+            }
+            break;
+        case PPCE500_INPUT_CINT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the critical IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
+            break;
+        case PPCE500_INPUT_INT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the core IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPCE500_INPUT_DEBUG:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the debug pin state to %d\n",
+                        __func__, level);
+            ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
+            break;
+        default:
+            /* Unknown pin - do nothing */
+            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppce500_irq_init(CPUPPCState *env)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq,
+                                                  cpu, PPCE500_INPUT_NB);
+}
+
+/* Enable or Disable the E500 EPR capability */
+void ppce500_set_mpic_proxy(bool enabled)
+{
+    CPUPPCState *env;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        PowerPCCPU *cpu = ppc_env_get_cpu(env);
+        CPUState *cs = CPU(cpu);
+
+        env->mpic_proxy = enabled;
+        if (kvm_enabled()) {
+            kvmppc_set_mpic_proxy(POWERPC_CPU(cs), enabled);
+        }
+    }
+}
+
+/*****************************************************************************/
+/* PowerPC time base and decrementer emulation */
+
+uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
+{
+    /* TB time in tb periods */
+    return muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()) + tb_offset;
+}
+
+uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    if (kvm_enabled()) {
+        return env->spr[SPR_TBL];
+    }
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
+
+    return tb;
+}
+
+static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
+
+    return tb >> 32;
+}
+
+uint32_t cpu_ppc_load_tbu (CPUPPCState *env)
+{
+    if (kvm_enabled()) {
+        return env->spr[SPR_TBU];
+    }
+
+    return _cpu_ppc_load_tbu(env);
+}
+
+static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
+                                    int64_t *tb_offsetp, uint64_t value)
+{
+    *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec());
+    LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n",
+                __func__, value, *tb_offsetp);
+}
+
+void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+    tb &= 0xFFFFFFFF00000000ULL;
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+                     &tb_env->tb_offset, tb | (uint64_t)value);
+}
+
+static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+    tb &= 0x00000000FFFFFFFFULL;
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+                     &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
+}
+
+void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value)
+{
+    _cpu_ppc_store_tbu(env, value);
+}
+
+uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
+
+    return tb;
+}
+
+uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
+
+    return tb >> 32;
+}
+
+void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+    tb &= 0xFFFFFFFF00000000ULL;
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+                     &tb_env->atb_offset, tb | (uint64_t)value);
+}
+
+void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+    tb &= 0x00000000FFFFFFFFULL;
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+                     &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
+}
+
+static void cpu_ppc_tb_stop (CPUPPCState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb, atb, vmclk;
+
+    /* If the time base is already frozen, do nothing */
+    if (tb_env->tb_freq != 0) {
+        vmclk = qemu_get_clock_ns(vm_clock);
+        /* Get the time base */
+        tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
+        /* Get the alternate time base */
+        atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
+        /* Store the time base value (ie compute the current offset) */
+        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
+        /* Store the alternate time base value (compute the current offset) */
+        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
+        /* Set the time base frequency to zero */
+        tb_env->tb_freq = 0;
+        /* Now, the time bases are frozen to tb_offset / atb_offset value */
+    }
+}
+
+static void cpu_ppc_tb_start (CPUPPCState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb, atb, vmclk;
+
+    /* If the time base is not frozen, do nothing */
+    if (tb_env->tb_freq == 0) {
+        vmclk = qemu_get_clock_ns(vm_clock);
+        /* Get the time base from tb_offset */
+        tb = tb_env->tb_offset;
+        /* Get the alternate time base from atb_offset */
+        atb = tb_env->atb_offset;
+        /* Restore the tb frequency from the decrementer frequency */
+        tb_env->tb_freq = tb_env->decr_freq;
+        /* Store the time base value */
+        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
+        /* Store the alternate time base value */
+        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
+    }
+}
+
+static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint32_t decr;
+    int64_t diff;
+
+    diff = next - qemu_get_clock_ns(vm_clock);
+    if (diff >= 0) {
+        decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec());
+    } else if (tb_env->flags & PPC_TIMER_BOOKE) {
+        decr = 0;
+    }  else {
+        decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec());
+    }
+    LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
+
+    return decr;
+}
+
+uint32_t cpu_ppc_load_decr (CPUPPCState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    if (kvm_enabled()) {
+        return env->spr[SPR_DECR];
+    }
+
+    return _cpu_ppc_load_decr(env, tb_env->decr_next);
+}
+
+uint32_t cpu_ppc_load_hdecr (CPUPPCState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    return _cpu_ppc_load_decr(env, tb_env->hdecr_next);
+}
+
+uint64_t cpu_ppc_load_purr (CPUPPCState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t diff;
+
+    diff = qemu_get_clock_ns(vm_clock) - tb_env->purr_start;
+
+    return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, get_ticks_per_sec());
+}
+
+/* When decrementer expires,
+ * all we need to do is generate or queue a CPU exception
+ */
+static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
+{
+    /* Raise it */
+    LOG_TB("raise decrementer exception\n");
+    ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
+}
+
+static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
+{
+    /* Raise it */
+    LOG_TB("raise decrementer exception\n");
+    ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
+}
+
+static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
+                                 struct QEMUTimer *timer,
+                                 void (*raise_excp)(PowerPCCPU *),
+                                 uint32_t decr, uint32_t value,
+                                 int is_excp)
+{
+    CPUPPCState *env = &cpu->env;
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t now, next;
+
+    LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
+                decr, value);
+
+    if (kvm_enabled()) {
+        /* KVM handles decrementer exceptions, we don't need our own timer */
+        return;
+    }
+
+    now = qemu_get_clock_ns(vm_clock);
+    next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
+    if (is_excp) {
+        next += *nextp - now;
+    }
+    if (next == now) {
+        next++;
+    }
+    *nextp = next;
+    /* Adjust timer */
+    qemu_mod_timer(timer, next);
+
+    /* If we set a negative value and the decrementer was positive, raise an
+     * exception.
+     */
+    if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED)
+        && (value & 0x80000000)
+        && !(decr & 0x80000000)) {
+        (*raise_excp)(cpu);
+    }
+}
+
+static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
+                                       uint32_t value, int is_excp)
+{
+    ppc_tb_t *tb_env = cpu->env.tb_env;
+
+    __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
+                         &cpu_ppc_decr_excp, decr, value, is_excp);
+}
+
+void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+    _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0);
+}
+
+static void cpu_ppc_decr_cb(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+
+    _cpu_ppc_store_decr(cpu, 0x00000000, 0xFFFFFFFF, 1);
+}
+
+static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
+                                        uint32_t value, int is_excp)
+{
+    ppc_tb_t *tb_env = cpu->env.tb_env;
+
+    if (tb_env->hdecr_timer != NULL) {
+        __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
+                             &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
+    }
+}
+
+void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+    _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0);
+}
+
+static void cpu_ppc_hdecr_cb(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+
+    _cpu_ppc_store_hdecr(cpu, 0x00000000, 0xFFFFFFFF, 1);
+}
+
+static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
+{
+    ppc_tb_t *tb_env = cpu->env.tb_env;
+
+    tb_env->purr_load = value;
+    tb_env->purr_start = qemu_get_clock_ns(vm_clock);
+}
+
+static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
+{
+    CPUPPCState *env = opaque;
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+    ppc_tb_t *tb_env = env->tb_env;
+
+    tb_env->tb_freq = freq;
+    tb_env->decr_freq = freq;
+    /* There is a bug in Linux 2.4 kernels:
+     * if a decrementer exception is pending when it enables msr_ee at startup,
+     * it's not ready to handle it...
+     */
+    _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+    _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+    cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
+}
+
+/* Set up (once) timebase frequency (in Hz) */
+clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+    ppc_tb_t *tb_env;
+
+    tb_env = g_malloc0(sizeof(ppc_tb_t));
+    env->tb_env = tb_env;
+    tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
+    /* Create new timer */
+    tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, cpu);
+    if (0) {
+        /* XXX: find a suitable condition to enable the hypervisor decrementer
+         */
+        tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb,
+                                                cpu);
+    } else {
+        tb_env->hdecr_timer = NULL;
+    }
+    cpu_ppc_set_tb_clk(env, freq);
+
+    return &cpu_ppc_set_tb_clk;
+}
+
+/* Specific helpers for POWER & PowerPC 601 RTC */
+#if 0
+static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env)
+{
+    return cpu_ppc_tb_init(env, 7812500);
+}
+#endif
+
+void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value)
+{
+    _cpu_ppc_store_tbu(env, value);
+}
+
+uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env)
+{
+    return _cpu_ppc_load_tbu(env);
+}
+
+void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value)
+{
+    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
+}
+
+uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env)
+{
+    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
+}
+
+/*****************************************************************************/
+/* PowerPC 40x timers */
+
+/* PIT, FIT & WDT */
+typedef struct ppc40x_timer_t ppc40x_timer_t;
+struct ppc40x_timer_t {
+    uint64_t pit_reload;  /* PIT auto-reload value        */
+    uint64_t fit_next;    /* Tick for next FIT interrupt  */
+    struct QEMUTimer *fit_timer;
+    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
+    struct QEMUTimer *wdt_timer;
+
+    /* 405 have the PIT, 440 have a DECR.  */
+    unsigned int decr_excp;
+};
+
+/* Fixed interval timer */
+static void cpu_4xx_fit_cb (void *opaque)
+{
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    ppc_tb_t *tb_env;
+    ppc40x_timer_t *ppc40x_timer;
+    uint64_t now, next;
+
+    env = opaque;
+    cpu = ppc_env_get_cpu(env);
+    tb_env = env->tb_env;
+    ppc40x_timer = tb_env->opaque;
+    now = qemu_get_clock_ns(vm_clock);
+    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
+    case 0:
+        next = 1 << 9;
+        break;
+    case 1:
+        next = 1 << 13;
+        break;
+    case 2:
+        next = 1 << 17;
+        break;
+    case 3:
+        next = 1 << 21;
+        break;
+    default:
+        /* Cannot occur, but makes gcc happy */
+        return;
+    }
+    next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq);
+    if (next == now)
+        next++;
+    qemu_mod_timer(ppc40x_timer->fit_timer, next);
+    env->spr[SPR_40x_TSR] |= 1 << 26;
+    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
+        ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1);
+    }
+    LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
+           (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
+           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
+}
+
+/* Programmable interval timer */
+static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
+{
+    ppc40x_timer_t *ppc40x_timer;
+    uint64_t now, next;
+
+    ppc40x_timer = tb_env->opaque;
+    if (ppc40x_timer->pit_reload <= 1 ||
+        !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
+        (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
+        /* Stop PIT */
+        LOG_TB("%s: stop PIT\n", __func__);
+        qemu_del_timer(tb_env->decr_timer);
+    } else {
+        LOG_TB("%s: start PIT %016" PRIx64 "\n",
+                    __func__, ppc40x_timer->pit_reload);
+        now = qemu_get_clock_ns(vm_clock);
+        next = now + muldiv64(ppc40x_timer->pit_reload,
+                              get_ticks_per_sec(), tb_env->decr_freq);
+        if (is_excp)
+            next += tb_env->decr_next - now;
+        if (next == now)
+            next++;
+        qemu_mod_timer(tb_env->decr_timer, next);
+        tb_env->decr_next = next;
+    }
+}
+
+static void cpu_4xx_pit_cb (void *opaque)
+{
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    ppc_tb_t *tb_env;
+    ppc40x_timer_t *ppc40x_timer;
+
+    env = opaque;
+    cpu = ppc_env_get_cpu(env);
+    tb_env = env->tb_env;
+    ppc40x_timer = tb_env->opaque;
+    env->spr[SPR_40x_TSR] |= 1 << 27;
+    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) {
+        ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1);
+    }
+    start_stop_pit(env, tb_env, 1);
+    LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
+           "%016" PRIx64 "\n", __func__,
+           (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
+           (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
+           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
+           ppc40x_timer->pit_reload);
+}
+
+/* Watchdog timer */
+static void cpu_4xx_wdt_cb (void *opaque)
+{
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    ppc_tb_t *tb_env;
+    ppc40x_timer_t *ppc40x_timer;
+    uint64_t now, next;
+
+    env = opaque;
+    cpu = ppc_env_get_cpu(env);
+    tb_env = env->tb_env;
+    ppc40x_timer = tb_env->opaque;
+    now = qemu_get_clock_ns(vm_clock);
+    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
+    case 0:
+        next = 1 << 17;
+        break;
+    case 1:
+        next = 1 << 21;
+        break;
+    case 2:
+        next = 1 << 25;
+        break;
+    case 3:
+        next = 1 << 29;
+        break;
+    default:
+        /* Cannot occur, but makes gcc happy */
+        return;
+    }
+    next = now + muldiv64(next, get_ticks_per_sec(), tb_env->decr_freq);
+    if (next == now)
+        next++;
+    LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
+           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
+    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
+    case 0x0:
+    case 0x1:
+        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
+        ppc40x_timer->wdt_next = next;
+        env->spr[SPR_40x_TSR] |= 1 << 31;
+        break;
+    case 0x2:
+        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
+        ppc40x_timer->wdt_next = next;
+        env->spr[SPR_40x_TSR] |= 1 << 30;
+        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) {
+            ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1);
+        }
+        break;
+    case 0x3:
+        env->spr[SPR_40x_TSR] &= ~0x30000000;
+        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
+        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
+        case 0x0:
+            /* No reset */
+            break;
+        case 0x1: /* Core reset */
+            ppc40x_core_reset(cpu);
+            break;
+        case 0x2: /* Chip reset */
+            ppc40x_chip_reset(cpu);
+            break;
+        case 0x3: /* System reset */
+            ppc40x_system_reset(cpu);
+            break;
+        }
+    }
+}
+
+void store_40x_pit (CPUPPCState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env;
+    ppc40x_timer_t *ppc40x_timer;
+
+    tb_env = env->tb_env;
+    ppc40x_timer = tb_env->opaque;
+    LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val);
+    ppc40x_timer->pit_reload = val;
+    start_stop_pit(env, tb_env, 0);
+}
+
+target_ulong load_40x_pit (CPUPPCState *env)
+{
+    return cpu_ppc_load_decr(env);
+}
+
+static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
+{
+    CPUPPCState *env = opaque;
+    ppc_tb_t *tb_env = env->tb_env;
+
+    LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__,
+                freq);
+    tb_env->tb_freq = freq;
+    tb_env->decr_freq = freq;
+    /* XXX: we should also update all timers */
+}
+
+clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
+                                  unsigned int decr_excp)
+{
+    ppc_tb_t *tb_env;
+    ppc40x_timer_t *ppc40x_timer;
+
+    tb_env = g_malloc0(sizeof(ppc_tb_t));
+    env->tb_env = tb_env;
+    tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
+    ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t));
+    tb_env->tb_freq = freq;
+    tb_env->decr_freq = freq;
+    tb_env->opaque = ppc40x_timer;
+    LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
+    if (ppc40x_timer != NULL) {
+        /* We use decr timer for PIT */
+        tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env);
+        ppc40x_timer->fit_timer =
+            qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env);
+        ppc40x_timer->wdt_timer =
+            qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env);
+        ppc40x_timer->decr_excp = decr_excp;
+    }
+
+    return &ppc_40x_set_tb_clk;
+}
+
+/*****************************************************************************/
+/* Embedded PowerPC Device Control Registers */
+typedef struct ppc_dcrn_t ppc_dcrn_t;
+struct ppc_dcrn_t {
+    dcr_read_cb dcr_read;
+    dcr_write_cb dcr_write;
+    void *opaque;
+};
+
+/* XXX: on 460, DCR addresses are 32 bits wide,
+ *      using DCRIPR to get the 22 upper bits of the DCR address
+ */
+#define DCRN_NB 1024
+struct ppc_dcr_t {
+    ppc_dcrn_t dcrn[DCRN_NB];
+    int (*read_error)(int dcrn);
+    int (*write_error)(int dcrn);
+};
+
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
+{
+    ppc_dcrn_t *dcr;
+
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        goto error;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->dcr_read == NULL)
+        goto error;
+    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
+
+    return 0;
+
+ error:
+    if (dcr_env->read_error != NULL)
+        return (*dcr_env->read_error)(dcrn);
+
+    return -1;
+}
+
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
+{
+    ppc_dcrn_t *dcr;
+
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        goto error;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->dcr_write == NULL)
+        goto error;
+    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
+
+    return 0;
+
+ error:
+    if (dcr_env->write_error != NULL)
+        return (*dcr_env->write_error)(dcrn);
+
+    return -1;
+}
+
+int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
+                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
+{
+    ppc_dcr_t *dcr_env;
+    ppc_dcrn_t *dcr;
+
+    dcr_env = env->dcr_env;
+    if (dcr_env == NULL)
+        return -1;
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        return -1;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->opaque != NULL ||
+        dcr->dcr_read != NULL ||
+        dcr->dcr_write != NULL)
+        return -1;
+    dcr->opaque = opaque;
+    dcr->dcr_read = dcr_read;
+    dcr->dcr_write = dcr_write;
+
+    return 0;
+}
+
+int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn),
+                  int (*write_error)(int dcrn))
+{
+    ppc_dcr_t *dcr_env;
+
+    dcr_env = g_malloc0(sizeof(ppc_dcr_t));
+    dcr_env->read_error = read_error;
+    dcr_env->write_error = write_error;
+    env->dcr_env = dcr_env;
+
+    return 0;
+}
+
+/*****************************************************************************/
+/* Debug port */
+void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
+{
+    addr &= 0xF;
+    switch (addr) {
+    case 0:
+        printf("%c", val);
+        break;
+    case 1:
+        printf("\n");
+        fflush(stdout);
+        break;
+    case 2:
+        printf("Set loglevel to %04" PRIx32 "\n", val);
+        qemu_set_log(val | 0x100);
+        break;
+    }
+}
+
+/*****************************************************************************/
+/* NVRAM helpers */
+static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr)
+{
+    return (*nvram->read_fn)(nvram->opaque, addr);
+}
+
+static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val)
+{
+    (*nvram->write_fn)(nvram->opaque, addr, val);
+}
+
+static void NVRAM_set_byte(nvram_t *nvram, uint32_t addr, uint8_t value)
+{
+    nvram_write(nvram, addr, value);
+}
+
+static uint8_t NVRAM_get_byte(nvram_t *nvram, uint32_t addr)
+{
+    return nvram_read(nvram, addr);
+}
+
+static void NVRAM_set_word(nvram_t *nvram, uint32_t addr, uint16_t value)
+{
+    nvram_write(nvram, addr, value >> 8);
+    nvram_write(nvram, addr + 1, value & 0xFF);
+}
+
+static uint16_t NVRAM_get_word(nvram_t *nvram, uint32_t addr)
+{
+    uint16_t tmp;
+
+    tmp = nvram_read(nvram, addr) << 8;
+    tmp |= nvram_read(nvram, addr + 1);
+
+    return tmp;
+}
+
+static void NVRAM_set_lword(nvram_t *nvram, uint32_t addr, uint32_t value)
+{
+    nvram_write(nvram, addr, value >> 24);
+    nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
+    nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
+    nvram_write(nvram, addr + 3, value & 0xFF);
+}
+
+uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr)
+{
+    uint32_t tmp;
+
+    tmp = nvram_read(nvram, addr) << 24;
+    tmp |= nvram_read(nvram, addr + 1) << 16;
+    tmp |= nvram_read(nvram, addr + 2) << 8;
+    tmp |= nvram_read(nvram, addr + 3);
+
+    return tmp;
+}
+
+static void NVRAM_set_string(nvram_t *nvram, uint32_t addr, const char *str,
+                             uint32_t max)
+{
+    int i;
+
+    for (i = 0; i < max && str[i] != '\0'; i++) {
+        nvram_write(nvram, addr + i, str[i]);
+    }
+    nvram_write(nvram, addr + i, str[i]);
+    nvram_write(nvram, addr + max - 1, '\0');
+}
+
+int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max)
+{
+    int i;
+
+    memset(dst, 0, max);
+    for (i = 0; i < max; i++) {
+        dst[i] = NVRAM_get_byte(nvram, addr + i);
+        if (dst[i] == '\0')
+            break;
+    }
+
+    return i;
+}
+
+static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
+{
+    uint16_t tmp;
+    uint16_t pd, pd1, pd2;
+
+    tmp = prev >> 8;
+    pd = prev ^ value;
+    pd1 = pd & 0x000F;
+    pd2 = ((pd >> 4) & 0x000F) ^ pd1;
+    tmp ^= (pd1 << 3) | (pd1 << 8);
+    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
+
+    return tmp;
+}
+
+static uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count)
+{
+    uint32_t i;
+    uint16_t crc = 0xFFFF;
+    int odd;
+
+    odd = count & 1;
+    count &= ~1;
+    for (i = 0; i != count; i++) {
+        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
+    }
+    if (odd) {
+        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
+    }
+
+    return crc;
+}
+
+#define CMDLINE_ADDR 0x017ff000
+
+int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
+                          const char *arch,
+                          uint32_t RAM_size, int boot_device,
+                          uint32_t kernel_image, uint32_t kernel_size,
+                          const char *cmdline,
+                          uint32_t initrd_image, uint32_t initrd_size,
+                          uint32_t NVRAM_image,
+                          int width, int height, int depth)
+{
+    uint16_t crc;
+
+    /* Set parameters for Open Hack'Ware BIOS */
+    NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
+    NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
+    NVRAM_set_word(nvram,   0x14, NVRAM_size);
+    NVRAM_set_string(nvram, 0x20, arch, 16);
+    NVRAM_set_lword(nvram,  0x30, RAM_size);
+    NVRAM_set_byte(nvram,   0x34, boot_device);
+    NVRAM_set_lword(nvram,  0x38, kernel_image);
+    NVRAM_set_lword(nvram,  0x3C, kernel_size);
+    if (cmdline) {
+        /* XXX: put the cmdline in NVRAM too ? */
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline);
+        NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
+        NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
+    } else {
+        NVRAM_set_lword(nvram,  0x40, 0);
+        NVRAM_set_lword(nvram,  0x44, 0);
+    }
+    NVRAM_set_lword(nvram,  0x48, initrd_image);
+    NVRAM_set_lword(nvram,  0x4C, initrd_size);
+    NVRAM_set_lword(nvram,  0x50, NVRAM_image);
+
+    NVRAM_set_word(nvram,   0x54, width);
+    NVRAM_set_word(nvram,   0x56, height);
+    NVRAM_set_word(nvram,   0x58, depth);
+    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
+    NVRAM_set_word(nvram,   0xFC, crc);
+
+    return 0;
+}
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
new file mode 100644 (file)
index 0000000..ba443cf
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * QEMU PowerPC 405 evaluation boards emulation
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "hw/ppc.h"
+#include "hw/ppc405.h"
+#include "hw/nvram.h"
+#include "hw/flash.h"
+#include "sysemu/sysemu.h"
+#include "block/block.h"
+#include "hw/boards.h"
+#include "qemu/log.h"
+#include "hw/loader.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+#define BIOS_FILENAME "ppc405_rom.bin"
+#define BIOS_SIZE (2048 * 1024)
+
+#define KERNEL_LOAD_ADDR 0x00000000
+#define INITRD_LOAD_ADDR 0x01800000
+
+#define USE_FLASH_BIOS
+
+#define DEBUG_BOARD_INIT
+
+/*****************************************************************************/
+/* PPC405EP reference board (IBM) */
+/* Standalone board with:
+ * - PowerPC 405EP CPU
+ * - SDRAM (0x00000000)
+ * - Flash (0xFFF80000)
+ * - SRAM  (0xFFF00000)
+ * - NVRAM (0xF0000000)
+ * - FPGA  (0xF0300000)
+ */
+typedef struct ref405ep_fpga_t ref405ep_fpga_t;
+struct ref405ep_fpga_t {
+    uint8_t reg0;
+    uint8_t reg1;
+};
+
+static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr)
+{
+    ref405ep_fpga_t *fpga;
+    uint32_t ret;
+
+    fpga = opaque;
+    switch (addr) {
+    case 0x0:
+        ret = fpga->reg0;
+        break;
+    case 0x1:
+        ret = fpga->reg1;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void ref405ep_fpga_writeb (void *opaque,
+                                  hwaddr addr, uint32_t value)
+{
+    ref405ep_fpga_t *fpga;
+
+    fpga = opaque;
+    switch (addr) {
+    case 0x0:
+        /* Read only */
+        break;
+    case 0x1:
+        fpga->reg1 = value;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t ref405ep_fpga_readw (void *opaque, hwaddr addr)
+{
+    uint32_t ret;
+
+    ret = ref405ep_fpga_readb(opaque, addr) << 8;
+    ret |= ref405ep_fpga_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void ref405ep_fpga_writew (void *opaque,
+                                  hwaddr addr, uint32_t value)
+{
+    ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF);
+    ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF);
+}
+
+static uint32_t ref405ep_fpga_readl (void *opaque, hwaddr addr)
+{
+    uint32_t ret;
+
+    ret = ref405ep_fpga_readb(opaque, addr) << 24;
+    ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16;
+    ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8;
+    ret |= ref405ep_fpga_readb(opaque, addr + 3);
+
+    return ret;
+}
+
+static void ref405ep_fpga_writel (void *opaque,
+                                  hwaddr addr, uint32_t value)
+{
+    ref405ep_fpga_writeb(opaque, addr, (value >> 24) & 0xFF);
+    ref405ep_fpga_writeb(opaque, addr + 1, (value >> 16) & 0xFF);
+    ref405ep_fpga_writeb(opaque, addr + 2, (value >> 8) & 0xFF);
+    ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF);
+}
+
+static const MemoryRegionOps ref405ep_fpga_ops = {
+    .old_mmio = {
+        .read = {
+            ref405ep_fpga_readb, ref405ep_fpga_readw, ref405ep_fpga_readl,
+        },
+        .write = {
+            ref405ep_fpga_writeb, ref405ep_fpga_writew, ref405ep_fpga_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void ref405ep_fpga_reset (void *opaque)
+{
+    ref405ep_fpga_t *fpga;
+
+    fpga = opaque;
+    fpga->reg0 = 0x00;
+    fpga->reg1 = 0x0F;
+}
+
+static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base)
+{
+    ref405ep_fpga_t *fpga;
+    MemoryRegion *fpga_memory = g_new(MemoryRegion, 1);
+
+    fpga = g_malloc0(sizeof(ref405ep_fpga_t));
+    memory_region_init_io(fpga_memory, &ref405ep_fpga_ops, fpga,
+                          "fpga", 0x00000100);
+    memory_region_add_subregion(sysmem, base, fpga_memory);
+    qemu_register_reset(&ref405ep_fpga_reset, fpga);
+}
+
+static void ref405ep_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    char *filename;
+    ppc4xx_bd_info_t bd;
+    CPUPPCState *env;
+    qemu_irq *pic;
+    MemoryRegion *bios;
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    ram_addr_t bdloc;
+    MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
+    hwaddr ram_bases[2], ram_sizes[2];
+    target_ulong sram_size;
+    long bios_size;
+    //int phy_addr = 0;
+    //static int phy_addr = 1;
+    target_ulong kernel_base, initrd_base;
+    long kernel_size, initrd_size;
+    int linux_boot;
+    int fl_idx, fl_sectors, len;
+    DriveInfo *dinfo;
+    MemoryRegion *sysmem = get_system_memory();
+
+    /* XXX: fix this */
+    memory_region_init_ram(&ram_memories[0], "ef405ep.ram", 0x08000000);
+    vmstate_register_ram_global(&ram_memories[0]);
+    ram_bases[0] = 0;
+    ram_sizes[0] = 0x08000000;
+    memory_region_init(&ram_memories[1], "ef405ep.ram1", 0);
+    ram_bases[1] = 0x00000000;
+    ram_sizes[1] = 0x00000000;
+    ram_size = 128 * 1024 * 1024;
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register cpu\n", __func__);
+#endif
+    env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
+                        33333333, &pic, kernel_filename == NULL ? 0 : 1);
+    /* allocate SRAM */
+    sram_size = 512 * 1024;
+    memory_region_init_ram(sram, "ef405ep.sram", sram_size);
+    vmstate_register_ram_global(sram);
+    memory_region_add_subregion(sysmem, 0xFFF00000, sram);
+    /* allocate and load BIOS */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register BIOS\n", __func__);
+#endif
+    fl_idx = 0;
+#ifdef USE_FLASH_BIOS
+    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
+    if (dinfo) {
+        bios_size = bdrv_getlength(dinfo->bdrv);
+        fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+        printf("Register parallel flash %d size %lx"
+               " at addr %lx '%s' %d\n",
+               fl_idx, bios_size, -bios_size,
+               bdrv_get_device_name(dinfo->bdrv), fl_sectors);
+#endif
+        pflash_cfi02_register((uint32_t)(-bios_size),
+                              NULL, "ef405ep.bios", bios_size,
+                              dinfo->bdrv, 65536, fl_sectors, 1,
+                              2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
+                              1);
+        fl_idx++;
+    } else
+#endif
+    {
+#ifdef DEBUG_BOARD_INIT
+        printf("Load BIOS from file\n");
+#endif
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, "ef405ep.bios", BIOS_SIZE);
+        vmstate_register_ram_global(bios);
+        if (bios_name == NULL)
+            bios_name = BIOS_FILENAME;
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        if (filename) {
+            bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
+            g_free(filename);
+        } else {
+            bios_size = -1;
+        }
+        if (bios_size < 0 || bios_size > BIOS_SIZE) {
+            fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
+                    bios_name);
+            exit(1);
+        }
+        bios_size = (bios_size + 0xfff) & ~0xfff;
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
+    }
+    /* Register FPGA */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register FPGA\n", __func__);
+#endif
+    ref405ep_fpga_init(sysmem, 0xF0300000);
+    /* Register NVRAM */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register NVRAM\n", __func__);
+#endif
+    m48t59_init(NULL, 0xF0000000, 0, 8192, 8);
+    /* Load kernel */
+    linux_boot = (kernel_filename != NULL);
+    if (linux_boot) {
+#ifdef DEBUG_BOARD_INIT
+        printf("%s: load kernel\n", __func__);
+#endif
+        memset(&bd, 0, sizeof(bd));
+        bd.bi_memstart = 0x00000000;
+        bd.bi_memsize = ram_size;
+        bd.bi_flashstart = -bios_size;
+        bd.bi_flashsize = -bios_size;
+        bd.bi_flashoffset = 0;
+        bd.bi_sramstart = 0xFFF00000;
+        bd.bi_sramsize = sram_size;
+        bd.bi_bootflags = 0;
+        bd.bi_intfreq = 133333333;
+        bd.bi_busfreq = 33333333;
+        bd.bi_baudrate = 115200;
+        bd.bi_s_version[0] = 'Q';
+        bd.bi_s_version[1] = 'M';
+        bd.bi_s_version[2] = 'U';
+        bd.bi_s_version[3] = '\0';
+        bd.bi_r_version[0] = 'Q';
+        bd.bi_r_version[1] = 'E';
+        bd.bi_r_version[2] = 'M';
+        bd.bi_r_version[3] = 'U';
+        bd.bi_r_version[4] = '\0';
+        bd.bi_procfreq = 133333333;
+        bd.bi_plb_busfreq = 33333333;
+        bd.bi_pci_busfreq = 33333333;
+        bd.bi_opbfreq = 33333333;
+        bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001);
+        env->gpr[3] = bdloc;
+        kernel_base = KERNEL_LOAD_ADDR;
+        /* now we can load the kernel */
+        kernel_size = load_image_targphys(kernel_filename, kernel_base,
+                                          ram_size - kernel_base);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        printf("Load kernel size %ld at " TARGET_FMT_lx,
+               kernel_size, kernel_base);
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+        env->gpr[4] = initrd_base;
+        env->gpr[5] = initrd_size;
+        if (kernel_cmdline != NULL) {
+            len = strlen(kernel_cmdline);
+            bdloc -= ((len + 255) & ~255);
+            cpu_physical_memory_write(bdloc, (void *)kernel_cmdline, len + 1);
+            env->gpr[6] = bdloc;
+            env->gpr[7] = bdloc + len;
+        } else {
+            env->gpr[6] = 0;
+            env->gpr[7] = 0;
+        }
+        env->nip = KERNEL_LOAD_ADDR;
+    } else {
+        kernel_base = 0;
+        kernel_size = 0;
+        initrd_base = 0;
+        initrd_size = 0;
+        bdloc = 0;
+    }
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: Done\n", __func__);
+#endif
+    printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
+}
+
+static QEMUMachine ref405ep_machine = {
+    .name = "ref405ep",
+    .desc = "ref405ep",
+    .init = ref405ep_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+/*****************************************************************************/
+/* AMCC Taihu evaluation board */
+/* - PowerPC 405EP processor
+ * - SDRAM               128 MB at 0x00000000
+ * - Boot flash          2 MB   at 0xFFE00000
+ * - Application flash   32 MB  at 0xFC000000
+ * - 2 serial ports
+ * - 2 ethernet PHY
+ * - 1 USB 1.1 device    0x50000000
+ * - 1 LCD display       0x50100000
+ * - 1 CPLD              0x50100000
+ * - 1 I2C EEPROM
+ * - 1 I2C thermal sensor
+ * - a set of LEDs
+ * - bit-bang SPI port using GPIOs
+ * - 1 EBC interface connector 0 0x50200000
+ * - 1 cardbus controller + expansion slot.
+ * - 1 PCI expansion slot.
+ */
+typedef struct taihu_cpld_t taihu_cpld_t;
+struct taihu_cpld_t {
+    uint8_t reg0;
+    uint8_t reg1;
+};
+
+static uint32_t taihu_cpld_readb (void *opaque, hwaddr addr)
+{
+    taihu_cpld_t *cpld;
+    uint32_t ret;
+
+    cpld = opaque;
+    switch (addr) {
+    case 0x0:
+        ret = cpld->reg0;
+        break;
+    case 0x1:
+        ret = cpld->reg1;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void taihu_cpld_writeb (void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+    taihu_cpld_t *cpld;
+
+    cpld = opaque;
+    switch (addr) {
+    case 0x0:
+        /* Read only */
+        break;
+    case 0x1:
+        cpld->reg1 = value;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t taihu_cpld_readw (void *opaque, hwaddr addr)
+{
+    uint32_t ret;
+
+    ret = taihu_cpld_readb(opaque, addr) << 8;
+    ret |= taihu_cpld_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void taihu_cpld_writew (void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+    taihu_cpld_writeb(opaque, addr, (value >> 8) & 0xFF);
+    taihu_cpld_writeb(opaque, addr + 1, value & 0xFF);
+}
+
+static uint32_t taihu_cpld_readl (void *opaque, hwaddr addr)
+{
+    uint32_t ret;
+
+    ret = taihu_cpld_readb(opaque, addr) << 24;
+    ret |= taihu_cpld_readb(opaque, addr + 1) << 16;
+    ret |= taihu_cpld_readb(opaque, addr + 2) << 8;
+    ret |= taihu_cpld_readb(opaque, addr + 3);
+
+    return ret;
+}
+
+static void taihu_cpld_writel (void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+    taihu_cpld_writel(opaque, addr, (value >> 24) & 0xFF);
+    taihu_cpld_writel(opaque, addr + 1, (value >> 16) & 0xFF);
+    taihu_cpld_writel(opaque, addr + 2, (value >> 8) & 0xFF);
+    taihu_cpld_writeb(opaque, addr + 3, value & 0xFF);
+}
+
+static const MemoryRegionOps taihu_cpld_ops = {
+    .old_mmio = {
+        .read = { taihu_cpld_readb, taihu_cpld_readw, taihu_cpld_readl, },
+        .write = { taihu_cpld_writeb, taihu_cpld_writew, taihu_cpld_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void taihu_cpld_reset (void *opaque)
+{
+    taihu_cpld_t *cpld;
+
+    cpld = opaque;
+    cpld->reg0 = 0x01;
+    cpld->reg1 = 0x80;
+}
+
+static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base)
+{
+    taihu_cpld_t *cpld;
+    MemoryRegion *cpld_memory = g_new(MemoryRegion, 1);
+
+    cpld = g_malloc0(sizeof(taihu_cpld_t));
+    memory_region_init_io(cpld_memory, &taihu_cpld_ops, cpld, "cpld", 0x100);
+    memory_region_add_subregion(sysmem, base, cpld_memory);
+    qemu_register_reset(&taihu_cpld_reset, cpld);
+}
+
+static void taihu_405ep_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *kernel_filename = args->kernel_filename;
+    const char *initrd_filename = args->initrd_filename;
+    char *filename;
+    qemu_irq *pic;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *bios;
+    MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
+    hwaddr ram_bases[2], ram_sizes[2];
+    long bios_size;
+    target_ulong kernel_base, initrd_base;
+    long kernel_size, initrd_size;
+    int linux_boot;
+    int fl_idx, fl_sectors;
+    DriveInfo *dinfo;
+
+    /* RAM is soldered to the board so the size cannot be changed */
+    memory_region_init_ram(&ram_memories[0],
+                           "taihu_405ep.ram-0", 0x04000000);
+    vmstate_register_ram_global(&ram_memories[0]);
+    ram_bases[0] = 0;
+    ram_sizes[0] = 0x04000000;
+    memory_region_init_ram(&ram_memories[1],
+                           "taihu_405ep.ram-1", 0x04000000);
+    vmstate_register_ram_global(&ram_memories[1]);
+    ram_bases[1] = 0x04000000;
+    ram_sizes[1] = 0x04000000;
+    ram_size = 0x08000000;
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register cpu\n", __func__);
+#endif
+    ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
+                  33333333, &pic, kernel_filename == NULL ? 0 : 1);
+    /* allocate and load BIOS */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register BIOS\n", __func__);
+#endif
+    fl_idx = 0;
+#if defined(USE_FLASH_BIOS)
+    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
+    if (dinfo) {
+        bios_size = bdrv_getlength(dinfo->bdrv);
+        /* XXX: should check that size is 2MB */
+        //        bios_size = 2 * 1024 * 1024;
+        fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+        printf("Register parallel flash %d size %lx"
+               " at addr %lx '%s' %d\n",
+               fl_idx, bios_size, -bios_size,
+               bdrv_get_device_name(dinfo->bdrv), fl_sectors);
+#endif
+        pflash_cfi02_register((uint32_t)(-bios_size),
+                              NULL, "taihu_405ep.bios", bios_size,
+                              dinfo->bdrv, 65536, fl_sectors, 1,
+                              4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
+                              1);
+        fl_idx++;
+    } else
+#endif
+    {
+#ifdef DEBUG_BOARD_INIT
+        printf("Load BIOS from file\n");
+#endif
+        if (bios_name == NULL)
+            bios_name = BIOS_FILENAME;
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, "taihu_405ep.bios", BIOS_SIZE);
+        vmstate_register_ram_global(bios);
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        if (filename) {
+            bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
+            g_free(filename);
+        } else {
+            bios_size = -1;
+        }
+        if (bios_size < 0 || bios_size > BIOS_SIZE) {
+            fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
+                    bios_name);
+            exit(1);
+        }
+        bios_size = (bios_size + 0xfff) & ~0xfff;
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
+    }
+    /* Register Linux flash */
+    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
+    if (dinfo) {
+        bios_size = bdrv_getlength(dinfo->bdrv);
+        /* XXX: should check that size is 32MB */
+        bios_size = 32 * 1024 * 1024;
+        fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+        printf("Register parallel flash %d size %lx"
+               " at addr " TARGET_FMT_lx " '%s'\n",
+               fl_idx, bios_size, (target_ulong)0xfc000000,
+               bdrv_get_device_name(dinfo->bdrv));
+#endif
+        pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size,
+                              dinfo->bdrv, 65536, fl_sectors, 1,
+                              4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
+                              1);
+        fl_idx++;
+    }
+    /* Register CLPD & LCD display */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register CPLD\n", __func__);
+#endif
+    taihu_cpld_init(sysmem, 0x50100000);
+    /* Load kernel */
+    linux_boot = (kernel_filename != NULL);
+    if (linux_boot) {
+#ifdef DEBUG_BOARD_INIT
+        printf("%s: load kernel\n", __func__);
+#endif
+        kernel_base = KERNEL_LOAD_ADDR;
+        /* now we can load the kernel */
+        kernel_size = load_image_targphys(kernel_filename, kernel_base,
+                                          ram_size - kernel_base);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                fprintf(stderr,
+                        "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+    } else {
+        kernel_base = 0;
+        kernel_size = 0;
+        initrd_base = 0;
+        initrd_size = 0;
+    }
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: Done\n", __func__);
+#endif
+}
+
+static QEMUMachine taihu_machine = {
+    .name = "taihu",
+    .desc = "taihu",
+    .init = taihu_405ep_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void ppc405_machine_init(void)
+{
+    qemu_register_machine(&ref405ep_machine);
+    qemu_register_machine(&taihu_machine);
+}
+
+machine_init(ppc405_machine_init);
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
new file mode 100644 (file)
index 0000000..8465f6d
--- /dev/null
@@ -0,0 +1,2548 @@
+/*
+ * QEMU PowerPC 405 embedded processors emulation
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "hw/ppc.h"
+#include "hw/ppc405.h"
+#include "hw/serial.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "qemu/log.h"
+#include "exec/address-spaces.h"
+
+#define DEBUG_OPBA
+#define DEBUG_SDRAM
+#define DEBUG_GPIO
+#define DEBUG_SERIAL
+#define DEBUG_OCM
+//#define DEBUG_I2C
+#define DEBUG_GPT
+#define DEBUG_MAL
+#define DEBUG_CLOCKS
+//#define DEBUG_CLOCKS_LL
+
+ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
+                                uint32_t flags)
+{
+    ram_addr_t bdloc;
+    int i, n;
+
+    /* We put the bd structure at the top of memory */
+    if (bd->bi_memsize >= 0x01000000UL)
+        bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t);
+    else
+        bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t);
+    stl_be_phys(bdloc + 0x00, bd->bi_memstart);
+    stl_be_phys(bdloc + 0x04, bd->bi_memsize);
+    stl_be_phys(bdloc + 0x08, bd->bi_flashstart);
+    stl_be_phys(bdloc + 0x0C, bd->bi_flashsize);
+    stl_be_phys(bdloc + 0x10, bd->bi_flashoffset);
+    stl_be_phys(bdloc + 0x14, bd->bi_sramstart);
+    stl_be_phys(bdloc + 0x18, bd->bi_sramsize);
+    stl_be_phys(bdloc + 0x1C, bd->bi_bootflags);
+    stl_be_phys(bdloc + 0x20, bd->bi_ipaddr);
+    for (i = 0; i < 6; i++) {
+        stb_phys(bdloc + 0x24 + i, bd->bi_enetaddr[i]);
+    }
+    stw_be_phys(bdloc + 0x2A, bd->bi_ethspeed);
+    stl_be_phys(bdloc + 0x2C, bd->bi_intfreq);
+    stl_be_phys(bdloc + 0x30, bd->bi_busfreq);
+    stl_be_phys(bdloc + 0x34, bd->bi_baudrate);
+    for (i = 0; i < 4; i++) {
+        stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]);
+    }
+    for (i = 0; i < 32; i++) {
+        stb_phys(bdloc + 0x3C + i, bd->bi_r_version[i]);
+    }
+    stl_be_phys(bdloc + 0x5C, bd->bi_plb_busfreq);
+    stl_be_phys(bdloc + 0x60, bd->bi_pci_busfreq);
+    for (i = 0; i < 6; i++) {
+        stb_phys(bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
+    }
+    n = 0x6A;
+    if (flags & 0x00000001) {
+        for (i = 0; i < 6; i++)
+            stb_phys(bdloc + n++, bd->bi_pci_enetaddr2[i]);
+    }
+    stl_be_phys(bdloc + n, bd->bi_opbfreq);
+    n += 4;
+    for (i = 0; i < 2; i++) {
+        stl_be_phys(bdloc + n, bd->bi_iic_fast[i]);
+        n += 4;
+    }
+
+    return bdloc;
+}
+
+/*****************************************************************************/
+/* Shared peripherals */
+
+/*****************************************************************************/
+/* Peripheral local bus arbitrer */
+enum {
+    PLB0_BESR = 0x084,
+    PLB0_BEAR = 0x086,
+    PLB0_ACR  = 0x087,
+};
+
+typedef struct ppc4xx_plb_t ppc4xx_plb_t;
+struct ppc4xx_plb_t {
+    uint32_t acr;
+    uint32_t bear;
+    uint32_t besr;
+};
+
+static uint32_t dcr_read_plb (void *opaque, int dcrn)
+{
+    ppc4xx_plb_t *plb;
+    uint32_t ret;
+
+    plb = opaque;
+    switch (dcrn) {
+    case PLB0_ACR:
+        ret = plb->acr;
+        break;
+    case PLB0_BEAR:
+        ret = plb->bear;
+        break;
+    case PLB0_BESR:
+        ret = plb->besr;
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_plb (void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_plb_t *plb;
+
+    plb = opaque;
+    switch (dcrn) {
+    case PLB0_ACR:
+        /* We don't care about the actual parameters written as
+         * we don't manage any priorities on the bus
+         */
+        plb->acr = val & 0xF8000000;
+        break;
+    case PLB0_BEAR:
+        /* Read only */
+        break;
+    case PLB0_BESR:
+        /* Write-clear */
+        plb->besr &= ~val;
+        break;
+    }
+}
+
+static void ppc4xx_plb_reset (void *opaque)
+{
+    ppc4xx_plb_t *plb;
+
+    plb = opaque;
+    plb->acr = 0x00000000;
+    plb->bear = 0x00000000;
+    plb->besr = 0x00000000;
+}
+
+static void ppc4xx_plb_init(CPUPPCState *env)
+{
+    ppc4xx_plb_t *plb;
+
+    plb = g_malloc0(sizeof(ppc4xx_plb_t));
+    ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
+    ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb);
+    ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb);
+    qemu_register_reset(ppc4xx_plb_reset, plb);
+}
+
+/*****************************************************************************/
+/* PLB to OPB bridge */
+enum {
+    POB0_BESR0 = 0x0A0,
+    POB0_BESR1 = 0x0A2,
+    POB0_BEAR  = 0x0A4,
+};
+
+typedef struct ppc4xx_pob_t ppc4xx_pob_t;
+struct ppc4xx_pob_t {
+    uint32_t bear;
+    uint32_t besr0;
+    uint32_t besr1;
+};
+
+static uint32_t dcr_read_pob (void *opaque, int dcrn)
+{
+    ppc4xx_pob_t *pob;
+    uint32_t ret;
+
+    pob = opaque;
+    switch (dcrn) {
+    case POB0_BEAR:
+        ret = pob->bear;
+        break;
+    case POB0_BESR0:
+        ret = pob->besr0;
+        break;
+    case POB0_BESR1:
+        ret = pob->besr1;
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_pob (void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_pob_t *pob;
+
+    pob = opaque;
+    switch (dcrn) {
+    case POB0_BEAR:
+        /* Read only */
+        break;
+    case POB0_BESR0:
+        /* Write-clear */
+        pob->besr0 &= ~val;
+        break;
+    case POB0_BESR1:
+        /* Write-clear */
+        pob->besr1 &= ~val;
+        break;
+    }
+}
+
+static void ppc4xx_pob_reset (void *opaque)
+{
+    ppc4xx_pob_t *pob;
+
+    pob = opaque;
+    /* No error */
+    pob->bear = 0x00000000;
+    pob->besr0 = 0x0000000;
+    pob->besr1 = 0x0000000;
+}
+
+static void ppc4xx_pob_init(CPUPPCState *env)
+{
+    ppc4xx_pob_t *pob;
+
+    pob = g_malloc0(sizeof(ppc4xx_pob_t));
+    ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob);
+    ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob);
+    ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob);
+    qemu_register_reset(ppc4xx_pob_reset, pob);
+}
+
+/*****************************************************************************/
+/* OPB arbitrer */
+typedef struct ppc4xx_opba_t ppc4xx_opba_t;
+struct ppc4xx_opba_t {
+    MemoryRegion io;
+    uint8_t cr;
+    uint8_t pr;
+};
+
+static uint32_t opba_readb (void *opaque, hwaddr addr)
+{
+    ppc4xx_opba_t *opba;
+    uint32_t ret;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    opba = opaque;
+    switch (addr) {
+    case 0x00:
+        ret = opba->cr;
+        break;
+    case 0x01:
+        ret = opba->pr;
+        break;
+    default:
+        ret = 0x00;
+        break;
+    }
+
+    return ret;
+}
+
+static void opba_writeb (void *opaque,
+                         hwaddr addr, uint32_t value)
+{
+    ppc4xx_opba_t *opba;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    opba = opaque;
+    switch (addr) {
+    case 0x00:
+        opba->cr = value & 0xF8;
+        break;
+    case 0x01:
+        opba->pr = value & 0xFF;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t opba_readw (void *opaque, hwaddr addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    ret = opba_readb(opaque, addr) << 8;
+    ret |= opba_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void opba_writew (void *opaque,
+                         hwaddr addr, uint32_t value)
+{
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    opba_writeb(opaque, addr, value >> 8);
+    opba_writeb(opaque, addr + 1, value);
+}
+
+static uint32_t opba_readl (void *opaque, hwaddr addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    ret = opba_readb(opaque, addr) << 24;
+    ret |= opba_readb(opaque, addr + 1) << 16;
+
+    return ret;
+}
+
+static void opba_writel (void *opaque,
+                         hwaddr addr, uint32_t value)
+{
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    opba_writeb(opaque, addr, value >> 24);
+    opba_writeb(opaque, addr + 1, value >> 16);
+}
+
+static const MemoryRegionOps opba_ops = {
+    .old_mmio = {
+        .read = { opba_readb, opba_readw, opba_readl, },
+        .write = { opba_writeb, opba_writew, opba_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void ppc4xx_opba_reset (void *opaque)
+{
+    ppc4xx_opba_t *opba;
+
+    opba = opaque;
+    opba->cr = 0x00; /* No dynamic priorities - park disabled */
+    opba->pr = 0x11;
+}
+
+static void ppc4xx_opba_init(hwaddr base)
+{
+    ppc4xx_opba_t *opba;
+
+    opba = g_malloc0(sizeof(ppc4xx_opba_t));
+#ifdef DEBUG_OPBA
+    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
+#endif
+    memory_region_init_io(&opba->io, &opba_ops, opba, "opba", 0x002);
+    memory_region_add_subregion(get_system_memory(), base, &opba->io);
+    qemu_register_reset(ppc4xx_opba_reset, opba);
+}
+
+/*****************************************************************************/
+/* Code decompression controller */
+/* XXX: TODO */
+
+/*****************************************************************************/
+/* Peripheral controller */
+typedef struct ppc4xx_ebc_t ppc4xx_ebc_t;
+struct ppc4xx_ebc_t {
+    uint32_t addr;
+    uint32_t bcr[8];
+    uint32_t bap[8];
+    uint32_t bear;
+    uint32_t besr0;
+    uint32_t besr1;
+    uint32_t cfg;
+};
+
+enum {
+    EBC0_CFGADDR = 0x012,
+    EBC0_CFGDATA = 0x013,
+};
+
+static uint32_t dcr_read_ebc (void *opaque, int dcrn)
+{
+    ppc4xx_ebc_t *ebc;
+    uint32_t ret;
+
+    ebc = opaque;
+    switch (dcrn) {
+    case EBC0_CFGADDR:
+        ret = ebc->addr;
+        break;
+    case EBC0_CFGDATA:
+        switch (ebc->addr) {
+        case 0x00: /* B0CR */
+            ret = ebc->bcr[0];
+            break;
+        case 0x01: /* B1CR */
+            ret = ebc->bcr[1];
+            break;
+        case 0x02: /* B2CR */
+            ret = ebc->bcr[2];
+            break;
+        case 0x03: /* B3CR */
+            ret = ebc->bcr[3];
+            break;
+        case 0x04: /* B4CR */
+            ret = ebc->bcr[4];
+            break;
+        case 0x05: /* B5CR */
+            ret = ebc->bcr[5];
+            break;
+        case 0x06: /* B6CR */
+            ret = ebc->bcr[6];
+            break;
+        case 0x07: /* B7CR */
+            ret = ebc->bcr[7];
+            break;
+        case 0x10: /* B0AP */
+            ret = ebc->bap[0];
+            break;
+        case 0x11: /* B1AP */
+            ret = ebc->bap[1];
+            break;
+        case 0x12: /* B2AP */
+            ret = ebc->bap[2];
+            break;
+        case 0x13: /* B3AP */
+            ret = ebc->bap[3];
+            break;
+        case 0x14: /* B4AP */
+            ret = ebc->bap[4];
+            break;
+        case 0x15: /* B5AP */
+            ret = ebc->bap[5];
+            break;
+        case 0x16: /* B6AP */
+            ret = ebc->bap[6];
+            break;
+        case 0x17: /* B7AP */
+            ret = ebc->bap[7];
+            break;
+        case 0x20: /* BEAR */
+            ret = ebc->bear;
+            break;
+        case 0x21: /* BESR0 */
+            ret = ebc->besr0;
+            break;
+        case 0x22: /* BESR1 */
+            ret = ebc->besr1;
+            break;
+        case 0x23: /* CFG */
+            ret = ebc->cfg;
+            break;
+        default:
+            ret = 0x00000000;
+            break;
+        }
+        break;
+    default:
+        ret = 0x00000000;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_ebc (void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_ebc_t *ebc;
+
+    ebc = opaque;
+    switch (dcrn) {
+    case EBC0_CFGADDR:
+        ebc->addr = val;
+        break;
+    case EBC0_CFGDATA:
+        switch (ebc->addr) {
+        case 0x00: /* B0CR */
+            break;
+        case 0x01: /* B1CR */
+            break;
+        case 0x02: /* B2CR */
+            break;
+        case 0x03: /* B3CR */
+            break;
+        case 0x04: /* B4CR */
+            break;
+        case 0x05: /* B5CR */
+            break;
+        case 0x06: /* B6CR */
+            break;
+        case 0x07: /* B7CR */
+            break;
+        case 0x10: /* B0AP */
+            break;
+        case 0x11: /* B1AP */
+            break;
+        case 0x12: /* B2AP */
+            break;
+        case 0x13: /* B3AP */
+            break;
+        case 0x14: /* B4AP */
+            break;
+        case 0x15: /* B5AP */
+            break;
+        case 0x16: /* B6AP */
+            break;
+        case 0x17: /* B7AP */
+            break;
+        case 0x20: /* BEAR */
+            break;
+        case 0x21: /* BESR0 */
+            break;
+        case 0x22: /* BESR1 */
+            break;
+        case 0x23: /* CFG */
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void ebc_reset (void *opaque)
+{
+    ppc4xx_ebc_t *ebc;
+    int i;
+
+    ebc = opaque;
+    ebc->addr = 0x00000000;
+    ebc->bap[0] = 0x7F8FFE80;
+    ebc->bcr[0] = 0xFFE28000;
+    for (i = 0; i < 8; i++) {
+        ebc->bap[i] = 0x00000000;
+        ebc->bcr[i] = 0x00000000;
+    }
+    ebc->besr0 = 0x00000000;
+    ebc->besr1 = 0x00000000;
+    ebc->cfg = 0x80400000;
+}
+
+static void ppc405_ebc_init(CPUPPCState *env)
+{
+    ppc4xx_ebc_t *ebc;
+
+    ebc = g_malloc0(sizeof(ppc4xx_ebc_t));
+    qemu_register_reset(&ebc_reset, ebc);
+    ppc_dcr_register(env, EBC0_CFGADDR,
+                     ebc, &dcr_read_ebc, &dcr_write_ebc);
+    ppc_dcr_register(env, EBC0_CFGDATA,
+                     ebc, &dcr_read_ebc, &dcr_write_ebc);
+}
+
+/*****************************************************************************/
+/* DMA controller */
+enum {
+    DMA0_CR0 = 0x100,
+    DMA0_CT0 = 0x101,
+    DMA0_DA0 = 0x102,
+    DMA0_SA0 = 0x103,
+    DMA0_SG0 = 0x104,
+    DMA0_CR1 = 0x108,
+    DMA0_CT1 = 0x109,
+    DMA0_DA1 = 0x10A,
+    DMA0_SA1 = 0x10B,
+    DMA0_SG1 = 0x10C,
+    DMA0_CR2 = 0x110,
+    DMA0_CT2 = 0x111,
+    DMA0_DA2 = 0x112,
+    DMA0_SA2 = 0x113,
+    DMA0_SG2 = 0x114,
+    DMA0_CR3 = 0x118,
+    DMA0_CT3 = 0x119,
+    DMA0_DA3 = 0x11A,
+    DMA0_SA3 = 0x11B,
+    DMA0_SG3 = 0x11C,
+    DMA0_SR  = 0x120,
+    DMA0_SGC = 0x123,
+    DMA0_SLP = 0x125,
+    DMA0_POL = 0x126,
+};
+
+typedef struct ppc405_dma_t ppc405_dma_t;
+struct ppc405_dma_t {
+    qemu_irq irqs[4];
+    uint32_t cr[4];
+    uint32_t ct[4];
+    uint32_t da[4];
+    uint32_t sa[4];
+    uint32_t sg[4];
+    uint32_t sr;
+    uint32_t sgc;
+    uint32_t slp;
+    uint32_t pol;
+};
+
+static uint32_t dcr_read_dma (void *opaque, int dcrn)
+{
+    return 0;
+}
+
+static void dcr_write_dma (void *opaque, int dcrn, uint32_t val)
+{
+}
+
+static void ppc405_dma_reset (void *opaque)
+{
+    ppc405_dma_t *dma;
+    int i;
+
+    dma = opaque;
+    for (i = 0; i < 4; i++) {
+        dma->cr[i] = 0x00000000;
+        dma->ct[i] = 0x00000000;
+        dma->da[i] = 0x00000000;
+        dma->sa[i] = 0x00000000;
+        dma->sg[i] = 0x00000000;
+    }
+    dma->sr = 0x00000000;
+    dma->sgc = 0x00000000;
+    dma->slp = 0x7C000000;
+    dma->pol = 0x00000000;
+}
+
+static void ppc405_dma_init(CPUPPCState *env, qemu_irq irqs[4])
+{
+    ppc405_dma_t *dma;
+
+    dma = g_malloc0(sizeof(ppc405_dma_t));
+    memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq));
+    qemu_register_reset(&ppc405_dma_reset, dma);
+    ppc_dcr_register(env, DMA0_CR0,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CT0,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_DA0,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SA0,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SG0,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CR1,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CT1,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_DA1,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SA1,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SG1,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CR2,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CT2,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_DA2,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SA2,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SG2,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CR3,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CT3,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_DA3,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SA3,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SG3,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SR,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SGC,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SLP,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_POL,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+}
+
+/*****************************************************************************/
+/* GPIO */
+typedef struct ppc405_gpio_t ppc405_gpio_t;
+struct ppc405_gpio_t {
+    MemoryRegion io;
+    uint32_t or;
+    uint32_t tcr;
+    uint32_t osrh;
+    uint32_t osrl;
+    uint32_t tsrh;
+    uint32_t tsrl;
+    uint32_t odr;
+    uint32_t ir;
+    uint32_t rr1;
+    uint32_t isr1h;
+    uint32_t isr1l;
+};
+
+static uint32_t ppc405_gpio_readb (void *opaque, hwaddr addr)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+
+    return 0;
+}
+
+static void ppc405_gpio_writeb (void *opaque,
+                                hwaddr addr, uint32_t value)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+}
+
+static uint32_t ppc405_gpio_readw (void *opaque, hwaddr addr)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+
+    return 0;
+}
+
+static void ppc405_gpio_writew (void *opaque,
+                                hwaddr addr, uint32_t value)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+}
+
+static uint32_t ppc405_gpio_readl (void *opaque, hwaddr addr)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+
+    return 0;
+}
+
+static void ppc405_gpio_writel (void *opaque,
+                                hwaddr addr, uint32_t value)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+}
+
+static const MemoryRegionOps ppc405_gpio_ops = {
+    .old_mmio = {
+        .read = { ppc405_gpio_readb, ppc405_gpio_readw, ppc405_gpio_readl, },
+        .write = { ppc405_gpio_writeb, ppc405_gpio_writew, ppc405_gpio_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void ppc405_gpio_reset (void *opaque)
+{
+}
+
+static void ppc405_gpio_init(hwaddr base)
+{
+    ppc405_gpio_t *gpio;
+
+    gpio = g_malloc0(sizeof(ppc405_gpio_t));
+#ifdef DEBUG_GPIO
+    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
+#endif
+    memory_region_init_io(&gpio->io, &ppc405_gpio_ops, gpio, "pgio", 0x038);
+    memory_region_add_subregion(get_system_memory(), base, &gpio->io);
+    qemu_register_reset(&ppc405_gpio_reset, gpio);
+}
+
+/*****************************************************************************/
+/* On Chip Memory */
+enum {
+    OCM0_ISARC   = 0x018,
+    OCM0_ISACNTL = 0x019,
+    OCM0_DSARC   = 0x01A,
+    OCM0_DSACNTL = 0x01B,
+};
+
+typedef struct ppc405_ocm_t ppc405_ocm_t;
+struct ppc405_ocm_t {
+    MemoryRegion ram;
+    MemoryRegion isarc_ram;
+    MemoryRegion dsarc_ram;
+    uint32_t isarc;
+    uint32_t isacntl;
+    uint32_t dsarc;
+    uint32_t dsacntl;
+};
+
+static void ocm_update_mappings (ppc405_ocm_t *ocm,
+                                 uint32_t isarc, uint32_t isacntl,
+                                 uint32_t dsarc, uint32_t dsacntl)
+{
+#ifdef DEBUG_OCM
+    printf("OCM update ISA %08" PRIx32 " %08" PRIx32 " (%08" PRIx32
+           " %08" PRIx32 ") DSA %08" PRIx32 " %08" PRIx32
+           " (%08" PRIx32 " %08" PRIx32 ")\n",
+           isarc, isacntl, dsarc, dsacntl,
+           ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl);
+#endif
+    if (ocm->isarc != isarc ||
+        (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) {
+        if (ocm->isacntl & 0x80000000) {
+            /* Unmap previously assigned memory region */
+            printf("OCM unmap ISA %08" PRIx32 "\n", ocm->isarc);
+            memory_region_del_subregion(get_system_memory(), &ocm->isarc_ram);
+        }
+        if (isacntl & 0x80000000) {
+            /* Map new instruction memory region */
+#ifdef DEBUG_OCM
+            printf("OCM map ISA %08" PRIx32 "\n", isarc);
+#endif
+            memory_region_add_subregion(get_system_memory(), isarc,
+                                        &ocm->isarc_ram);
+        }
+    }
+    if (ocm->dsarc != dsarc ||
+        (ocm->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) {
+        if (ocm->dsacntl & 0x80000000) {
+            /* Beware not to unmap the region we just mapped */
+            if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) {
+                /* Unmap previously assigned memory region */
+#ifdef DEBUG_OCM
+                printf("OCM unmap DSA %08" PRIx32 "\n", ocm->dsarc);
+#endif
+                memory_region_del_subregion(get_system_memory(),
+                                            &ocm->dsarc_ram);
+            }
+        }
+        if (dsacntl & 0x80000000) {
+            /* Beware not to remap the region we just mapped */
+            if (!(isacntl & 0x80000000) || dsarc != isarc) {
+                /* Map new data memory region */
+#ifdef DEBUG_OCM
+                printf("OCM map DSA %08" PRIx32 "\n", dsarc);
+#endif
+                memory_region_add_subregion(get_system_memory(), dsarc,
+                                            &ocm->dsarc_ram);
+            }
+        }
+    }
+}
+
+static uint32_t dcr_read_ocm (void *opaque, int dcrn)
+{
+    ppc405_ocm_t *ocm;
+    uint32_t ret;
+
+    ocm = opaque;
+    switch (dcrn) {
+    case OCM0_ISARC:
+        ret = ocm->isarc;
+        break;
+    case OCM0_ISACNTL:
+        ret = ocm->isacntl;
+        break;
+    case OCM0_DSARC:
+        ret = ocm->dsarc;
+        break;
+    case OCM0_DSACNTL:
+        ret = ocm->dsacntl;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_ocm (void *opaque, int dcrn, uint32_t val)
+{
+    ppc405_ocm_t *ocm;
+    uint32_t isarc, dsarc, isacntl, dsacntl;
+
+    ocm = opaque;
+    isarc = ocm->isarc;
+    dsarc = ocm->dsarc;
+    isacntl = ocm->isacntl;
+    dsacntl = ocm->dsacntl;
+    switch (dcrn) {
+    case OCM0_ISARC:
+        isarc = val & 0xFC000000;
+        break;
+    case OCM0_ISACNTL:
+        isacntl = val & 0xC0000000;
+        break;
+    case OCM0_DSARC:
+        isarc = val & 0xFC000000;
+        break;
+    case OCM0_DSACNTL:
+        isacntl = val & 0xC0000000;
+        break;
+    }
+    ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
+    ocm->isarc = isarc;
+    ocm->dsarc = dsarc;
+    ocm->isacntl = isacntl;
+    ocm->dsacntl = dsacntl;
+}
+
+static void ocm_reset (void *opaque)
+{
+    ppc405_ocm_t *ocm;
+    uint32_t isarc, dsarc, isacntl, dsacntl;
+
+    ocm = opaque;
+    isarc = 0x00000000;
+    isacntl = 0x00000000;
+    dsarc = 0x00000000;
+    dsacntl = 0x00000000;
+    ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
+    ocm->isarc = isarc;
+    ocm->dsarc = dsarc;
+    ocm->isacntl = isacntl;
+    ocm->dsacntl = dsacntl;
+}
+
+static void ppc405_ocm_init(CPUPPCState *env)
+{
+    ppc405_ocm_t *ocm;
+
+    ocm = g_malloc0(sizeof(ppc405_ocm_t));
+    /* XXX: Size is 4096 or 0x04000000 */
+    memory_region_init_ram(&ocm->isarc_ram, "ppc405.ocm", 4096);
+    vmstate_register_ram_global(&ocm->isarc_ram);
+    memory_region_init_alias(&ocm->dsarc_ram, "ppc405.dsarc", &ocm->isarc_ram,
+                             0, 4096);
+    qemu_register_reset(&ocm_reset, ocm);
+    ppc_dcr_register(env, OCM0_ISARC,
+                     ocm, &dcr_read_ocm, &dcr_write_ocm);
+    ppc_dcr_register(env, OCM0_ISACNTL,
+                     ocm, &dcr_read_ocm, &dcr_write_ocm);
+    ppc_dcr_register(env, OCM0_DSARC,
+                     ocm, &dcr_read_ocm, &dcr_write_ocm);
+    ppc_dcr_register(env, OCM0_DSACNTL,
+                     ocm, &dcr_read_ocm, &dcr_write_ocm);
+}
+
+/*****************************************************************************/
+/* I2C controller */
+typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
+struct ppc4xx_i2c_t {
+    qemu_irq irq;
+    MemoryRegion iomem;
+    uint8_t mdata;
+    uint8_t lmadr;
+    uint8_t hmadr;
+    uint8_t cntl;
+    uint8_t mdcntl;
+    uint8_t sts;
+    uint8_t extsts;
+    uint8_t sdata;
+    uint8_t lsadr;
+    uint8_t hsadr;
+    uint8_t clkdiv;
+    uint8_t intrmsk;
+    uint8_t xfrcnt;
+    uint8_t xtcntlss;
+    uint8_t directcntl;
+};
+
+static uint32_t ppc4xx_i2c_readb (void *opaque, hwaddr addr)
+{
+    ppc4xx_i2c_t *i2c;
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    i2c = opaque;
+    switch (addr) {
+    case 0x00:
+        //        i2c_readbyte(&i2c->mdata);
+        ret = i2c->mdata;
+        break;
+    case 0x02:
+        ret = i2c->sdata;
+        break;
+    case 0x04:
+        ret = i2c->lmadr;
+        break;
+    case 0x05:
+        ret = i2c->hmadr;
+        break;
+    case 0x06:
+        ret = i2c->cntl;
+        break;
+    case 0x07:
+        ret = i2c->mdcntl;
+        break;
+    case 0x08:
+        ret = i2c->sts;
+        break;
+    case 0x09:
+        ret = i2c->extsts;
+        break;
+    case 0x0A:
+        ret = i2c->lsadr;
+        break;
+    case 0x0B:
+        ret = i2c->hsadr;
+        break;
+    case 0x0C:
+        ret = i2c->clkdiv;
+        break;
+    case 0x0D:
+        ret = i2c->intrmsk;
+        break;
+    case 0x0E:
+        ret = i2c->xfrcnt;
+        break;
+    case 0x0F:
+        ret = i2c->xtcntlss;
+        break;
+    case 0x10:
+        ret = i2c->directcntl;
+        break;
+    default:
+        ret = 0x00;
+        break;
+    }
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__, addr, ret);
+#endif
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writeb (void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+    ppc4xx_i2c_t *i2c;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    i2c = opaque;
+    switch (addr) {
+    case 0x00:
+        i2c->mdata = value;
+        //        i2c_sendbyte(&i2c->mdata);
+        break;
+    case 0x02:
+        i2c->sdata = value;
+        break;
+    case 0x04:
+        i2c->lmadr = value;
+        break;
+    case 0x05:
+        i2c->hmadr = value;
+        break;
+    case 0x06:
+        i2c->cntl = value;
+        break;
+    case 0x07:
+        i2c->mdcntl = value & 0xDF;
+        break;
+    case 0x08:
+        i2c->sts &= ~(value & 0x0A);
+        break;
+    case 0x09:
+        i2c->extsts &= ~(value & 0x8F);
+        break;
+    case 0x0A:
+        i2c->lsadr = value;
+        break;
+    case 0x0B:
+        i2c->hsadr = value;
+        break;
+    case 0x0C:
+        i2c->clkdiv = value;
+        break;
+    case 0x0D:
+        i2c->intrmsk = value;
+        break;
+    case 0x0E:
+        i2c->xfrcnt = value & 0x77;
+        break;
+    case 0x0F:
+        i2c->xtcntlss = value;
+        break;
+    case 0x10:
+        i2c->directcntl = value & 0x7;
+        break;
+    }
+}
+
+static uint32_t ppc4xx_i2c_readw (void *opaque, hwaddr addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    ret = ppc4xx_i2c_readb(opaque, addr) << 8;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writew (void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    ppc4xx_i2c_writeb(opaque, addr, value >> 8);
+    ppc4xx_i2c_writeb(opaque, addr + 1, value);
+}
+
+static uint32_t ppc4xx_i2c_readl (void *opaque, hwaddr addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    ret = ppc4xx_i2c_readb(opaque, addr) << 24;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 3);
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writel (void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    ppc4xx_i2c_writeb(opaque, addr, value >> 24);
+    ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16);
+    ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8);
+    ppc4xx_i2c_writeb(opaque, addr + 3, value);
+}
+
+static const MemoryRegionOps i2c_ops = {
+    .old_mmio = {
+        .read = { ppc4xx_i2c_readb, ppc4xx_i2c_readw, ppc4xx_i2c_readl, },
+        .write = { ppc4xx_i2c_writeb, ppc4xx_i2c_writew, ppc4xx_i2c_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void ppc4xx_i2c_reset (void *opaque)
+{
+    ppc4xx_i2c_t *i2c;
+
+    i2c = opaque;
+    i2c->mdata = 0x00;
+    i2c->sdata = 0x00;
+    i2c->cntl = 0x00;
+    i2c->mdcntl = 0x00;
+    i2c->sts = 0x00;
+    i2c->extsts = 0x00;
+    i2c->clkdiv = 0x00;
+    i2c->xfrcnt = 0x00;
+    i2c->directcntl = 0x0F;
+}
+
+static void ppc405_i2c_init(hwaddr base, qemu_irq irq)
+{
+    ppc4xx_i2c_t *i2c;
+
+    i2c = g_malloc0(sizeof(ppc4xx_i2c_t));
+    i2c->irq = irq;
+#ifdef DEBUG_I2C
+    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
+#endif
+    memory_region_init_io(&i2c->iomem, &i2c_ops, i2c, "i2c", 0x011);
+    memory_region_add_subregion(get_system_memory(), base, &i2c->iomem);
+    qemu_register_reset(ppc4xx_i2c_reset, i2c);
+}
+
+/*****************************************************************************/
+/* General purpose timers */
+typedef struct ppc4xx_gpt_t ppc4xx_gpt_t;
+struct ppc4xx_gpt_t {
+    MemoryRegion iomem;
+    int64_t tb_offset;
+    uint32_t tb_freq;
+    struct QEMUTimer *timer;
+    qemu_irq irqs[5];
+    uint32_t oe;
+    uint32_t ol;
+    uint32_t im;
+    uint32_t is;
+    uint32_t ie;
+    uint32_t comp[5];
+    uint32_t mask[5];
+};
+
+static uint32_t ppc4xx_gpt_readb (void *opaque, hwaddr addr)
+{
+#ifdef DEBUG_GPT
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    /* XXX: generate a bus fault */
+    return -1;
+}
+
+static void ppc4xx_gpt_writeb (void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    /* XXX: generate a bus fault */
+}
+
+static uint32_t ppc4xx_gpt_readw (void *opaque, hwaddr addr)
+{
+#ifdef DEBUG_GPT
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    /* XXX: generate a bus fault */
+    return -1;
+}
+
+static void ppc4xx_gpt_writew (void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    /* XXX: generate a bus fault */
+}
+
+static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n)
+{
+    /* XXX: TODO */
+    return 0;
+}
+
+static void ppc4xx_gpt_set_output (ppc4xx_gpt_t *gpt, int n, int level)
+{
+    /* XXX: TODO */
+}
+
+static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt)
+{
+    uint32_t mask;
+    int i;
+
+    mask = 0x80000000;
+    for (i = 0; i < 5; i++) {
+        if (gpt->oe & mask) {
+            /* Output is enabled */
+            if (ppc4xx_gpt_compare(gpt, i)) {
+                /* Comparison is OK */
+                ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask);
+            } else {
+                /* Comparison is KO */
+                ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask ? 0 : 1);
+            }
+        }
+        mask = mask >> 1;
+    }
+}
+
+static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt)
+{
+    uint32_t mask;
+    int i;
+
+    mask = 0x00008000;
+    for (i = 0; i < 5; i++) {
+        if (gpt->is & gpt->im & mask)
+            qemu_irq_raise(gpt->irqs[i]);
+        else
+            qemu_irq_lower(gpt->irqs[i]);
+        mask = mask >> 1;
+    }
+}
+
+static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt)
+{
+    /* XXX: TODO */
+}
+
+static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr)
+{
+    ppc4xx_gpt_t *gpt;
+    uint32_t ret;
+    int idx;
+
+#ifdef DEBUG_GPT
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    gpt = opaque;
+    switch (addr) {
+    case 0x00:
+        /* Time base counter */
+        ret = muldiv64(qemu_get_clock_ns(vm_clock) + gpt->tb_offset,
+                       gpt->tb_freq, get_ticks_per_sec());
+        break;
+    case 0x10:
+        /* Output enable */
+        ret = gpt->oe;
+        break;
+    case 0x14:
+        /* Output level */
+        ret = gpt->ol;
+        break;
+    case 0x18:
+        /* Interrupt mask */
+        ret = gpt->im;
+        break;
+    case 0x1C:
+    case 0x20:
+        /* Interrupt status */
+        ret = gpt->is;
+        break;
+    case 0x24:
+        /* Interrupt enable */
+        ret = gpt->ie;
+        break;
+    case 0x80 ... 0x90:
+        /* Compare timer */
+        idx = (addr - 0x80) >> 2;
+        ret = gpt->comp[idx];
+        break;
+    case 0xC0 ... 0xD0:
+        /* Compare mask */
+        idx = (addr - 0xC0) >> 2;
+        ret = gpt->mask[idx];
+        break;
+    default:
+        ret = -1;
+        break;
+    }
+
+    return ret;
+}
+
+static void ppc4xx_gpt_writel (void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+    ppc4xx_gpt_t *gpt;
+    int idx;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    gpt = opaque;
+    switch (addr) {
+    case 0x00:
+        /* Time base counter */
+        gpt->tb_offset = muldiv64(value, get_ticks_per_sec(), gpt->tb_freq)
+            - qemu_get_clock_ns(vm_clock);
+        ppc4xx_gpt_compute_timer(gpt);
+        break;
+    case 0x10:
+        /* Output enable */
+        gpt->oe = value & 0xF8000000;
+        ppc4xx_gpt_set_outputs(gpt);
+        break;
+    case 0x14:
+        /* Output level */
+        gpt->ol = value & 0xF8000000;
+        ppc4xx_gpt_set_outputs(gpt);
+        break;
+    case 0x18:
+        /* Interrupt mask */
+        gpt->im = value & 0x0000F800;
+        break;
+    case 0x1C:
+        /* Interrupt status set */
+        gpt->is |= value & 0x0000F800;
+        ppc4xx_gpt_set_irqs(gpt);
+        break;
+    case 0x20:
+        /* Interrupt status clear */
+        gpt->is &= ~(value & 0x0000F800);
+        ppc4xx_gpt_set_irqs(gpt);
+        break;
+    case 0x24:
+        /* Interrupt enable */
+        gpt->ie = value & 0x0000F800;
+        ppc4xx_gpt_set_irqs(gpt);
+        break;
+    case 0x80 ... 0x90:
+        /* Compare timer */
+        idx = (addr - 0x80) >> 2;
+        gpt->comp[idx] = value & 0xF8000000;
+        ppc4xx_gpt_compute_timer(gpt);
+        break;
+    case 0xC0 ... 0xD0:
+        /* Compare mask */
+        idx = (addr - 0xC0) >> 2;
+        gpt->mask[idx] = value & 0xF8000000;
+        ppc4xx_gpt_compute_timer(gpt);
+        break;
+    }
+}
+
+static const MemoryRegionOps gpt_ops = {
+    .old_mmio = {
+        .read = { ppc4xx_gpt_readb, ppc4xx_gpt_readw, ppc4xx_gpt_readl, },
+        .write = { ppc4xx_gpt_writeb, ppc4xx_gpt_writew, ppc4xx_gpt_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void ppc4xx_gpt_cb (void *opaque)
+{
+    ppc4xx_gpt_t *gpt;
+
+    gpt = opaque;
+    ppc4xx_gpt_set_irqs(gpt);
+    ppc4xx_gpt_set_outputs(gpt);
+    ppc4xx_gpt_compute_timer(gpt);
+}
+
+static void ppc4xx_gpt_reset (void *opaque)
+{
+    ppc4xx_gpt_t *gpt;
+    int i;
+
+    gpt = opaque;
+    qemu_del_timer(gpt->timer);
+    gpt->oe = 0x00000000;
+    gpt->ol = 0x00000000;
+    gpt->im = 0x00000000;
+    gpt->is = 0x00000000;
+    gpt->ie = 0x00000000;
+    for (i = 0; i < 5; i++) {
+        gpt->comp[i] = 0x00000000;
+        gpt->mask[i] = 0x00000000;
+    }
+}
+
+static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5])
+{
+    ppc4xx_gpt_t *gpt;
+    int i;
+
+    gpt = g_malloc0(sizeof(ppc4xx_gpt_t));
+    for (i = 0; i < 5; i++) {
+        gpt->irqs[i] = irqs[i];
+    }
+    gpt->timer = qemu_new_timer_ns(vm_clock, &ppc4xx_gpt_cb, gpt);
+#ifdef DEBUG_GPT
+    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
+#endif
+    memory_region_init_io(&gpt->iomem, &gpt_ops, gpt, "gpt", 0x0d4);
+    memory_region_add_subregion(get_system_memory(), base, &gpt->iomem);
+    qemu_register_reset(ppc4xx_gpt_reset, gpt);
+}
+
+/*****************************************************************************/
+/* MAL */
+enum {
+    MAL0_CFG      = 0x180,
+    MAL0_ESR      = 0x181,
+    MAL0_IER      = 0x182,
+    MAL0_TXCASR   = 0x184,
+    MAL0_TXCARR   = 0x185,
+    MAL0_TXEOBISR = 0x186,
+    MAL0_TXDEIR   = 0x187,
+    MAL0_RXCASR   = 0x190,
+    MAL0_RXCARR   = 0x191,
+    MAL0_RXEOBISR = 0x192,
+    MAL0_RXDEIR   = 0x193,
+    MAL0_TXCTP0R  = 0x1A0,
+    MAL0_TXCTP1R  = 0x1A1,
+    MAL0_TXCTP2R  = 0x1A2,
+    MAL0_TXCTP3R  = 0x1A3,
+    MAL0_RXCTP0R  = 0x1C0,
+    MAL0_RXCTP1R  = 0x1C1,
+    MAL0_RCBS0    = 0x1E0,
+    MAL0_RCBS1    = 0x1E1,
+};
+
+typedef struct ppc40x_mal_t ppc40x_mal_t;
+struct ppc40x_mal_t {
+    qemu_irq irqs[4];
+    uint32_t cfg;
+    uint32_t esr;
+    uint32_t ier;
+    uint32_t txcasr;
+    uint32_t txcarr;
+    uint32_t txeobisr;
+    uint32_t txdeir;
+    uint32_t rxcasr;
+    uint32_t rxcarr;
+    uint32_t rxeobisr;
+    uint32_t rxdeir;
+    uint32_t txctpr[4];
+    uint32_t rxctpr[2];
+    uint32_t rcbs[2];
+};
+
+static void ppc40x_mal_reset (void *opaque);
+
+static uint32_t dcr_read_mal (void *opaque, int dcrn)
+{
+    ppc40x_mal_t *mal;
+    uint32_t ret;
+
+    mal = opaque;
+    switch (dcrn) {
+    case MAL0_CFG:
+        ret = mal->cfg;
+        break;
+    case MAL0_ESR:
+        ret = mal->esr;
+        break;
+    case MAL0_IER:
+        ret = mal->ier;
+        break;
+    case MAL0_TXCASR:
+        ret = mal->txcasr;
+        break;
+    case MAL0_TXCARR:
+        ret = mal->txcarr;
+        break;
+    case MAL0_TXEOBISR:
+        ret = mal->txeobisr;
+        break;
+    case MAL0_TXDEIR:
+        ret = mal->txdeir;
+        break;
+    case MAL0_RXCASR:
+        ret = mal->rxcasr;
+        break;
+    case MAL0_RXCARR:
+        ret = mal->rxcarr;
+        break;
+    case MAL0_RXEOBISR:
+        ret = mal->rxeobisr;
+        break;
+    case MAL0_RXDEIR:
+        ret = mal->rxdeir;
+        break;
+    case MAL0_TXCTP0R:
+        ret = mal->txctpr[0];
+        break;
+    case MAL0_TXCTP1R:
+        ret = mal->txctpr[1];
+        break;
+    case MAL0_TXCTP2R:
+        ret = mal->txctpr[2];
+        break;
+    case MAL0_TXCTP3R:
+        ret = mal->txctpr[3];
+        break;
+    case MAL0_RXCTP0R:
+        ret = mal->rxctpr[0];
+        break;
+    case MAL0_RXCTP1R:
+        ret = mal->rxctpr[1];
+        break;
+    case MAL0_RCBS0:
+        ret = mal->rcbs[0];
+        break;
+    case MAL0_RCBS1:
+        ret = mal->rcbs[1];
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_mal (void *opaque, int dcrn, uint32_t val)
+{
+    ppc40x_mal_t *mal;
+    int idx;
+
+    mal = opaque;
+    switch (dcrn) {
+    case MAL0_CFG:
+        if (val & 0x80000000)
+            ppc40x_mal_reset(mal);
+        mal->cfg = val & 0x00FFC087;
+        break;
+    case MAL0_ESR:
+        /* Read/clear */
+        mal->esr &= ~val;
+        break;
+    case MAL0_IER:
+        mal->ier = val & 0x0000001F;
+        break;
+    case MAL0_TXCASR:
+        mal->txcasr = val & 0xF0000000;
+        break;
+    case MAL0_TXCARR:
+        mal->txcarr = val & 0xF0000000;
+        break;
+    case MAL0_TXEOBISR:
+        /* Read/clear */
+        mal->txeobisr &= ~val;
+        break;
+    case MAL0_TXDEIR:
+        /* Read/clear */
+        mal->txdeir &= ~val;
+        break;
+    case MAL0_RXCASR:
+        mal->rxcasr = val & 0xC0000000;
+        break;
+    case MAL0_RXCARR:
+        mal->rxcarr = val & 0xC0000000;
+        break;
+    case MAL0_RXEOBISR:
+        /* Read/clear */
+        mal->rxeobisr &= ~val;
+        break;
+    case MAL0_RXDEIR:
+        /* Read/clear */
+        mal->rxdeir &= ~val;
+        break;
+    case MAL0_TXCTP0R:
+        idx = 0;
+        goto update_tx_ptr;
+    case MAL0_TXCTP1R:
+        idx = 1;
+        goto update_tx_ptr;
+    case MAL0_TXCTP2R:
+        idx = 2;
+        goto update_tx_ptr;
+    case MAL0_TXCTP3R:
+        idx = 3;
+    update_tx_ptr:
+        mal->txctpr[idx] = val;
+        break;
+    case MAL0_RXCTP0R:
+        idx = 0;
+        goto update_rx_ptr;
+    case MAL0_RXCTP1R:
+        idx = 1;
+    update_rx_ptr:
+        mal->rxctpr[idx] = val;
+        break;
+    case MAL0_RCBS0:
+        idx = 0;
+        goto update_rx_size;
+    case MAL0_RCBS1:
+        idx = 1;
+    update_rx_size:
+        mal->rcbs[idx] = val & 0x000000FF;
+        break;
+    }
+}
+
+static void ppc40x_mal_reset (void *opaque)
+{
+    ppc40x_mal_t *mal;
+
+    mal = opaque;
+    mal->cfg = 0x0007C000;
+    mal->esr = 0x00000000;
+    mal->ier = 0x00000000;
+    mal->rxcasr = 0x00000000;
+    mal->rxdeir = 0x00000000;
+    mal->rxeobisr = 0x00000000;
+    mal->txcasr = 0x00000000;
+    mal->txdeir = 0x00000000;
+    mal->txeobisr = 0x00000000;
+}
+
+static void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4])
+{
+    ppc40x_mal_t *mal;
+    int i;
+
+    mal = g_malloc0(sizeof(ppc40x_mal_t));
+    for (i = 0; i < 4; i++)
+        mal->irqs[i] = irqs[i];
+    qemu_register_reset(&ppc40x_mal_reset, mal);
+    ppc_dcr_register(env, MAL0_CFG,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_ESR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_IER,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCASR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCARR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXEOBISR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXDEIR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXCASR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXCARR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXEOBISR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXDEIR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCTP0R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCTP1R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCTP2R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCTP3R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXCTP0R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXCTP1R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RCBS0,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RCBS1,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+}
+
+/*****************************************************************************/
+/* SPR */
+void ppc40x_core_reset(PowerPCCPU *cpu)
+{
+    CPUPPCState *env = &cpu->env;
+    target_ulong dbsr;
+
+    printf("Reset PowerPC core\n");
+    cpu_interrupt(env, CPU_INTERRUPT_RESET);
+    dbsr = env->spr[SPR_40x_DBSR];
+    dbsr &= ~0x00000300;
+    dbsr |= 0x00000100;
+    env->spr[SPR_40x_DBSR] = dbsr;
+}
+
+void ppc40x_chip_reset(PowerPCCPU *cpu)
+{
+    CPUPPCState *env = &cpu->env;
+    target_ulong dbsr;
+
+    printf("Reset PowerPC chip\n");
+    cpu_interrupt(env, CPU_INTERRUPT_RESET);
+    /* XXX: TODO reset all internal peripherals */
+    dbsr = env->spr[SPR_40x_DBSR];
+    dbsr &= ~0x00000300;
+    dbsr |= 0x00000200;
+    env->spr[SPR_40x_DBSR] = dbsr;
+}
+
+void ppc40x_system_reset(PowerPCCPU *cpu)
+{
+    printf("Reset PowerPC system\n");
+    qemu_system_reset_request();
+}
+
+void store_40x_dbcr0 (CPUPPCState *env, uint32_t val)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+    switch ((val >> 28) & 0x3) {
+    case 0x0:
+        /* No action */
+        break;
+    case 0x1:
+        /* Core reset */
+        ppc40x_core_reset(cpu);
+        break;
+    case 0x2:
+        /* Chip reset */
+        ppc40x_chip_reset(cpu);
+        break;
+    case 0x3:
+        /* System reset */
+        ppc40x_system_reset(cpu);
+        break;
+    }
+}
+
+/*****************************************************************************/
+/* PowerPC 405CR */
+enum {
+    PPC405CR_CPC0_PLLMR  = 0x0B0,
+    PPC405CR_CPC0_CR0    = 0x0B1,
+    PPC405CR_CPC0_CR1    = 0x0B2,
+    PPC405CR_CPC0_PSR    = 0x0B4,
+    PPC405CR_CPC0_JTAGID = 0x0B5,
+    PPC405CR_CPC0_ER     = 0x0B9,
+    PPC405CR_CPC0_FR     = 0x0BA,
+    PPC405CR_CPC0_SR     = 0x0BB,
+};
+
+enum {
+    PPC405CR_CPU_CLK   = 0,
+    PPC405CR_TMR_CLK   = 1,
+    PPC405CR_PLB_CLK   = 2,
+    PPC405CR_SDRAM_CLK = 3,
+    PPC405CR_OPB_CLK   = 4,
+    PPC405CR_EXT_CLK   = 5,
+    PPC405CR_UART_CLK  = 6,
+    PPC405CR_CLK_NB    = 7,
+};
+
+typedef struct ppc405cr_cpc_t ppc405cr_cpc_t;
+struct ppc405cr_cpc_t {
+    clk_setup_t clk_setup[PPC405CR_CLK_NB];
+    uint32_t sysclk;
+    uint32_t psr;
+    uint32_t cr0;
+    uint32_t cr1;
+    uint32_t jtagid;
+    uint32_t pllmr;
+    uint32_t er;
+    uint32_t fr;
+};
+
+static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc)
+{
+    uint64_t VCO_out, PLL_out;
+    uint32_t CPU_clk, TMR_clk, SDRAM_clk, PLB_clk, OPB_clk, EXT_clk, UART_clk;
+    int M, D0, D1, D2;
+
+    D0 = ((cpc->pllmr >> 26) & 0x3) + 1; /* CBDV */
+    if (cpc->pllmr & 0x80000000) {
+        D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */
+        D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */
+        M = D0 * D1 * D2;
+        VCO_out = cpc->sysclk * M;
+        if (VCO_out < 400000000 || VCO_out > 800000000) {
+            /* PLL cannot lock */
+            cpc->pllmr &= ~0x80000000;
+            goto bypass_pll;
+        }
+        PLL_out = VCO_out / D2;
+    } else {
+        /* Bypass PLL */
+    bypass_pll:
+        M = D0;
+        PLL_out = cpc->sysclk * M;
+    }
+    CPU_clk = PLL_out;
+    if (cpc->cr1 & 0x00800000)
+        TMR_clk = cpc->sysclk; /* Should have a separate clock */
+    else
+        TMR_clk = CPU_clk;
+    PLB_clk = CPU_clk / D0;
+    SDRAM_clk = PLB_clk;
+    D0 = ((cpc->pllmr >> 10) & 0x3) + 1;
+    OPB_clk = PLB_clk / D0;
+    D0 = ((cpc->pllmr >> 24) & 0x3) + 2;
+    EXT_clk = PLB_clk / D0;
+    D0 = ((cpc->cr0 >> 1) & 0x1F) + 1;
+    UART_clk = CPU_clk / D0;
+    /* Setup CPU clocks */
+    clk_setup(&cpc->clk_setup[PPC405CR_CPU_CLK], CPU_clk);
+    /* Setup time-base clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_TMR_CLK], TMR_clk);
+    /* Setup PLB clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_PLB_CLK], PLB_clk);
+    /* Setup SDRAM clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_SDRAM_CLK], SDRAM_clk);
+    /* Setup OPB clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_OPB_CLK], OPB_clk);
+    /* Setup external clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_EXT_CLK], EXT_clk);
+    /* Setup UART clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_UART_CLK], UART_clk);
+}
+
+static uint32_t dcr_read_crcpc (void *opaque, int dcrn)
+{
+    ppc405cr_cpc_t *cpc;
+    uint32_t ret;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405CR_CPC0_PLLMR:
+        ret = cpc->pllmr;
+        break;
+    case PPC405CR_CPC0_CR0:
+        ret = cpc->cr0;
+        break;
+    case PPC405CR_CPC0_CR1:
+        ret = cpc->cr1;
+        break;
+    case PPC405CR_CPC0_PSR:
+        ret = cpc->psr;
+        break;
+    case PPC405CR_CPC0_JTAGID:
+        ret = cpc->jtagid;
+        break;
+    case PPC405CR_CPC0_ER:
+        ret = cpc->er;
+        break;
+    case PPC405CR_CPC0_FR:
+        ret = cpc->fr;
+        break;
+    case PPC405CR_CPC0_SR:
+        ret = ~(cpc->er | cpc->fr) & 0xFFFF0000;
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_crcpc (void *opaque, int dcrn, uint32_t val)
+{
+    ppc405cr_cpc_t *cpc;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405CR_CPC0_PLLMR:
+        cpc->pllmr = val & 0xFFF77C3F;
+        break;
+    case PPC405CR_CPC0_CR0:
+        cpc->cr0 = val & 0x0FFFFFFE;
+        break;
+    case PPC405CR_CPC0_CR1:
+        cpc->cr1 = val & 0x00800000;
+        break;
+    case PPC405CR_CPC0_PSR:
+        /* Read-only */
+        break;
+    case PPC405CR_CPC0_JTAGID:
+        /* Read-only */
+        break;
+    case PPC405CR_CPC0_ER:
+        cpc->er = val & 0xBFFC0000;
+        break;
+    case PPC405CR_CPC0_FR:
+        cpc->fr = val & 0xBFFC0000;
+        break;
+    case PPC405CR_CPC0_SR:
+        /* Read-only */
+        break;
+    }
+}
+
+static void ppc405cr_cpc_reset (void *opaque)
+{
+    ppc405cr_cpc_t *cpc;
+    int D;
+
+    cpc = opaque;
+    /* Compute PLLMR value from PSR settings */
+    cpc->pllmr = 0x80000000;
+    /* PFWD */
+    switch ((cpc->psr >> 30) & 3) {
+    case 0:
+        /* Bypass */
+        cpc->pllmr &= ~0x80000000;
+        break;
+    case 1:
+        /* Divide by 3 */
+        cpc->pllmr |= 5 << 16;
+        break;
+    case 2:
+        /* Divide by 4 */
+        cpc->pllmr |= 4 << 16;
+        break;
+    case 3:
+        /* Divide by 6 */
+        cpc->pllmr |= 2 << 16;
+        break;
+    }
+    /* PFBD */
+    D = (cpc->psr >> 28) & 3;
+    cpc->pllmr |= (D + 1) << 20;
+    /* PT   */
+    D = (cpc->psr >> 25) & 7;
+    switch (D) {
+    case 0x2:
+        cpc->pllmr |= 0x13;
+        break;
+    case 0x4:
+        cpc->pllmr |= 0x15;
+        break;
+    case 0x5:
+        cpc->pllmr |= 0x16;
+        break;
+    default:
+        break;
+    }
+    /* PDC  */
+    D = (cpc->psr >> 23) & 3;
+    cpc->pllmr |= D << 26;
+    /* ODP  */
+    D = (cpc->psr >> 21) & 3;
+    cpc->pllmr |= D << 10;
+    /* EBPD */
+    D = (cpc->psr >> 17) & 3;
+    cpc->pllmr |= D << 24;
+    cpc->cr0 = 0x0000003C;
+    cpc->cr1 = 0x2B0D8800;
+    cpc->er = 0x00000000;
+    cpc->fr = 0x00000000;
+    ppc405cr_clk_setup(cpc);
+}
+
+static void ppc405cr_clk_init (ppc405cr_cpc_t *cpc)
+{
+    int D;
+
+    /* XXX: this should be read from IO pins */
+    cpc->psr = 0x00000000; /* 8 bits ROM */
+    /* PFWD */
+    D = 0x2; /* Divide by 4 */
+    cpc->psr |= D << 30;
+    /* PFBD */
+    D = 0x1; /* Divide by 2 */
+    cpc->psr |= D << 28;
+    /* PDC */
+    D = 0x1; /* Divide by 2 */
+    cpc->psr |= D << 23;
+    /* PT */
+    D = 0x5; /* M = 16 */
+    cpc->psr |= D << 25;
+    /* ODP */
+    D = 0x1; /* Divide by 2 */
+    cpc->psr |= D << 21;
+    /* EBDP */
+    D = 0x2; /* Divide by 4 */
+    cpc->psr |= D << 17;
+}
+
+static void ppc405cr_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[7],
+                               uint32_t sysclk)
+{
+    ppc405cr_cpc_t *cpc;
+
+    cpc = g_malloc0(sizeof(ppc405cr_cpc_t));
+    memcpy(cpc->clk_setup, clk_setup,
+           PPC405CR_CLK_NB * sizeof(clk_setup_t));
+    cpc->sysclk = sysclk;
+    cpc->jtagid = 0x42051049;
+    ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_CR0, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_CR1, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_JTAGID, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_PLLMR, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_ER, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_FR, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_SR, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc405cr_clk_init(cpc);
+    qemu_register_reset(ppc405cr_cpc_reset, cpc);
+}
+
+CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[4],
+                        hwaddr ram_bases[4],
+                        hwaddr ram_sizes[4],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init)
+{
+    clk_setup_t clk_setup[PPC405CR_CLK_NB];
+    qemu_irq dma_irqs[4];
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    qemu_irq *pic, *irqs;
+
+    memset(clk_setup, 0, sizeof(clk_setup));
+    cpu = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK],
+                      &clk_setup[PPC405CR_TMR_CLK], sysclk);
+    env = &cpu->env;
+    /* Memory mapped devices registers */
+    /* PLB arbitrer */
+    ppc4xx_plb_init(env);
+    /* PLB to OPB bridge */
+    ppc4xx_pob_init(env);
+    /* OBP arbitrer */
+    ppc4xx_opba_init(0xef600600);
+    /* Universal interrupt controller */
+    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    *picp = pic;
+    /* SDRAM controller */
+    ppc4xx_sdram_init(env, pic[14], 1, ram_memories,
+                      ram_bases, ram_sizes, do_init);
+    /* External bus controller */
+    ppc405_ebc_init(env);
+    /* DMA controller */
+    dma_irqs[0] = pic[26];
+    dma_irqs[1] = pic[25];
+    dma_irqs[2] = pic[24];
+    dma_irqs[3] = pic[23];
+    ppc405_dma_init(env, dma_irqs);
+    /* Serial ports */
+    if (serial_hds[0] != NULL) {
+        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
+    }
+    if (serial_hds[1] != NULL) {
+        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
+    }
+    /* IIC controller */
+    ppc405_i2c_init(0xef600500, pic[2]);
+    /* GPIO */
+    ppc405_gpio_init(0xef600700);
+    /* CPU control */
+    ppc405cr_cpc_init(env, clk_setup, sysclk);
+
+    return env;
+}
+
+/*****************************************************************************/
+/* PowerPC 405EP */
+/* CPU control */
+enum {
+    PPC405EP_CPC0_PLLMR0 = 0x0F0,
+    PPC405EP_CPC0_BOOT   = 0x0F1,
+    PPC405EP_CPC0_EPCTL  = 0x0F3,
+    PPC405EP_CPC0_PLLMR1 = 0x0F4,
+    PPC405EP_CPC0_UCR    = 0x0F5,
+    PPC405EP_CPC0_SRR    = 0x0F6,
+    PPC405EP_CPC0_JTAGID = 0x0F7,
+    PPC405EP_CPC0_PCI    = 0x0F9,
+#if 0
+    PPC405EP_CPC0_ER     = xxx,
+    PPC405EP_CPC0_FR     = xxx,
+    PPC405EP_CPC0_SR     = xxx,
+#endif
+};
+
+enum {
+    PPC405EP_CPU_CLK   = 0,
+    PPC405EP_PLB_CLK   = 1,
+    PPC405EP_OPB_CLK   = 2,
+    PPC405EP_EBC_CLK   = 3,
+    PPC405EP_MAL_CLK   = 4,
+    PPC405EP_PCI_CLK   = 5,
+    PPC405EP_UART0_CLK = 6,
+    PPC405EP_UART1_CLK = 7,
+    PPC405EP_CLK_NB    = 8,
+};
+
+typedef struct ppc405ep_cpc_t ppc405ep_cpc_t;
+struct ppc405ep_cpc_t {
+    uint32_t sysclk;
+    clk_setup_t clk_setup[PPC405EP_CLK_NB];
+    uint32_t boot;
+    uint32_t epctl;
+    uint32_t pllmr[2];
+    uint32_t ucr;
+    uint32_t srr;
+    uint32_t jtagid;
+    uint32_t pci;
+    /* Clock and power management */
+    uint32_t er;
+    uint32_t fr;
+    uint32_t sr;
+};
+
+static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc)
+{
+    uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk;
+    uint32_t UART0_clk, UART1_clk;
+    uint64_t VCO_out, PLL_out;
+    int M, D;
+
+    VCO_out = 0;
+    if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) {
+        M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */
+#ifdef DEBUG_CLOCKS_LL
+        printf("FBMUL %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 20) & 0xF, M);
+#endif
+        D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */
+#ifdef DEBUG_CLOCKS_LL
+        printf("FWDA %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 16) & 0x7, D);
+#endif
+        VCO_out = cpc->sysclk * M * D;
+        if (VCO_out < 500000000UL || VCO_out > 1000000000UL) {
+            /* Error - unlock the PLL */
+            printf("VCO out of range %" PRIu64 "\n", VCO_out);
+#if 0
+            cpc->pllmr[1] &= ~0x80000000;
+            goto pll_bypass;
+#endif
+        }
+        PLL_out = VCO_out / D;
+        /* Pretend the PLL is locked */
+        cpc->boot |= 0x00000001;
+    } else {
+#if 0
+    pll_bypass:
+#endif
+        PLL_out = cpc->sysclk;
+        if (cpc->pllmr[1] & 0x40000000) {
+            /* Pretend the PLL is not locked */
+            cpc->boot &= ~0x00000001;
+        }
+    }
+    /* Now, compute all other clocks */
+    D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("CCDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 20) & 0x3, D);
+#endif
+    CPU_clk = PLL_out / D;
+    D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("CBDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 16) & 0x3, D);
+#endif
+    PLB_clk = CPU_clk / D;
+    D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("OPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 12) & 0x3, D);
+#endif
+    OPB_clk = PLB_clk / D;
+    D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("EPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 8) & 0x3, D);
+#endif
+    EBC_clk = PLB_clk / D;
+    D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("MPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 4) & 0x3, D);
+#endif
+    MAL_clk = PLB_clk / D;
+    D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("PPDV %01" PRIx32 " %d\n", cpc->pllmr[0] & 0x3, D);
+#endif
+    PCI_clk = PLB_clk / D;
+    D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("U0DIV %01" PRIx32 " %d\n", cpc->ucr & 0x7F, D);
+#endif
+    UART0_clk = PLL_out / D;
+    D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("U1DIV %01" PRIx32 " %d\n", (cpc->ucr >> 8) & 0x7F, D);
+#endif
+    UART1_clk = PLL_out / D;
+#ifdef DEBUG_CLOCKS
+    printf("Setup PPC405EP clocks - sysclk %" PRIu32 " VCO %" PRIu64
+           " PLL out %" PRIu64 " Hz\n", cpc->sysclk, VCO_out, PLL_out);
+    printf("CPU %" PRIu32 " PLB %" PRIu32 " OPB %" PRIu32 " EBC %" PRIu32
+           " MAL %" PRIu32 " PCI %" PRIu32 " UART0 %" PRIu32
+           " UART1 %" PRIu32 "\n",
+           CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk,
+           UART0_clk, UART1_clk);
+#endif
+    /* Setup CPU clocks */
+    clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk);
+    /* Setup PLB clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_PLB_CLK], PLB_clk);
+    /* Setup OPB clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_OPB_CLK], OPB_clk);
+    /* Setup external clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_EBC_CLK], EBC_clk);
+    /* Setup MAL clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_MAL_CLK], MAL_clk);
+    /* Setup PCI clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_PCI_CLK], PCI_clk);
+    /* Setup UART0 clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_UART0_CLK], UART0_clk);
+    /* Setup UART1 clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk);
+}
+
+static uint32_t dcr_read_epcpc (void *opaque, int dcrn)
+{
+    ppc405ep_cpc_t *cpc;
+    uint32_t ret;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405EP_CPC0_BOOT:
+        ret = cpc->boot;
+        break;
+    case PPC405EP_CPC0_EPCTL:
+        ret = cpc->epctl;
+        break;
+    case PPC405EP_CPC0_PLLMR0:
+        ret = cpc->pllmr[0];
+        break;
+    case PPC405EP_CPC0_PLLMR1:
+        ret = cpc->pllmr[1];
+        break;
+    case PPC405EP_CPC0_UCR:
+        ret = cpc->ucr;
+        break;
+    case PPC405EP_CPC0_SRR:
+        ret = cpc->srr;
+        break;
+    case PPC405EP_CPC0_JTAGID:
+        ret = cpc->jtagid;
+        break;
+    case PPC405EP_CPC0_PCI:
+        ret = cpc->pci;
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_epcpc (void *opaque, int dcrn, uint32_t val)
+{
+    ppc405ep_cpc_t *cpc;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405EP_CPC0_BOOT:
+        /* Read-only register */
+        break;
+    case PPC405EP_CPC0_EPCTL:
+        /* Don't care for now */
+        cpc->epctl = val & 0xC00000F3;
+        break;
+    case PPC405EP_CPC0_PLLMR0:
+        cpc->pllmr[0] = val & 0x00633333;
+        ppc405ep_compute_clocks(cpc);
+        break;
+    case PPC405EP_CPC0_PLLMR1:
+        cpc->pllmr[1] = val & 0xC0F73FFF;
+        ppc405ep_compute_clocks(cpc);
+        break;
+    case PPC405EP_CPC0_UCR:
+        /* UART control - don't care for now */
+        cpc->ucr = val & 0x003F7F7F;
+        break;
+    case PPC405EP_CPC0_SRR:
+        cpc->srr = val;
+        break;
+    case PPC405EP_CPC0_JTAGID:
+        /* Read-only */
+        break;
+    case PPC405EP_CPC0_PCI:
+        cpc->pci = val;
+        break;
+    }
+}
+
+static void ppc405ep_cpc_reset (void *opaque)
+{
+    ppc405ep_cpc_t *cpc = opaque;
+
+    cpc->boot = 0x00000010;     /* Boot from PCI - IIC EEPROM disabled */
+    cpc->epctl = 0x00000000;
+    cpc->pllmr[0] = 0x00011010;
+    cpc->pllmr[1] = 0x40000000;
+    cpc->ucr = 0x00000000;
+    cpc->srr = 0x00040000;
+    cpc->pci = 0x00000000;
+    cpc->er = 0x00000000;
+    cpc->fr = 0x00000000;
+    cpc->sr = 0x00000000;
+    ppc405ep_compute_clocks(cpc);
+}
+
+/* XXX: sysclk should be between 25 and 100 MHz */
+static void ppc405ep_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[8],
+                               uint32_t sysclk)
+{
+    ppc405ep_cpc_t *cpc;
+
+    cpc = g_malloc0(sizeof(ppc405ep_cpc_t));
+    memcpy(cpc->clk_setup, clk_setup,
+           PPC405EP_CLK_NB * sizeof(clk_setup_t));
+    cpc->jtagid = 0x20267049;
+    cpc->sysclk = sysclk;
+    qemu_register_reset(&ppc405ep_cpc_reset, cpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_BOOT, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_EPCTL, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_PLLMR0, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_PLLMR1, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_UCR, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_SRR, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_JTAGID, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+#if 0
+    ppc_dcr_register(env, PPC405EP_CPC0_ER, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_FR, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_SR, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+#endif
+}
+
+CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[2],
+                        hwaddr ram_bases[2],
+                        hwaddr ram_sizes[2],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init)
+{
+    clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
+    qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    qemu_irq *pic, *irqs;
+
+    memset(clk_setup, 0, sizeof(clk_setup));
+    /* init CPUs */
+    cpu = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK],
+                      &tlb_clk_setup, sysclk);
+    env = &cpu->env;
+    clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb;
+    clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque;
+    /* Internal devices init */
+    /* Memory mapped devices registers */
+    /* PLB arbitrer */
+    ppc4xx_plb_init(env);
+    /* PLB to OPB bridge */
+    ppc4xx_pob_init(env);
+    /* OBP arbitrer */
+    ppc4xx_opba_init(0xef600600);
+    /* Initialize timers */
+    ppc_booke_timers_init(cpu, sysclk, 0);
+    /* Universal interrupt controller */
+    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    *picp = pic;
+    /* SDRAM controller */
+       /* XXX 405EP has no ECC interrupt */
+    ppc4xx_sdram_init(env, pic[17], 2, ram_memories,
+                      ram_bases, ram_sizes, do_init);
+    /* External bus controller */
+    ppc405_ebc_init(env);
+    /* DMA controller */
+    dma_irqs[0] = pic[5];
+    dma_irqs[1] = pic[6];
+    dma_irqs[2] = pic[7];
+    dma_irqs[3] = pic[8];
+    ppc405_dma_init(env, dma_irqs);
+    /* IIC controller */
+    ppc405_i2c_init(0xef600500, pic[2]);
+    /* GPIO */
+    ppc405_gpio_init(0xef600700);
+    /* Serial ports */
+    if (serial_hds[0] != NULL) {
+        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
+    }
+    if (serial_hds[1] != NULL) {
+        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
+    }
+    /* OCM */
+    ppc405_ocm_init(env);
+    /* GPT */
+    gpt_irqs[0] = pic[19];
+    gpt_irqs[1] = pic[20];
+    gpt_irqs[2] = pic[21];
+    gpt_irqs[3] = pic[22];
+    gpt_irqs[4] = pic[23];
+    ppc4xx_gpt_init(0xef600000, gpt_irqs);
+    /* PCI */
+    /* Uses pic[3], pic[16], pic[18] */
+    /* MAL */
+    mal_irqs[0] = pic[11];
+    mal_irqs[1] = pic[12];
+    mal_irqs[2] = pic[13];
+    mal_irqs[3] = pic[14];
+    ppc405_mal_init(env, mal_irqs);
+    /* Ethernet */
+    /* Uses pic[9], pic[15], pic[17] */
+    /* CPU control */
+    ppc405ep_cpc_init(env, clk_setup, sysclk);
+
+    return env;
+}
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
new file mode 100644 (file)
index 0000000..66911b5
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * QEMU PowerPC 440 Bamboo board emulation
+ *
+ * Copyright 2007 IBM Corporation.
+ * Authors:
+ *     Jerone Young <jyoung5@us.ibm.com>
+ *     Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ *     Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "net/net.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hw/boards.h"
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+#include "sysemu/device_tree.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "exec/address-spaces.h"
+#include "hw/serial.h"
+#include "hw/ppc.h"
+#include "hw/ppc405.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+
+#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
+
+/* from u-boot */
+#define KERNEL_ADDR  0x1000000
+#define FDT_ADDR     0x1800000
+#define RAMDISK_ADDR 0x1900000
+
+#define PPC440EP_PCI_CONFIG     0xeec00000
+#define PPC440EP_PCI_INTACK     0xeed00000
+#define PPC440EP_PCI_SPECIAL    0xeed00000
+#define PPC440EP_PCI_REGS       0xef400000
+#define PPC440EP_PCI_IO         0xe8000000
+#define PPC440EP_PCI_IOLEN      0x00010000
+
+#define PPC440EP_SDRAM_NR_BANKS 4
+
+static const unsigned int ppc440ep_sdram_bank_sizes[] = {
+    256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
+};
+
+static hwaddr entry;
+
+static int bamboo_load_device_tree(hwaddr addr,
+                                     uint32_t ramsize,
+                                     hwaddr initrd_base,
+                                     hwaddr initrd_size,
+                                     const char *kernel_cmdline)
+{
+    int ret = -1;
+#ifdef CONFIG_FDT
+    uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
+    char *filename;
+    int fdt_size;
+    void *fdt;
+    uint32_t tb_freq = 400000000;
+    uint32_t clock_freq = 400000000;
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+    if (!filename) {
+        goto out;
+    }
+    fdt = load_device_tree(filename, &fdt_size);
+    g_free(filename);
+    if (fdt == NULL) {
+        goto out;
+    }
+
+    /* Manipulate device tree in memory. */
+
+    ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
+                               sizeof(mem_reg_property));
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /memory/reg\n");
+
+    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+                                    initrd_base);
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
+
+    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+                                    (initrd_base + initrd_size));
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
+
+    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
+                                      kernel_cmdline);
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+
+    /* Copy data from the host device tree into the guest. Since the guest can
+     * directly access the timebase without host involvement, we must expose
+     * the correct frequencies. */
+    if (kvm_enabled()) {
+        tb_freq = kvmppc_get_tbfreq();
+        clock_freq = kvmppc_get_clockfreq();
+    }
+
+    qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
+                              clock_freq);
+    qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
+                              tb_freq);
+
+    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
+    g_free(fdt);
+
+out:
+#endif
+
+    return ret;
+}
+
+/* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
+static void mmubooke_create_initial_mapping(CPUPPCState *env,
+                                     target_ulong va,
+                                     hwaddr pa)
+{
+    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0x80000000  */
+    tlb->EPN = va & TARGET_PAGE_MASK;
+    tlb->RPN = pa & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+
+    tlb = &env->tlb.tlbe[1];
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0xffffffff  */
+    tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
+    tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+
+    cpu_reset(CPU(cpu));
+    env->gpr[1] = (16<<20) - 8;
+    env->gpr[3] = FDT_ADDR;
+    env->nip = entry;
+
+    /* Create a mapping for the kernel.  */
+    mmubooke_create_initial_mapping(env, 0, 0);
+}
+
+static void bamboo_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram_memories
+        = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
+    hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS];
+    hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS];
+    qemu_irq *pic;
+    qemu_irq *irqs;
+    PCIBus *pcibus;
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    uint64_t elf_entry;
+    uint64_t elf_lowaddr;
+    hwaddr loadaddr = 0;
+    target_long initrd_size = 0;
+    DeviceState *dev;
+    int success;
+    int i;
+
+    /* Setup CPU. */
+    if (cpu_model == NULL) {
+        cpu_model = "440EP";
+    }
+    cpu = cpu_ppc_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "Unable to initialize CPU!\n");
+        exit(1);
+    }
+    env = &cpu->env;
+
+    qemu_register_reset(main_cpu_reset, cpu);
+    ppc_booke_timers_init(cpu, 400000000, 0);
+    ppc_dcr_init(env, NULL, NULL);
+
+    /* interrupt controller */
+    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+
+    /* SDRAM controller */
+    memset(ram_bases, 0, sizeof(ram_bases));
+    memset(ram_sizes, 0, sizeof(ram_sizes));
+    ram_size = ppc4xx_sdram_adjust(ram_size, PPC440EP_SDRAM_NR_BANKS,
+                                   ram_memories,
+                                   ram_bases, ram_sizes,
+                                   ppc440ep_sdram_bank_sizes);
+    /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
+    ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
+                      ram_bases, ram_sizes, 1);
+
+    /* PCI */
+    dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
+                                PPC440EP_PCI_CONFIG,
+                                pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
+                                pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
+                                NULL);
+    pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+    if (!pcibus) {
+        fprintf(stderr, "couldn't create PCI controller!\n");
+        exit(1);
+    }
+
+    isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
+
+    if (serial_hds[0] != NULL) {
+        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
+    }
+    if (serial_hds[1] != NULL) {
+        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
+    }
+
+    if (pcibus) {
+        /* Register network interfaces. */
+        for (i = 0; i < nb_nics; i++) {
+            /* There are no PCI NICs on the Bamboo board, but there are
+             * PCI slots, so we can pick whatever default model we want. */
+            pci_nic_init_nofail(&nd_table[i], "e1000", NULL);
+        }
+    }
+
+    /* Load kernel. */
+    if (kernel_filename) {
+        success = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
+        if (success < 0) {
+            success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                               &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+            entry = elf_entry;
+            loadaddr = elf_lowaddr;
+        }
+        /* XXX try again as binary */
+        if (success < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    /* Load initrd. */
+    if (initrd_filename) {
+        initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR,
+                                          ram_size - RAMDISK_ADDR);
+
+        if (initrd_size < 0) {
+            fprintf(stderr, "qemu: could not load ram disk '%s' at %x\n",
+                    initrd_filename, RAMDISK_ADDR);
+            exit(1);
+        }
+    }
+
+    /* If we're loading a kernel directly, we must load the device tree too. */
+    if (kernel_filename) {
+        if (bamboo_load_device_tree(FDT_ADDR, ram_size, RAMDISK_ADDR,
+                                    initrd_size, kernel_cmdline) < 0) {
+            fprintf(stderr, "couldn't load device tree\n");
+            exit(1);
+        }
+    }
+
+    if (kvm_enabled())
+        kvmppc_init();
+}
+
+static QEMUMachine bamboo_machine = {
+    .name = "bamboo",
+    .desc = "bamboo",
+    .init = bamboo_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void bamboo_machine_init(void)
+{
+    qemu_register_machine(&bamboo_machine);
+}
+
+machine_init(bamboo_machine_init);
diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c
new file mode 100644 (file)
index 0000000..30375c0
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * QEMU PowerPC Booke hardware System Emulator
+ *
+ * Copyright (c) 2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "hw/ppc.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "hw/nvram.h"
+#include "qemu/log.h"
+#include "hw/loader.h"
+
+
+/* Timer Control Register */
+
+#define TCR_WP_SHIFT  30        /* Watchdog Timer Period */
+#define TCR_WP_MASK   (0x3 << TCR_WP_SHIFT)
+#define TCR_WRC_SHIFT 28        /* Watchdog Timer Reset Control */
+#define TCR_WRC_MASK  (0x3 << TCR_WRC_SHIFT)
+#define TCR_WIE       (1 << 27) /* Watchdog Timer Interrupt Enable */
+#define TCR_DIE       (1 << 26) /* Decrementer Interrupt Enable */
+#define TCR_FP_SHIFT  24        /* Fixed-Interval Timer Period */
+#define TCR_FP_MASK   (0x3 << TCR_FP_SHIFT)
+#define TCR_FIE       (1 << 23) /* Fixed-Interval Timer Interrupt Enable */
+#define TCR_ARE       (1 << 22) /* Auto-Reload Enable */
+
+/* Timer Control Register (e500 specific fields) */
+
+#define TCR_E500_FPEXT_SHIFT 13 /* Fixed-Interval Timer Period Extension */
+#define TCR_E500_FPEXT_MASK  (0xf << TCR_E500_FPEXT_SHIFT)
+#define TCR_E500_WPEXT_SHIFT 17 /* Watchdog Timer Period Extension */
+#define TCR_E500_WPEXT_MASK  (0xf << TCR_E500_WPEXT_SHIFT)
+
+/* Timer Status Register  */
+
+#define TSR_FIS       (1 << 26) /* Fixed-Interval Timer Interrupt Status */
+#define TSR_DIS       (1 << 27) /* Decrementer Interrupt Status */
+#define TSR_WRS_SHIFT 28        /* Watchdog Timer Reset Status */
+#define TSR_WRS_MASK  (0x3 << TSR_WRS_SHIFT)
+#define TSR_WIS       (1 << 30) /* Watchdog Timer Interrupt Status */
+#define TSR_ENW       (1 << 31) /* Enable Next Watchdog Timer */
+
+typedef struct booke_timer_t booke_timer_t;
+struct booke_timer_t {
+
+    uint64_t fit_next;
+    struct QEMUTimer *fit_timer;
+
+    uint64_t wdt_next;
+    struct QEMUTimer *wdt_timer;
+
+    uint32_t flags;
+};
+
+static void booke_update_irq(PowerPCCPU *cpu)
+{
+    CPUPPCState *env = &cpu->env;
+
+    ppc_set_irq(cpu, PPC_INTERRUPT_DECR,
+                (env->spr[SPR_BOOKE_TSR] & TSR_DIS
+                 && env->spr[SPR_BOOKE_TCR] & TCR_DIE));
+
+    ppc_set_irq(cpu, PPC_INTERRUPT_WDT,
+                (env->spr[SPR_BOOKE_TSR] & TSR_WIS
+                 && env->spr[SPR_BOOKE_TCR] & TCR_WIE));
+
+    ppc_set_irq(cpu, PPC_INTERRUPT_FIT,
+                (env->spr[SPR_BOOKE_TSR] & TSR_FIS
+                 && env->spr[SPR_BOOKE_TCR] & TCR_FIE));
+}
+
+/* Return the location of the bit of time base at which the FIT will raise an
+   interrupt */
+static uint8_t booke_get_fit_target(CPUPPCState *env, ppc_tb_t *tb_env)
+{
+    uint8_t fp = (env->spr[SPR_BOOKE_TCR] & TCR_FP_MASK) >> TCR_FP_SHIFT;
+
+    if (tb_env->flags & PPC_TIMER_E500) {
+        /* e500 Fixed-interval timer period extension */
+        uint32_t fpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_FPEXT_MASK)
+            >> TCR_E500_FPEXT_SHIFT;
+        fp = 63 - (fp | fpext << 2);
+    } else {
+        fp = env->fit_period[fp];
+    }
+
+    return fp;
+}
+
+/* Return the location of the bit of time base at which the WDT will raise an
+   interrupt */
+static uint8_t booke_get_wdt_target(CPUPPCState *env, ppc_tb_t *tb_env)
+{
+    uint8_t wp = (env->spr[SPR_BOOKE_TCR] & TCR_WP_MASK) >> TCR_WP_SHIFT;
+
+    if (tb_env->flags & PPC_TIMER_E500) {
+        /* e500 Watchdog timer period extension */
+        uint32_t wpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_WPEXT_MASK)
+            >> TCR_E500_WPEXT_SHIFT;
+        wp = 63 - (wp | wpext << 2);
+    } else {
+        wp = env->wdt_period[wp];
+    }
+
+    return wp;
+}
+
+static void booke_update_fixed_timer(CPUPPCState         *env,
+                                     uint8_t           target_bit,
+                                     uint64_t          *next,
+                                     struct QEMUTimer *timer)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t lapse;
+    uint64_t tb;
+    uint64_t period = 1 << (target_bit + 1);
+    uint64_t now;
+
+    now = qemu_get_clock_ns(vm_clock);
+    tb  = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset);
+
+    lapse = period - ((tb - (1 << target_bit)) & (period - 1));
+
+    *next = now + muldiv64(lapse, get_ticks_per_sec(), tb_env->tb_freq);
+
+    /* XXX: If expire time is now. We can't run the callback because we don't
+     * have access to it. So we just set the timer one nanosecond later.
+     */
+
+    if (*next == now) {
+        (*next)++;
+    }
+
+    qemu_mod_timer(timer, *next);
+}
+
+static void booke_decr_cb(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+
+    env->spr[SPR_BOOKE_TSR] |= TSR_DIS;
+    booke_update_irq(cpu);
+
+    if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) {
+        /* Auto Reload */
+        cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]);
+    }
+}
+
+static void booke_fit_cb(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    tb_env = env->tb_env;
+    booke_timer = tb_env->opaque;
+    env->spr[SPR_BOOKE_TSR] |= TSR_FIS;
+
+    booke_update_irq(cpu);
+
+    booke_update_fixed_timer(env,
+                             booke_get_fit_target(env, tb_env),
+                             &booke_timer->fit_next,
+                             booke_timer->fit_timer);
+}
+
+static void booke_wdt_cb(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    tb_env = env->tb_env;
+    booke_timer = tb_env->opaque;
+
+    /* TODO: There's lots of complicated stuff to do here */
+
+    booke_update_irq(cpu);
+
+    booke_update_fixed_timer(env,
+                             booke_get_wdt_target(env, tb_env),
+                             &booke_timer->wdt_next,
+                             booke_timer->wdt_timer);
+}
+
+void store_booke_tsr(CPUPPCState *env, target_ulong val)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+    env->spr[SPR_BOOKE_TSR] &= ~val;
+    booke_update_irq(cpu);
+}
+
+void store_booke_tcr(CPUPPCState *env, target_ulong val)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+    ppc_tb_t *tb_env = env->tb_env;
+    booke_timer_t *booke_timer = tb_env->opaque;
+
+    tb_env = env->tb_env;
+    env->spr[SPR_BOOKE_TCR] = val;
+
+    booke_update_irq(cpu);
+
+    booke_update_fixed_timer(env,
+                             booke_get_fit_target(env, tb_env),
+                             &booke_timer->fit_next,
+                             booke_timer->fit_timer);
+
+    booke_update_fixed_timer(env,
+                             booke_get_wdt_target(env, tb_env),
+                             &booke_timer->wdt_next,
+                             booke_timer->wdt_timer);
+
+}
+
+static void ppc_booke_timer_reset_handle(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+
+    env->spr[SPR_BOOKE_TSR] = 0;
+    env->spr[SPR_BOOKE_TCR] = 0;
+
+    booke_update_irq(cpu);
+}
+
+void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
+{
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    tb_env      = g_malloc0(sizeof(ppc_tb_t));
+    booke_timer = g_malloc0(sizeof(booke_timer_t));
+
+    cpu->env.tb_env = tb_env;
+    tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
+
+    tb_env->tb_freq    = freq;
+    tb_env->decr_freq  = freq;
+    tb_env->opaque     = booke_timer;
+    tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, cpu);
+
+    booke_timer->fit_timer =
+        qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu);
+    booke_timer->wdt_timer =
+        qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu);
+
+    qemu_register_reset(ppc_booke_timer_reset_handle, cpu);
+}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
new file mode 100644 (file)
index 0000000..2709c66
--- /dev/null
@@ -0,0 +1,963 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ * Copyright (c) 2010 David Gibson, IBM Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#include "sysemu/sysemu.h"
+#include "hw/hw.h"
+#include "elf.h"
+#include "net/net.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/cpus.h"
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+
+#include "hw/boards.h"
+#include "hw/ppc.h"
+#include "hw/loader.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+#include "hw/spapr_pci.h"
+#include "hw/xics.h"
+#include "hw/pci/msi.h"
+
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+#include "hw/pci/pci.h"
+
+#include "exec/address-spaces.h"
+#include "hw/usb.h"
+#include "qemu/config-file.h"
+
+#include <libfdt.h>
+
+/* SLOF memory layout:
+ *
+ * SLOF raw image loaded at 0, copies its romfs right below the flat
+ * device-tree, then position SLOF itself 31M below that
+ *
+ * So we set FW_OVERHEAD to 40MB which should account for all of that
+ * and more
+ *
+ * We load our kernel at 4M, leaving space for SLOF initial image
+ */
+#define FDT_MAX_SIZE            0x10000
+#define RTAS_MAX_SIZE           0x10000
+#define FW_MAX_SIZE             0x400000
+#define FW_FILE_NAME            "slof.bin"
+#define FW_OVERHEAD             0x2800000
+#define KERNEL_LOAD_ADDR        FW_MAX_SIZE
+
+#define MIN_RMA_SLOF            128UL
+
+#define TIMEBASE_FREQ           512000000ULL
+
+#define MAX_CPUS                256
+#define XICS_IRQS               1024
+
+#define PHANDLE_XICP            0x00001111
+
+#define HTAB_SIZE(spapr)        (1ULL << ((spapr)->htab_shift))
+
+sPAPREnvironment *spapr;
+
+int spapr_allocate_irq(int hint, bool lsi)
+{
+    int irq;
+
+    if (hint) {
+        irq = hint;
+        /* FIXME: we should probably check for collisions somehow */
+    } else {
+        irq = spapr->next_irq++;
+    }
+
+    /* Configure irq type */
+    if (!xics_get_qirq(spapr->icp, irq)) {
+        return 0;
+    }
+
+    xics_set_irq_type(spapr->icp, irq, lsi);
+
+    return irq;
+}
+
+/* Allocate block of consequtive IRQs, returns a number of the first */
+int spapr_allocate_irq_block(int num, bool lsi)
+{
+    int first = -1;
+    int i;
+
+    for (i = 0; i < num; ++i) {
+        int irq;
+
+        irq = spapr_allocate_irq(0, lsi);
+        if (!irq) {
+            return -1;
+        }
+
+        if (0 == i) {
+            first = irq;
+        }
+
+        /* If the above doesn't create a consecutive block then that's
+         * an internal bug */
+        assert(irq == (first + i));
+    }
+
+    return first;
+}
+
+static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
+{
+    int ret = 0, offset;
+    CPUPPCState *env;
+    CPUState *cpu;
+    char cpu_model[32];
+    int smt = kvmppc_smt_threads();
+    uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
+
+    assert(spapr->cpu_model);
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu = CPU(ppc_env_get_cpu(env));
+        uint32_t associativity[] = {cpu_to_be32(0x5),
+                                    cpu_to_be32(0x0),
+                                    cpu_to_be32(0x0),
+                                    cpu_to_be32(0x0),
+                                    cpu_to_be32(cpu->numa_node),
+                                    cpu_to_be32(cpu->cpu_index)};
+
+        if ((cpu->cpu_index % smt) != 0) {
+            continue;
+        }
+
+        snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model,
+                 cpu->cpu_index);
+
+        offset = fdt_path_offset(fdt, cpu_model);
+        if (offset < 0) {
+            return offset;
+        }
+
+        if (nb_numa_nodes > 1) {
+            ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
+                              sizeof(associativity));
+            if (ret < 0) {
+                return ret;
+            }
+        }
+
+        ret = fdt_setprop(fdt, offset, "ibm,pft-size",
+                          pft_size_prop, sizeof(pft_size_prop));
+        if (ret < 0) {
+            return ret;
+        }
+    }
+    return ret;
+}
+
+
+static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
+                                     size_t maxsize)
+{
+    size_t maxcells = maxsize / sizeof(uint32_t);
+    int i, j, count;
+    uint32_t *p = prop;
+
+    for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
+        struct ppc_one_seg_page_size *sps = &env->sps.sps[i];
+
+        if (!sps->page_shift) {
+            break;
+        }
+        for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) {
+            if (sps->enc[count].page_shift == 0) {
+                break;
+            }
+        }
+        if ((p - prop) >= (maxcells - 3 - count * 2)) {
+            break;
+        }
+        *(p++) = cpu_to_be32(sps->page_shift);
+        *(p++) = cpu_to_be32(sps->slb_enc);
+        *(p++) = cpu_to_be32(count);
+        for (j = 0; j < count; j++) {
+            *(p++) = cpu_to_be32(sps->enc[j].page_shift);
+            *(p++) = cpu_to_be32(sps->enc[j].pte_enc);
+        }
+    }
+
+    return (p - prop) * sizeof(uint32_t);
+}
+
+#define _FDT(exp) \
+    do { \
+        int ret = (exp);                                           \
+        if (ret < 0) {                                             \
+            fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
+                    #exp, fdt_strerror(ret));                      \
+            exit(1);                                               \
+        }                                                          \
+    } while (0)
+
+
+static void *spapr_create_fdt_skel(const char *cpu_model,
+                                   hwaddr initrd_base,
+                                   hwaddr initrd_size,
+                                   hwaddr kernel_size,
+                                   const char *boot_device,
+                                   const char *kernel_cmdline,
+                                   uint32_t epow_irq)
+{
+    void *fdt;
+    CPUPPCState *env;
+    uint32_t start_prop = cpu_to_be32(initrd_base);
+    uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
+    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
+        "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk";
+    char qemu_hypertas_prop[] = "hcall-memop1";
+    uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
+    uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
+    char *modelname;
+    int i, smt = kvmppc_smt_threads();
+    unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
+
+    fdt = g_malloc0(FDT_MAX_SIZE);
+    _FDT((fdt_create(fdt, FDT_MAX_SIZE)));
+
+    if (kernel_size) {
+        _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size)));
+    }
+    if (initrd_size) {
+        _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size)));
+    }
+    _FDT((fdt_finish_reservemap(fdt)));
+
+    /* Root node */
+    _FDT((fdt_begin_node(fdt, "")));
+    _FDT((fdt_property_string(fdt, "device_type", "chrp")));
+    _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)")));
+
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
+
+    /* /chosen */
+    _FDT((fdt_begin_node(fdt, "chosen")));
+
+    /* Set Form1_affinity */
+    _FDT((fdt_property(fdt, "ibm,architecture-vec-5", vec5, sizeof(vec5))));
+
+    _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
+    _FDT((fdt_property(fdt, "linux,initrd-start",
+                       &start_prop, sizeof(start_prop))));
+    _FDT((fdt_property(fdt, "linux,initrd-end",
+                       &end_prop, sizeof(end_prop))));
+    if (kernel_size) {
+        uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
+                              cpu_to_be64(kernel_size) };
+
+        _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
+    }
+    if (boot_device) {
+        _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
+    }
+    _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width)));
+    _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height)));
+    _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth)));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* cpus */
+    _FDT((fdt_begin_node(fdt, "cpus")));
+
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+
+    modelname = g_strdup(cpu_model);
+
+    for (i = 0; i < strlen(modelname); i++) {
+        modelname[i] = toupper(modelname[i]);
+    }
+
+    /* This is needed during FDT finalization */
+    spapr->cpu_model = g_strdup(modelname);
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        CPUState *cpu = CPU(ppc_env_get_cpu(env));
+        int index = cpu->cpu_index;
+        uint32_t servers_prop[smp_threads];
+        uint32_t gservers_prop[smp_threads * 2];
+        char *nodename;
+        uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
+                           0xffffffff, 0xffffffff};
+        uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
+        uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
+        uint32_t page_sizes_prop[64];
+        size_t page_sizes_prop_size;
+
+        if ((index % smt) != 0) {
+            continue;
+        }
+
+        nodename = g_strdup_printf("%s@%x", modelname, index);
+
+        _FDT((fdt_begin_node(fdt, nodename)));
+
+        g_free(nodename);
+
+        _FDT((fdt_property_cell(fdt, "reg", index)));
+        _FDT((fdt_property_string(fdt, "device_type", "cpu")));
+
+        _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR])));
+        _FDT((fdt_property_cell(fdt, "dcache-block-size",
+                                env->dcache_line_size)));
+        _FDT((fdt_property_cell(fdt, "icache-block-size",
+                                env->icache_line_size)));
+        _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq)));
+        _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq)));
+        _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
+        _FDT((fdt_property_string(fdt, "status", "okay")));
+        _FDT((fdt_property(fdt, "64-bit", NULL, 0)));
+
+        /* Build interrupt servers and gservers properties */
+        for (i = 0; i < smp_threads; i++) {
+            servers_prop[i] = cpu_to_be32(index + i);
+            /* Hack, direct the group queues back to cpu 0 */
+            gservers_prop[i*2] = cpu_to_be32(index + i);
+            gservers_prop[i*2 + 1] = 0;
+        }
+        _FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s",
+                           servers_prop, sizeof(servers_prop))));
+        _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
+                           gservers_prop, sizeof(gservers_prop))));
+
+        if (env->mmu_model & POWERPC_MMU_1TSEG) {
+            _FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
+                               segs, sizeof(segs))));
+        }
+
+        /* Advertise VMX/VSX (vector extensions) if available
+         *   0 / no property == no vector extensions
+         *   1               == VMX / Altivec available
+         *   2               == VSX available */
+        if (env->insns_flags & PPC_ALTIVEC) {
+            uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
+
+            _FDT((fdt_property_cell(fdt, "ibm,vmx", vmx)));
+        }
+
+        /* Advertise DFP (Decimal Floating Point) if available
+         *   0 / no property == no DFP
+         *   1               == DFP available */
+        if (env->insns_flags2 & PPC2_DFP) {
+            _FDT((fdt_property_cell(fdt, "ibm,dfp", 1)));
+        }
+
+        page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop,
+                                                      sizeof(page_sizes_prop));
+        if (page_sizes_prop_size) {
+            _FDT((fdt_property(fdt, "ibm,segment-page-sizes",
+                               page_sizes_prop, page_sizes_prop_size)));
+        }
+
+        _FDT((fdt_end_node(fdt)));
+    }
+
+    g_free(modelname);
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* RTAS */
+    _FDT((fdt_begin_node(fdt, "rtas")));
+
+    _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
+                       sizeof(hypertas_prop))));
+    _FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas_prop,
+                       sizeof(qemu_hypertas_prop))));
+
+    _FDT((fdt_property(fdt, "ibm,associativity-reference-points",
+        refpoints, sizeof(refpoints))));
+
+    _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX)));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* interrupt controller */
+    _FDT((fdt_begin_node(fdt, "interrupt-controller")));
+
+    _FDT((fdt_property_string(fdt, "device_type",
+                              "PowerPC-External-Interrupt-Presentation")));
+    _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
+    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
+    _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
+                       interrupt_server_ranges_prop,
+                       sizeof(interrupt_server_ranges_prop))));
+    _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2)));
+    _FDT((fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP)));
+    _FDT((fdt_property_cell(fdt, "phandle", PHANDLE_XICP)));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* vdevice */
+    _FDT((fdt_begin_node(fdt, "vdevice")));
+
+    _FDT((fdt_property_string(fdt, "device_type", "vdevice")));
+    _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+    _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2)));
+    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* event-sources */
+    spapr_events_fdt_skel(fdt, epow_irq);
+
+    _FDT((fdt_end_node(fdt))); /* close root node */
+    _FDT((fdt_finish(fdt)));
+
+    return fdt;
+}
+
+static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
+{
+    uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0),
+                                cpu_to_be32(0x0), cpu_to_be32(0x0),
+                                cpu_to_be32(0x0)};
+    char mem_name[32];
+    hwaddr node0_size, mem_start;
+    uint64_t mem_reg_property[2];
+    int i, off;
+
+    /* memory node(s) */
+    node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size;
+    if (spapr->rma_size > node0_size) {
+        spapr->rma_size = node0_size;
+    }
+
+    /* RMA */
+    mem_reg_property[0] = 0;
+    mem_reg_property[1] = cpu_to_be64(spapr->rma_size);
+    off = fdt_add_subnode(fdt, 0, "memory@0");
+    _FDT(off);
+    _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
+    _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
+                      sizeof(mem_reg_property))));
+    _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
+                      sizeof(associativity))));
+
+    /* RAM: Node 0 */
+    if (node0_size > spapr->rma_size) {
+        mem_reg_property[0] = cpu_to_be64(spapr->rma_size);
+        mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size);
+
+        sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size);
+        off = fdt_add_subnode(fdt, 0, mem_name);
+        _FDT(off);
+        _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
+        _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
+                          sizeof(mem_reg_property))));
+        _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
+                          sizeof(associativity))));
+    }
+
+    /* RAM: Node 1 and beyond */
+    mem_start = node0_size;
+    for (i = 1; i < nb_numa_nodes; i++) {
+        mem_reg_property[0] = cpu_to_be64(mem_start);
+        mem_reg_property[1] = cpu_to_be64(node_mem[i]);
+        associativity[3] = associativity[4] = cpu_to_be32(i);
+        sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start);
+        off = fdt_add_subnode(fdt, 0, mem_name);
+        _FDT(off);
+        _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
+        _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
+                          sizeof(mem_reg_property))));
+        _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
+                          sizeof(associativity))));
+        mem_start += node_mem[i];
+    }
+
+    return 0;
+}
+
+static void spapr_finalize_fdt(sPAPREnvironment *spapr,
+                               hwaddr fdt_addr,
+                               hwaddr rtas_addr,
+                               hwaddr rtas_size)
+{
+    int ret;
+    void *fdt;
+    sPAPRPHBState *phb;
+
+    fdt = g_malloc(FDT_MAX_SIZE);
+
+    /* open out the base tree into a temp buffer for the final tweaks */
+    _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE)));
+
+    ret = spapr_populate_memory(spapr, fdt);
+    if (ret < 0) {
+        fprintf(stderr, "couldn't setup memory nodes in fdt\n");
+        exit(1);
+    }
+
+    ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
+    if (ret < 0) {
+        fprintf(stderr, "couldn't setup vio devices in fdt\n");
+        exit(1);
+    }
+
+    QLIST_FOREACH(phb, &spapr->phbs, list) {
+        ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt);
+    }
+
+    if (ret < 0) {
+        fprintf(stderr, "couldn't setup PCI devices in fdt\n");
+        exit(1);
+    }
+
+    /* RTAS */
+    ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
+    }
+
+    /* Advertise NUMA via ibm,associativity */
+    ret = spapr_fixup_cpu_dt(fdt, spapr);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't finalize CPU device tree properties\n");
+    }
+
+    if (!spapr->has_graphics) {
+        spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
+    }
+
+    _FDT((fdt_pack(fdt)));
+
+    if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
+        hw_error("FDT too big ! 0x%x bytes (max is 0x%x)\n",
+                 fdt_totalsize(fdt), FDT_MAX_SIZE);
+        exit(1);
+    }
+
+    cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
+
+    g_free(fdt);
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
+}
+
+static void emulate_spapr_hypercall(PowerPCCPU *cpu)
+{
+    CPUPPCState *env = &cpu->env;
+
+    if (msr_pr) {
+        hcall_dprintf("Hypercall made with MSR[PR]=1\n");
+        env->gpr[3] = H_PRIVILEGE;
+    } else {
+        env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
+    }
+}
+
+static void spapr_reset_htab(sPAPREnvironment *spapr)
+{
+    long shift;
+
+    /* allocate hash page table.  For now we always make this 16mb,
+     * later we should probably make it scale to the size of guest
+     * RAM */
+
+    shift = kvmppc_reset_htab(spapr->htab_shift);
+
+    if (shift > 0) {
+        /* Kernel handles htab, we don't need to allocate one */
+        spapr->htab_shift = shift;
+    } else {
+        if (!spapr->htab) {
+            /* Allocate an htab if we don't yet have one */
+            spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr));
+        }
+
+        /* And clear it */
+        memset(spapr->htab, 0, HTAB_SIZE(spapr));
+    }
+
+    /* Update the RMA size if necessary */
+    if (spapr->vrma_adjust) {
+        spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift);
+    }
+}
+
+static void ppc_spapr_reset(void)
+{
+    /* Reset the hash table & recalc the RMA */
+    spapr_reset_htab(spapr);
+
+    qemu_devices_reset();
+
+    /* Load the fdt */
+    spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr,
+                       spapr->rtas_size);
+
+    /* Set up the entry state */
+    first_cpu->gpr[3] = spapr->fdt_addr;
+    first_cpu->gpr[5] = 0;
+    first_cpu->halted = 0;
+    first_cpu->nip = spapr->entry_point;
+
+}
+
+static void spapr_cpu_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+
+    cpu_reset(CPU(cpu));
+
+    /* All CPUs start halted.  CPU0 is unhalted from the machine level
+     * reset code and the rest are explicitly started up by the guest
+     * using an RTAS call */
+    env->halted = 1;
+
+    env->spr[SPR_HIOR] = 0;
+
+    env->external_htab = spapr->htab;
+    env->htab_base = -1;
+    env->htab_mask = HTAB_SIZE(spapr) - 1;
+    env->spr[SPR_SDR1] = (unsigned long)spapr->htab |
+        (spapr->htab_shift - 18);
+}
+
+static void spapr_create_nvram(sPAPREnvironment *spapr)
+{
+    QemuOpts *machine_opts;
+    DeviceState *dev;
+
+    dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
+
+    machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+    if (machine_opts) {
+        const char *drivename;
+
+        drivename = qemu_opt_get(machine_opts, "nvram");
+        if (drivename) {
+            BlockDriverState *bs;
+
+            bs = bdrv_find(drivename);
+            if (!bs) {
+                fprintf(stderr, "No such block device \"%s\" for nvram\n",
+                        drivename);
+                exit(1);
+            }
+            qdev_prop_set_drive_nofail(dev, "drive", bs);
+        }
+    }
+
+    qdev_init_nofail(dev);
+
+    spapr->nvram = (struct sPAPRNVRAM *)dev;
+}
+
+/* Returns whether we want to use VGA or not */
+static int spapr_vga_init(PCIBus *pci_bus)
+{
+    switch (vga_interface_type) {
+    case VGA_NONE:
+    case VGA_STD:
+        return pci_vga_init(pci_bus) != NULL;
+    default:
+        fprintf(stderr, "This vga model is not supported,"
+                "currently it only supports -vga std\n");
+        exit(0);
+        break;
+    }
+}
+
+/* pSeries LPAR / sPAPR hardware init */
+static void ppc_spapr_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    PCIHostState *phb;
+    int i;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    hwaddr rma_alloc_size;
+    uint32_t initrd_base = 0;
+    long kernel_size = 0, initrd_size = 0;
+    long load_limit, rtas_limit, fw_size;
+    char *filename;
+
+    msi_supported = true;
+
+    spapr = g_malloc0(sizeof(*spapr));
+    QLIST_INIT(&spapr->phbs);
+
+    cpu_ppc_hypercall = emulate_spapr_hypercall;
+
+    /* Allocate RMA if necessary */
+    rma_alloc_size = kvmppc_alloc_rma("ppc_spapr.rma", sysmem);
+
+    if (rma_alloc_size == -1) {
+        hw_error("qemu: Unable to create RMA\n");
+        exit(1);
+    }
+
+    if (rma_alloc_size && (rma_alloc_size < ram_size)) {
+        spapr->rma_size = rma_alloc_size;
+    } else {
+        spapr->rma_size = ram_size;
+
+        /* With KVM, we don't actually know whether KVM supports an
+         * unbounded RMA (PR KVM) or is limited by the hash table size
+         * (HV KVM using VRMA), so we always assume the latter
+         *
+         * In that case, we also limit the initial allocations for RTAS
+         * etc... to 256M since we have no way to know what the VRMA size
+         * is going to be as it depends on the size of the hash table
+         * isn't determined yet.
+         */
+        if (kvm_enabled()) {
+            spapr->vrma_adjust = 1;
+            spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
+        }
+    }
+
+    /* We place the device tree and RTAS just below either the top of the RMA,
+     * or just below 2GB, whichever is lowere, so that it can be
+     * processed with 32-bit real mode code if necessary */
+    rtas_limit = MIN(spapr->rma_size, 0x80000000);
+    spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;
+    spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;
+    load_limit = spapr->fdt_addr - FW_OVERHEAD;
+
+    /* We aim for a hash table of size 1/128 the size of RAM.  The
+     * normal rule of thumb is 1/64 the size of RAM, but that's much
+     * more than needed for the Linux guests we support. */
+    spapr->htab_shift = 18; /* Minimum architected size */
+    while (spapr->htab_shift <= 46) {
+        if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) {
+            break;
+        }
+        spapr->htab_shift++;
+    }
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = kvm_enabled() ? "host" : "POWER7";
+    }
+    for (i = 0; i < smp_cpus; i++) {
+        cpu = cpu_ppc_init(cpu_model);
+        if (cpu == NULL) {
+            fprintf(stderr, "Unable to find PowerPC CPU definition\n");
+            exit(1);
+        }
+        env = &cpu->env;
+
+        /* Set time-base frequency to 512 MHz */
+        cpu_ppc_tb_init(env, TIMEBASE_FREQ);
+
+        /* PAPR always has exception vectors in RAM not ROM */
+        env->hreset_excp_prefix = 0;
+
+        /* Tell KVM that we're in PAPR mode */
+        if (kvm_enabled()) {
+            kvmppc_set_papr(cpu);
+        }
+
+        qemu_register_reset(spapr_cpu_reset, cpu);
+    }
+
+    /* allocate RAM */
+    spapr->ram_limit = ram_size;
+    if (spapr->ram_limit > rma_alloc_size) {
+        ram_addr_t nonrma_base = rma_alloc_size;
+        ram_addr_t nonrma_size = spapr->ram_limit - rma_alloc_size;
+
+        memory_region_init_ram(ram, "ppc_spapr.ram", nonrma_size);
+        vmstate_register_ram_global(ram);
+        memory_region_add_subregion(sysmem, nonrma_base, ram);
+    }
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
+    spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,
+                                           rtas_limit - spapr->rtas_addr);
+    if (spapr->rtas_size < 0) {
+        hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+        exit(1);
+    }
+    if (spapr->rtas_size > RTAS_MAX_SIZE) {
+        hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n",
+                 spapr->rtas_size, RTAS_MAX_SIZE);
+        exit(1);
+    }
+    g_free(filename);
+
+
+    /* Set up Interrupt Controller */
+    spapr->icp = xics_system_init(XICS_IRQS);
+    spapr->next_irq = XICS_IRQ_BASE;
+
+    /* Set up EPOW events infrastructure */
+    spapr_events_init(spapr);
+
+    /* Set up IOMMU */
+    spapr_iommu_init();
+
+    /* Set up VIO bus */
+    spapr->vio_bus = spapr_vio_bus_init();
+
+    for (i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            spapr_vty_create(spapr->vio_bus, serial_hds[i]);
+        }
+    }
+
+    /* We always have at least the nvram device on VIO */
+    spapr_create_nvram(spapr);
+
+    /* Set up PCI */
+    spapr_pci_rtas_init();
+
+    phb = spapr_create_phb(spapr, 0, "pci");
+
+    for (i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!nd->model) {
+            nd->model = g_strdup("ibmveth");
+        }
+
+        if (strcmp(nd->model, "ibmveth") == 0) {
+            spapr_vlan_create(spapr->vio_bus, nd);
+        } else {
+            pci_nic_init_nofail(&nd_table[i], nd->model, NULL);
+        }
+    }
+
+    for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
+        spapr_vscsi_create(spapr->vio_bus);
+    }
+
+    /* Graphics */
+    if (spapr_vga_init(phb->bus)) {
+        spapr->has_graphics = true;
+    }
+
+    if (usb_enabled(spapr->has_graphics)) {
+        pci_create_simple(phb->bus, -1, "pci-ohci");
+        if (spapr->has_graphics) {
+            usbdevice_create("keyboard");
+            usbdevice_create("mouse");
+        }
+    }
+
+    if (spapr->rma_size < (MIN_RMA_SLOF << 20)) {
+        fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
+                "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
+        exit(1);
+    }
+
+    if (kernel_filename) {
+        uint64_t lowaddr = 0;
+
+        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
+                               NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              load_limit - KERNEL_LOAD_ADDR);
+        }
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+
+        /* load initrd */
+        if (initrd_filename) {
+            /* Try to locate the initrd in the gap between the kernel
+             * and the firmware. Add a bit of space just in case
+             */
+            initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff;
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              load_limit - initrd_base);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+    }
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
+    fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
+    if (fw_size < 0) {
+        hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+        exit(1);
+    }
+    g_free(filename);
+
+    spapr->entry_point = 0x100;
+
+    /* Prepare the device tree */
+    spapr->fdt_skel = spapr_create_fdt_skel(cpu_model,
+                                            initrd_base, initrd_size,
+                                            kernel_size,
+                                            boot_device, kernel_cmdline,
+                                            spapr->epow_irq);
+    assert(spapr->fdt_skel != NULL);
+}
+
+static QEMUMachine spapr_machine = {
+    .name = "pseries",
+    .desc = "pSeries Logical Partition (PAPR compliant)",
+    .init = ppc_spapr_init,
+    .reset = ppc_spapr_reset,
+    .block_default_type = IF_SCSI,
+    .max_cpus = MAX_CPUS,
+    .no_parallel = 1,
+    .boot_order = NULL,
+};
+
+static void spapr_machine_init(void)
+{
+    qemu_register_machine(&spapr_machine);
+}
+
+machine_init(spapr_machine_init);
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
new file mode 100644 (file)
index 0000000..41eab16
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Model of Xilinx Virtex5 ML507 PPC-440 refdesign.
+ *
+ * Copyright (c) 2010 Edgar E. Iglesias.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "hw/serial.h"
+#include "hw/flash.h"
+#include "sysemu/sysemu.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "sysemu/device_tree.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "qemu/log.h"
+#include "exec/address-spaces.h"
+
+#include "hw/ppc.h"
+#include "hw/ppc4xx.h"
+#include "hw/ppc405.h"
+
+#include "sysemu/blockdev.h"
+#include "hw/xilinx.h"
+
+#define EPAPR_MAGIC    (0x45504150)
+#define FLASH_SIZE     (16 * 1024 * 1024)
+
+static struct boot_info
+{
+    uint32_t bootstrap_pc;
+    uint32_t cmdline;
+    uint32_t fdt;
+    uint32_t ima_size;
+    void *vfdt;
+} boot_info;
+
+/* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
+static void mmubooke_create_initial_mapping(CPUPPCState *env,
+                                     target_ulong va,
+                                     hwaddr pa)
+{
+    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0x80000000  */
+    tlb->EPN = va & TARGET_PAGE_MASK;
+    tlb->RPN = pa & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+
+    tlb = &env->tlb.tlbe[1];
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0xffffffff  */
+    tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
+    tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+}
+
+static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size,
+                                      int do_init,
+                                      const char *cpu_model,
+                                      uint32_t sysclk)
+{
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    qemu_irq *irqs;
+
+    cpu = cpu_ppc_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "Unable to initialize CPU!\n");
+        exit(1);
+    }
+    env = &cpu->env;
+
+    ppc_booke_timers_init(cpu, sysclk, 0/* no flags */);
+
+    ppc_dcr_init(env, NULL, NULL);
+
+    /* interrupt controller */
+    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    return cpu;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    struct boot_info *bi = env->load_info;
+
+    cpu_reset(CPU(cpu));
+    /* Linux Kernel Parameters (passing device tree):
+       *   r3: pointer to the fdt
+       *   r4: 0
+       *   r5: 0
+       *   r6: epapr magic
+       *   r7: size of IMA in bytes
+       *   r8: 0
+       *   r9: 0
+    */
+    env->gpr[1] = (16<<20) - 8;
+    /* Provide a device-tree.  */
+    env->gpr[3] = bi->fdt;
+    env->nip = bi->bootstrap_pc;
+
+    /* Create a mapping for the kernel.  */
+    mmubooke_create_initial_mapping(env, 0, 0);
+    env->gpr[6] = tswap32(EPAPR_MAGIC);
+    env->gpr[7] = bi->ima_size;
+}
+
+#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb"
+static int xilinx_load_device_tree(hwaddr addr,
+                                      uint32_t ramsize,
+                                      hwaddr initrd_base,
+                                      hwaddr initrd_size,
+                                      const char *kernel_cmdline)
+{
+    char *path;
+    int fdt_size;
+#ifdef CONFIG_FDT
+    void *fdt;
+    int r;
+
+    /* Try the local "ppc.dtb" override.  */
+    fdt = load_device_tree("ppc.dtb", &fdt_size);
+    if (!fdt) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt = load_device_tree(path, &fdt_size);
+            g_free(path);
+        }
+        if (!fdt) {
+            return 0;
+        }
+    }
+
+    r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
+    if (r < 0)
+        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+    cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
+#else
+    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
+       to the kernel.  */
+    fdt_size = load_image_targphys("ppc.dtb", addr, 0x10000);
+    if (fdt_size < 0) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt_size = load_image_targphys(path, addr, 0x10000);
+            g_free(path);
+        }
+    }
+
+    if (kernel_cmdline) {
+        fprintf(stderr,
+                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
+    }
+#endif
+    return fdt_size;
+}
+
+static void virtex_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    MemoryRegion *address_space_mem = get_system_memory();
+    DeviceState *dev;
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    hwaddr ram_base = 0;
+    DriveInfo *dinfo;
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    qemu_irq irq[32], *cpu_irq;
+    int kernel_size;
+    int i;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "440-Xilinx";
+    }
+
+    cpu = ppc440_init_xilinx(&ram_size, 1, cpu_model, 400000000);
+    env = &cpu->env;
+    qemu_register_reset(main_cpu_reset, cpu);
+
+    memory_region_init_ram(phys_ram, "ram", ram_size);
+    vmstate_register_ram_global(phys_ram);
+    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi01_register(0xfc000000, NULL, "virtex.flash", FLASH_SIZE,
+                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                          FLASH_SIZE >> 16,
+                          1, 0x89, 0x18, 0x0000, 0x0, 1);
+
+    cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT];
+    dev = xilinx_intc_create(0x81800000, cpu_irq[0], 0);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    serial_mm_init(address_space_mem, 0x83e01003ULL, 2, irq[9], 115200,
+                   serial_hds[0], DEVICE_LITTLE_ENDIAN);
+
+    /* 2 timers at irq 2 @ 62 Mhz.  */
+    xilinx_timer_create(0x83c00000, irq[3], 0, 62 * 1000000);
+
+    if (kernel_filename) {
+        uint64_t entry, low, high;
+        hwaddr boot_offset;
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL,
+                               &entry, &low, &high, 1, ELF_MACHINE, 0);
+        boot_info.bootstrap_pc = entry & 0x00ffffff;
+
+        if (kernel_size < 0) {
+            boot_offset = 0x1200000;
+            /* If we failed loading ELF's try a raw image.  */
+            kernel_size = load_image_targphys(kernel_filename,
+                                              boot_offset,
+                                              ram_size);
+            boot_info.bootstrap_pc = boot_offset;
+            high = boot_info.bootstrap_pc + kernel_size + 8192;
+        }
+
+        boot_info.ima_size = kernel_size;
+
+        /* Provide a device-tree.  */
+        boot_info.fdt = high + (8192 * 2);
+        boot_info.fdt &= ~8191;
+        xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline);
+    }
+    env->load_info = &boot_info;
+}
+
+static QEMUMachine virtex_machine = {
+    .name = "virtex-ml507",
+    .desc = "Xilinx Virtex ML507 reference design",
+    .init = virtex_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void virtex_machine_init(void)
+{
+    qemu_register_machine(&virtex_machine);
+}
+
+machine_init(virtex_machine_init);
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
deleted file mode 100644 (file)
index ba443cf..0000000
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- * QEMU PowerPC 405 evaluation boards emulation
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/hw.h"
-#include "hw/ppc.h"
-#include "hw/ppc405.h"
-#include "hw/nvram.h"
-#include "hw/flash.h"
-#include "sysemu/sysemu.h"
-#include "block/block.h"
-#include "hw/boards.h"
-#include "qemu/log.h"
-#include "hw/loader.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-#define BIOS_FILENAME "ppc405_rom.bin"
-#define BIOS_SIZE (2048 * 1024)
-
-#define KERNEL_LOAD_ADDR 0x00000000
-#define INITRD_LOAD_ADDR 0x01800000
-
-#define USE_FLASH_BIOS
-
-#define DEBUG_BOARD_INIT
-
-/*****************************************************************************/
-/* PPC405EP reference board (IBM) */
-/* Standalone board with:
- * - PowerPC 405EP CPU
- * - SDRAM (0x00000000)
- * - Flash (0xFFF80000)
- * - SRAM  (0xFFF00000)
- * - NVRAM (0xF0000000)
- * - FPGA  (0xF0300000)
- */
-typedef struct ref405ep_fpga_t ref405ep_fpga_t;
-struct ref405ep_fpga_t {
-    uint8_t reg0;
-    uint8_t reg1;
-};
-
-static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr)
-{
-    ref405ep_fpga_t *fpga;
-    uint32_t ret;
-
-    fpga = opaque;
-    switch (addr) {
-    case 0x0:
-        ret = fpga->reg0;
-        break;
-    case 0x1:
-        ret = fpga->reg1;
-        break;
-    default:
-        ret = 0;
-        break;
-    }
-
-    return ret;
-}
-
-static void ref405ep_fpga_writeb (void *opaque,
-                                  hwaddr addr, uint32_t value)
-{
-    ref405ep_fpga_t *fpga;
-
-    fpga = opaque;
-    switch (addr) {
-    case 0x0:
-        /* Read only */
-        break;
-    case 0x1:
-        fpga->reg1 = value;
-        break;
-    default:
-        break;
-    }
-}
-
-static uint32_t ref405ep_fpga_readw (void *opaque, hwaddr addr)
-{
-    uint32_t ret;
-
-    ret = ref405ep_fpga_readb(opaque, addr) << 8;
-    ret |= ref405ep_fpga_readb(opaque, addr + 1);
-
-    return ret;
-}
-
-static void ref405ep_fpga_writew (void *opaque,
-                                  hwaddr addr, uint32_t value)
-{
-    ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF);
-    ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF);
-}
-
-static uint32_t ref405ep_fpga_readl (void *opaque, hwaddr addr)
-{
-    uint32_t ret;
-
-    ret = ref405ep_fpga_readb(opaque, addr) << 24;
-    ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16;
-    ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8;
-    ret |= ref405ep_fpga_readb(opaque, addr + 3);
-
-    return ret;
-}
-
-static void ref405ep_fpga_writel (void *opaque,
-                                  hwaddr addr, uint32_t value)
-{
-    ref405ep_fpga_writeb(opaque, addr, (value >> 24) & 0xFF);
-    ref405ep_fpga_writeb(opaque, addr + 1, (value >> 16) & 0xFF);
-    ref405ep_fpga_writeb(opaque, addr + 2, (value >> 8) & 0xFF);
-    ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF);
-}
-
-static const MemoryRegionOps ref405ep_fpga_ops = {
-    .old_mmio = {
-        .read = {
-            ref405ep_fpga_readb, ref405ep_fpga_readw, ref405ep_fpga_readl,
-        },
-        .write = {
-            ref405ep_fpga_writeb, ref405ep_fpga_writew, ref405ep_fpga_writel,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ref405ep_fpga_reset (void *opaque)
-{
-    ref405ep_fpga_t *fpga;
-
-    fpga = opaque;
-    fpga->reg0 = 0x00;
-    fpga->reg1 = 0x0F;
-}
-
-static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base)
-{
-    ref405ep_fpga_t *fpga;
-    MemoryRegion *fpga_memory = g_new(MemoryRegion, 1);
-
-    fpga = g_malloc0(sizeof(ref405ep_fpga_t));
-    memory_region_init_io(fpga_memory, &ref405ep_fpga_ops, fpga,
-                          "fpga", 0x00000100);
-    memory_region_add_subregion(sysmem, base, fpga_memory);
-    qemu_register_reset(&ref405ep_fpga_reset, fpga);
-}
-
-static void ref405ep_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    char *filename;
-    ppc4xx_bd_info_t bd;
-    CPUPPCState *env;
-    qemu_irq *pic;
-    MemoryRegion *bios;
-    MemoryRegion *sram = g_new(MemoryRegion, 1);
-    ram_addr_t bdloc;
-    MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
-    hwaddr ram_bases[2], ram_sizes[2];
-    target_ulong sram_size;
-    long bios_size;
-    //int phy_addr = 0;
-    //static int phy_addr = 1;
-    target_ulong kernel_base, initrd_base;
-    long kernel_size, initrd_size;
-    int linux_boot;
-    int fl_idx, fl_sectors, len;
-    DriveInfo *dinfo;
-    MemoryRegion *sysmem = get_system_memory();
-
-    /* XXX: fix this */
-    memory_region_init_ram(&ram_memories[0], "ef405ep.ram", 0x08000000);
-    vmstate_register_ram_global(&ram_memories[0]);
-    ram_bases[0] = 0;
-    ram_sizes[0] = 0x08000000;
-    memory_region_init(&ram_memories[1], "ef405ep.ram1", 0);
-    ram_bases[1] = 0x00000000;
-    ram_sizes[1] = 0x00000000;
-    ram_size = 128 * 1024 * 1024;
-#ifdef DEBUG_BOARD_INIT
-    printf("%s: register cpu\n", __func__);
-#endif
-    env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
-                        33333333, &pic, kernel_filename == NULL ? 0 : 1);
-    /* allocate SRAM */
-    sram_size = 512 * 1024;
-    memory_region_init_ram(sram, "ef405ep.sram", sram_size);
-    vmstate_register_ram_global(sram);
-    memory_region_add_subregion(sysmem, 0xFFF00000, sram);
-    /* allocate and load BIOS */
-#ifdef DEBUG_BOARD_INIT
-    printf("%s: register BIOS\n", __func__);
-#endif
-    fl_idx = 0;
-#ifdef USE_FLASH_BIOS
-    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
-    if (dinfo) {
-        bios_size = bdrv_getlength(dinfo->bdrv);
-        fl_sectors = (bios_size + 65535) >> 16;
-#ifdef DEBUG_BOARD_INIT
-        printf("Register parallel flash %d size %lx"
-               " at addr %lx '%s' %d\n",
-               fl_idx, bios_size, -bios_size,
-               bdrv_get_device_name(dinfo->bdrv), fl_sectors);
-#endif
-        pflash_cfi02_register((uint32_t)(-bios_size),
-                              NULL, "ef405ep.bios", bios_size,
-                              dinfo->bdrv, 65536, fl_sectors, 1,
-                              2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
-                              1);
-        fl_idx++;
-    } else
-#endif
-    {
-#ifdef DEBUG_BOARD_INIT
-        printf("Load BIOS from file\n");
-#endif
-        bios = g_new(MemoryRegion, 1);
-        memory_region_init_ram(bios, "ef405ep.bios", BIOS_SIZE);
-        vmstate_register_ram_global(bios);
-        if (bios_name == NULL)
-            bios_name = BIOS_FILENAME;
-        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-        if (filename) {
-            bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
-            g_free(filename);
-        } else {
-            bios_size = -1;
-        }
-        if (bios_size < 0 || bios_size > BIOS_SIZE) {
-            fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
-                    bios_name);
-            exit(1);
-        }
-        bios_size = (bios_size + 0xfff) & ~0xfff;
-        memory_region_set_readonly(bios, true);
-        memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
-    }
-    /* Register FPGA */
-#ifdef DEBUG_BOARD_INIT
-    printf("%s: register FPGA\n", __func__);
-#endif
-    ref405ep_fpga_init(sysmem, 0xF0300000);
-    /* Register NVRAM */
-#ifdef DEBUG_BOARD_INIT
-    printf("%s: register NVRAM\n", __func__);
-#endif
-    m48t59_init(NULL, 0xF0000000, 0, 8192, 8);
-    /* Load kernel */
-    linux_boot = (kernel_filename != NULL);
-    if (linux_boot) {
-#ifdef DEBUG_BOARD_INIT
-        printf("%s: load kernel\n", __func__);
-#endif
-        memset(&bd, 0, sizeof(bd));
-        bd.bi_memstart = 0x00000000;
-        bd.bi_memsize = ram_size;
-        bd.bi_flashstart = -bios_size;
-        bd.bi_flashsize = -bios_size;
-        bd.bi_flashoffset = 0;
-        bd.bi_sramstart = 0xFFF00000;
-        bd.bi_sramsize = sram_size;
-        bd.bi_bootflags = 0;
-        bd.bi_intfreq = 133333333;
-        bd.bi_busfreq = 33333333;
-        bd.bi_baudrate = 115200;
-        bd.bi_s_version[0] = 'Q';
-        bd.bi_s_version[1] = 'M';
-        bd.bi_s_version[2] = 'U';
-        bd.bi_s_version[3] = '\0';
-        bd.bi_r_version[0] = 'Q';
-        bd.bi_r_version[1] = 'E';
-        bd.bi_r_version[2] = 'M';
-        bd.bi_r_version[3] = 'U';
-        bd.bi_r_version[4] = '\0';
-        bd.bi_procfreq = 133333333;
-        bd.bi_plb_busfreq = 33333333;
-        bd.bi_pci_busfreq = 33333333;
-        bd.bi_opbfreq = 33333333;
-        bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001);
-        env->gpr[3] = bdloc;
-        kernel_base = KERNEL_LOAD_ADDR;
-        /* now we can load the kernel */
-        kernel_size = load_image_targphys(kernel_filename, kernel_base,
-                                          ram_size - kernel_base);
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-        printf("Load kernel size %ld at " TARGET_FMT_lx,
-               kernel_size, kernel_base);
-        /* load initrd */
-        if (initrd_filename) {
-            initrd_base = INITRD_LOAD_ADDR;
-            initrd_size = load_image_targphys(initrd_filename, initrd_base,
-                                              ram_size - initrd_base);
-            if (initrd_size < 0) {
-                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                        initrd_filename);
-                exit(1);
-            }
-        } else {
-            initrd_base = 0;
-            initrd_size = 0;
-        }
-        env->gpr[4] = initrd_base;
-        env->gpr[5] = initrd_size;
-        if (kernel_cmdline != NULL) {
-            len = strlen(kernel_cmdline);
-            bdloc -= ((len + 255) & ~255);
-            cpu_physical_memory_write(bdloc, (void *)kernel_cmdline, len + 1);
-            env->gpr[6] = bdloc;
-            env->gpr[7] = bdloc + len;
-        } else {
-            env->gpr[6] = 0;
-            env->gpr[7] = 0;
-        }
-        env->nip = KERNEL_LOAD_ADDR;
-    } else {
-        kernel_base = 0;
-        kernel_size = 0;
-        initrd_base = 0;
-        initrd_size = 0;
-        bdloc = 0;
-    }
-#ifdef DEBUG_BOARD_INIT
-    printf("%s: Done\n", __func__);
-#endif
-    printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
-}
-
-static QEMUMachine ref405ep_machine = {
-    .name = "ref405ep",
-    .desc = "ref405ep",
-    .init = ref405ep_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-/*****************************************************************************/
-/* AMCC Taihu evaluation board */
-/* - PowerPC 405EP processor
- * - SDRAM               128 MB at 0x00000000
- * - Boot flash          2 MB   at 0xFFE00000
- * - Application flash   32 MB  at 0xFC000000
- * - 2 serial ports
- * - 2 ethernet PHY
- * - 1 USB 1.1 device    0x50000000
- * - 1 LCD display       0x50100000
- * - 1 CPLD              0x50100000
- * - 1 I2C EEPROM
- * - 1 I2C thermal sensor
- * - a set of LEDs
- * - bit-bang SPI port using GPIOs
- * - 1 EBC interface connector 0 0x50200000
- * - 1 cardbus controller + expansion slot.
- * - 1 PCI expansion slot.
- */
-typedef struct taihu_cpld_t taihu_cpld_t;
-struct taihu_cpld_t {
-    uint8_t reg0;
-    uint8_t reg1;
-};
-
-static uint32_t taihu_cpld_readb (void *opaque, hwaddr addr)
-{
-    taihu_cpld_t *cpld;
-    uint32_t ret;
-
-    cpld = opaque;
-    switch (addr) {
-    case 0x0:
-        ret = cpld->reg0;
-        break;
-    case 0x1:
-        ret = cpld->reg1;
-        break;
-    default:
-        ret = 0;
-        break;
-    }
-
-    return ret;
-}
-
-static void taihu_cpld_writeb (void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-    taihu_cpld_t *cpld;
-
-    cpld = opaque;
-    switch (addr) {
-    case 0x0:
-        /* Read only */
-        break;
-    case 0x1:
-        cpld->reg1 = value;
-        break;
-    default:
-        break;
-    }
-}
-
-static uint32_t taihu_cpld_readw (void *opaque, hwaddr addr)
-{
-    uint32_t ret;
-
-    ret = taihu_cpld_readb(opaque, addr) << 8;
-    ret |= taihu_cpld_readb(opaque, addr + 1);
-
-    return ret;
-}
-
-static void taihu_cpld_writew (void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-    taihu_cpld_writeb(opaque, addr, (value >> 8) & 0xFF);
-    taihu_cpld_writeb(opaque, addr + 1, value & 0xFF);
-}
-
-static uint32_t taihu_cpld_readl (void *opaque, hwaddr addr)
-{
-    uint32_t ret;
-
-    ret = taihu_cpld_readb(opaque, addr) << 24;
-    ret |= taihu_cpld_readb(opaque, addr + 1) << 16;
-    ret |= taihu_cpld_readb(opaque, addr + 2) << 8;
-    ret |= taihu_cpld_readb(opaque, addr + 3);
-
-    return ret;
-}
-
-static void taihu_cpld_writel (void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-    taihu_cpld_writel(opaque, addr, (value >> 24) & 0xFF);
-    taihu_cpld_writel(opaque, addr + 1, (value >> 16) & 0xFF);
-    taihu_cpld_writel(opaque, addr + 2, (value >> 8) & 0xFF);
-    taihu_cpld_writeb(opaque, addr + 3, value & 0xFF);
-}
-
-static const MemoryRegionOps taihu_cpld_ops = {
-    .old_mmio = {
-        .read = { taihu_cpld_readb, taihu_cpld_readw, taihu_cpld_readl, },
-        .write = { taihu_cpld_writeb, taihu_cpld_writew, taihu_cpld_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void taihu_cpld_reset (void *opaque)
-{
-    taihu_cpld_t *cpld;
-
-    cpld = opaque;
-    cpld->reg0 = 0x01;
-    cpld->reg1 = 0x80;
-}
-
-static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base)
-{
-    taihu_cpld_t *cpld;
-    MemoryRegion *cpld_memory = g_new(MemoryRegion, 1);
-
-    cpld = g_malloc0(sizeof(taihu_cpld_t));
-    memory_region_init_io(cpld_memory, &taihu_cpld_ops, cpld, "cpld", 0x100);
-    memory_region_add_subregion(sysmem, base, cpld_memory);
-    qemu_register_reset(&taihu_cpld_reset, cpld);
-}
-
-static void taihu_405ep_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *kernel_filename = args->kernel_filename;
-    const char *initrd_filename = args->initrd_filename;
-    char *filename;
-    qemu_irq *pic;
-    MemoryRegion *sysmem = get_system_memory();
-    MemoryRegion *bios;
-    MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
-    hwaddr ram_bases[2], ram_sizes[2];
-    long bios_size;
-    target_ulong kernel_base, initrd_base;
-    long kernel_size, initrd_size;
-    int linux_boot;
-    int fl_idx, fl_sectors;
-    DriveInfo *dinfo;
-
-    /* RAM is soldered to the board so the size cannot be changed */
-    memory_region_init_ram(&ram_memories[0],
-                           "taihu_405ep.ram-0", 0x04000000);
-    vmstate_register_ram_global(&ram_memories[0]);
-    ram_bases[0] = 0;
-    ram_sizes[0] = 0x04000000;
-    memory_region_init_ram(&ram_memories[1],
-                           "taihu_405ep.ram-1", 0x04000000);
-    vmstate_register_ram_global(&ram_memories[1]);
-    ram_bases[1] = 0x04000000;
-    ram_sizes[1] = 0x04000000;
-    ram_size = 0x08000000;
-#ifdef DEBUG_BOARD_INIT
-    printf("%s: register cpu\n", __func__);
-#endif
-    ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
-                  33333333, &pic, kernel_filename == NULL ? 0 : 1);
-    /* allocate and load BIOS */
-#ifdef DEBUG_BOARD_INIT
-    printf("%s: register BIOS\n", __func__);
-#endif
-    fl_idx = 0;
-#if defined(USE_FLASH_BIOS)
-    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
-    if (dinfo) {
-        bios_size = bdrv_getlength(dinfo->bdrv);
-        /* XXX: should check that size is 2MB */
-        //        bios_size = 2 * 1024 * 1024;
-        fl_sectors = (bios_size + 65535) >> 16;
-#ifdef DEBUG_BOARD_INIT
-        printf("Register parallel flash %d size %lx"
-               " at addr %lx '%s' %d\n",
-               fl_idx, bios_size, -bios_size,
-               bdrv_get_device_name(dinfo->bdrv), fl_sectors);
-#endif
-        pflash_cfi02_register((uint32_t)(-bios_size),
-                              NULL, "taihu_405ep.bios", bios_size,
-                              dinfo->bdrv, 65536, fl_sectors, 1,
-                              4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
-                              1);
-        fl_idx++;
-    } else
-#endif
-    {
-#ifdef DEBUG_BOARD_INIT
-        printf("Load BIOS from file\n");
-#endif
-        if (bios_name == NULL)
-            bios_name = BIOS_FILENAME;
-        bios = g_new(MemoryRegion, 1);
-        memory_region_init_ram(bios, "taihu_405ep.bios", BIOS_SIZE);
-        vmstate_register_ram_global(bios);
-        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-        if (filename) {
-            bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
-            g_free(filename);
-        } else {
-            bios_size = -1;
-        }
-        if (bios_size < 0 || bios_size > BIOS_SIZE) {
-            fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
-                    bios_name);
-            exit(1);
-        }
-        bios_size = (bios_size + 0xfff) & ~0xfff;
-        memory_region_set_readonly(bios, true);
-        memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
-    }
-    /* Register Linux flash */
-    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
-    if (dinfo) {
-        bios_size = bdrv_getlength(dinfo->bdrv);
-        /* XXX: should check that size is 32MB */
-        bios_size = 32 * 1024 * 1024;
-        fl_sectors = (bios_size + 65535) >> 16;
-#ifdef DEBUG_BOARD_INIT
-        printf("Register parallel flash %d size %lx"
-               " at addr " TARGET_FMT_lx " '%s'\n",
-               fl_idx, bios_size, (target_ulong)0xfc000000,
-               bdrv_get_device_name(dinfo->bdrv));
-#endif
-        pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size,
-                              dinfo->bdrv, 65536, fl_sectors, 1,
-                              4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
-                              1);
-        fl_idx++;
-    }
-    /* Register CLPD & LCD display */
-#ifdef DEBUG_BOARD_INIT
-    printf("%s: register CPLD\n", __func__);
-#endif
-    taihu_cpld_init(sysmem, 0x50100000);
-    /* Load kernel */
-    linux_boot = (kernel_filename != NULL);
-    if (linux_boot) {
-#ifdef DEBUG_BOARD_INIT
-        printf("%s: load kernel\n", __func__);
-#endif
-        kernel_base = KERNEL_LOAD_ADDR;
-        /* now we can load the kernel */
-        kernel_size = load_image_targphys(kernel_filename, kernel_base,
-                                          ram_size - kernel_base);
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-        /* load initrd */
-        if (initrd_filename) {
-            initrd_base = INITRD_LOAD_ADDR;
-            initrd_size = load_image_targphys(initrd_filename, initrd_base,
-                                              ram_size - initrd_base);
-            if (initrd_size < 0) {
-                fprintf(stderr,
-                        "qemu: could not load initial ram disk '%s'\n",
-                        initrd_filename);
-                exit(1);
-            }
-        } else {
-            initrd_base = 0;
-            initrd_size = 0;
-        }
-    } else {
-        kernel_base = 0;
-        kernel_size = 0;
-        initrd_base = 0;
-        initrd_size = 0;
-    }
-#ifdef DEBUG_BOARD_INIT
-    printf("%s: Done\n", __func__);
-#endif
-}
-
-static QEMUMachine taihu_machine = {
-    .name = "taihu",
-    .desc = "taihu",
-    .init = taihu_405ep_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void ppc405_machine_init(void)
-{
-    qemu_register_machine(&ref405ep_machine);
-    qemu_register_machine(&taihu_machine);
-}
-
-machine_init(ppc405_machine_init);
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
deleted file mode 100644 (file)
index 8465f6d..0000000
+++ /dev/null
@@ -1,2548 +0,0 @@
-/*
- * QEMU PowerPC 405 embedded processors emulation
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/hw.h"
-#include "hw/ppc.h"
-#include "hw/ppc405.h"
-#include "hw/serial.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "qemu/log.h"
-#include "exec/address-spaces.h"
-
-#define DEBUG_OPBA
-#define DEBUG_SDRAM
-#define DEBUG_GPIO
-#define DEBUG_SERIAL
-#define DEBUG_OCM
-//#define DEBUG_I2C
-#define DEBUG_GPT
-#define DEBUG_MAL
-#define DEBUG_CLOCKS
-//#define DEBUG_CLOCKS_LL
-
-ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
-                                uint32_t flags)
-{
-    ram_addr_t bdloc;
-    int i, n;
-
-    /* We put the bd structure at the top of memory */
-    if (bd->bi_memsize >= 0x01000000UL)
-        bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t);
-    else
-        bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t);
-    stl_be_phys(bdloc + 0x00, bd->bi_memstart);
-    stl_be_phys(bdloc + 0x04, bd->bi_memsize);
-    stl_be_phys(bdloc + 0x08, bd->bi_flashstart);
-    stl_be_phys(bdloc + 0x0C, bd->bi_flashsize);
-    stl_be_phys(bdloc + 0x10, bd->bi_flashoffset);
-    stl_be_phys(bdloc + 0x14, bd->bi_sramstart);
-    stl_be_phys(bdloc + 0x18, bd->bi_sramsize);
-    stl_be_phys(bdloc + 0x1C, bd->bi_bootflags);
-    stl_be_phys(bdloc + 0x20, bd->bi_ipaddr);
-    for (i = 0; i < 6; i++) {
-        stb_phys(bdloc + 0x24 + i, bd->bi_enetaddr[i]);
-    }
-    stw_be_phys(bdloc + 0x2A, bd->bi_ethspeed);
-    stl_be_phys(bdloc + 0x2C, bd->bi_intfreq);
-    stl_be_phys(bdloc + 0x30, bd->bi_busfreq);
-    stl_be_phys(bdloc + 0x34, bd->bi_baudrate);
-    for (i = 0; i < 4; i++) {
-        stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]);
-    }
-    for (i = 0; i < 32; i++) {
-        stb_phys(bdloc + 0x3C + i, bd->bi_r_version[i]);
-    }
-    stl_be_phys(bdloc + 0x5C, bd->bi_plb_busfreq);
-    stl_be_phys(bdloc + 0x60, bd->bi_pci_busfreq);
-    for (i = 0; i < 6; i++) {
-        stb_phys(bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
-    }
-    n = 0x6A;
-    if (flags & 0x00000001) {
-        for (i = 0; i < 6; i++)
-            stb_phys(bdloc + n++, bd->bi_pci_enetaddr2[i]);
-    }
-    stl_be_phys(bdloc + n, bd->bi_opbfreq);
-    n += 4;
-    for (i = 0; i < 2; i++) {
-        stl_be_phys(bdloc + n, bd->bi_iic_fast[i]);
-        n += 4;
-    }
-
-    return bdloc;
-}
-
-/*****************************************************************************/
-/* Shared peripherals */
-
-/*****************************************************************************/
-/* Peripheral local bus arbitrer */
-enum {
-    PLB0_BESR = 0x084,
-    PLB0_BEAR = 0x086,
-    PLB0_ACR  = 0x087,
-};
-
-typedef struct ppc4xx_plb_t ppc4xx_plb_t;
-struct ppc4xx_plb_t {
-    uint32_t acr;
-    uint32_t bear;
-    uint32_t besr;
-};
-
-static uint32_t dcr_read_plb (void *opaque, int dcrn)
-{
-    ppc4xx_plb_t *plb;
-    uint32_t ret;
-
-    plb = opaque;
-    switch (dcrn) {
-    case PLB0_ACR:
-        ret = plb->acr;
-        break;
-    case PLB0_BEAR:
-        ret = plb->bear;
-        break;
-    case PLB0_BESR:
-        ret = plb->besr;
-        break;
-    default:
-        /* Avoid gcc warning */
-        ret = 0;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_plb (void *opaque, int dcrn, uint32_t val)
-{
-    ppc4xx_plb_t *plb;
-
-    plb = opaque;
-    switch (dcrn) {
-    case PLB0_ACR:
-        /* We don't care about the actual parameters written as
-         * we don't manage any priorities on the bus
-         */
-        plb->acr = val & 0xF8000000;
-        break;
-    case PLB0_BEAR:
-        /* Read only */
-        break;
-    case PLB0_BESR:
-        /* Write-clear */
-        plb->besr &= ~val;
-        break;
-    }
-}
-
-static void ppc4xx_plb_reset (void *opaque)
-{
-    ppc4xx_plb_t *plb;
-
-    plb = opaque;
-    plb->acr = 0x00000000;
-    plb->bear = 0x00000000;
-    plb->besr = 0x00000000;
-}
-
-static void ppc4xx_plb_init(CPUPPCState *env)
-{
-    ppc4xx_plb_t *plb;
-
-    plb = g_malloc0(sizeof(ppc4xx_plb_t));
-    ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
-    ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb);
-    ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb);
-    qemu_register_reset(ppc4xx_plb_reset, plb);
-}
-
-/*****************************************************************************/
-/* PLB to OPB bridge */
-enum {
-    POB0_BESR0 = 0x0A0,
-    POB0_BESR1 = 0x0A2,
-    POB0_BEAR  = 0x0A4,
-};
-
-typedef struct ppc4xx_pob_t ppc4xx_pob_t;
-struct ppc4xx_pob_t {
-    uint32_t bear;
-    uint32_t besr0;
-    uint32_t besr1;
-};
-
-static uint32_t dcr_read_pob (void *opaque, int dcrn)
-{
-    ppc4xx_pob_t *pob;
-    uint32_t ret;
-
-    pob = opaque;
-    switch (dcrn) {
-    case POB0_BEAR:
-        ret = pob->bear;
-        break;
-    case POB0_BESR0:
-        ret = pob->besr0;
-        break;
-    case POB0_BESR1:
-        ret = pob->besr1;
-        break;
-    default:
-        /* Avoid gcc warning */
-        ret = 0;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_pob (void *opaque, int dcrn, uint32_t val)
-{
-    ppc4xx_pob_t *pob;
-
-    pob = opaque;
-    switch (dcrn) {
-    case POB0_BEAR:
-        /* Read only */
-        break;
-    case POB0_BESR0:
-        /* Write-clear */
-        pob->besr0 &= ~val;
-        break;
-    case POB0_BESR1:
-        /* Write-clear */
-        pob->besr1 &= ~val;
-        break;
-    }
-}
-
-static void ppc4xx_pob_reset (void *opaque)
-{
-    ppc4xx_pob_t *pob;
-
-    pob = opaque;
-    /* No error */
-    pob->bear = 0x00000000;
-    pob->besr0 = 0x0000000;
-    pob->besr1 = 0x0000000;
-}
-
-static void ppc4xx_pob_init(CPUPPCState *env)
-{
-    ppc4xx_pob_t *pob;
-
-    pob = g_malloc0(sizeof(ppc4xx_pob_t));
-    ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob);
-    ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob);
-    ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob);
-    qemu_register_reset(ppc4xx_pob_reset, pob);
-}
-
-/*****************************************************************************/
-/* OPB arbitrer */
-typedef struct ppc4xx_opba_t ppc4xx_opba_t;
-struct ppc4xx_opba_t {
-    MemoryRegion io;
-    uint8_t cr;
-    uint8_t pr;
-};
-
-static uint32_t opba_readb (void *opaque, hwaddr addr)
-{
-    ppc4xx_opba_t *opba;
-    uint32_t ret;
-
-#ifdef DEBUG_OPBA
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-    opba = opaque;
-    switch (addr) {
-    case 0x00:
-        ret = opba->cr;
-        break;
-    case 0x01:
-        ret = opba->pr;
-        break;
-    default:
-        ret = 0x00;
-        break;
-    }
-
-    return ret;
-}
-
-static void opba_writeb (void *opaque,
-                         hwaddr addr, uint32_t value)
-{
-    ppc4xx_opba_t *opba;
-
-#ifdef DEBUG_OPBA
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-    opba = opaque;
-    switch (addr) {
-    case 0x00:
-        opba->cr = value & 0xF8;
-        break;
-    case 0x01:
-        opba->pr = value & 0xFF;
-        break;
-    default:
-        break;
-    }
-}
-
-static uint32_t opba_readw (void *opaque, hwaddr addr)
-{
-    uint32_t ret;
-
-#ifdef DEBUG_OPBA
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-    ret = opba_readb(opaque, addr) << 8;
-    ret |= opba_readb(opaque, addr + 1);
-
-    return ret;
-}
-
-static void opba_writew (void *opaque,
-                         hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_OPBA
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-    opba_writeb(opaque, addr, value >> 8);
-    opba_writeb(opaque, addr + 1, value);
-}
-
-static uint32_t opba_readl (void *opaque, hwaddr addr)
-{
-    uint32_t ret;
-
-#ifdef DEBUG_OPBA
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-    ret = opba_readb(opaque, addr) << 24;
-    ret |= opba_readb(opaque, addr + 1) << 16;
-
-    return ret;
-}
-
-static void opba_writel (void *opaque,
-                         hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_OPBA
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-    opba_writeb(opaque, addr, value >> 24);
-    opba_writeb(opaque, addr + 1, value >> 16);
-}
-
-static const MemoryRegionOps opba_ops = {
-    .old_mmio = {
-        .read = { opba_readb, opba_readw, opba_readl, },
-        .write = { opba_writeb, opba_writew, opba_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ppc4xx_opba_reset (void *opaque)
-{
-    ppc4xx_opba_t *opba;
-
-    opba = opaque;
-    opba->cr = 0x00; /* No dynamic priorities - park disabled */
-    opba->pr = 0x11;
-}
-
-static void ppc4xx_opba_init(hwaddr base)
-{
-    ppc4xx_opba_t *opba;
-
-    opba = g_malloc0(sizeof(ppc4xx_opba_t));
-#ifdef DEBUG_OPBA
-    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
-#endif
-    memory_region_init_io(&opba->io, &opba_ops, opba, "opba", 0x002);
-    memory_region_add_subregion(get_system_memory(), base, &opba->io);
-    qemu_register_reset(ppc4xx_opba_reset, opba);
-}
-
-/*****************************************************************************/
-/* Code decompression controller */
-/* XXX: TODO */
-
-/*****************************************************************************/
-/* Peripheral controller */
-typedef struct ppc4xx_ebc_t ppc4xx_ebc_t;
-struct ppc4xx_ebc_t {
-    uint32_t addr;
-    uint32_t bcr[8];
-    uint32_t bap[8];
-    uint32_t bear;
-    uint32_t besr0;
-    uint32_t besr1;
-    uint32_t cfg;
-};
-
-enum {
-    EBC0_CFGADDR = 0x012,
-    EBC0_CFGDATA = 0x013,
-};
-
-static uint32_t dcr_read_ebc (void *opaque, int dcrn)
-{
-    ppc4xx_ebc_t *ebc;
-    uint32_t ret;
-
-    ebc = opaque;
-    switch (dcrn) {
-    case EBC0_CFGADDR:
-        ret = ebc->addr;
-        break;
-    case EBC0_CFGDATA:
-        switch (ebc->addr) {
-        case 0x00: /* B0CR */
-            ret = ebc->bcr[0];
-            break;
-        case 0x01: /* B1CR */
-            ret = ebc->bcr[1];
-            break;
-        case 0x02: /* B2CR */
-            ret = ebc->bcr[2];
-            break;
-        case 0x03: /* B3CR */
-            ret = ebc->bcr[3];
-            break;
-        case 0x04: /* B4CR */
-            ret = ebc->bcr[4];
-            break;
-        case 0x05: /* B5CR */
-            ret = ebc->bcr[5];
-            break;
-        case 0x06: /* B6CR */
-            ret = ebc->bcr[6];
-            break;
-        case 0x07: /* B7CR */
-            ret = ebc->bcr[7];
-            break;
-        case 0x10: /* B0AP */
-            ret = ebc->bap[0];
-            break;
-        case 0x11: /* B1AP */
-            ret = ebc->bap[1];
-            break;
-        case 0x12: /* B2AP */
-            ret = ebc->bap[2];
-            break;
-        case 0x13: /* B3AP */
-            ret = ebc->bap[3];
-            break;
-        case 0x14: /* B4AP */
-            ret = ebc->bap[4];
-            break;
-        case 0x15: /* B5AP */
-            ret = ebc->bap[5];
-            break;
-        case 0x16: /* B6AP */
-            ret = ebc->bap[6];
-            break;
-        case 0x17: /* B7AP */
-            ret = ebc->bap[7];
-            break;
-        case 0x20: /* BEAR */
-            ret = ebc->bear;
-            break;
-        case 0x21: /* BESR0 */
-            ret = ebc->besr0;
-            break;
-        case 0x22: /* BESR1 */
-            ret = ebc->besr1;
-            break;
-        case 0x23: /* CFG */
-            ret = ebc->cfg;
-            break;
-        default:
-            ret = 0x00000000;
-            break;
-        }
-        break;
-    default:
-        ret = 0x00000000;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_ebc (void *opaque, int dcrn, uint32_t val)
-{
-    ppc4xx_ebc_t *ebc;
-
-    ebc = opaque;
-    switch (dcrn) {
-    case EBC0_CFGADDR:
-        ebc->addr = val;
-        break;
-    case EBC0_CFGDATA:
-        switch (ebc->addr) {
-        case 0x00: /* B0CR */
-            break;
-        case 0x01: /* B1CR */
-            break;
-        case 0x02: /* B2CR */
-            break;
-        case 0x03: /* B3CR */
-            break;
-        case 0x04: /* B4CR */
-            break;
-        case 0x05: /* B5CR */
-            break;
-        case 0x06: /* B6CR */
-            break;
-        case 0x07: /* B7CR */
-            break;
-        case 0x10: /* B0AP */
-            break;
-        case 0x11: /* B1AP */
-            break;
-        case 0x12: /* B2AP */
-            break;
-        case 0x13: /* B3AP */
-            break;
-        case 0x14: /* B4AP */
-            break;
-        case 0x15: /* B5AP */
-            break;
-        case 0x16: /* B6AP */
-            break;
-        case 0x17: /* B7AP */
-            break;
-        case 0x20: /* BEAR */
-            break;
-        case 0x21: /* BESR0 */
-            break;
-        case 0x22: /* BESR1 */
-            break;
-        case 0x23: /* CFG */
-            break;
-        default:
-            break;
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-static void ebc_reset (void *opaque)
-{
-    ppc4xx_ebc_t *ebc;
-    int i;
-
-    ebc = opaque;
-    ebc->addr = 0x00000000;
-    ebc->bap[0] = 0x7F8FFE80;
-    ebc->bcr[0] = 0xFFE28000;
-    for (i = 0; i < 8; i++) {
-        ebc->bap[i] = 0x00000000;
-        ebc->bcr[i] = 0x00000000;
-    }
-    ebc->besr0 = 0x00000000;
-    ebc->besr1 = 0x00000000;
-    ebc->cfg = 0x80400000;
-}
-
-static void ppc405_ebc_init(CPUPPCState *env)
-{
-    ppc4xx_ebc_t *ebc;
-
-    ebc = g_malloc0(sizeof(ppc4xx_ebc_t));
-    qemu_register_reset(&ebc_reset, ebc);
-    ppc_dcr_register(env, EBC0_CFGADDR,
-                     ebc, &dcr_read_ebc, &dcr_write_ebc);
-    ppc_dcr_register(env, EBC0_CFGDATA,
-                     ebc, &dcr_read_ebc, &dcr_write_ebc);
-}
-
-/*****************************************************************************/
-/* DMA controller */
-enum {
-    DMA0_CR0 = 0x100,
-    DMA0_CT0 = 0x101,
-    DMA0_DA0 = 0x102,
-    DMA0_SA0 = 0x103,
-    DMA0_SG0 = 0x104,
-    DMA0_CR1 = 0x108,
-    DMA0_CT1 = 0x109,
-    DMA0_DA1 = 0x10A,
-    DMA0_SA1 = 0x10B,
-    DMA0_SG1 = 0x10C,
-    DMA0_CR2 = 0x110,
-    DMA0_CT2 = 0x111,
-    DMA0_DA2 = 0x112,
-    DMA0_SA2 = 0x113,
-    DMA0_SG2 = 0x114,
-    DMA0_CR3 = 0x118,
-    DMA0_CT3 = 0x119,
-    DMA0_DA3 = 0x11A,
-    DMA0_SA3 = 0x11B,
-    DMA0_SG3 = 0x11C,
-    DMA0_SR  = 0x120,
-    DMA0_SGC = 0x123,
-    DMA0_SLP = 0x125,
-    DMA0_POL = 0x126,
-};
-
-typedef struct ppc405_dma_t ppc405_dma_t;
-struct ppc405_dma_t {
-    qemu_irq irqs[4];
-    uint32_t cr[4];
-    uint32_t ct[4];
-    uint32_t da[4];
-    uint32_t sa[4];
-    uint32_t sg[4];
-    uint32_t sr;
-    uint32_t sgc;
-    uint32_t slp;
-    uint32_t pol;
-};
-
-static uint32_t dcr_read_dma (void *opaque, int dcrn)
-{
-    return 0;
-}
-
-static void dcr_write_dma (void *opaque, int dcrn, uint32_t val)
-{
-}
-
-static void ppc405_dma_reset (void *opaque)
-{
-    ppc405_dma_t *dma;
-    int i;
-
-    dma = opaque;
-    for (i = 0; i < 4; i++) {
-        dma->cr[i] = 0x00000000;
-        dma->ct[i] = 0x00000000;
-        dma->da[i] = 0x00000000;
-        dma->sa[i] = 0x00000000;
-        dma->sg[i] = 0x00000000;
-    }
-    dma->sr = 0x00000000;
-    dma->sgc = 0x00000000;
-    dma->slp = 0x7C000000;
-    dma->pol = 0x00000000;
-}
-
-static void ppc405_dma_init(CPUPPCState *env, qemu_irq irqs[4])
-{
-    ppc405_dma_t *dma;
-
-    dma = g_malloc0(sizeof(ppc405_dma_t));
-    memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq));
-    qemu_register_reset(&ppc405_dma_reset, dma);
-    ppc_dcr_register(env, DMA0_CR0,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_CT0,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_DA0,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SA0,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SG0,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_CR1,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_CT1,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_DA1,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SA1,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SG1,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_CR2,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_CT2,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_DA2,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SA2,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SG2,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_CR3,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_CT3,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_DA3,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SA3,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SG3,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SR,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SGC,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_SLP,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-    ppc_dcr_register(env, DMA0_POL,
-                     dma, &dcr_read_dma, &dcr_write_dma);
-}
-
-/*****************************************************************************/
-/* GPIO */
-typedef struct ppc405_gpio_t ppc405_gpio_t;
-struct ppc405_gpio_t {
-    MemoryRegion io;
-    uint32_t or;
-    uint32_t tcr;
-    uint32_t osrh;
-    uint32_t osrl;
-    uint32_t tsrh;
-    uint32_t tsrl;
-    uint32_t odr;
-    uint32_t ir;
-    uint32_t rr1;
-    uint32_t isr1h;
-    uint32_t isr1l;
-};
-
-static uint32_t ppc405_gpio_readb (void *opaque, hwaddr addr)
-{
-#ifdef DEBUG_GPIO
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-
-    return 0;
-}
-
-static void ppc405_gpio_writeb (void *opaque,
-                                hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_GPIO
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-}
-
-static uint32_t ppc405_gpio_readw (void *opaque, hwaddr addr)
-{
-#ifdef DEBUG_GPIO
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-
-    return 0;
-}
-
-static void ppc405_gpio_writew (void *opaque,
-                                hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_GPIO
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-}
-
-static uint32_t ppc405_gpio_readl (void *opaque, hwaddr addr)
-{
-#ifdef DEBUG_GPIO
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-
-    return 0;
-}
-
-static void ppc405_gpio_writel (void *opaque,
-                                hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_GPIO
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-}
-
-static const MemoryRegionOps ppc405_gpio_ops = {
-    .old_mmio = {
-        .read = { ppc405_gpio_readb, ppc405_gpio_readw, ppc405_gpio_readl, },
-        .write = { ppc405_gpio_writeb, ppc405_gpio_writew, ppc405_gpio_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ppc405_gpio_reset (void *opaque)
-{
-}
-
-static void ppc405_gpio_init(hwaddr base)
-{
-    ppc405_gpio_t *gpio;
-
-    gpio = g_malloc0(sizeof(ppc405_gpio_t));
-#ifdef DEBUG_GPIO
-    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
-#endif
-    memory_region_init_io(&gpio->io, &ppc405_gpio_ops, gpio, "pgio", 0x038);
-    memory_region_add_subregion(get_system_memory(), base, &gpio->io);
-    qemu_register_reset(&ppc405_gpio_reset, gpio);
-}
-
-/*****************************************************************************/
-/* On Chip Memory */
-enum {
-    OCM0_ISARC   = 0x018,
-    OCM0_ISACNTL = 0x019,
-    OCM0_DSARC   = 0x01A,
-    OCM0_DSACNTL = 0x01B,
-};
-
-typedef struct ppc405_ocm_t ppc405_ocm_t;
-struct ppc405_ocm_t {
-    MemoryRegion ram;
-    MemoryRegion isarc_ram;
-    MemoryRegion dsarc_ram;
-    uint32_t isarc;
-    uint32_t isacntl;
-    uint32_t dsarc;
-    uint32_t dsacntl;
-};
-
-static void ocm_update_mappings (ppc405_ocm_t *ocm,
-                                 uint32_t isarc, uint32_t isacntl,
-                                 uint32_t dsarc, uint32_t dsacntl)
-{
-#ifdef DEBUG_OCM
-    printf("OCM update ISA %08" PRIx32 " %08" PRIx32 " (%08" PRIx32
-           " %08" PRIx32 ") DSA %08" PRIx32 " %08" PRIx32
-           " (%08" PRIx32 " %08" PRIx32 ")\n",
-           isarc, isacntl, dsarc, dsacntl,
-           ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl);
-#endif
-    if (ocm->isarc != isarc ||
-        (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) {
-        if (ocm->isacntl & 0x80000000) {
-            /* Unmap previously assigned memory region */
-            printf("OCM unmap ISA %08" PRIx32 "\n", ocm->isarc);
-            memory_region_del_subregion(get_system_memory(), &ocm->isarc_ram);
-        }
-        if (isacntl & 0x80000000) {
-            /* Map new instruction memory region */
-#ifdef DEBUG_OCM
-            printf("OCM map ISA %08" PRIx32 "\n", isarc);
-#endif
-            memory_region_add_subregion(get_system_memory(), isarc,
-                                        &ocm->isarc_ram);
-        }
-    }
-    if (ocm->dsarc != dsarc ||
-        (ocm->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) {
-        if (ocm->dsacntl & 0x80000000) {
-            /* Beware not to unmap the region we just mapped */
-            if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) {
-                /* Unmap previously assigned memory region */
-#ifdef DEBUG_OCM
-                printf("OCM unmap DSA %08" PRIx32 "\n", ocm->dsarc);
-#endif
-                memory_region_del_subregion(get_system_memory(),
-                                            &ocm->dsarc_ram);
-            }
-        }
-        if (dsacntl & 0x80000000) {
-            /* Beware not to remap the region we just mapped */
-            if (!(isacntl & 0x80000000) || dsarc != isarc) {
-                /* Map new data memory region */
-#ifdef DEBUG_OCM
-                printf("OCM map DSA %08" PRIx32 "\n", dsarc);
-#endif
-                memory_region_add_subregion(get_system_memory(), dsarc,
-                                            &ocm->dsarc_ram);
-            }
-        }
-    }
-}
-
-static uint32_t dcr_read_ocm (void *opaque, int dcrn)
-{
-    ppc405_ocm_t *ocm;
-    uint32_t ret;
-
-    ocm = opaque;
-    switch (dcrn) {
-    case OCM0_ISARC:
-        ret = ocm->isarc;
-        break;
-    case OCM0_ISACNTL:
-        ret = ocm->isacntl;
-        break;
-    case OCM0_DSARC:
-        ret = ocm->dsarc;
-        break;
-    case OCM0_DSACNTL:
-        ret = ocm->dsacntl;
-        break;
-    default:
-        ret = 0;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_ocm (void *opaque, int dcrn, uint32_t val)
-{
-    ppc405_ocm_t *ocm;
-    uint32_t isarc, dsarc, isacntl, dsacntl;
-
-    ocm = opaque;
-    isarc = ocm->isarc;
-    dsarc = ocm->dsarc;
-    isacntl = ocm->isacntl;
-    dsacntl = ocm->dsacntl;
-    switch (dcrn) {
-    case OCM0_ISARC:
-        isarc = val & 0xFC000000;
-        break;
-    case OCM0_ISACNTL:
-        isacntl = val & 0xC0000000;
-        break;
-    case OCM0_DSARC:
-        isarc = val & 0xFC000000;
-        break;
-    case OCM0_DSACNTL:
-        isacntl = val & 0xC0000000;
-        break;
-    }
-    ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
-    ocm->isarc = isarc;
-    ocm->dsarc = dsarc;
-    ocm->isacntl = isacntl;
-    ocm->dsacntl = dsacntl;
-}
-
-static void ocm_reset (void *opaque)
-{
-    ppc405_ocm_t *ocm;
-    uint32_t isarc, dsarc, isacntl, dsacntl;
-
-    ocm = opaque;
-    isarc = 0x00000000;
-    isacntl = 0x00000000;
-    dsarc = 0x00000000;
-    dsacntl = 0x00000000;
-    ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
-    ocm->isarc = isarc;
-    ocm->dsarc = dsarc;
-    ocm->isacntl = isacntl;
-    ocm->dsacntl = dsacntl;
-}
-
-static void ppc405_ocm_init(CPUPPCState *env)
-{
-    ppc405_ocm_t *ocm;
-
-    ocm = g_malloc0(sizeof(ppc405_ocm_t));
-    /* XXX: Size is 4096 or 0x04000000 */
-    memory_region_init_ram(&ocm->isarc_ram, "ppc405.ocm", 4096);
-    vmstate_register_ram_global(&ocm->isarc_ram);
-    memory_region_init_alias(&ocm->dsarc_ram, "ppc405.dsarc", &ocm->isarc_ram,
-                             0, 4096);
-    qemu_register_reset(&ocm_reset, ocm);
-    ppc_dcr_register(env, OCM0_ISARC,
-                     ocm, &dcr_read_ocm, &dcr_write_ocm);
-    ppc_dcr_register(env, OCM0_ISACNTL,
-                     ocm, &dcr_read_ocm, &dcr_write_ocm);
-    ppc_dcr_register(env, OCM0_DSARC,
-                     ocm, &dcr_read_ocm, &dcr_write_ocm);
-    ppc_dcr_register(env, OCM0_DSACNTL,
-                     ocm, &dcr_read_ocm, &dcr_write_ocm);
-}
-
-/*****************************************************************************/
-/* I2C controller */
-typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
-struct ppc4xx_i2c_t {
-    qemu_irq irq;
-    MemoryRegion iomem;
-    uint8_t mdata;
-    uint8_t lmadr;
-    uint8_t hmadr;
-    uint8_t cntl;
-    uint8_t mdcntl;
-    uint8_t sts;
-    uint8_t extsts;
-    uint8_t sdata;
-    uint8_t lsadr;
-    uint8_t hsadr;
-    uint8_t clkdiv;
-    uint8_t intrmsk;
-    uint8_t xfrcnt;
-    uint8_t xtcntlss;
-    uint8_t directcntl;
-};
-
-static uint32_t ppc4xx_i2c_readb (void *opaque, hwaddr addr)
-{
-    ppc4xx_i2c_t *i2c;
-    uint32_t ret;
-
-#ifdef DEBUG_I2C
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-    i2c = opaque;
-    switch (addr) {
-    case 0x00:
-        //        i2c_readbyte(&i2c->mdata);
-        ret = i2c->mdata;
-        break;
-    case 0x02:
-        ret = i2c->sdata;
-        break;
-    case 0x04:
-        ret = i2c->lmadr;
-        break;
-    case 0x05:
-        ret = i2c->hmadr;
-        break;
-    case 0x06:
-        ret = i2c->cntl;
-        break;
-    case 0x07:
-        ret = i2c->mdcntl;
-        break;
-    case 0x08:
-        ret = i2c->sts;
-        break;
-    case 0x09:
-        ret = i2c->extsts;
-        break;
-    case 0x0A:
-        ret = i2c->lsadr;
-        break;
-    case 0x0B:
-        ret = i2c->hsadr;
-        break;
-    case 0x0C:
-        ret = i2c->clkdiv;
-        break;
-    case 0x0D:
-        ret = i2c->intrmsk;
-        break;
-    case 0x0E:
-        ret = i2c->xfrcnt;
-        break;
-    case 0x0F:
-        ret = i2c->xtcntlss;
-        break;
-    case 0x10:
-        ret = i2c->directcntl;
-        break;
-    default:
-        ret = 0x00;
-        break;
-    }
-#ifdef DEBUG_I2C
-    printf("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__, addr, ret);
-#endif
-
-    return ret;
-}
-
-static void ppc4xx_i2c_writeb (void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-    ppc4xx_i2c_t *i2c;
-
-#ifdef DEBUG_I2C
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-    i2c = opaque;
-    switch (addr) {
-    case 0x00:
-        i2c->mdata = value;
-        //        i2c_sendbyte(&i2c->mdata);
-        break;
-    case 0x02:
-        i2c->sdata = value;
-        break;
-    case 0x04:
-        i2c->lmadr = value;
-        break;
-    case 0x05:
-        i2c->hmadr = value;
-        break;
-    case 0x06:
-        i2c->cntl = value;
-        break;
-    case 0x07:
-        i2c->mdcntl = value & 0xDF;
-        break;
-    case 0x08:
-        i2c->sts &= ~(value & 0x0A);
-        break;
-    case 0x09:
-        i2c->extsts &= ~(value & 0x8F);
-        break;
-    case 0x0A:
-        i2c->lsadr = value;
-        break;
-    case 0x0B:
-        i2c->hsadr = value;
-        break;
-    case 0x0C:
-        i2c->clkdiv = value;
-        break;
-    case 0x0D:
-        i2c->intrmsk = value;
-        break;
-    case 0x0E:
-        i2c->xfrcnt = value & 0x77;
-        break;
-    case 0x0F:
-        i2c->xtcntlss = value;
-        break;
-    case 0x10:
-        i2c->directcntl = value & 0x7;
-        break;
-    }
-}
-
-static uint32_t ppc4xx_i2c_readw (void *opaque, hwaddr addr)
-{
-    uint32_t ret;
-
-#ifdef DEBUG_I2C
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-    ret = ppc4xx_i2c_readb(opaque, addr) << 8;
-    ret |= ppc4xx_i2c_readb(opaque, addr + 1);
-
-    return ret;
-}
-
-static void ppc4xx_i2c_writew (void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_I2C
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-    ppc4xx_i2c_writeb(opaque, addr, value >> 8);
-    ppc4xx_i2c_writeb(opaque, addr + 1, value);
-}
-
-static uint32_t ppc4xx_i2c_readl (void *opaque, hwaddr addr)
-{
-    uint32_t ret;
-
-#ifdef DEBUG_I2C
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-    ret = ppc4xx_i2c_readb(opaque, addr) << 24;
-    ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16;
-    ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8;
-    ret |= ppc4xx_i2c_readb(opaque, addr + 3);
-
-    return ret;
-}
-
-static void ppc4xx_i2c_writel (void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_I2C
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-    ppc4xx_i2c_writeb(opaque, addr, value >> 24);
-    ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16);
-    ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8);
-    ppc4xx_i2c_writeb(opaque, addr + 3, value);
-}
-
-static const MemoryRegionOps i2c_ops = {
-    .old_mmio = {
-        .read = { ppc4xx_i2c_readb, ppc4xx_i2c_readw, ppc4xx_i2c_readl, },
-        .write = { ppc4xx_i2c_writeb, ppc4xx_i2c_writew, ppc4xx_i2c_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ppc4xx_i2c_reset (void *opaque)
-{
-    ppc4xx_i2c_t *i2c;
-
-    i2c = opaque;
-    i2c->mdata = 0x00;
-    i2c->sdata = 0x00;
-    i2c->cntl = 0x00;
-    i2c->mdcntl = 0x00;
-    i2c->sts = 0x00;
-    i2c->extsts = 0x00;
-    i2c->clkdiv = 0x00;
-    i2c->xfrcnt = 0x00;
-    i2c->directcntl = 0x0F;
-}
-
-static void ppc405_i2c_init(hwaddr base, qemu_irq irq)
-{
-    ppc4xx_i2c_t *i2c;
-
-    i2c = g_malloc0(sizeof(ppc4xx_i2c_t));
-    i2c->irq = irq;
-#ifdef DEBUG_I2C
-    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
-#endif
-    memory_region_init_io(&i2c->iomem, &i2c_ops, i2c, "i2c", 0x011);
-    memory_region_add_subregion(get_system_memory(), base, &i2c->iomem);
-    qemu_register_reset(ppc4xx_i2c_reset, i2c);
-}
-
-/*****************************************************************************/
-/* General purpose timers */
-typedef struct ppc4xx_gpt_t ppc4xx_gpt_t;
-struct ppc4xx_gpt_t {
-    MemoryRegion iomem;
-    int64_t tb_offset;
-    uint32_t tb_freq;
-    struct QEMUTimer *timer;
-    qemu_irq irqs[5];
-    uint32_t oe;
-    uint32_t ol;
-    uint32_t im;
-    uint32_t is;
-    uint32_t ie;
-    uint32_t comp[5];
-    uint32_t mask[5];
-};
-
-static uint32_t ppc4xx_gpt_readb (void *opaque, hwaddr addr)
-{
-#ifdef DEBUG_GPT
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-    /* XXX: generate a bus fault */
-    return -1;
-}
-
-static void ppc4xx_gpt_writeb (void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_I2C
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-    /* XXX: generate a bus fault */
-}
-
-static uint32_t ppc4xx_gpt_readw (void *opaque, hwaddr addr)
-{
-#ifdef DEBUG_GPT
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-    /* XXX: generate a bus fault */
-    return -1;
-}
-
-static void ppc4xx_gpt_writew (void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_I2C
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-    /* XXX: generate a bus fault */
-}
-
-static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n)
-{
-    /* XXX: TODO */
-    return 0;
-}
-
-static void ppc4xx_gpt_set_output (ppc4xx_gpt_t *gpt, int n, int level)
-{
-    /* XXX: TODO */
-}
-
-static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt)
-{
-    uint32_t mask;
-    int i;
-
-    mask = 0x80000000;
-    for (i = 0; i < 5; i++) {
-        if (gpt->oe & mask) {
-            /* Output is enabled */
-            if (ppc4xx_gpt_compare(gpt, i)) {
-                /* Comparison is OK */
-                ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask);
-            } else {
-                /* Comparison is KO */
-                ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask ? 0 : 1);
-            }
-        }
-        mask = mask >> 1;
-    }
-}
-
-static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt)
-{
-    uint32_t mask;
-    int i;
-
-    mask = 0x00008000;
-    for (i = 0; i < 5; i++) {
-        if (gpt->is & gpt->im & mask)
-            qemu_irq_raise(gpt->irqs[i]);
-        else
-            qemu_irq_lower(gpt->irqs[i]);
-        mask = mask >> 1;
-    }
-}
-
-static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt)
-{
-    /* XXX: TODO */
-}
-
-static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr)
-{
-    ppc4xx_gpt_t *gpt;
-    uint32_t ret;
-    int idx;
-
-#ifdef DEBUG_GPT
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-    gpt = opaque;
-    switch (addr) {
-    case 0x00:
-        /* Time base counter */
-        ret = muldiv64(qemu_get_clock_ns(vm_clock) + gpt->tb_offset,
-                       gpt->tb_freq, get_ticks_per_sec());
-        break;
-    case 0x10:
-        /* Output enable */
-        ret = gpt->oe;
-        break;
-    case 0x14:
-        /* Output level */
-        ret = gpt->ol;
-        break;
-    case 0x18:
-        /* Interrupt mask */
-        ret = gpt->im;
-        break;
-    case 0x1C:
-    case 0x20:
-        /* Interrupt status */
-        ret = gpt->is;
-        break;
-    case 0x24:
-        /* Interrupt enable */
-        ret = gpt->ie;
-        break;
-    case 0x80 ... 0x90:
-        /* Compare timer */
-        idx = (addr - 0x80) >> 2;
-        ret = gpt->comp[idx];
-        break;
-    case 0xC0 ... 0xD0:
-        /* Compare mask */
-        idx = (addr - 0xC0) >> 2;
-        ret = gpt->mask[idx];
-        break;
-    default:
-        ret = -1;
-        break;
-    }
-
-    return ret;
-}
-
-static void ppc4xx_gpt_writel (void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-    ppc4xx_gpt_t *gpt;
-    int idx;
-
-#ifdef DEBUG_I2C
-    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
-           value);
-#endif
-    gpt = opaque;
-    switch (addr) {
-    case 0x00:
-        /* Time base counter */
-        gpt->tb_offset = muldiv64(value, get_ticks_per_sec(), gpt->tb_freq)
-            - qemu_get_clock_ns(vm_clock);
-        ppc4xx_gpt_compute_timer(gpt);
-        break;
-    case 0x10:
-        /* Output enable */
-        gpt->oe = value & 0xF8000000;
-        ppc4xx_gpt_set_outputs(gpt);
-        break;
-    case 0x14:
-        /* Output level */
-        gpt->ol = value & 0xF8000000;
-        ppc4xx_gpt_set_outputs(gpt);
-        break;
-    case 0x18:
-        /* Interrupt mask */
-        gpt->im = value & 0x0000F800;
-        break;
-    case 0x1C:
-        /* Interrupt status set */
-        gpt->is |= value & 0x0000F800;
-        ppc4xx_gpt_set_irqs(gpt);
-        break;
-    case 0x20:
-        /* Interrupt status clear */
-        gpt->is &= ~(value & 0x0000F800);
-        ppc4xx_gpt_set_irqs(gpt);
-        break;
-    case 0x24:
-        /* Interrupt enable */
-        gpt->ie = value & 0x0000F800;
-        ppc4xx_gpt_set_irqs(gpt);
-        break;
-    case 0x80 ... 0x90:
-        /* Compare timer */
-        idx = (addr - 0x80) >> 2;
-        gpt->comp[idx] = value & 0xF8000000;
-        ppc4xx_gpt_compute_timer(gpt);
-        break;
-    case 0xC0 ... 0xD0:
-        /* Compare mask */
-        idx = (addr - 0xC0) >> 2;
-        gpt->mask[idx] = value & 0xF8000000;
-        ppc4xx_gpt_compute_timer(gpt);
-        break;
-    }
-}
-
-static const MemoryRegionOps gpt_ops = {
-    .old_mmio = {
-        .read = { ppc4xx_gpt_readb, ppc4xx_gpt_readw, ppc4xx_gpt_readl, },
-        .write = { ppc4xx_gpt_writeb, ppc4xx_gpt_writew, ppc4xx_gpt_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ppc4xx_gpt_cb (void *opaque)
-{
-    ppc4xx_gpt_t *gpt;
-
-    gpt = opaque;
-    ppc4xx_gpt_set_irqs(gpt);
-    ppc4xx_gpt_set_outputs(gpt);
-    ppc4xx_gpt_compute_timer(gpt);
-}
-
-static void ppc4xx_gpt_reset (void *opaque)
-{
-    ppc4xx_gpt_t *gpt;
-    int i;
-
-    gpt = opaque;
-    qemu_del_timer(gpt->timer);
-    gpt->oe = 0x00000000;
-    gpt->ol = 0x00000000;
-    gpt->im = 0x00000000;
-    gpt->is = 0x00000000;
-    gpt->ie = 0x00000000;
-    for (i = 0; i < 5; i++) {
-        gpt->comp[i] = 0x00000000;
-        gpt->mask[i] = 0x00000000;
-    }
-}
-
-static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5])
-{
-    ppc4xx_gpt_t *gpt;
-    int i;
-
-    gpt = g_malloc0(sizeof(ppc4xx_gpt_t));
-    for (i = 0; i < 5; i++) {
-        gpt->irqs[i] = irqs[i];
-    }
-    gpt->timer = qemu_new_timer_ns(vm_clock, &ppc4xx_gpt_cb, gpt);
-#ifdef DEBUG_GPT
-    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
-#endif
-    memory_region_init_io(&gpt->iomem, &gpt_ops, gpt, "gpt", 0x0d4);
-    memory_region_add_subregion(get_system_memory(), base, &gpt->iomem);
-    qemu_register_reset(ppc4xx_gpt_reset, gpt);
-}
-
-/*****************************************************************************/
-/* MAL */
-enum {
-    MAL0_CFG      = 0x180,
-    MAL0_ESR      = 0x181,
-    MAL0_IER      = 0x182,
-    MAL0_TXCASR   = 0x184,
-    MAL0_TXCARR   = 0x185,
-    MAL0_TXEOBISR = 0x186,
-    MAL0_TXDEIR   = 0x187,
-    MAL0_RXCASR   = 0x190,
-    MAL0_RXCARR   = 0x191,
-    MAL0_RXEOBISR = 0x192,
-    MAL0_RXDEIR   = 0x193,
-    MAL0_TXCTP0R  = 0x1A0,
-    MAL0_TXCTP1R  = 0x1A1,
-    MAL0_TXCTP2R  = 0x1A2,
-    MAL0_TXCTP3R  = 0x1A3,
-    MAL0_RXCTP0R  = 0x1C0,
-    MAL0_RXCTP1R  = 0x1C1,
-    MAL0_RCBS0    = 0x1E0,
-    MAL0_RCBS1    = 0x1E1,
-};
-
-typedef struct ppc40x_mal_t ppc40x_mal_t;
-struct ppc40x_mal_t {
-    qemu_irq irqs[4];
-    uint32_t cfg;
-    uint32_t esr;
-    uint32_t ier;
-    uint32_t txcasr;
-    uint32_t txcarr;
-    uint32_t txeobisr;
-    uint32_t txdeir;
-    uint32_t rxcasr;
-    uint32_t rxcarr;
-    uint32_t rxeobisr;
-    uint32_t rxdeir;
-    uint32_t txctpr[4];
-    uint32_t rxctpr[2];
-    uint32_t rcbs[2];
-};
-
-static void ppc40x_mal_reset (void *opaque);
-
-static uint32_t dcr_read_mal (void *opaque, int dcrn)
-{
-    ppc40x_mal_t *mal;
-    uint32_t ret;
-
-    mal = opaque;
-    switch (dcrn) {
-    case MAL0_CFG:
-        ret = mal->cfg;
-        break;
-    case MAL0_ESR:
-        ret = mal->esr;
-        break;
-    case MAL0_IER:
-        ret = mal->ier;
-        break;
-    case MAL0_TXCASR:
-        ret = mal->txcasr;
-        break;
-    case MAL0_TXCARR:
-        ret = mal->txcarr;
-        break;
-    case MAL0_TXEOBISR:
-        ret = mal->txeobisr;
-        break;
-    case MAL0_TXDEIR:
-        ret = mal->txdeir;
-        break;
-    case MAL0_RXCASR:
-        ret = mal->rxcasr;
-        break;
-    case MAL0_RXCARR:
-        ret = mal->rxcarr;
-        break;
-    case MAL0_RXEOBISR:
-        ret = mal->rxeobisr;
-        break;
-    case MAL0_RXDEIR:
-        ret = mal->rxdeir;
-        break;
-    case MAL0_TXCTP0R:
-        ret = mal->txctpr[0];
-        break;
-    case MAL0_TXCTP1R:
-        ret = mal->txctpr[1];
-        break;
-    case MAL0_TXCTP2R:
-        ret = mal->txctpr[2];
-        break;
-    case MAL0_TXCTP3R:
-        ret = mal->txctpr[3];
-        break;
-    case MAL0_RXCTP0R:
-        ret = mal->rxctpr[0];
-        break;
-    case MAL0_RXCTP1R:
-        ret = mal->rxctpr[1];
-        break;
-    case MAL0_RCBS0:
-        ret = mal->rcbs[0];
-        break;
-    case MAL0_RCBS1:
-        ret = mal->rcbs[1];
-        break;
-    default:
-        ret = 0;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_mal (void *opaque, int dcrn, uint32_t val)
-{
-    ppc40x_mal_t *mal;
-    int idx;
-
-    mal = opaque;
-    switch (dcrn) {
-    case MAL0_CFG:
-        if (val & 0x80000000)
-            ppc40x_mal_reset(mal);
-        mal->cfg = val & 0x00FFC087;
-        break;
-    case MAL0_ESR:
-        /* Read/clear */
-        mal->esr &= ~val;
-        break;
-    case MAL0_IER:
-        mal->ier = val & 0x0000001F;
-        break;
-    case MAL0_TXCASR:
-        mal->txcasr = val & 0xF0000000;
-        break;
-    case MAL0_TXCARR:
-        mal->txcarr = val & 0xF0000000;
-        break;
-    case MAL0_TXEOBISR:
-        /* Read/clear */
-        mal->txeobisr &= ~val;
-        break;
-    case MAL0_TXDEIR:
-        /* Read/clear */
-        mal->txdeir &= ~val;
-        break;
-    case MAL0_RXCASR:
-        mal->rxcasr = val & 0xC0000000;
-        break;
-    case MAL0_RXCARR:
-        mal->rxcarr = val & 0xC0000000;
-        break;
-    case MAL0_RXEOBISR:
-        /* Read/clear */
-        mal->rxeobisr &= ~val;
-        break;
-    case MAL0_RXDEIR:
-        /* Read/clear */
-        mal->rxdeir &= ~val;
-        break;
-    case MAL0_TXCTP0R:
-        idx = 0;
-        goto update_tx_ptr;
-    case MAL0_TXCTP1R:
-        idx = 1;
-        goto update_tx_ptr;
-    case MAL0_TXCTP2R:
-        idx = 2;
-        goto update_tx_ptr;
-    case MAL0_TXCTP3R:
-        idx = 3;
-    update_tx_ptr:
-        mal->txctpr[idx] = val;
-        break;
-    case MAL0_RXCTP0R:
-        idx = 0;
-        goto update_rx_ptr;
-    case MAL0_RXCTP1R:
-        idx = 1;
-    update_rx_ptr:
-        mal->rxctpr[idx] = val;
-        break;
-    case MAL0_RCBS0:
-        idx = 0;
-        goto update_rx_size;
-    case MAL0_RCBS1:
-        idx = 1;
-    update_rx_size:
-        mal->rcbs[idx] = val & 0x000000FF;
-        break;
-    }
-}
-
-static void ppc40x_mal_reset (void *opaque)
-{
-    ppc40x_mal_t *mal;
-
-    mal = opaque;
-    mal->cfg = 0x0007C000;
-    mal->esr = 0x00000000;
-    mal->ier = 0x00000000;
-    mal->rxcasr = 0x00000000;
-    mal->rxdeir = 0x00000000;
-    mal->rxeobisr = 0x00000000;
-    mal->txcasr = 0x00000000;
-    mal->txdeir = 0x00000000;
-    mal->txeobisr = 0x00000000;
-}
-
-static void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4])
-{
-    ppc40x_mal_t *mal;
-    int i;
-
-    mal = g_malloc0(sizeof(ppc40x_mal_t));
-    for (i = 0; i < 4; i++)
-        mal->irqs[i] = irqs[i];
-    qemu_register_reset(&ppc40x_mal_reset, mal);
-    ppc_dcr_register(env, MAL0_CFG,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_ESR,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_IER,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_TXCASR,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_TXCARR,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_TXEOBISR,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_TXDEIR,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_RXCASR,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_RXCARR,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_RXEOBISR,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_RXDEIR,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_TXCTP0R,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_TXCTP1R,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_TXCTP2R,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_TXCTP3R,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_RXCTP0R,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_RXCTP1R,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_RCBS0,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-    ppc_dcr_register(env, MAL0_RCBS1,
-                     mal, &dcr_read_mal, &dcr_write_mal);
-}
-
-/*****************************************************************************/
-/* SPR */
-void ppc40x_core_reset(PowerPCCPU *cpu)
-{
-    CPUPPCState *env = &cpu->env;
-    target_ulong dbsr;
-
-    printf("Reset PowerPC core\n");
-    cpu_interrupt(env, CPU_INTERRUPT_RESET);
-    dbsr = env->spr[SPR_40x_DBSR];
-    dbsr &= ~0x00000300;
-    dbsr |= 0x00000100;
-    env->spr[SPR_40x_DBSR] = dbsr;
-}
-
-void ppc40x_chip_reset(PowerPCCPU *cpu)
-{
-    CPUPPCState *env = &cpu->env;
-    target_ulong dbsr;
-
-    printf("Reset PowerPC chip\n");
-    cpu_interrupt(env, CPU_INTERRUPT_RESET);
-    /* XXX: TODO reset all internal peripherals */
-    dbsr = env->spr[SPR_40x_DBSR];
-    dbsr &= ~0x00000300;
-    dbsr |= 0x00000200;
-    env->spr[SPR_40x_DBSR] = dbsr;
-}
-
-void ppc40x_system_reset(PowerPCCPU *cpu)
-{
-    printf("Reset PowerPC system\n");
-    qemu_system_reset_request();
-}
-
-void store_40x_dbcr0 (CPUPPCState *env, uint32_t val)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
-    switch ((val >> 28) & 0x3) {
-    case 0x0:
-        /* No action */
-        break;
-    case 0x1:
-        /* Core reset */
-        ppc40x_core_reset(cpu);
-        break;
-    case 0x2:
-        /* Chip reset */
-        ppc40x_chip_reset(cpu);
-        break;
-    case 0x3:
-        /* System reset */
-        ppc40x_system_reset(cpu);
-        break;
-    }
-}
-
-/*****************************************************************************/
-/* PowerPC 405CR */
-enum {
-    PPC405CR_CPC0_PLLMR  = 0x0B0,
-    PPC405CR_CPC0_CR0    = 0x0B1,
-    PPC405CR_CPC0_CR1    = 0x0B2,
-    PPC405CR_CPC0_PSR    = 0x0B4,
-    PPC405CR_CPC0_JTAGID = 0x0B5,
-    PPC405CR_CPC0_ER     = 0x0B9,
-    PPC405CR_CPC0_FR     = 0x0BA,
-    PPC405CR_CPC0_SR     = 0x0BB,
-};
-
-enum {
-    PPC405CR_CPU_CLK   = 0,
-    PPC405CR_TMR_CLK   = 1,
-    PPC405CR_PLB_CLK   = 2,
-    PPC405CR_SDRAM_CLK = 3,
-    PPC405CR_OPB_CLK   = 4,
-    PPC405CR_EXT_CLK   = 5,
-    PPC405CR_UART_CLK  = 6,
-    PPC405CR_CLK_NB    = 7,
-};
-
-typedef struct ppc405cr_cpc_t ppc405cr_cpc_t;
-struct ppc405cr_cpc_t {
-    clk_setup_t clk_setup[PPC405CR_CLK_NB];
-    uint32_t sysclk;
-    uint32_t psr;
-    uint32_t cr0;
-    uint32_t cr1;
-    uint32_t jtagid;
-    uint32_t pllmr;
-    uint32_t er;
-    uint32_t fr;
-};
-
-static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc)
-{
-    uint64_t VCO_out, PLL_out;
-    uint32_t CPU_clk, TMR_clk, SDRAM_clk, PLB_clk, OPB_clk, EXT_clk, UART_clk;
-    int M, D0, D1, D2;
-
-    D0 = ((cpc->pllmr >> 26) & 0x3) + 1; /* CBDV */
-    if (cpc->pllmr & 0x80000000) {
-        D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */
-        D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */
-        M = D0 * D1 * D2;
-        VCO_out = cpc->sysclk * M;
-        if (VCO_out < 400000000 || VCO_out > 800000000) {
-            /* PLL cannot lock */
-            cpc->pllmr &= ~0x80000000;
-            goto bypass_pll;
-        }
-        PLL_out = VCO_out / D2;
-    } else {
-        /* Bypass PLL */
-    bypass_pll:
-        M = D0;
-        PLL_out = cpc->sysclk * M;
-    }
-    CPU_clk = PLL_out;
-    if (cpc->cr1 & 0x00800000)
-        TMR_clk = cpc->sysclk; /* Should have a separate clock */
-    else
-        TMR_clk = CPU_clk;
-    PLB_clk = CPU_clk / D0;
-    SDRAM_clk = PLB_clk;
-    D0 = ((cpc->pllmr >> 10) & 0x3) + 1;
-    OPB_clk = PLB_clk / D0;
-    D0 = ((cpc->pllmr >> 24) & 0x3) + 2;
-    EXT_clk = PLB_clk / D0;
-    D0 = ((cpc->cr0 >> 1) & 0x1F) + 1;
-    UART_clk = CPU_clk / D0;
-    /* Setup CPU clocks */
-    clk_setup(&cpc->clk_setup[PPC405CR_CPU_CLK], CPU_clk);
-    /* Setup time-base clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_TMR_CLK], TMR_clk);
-    /* Setup PLB clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_PLB_CLK], PLB_clk);
-    /* Setup SDRAM clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_SDRAM_CLK], SDRAM_clk);
-    /* Setup OPB clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_OPB_CLK], OPB_clk);
-    /* Setup external clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_EXT_CLK], EXT_clk);
-    /* Setup UART clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_UART_CLK], UART_clk);
-}
-
-static uint32_t dcr_read_crcpc (void *opaque, int dcrn)
-{
-    ppc405cr_cpc_t *cpc;
-    uint32_t ret;
-
-    cpc = opaque;
-    switch (dcrn) {
-    case PPC405CR_CPC0_PLLMR:
-        ret = cpc->pllmr;
-        break;
-    case PPC405CR_CPC0_CR0:
-        ret = cpc->cr0;
-        break;
-    case PPC405CR_CPC0_CR1:
-        ret = cpc->cr1;
-        break;
-    case PPC405CR_CPC0_PSR:
-        ret = cpc->psr;
-        break;
-    case PPC405CR_CPC0_JTAGID:
-        ret = cpc->jtagid;
-        break;
-    case PPC405CR_CPC0_ER:
-        ret = cpc->er;
-        break;
-    case PPC405CR_CPC0_FR:
-        ret = cpc->fr;
-        break;
-    case PPC405CR_CPC0_SR:
-        ret = ~(cpc->er | cpc->fr) & 0xFFFF0000;
-        break;
-    default:
-        /* Avoid gcc warning */
-        ret = 0;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_crcpc (void *opaque, int dcrn, uint32_t val)
-{
-    ppc405cr_cpc_t *cpc;
-
-    cpc = opaque;
-    switch (dcrn) {
-    case PPC405CR_CPC0_PLLMR:
-        cpc->pllmr = val & 0xFFF77C3F;
-        break;
-    case PPC405CR_CPC0_CR0:
-        cpc->cr0 = val & 0x0FFFFFFE;
-        break;
-    case PPC405CR_CPC0_CR1:
-        cpc->cr1 = val & 0x00800000;
-        break;
-    case PPC405CR_CPC0_PSR:
-        /* Read-only */
-        break;
-    case PPC405CR_CPC0_JTAGID:
-        /* Read-only */
-        break;
-    case PPC405CR_CPC0_ER:
-        cpc->er = val & 0xBFFC0000;
-        break;
-    case PPC405CR_CPC0_FR:
-        cpc->fr = val & 0xBFFC0000;
-        break;
-    case PPC405CR_CPC0_SR:
-        /* Read-only */
-        break;
-    }
-}
-
-static void ppc405cr_cpc_reset (void *opaque)
-{
-    ppc405cr_cpc_t *cpc;
-    int D;
-
-    cpc = opaque;
-    /* Compute PLLMR value from PSR settings */
-    cpc->pllmr = 0x80000000;
-    /* PFWD */
-    switch ((cpc->psr >> 30) & 3) {
-    case 0:
-        /* Bypass */
-        cpc->pllmr &= ~0x80000000;
-        break;
-    case 1:
-        /* Divide by 3 */
-        cpc->pllmr |= 5 << 16;
-        break;
-    case 2:
-        /* Divide by 4 */
-        cpc->pllmr |= 4 << 16;
-        break;
-    case 3:
-        /* Divide by 6 */
-        cpc->pllmr |= 2 << 16;
-        break;
-    }
-    /* PFBD */
-    D = (cpc->psr >> 28) & 3;
-    cpc->pllmr |= (D + 1) << 20;
-    /* PT   */
-    D = (cpc->psr >> 25) & 7;
-    switch (D) {
-    case 0x2:
-        cpc->pllmr |= 0x13;
-        break;
-    case 0x4:
-        cpc->pllmr |= 0x15;
-        break;
-    case 0x5:
-        cpc->pllmr |= 0x16;
-        break;
-    default:
-        break;
-    }
-    /* PDC  */
-    D = (cpc->psr >> 23) & 3;
-    cpc->pllmr |= D << 26;
-    /* ODP  */
-    D = (cpc->psr >> 21) & 3;
-    cpc->pllmr |= D << 10;
-    /* EBPD */
-    D = (cpc->psr >> 17) & 3;
-    cpc->pllmr |= D << 24;
-    cpc->cr0 = 0x0000003C;
-    cpc->cr1 = 0x2B0D8800;
-    cpc->er = 0x00000000;
-    cpc->fr = 0x00000000;
-    ppc405cr_clk_setup(cpc);
-}
-
-static void ppc405cr_clk_init (ppc405cr_cpc_t *cpc)
-{
-    int D;
-
-    /* XXX: this should be read from IO pins */
-    cpc->psr = 0x00000000; /* 8 bits ROM */
-    /* PFWD */
-    D = 0x2; /* Divide by 4 */
-    cpc->psr |= D << 30;
-    /* PFBD */
-    D = 0x1; /* Divide by 2 */
-    cpc->psr |= D << 28;
-    /* PDC */
-    D = 0x1; /* Divide by 2 */
-    cpc->psr |= D << 23;
-    /* PT */
-    D = 0x5; /* M = 16 */
-    cpc->psr |= D << 25;
-    /* ODP */
-    D = 0x1; /* Divide by 2 */
-    cpc->psr |= D << 21;
-    /* EBDP */
-    D = 0x2; /* Divide by 4 */
-    cpc->psr |= D << 17;
-}
-
-static void ppc405cr_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[7],
-                               uint32_t sysclk)
-{
-    ppc405cr_cpc_t *cpc;
-
-    cpc = g_malloc0(sizeof(ppc405cr_cpc_t));
-    memcpy(cpc->clk_setup, clk_setup,
-           PPC405CR_CLK_NB * sizeof(clk_setup_t));
-    cpc->sysclk = sysclk;
-    cpc->jtagid = 0x42051049;
-    ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_CR0, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_CR1, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_JTAGID, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_PLLMR, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_ER, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_FR, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_SR, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc405cr_clk_init(cpc);
-    qemu_register_reset(ppc405cr_cpc_reset, cpc);
-}
-
-CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
-                        MemoryRegion ram_memories[4],
-                        hwaddr ram_bases[4],
-                        hwaddr ram_sizes[4],
-                        uint32_t sysclk, qemu_irq **picp,
-                        int do_init)
-{
-    clk_setup_t clk_setup[PPC405CR_CLK_NB];
-    qemu_irq dma_irqs[4];
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-    qemu_irq *pic, *irqs;
-
-    memset(clk_setup, 0, sizeof(clk_setup));
-    cpu = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK],
-                      &clk_setup[PPC405CR_TMR_CLK], sysclk);
-    env = &cpu->env;
-    /* Memory mapped devices registers */
-    /* PLB arbitrer */
-    ppc4xx_plb_init(env);
-    /* PLB to OPB bridge */
-    ppc4xx_pob_init(env);
-    /* OBP arbitrer */
-    ppc4xx_opba_init(0xef600600);
-    /* Universal interrupt controller */
-    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
-    irqs[PPCUIC_OUTPUT_INT] =
-        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
-    irqs[PPCUIC_OUTPUT_CINT] =
-        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
-    *picp = pic;
-    /* SDRAM controller */
-    ppc4xx_sdram_init(env, pic[14], 1, ram_memories,
-                      ram_bases, ram_sizes, do_init);
-    /* External bus controller */
-    ppc405_ebc_init(env);
-    /* DMA controller */
-    dma_irqs[0] = pic[26];
-    dma_irqs[1] = pic[25];
-    dma_irqs[2] = pic[24];
-    dma_irqs[3] = pic[23];
-    ppc405_dma_init(env, dma_irqs);
-    /* Serial ports */
-    if (serial_hds[0] != NULL) {
-        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
-                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
-                       DEVICE_BIG_ENDIAN);
-    }
-    if (serial_hds[1] != NULL) {
-        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
-                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
-                       DEVICE_BIG_ENDIAN);
-    }
-    /* IIC controller */
-    ppc405_i2c_init(0xef600500, pic[2]);
-    /* GPIO */
-    ppc405_gpio_init(0xef600700);
-    /* CPU control */
-    ppc405cr_cpc_init(env, clk_setup, sysclk);
-
-    return env;
-}
-
-/*****************************************************************************/
-/* PowerPC 405EP */
-/* CPU control */
-enum {
-    PPC405EP_CPC0_PLLMR0 = 0x0F0,
-    PPC405EP_CPC0_BOOT   = 0x0F1,
-    PPC405EP_CPC0_EPCTL  = 0x0F3,
-    PPC405EP_CPC0_PLLMR1 = 0x0F4,
-    PPC405EP_CPC0_UCR    = 0x0F5,
-    PPC405EP_CPC0_SRR    = 0x0F6,
-    PPC405EP_CPC0_JTAGID = 0x0F7,
-    PPC405EP_CPC0_PCI    = 0x0F9,
-#if 0
-    PPC405EP_CPC0_ER     = xxx,
-    PPC405EP_CPC0_FR     = xxx,
-    PPC405EP_CPC0_SR     = xxx,
-#endif
-};
-
-enum {
-    PPC405EP_CPU_CLK   = 0,
-    PPC405EP_PLB_CLK   = 1,
-    PPC405EP_OPB_CLK   = 2,
-    PPC405EP_EBC_CLK   = 3,
-    PPC405EP_MAL_CLK   = 4,
-    PPC405EP_PCI_CLK   = 5,
-    PPC405EP_UART0_CLK = 6,
-    PPC405EP_UART1_CLK = 7,
-    PPC405EP_CLK_NB    = 8,
-};
-
-typedef struct ppc405ep_cpc_t ppc405ep_cpc_t;
-struct ppc405ep_cpc_t {
-    uint32_t sysclk;
-    clk_setup_t clk_setup[PPC405EP_CLK_NB];
-    uint32_t boot;
-    uint32_t epctl;
-    uint32_t pllmr[2];
-    uint32_t ucr;
-    uint32_t srr;
-    uint32_t jtagid;
-    uint32_t pci;
-    /* Clock and power management */
-    uint32_t er;
-    uint32_t fr;
-    uint32_t sr;
-};
-
-static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc)
-{
-    uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk;
-    uint32_t UART0_clk, UART1_clk;
-    uint64_t VCO_out, PLL_out;
-    int M, D;
-
-    VCO_out = 0;
-    if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) {
-        M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */
-#ifdef DEBUG_CLOCKS_LL
-        printf("FBMUL %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 20) & 0xF, M);
-#endif
-        D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */
-#ifdef DEBUG_CLOCKS_LL
-        printf("FWDA %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 16) & 0x7, D);
-#endif
-        VCO_out = cpc->sysclk * M * D;
-        if (VCO_out < 500000000UL || VCO_out > 1000000000UL) {
-            /* Error - unlock the PLL */
-            printf("VCO out of range %" PRIu64 "\n", VCO_out);
-#if 0
-            cpc->pllmr[1] &= ~0x80000000;
-            goto pll_bypass;
-#endif
-        }
-        PLL_out = VCO_out / D;
-        /* Pretend the PLL is locked */
-        cpc->boot |= 0x00000001;
-    } else {
-#if 0
-    pll_bypass:
-#endif
-        PLL_out = cpc->sysclk;
-        if (cpc->pllmr[1] & 0x40000000) {
-            /* Pretend the PLL is not locked */
-            cpc->boot &= ~0x00000001;
-        }
-    }
-    /* Now, compute all other clocks */
-    D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */
-#ifdef DEBUG_CLOCKS_LL
-    printf("CCDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 20) & 0x3, D);
-#endif
-    CPU_clk = PLL_out / D;
-    D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */
-#ifdef DEBUG_CLOCKS_LL
-    printf("CBDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 16) & 0x3, D);
-#endif
-    PLB_clk = CPU_clk / D;
-    D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */
-#ifdef DEBUG_CLOCKS_LL
-    printf("OPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 12) & 0x3, D);
-#endif
-    OPB_clk = PLB_clk / D;
-    D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */
-#ifdef DEBUG_CLOCKS_LL
-    printf("EPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 8) & 0x3, D);
-#endif
-    EBC_clk = PLB_clk / D;
-    D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */
-#ifdef DEBUG_CLOCKS_LL
-    printf("MPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 4) & 0x3, D);
-#endif
-    MAL_clk = PLB_clk / D;
-    D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */
-#ifdef DEBUG_CLOCKS_LL
-    printf("PPDV %01" PRIx32 " %d\n", cpc->pllmr[0] & 0x3, D);
-#endif
-    PCI_clk = PLB_clk / D;
-    D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */
-#ifdef DEBUG_CLOCKS_LL
-    printf("U0DIV %01" PRIx32 " %d\n", cpc->ucr & 0x7F, D);
-#endif
-    UART0_clk = PLL_out / D;
-    D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */
-#ifdef DEBUG_CLOCKS_LL
-    printf("U1DIV %01" PRIx32 " %d\n", (cpc->ucr >> 8) & 0x7F, D);
-#endif
-    UART1_clk = PLL_out / D;
-#ifdef DEBUG_CLOCKS
-    printf("Setup PPC405EP clocks - sysclk %" PRIu32 " VCO %" PRIu64
-           " PLL out %" PRIu64 " Hz\n", cpc->sysclk, VCO_out, PLL_out);
-    printf("CPU %" PRIu32 " PLB %" PRIu32 " OPB %" PRIu32 " EBC %" PRIu32
-           " MAL %" PRIu32 " PCI %" PRIu32 " UART0 %" PRIu32
-           " UART1 %" PRIu32 "\n",
-           CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk,
-           UART0_clk, UART1_clk);
-#endif
-    /* Setup CPU clocks */
-    clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk);
-    /* Setup PLB clock */
-    clk_setup(&cpc->clk_setup[PPC405EP_PLB_CLK], PLB_clk);
-    /* Setup OPB clock */
-    clk_setup(&cpc->clk_setup[PPC405EP_OPB_CLK], OPB_clk);
-    /* Setup external clock */
-    clk_setup(&cpc->clk_setup[PPC405EP_EBC_CLK], EBC_clk);
-    /* Setup MAL clock */
-    clk_setup(&cpc->clk_setup[PPC405EP_MAL_CLK], MAL_clk);
-    /* Setup PCI clock */
-    clk_setup(&cpc->clk_setup[PPC405EP_PCI_CLK], PCI_clk);
-    /* Setup UART0 clock */
-    clk_setup(&cpc->clk_setup[PPC405EP_UART0_CLK], UART0_clk);
-    /* Setup UART1 clock */
-    clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk);
-}
-
-static uint32_t dcr_read_epcpc (void *opaque, int dcrn)
-{
-    ppc405ep_cpc_t *cpc;
-    uint32_t ret;
-
-    cpc = opaque;
-    switch (dcrn) {
-    case PPC405EP_CPC0_BOOT:
-        ret = cpc->boot;
-        break;
-    case PPC405EP_CPC0_EPCTL:
-        ret = cpc->epctl;
-        break;
-    case PPC405EP_CPC0_PLLMR0:
-        ret = cpc->pllmr[0];
-        break;
-    case PPC405EP_CPC0_PLLMR1:
-        ret = cpc->pllmr[1];
-        break;
-    case PPC405EP_CPC0_UCR:
-        ret = cpc->ucr;
-        break;
-    case PPC405EP_CPC0_SRR:
-        ret = cpc->srr;
-        break;
-    case PPC405EP_CPC0_JTAGID:
-        ret = cpc->jtagid;
-        break;
-    case PPC405EP_CPC0_PCI:
-        ret = cpc->pci;
-        break;
-    default:
-        /* Avoid gcc warning */
-        ret = 0;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_epcpc (void *opaque, int dcrn, uint32_t val)
-{
-    ppc405ep_cpc_t *cpc;
-
-    cpc = opaque;
-    switch (dcrn) {
-    case PPC405EP_CPC0_BOOT:
-        /* Read-only register */
-        break;
-    case PPC405EP_CPC0_EPCTL:
-        /* Don't care for now */
-        cpc->epctl = val & 0xC00000F3;
-        break;
-    case PPC405EP_CPC0_PLLMR0:
-        cpc->pllmr[0] = val & 0x00633333;
-        ppc405ep_compute_clocks(cpc);
-        break;
-    case PPC405EP_CPC0_PLLMR1:
-        cpc->pllmr[1] = val & 0xC0F73FFF;
-        ppc405ep_compute_clocks(cpc);
-        break;
-    case PPC405EP_CPC0_UCR:
-        /* UART control - don't care for now */
-        cpc->ucr = val & 0x003F7F7F;
-        break;
-    case PPC405EP_CPC0_SRR:
-        cpc->srr = val;
-        break;
-    case PPC405EP_CPC0_JTAGID:
-        /* Read-only */
-        break;
-    case PPC405EP_CPC0_PCI:
-        cpc->pci = val;
-        break;
-    }
-}
-
-static void ppc405ep_cpc_reset (void *opaque)
-{
-    ppc405ep_cpc_t *cpc = opaque;
-
-    cpc->boot = 0x00000010;     /* Boot from PCI - IIC EEPROM disabled */
-    cpc->epctl = 0x00000000;
-    cpc->pllmr[0] = 0x00011010;
-    cpc->pllmr[1] = 0x40000000;
-    cpc->ucr = 0x00000000;
-    cpc->srr = 0x00040000;
-    cpc->pci = 0x00000000;
-    cpc->er = 0x00000000;
-    cpc->fr = 0x00000000;
-    cpc->sr = 0x00000000;
-    ppc405ep_compute_clocks(cpc);
-}
-
-/* XXX: sysclk should be between 25 and 100 MHz */
-static void ppc405ep_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[8],
-                               uint32_t sysclk)
-{
-    ppc405ep_cpc_t *cpc;
-
-    cpc = g_malloc0(sizeof(ppc405ep_cpc_t));
-    memcpy(cpc->clk_setup, clk_setup,
-           PPC405EP_CLK_NB * sizeof(clk_setup_t));
-    cpc->jtagid = 0x20267049;
-    cpc->sysclk = sysclk;
-    qemu_register_reset(&ppc405ep_cpc_reset, cpc);
-    ppc_dcr_register(env, PPC405EP_CPC0_BOOT, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-    ppc_dcr_register(env, PPC405EP_CPC0_EPCTL, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-    ppc_dcr_register(env, PPC405EP_CPC0_PLLMR0, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-    ppc_dcr_register(env, PPC405EP_CPC0_PLLMR1, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-    ppc_dcr_register(env, PPC405EP_CPC0_UCR, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-    ppc_dcr_register(env, PPC405EP_CPC0_SRR, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-    ppc_dcr_register(env, PPC405EP_CPC0_JTAGID, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-    ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-#if 0
-    ppc_dcr_register(env, PPC405EP_CPC0_ER, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-    ppc_dcr_register(env, PPC405EP_CPC0_FR, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-    ppc_dcr_register(env, PPC405EP_CPC0_SR, cpc,
-                     &dcr_read_epcpc, &dcr_write_epcpc);
-#endif
-}
-
-CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
-                        MemoryRegion ram_memories[2],
-                        hwaddr ram_bases[2],
-                        hwaddr ram_sizes[2],
-                        uint32_t sysclk, qemu_irq **picp,
-                        int do_init)
-{
-    clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
-    qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-    qemu_irq *pic, *irqs;
-
-    memset(clk_setup, 0, sizeof(clk_setup));
-    /* init CPUs */
-    cpu = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK],
-                      &tlb_clk_setup, sysclk);
-    env = &cpu->env;
-    clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb;
-    clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque;
-    /* Internal devices init */
-    /* Memory mapped devices registers */
-    /* PLB arbitrer */
-    ppc4xx_plb_init(env);
-    /* PLB to OPB bridge */
-    ppc4xx_pob_init(env);
-    /* OBP arbitrer */
-    ppc4xx_opba_init(0xef600600);
-    /* Initialize timers */
-    ppc_booke_timers_init(cpu, sysclk, 0);
-    /* Universal interrupt controller */
-    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
-    irqs[PPCUIC_OUTPUT_INT] =
-        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
-    irqs[PPCUIC_OUTPUT_CINT] =
-        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
-    *picp = pic;
-    /* SDRAM controller */
-       /* XXX 405EP has no ECC interrupt */
-    ppc4xx_sdram_init(env, pic[17], 2, ram_memories,
-                      ram_bases, ram_sizes, do_init);
-    /* External bus controller */
-    ppc405_ebc_init(env);
-    /* DMA controller */
-    dma_irqs[0] = pic[5];
-    dma_irqs[1] = pic[6];
-    dma_irqs[2] = pic[7];
-    dma_irqs[3] = pic[8];
-    ppc405_dma_init(env, dma_irqs);
-    /* IIC controller */
-    ppc405_i2c_init(0xef600500, pic[2]);
-    /* GPIO */
-    ppc405_gpio_init(0xef600700);
-    /* Serial ports */
-    if (serial_hds[0] != NULL) {
-        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
-                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
-                       DEVICE_BIG_ENDIAN);
-    }
-    if (serial_hds[1] != NULL) {
-        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
-                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
-                       DEVICE_BIG_ENDIAN);
-    }
-    /* OCM */
-    ppc405_ocm_init(env);
-    /* GPT */
-    gpt_irqs[0] = pic[19];
-    gpt_irqs[1] = pic[20];
-    gpt_irqs[2] = pic[21];
-    gpt_irqs[3] = pic[22];
-    gpt_irqs[4] = pic[23];
-    ppc4xx_gpt_init(0xef600000, gpt_irqs);
-    /* PCI */
-    /* Uses pic[3], pic[16], pic[18] */
-    /* MAL */
-    mal_irqs[0] = pic[11];
-    mal_irqs[1] = pic[12];
-    mal_irqs[2] = pic[13];
-    mal_irqs[3] = pic[14];
-    ppc405_mal_init(env, mal_irqs);
-    /* Ethernet */
-    /* Uses pic[9], pic[15], pic[17] */
-    /* CPU control */
-    ppc405ep_cpc_init(env, clk_setup, sysclk);
-
-    return env;
-}
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
deleted file mode 100644 (file)
index 66911b5..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * QEMU PowerPC 440 Bamboo board emulation
- *
- * Copyright 2007 IBM Corporation.
- * Authors:
- *     Jerone Young <jyoung5@us.ibm.com>
- *     Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- *     Hollis Blanchard <hollisb@us.ibm.com>
- *
- * This work is licensed under the GNU GPL license version 2 or later.
- *
- */
-
-#include "config.h"
-#include "qemu-common.h"
-#include "net/net.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/boards.h"
-#include "sysemu/kvm.h"
-#include "kvm_ppc.h"
-#include "sysemu/device_tree.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-#include "hw/serial.h"
-#include "hw/ppc.h"
-#include "hw/ppc405.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-
-#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
-
-/* from u-boot */
-#define KERNEL_ADDR  0x1000000
-#define FDT_ADDR     0x1800000
-#define RAMDISK_ADDR 0x1900000
-
-#define PPC440EP_PCI_CONFIG     0xeec00000
-#define PPC440EP_PCI_INTACK     0xeed00000
-#define PPC440EP_PCI_SPECIAL    0xeed00000
-#define PPC440EP_PCI_REGS       0xef400000
-#define PPC440EP_PCI_IO         0xe8000000
-#define PPC440EP_PCI_IOLEN      0x00010000
-
-#define PPC440EP_SDRAM_NR_BANKS 4
-
-static const unsigned int ppc440ep_sdram_bank_sizes[] = {
-    256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
-};
-
-static hwaddr entry;
-
-static int bamboo_load_device_tree(hwaddr addr,
-                                     uint32_t ramsize,
-                                     hwaddr initrd_base,
-                                     hwaddr initrd_size,
-                                     const char *kernel_cmdline)
-{
-    int ret = -1;
-#ifdef CONFIG_FDT
-    uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
-    char *filename;
-    int fdt_size;
-    void *fdt;
-    uint32_t tb_freq = 400000000;
-    uint32_t clock_freq = 400000000;
-
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
-    if (!filename) {
-        goto out;
-    }
-    fdt = load_device_tree(filename, &fdt_size);
-    g_free(filename);
-    if (fdt == NULL) {
-        goto out;
-    }
-
-    /* Manipulate device tree in memory. */
-
-    ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
-                               sizeof(mem_reg_property));
-    if (ret < 0)
-        fprintf(stderr, "couldn't set /memory/reg\n");
-
-    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
-                                    initrd_base);
-    if (ret < 0)
-        fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
-
-    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
-                                    (initrd_base + initrd_size));
-    if (ret < 0)
-        fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
-
-    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
-                                      kernel_cmdline);
-    if (ret < 0)
-        fprintf(stderr, "couldn't set /chosen/bootargs\n");
-
-    /* Copy data from the host device tree into the guest. Since the guest can
-     * directly access the timebase without host involvement, we must expose
-     * the correct frequencies. */
-    if (kvm_enabled()) {
-        tb_freq = kvmppc_get_tbfreq();
-        clock_freq = kvmppc_get_clockfreq();
-    }
-
-    qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
-                              clock_freq);
-    qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
-                              tb_freq);
-
-    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
-    g_free(fdt);
-
-out:
-#endif
-
-    return ret;
-}
-
-/* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
-                                     target_ulong va,
-                                     hwaddr pa)
-{
-    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
-
-    tlb->attr = 0;
-    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
-    tlb->size = 1 << 31; /* up to 0x80000000  */
-    tlb->EPN = va & TARGET_PAGE_MASK;
-    tlb->RPN = pa & TARGET_PAGE_MASK;
-    tlb->PID = 0;
-
-    tlb = &env->tlb.tlbe[1];
-    tlb->attr = 0;
-    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
-    tlb->size = 1 << 31; /* up to 0xffffffff  */
-    tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
-    tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
-    tlb->PID = 0;
-}
-
-static void main_cpu_reset(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-
-    cpu_reset(CPU(cpu));
-    env->gpr[1] = (16<<20) - 8;
-    env->gpr[3] = FDT_ADDR;
-    env->nip = entry;
-
-    /* Create a mapping for the kernel.  */
-    mmubooke_create_initial_mapping(env, 0, 0);
-}
-
-static void bamboo_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram_memories
-        = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
-    hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS];
-    hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS];
-    qemu_irq *pic;
-    qemu_irq *irqs;
-    PCIBus *pcibus;
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-    uint64_t elf_entry;
-    uint64_t elf_lowaddr;
-    hwaddr loadaddr = 0;
-    target_long initrd_size = 0;
-    DeviceState *dev;
-    int success;
-    int i;
-
-    /* Setup CPU. */
-    if (cpu_model == NULL) {
-        cpu_model = "440EP";
-    }
-    cpu = cpu_ppc_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "Unable to initialize CPU!\n");
-        exit(1);
-    }
-    env = &cpu->env;
-
-    qemu_register_reset(main_cpu_reset, cpu);
-    ppc_booke_timers_init(cpu, 400000000, 0);
-    ppc_dcr_init(env, NULL, NULL);
-
-    /* interrupt controller */
-    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
-    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
-    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
-
-    /* SDRAM controller */
-    memset(ram_bases, 0, sizeof(ram_bases));
-    memset(ram_sizes, 0, sizeof(ram_sizes));
-    ram_size = ppc4xx_sdram_adjust(ram_size, PPC440EP_SDRAM_NR_BANKS,
-                                   ram_memories,
-                                   ram_bases, ram_sizes,
-                                   ppc440ep_sdram_bank_sizes);
-    /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
-    ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
-                      ram_bases, ram_sizes, 1);
-
-    /* PCI */
-    dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
-                                PPC440EP_PCI_CONFIG,
-                                pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
-                                pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
-                                NULL);
-    pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
-    if (!pcibus) {
-        fprintf(stderr, "couldn't create PCI controller!\n");
-        exit(1);
-    }
-
-    isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
-
-    if (serial_hds[0] != NULL) {
-        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
-                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
-                       DEVICE_BIG_ENDIAN);
-    }
-    if (serial_hds[1] != NULL) {
-        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
-                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
-                       DEVICE_BIG_ENDIAN);
-    }
-
-    if (pcibus) {
-        /* Register network interfaces. */
-        for (i = 0; i < nb_nics; i++) {
-            /* There are no PCI NICs on the Bamboo board, but there are
-             * PCI slots, so we can pick whatever default model we want. */
-            pci_nic_init_nofail(&nd_table[i], "e1000", NULL);
-        }
-    }
-
-    /* Load kernel. */
-    if (kernel_filename) {
-        success = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
-        if (success < 0) {
-            success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
-                               &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
-            entry = elf_entry;
-            loadaddr = elf_lowaddr;
-        }
-        /* XXX try again as binary */
-        if (success < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-    }
-
-    /* Load initrd. */
-    if (initrd_filename) {
-        initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR,
-                                          ram_size - RAMDISK_ADDR);
-
-        if (initrd_size < 0) {
-            fprintf(stderr, "qemu: could not load ram disk '%s' at %x\n",
-                    initrd_filename, RAMDISK_ADDR);
-            exit(1);
-        }
-    }
-
-    /* If we're loading a kernel directly, we must load the device tree too. */
-    if (kernel_filename) {
-        if (bamboo_load_device_tree(FDT_ADDR, ram_size, RAMDISK_ADDR,
-                                    initrd_size, kernel_cmdline) < 0) {
-            fprintf(stderr, "couldn't load device tree\n");
-            exit(1);
-        }
-    }
-
-    if (kvm_enabled())
-        kvmppc_init();
-}
-
-static QEMUMachine bamboo_machine = {
-    .name = "bamboo",
-    .desc = "bamboo",
-    .init = bamboo_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void bamboo_machine_init(void)
-{
-    qemu_register_machine(&bamboo_machine);
-}
-
-machine_init(bamboo_machine_init);
diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c
deleted file mode 100644 (file)
index 30375c0..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * QEMU PowerPC Booke hardware System Emulator
- *
- * Copyright (c) 2011 AdaCore
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/hw.h"
-#include "hw/ppc.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/nvram.h"
-#include "qemu/log.h"
-#include "hw/loader.h"
-
-
-/* Timer Control Register */
-
-#define TCR_WP_SHIFT  30        /* Watchdog Timer Period */
-#define TCR_WP_MASK   (0x3 << TCR_WP_SHIFT)
-#define TCR_WRC_SHIFT 28        /* Watchdog Timer Reset Control */
-#define TCR_WRC_MASK  (0x3 << TCR_WRC_SHIFT)
-#define TCR_WIE       (1 << 27) /* Watchdog Timer Interrupt Enable */
-#define TCR_DIE       (1 << 26) /* Decrementer Interrupt Enable */
-#define TCR_FP_SHIFT  24        /* Fixed-Interval Timer Period */
-#define TCR_FP_MASK   (0x3 << TCR_FP_SHIFT)
-#define TCR_FIE       (1 << 23) /* Fixed-Interval Timer Interrupt Enable */
-#define TCR_ARE       (1 << 22) /* Auto-Reload Enable */
-
-/* Timer Control Register (e500 specific fields) */
-
-#define TCR_E500_FPEXT_SHIFT 13 /* Fixed-Interval Timer Period Extension */
-#define TCR_E500_FPEXT_MASK  (0xf << TCR_E500_FPEXT_SHIFT)
-#define TCR_E500_WPEXT_SHIFT 17 /* Watchdog Timer Period Extension */
-#define TCR_E500_WPEXT_MASK  (0xf << TCR_E500_WPEXT_SHIFT)
-
-/* Timer Status Register  */
-
-#define TSR_FIS       (1 << 26) /* Fixed-Interval Timer Interrupt Status */
-#define TSR_DIS       (1 << 27) /* Decrementer Interrupt Status */
-#define TSR_WRS_SHIFT 28        /* Watchdog Timer Reset Status */
-#define TSR_WRS_MASK  (0x3 << TSR_WRS_SHIFT)
-#define TSR_WIS       (1 << 30) /* Watchdog Timer Interrupt Status */
-#define TSR_ENW       (1 << 31) /* Enable Next Watchdog Timer */
-
-typedef struct booke_timer_t booke_timer_t;
-struct booke_timer_t {
-
-    uint64_t fit_next;
-    struct QEMUTimer *fit_timer;
-
-    uint64_t wdt_next;
-    struct QEMUTimer *wdt_timer;
-
-    uint32_t flags;
-};
-
-static void booke_update_irq(PowerPCCPU *cpu)
-{
-    CPUPPCState *env = &cpu->env;
-
-    ppc_set_irq(cpu, PPC_INTERRUPT_DECR,
-                (env->spr[SPR_BOOKE_TSR] & TSR_DIS
-                 && env->spr[SPR_BOOKE_TCR] & TCR_DIE));
-
-    ppc_set_irq(cpu, PPC_INTERRUPT_WDT,
-                (env->spr[SPR_BOOKE_TSR] & TSR_WIS
-                 && env->spr[SPR_BOOKE_TCR] & TCR_WIE));
-
-    ppc_set_irq(cpu, PPC_INTERRUPT_FIT,
-                (env->spr[SPR_BOOKE_TSR] & TSR_FIS
-                 && env->spr[SPR_BOOKE_TCR] & TCR_FIE));
-}
-
-/* Return the location of the bit of time base at which the FIT will raise an
-   interrupt */
-static uint8_t booke_get_fit_target(CPUPPCState *env, ppc_tb_t *tb_env)
-{
-    uint8_t fp = (env->spr[SPR_BOOKE_TCR] & TCR_FP_MASK) >> TCR_FP_SHIFT;
-
-    if (tb_env->flags & PPC_TIMER_E500) {
-        /* e500 Fixed-interval timer period extension */
-        uint32_t fpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_FPEXT_MASK)
-            >> TCR_E500_FPEXT_SHIFT;
-        fp = 63 - (fp | fpext << 2);
-    } else {
-        fp = env->fit_period[fp];
-    }
-
-    return fp;
-}
-
-/* Return the location of the bit of time base at which the WDT will raise an
-   interrupt */
-static uint8_t booke_get_wdt_target(CPUPPCState *env, ppc_tb_t *tb_env)
-{
-    uint8_t wp = (env->spr[SPR_BOOKE_TCR] & TCR_WP_MASK) >> TCR_WP_SHIFT;
-
-    if (tb_env->flags & PPC_TIMER_E500) {
-        /* e500 Watchdog timer period extension */
-        uint32_t wpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_WPEXT_MASK)
-            >> TCR_E500_WPEXT_SHIFT;
-        wp = 63 - (wp | wpext << 2);
-    } else {
-        wp = env->wdt_period[wp];
-    }
-
-    return wp;
-}
-
-static void booke_update_fixed_timer(CPUPPCState         *env,
-                                     uint8_t           target_bit,
-                                     uint64_t          *next,
-                                     struct QEMUTimer *timer)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    uint64_t lapse;
-    uint64_t tb;
-    uint64_t period = 1 << (target_bit + 1);
-    uint64_t now;
-
-    now = qemu_get_clock_ns(vm_clock);
-    tb  = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset);
-
-    lapse = period - ((tb - (1 << target_bit)) & (period - 1));
-
-    *next = now + muldiv64(lapse, get_ticks_per_sec(), tb_env->tb_freq);
-
-    /* XXX: If expire time is now. We can't run the callback because we don't
-     * have access to it. So we just set the timer one nanosecond later.
-     */
-
-    if (*next == now) {
-        (*next)++;
-    }
-
-    qemu_mod_timer(timer, *next);
-}
-
-static void booke_decr_cb(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-
-    env->spr[SPR_BOOKE_TSR] |= TSR_DIS;
-    booke_update_irq(cpu);
-
-    if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) {
-        /* Auto Reload */
-        cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]);
-    }
-}
-
-static void booke_fit_cb(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-    ppc_tb_t *tb_env;
-    booke_timer_t *booke_timer;
-
-    tb_env = env->tb_env;
-    booke_timer = tb_env->opaque;
-    env->spr[SPR_BOOKE_TSR] |= TSR_FIS;
-
-    booke_update_irq(cpu);
-
-    booke_update_fixed_timer(env,
-                             booke_get_fit_target(env, tb_env),
-                             &booke_timer->fit_next,
-                             booke_timer->fit_timer);
-}
-
-static void booke_wdt_cb(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-    ppc_tb_t *tb_env;
-    booke_timer_t *booke_timer;
-
-    tb_env = env->tb_env;
-    booke_timer = tb_env->opaque;
-
-    /* TODO: There's lots of complicated stuff to do here */
-
-    booke_update_irq(cpu);
-
-    booke_update_fixed_timer(env,
-                             booke_get_wdt_target(env, tb_env),
-                             &booke_timer->wdt_next,
-                             booke_timer->wdt_timer);
-}
-
-void store_booke_tsr(CPUPPCState *env, target_ulong val)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
-    env->spr[SPR_BOOKE_TSR] &= ~val;
-    booke_update_irq(cpu);
-}
-
-void store_booke_tcr(CPUPPCState *env, target_ulong val)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-    ppc_tb_t *tb_env = env->tb_env;
-    booke_timer_t *booke_timer = tb_env->opaque;
-
-    tb_env = env->tb_env;
-    env->spr[SPR_BOOKE_TCR] = val;
-
-    booke_update_irq(cpu);
-
-    booke_update_fixed_timer(env,
-                             booke_get_fit_target(env, tb_env),
-                             &booke_timer->fit_next,
-                             booke_timer->fit_timer);
-
-    booke_update_fixed_timer(env,
-                             booke_get_wdt_target(env, tb_env),
-                             &booke_timer->wdt_next,
-                             booke_timer->wdt_timer);
-
-}
-
-static void ppc_booke_timer_reset_handle(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-
-    env->spr[SPR_BOOKE_TSR] = 0;
-    env->spr[SPR_BOOKE_TCR] = 0;
-
-    booke_update_irq(cpu);
-}
-
-void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
-{
-    ppc_tb_t *tb_env;
-    booke_timer_t *booke_timer;
-
-    tb_env      = g_malloc0(sizeof(ppc_tb_t));
-    booke_timer = g_malloc0(sizeof(booke_timer_t));
-
-    cpu->env.tb_env = tb_env;
-    tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
-
-    tb_env->tb_freq    = freq;
-    tb_env->decr_freq  = freq;
-    tb_env->opaque     = booke_timer;
-    tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, cpu);
-
-    booke_timer->fit_timer =
-        qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu);
-    booke_timer->wdt_timer =
-        qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu);
-
-    qemu_register_reset(ppc_booke_timer_reset_handle, cpu);
-}
diff --git a/hw/puv3.c b/hw/puv3.c
deleted file mode 100644 (file)
index f9d0c2b..0000000
--- a/hw/puv3.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Generic PKUnity SoC machine and board descriptor
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu-common.h"
-#include "ui/console.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-#include "hw/sysbus.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "hw/pc.h"
-
-#undef DEBUG_PUV3
-#include "hw/puv3.h"
-
-#define KERNEL_LOAD_ADDR        0x03000000
-#define KERNEL_MAX_SIZE         0x00800000 /* Just a guess */
-
-static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
-{
-    CPUUniCore32State *env = opaque;
-
-    assert(irq == 0);
-    if (level) {
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
-    } else {
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
-}
-
-static void puv3_soc_init(CPUUniCore32State *env)
-{
-    qemu_irq *cpu_intc, irqs[PUV3_IRQS_NR];
-    DeviceState *dev;
-    MemoryRegion *i8042 = g_new(MemoryRegion, 1);
-    int i;
-
-    /* Initialize interrupt controller */
-    cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, env, 1);
-    dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc);
-    for (i = 0; i < PUV3_IRQS_NR; i++) {
-        irqs[i] = qdev_get_gpio_in(dev, i);
-    }
-
-    /* Initialize minimal necessary devices for kernel booting */
-    sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL);
-    sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL);
-    sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]);
-    sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE,
-            irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1],
-            irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3],
-            irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5],
-            irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7],
-            irqs[PUV3_IRQS_GPIOHIGH], NULL);
-
-    /* Keyboard (i8042), mouse disabled for nographic */
-    i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4);
-    memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042);
-}
-
-static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size)
-{
-    MemoryRegion *ram_memory = g_new(MemoryRegion, 1);
-
-    /* SDRAM at address zero.  */
-    memory_region_init_ram(ram_memory, "puv3.ram", ram_size);
-    vmstate_register_ram_global(ram_memory);
-    memory_region_add_subregion(get_system_memory(), 0, ram_memory);
-}
-
-static void puv3_load_kernel(const char *kernel_filename)
-{
-    int size;
-
-    assert(kernel_filename != NULL);
-
-    /* only zImage format supported */
-    size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
-            KERNEL_MAX_SIZE);
-    if (size < 0) {
-        hw_error("Load kernel error: '%s'\n", kernel_filename);
-    }
-
-    /* cheat curses that we have a graphic console, only under ocd console */
-    graphic_console_init(NULL, NULL, NULL, NULL, NULL);
-}
-
-static void puv3_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *initrd_filename = args->initrd_filename;
-    CPUUniCore32State *env;
-
-    if (initrd_filename) {
-        hw_error("Please use kernel built-in initramdisk.\n");
-    }
-
-    if (!cpu_model) {
-        cpu_model = "UniCore-II";
-    }
-
-    env = cpu_init(cpu_model);
-    if (!env) {
-        hw_error("Unable to find CPU definition\n");
-    }
-
-    puv3_soc_init(env);
-    puv3_board_init(env, ram_size);
-    puv3_load_kernel(kernel_filename);
-}
-
-static QEMUMachine puv3_machine = {
-    .name = "puv3",
-    .desc = "PKUnity Version-3 based on UniCore32",
-    .init = puv3_init,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void puv3_machine_init(void)
-{
-    qemu_register_machine(&puv3_machine);
-}
-
-machine_init(puv3_machine_init)
diff --git a/hw/r2d.c b/hw/r2d.c
deleted file mode 100644 (file)
index faa03d2..0000000
--- a/hw/r2d.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Renesas SH7751R R2D-PLUS emulation
- *
- * Copyright (c) 2007 Magnus Damm
- * Copyright (c) 2008 Paul Mundt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/sh.h"
-#include "hw/devices.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "hw/sh7750_regs.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "hw/usb.h"
-#include "hw/flash.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-#define FLASH_BASE 0x00000000
-#define FLASH_SIZE 0x02000000
-
-#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
-#define SDRAM_SIZE 0x04000000
-
-#define SM501_VRAM_SIZE 0x800000
-
-#define BOOT_PARAMS_OFFSET 0x0010000
-/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */
-#define LINUX_LOAD_OFFSET  0x0800000
-#define INITRD_LOAD_OFFSET 0x1800000
-
-#define PA_IRLMSK      0x00
-#define PA_POWOFF      0x30
-#define PA_VERREG      0x32
-#define PA_OUTPORT     0x36
-
-typedef struct {
-    uint16_t bcr;
-    uint16_t irlmsk;
-    uint16_t irlmon;
-    uint16_t cfctl;
-    uint16_t cfpow;
-    uint16_t dispctl;
-    uint16_t sdmpow;
-    uint16_t rtcce;
-    uint16_t pcicd;
-    uint16_t voyagerrts;
-    uint16_t cfrst;
-    uint16_t admrts;
-    uint16_t extrst;
-    uint16_t cfcdintclr;
-    uint16_t keyctlclr;
-    uint16_t pad0;
-    uint16_t pad1;
-    uint16_t verreg;
-    uint16_t inport;
-    uint16_t outport;
-    uint16_t bverreg;
-
-/* output pin */
-    qemu_irq irl;
-    MemoryRegion iomem;
-} r2d_fpga_t;
-
-enum r2d_fpga_irq {
-    PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T,
-    SDCARD, PCI_INTA, PCI_INTB, EXT, TP,
-    NR_IRQS
-};
-
-static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = {
-    [CF_IDE]   = {  1, 1<<9 },
-    [CF_CD]    = {  2, 1<<8 },
-    [PCI_INTA] = {  9, 1<<14 },
-    [PCI_INTB] = { 10, 1<<13 },
-    [PCI_INTC] = {  3, 1<<12 },
-    [PCI_INTD] = {  0, 1<<11 },
-    [SM501]    = {  4, 1<<10 },
-    [KEY]      = {  5, 1<<6 },
-    [RTC_A]    = {  6, 1<<5 },
-    [RTC_T]    = {  7, 1<<4 },
-    [SDCARD]   = {  8, 1<<7 },
-    [EXT]      = { 11, 1<<0 },
-    [TP]       = { 12, 1<<15 },
-};
-
-static void update_irl(r2d_fpga_t *fpga)
-{
-    int i, irl = 15;
-    for (i = 0; i < NR_IRQS; i++)
-        if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk)
-            if (irqtab[i].irl < irl)
-                irl = irqtab[i].irl;
-    qemu_set_irq(fpga->irl, irl ^ 15);
-}
-
-static void r2d_fpga_irq_set(void *opaque, int n, int level)
-{
-    r2d_fpga_t *fpga = opaque;
-    if (level)
-        fpga->irlmon |= irqtab[n].msk;
-    else
-        fpga->irlmon &= ~irqtab[n].msk;
-    update_irl(fpga);
-}
-
-static uint32_t r2d_fpga_read(void *opaque, hwaddr addr)
-{
-    r2d_fpga_t *s = opaque;
-
-    switch (addr) {
-    case PA_IRLMSK:
-        return s->irlmsk;
-    case PA_OUTPORT:
-       return s->outport;
-    case PA_POWOFF:
-       return 0x00;
-    case PA_VERREG:
-       return 0x10;
-    }
-
-    return 0;
-}
-
-static void
-r2d_fpga_write(void *opaque, hwaddr addr, uint32_t value)
-{
-    r2d_fpga_t *s = opaque;
-
-    switch (addr) {
-    case PA_IRLMSK:
-        s->irlmsk = value;
-        update_irl(s);
-       break;
-    case PA_OUTPORT:
-       s->outport = value;
-       break;
-    case PA_POWOFF:
-        if (value & 1) {
-            qemu_system_shutdown_request();
-        }
-        break;
-    case PA_VERREG:
-       /* Discard writes */
-       break;
-    }
-}
-
-static const MemoryRegionOps r2d_fpga_ops = {
-    .old_mmio = {
-        .read = { r2d_fpga_read, r2d_fpga_read, NULL, },
-        .write = { r2d_fpga_write, r2d_fpga_write, NULL, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem,
-                               hwaddr base, qemu_irq irl)
-{
-    r2d_fpga_t *s;
-
-    s = g_malloc0(sizeof(r2d_fpga_t));
-
-    s->irl = irl;
-
-    memory_region_init_io(&s->iomem, &r2d_fpga_ops, s, "r2d-fpga", 0x40);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-    return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
-}
-
-typedef struct ResetData {
-    SuperHCPU *cpu;
-    uint32_t vector;
-} ResetData;
-
-static void main_cpu_reset(void *opaque)
-{
-    ResetData *s = (ResetData *)opaque;
-    CPUSH4State *env = &s->cpu->env;
-
-    cpu_reset(CPU(s->cpu));
-    env->pc = s->vector;
-}
-
-static struct QEMU_PACKED
-{
-    int mount_root_rdonly;
-    int ramdisk_flags;
-    int orig_root_dev;
-    int loader_type;
-    int initrd_start;
-    int initrd_size;
-
-    char pad[232];
-
-    char kernel_cmdline[256];
-} boot_params;
-
-static void r2d_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    SuperHCPU *cpu;
-    CPUSH4State *env;
-    ResetData *reset_info;
-    struct SH7750State *s;
-    MemoryRegion *sdram = g_new(MemoryRegion, 1);
-    qemu_irq *irq;
-    DriveInfo *dinfo;
-    int i;
-    DeviceState *dev;
-    SysBusDevice *busdev;
-    MemoryRegion *address_space_mem = get_system_memory();
-
-    if (cpu_model == NULL) {
-        cpu_model = "SH7751R";
-    }
-
-    cpu = cpu_sh4_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-    env = &cpu->env;
-
-    reset_info = g_malloc0(sizeof(ResetData));
-    reset_info->cpu = cpu;
-    reset_info->vector = env->pc;
-    qemu_register_reset(main_cpu_reset, reset_info);
-
-    /* Allocate memory space */
-    memory_region_init_ram(sdram, "r2d.sdram", SDRAM_SIZE);
-    vmstate_register_ram_global(sdram);
-    memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram);
-    /* Register peripherals */
-    s = sh7750_init(env, address_space_mem);
-    irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s));
-
-    dev = qdev_create(NULL, "sh_pci");
-    busdev = SYS_BUS_DEVICE(dev);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000));
-    sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000));
-    sysbus_connect_irq(busdev, 0, irq[PCI_INTA]);
-    sysbus_connect_irq(busdev, 1, irq[PCI_INTB]);
-    sysbus_connect_irq(busdev, 2, irq[PCI_INTC]);
-    sysbus_connect_irq(busdev, 3, irq[PCI_INTD]);
-
-    sm501_init(address_space_mem, 0x10000000, SM501_VRAM_SIZE,
-               irq[SM501], serial_hds[2]);
-
-    /* onboard CF (True IDE mode, Master only). */
-    dinfo = drive_get(IF_IDE, 0, 0);
-    dev = qdev_create(NULL, "mmio-ide");
-    busdev = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(busdev, 0, irq[CF_IDE]);
-    qdev_prop_set_uint32(dev, "shift", 1);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(busdev, 0, 0x14001000);
-    sysbus_mmio_map(busdev, 1, 0x1400080c);
-    mmio_ide_init_drives(dev, dinfo, NULL);
-
-    /* onboard flash memory */
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi02_register(0x0, NULL, "r2d.flash", FLASH_SIZE,
-                          dinfo ? dinfo->bdrv : NULL, (16 * 1024),
-                          FLASH_SIZE >> 16,
-                          1, 4, 0x0000, 0x0000, 0x0000, 0x0000,
-                          0x555, 0x2aa, 0);
-
-    /* NIC: rtl8139 on-board, and 2 slots. */
-    for (i = 0; i < nb_nics; i++)
-        pci_nic_init_nofail(&nd_table[i], "rtl8139", i==0 ? "2" : NULL);
-
-    /* USB keyboard */
-    usbdevice_create("keyboard");
-
-    /* Todo: register on board registers */
-    memset(&boot_params, 0, sizeof(boot_params));
-
-    if (kernel_filename) {
-        int kernel_size;
-
-        kernel_size = load_image_targphys(kernel_filename,
-                                          SDRAM_BASE + LINUX_LOAD_OFFSET,
-                                          INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET);
-        if (kernel_size < 0) {
-          fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
-          exit(1);
-        }
-
-        /* initialization which should be done by firmware */
-        stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */
-        stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */
-        reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */
-    }
-
-    if (initrd_filename) {
-        int initrd_size;
-
-        initrd_size = load_image_targphys(initrd_filename,
-                                          SDRAM_BASE + INITRD_LOAD_OFFSET,
-                                          SDRAM_SIZE - INITRD_LOAD_OFFSET);
-
-        if (initrd_size < 0) {
-          fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename);
-          exit(1);
-        }
-
-        /* initialization which should be done by firmware */
-        boot_params.loader_type = 1;
-        boot_params.initrd_start = INITRD_LOAD_OFFSET;
-        boot_params.initrd_size = initrd_size;
-    }
-
-    if (kernel_cmdline) {
-        /* I see no evidence that this .kernel_cmdline buffer requires
-           NUL-termination, so using strncpy should be ok. */
-        strncpy(boot_params.kernel_cmdline, kernel_cmdline,
-                sizeof(boot_params.kernel_cmdline));
-    }
-
-    rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params),
-                       SDRAM_BASE + BOOT_PARAMS_OFFSET);
-}
-
-static QEMUMachine r2d_machine = {
-    .name = "r2d",
-    .desc = "r2d-plus board",
-    .init = r2d_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void r2d_machine_init(void)
-{
-    qemu_register_machine(&r2d_machine);
-}
-
-machine_init(r2d_machine_init);
diff --git a/hw/realview.c b/hw/realview.c
deleted file mode 100644 (file)
index 5fb490c..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * ARM RealView Baseboard System emulation.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "hw/primecell.h"
-#include "hw/devices.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/i2c.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-#define SMP_BOOT_ADDR 0xe0000000
-#define SMP_BOOTREG_ADDR 0x10000030
-
-/* Board init.  */
-
-static struct arm_boot_info realview_binfo = {
-    .smp_loader_start = SMP_BOOT_ADDR,
-    .smp_bootreg_addr = SMP_BOOTREG_ADDR,
-};
-
-/* The following two lists must be consistent.  */
-enum realview_board_type {
-    BOARD_EB,
-    BOARD_EB_MPCORE,
-    BOARD_PB_A8,
-    BOARD_PBX_A9,
-};
-
-static const int realview_board_id[] = {
-    0x33b,
-    0x33b,
-    0x769,
-    0x76d
-};
-
-static void realview_init(QEMUMachineInitArgs *args,
-                          enum realview_board_type board_type)
-{
-    ARMCPU *cpu = NULL;
-    CPUARMState *env;
-    MemoryRegion *sysmem = get_system_memory();
-    MemoryRegion *ram_lo = g_new(MemoryRegion, 1);
-    MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
-    MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
-    MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
-    DeviceState *dev, *sysctl, *gpio2, *pl041;
-    SysBusDevice *busdev;
-    qemu_irq *irqp;
-    qemu_irq pic[64];
-    qemu_irq mmc_irq[2];
-    PCIBus *pci_bus;
-    NICInfo *nd;
-    i2c_bus *i2c;
-    int n;
-    int done_nic = 0;
-    qemu_irq cpu_irq[4];
-    int is_mpcore = 0;
-    int is_pb = 0;
-    uint32_t proc_id = 0;
-    uint32_t sys_id;
-    ram_addr_t low_ram_size;
-    ram_addr_t ram_size = args->ram_size;
-
-    switch (board_type) {
-    case BOARD_EB:
-        break;
-    case BOARD_EB_MPCORE:
-        is_mpcore = 1;
-        break;
-    case BOARD_PB_A8:
-        is_pb = 1;
-        break;
-    case BOARD_PBX_A9:
-        is_mpcore = 1;
-        is_pb = 1;
-        break;
-    }
-    for (n = 0; n < smp_cpus; n++) {
-        cpu = cpu_arm_init(args->cpu_model);
-        if (!cpu) {
-            fprintf(stderr, "Unable to find CPU definition\n");
-            exit(1);
-        }
-        irqp = arm_pic_init_cpu(cpu);
-        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
-    }
-    env = &cpu->env;
-    if (arm_feature(env, ARM_FEATURE_V7)) {
-        if (is_mpcore) {
-            proc_id = 0x0c000000;
-        } else {
-            proc_id = 0x0e000000;
-        }
-    } else if (arm_feature(env, ARM_FEATURE_V6K)) {
-        proc_id = 0x06000000;
-    } else if (arm_feature(env, ARM_FEATURE_V6)) {
-        proc_id = 0x04000000;
-    } else {
-        proc_id = 0x02000000;
-    }
-
-    if (is_pb && ram_size > 0x20000000) {
-        /* Core tile RAM.  */
-        low_ram_size = ram_size - 0x20000000;
-        ram_size = 0x20000000;
-        memory_region_init_ram(ram_lo, "realview.lowmem", low_ram_size);
-        vmstate_register_ram_global(ram_lo);
-        memory_region_add_subregion(sysmem, 0x20000000, ram_lo);
-    }
-
-    memory_region_init_ram(ram_hi, "realview.highmem", ram_size);
-    vmstate_register_ram_global(ram_hi);
-    low_ram_size = ram_size;
-    if (low_ram_size > 0x10000000)
-      low_ram_size = 0x10000000;
-    /* SDRAM at address zero.  */
-    memory_region_init_alias(ram_alias, "realview.alias",
-                             ram_hi, 0, low_ram_size);
-    memory_region_add_subregion(sysmem, 0, ram_alias);
-    if (is_pb) {
-        /* And again at a high address.  */
-        memory_region_add_subregion(sysmem, 0x70000000, ram_hi);
-    } else {
-        ram_size = low_ram_size;
-    }
-
-    sys_id = is_pb ? 0x01780500 : 0xc1400400;
-    sysctl = qdev_create(NULL, "realview_sysctl");
-    qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
-    qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
-    qdev_init_nofail(sysctl);
-    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
-
-    if (is_mpcore) {
-        hwaddr periphbase;
-        dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
-        qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
-        qdev_init_nofail(dev);
-        busdev = SYS_BUS_DEVICE(dev);
-        if (is_pb) {
-            periphbase = 0x1f000000;
-        } else {
-            periphbase = 0x10100000;
-        }
-        sysbus_mmio_map(busdev, 0, periphbase);
-        for (n = 0; n < smp_cpus; n++) {
-            sysbus_connect_irq(busdev, n, cpu_irq[n]);
-        }
-        sysbus_create_varargs("l2x0", periphbase + 0x2000, NULL);
-        /* Both A9 and 11MPCore put the GIC CPU i/f at base + 0x100 */
-        realview_binfo.gic_cpu_if_addr = periphbase + 0x100;
-    } else {
-        uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000;
-        /* For now just create the nIRQ GIC, and ignore the others.  */
-        dev = sysbus_create_simple("realview_gic", gic_addr, cpu_irq[0]);
-    }
-    for (n = 0; n < 64; n++) {
-        pic[n] = qdev_get_gpio_in(dev, n);
-    }
-
-    pl041 = qdev_create(NULL, "pl041");
-    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
-    qdev_init_nofail(pl041);
-    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
-    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[19]);
-
-    sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]);
-    sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]);
-
-    sysbus_create_simple("pl011", 0x10009000, pic[12]);
-    sysbus_create_simple("pl011", 0x1000a000, pic[13]);
-    sysbus_create_simple("pl011", 0x1000b000, pic[14]);
-    sysbus_create_simple("pl011", 0x1000c000, pic[15]);
-
-    /* DMA controller is optional, apparently.  */
-    sysbus_create_simple("pl081", 0x10030000, pic[24]);
-
-    sysbus_create_simple("sp804", 0x10011000, pic[4]);
-    sysbus_create_simple("sp804", 0x10012000, pic[5]);
-
-    sysbus_create_simple("pl061", 0x10013000, pic[6]);
-    sysbus_create_simple("pl061", 0x10014000, pic[7]);
-    gpio2 = sysbus_create_simple("pl061", 0x10015000, pic[8]);
-
-    sysbus_create_simple("pl111", 0x10020000, pic[23]);
-
-    dev = sysbus_create_varargs("pl181", 0x10005000, pic[17], pic[18], NULL);
-    /* Wire up MMC card detect and read-only signals. These have
-     * to go to both the PL061 GPIO and the sysctl register.
-     * Note that the PL181 orders these lines (readonly,inserted)
-     * and the PL061 has them the other way about. Also the card
-     * detect line is inverted.
-     */
-    mmc_irq[0] = qemu_irq_split(
-        qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT),
-        qdev_get_gpio_in(gpio2, 1));
-    mmc_irq[1] = qemu_irq_split(
-        qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN),
-        qemu_irq_invert(qdev_get_gpio_in(gpio2, 0)));
-    qdev_connect_gpio_out(dev, 0, mmc_irq[0]);
-    qdev_connect_gpio_out(dev, 1, mmc_irq[1]);
-
-    sysbus_create_simple("pl031", 0x10017000, pic[10]);
-
-    if (!is_pb) {
-        dev = qdev_create(NULL, "realview_pci");
-        busdev = SYS_BUS_DEVICE(dev);
-        qdev_init_nofail(dev);
-        sysbus_mmio_map(busdev, 0, 0x61000000); /* PCI self-config */
-        sysbus_mmio_map(busdev, 1, 0x62000000); /* PCI config */
-        sysbus_mmio_map(busdev, 2, 0x63000000); /* PCI I/O */
-        sysbus_connect_irq(busdev, 0, pic[48]);
-        sysbus_connect_irq(busdev, 1, pic[49]);
-        sysbus_connect_irq(busdev, 2, pic[50]);
-        sysbus_connect_irq(busdev, 3, pic[51]);
-        pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
-        if (usb_enabled(false)) {
-            pci_create_simple(pci_bus, -1, "pci-ohci");
-        }
-        n = drive_get_max_bus(IF_SCSI);
-        while (n >= 0) {
-            pci_create_simple(pci_bus, -1, "lsi53c895a");
-            n--;
-        }
-    }
-    for(n = 0; n < nb_nics; n++) {
-        nd = &nd_table[n];
-
-        if (!done_nic && (!nd->model ||
-                    strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0)) {
-            if (is_pb) {
-                lan9118_init(nd, 0x4e000000, pic[28]);
-            } else {
-                smc91c111_init(nd, 0x4e000000, pic[28]);
-            }
-            done_nic = 1;
-        } else {
-            pci_nic_init_nofail(nd, "rtl8139", NULL);
-        }
-    }
-
-    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
-    i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
-    i2c_create_slave(i2c, "ds1338", 0x68);
-
-    /* Memory map for RealView Emulation Baseboard:  */
-    /* 0x10000000 System registers.  */
-    /*  0x10001000 System controller.  */
-    /* 0x10002000 Two-Wire Serial Bus.  */
-    /* 0x10003000 Reserved.  */
-    /*  0x10004000 AACI.  */
-    /*  0x10005000 MCI.  */
-    /* 0x10006000 KMI0.  */
-    /* 0x10007000 KMI1.  */
-    /*  0x10008000 Character LCD. (EB) */
-    /* 0x10009000 UART0.  */
-    /* 0x1000a000 UART1.  */
-    /* 0x1000b000 UART2.  */
-    /* 0x1000c000 UART3.  */
-    /*  0x1000d000 SSPI.  */
-    /*  0x1000e000 SCI.  */
-    /* 0x1000f000 Reserved.  */
-    /*  0x10010000 Watchdog.  */
-    /* 0x10011000 Timer 0+1.  */
-    /* 0x10012000 Timer 2+3.  */
-    /*  0x10013000 GPIO 0.  */
-    /*  0x10014000 GPIO 1.  */
-    /*  0x10015000 GPIO 2.  */
-    /*  0x10002000 Two-Wire Serial Bus - DVI. (PB) */
-    /* 0x10017000 RTC.  */
-    /*  0x10018000 DMC.  */
-    /*  0x10019000 PCI controller config.  */
-    /*  0x10020000 CLCD.  */
-    /* 0x10030000 DMA Controller.  */
-    /* 0x10040000 GIC1. (EB) */
-    /*  0x10050000 GIC2. (EB) */
-    /*  0x10060000 GIC3. (EB) */
-    /*  0x10070000 GIC4. (EB) */
-    /*  0x10080000 SMC.  */
-    /* 0x1e000000 GIC1. (PB) */
-    /*  0x1e001000 GIC2. (PB) */
-    /*  0x1e002000 GIC3. (PB) */
-    /*  0x1e003000 GIC4. (PB) */
-    /*  0x40000000 NOR flash.  */
-    /*  0x44000000 DoC flash.  */
-    /*  0x48000000 SRAM.  */
-    /*  0x4c000000 Configuration flash.  */
-    /* 0x4e000000 Ethernet.  */
-    /*  0x4f000000 USB.  */
-    /*  0x50000000 PISMO.  */
-    /*  0x54000000 PISMO.  */
-    /*  0x58000000 PISMO.  */
-    /*  0x5c000000 PISMO.  */
-    /* 0x60000000 PCI.  */
-    /* 0x61000000 PCI Self Config.  */
-    /* 0x62000000 PCI Config.  */
-    /* 0x63000000 PCI IO.  */
-    /* 0x64000000 PCI mem 0.  */
-    /* 0x68000000 PCI mem 1.  */
-    /* 0x6c000000 PCI mem 2.  */
-
-    /* ??? Hack to map an additional page of ram for the secondary CPU
-       startup code.  I guess this works on real hardware because the
-       BootROM happens to be in ROM/flash or in memory that isn't clobbered
-       until after Linux boots the secondary CPUs.  */
-    memory_region_init_ram(ram_hack, "realview.hack", 0x1000);
-    vmstate_register_ram_global(ram_hack);
-    memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
-
-    realview_binfo.ram_size = ram_size;
-    realview_binfo.kernel_filename = args->kernel_filename;
-    realview_binfo.kernel_cmdline = args->kernel_cmdline;
-    realview_binfo.initrd_filename = args->initrd_filename;
-    realview_binfo.nb_cpus = smp_cpus;
-    realview_binfo.board_id = realview_board_id[board_type];
-    realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
-    arm_load_kernel(arm_env_get_cpu(first_cpu), &realview_binfo);
-}
-
-static void realview_eb_init(QEMUMachineInitArgs *args)
-{
-    if (!args->cpu_model) {
-        args->cpu_model = "arm926";
-    }
-    realview_init(args, BOARD_EB);
-}
-
-static void realview_eb_mpcore_init(QEMUMachineInitArgs *args)
-{
-    if (!args->cpu_model) {
-        args->cpu_model = "arm11mpcore";
-    }
-    realview_init(args, BOARD_EB_MPCORE);
-}
-
-static void realview_pb_a8_init(QEMUMachineInitArgs *args)
-{
-    if (!args->cpu_model) {
-        args->cpu_model = "cortex-a8";
-    }
-    realview_init(args, BOARD_PB_A8);
-}
-
-static void realview_pbx_a9_init(QEMUMachineInitArgs *args)
-{
-    if (!args->cpu_model) {
-        args->cpu_model = "cortex-a9";
-    }
-    realview_init(args, BOARD_PBX_A9);
-}
-
-static QEMUMachine realview_eb_machine = {
-    .name = "realview-eb",
-    .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)",
-    .init = realview_eb_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine realview_eb_mpcore_machine = {
-    .name = "realview-eb-mpcore",
-    .desc = "ARM RealView Emulation Baseboard (ARM11MPCore)",
-    .init = realview_eb_mpcore_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine realview_pb_a8_machine = {
-    .name = "realview-pb-a8",
-    .desc = "ARM RealView Platform Baseboard for Cortex-A8",
-    .init = realview_pb_a8_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine realview_pbx_a9_machine = {
-    .name = "realview-pbx-a9",
-    .desc = "ARM RealView Platform Baseboard Explore for Cortex-A9",
-    .init = realview_pbx_a9_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void realview_machine_init(void)
-{
-    qemu_register_machine(&realview_eb_machine);
-    qemu_register_machine(&realview_eb_mpcore_machine);
-    qemu_register_machine(&realview_pb_a8_machine);
-    qemu_register_machine(&realview_pbx_a9_machine);
-}
-
-machine_init(realview_machine_init);
index 68c592179070394e8c53aebd32f599f2df311724..b2e1f1e0442e3549298b830b66985ddf330faf0d 100644 (file)
@@ -1,5 +1,7 @@
-obj-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
+obj-y = sh7750.o sh7750_regnames.o tc58128.o
 obj-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
 obj-y += ide/mmio.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-y += shix.o r2d.o
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
new file mode 100644 (file)
index 0000000..faa03d2
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Renesas SH7751R R2D-PLUS emulation
+ *
+ * Copyright (c) 2007 Magnus Damm
+ * Copyright (c) 2008 Paul Mundt
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "hw/sh.h"
+#include "hw/devices.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/pci/pci.h"
+#include "net/net.h"
+#include "hw/sh7750_regs.h"
+#include "hw/ide.h"
+#include "hw/loader.h"
+#include "hw/usb.h"
+#include "hw/flash.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+#define FLASH_BASE 0x00000000
+#define FLASH_SIZE 0x02000000
+
+#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
+#define SDRAM_SIZE 0x04000000
+
+#define SM501_VRAM_SIZE 0x800000
+
+#define BOOT_PARAMS_OFFSET 0x0010000
+/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */
+#define LINUX_LOAD_OFFSET  0x0800000
+#define INITRD_LOAD_OFFSET 0x1800000
+
+#define PA_IRLMSK      0x00
+#define PA_POWOFF      0x30
+#define PA_VERREG      0x32
+#define PA_OUTPORT     0x36
+
+typedef struct {
+    uint16_t bcr;
+    uint16_t irlmsk;
+    uint16_t irlmon;
+    uint16_t cfctl;
+    uint16_t cfpow;
+    uint16_t dispctl;
+    uint16_t sdmpow;
+    uint16_t rtcce;
+    uint16_t pcicd;
+    uint16_t voyagerrts;
+    uint16_t cfrst;
+    uint16_t admrts;
+    uint16_t extrst;
+    uint16_t cfcdintclr;
+    uint16_t keyctlclr;
+    uint16_t pad0;
+    uint16_t pad1;
+    uint16_t verreg;
+    uint16_t inport;
+    uint16_t outport;
+    uint16_t bverreg;
+
+/* output pin */
+    qemu_irq irl;
+    MemoryRegion iomem;
+} r2d_fpga_t;
+
+enum r2d_fpga_irq {
+    PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T,
+    SDCARD, PCI_INTA, PCI_INTB, EXT, TP,
+    NR_IRQS
+};
+
+static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = {
+    [CF_IDE]   = {  1, 1<<9 },
+    [CF_CD]    = {  2, 1<<8 },
+    [PCI_INTA] = {  9, 1<<14 },
+    [PCI_INTB] = { 10, 1<<13 },
+    [PCI_INTC] = {  3, 1<<12 },
+    [PCI_INTD] = {  0, 1<<11 },
+    [SM501]    = {  4, 1<<10 },
+    [KEY]      = {  5, 1<<6 },
+    [RTC_A]    = {  6, 1<<5 },
+    [RTC_T]    = {  7, 1<<4 },
+    [SDCARD]   = {  8, 1<<7 },
+    [EXT]      = { 11, 1<<0 },
+    [TP]       = { 12, 1<<15 },
+};
+
+static void update_irl(r2d_fpga_t *fpga)
+{
+    int i, irl = 15;
+    for (i = 0; i < NR_IRQS; i++)
+        if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk)
+            if (irqtab[i].irl < irl)
+                irl = irqtab[i].irl;
+    qemu_set_irq(fpga->irl, irl ^ 15);
+}
+
+static void r2d_fpga_irq_set(void *opaque, int n, int level)
+{
+    r2d_fpga_t *fpga = opaque;
+    if (level)
+        fpga->irlmon |= irqtab[n].msk;
+    else
+        fpga->irlmon &= ~irqtab[n].msk;
+    update_irl(fpga);
+}
+
+static uint32_t r2d_fpga_read(void *opaque, hwaddr addr)
+{
+    r2d_fpga_t *s = opaque;
+
+    switch (addr) {
+    case PA_IRLMSK:
+        return s->irlmsk;
+    case PA_OUTPORT:
+       return s->outport;
+    case PA_POWOFF:
+       return 0x00;
+    case PA_VERREG:
+       return 0x10;
+    }
+
+    return 0;
+}
+
+static void
+r2d_fpga_write(void *opaque, hwaddr addr, uint32_t value)
+{
+    r2d_fpga_t *s = opaque;
+
+    switch (addr) {
+    case PA_IRLMSK:
+        s->irlmsk = value;
+        update_irl(s);
+       break;
+    case PA_OUTPORT:
+       s->outport = value;
+       break;
+    case PA_POWOFF:
+        if (value & 1) {
+            qemu_system_shutdown_request();
+        }
+        break;
+    case PA_VERREG:
+       /* Discard writes */
+       break;
+    }
+}
+
+static const MemoryRegionOps r2d_fpga_ops = {
+    .old_mmio = {
+        .read = { r2d_fpga_read, r2d_fpga_read, NULL, },
+        .write = { r2d_fpga_write, r2d_fpga_write, NULL, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem,
+                               hwaddr base, qemu_irq irl)
+{
+    r2d_fpga_t *s;
+
+    s = g_malloc0(sizeof(r2d_fpga_t));
+
+    s->irl = irl;
+
+    memory_region_init_io(&s->iomem, &r2d_fpga_ops, s, "r2d-fpga", 0x40);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+    return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
+}
+
+typedef struct ResetData {
+    SuperHCPU *cpu;
+    uint32_t vector;
+} ResetData;
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *)opaque;
+    CPUSH4State *env = &s->cpu->env;
+
+    cpu_reset(CPU(s->cpu));
+    env->pc = s->vector;
+}
+
+static struct QEMU_PACKED
+{
+    int mount_root_rdonly;
+    int ramdisk_flags;
+    int orig_root_dev;
+    int loader_type;
+    int initrd_start;
+    int initrd_size;
+
+    char pad[232];
+
+    char kernel_cmdline[256];
+} boot_params;
+
+static void r2d_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    SuperHCPU *cpu;
+    CPUSH4State *env;
+    ResetData *reset_info;
+    struct SH7750State *s;
+    MemoryRegion *sdram = g_new(MemoryRegion, 1);
+    qemu_irq *irq;
+    DriveInfo *dinfo;
+    int i;
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    MemoryRegion *address_space_mem = get_system_memory();
+
+    if (cpu_model == NULL) {
+        cpu_model = "SH7751R";
+    }
+
+    cpu = cpu_sh4_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    env = &cpu->env;
+
+    reset_info = g_malloc0(sizeof(ResetData));
+    reset_info->cpu = cpu;
+    reset_info->vector = env->pc;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    /* Allocate memory space */
+    memory_region_init_ram(sdram, "r2d.sdram", SDRAM_SIZE);
+    vmstate_register_ram_global(sdram);
+    memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram);
+    /* Register peripherals */
+    s = sh7750_init(env, address_space_mem);
+    irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s));
+
+    dev = qdev_create(NULL, "sh_pci");
+    busdev = SYS_BUS_DEVICE(dev);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000));
+    sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000));
+    sysbus_connect_irq(busdev, 0, irq[PCI_INTA]);
+    sysbus_connect_irq(busdev, 1, irq[PCI_INTB]);
+    sysbus_connect_irq(busdev, 2, irq[PCI_INTC]);
+    sysbus_connect_irq(busdev, 3, irq[PCI_INTD]);
+
+    sm501_init(address_space_mem, 0x10000000, SM501_VRAM_SIZE,
+               irq[SM501], serial_hds[2]);
+
+    /* onboard CF (True IDE mode, Master only). */
+    dinfo = drive_get(IF_IDE, 0, 0);
+    dev = qdev_create(NULL, "mmio-ide");
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(busdev, 0, irq[CF_IDE]);
+    qdev_prop_set_uint32(dev, "shift", 1);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(busdev, 0, 0x14001000);
+    sysbus_mmio_map(busdev, 1, 0x1400080c);
+    mmio_ide_init_drives(dev, dinfo, NULL);
+
+    /* onboard flash memory */
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi02_register(0x0, NULL, "r2d.flash", FLASH_SIZE,
+                          dinfo ? dinfo->bdrv : NULL, (16 * 1024),
+                          FLASH_SIZE >> 16,
+                          1, 4, 0x0000, 0x0000, 0x0000, 0x0000,
+                          0x555, 0x2aa, 0);
+
+    /* NIC: rtl8139 on-board, and 2 slots. */
+    for (i = 0; i < nb_nics; i++)
+        pci_nic_init_nofail(&nd_table[i], "rtl8139", i==0 ? "2" : NULL);
+
+    /* USB keyboard */
+    usbdevice_create("keyboard");
+
+    /* Todo: register on board registers */
+    memset(&boot_params, 0, sizeof(boot_params));
+
+    if (kernel_filename) {
+        int kernel_size;
+
+        kernel_size = load_image_targphys(kernel_filename,
+                                          SDRAM_BASE + LINUX_LOAD_OFFSET,
+                                          INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET);
+        if (kernel_size < 0) {
+          fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
+          exit(1);
+        }
+
+        /* initialization which should be done by firmware */
+        stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */
+        stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */
+        reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */
+    }
+
+    if (initrd_filename) {
+        int initrd_size;
+
+        initrd_size = load_image_targphys(initrd_filename,
+                                          SDRAM_BASE + INITRD_LOAD_OFFSET,
+                                          SDRAM_SIZE - INITRD_LOAD_OFFSET);
+
+        if (initrd_size < 0) {
+          fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename);
+          exit(1);
+        }
+
+        /* initialization which should be done by firmware */
+        boot_params.loader_type = 1;
+        boot_params.initrd_start = INITRD_LOAD_OFFSET;
+        boot_params.initrd_size = initrd_size;
+    }
+
+    if (kernel_cmdline) {
+        /* I see no evidence that this .kernel_cmdline buffer requires
+           NUL-termination, so using strncpy should be ok. */
+        strncpy(boot_params.kernel_cmdline, kernel_cmdline,
+                sizeof(boot_params.kernel_cmdline));
+    }
+
+    rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params),
+                       SDRAM_BASE + BOOT_PARAMS_OFFSET);
+}
+
+static QEMUMachine r2d_machine = {
+    .name = "r2d",
+    .desc = "r2d-plus board",
+    .init = r2d_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void r2d_machine_init(void)
+{
+    qemu_register_machine(&r2d_machine);
+}
+
+machine_init(r2d_machine_init);
diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c
new file mode 100644 (file)
index 0000000..192579d
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * SHIX 2.0 board description
+ *
+ * Copyright (c) 2005 Samuel Tardieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+/*
+   Shix 2.0 board by Alexis Polti, described at
+   http://perso.enst.fr/~polti/realisations/shix20/
+
+   More information in target-sh4/README.sh4
+*/
+#include "hw/hw.h"
+#include "hw/sh.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "exec/address-spaces.h"
+
+#define BIOS_FILENAME "shix_bios.bin"
+#define BIOS_ADDRESS 0xA0000000
+
+static void shix_init(QEMUMachineInitArgs *args)
+{
+    const char *cpu_model = args->cpu_model;
+    int ret;
+    CPUSH4State *env;
+    struct SH7750State *s;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *rom = g_new(MemoryRegion, 1);
+    MemoryRegion *sdram = g_new(MemoryRegion, 2);
+    
+    if (!cpu_model)
+        cpu_model = "any";
+
+    printf("Initializing CPU\n");
+    env = cpu_init(cpu_model);
+
+    /* Allocate memory space */
+    printf("Allocating ROM\n");
+    memory_region_init_ram(rom, "shix.rom", 0x4000);
+    vmstate_register_ram_global(rom);
+    memory_region_set_readonly(rom, true);
+    memory_region_add_subregion(sysmem, 0x00000000, rom);
+    printf("Allocating SDRAM 1\n");
+    memory_region_init_ram(&sdram[0], "shix.sdram1", 0x01000000);
+    vmstate_register_ram_global(&sdram[0]);
+    memory_region_add_subregion(sysmem, 0x08000000, &sdram[0]);
+    printf("Allocating SDRAM 2\n");
+    memory_region_init_ram(&sdram[1], "shix.sdram2", 0x01000000);
+    vmstate_register_ram_global(&sdram[1]);
+    memory_region_add_subregion(sysmem, 0x0c000000, &sdram[1]);
+
+    /* Load BIOS in 0 (and access it through P2, 0xA0000000) */
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    printf("%s: load BIOS '%s'\n", __func__, bios_name);
+    ret = load_image_targphys(bios_name, 0, 0x4000);
+    if (ret < 0) {             /* Check bios size */
+       fprintf(stderr, "ret=%d\n", ret);
+       fprintf(stderr, "qemu: could not load SHIX bios '%s'\n",
+               bios_name);
+       exit(1);
+    }
+
+    /* Register peripherals */
+    s = sh7750_init(env, sysmem);
+    /* XXXXX Check success */
+    tc58128_init(s, "shix_linux_nand.bin", NULL);
+    fprintf(stderr, "initialization terminated\n");
+}
+
+static QEMUMachine shix_machine = {
+    .name = "shix",
+    .desc = "shix card",
+    .init = shix_init,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void shix_machine_init(void)
+{
+    qemu_register_machine(&shix_machine);
+}
+
+machine_init(shix_machine_init);
diff --git a/hw/shix.c b/hw/shix.c
deleted file mode 100644 (file)
index 192579d..0000000
--- a/hw/shix.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * SHIX 2.0 board description
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-/*
-   Shix 2.0 board by Alexis Polti, described at
-   http://perso.enst.fr/~polti/realisations/shix20/
-
-   More information in target-sh4/README.sh4
-*/
-#include "hw/hw.h"
-#include "hw/sh.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "exec/address-spaces.h"
-
-#define BIOS_FILENAME "shix_bios.bin"
-#define BIOS_ADDRESS 0xA0000000
-
-static void shix_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    int ret;
-    CPUSH4State *env;
-    struct SH7750State *s;
-    MemoryRegion *sysmem = get_system_memory();
-    MemoryRegion *rom = g_new(MemoryRegion, 1);
-    MemoryRegion *sdram = g_new(MemoryRegion, 2);
-    
-    if (!cpu_model)
-        cpu_model = "any";
-
-    printf("Initializing CPU\n");
-    env = cpu_init(cpu_model);
-
-    /* Allocate memory space */
-    printf("Allocating ROM\n");
-    memory_region_init_ram(rom, "shix.rom", 0x4000);
-    vmstate_register_ram_global(rom);
-    memory_region_set_readonly(rom, true);
-    memory_region_add_subregion(sysmem, 0x00000000, rom);
-    printf("Allocating SDRAM 1\n");
-    memory_region_init_ram(&sdram[0], "shix.sdram1", 0x01000000);
-    vmstate_register_ram_global(&sdram[0]);
-    memory_region_add_subregion(sysmem, 0x08000000, &sdram[0]);
-    printf("Allocating SDRAM 2\n");
-    memory_region_init_ram(&sdram[1], "shix.sdram2", 0x01000000);
-    vmstate_register_ram_global(&sdram[1]);
-    memory_region_add_subregion(sysmem, 0x0c000000, &sdram[1]);
-
-    /* Load BIOS in 0 (and access it through P2, 0xA0000000) */
-    if (bios_name == NULL)
-        bios_name = BIOS_FILENAME;
-    printf("%s: load BIOS '%s'\n", __func__, bios_name);
-    ret = load_image_targphys(bios_name, 0, 0x4000);
-    if (ret < 0) {             /* Check bios size */
-       fprintf(stderr, "ret=%d\n", ret);
-       fprintf(stderr, "qemu: could not load SHIX bios '%s'\n",
-               bios_name);
-       exit(1);
-    }
-
-    /* Register peripherals */
-    s = sh7750_init(env, sysmem);
-    /* XXXXX Check success */
-    tc58128_init(s, "shix_linux_nand.bin", NULL);
-    fprintf(stderr, "initialization terminated\n");
-}
-
-static QEMUMachine shix_machine = {
-    .name = "shix",
-    .desc = "shix card",
-    .init = shix_init,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void shix_machine_init(void)
-{
-    qemu_register_machine(&shix_machine);
-}
-
-machine_init(shix_machine_init);
diff --git a/hw/smbios.c b/hw/smbios.c
deleted file mode 100644 (file)
index 672ee9b..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * SMBIOS Support
- *
- * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
- *
- * Authors:
- *  Alex Williamson <alex.williamson@hp.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "sysemu/sysemu.h"
-#include "hw/smbios.h"
-#include "hw/loader.h"
-
-/*
- * Structures shared with the BIOS
- */
-struct smbios_header {
-    uint16_t length;
-    uint8_t type;
-} QEMU_PACKED;
-
-struct smbios_field {
-    struct smbios_header header;
-    uint8_t type;
-    uint16_t offset;
-    uint8_t data[];
-} QEMU_PACKED;
-
-struct smbios_table {
-    struct smbios_header header;
-    uint8_t data[];
-} QEMU_PACKED;
-
-#define SMBIOS_FIELD_ENTRY 0
-#define SMBIOS_TABLE_ENTRY 1
-
-
-static uint8_t *smbios_entries;
-static size_t smbios_entries_len;
-static int smbios_type4_count = 0;
-
-static void smbios_validate_table(void)
-{
-    if (smbios_type4_count && smbios_type4_count != smp_cpus) {
-         fprintf(stderr,
-                 "Number of SMBIOS Type 4 tables must match cpu count.\n");
-        exit(1);
-    }
-}
-
-uint8_t *smbios_get_table(size_t *length)
-{
-    smbios_validate_table();
-    *length = smbios_entries_len;
-    return smbios_entries;
-}
-
-/*
- * To avoid unresolvable overlaps in data, don't allow both
- * tables and fields for the same smbios type.
- */
-static void smbios_check_collision(int type, int entry)
-{
-    uint16_t *num_entries = (uint16_t *)smbios_entries;
-    struct smbios_header *header;
-    char *p;
-    int i;
-
-    if (!num_entries)
-        return;
-
-    p = (char *)(num_entries + 1);
-
-    for (i = 0; i < *num_entries; i++) {
-        header = (struct smbios_header *)p;
-        if (entry == SMBIOS_TABLE_ENTRY && header->type == SMBIOS_FIELD_ENTRY) {
-            struct smbios_field *field = (void *)header;
-            if (type == field->type) {
-                fprintf(stderr, "SMBIOS type %d field already defined, "
-                                "cannot add table\n", type);
-                exit(1);
-            }
-        } else if (entry == SMBIOS_FIELD_ENTRY &&
-                   header->type == SMBIOS_TABLE_ENTRY) {
-            struct smbios_structure_header *table = (void *)(header + 1);
-            if (type == table->type) {
-                fprintf(stderr, "SMBIOS type %d table already defined, "
-                                "cannot add field\n", type);
-                exit(1);
-            }
-        }
-        p += le16_to_cpu(header->length);
-    }
-}
-
-void smbios_add_field(int type, int offset, int len, void *data)
-{
-    struct smbios_field *field;
-
-    smbios_check_collision(type, SMBIOS_FIELD_ENTRY);
-
-    if (!smbios_entries) {
-        smbios_entries_len = sizeof(uint16_t);
-        smbios_entries = g_malloc0(smbios_entries_len);
-    }
-    smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
-                                                  sizeof(*field) + len);
-    field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
-    field->header.type = SMBIOS_FIELD_ENTRY;
-    field->header.length = cpu_to_le16(sizeof(*field) + len);
-
-    field->type = type;
-    field->offset = cpu_to_le16(offset);
-    memcpy(field->data, data, len);
-
-    smbios_entries_len += sizeof(*field) + len;
-    (*(uint16_t *)smbios_entries) =
-            cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
-}
-
-static void smbios_build_type_0_fields(const char *t)
-{
-    char buf[1024];
-
-    if (get_param_value(buf, sizeof(buf), "vendor", t))
-        smbios_add_field(0, offsetof(struct smbios_type_0, vendor_str),
-                         strlen(buf) + 1, buf);
-    if (get_param_value(buf, sizeof(buf), "version", t))
-        smbios_add_field(0, offsetof(struct smbios_type_0, bios_version_str),
-                         strlen(buf) + 1, buf);
-    if (get_param_value(buf, sizeof(buf), "date", t))
-        smbios_add_field(0, offsetof(struct smbios_type_0,
-                                     bios_release_date_str),
-                                     strlen(buf) + 1, buf);
-    if (get_param_value(buf, sizeof(buf), "release", t)) {
-        int major, minor;
-        sscanf(buf, "%d.%d", &major, &minor);
-        smbios_add_field(0, offsetof(struct smbios_type_0,
-                                     system_bios_major_release), 1, &major);
-        smbios_add_field(0, offsetof(struct smbios_type_0,
-                                     system_bios_minor_release), 1, &minor);
-    }
-}
-
-static void smbios_build_type_1_fields(const char *t)
-{
-    char buf[1024];
-
-    if (get_param_value(buf, sizeof(buf), "manufacturer", t))
-        smbios_add_field(1, offsetof(struct smbios_type_1, manufacturer_str),
-                         strlen(buf) + 1, buf);
-    if (get_param_value(buf, sizeof(buf), "product", t))
-        smbios_add_field(1, offsetof(struct smbios_type_1, product_name_str),
-                         strlen(buf) + 1, buf);
-    if (get_param_value(buf, sizeof(buf), "version", t))
-        smbios_add_field(1, offsetof(struct smbios_type_1, version_str),
-                         strlen(buf) + 1, buf);
-    if (get_param_value(buf, sizeof(buf), "serial", t))
-        smbios_add_field(1, offsetof(struct smbios_type_1, serial_number_str),
-                         strlen(buf) + 1, buf);
-    if (get_param_value(buf, sizeof(buf), "uuid", t)) {
-        if (qemu_uuid_parse(buf, qemu_uuid) != 0) {
-            fprintf(stderr, "Invalid SMBIOS UUID string\n");
-            exit(1);
-        }
-    }
-    if (get_param_value(buf, sizeof(buf), "sku", t))
-        smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str),
-                         strlen(buf) + 1, buf);
-    if (get_param_value(buf, sizeof(buf), "family", t))
-        smbios_add_field(1, offsetof(struct smbios_type_1, family_str),
-                         strlen(buf) + 1, buf);
-}
-
-int smbios_entry_add(const char *t)
-{
-    char buf[1024];
-
-    if (get_param_value(buf, sizeof(buf), "file", t)) {
-        struct smbios_structure_header *header;
-        struct smbios_table *table;
-        int size = get_image_size(buf);
-
-        if (size == -1 || size < sizeof(struct smbios_structure_header)) {
-            fprintf(stderr, "Cannot read smbios file %s\n", buf);
-            exit(1);
-        }
-
-        if (!smbios_entries) {
-            smbios_entries_len = sizeof(uint16_t);
-            smbios_entries = g_malloc0(smbios_entries_len);
-        }
-
-        smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
-                                                      sizeof(*table) + size);
-        table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
-        table->header.type = SMBIOS_TABLE_ENTRY;
-        table->header.length = cpu_to_le16(sizeof(*table) + size);
-
-        if (load_image(buf, table->data) != size) {
-            fprintf(stderr, "Failed to load smbios file %s", buf);
-            exit(1);
-        }
-
-        header = (struct smbios_structure_header *)(table->data);
-        smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY);
-        if (header->type == 4) {
-            smbios_type4_count++;
-        }
-
-        smbios_entries_len += sizeof(*table) + size;
-        (*(uint16_t *)smbios_entries) =
-                cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
-        return 0;
-    }
-
-    if (get_param_value(buf, sizeof(buf), "type", t)) {
-        unsigned long type = strtoul(buf, NULL, 0);
-        switch (type) {
-        case 0:
-            smbios_build_type_0_fields(t);
-            return 0;
-        case 1:
-            smbios_build_type_1_fields(t);
-            return 0;
-        default:
-            fprintf(stderr, "Don't know how to build fields for SMBIOS type "
-                    "%ld\n", type);
-            exit(1);
-        }
-    }
-
-    fprintf(stderr, "smbios: must specify type= or file=\n");
-    return -1;
-}
diff --git a/hw/spapr.c b/hw/spapr.c
deleted file mode 100644 (file)
index 2709c66..0000000
+++ /dev/null
@@ -1,963 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * Copyright (c) 2004-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- * Copyright (c) 2010 David Gibson, IBM Corporation.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-#include "sysemu/sysemu.h"
-#include "hw/hw.h"
-#include "elf.h"
-#include "net/net.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/cpus.h"
-#include "sysemu/kvm.h"
-#include "kvm_ppc.h"
-
-#include "hw/boards.h"
-#include "hw/ppc.h"
-#include "hw/loader.h"
-
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
-#include "hw/spapr_pci.h"
-#include "hw/xics.h"
-#include "hw/pci/msi.h"
-
-#include "sysemu/kvm.h"
-#include "kvm_ppc.h"
-#include "hw/pci/pci.h"
-
-#include "exec/address-spaces.h"
-#include "hw/usb.h"
-#include "qemu/config-file.h"
-
-#include <libfdt.h>
-
-/* SLOF memory layout:
- *
- * SLOF raw image loaded at 0, copies its romfs right below the flat
- * device-tree, then position SLOF itself 31M below that
- *
- * So we set FW_OVERHEAD to 40MB which should account for all of that
- * and more
- *
- * We load our kernel at 4M, leaving space for SLOF initial image
- */
-#define FDT_MAX_SIZE            0x10000
-#define RTAS_MAX_SIZE           0x10000
-#define FW_MAX_SIZE             0x400000
-#define FW_FILE_NAME            "slof.bin"
-#define FW_OVERHEAD             0x2800000
-#define KERNEL_LOAD_ADDR        FW_MAX_SIZE
-
-#define MIN_RMA_SLOF            128UL
-
-#define TIMEBASE_FREQ           512000000ULL
-
-#define MAX_CPUS                256
-#define XICS_IRQS               1024
-
-#define PHANDLE_XICP            0x00001111
-
-#define HTAB_SIZE(spapr)        (1ULL << ((spapr)->htab_shift))
-
-sPAPREnvironment *spapr;
-
-int spapr_allocate_irq(int hint, bool lsi)
-{
-    int irq;
-
-    if (hint) {
-        irq = hint;
-        /* FIXME: we should probably check for collisions somehow */
-    } else {
-        irq = spapr->next_irq++;
-    }
-
-    /* Configure irq type */
-    if (!xics_get_qirq(spapr->icp, irq)) {
-        return 0;
-    }
-
-    xics_set_irq_type(spapr->icp, irq, lsi);
-
-    return irq;
-}
-
-/* Allocate block of consequtive IRQs, returns a number of the first */
-int spapr_allocate_irq_block(int num, bool lsi)
-{
-    int first = -1;
-    int i;
-
-    for (i = 0; i < num; ++i) {
-        int irq;
-
-        irq = spapr_allocate_irq(0, lsi);
-        if (!irq) {
-            return -1;
-        }
-
-        if (0 == i) {
-            first = irq;
-        }
-
-        /* If the above doesn't create a consecutive block then that's
-         * an internal bug */
-        assert(irq == (first + i));
-    }
-
-    return first;
-}
-
-static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
-{
-    int ret = 0, offset;
-    CPUPPCState *env;
-    CPUState *cpu;
-    char cpu_model[32];
-    int smt = kvmppc_smt_threads();
-    uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
-
-    assert(spapr->cpu_model);
-
-    for (env = first_cpu; env != NULL; env = env->next_cpu) {
-        cpu = CPU(ppc_env_get_cpu(env));
-        uint32_t associativity[] = {cpu_to_be32(0x5),
-                                    cpu_to_be32(0x0),
-                                    cpu_to_be32(0x0),
-                                    cpu_to_be32(0x0),
-                                    cpu_to_be32(cpu->numa_node),
-                                    cpu_to_be32(cpu->cpu_index)};
-
-        if ((cpu->cpu_index % smt) != 0) {
-            continue;
-        }
-
-        snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model,
-                 cpu->cpu_index);
-
-        offset = fdt_path_offset(fdt, cpu_model);
-        if (offset < 0) {
-            return offset;
-        }
-
-        if (nb_numa_nodes > 1) {
-            ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
-                              sizeof(associativity));
-            if (ret < 0) {
-                return ret;
-            }
-        }
-
-        ret = fdt_setprop(fdt, offset, "ibm,pft-size",
-                          pft_size_prop, sizeof(pft_size_prop));
-        if (ret < 0) {
-            return ret;
-        }
-    }
-    return ret;
-}
-
-
-static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
-                                     size_t maxsize)
-{
-    size_t maxcells = maxsize / sizeof(uint32_t);
-    int i, j, count;
-    uint32_t *p = prop;
-
-    for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
-        struct ppc_one_seg_page_size *sps = &env->sps.sps[i];
-
-        if (!sps->page_shift) {
-            break;
-        }
-        for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) {
-            if (sps->enc[count].page_shift == 0) {
-                break;
-            }
-        }
-        if ((p - prop) >= (maxcells - 3 - count * 2)) {
-            break;
-        }
-        *(p++) = cpu_to_be32(sps->page_shift);
-        *(p++) = cpu_to_be32(sps->slb_enc);
-        *(p++) = cpu_to_be32(count);
-        for (j = 0; j < count; j++) {
-            *(p++) = cpu_to_be32(sps->enc[j].page_shift);
-            *(p++) = cpu_to_be32(sps->enc[j].pte_enc);
-        }
-    }
-
-    return (p - prop) * sizeof(uint32_t);
-}
-
-#define _FDT(exp) \
-    do { \
-        int ret = (exp);                                           \
-        if (ret < 0) {                                             \
-            fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
-                    #exp, fdt_strerror(ret));                      \
-            exit(1);                                               \
-        }                                                          \
-    } while (0)
-
-
-static void *spapr_create_fdt_skel(const char *cpu_model,
-                                   hwaddr initrd_base,
-                                   hwaddr initrd_size,
-                                   hwaddr kernel_size,
-                                   const char *boot_device,
-                                   const char *kernel_cmdline,
-                                   uint32_t epow_irq)
-{
-    void *fdt;
-    CPUPPCState *env;
-    uint32_t start_prop = cpu_to_be32(initrd_base);
-    uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
-    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
-        "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk";
-    char qemu_hypertas_prop[] = "hcall-memop1";
-    uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
-    uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
-    char *modelname;
-    int i, smt = kvmppc_smt_threads();
-    unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
-
-    fdt = g_malloc0(FDT_MAX_SIZE);
-    _FDT((fdt_create(fdt, FDT_MAX_SIZE)));
-
-    if (kernel_size) {
-        _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size)));
-    }
-    if (initrd_size) {
-        _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size)));
-    }
-    _FDT((fdt_finish_reservemap(fdt)));
-
-    /* Root node */
-    _FDT((fdt_begin_node(fdt, "")));
-    _FDT((fdt_property_string(fdt, "device_type", "chrp")));
-    _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)")));
-
-    _FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
-    _FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
-
-    /* /chosen */
-    _FDT((fdt_begin_node(fdt, "chosen")));
-
-    /* Set Form1_affinity */
-    _FDT((fdt_property(fdt, "ibm,architecture-vec-5", vec5, sizeof(vec5))));
-
-    _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
-    _FDT((fdt_property(fdt, "linux,initrd-start",
-                       &start_prop, sizeof(start_prop))));
-    _FDT((fdt_property(fdt, "linux,initrd-end",
-                       &end_prop, sizeof(end_prop))));
-    if (kernel_size) {
-        uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
-                              cpu_to_be64(kernel_size) };
-
-        _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
-    }
-    if (boot_device) {
-        _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
-    }
-    _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width)));
-    _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height)));
-    _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth)));
-
-    _FDT((fdt_end_node(fdt)));
-
-    /* cpus */
-    _FDT((fdt_begin_node(fdt, "cpus")));
-
-    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
-    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
-
-    modelname = g_strdup(cpu_model);
-
-    for (i = 0; i < strlen(modelname); i++) {
-        modelname[i] = toupper(modelname[i]);
-    }
-
-    /* This is needed during FDT finalization */
-    spapr->cpu_model = g_strdup(modelname);
-
-    for (env = first_cpu; env != NULL; env = env->next_cpu) {
-        CPUState *cpu = CPU(ppc_env_get_cpu(env));
-        int index = cpu->cpu_index;
-        uint32_t servers_prop[smp_threads];
-        uint32_t gservers_prop[smp_threads * 2];
-        char *nodename;
-        uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
-                           0xffffffff, 0xffffffff};
-        uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
-        uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
-        uint32_t page_sizes_prop[64];
-        size_t page_sizes_prop_size;
-
-        if ((index % smt) != 0) {
-            continue;
-        }
-
-        nodename = g_strdup_printf("%s@%x", modelname, index);
-
-        _FDT((fdt_begin_node(fdt, nodename)));
-
-        g_free(nodename);
-
-        _FDT((fdt_property_cell(fdt, "reg", index)));
-        _FDT((fdt_property_string(fdt, "device_type", "cpu")));
-
-        _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR])));
-        _FDT((fdt_property_cell(fdt, "dcache-block-size",
-                                env->dcache_line_size)));
-        _FDT((fdt_property_cell(fdt, "icache-block-size",
-                                env->icache_line_size)));
-        _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq)));
-        _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq)));
-        _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
-        _FDT((fdt_property_string(fdt, "status", "okay")));
-        _FDT((fdt_property(fdt, "64-bit", NULL, 0)));
-
-        /* Build interrupt servers and gservers properties */
-        for (i = 0; i < smp_threads; i++) {
-            servers_prop[i] = cpu_to_be32(index + i);
-            /* Hack, direct the group queues back to cpu 0 */
-            gservers_prop[i*2] = cpu_to_be32(index + i);
-            gservers_prop[i*2 + 1] = 0;
-        }
-        _FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s",
-                           servers_prop, sizeof(servers_prop))));
-        _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
-                           gservers_prop, sizeof(gservers_prop))));
-
-        if (env->mmu_model & POWERPC_MMU_1TSEG) {
-            _FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
-                               segs, sizeof(segs))));
-        }
-
-        /* Advertise VMX/VSX (vector extensions) if available
-         *   0 / no property == no vector extensions
-         *   1               == VMX / Altivec available
-         *   2               == VSX available */
-        if (env->insns_flags & PPC_ALTIVEC) {
-            uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
-
-            _FDT((fdt_property_cell(fdt, "ibm,vmx", vmx)));
-        }
-
-        /* Advertise DFP (Decimal Floating Point) if available
-         *   0 / no property == no DFP
-         *   1               == DFP available */
-        if (env->insns_flags2 & PPC2_DFP) {
-            _FDT((fdt_property_cell(fdt, "ibm,dfp", 1)));
-        }
-
-        page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop,
-                                                      sizeof(page_sizes_prop));
-        if (page_sizes_prop_size) {
-            _FDT((fdt_property(fdt, "ibm,segment-page-sizes",
-                               page_sizes_prop, page_sizes_prop_size)));
-        }
-
-        _FDT((fdt_end_node(fdt)));
-    }
-
-    g_free(modelname);
-
-    _FDT((fdt_end_node(fdt)));
-
-    /* RTAS */
-    _FDT((fdt_begin_node(fdt, "rtas")));
-
-    _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
-                       sizeof(hypertas_prop))));
-    _FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas_prop,
-                       sizeof(qemu_hypertas_prop))));
-
-    _FDT((fdt_property(fdt, "ibm,associativity-reference-points",
-        refpoints, sizeof(refpoints))));
-
-    _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX)));
-
-    _FDT((fdt_end_node(fdt)));
-
-    /* interrupt controller */
-    _FDT((fdt_begin_node(fdt, "interrupt-controller")));
-
-    _FDT((fdt_property_string(fdt, "device_type",
-                              "PowerPC-External-Interrupt-Presentation")));
-    _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
-    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
-    _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
-                       interrupt_server_ranges_prop,
-                       sizeof(interrupt_server_ranges_prop))));
-    _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2)));
-    _FDT((fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP)));
-    _FDT((fdt_property_cell(fdt, "phandle", PHANDLE_XICP)));
-
-    _FDT((fdt_end_node(fdt)));
-
-    /* vdevice */
-    _FDT((fdt_begin_node(fdt, "vdevice")));
-
-    _FDT((fdt_property_string(fdt, "device_type", "vdevice")));
-    _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
-    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
-    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
-    _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2)));
-    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
-
-    _FDT((fdt_end_node(fdt)));
-
-    /* event-sources */
-    spapr_events_fdt_skel(fdt, epow_irq);
-
-    _FDT((fdt_end_node(fdt))); /* close root node */
-    _FDT((fdt_finish(fdt)));
-
-    return fdt;
-}
-
-static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
-{
-    uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0),
-                                cpu_to_be32(0x0), cpu_to_be32(0x0),
-                                cpu_to_be32(0x0)};
-    char mem_name[32];
-    hwaddr node0_size, mem_start;
-    uint64_t mem_reg_property[2];
-    int i, off;
-
-    /* memory node(s) */
-    node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size;
-    if (spapr->rma_size > node0_size) {
-        spapr->rma_size = node0_size;
-    }
-
-    /* RMA */
-    mem_reg_property[0] = 0;
-    mem_reg_property[1] = cpu_to_be64(spapr->rma_size);
-    off = fdt_add_subnode(fdt, 0, "memory@0");
-    _FDT(off);
-    _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
-    _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
-                      sizeof(mem_reg_property))));
-    _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
-                      sizeof(associativity))));
-
-    /* RAM: Node 0 */
-    if (node0_size > spapr->rma_size) {
-        mem_reg_property[0] = cpu_to_be64(spapr->rma_size);
-        mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size);
-
-        sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size);
-        off = fdt_add_subnode(fdt, 0, mem_name);
-        _FDT(off);
-        _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
-        _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
-                          sizeof(mem_reg_property))));
-        _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
-                          sizeof(associativity))));
-    }
-
-    /* RAM: Node 1 and beyond */
-    mem_start = node0_size;
-    for (i = 1; i < nb_numa_nodes; i++) {
-        mem_reg_property[0] = cpu_to_be64(mem_start);
-        mem_reg_property[1] = cpu_to_be64(node_mem[i]);
-        associativity[3] = associativity[4] = cpu_to_be32(i);
-        sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start);
-        off = fdt_add_subnode(fdt, 0, mem_name);
-        _FDT(off);
-        _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
-        _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
-                          sizeof(mem_reg_property))));
-        _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
-                          sizeof(associativity))));
-        mem_start += node_mem[i];
-    }
-
-    return 0;
-}
-
-static void spapr_finalize_fdt(sPAPREnvironment *spapr,
-                               hwaddr fdt_addr,
-                               hwaddr rtas_addr,
-                               hwaddr rtas_size)
-{
-    int ret;
-    void *fdt;
-    sPAPRPHBState *phb;
-
-    fdt = g_malloc(FDT_MAX_SIZE);
-
-    /* open out the base tree into a temp buffer for the final tweaks */
-    _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE)));
-
-    ret = spapr_populate_memory(spapr, fdt);
-    if (ret < 0) {
-        fprintf(stderr, "couldn't setup memory nodes in fdt\n");
-        exit(1);
-    }
-
-    ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
-    if (ret < 0) {
-        fprintf(stderr, "couldn't setup vio devices in fdt\n");
-        exit(1);
-    }
-
-    QLIST_FOREACH(phb, &spapr->phbs, list) {
-        ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt);
-    }
-
-    if (ret < 0) {
-        fprintf(stderr, "couldn't setup PCI devices in fdt\n");
-        exit(1);
-    }
-
-    /* RTAS */
-    ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
-    if (ret < 0) {
-        fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
-    }
-
-    /* Advertise NUMA via ibm,associativity */
-    ret = spapr_fixup_cpu_dt(fdt, spapr);
-    if (ret < 0) {
-        fprintf(stderr, "Couldn't finalize CPU device tree properties\n");
-    }
-
-    if (!spapr->has_graphics) {
-        spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
-    }
-
-    _FDT((fdt_pack(fdt)));
-
-    if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
-        hw_error("FDT too big ! 0x%x bytes (max is 0x%x)\n",
-                 fdt_totalsize(fdt), FDT_MAX_SIZE);
-        exit(1);
-    }
-
-    cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
-
-    g_free(fdt);
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
-    return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
-}
-
-static void emulate_spapr_hypercall(PowerPCCPU *cpu)
-{
-    CPUPPCState *env = &cpu->env;
-
-    if (msr_pr) {
-        hcall_dprintf("Hypercall made with MSR[PR]=1\n");
-        env->gpr[3] = H_PRIVILEGE;
-    } else {
-        env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
-    }
-}
-
-static void spapr_reset_htab(sPAPREnvironment *spapr)
-{
-    long shift;
-
-    /* allocate hash page table.  For now we always make this 16mb,
-     * later we should probably make it scale to the size of guest
-     * RAM */
-
-    shift = kvmppc_reset_htab(spapr->htab_shift);
-
-    if (shift > 0) {
-        /* Kernel handles htab, we don't need to allocate one */
-        spapr->htab_shift = shift;
-    } else {
-        if (!spapr->htab) {
-            /* Allocate an htab if we don't yet have one */
-            spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr));
-        }
-
-        /* And clear it */
-        memset(spapr->htab, 0, HTAB_SIZE(spapr));
-    }
-
-    /* Update the RMA size if necessary */
-    if (spapr->vrma_adjust) {
-        spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift);
-    }
-}
-
-static void ppc_spapr_reset(void)
-{
-    /* Reset the hash table & recalc the RMA */
-    spapr_reset_htab(spapr);
-
-    qemu_devices_reset();
-
-    /* Load the fdt */
-    spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr,
-                       spapr->rtas_size);
-
-    /* Set up the entry state */
-    first_cpu->gpr[3] = spapr->fdt_addr;
-    first_cpu->gpr[5] = 0;
-    first_cpu->halted = 0;
-    first_cpu->nip = spapr->entry_point;
-
-}
-
-static void spapr_cpu_reset(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-
-    cpu_reset(CPU(cpu));
-
-    /* All CPUs start halted.  CPU0 is unhalted from the machine level
-     * reset code and the rest are explicitly started up by the guest
-     * using an RTAS call */
-    env->halted = 1;
-
-    env->spr[SPR_HIOR] = 0;
-
-    env->external_htab = spapr->htab;
-    env->htab_base = -1;
-    env->htab_mask = HTAB_SIZE(spapr) - 1;
-    env->spr[SPR_SDR1] = (unsigned long)spapr->htab |
-        (spapr->htab_shift - 18);
-}
-
-static void spapr_create_nvram(sPAPREnvironment *spapr)
-{
-    QemuOpts *machine_opts;
-    DeviceState *dev;
-
-    dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
-
-    machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
-    if (machine_opts) {
-        const char *drivename;
-
-        drivename = qemu_opt_get(machine_opts, "nvram");
-        if (drivename) {
-            BlockDriverState *bs;
-
-            bs = bdrv_find(drivename);
-            if (!bs) {
-                fprintf(stderr, "No such block device \"%s\" for nvram\n",
-                        drivename);
-                exit(1);
-            }
-            qdev_prop_set_drive_nofail(dev, "drive", bs);
-        }
-    }
-
-    qdev_init_nofail(dev);
-
-    spapr->nvram = (struct sPAPRNVRAM *)dev;
-}
-
-/* Returns whether we want to use VGA or not */
-static int spapr_vga_init(PCIBus *pci_bus)
-{
-    switch (vga_interface_type) {
-    case VGA_NONE:
-    case VGA_STD:
-        return pci_vga_init(pci_bus) != NULL;
-    default:
-        fprintf(stderr, "This vga model is not supported,"
-                "currently it only supports -vga std\n");
-        exit(0);
-        break;
-    }
-}
-
-/* pSeries LPAR / sPAPR hardware init */
-static void ppc_spapr_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-    PCIHostState *phb;
-    int i;
-    MemoryRegion *sysmem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    hwaddr rma_alloc_size;
-    uint32_t initrd_base = 0;
-    long kernel_size = 0, initrd_size = 0;
-    long load_limit, rtas_limit, fw_size;
-    char *filename;
-
-    msi_supported = true;
-
-    spapr = g_malloc0(sizeof(*spapr));
-    QLIST_INIT(&spapr->phbs);
-
-    cpu_ppc_hypercall = emulate_spapr_hypercall;
-
-    /* Allocate RMA if necessary */
-    rma_alloc_size = kvmppc_alloc_rma("ppc_spapr.rma", sysmem);
-
-    if (rma_alloc_size == -1) {
-        hw_error("qemu: Unable to create RMA\n");
-        exit(1);
-    }
-
-    if (rma_alloc_size && (rma_alloc_size < ram_size)) {
-        spapr->rma_size = rma_alloc_size;
-    } else {
-        spapr->rma_size = ram_size;
-
-        /* With KVM, we don't actually know whether KVM supports an
-         * unbounded RMA (PR KVM) or is limited by the hash table size
-         * (HV KVM using VRMA), so we always assume the latter
-         *
-         * In that case, we also limit the initial allocations for RTAS
-         * etc... to 256M since we have no way to know what the VRMA size
-         * is going to be as it depends on the size of the hash table
-         * isn't determined yet.
-         */
-        if (kvm_enabled()) {
-            spapr->vrma_adjust = 1;
-            spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
-        }
-    }
-
-    /* We place the device tree and RTAS just below either the top of the RMA,
-     * or just below 2GB, whichever is lowere, so that it can be
-     * processed with 32-bit real mode code if necessary */
-    rtas_limit = MIN(spapr->rma_size, 0x80000000);
-    spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;
-    spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;
-    load_limit = spapr->fdt_addr - FW_OVERHEAD;
-
-    /* We aim for a hash table of size 1/128 the size of RAM.  The
-     * normal rule of thumb is 1/64 the size of RAM, but that's much
-     * more than needed for the Linux guests we support. */
-    spapr->htab_shift = 18; /* Minimum architected size */
-    while (spapr->htab_shift <= 46) {
-        if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) {
-            break;
-        }
-        spapr->htab_shift++;
-    }
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-        cpu_model = kvm_enabled() ? "host" : "POWER7";
-    }
-    for (i = 0; i < smp_cpus; i++) {
-        cpu = cpu_ppc_init(cpu_model);
-        if (cpu == NULL) {
-            fprintf(stderr, "Unable to find PowerPC CPU definition\n");
-            exit(1);
-        }
-        env = &cpu->env;
-
-        /* Set time-base frequency to 512 MHz */
-        cpu_ppc_tb_init(env, TIMEBASE_FREQ);
-
-        /* PAPR always has exception vectors in RAM not ROM */
-        env->hreset_excp_prefix = 0;
-
-        /* Tell KVM that we're in PAPR mode */
-        if (kvm_enabled()) {
-            kvmppc_set_papr(cpu);
-        }
-
-        qemu_register_reset(spapr_cpu_reset, cpu);
-    }
-
-    /* allocate RAM */
-    spapr->ram_limit = ram_size;
-    if (spapr->ram_limit > rma_alloc_size) {
-        ram_addr_t nonrma_base = rma_alloc_size;
-        ram_addr_t nonrma_size = spapr->ram_limit - rma_alloc_size;
-
-        memory_region_init_ram(ram, "ppc_spapr.ram", nonrma_size);
-        vmstate_register_ram_global(ram);
-        memory_region_add_subregion(sysmem, nonrma_base, ram);
-    }
-
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
-    spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,
-                                           rtas_limit - spapr->rtas_addr);
-    if (spapr->rtas_size < 0) {
-        hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
-        exit(1);
-    }
-    if (spapr->rtas_size > RTAS_MAX_SIZE) {
-        hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n",
-                 spapr->rtas_size, RTAS_MAX_SIZE);
-        exit(1);
-    }
-    g_free(filename);
-
-
-    /* Set up Interrupt Controller */
-    spapr->icp = xics_system_init(XICS_IRQS);
-    spapr->next_irq = XICS_IRQ_BASE;
-
-    /* Set up EPOW events infrastructure */
-    spapr_events_init(spapr);
-
-    /* Set up IOMMU */
-    spapr_iommu_init();
-
-    /* Set up VIO bus */
-    spapr->vio_bus = spapr_vio_bus_init();
-
-    for (i = 0; i < MAX_SERIAL_PORTS; i++) {
-        if (serial_hds[i]) {
-            spapr_vty_create(spapr->vio_bus, serial_hds[i]);
-        }
-    }
-
-    /* We always have at least the nvram device on VIO */
-    spapr_create_nvram(spapr);
-
-    /* Set up PCI */
-    spapr_pci_rtas_init();
-
-    phb = spapr_create_phb(spapr, 0, "pci");
-
-    for (i = 0; i < nb_nics; i++) {
-        NICInfo *nd = &nd_table[i];
-
-        if (!nd->model) {
-            nd->model = g_strdup("ibmveth");
-        }
-
-        if (strcmp(nd->model, "ibmveth") == 0) {
-            spapr_vlan_create(spapr->vio_bus, nd);
-        } else {
-            pci_nic_init_nofail(&nd_table[i], nd->model, NULL);
-        }
-    }
-
-    for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
-        spapr_vscsi_create(spapr->vio_bus);
-    }
-
-    /* Graphics */
-    if (spapr_vga_init(phb->bus)) {
-        spapr->has_graphics = true;
-    }
-
-    if (usb_enabled(spapr->has_graphics)) {
-        pci_create_simple(phb->bus, -1, "pci-ohci");
-        if (spapr->has_graphics) {
-            usbdevice_create("keyboard");
-            usbdevice_create("mouse");
-        }
-    }
-
-    if (spapr->rma_size < (MIN_RMA_SLOF << 20)) {
-        fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
-                "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
-        exit(1);
-    }
-
-    if (kernel_filename) {
-        uint64_t lowaddr = 0;
-
-        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
-                               NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
-        if (kernel_size < 0) {
-            kernel_size = load_image_targphys(kernel_filename,
-                                              KERNEL_LOAD_ADDR,
-                                              load_limit - KERNEL_LOAD_ADDR);
-        }
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-
-        /* load initrd */
-        if (initrd_filename) {
-            /* Try to locate the initrd in the gap between the kernel
-             * and the firmware. Add a bit of space just in case
-             */
-            initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff;
-            initrd_size = load_image_targphys(initrd_filename, initrd_base,
-                                              load_limit - initrd_base);
-            if (initrd_size < 0) {
-                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                        initrd_filename);
-                exit(1);
-            }
-        } else {
-            initrd_base = 0;
-            initrd_size = 0;
-        }
-    }
-
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
-    fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
-    if (fw_size < 0) {
-        hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
-        exit(1);
-    }
-    g_free(filename);
-
-    spapr->entry_point = 0x100;
-
-    /* Prepare the device tree */
-    spapr->fdt_skel = spapr_create_fdt_skel(cpu_model,
-                                            initrd_base, initrd_size,
-                                            kernel_size,
-                                            boot_device, kernel_cmdline,
-                                            spapr->epow_irq);
-    assert(spapr->fdt_skel != NULL);
-}
-
-static QEMUMachine spapr_machine = {
-    .name = "pseries",
-    .desc = "pSeries Logical Partition (PAPR compliant)",
-    .init = ppc_spapr_init,
-    .reset = ppc_spapr_reset,
-    .block_default_type = IF_SCSI,
-    .max_cpus = MAX_CPUS,
-    .no_parallel = 1,
-    .boot_order = NULL,
-};
-
-static void spapr_machine_init(void)
-{
-    qemu_register_machine(&spapr_machine);
-}
-
-machine_init(spapr_machine_init);
index a39a511c527013e80fdeb2f883e2b5e4ea6f3ab3..71bbddf8c31c8e441360c7a762aaefe508e01e07 100644 (file)
@@ -1,8 +1,10 @@
-obj-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
+obj-y = lance.o tcx.o sun4m_iommu.o slavio_intctl.o
 obj-y += slavio_timer.o slavio_misc.o sparc32_dma.o
-obj-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
+obj-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
 
 # GRLIB
 obj-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-y += sun4m.o leon3.o
diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c
new file mode 100644 (file)
index 0000000..f58061f
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * QEMU Leon3 System Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "char/char.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "trace.h"
+#include "exec/address-spaces.h"
+
+#include "hw/grlib.h"
+
+/* Default system clock.  */
+#define CPU_CLK (40 * 1000 * 1000)
+
+#define PROM_FILENAME        "u-boot.bin"
+
+#define MAX_PILS 16
+
+typedef struct ResetData {
+    SPARCCPU *cpu;
+    uint32_t  entry;            /* save kernel entry in case of reset */
+} ResetData;
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s   = (ResetData *)opaque;
+    CPUSPARCState  *env = &s->cpu->env;
+
+    cpu_reset(CPU(s->cpu));
+
+    env->halted = 0;
+    env->pc     = s->entry;
+    env->npc    = s->entry + 4;
+}
+
+void leon3_irq_ack(void *irq_manager, int intno)
+{
+    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
+}
+
+static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
+{
+    CPUSPARCState *env = (CPUSPARCState *)opaque;
+
+    assert(env != NULL);
+
+    env->pil_in = pil_in;
+
+    if (env->pil_in && (env->interrupt_index == 0 ||
+                        (env->interrupt_index & ~15) == TT_EXTINT)) {
+        unsigned int i;
+
+        for (i = 15; i > 0; i--) {
+            if (env->pil_in & (1 << i)) {
+                int old_interrupt = env->interrupt_index;
+
+                env->interrupt_index = TT_EXTINT | i;
+                if (old_interrupt != env->interrupt_index) {
+                    trace_leon3_set_irq(i);
+                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                }
+                break;
+            }
+        }
+    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
+        trace_leon3_reset_irq(env->interrupt_index & 15);
+        env->interrupt_index = 0;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void leon3_generic_hw_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    SPARCCPU *cpu;
+    CPUSPARCState   *env;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *prom = g_new(MemoryRegion, 1);
+    int         ret;
+    char       *filename;
+    qemu_irq   *cpu_irqs = NULL;
+    int         bios_size;
+    int         prom_size;
+    ResetData  *reset_info;
+
+    /* Init CPU */
+    if (!cpu_model) {
+        cpu_model = "LEON3";
+    }
+
+    cpu = cpu_sparc_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
+    env = &cpu->env;
+
+    cpu_sparc_set_id(env, 0);
+
+    /* Reset data */
+    reset_info        = g_malloc0(sizeof(ResetData));
+    reset_info->cpu   = cpu;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    /* Allocate IRQ manager */
+    grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in);
+
+    env->qemu_irq_ack = leon3_irq_manager;
+
+    /* Allocate RAM */
+    if ((uint64_t)ram_size > (1UL << 30)) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d, maximum 1G\n",
+                (unsigned int)(ram_size / (1024 * 1024)));
+        exit(1);
+    }
+
+    memory_region_init_ram(ram, "leon3.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(address_space_mem, 0x40000000, ram);
+
+    /* Allocate BIOS */
+    prom_size = 8 * 1024 * 1024; /* 8Mb */
+    memory_region_init_ram(prom, "Leon3.bios", prom_size);
+    vmstate_register_ram_global(prom);
+    memory_region_set_readonly(prom, true);
+    memory_region_add_subregion(address_space_mem, 0x00000000, prom);
+
+    /* Load boot prom */
+    if (bios_name == NULL) {
+        bios_name = PROM_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+    bios_size = get_image_size(filename);
+
+    if (bios_size > prom_size) {
+        fprintf(stderr, "qemu: could not load prom '%s': file too big\n",
+                filename);
+        exit(1);
+    }
+
+    if (bios_size > 0) {
+        ret = load_image_targphys(filename, 0x00000000, bios_size);
+        if (ret < 0 || ret > prom_size) {
+            fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
+            exit(1);
+        }
+    } else if (kernel_filename == NULL) {
+        fprintf(stderr, "Can't read bios image %s\n", filename);
+        exit(1);
+    }
+
+    /* Can directly load an application. */
+    if (kernel_filename != NULL) {
+        long     kernel_size;
+        uint64_t entry;
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1 /* big endian */, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        if (bios_size <= 0) {
+            /* If there is no bios/monitor, start the application.  */
+            env->pc = entry;
+            env->npc = entry + 4;
+            reset_info->entry = entry;
+        }
+    }
+
+    /* Allocate timers */
+    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
+
+    /* Allocate uart */
+    if (serial_hds[0]) {
+        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
+    }
+}
+
+static QEMUMachine leon3_generic_machine = {
+    .name     = "leon3_generic",
+    .desc     = "Leon-3 generic",
+    .init     = leon3_generic_hw_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void leon3_machine_init(void)
+{
+    qemu_register_machine(&leon3_generic_machine);
+}
+
+machine_init(leon3_machine_init);
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
new file mode 100644 (file)
index 0000000..37bd041
--- /dev/null
@@ -0,0 +1,1936 @@
+/*
+ * QEMU Sun4m & Sun4d & Sun4c System Emulator
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "hw/sun4m.h"
+#include "hw/nvram.h"
+#include "hw/sparc32_dma.h"
+#include "hw/fdc.h"
+#include "sysemu/sysemu.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "hw/firmware_abi.h"
+#include "hw/esp.h"
+#include "hw/pc.h"
+#include "hw/isa.h"
+#include "hw/fw_cfg.h"
+#include "hw/escc.h"
+#include "hw/empty_slot.h"
+#include "hw/qdev-addr.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "sysemu/blockdev.h"
+#include "trace.h"
+
+/*
+ * Sun4m architecture was used in the following machines:
+ *
+ * SPARCserver 6xxMP/xx
+ * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15),
+ * SPARCclassic X (4/10)
+ * SPARCstation LX/ZX (4/30)
+ * SPARCstation Voyager
+ * SPARCstation 10/xx, SPARCserver 10/xx
+ * SPARCstation 5, SPARCserver 5
+ * SPARCstation 20/xx, SPARCserver 20
+ * SPARCstation 4
+ *
+ * Sun4d architecture was used in the following machines:
+ *
+ * SPARCcenter 2000
+ * SPARCserver 1000
+ *
+ * Sun4c architecture was used in the following machines:
+ * SPARCstation 1/1+, SPARCserver 1/1+
+ * SPARCstation SLC
+ * SPARCstation IPC
+ * SPARCstation ELC
+ * SPARCstation IPX
+ *
+ * See for example: http://www.sunhelp.org/faq/sunref1.html
+ */
+
+#define KERNEL_LOAD_ADDR     0x00004000
+#define CMDLINE_ADDR         0x007ff000
+#define INITRD_LOAD_ADDR     0x00800000
+#define PROM_SIZE_MAX        (1024 * 1024)
+#define PROM_VADDR           0xffd00000
+#define PROM_FILENAME        "openbios-sparc32"
+#define CFG_ADDR             0xd00000510ULL
+#define FW_CFG_SUN4M_DEPTH   (FW_CFG_ARCH_LOCAL + 0x00)
+
+#define MAX_CPUS 16
+#define MAX_PILS 16
+#define MAX_VSIMMS 4
+
+#define ESCC_CLOCK 4915200
+
+struct sun4m_hwdef {
+    hwaddr iommu_base, iommu_pad_base, iommu_pad_len, slavio_base;
+    hwaddr intctl_base, counter_base, nvram_base, ms_kb_base;
+    hwaddr serial_base, fd_base;
+    hwaddr afx_base, idreg_base, dma_base, esp_base, le_base;
+    hwaddr tcx_base, cs_base, apc_base, aux1_base, aux2_base;
+    hwaddr bpp_base, dbri_base, sx_base;
+    struct {
+        hwaddr reg_base, vram_base;
+    } vsimm[MAX_VSIMMS];
+    hwaddr ecc_base;
+    uint64_t max_mem;
+    const char * const default_cpu_model;
+    uint32_t ecc_version;
+    uint32_t iommu_version;
+    uint16_t machine_id;
+    uint8_t nvram_machine_id;
+};
+
+#define MAX_IOUNITS 5
+
+struct sun4d_hwdef {
+    hwaddr iounit_bases[MAX_IOUNITS], slavio_base;
+    hwaddr counter_base, nvram_base, ms_kb_base;
+    hwaddr serial_base;
+    hwaddr espdma_base, esp_base;
+    hwaddr ledma_base, le_base;
+    hwaddr tcx_base;
+    hwaddr sbi_base;
+    uint64_t max_mem;
+    const char * const default_cpu_model;
+    uint32_t iounit_version;
+    uint16_t machine_id;
+    uint8_t nvram_machine_id;
+};
+
+struct sun4c_hwdef {
+    hwaddr iommu_base, slavio_base;
+    hwaddr intctl_base, counter_base, nvram_base, ms_kb_base;
+    hwaddr serial_base, fd_base;
+    hwaddr idreg_base, dma_base, esp_base, le_base;
+    hwaddr tcx_base, aux1_base;
+    uint64_t max_mem;
+    const char * const default_cpu_model;
+    uint32_t iommu_version;
+    uint16_t machine_id;
+    uint8_t nvram_machine_id;
+};
+
+int DMA_get_channel_mode (int nchan)
+{
+    return 0;
+}
+int DMA_read_memory (int nchan, void *buf, int pos, int size)
+{
+    return 0;
+}
+int DMA_write_memory (int nchan, void *buf, int pos, int size)
+{
+    return 0;
+}
+void DMA_hold_DREQ (int nchan) {}
+void DMA_release_DREQ (int nchan) {}
+void DMA_schedule(int nchan) {}
+
+void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit)
+{
+}
+
+void DMA_register_channel (int nchan,
+                           DMA_transfer_handler transfer_handler,
+                           void *opaque)
+{
+}
+
+static int fw_cfg_boot_set(void *opaque, const char *boot_device)
+{
+    fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    return 0;
+}
+
+static void nvram_init(M48t59State *nvram, uint8_t *macaddr,
+                       const char *cmdline, const char *boot_devices,
+                       ram_addr_t RAM_size, uint32_t kernel_size,
+                       int width, int height, int depth,
+                       int nvram_machine_id, const char *arch)
+{
+    unsigned int i;
+    uint32_t start, end;
+    uint8_t image[0x1ff0];
+    struct OpenBIOS_nvpart_v1 *part_header;
+
+    memset(image, '\0', sizeof(image));
+
+    start = 0;
+
+    // OpenBIOS nvram variables
+    // Variable partition
+    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
+    part_header->signature = OPENBIOS_PART_SYSTEM;
+    pstrcpy(part_header->name, sizeof(part_header->name), "system");
+
+    end = start + sizeof(struct OpenBIOS_nvpart_v1);
+    for (i = 0; i < nb_prom_envs; i++)
+        end = OpenBIOS_set_var(image, end, prom_envs[i]);
+
+    // End marker
+    image[end++] = '\0';
+
+    end = start + ((end - start + 15) & ~15);
+    OpenBIOS_finish_partition(part_header, end - start);
+
+    // free partition
+    start = end;
+    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
+    part_header->signature = OPENBIOS_PART_FREE;
+    pstrcpy(part_header->name, sizeof(part_header->name), "free");
+
+    end = 0x1fd0;
+    OpenBIOS_finish_partition(part_header, end - start);
+
+    Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr,
+                    nvram_machine_id);
+
+    for (i = 0; i < sizeof(image); i++)
+        m48t59_write(nvram, i, image[i]);
+}
+
+static DeviceState *slavio_intctl;
+
+void sun4m_pic_info(Monitor *mon, const QDict *qdict)
+{
+    if (slavio_intctl)
+        slavio_pic_info(mon, slavio_intctl);
+}
+
+void sun4m_irq_info(Monitor *mon, const QDict *qdict)
+{
+    if (slavio_intctl)
+        slavio_irq_info(mon, slavio_intctl);
+}
+
+void cpu_check_irqs(CPUSPARCState *env)
+{
+    if (env->pil_in && (env->interrupt_index == 0 ||
+                        (env->interrupt_index & ~15) == TT_EXTINT)) {
+        unsigned int i;
+
+        for (i = 15; i > 0; i--) {
+            if (env->pil_in & (1 << i)) {
+                int old_interrupt = env->interrupt_index;
+
+                env->interrupt_index = TT_EXTINT | i;
+                if (old_interrupt != env->interrupt_index) {
+                    trace_sun4m_cpu_interrupt(i);
+                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                }
+                break;
+            }
+        }
+    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
+        trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15);
+        env->interrupt_index = 0;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void cpu_kick_irq(SPARCCPU *cpu)
+{
+    CPUSPARCState *env = &cpu->env;
+
+    env->halted = 0;
+    cpu_check_irqs(env);
+    qemu_cpu_kick(CPU(cpu));
+}
+
+static void cpu_set_irq(void *opaque, int irq, int level)
+{
+    SPARCCPU *cpu = opaque;
+    CPUSPARCState *env = &cpu->env;
+
+    if (level) {
+        trace_sun4m_cpu_set_irq_raise(irq);
+        env->pil_in |= 1 << irq;
+        cpu_kick_irq(cpu);
+    } else {
+        trace_sun4m_cpu_set_irq_lower(irq);
+        env->pil_in &= ~(1 << irq);
+        cpu_check_irqs(env);
+    }
+}
+
+static void dummy_cpu_set_irq(void *opaque, int irq, int level)
+{
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    SPARCCPU *cpu = opaque;
+    CPUSPARCState *env = &cpu->env;
+
+    cpu_reset(CPU(cpu));
+    env->halted = 0;
+}
+
+static void secondary_cpu_reset(void *opaque)
+{
+    SPARCCPU *cpu = opaque;
+    CPUSPARCState *env = &cpu->env;
+
+    cpu_reset(CPU(cpu));
+    env->halted = 1;
+}
+
+static void cpu_halt_signal(void *opaque, int irq, int level)
+{
+    if (level && cpu_single_env)
+        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return addr - 0xf0000000ULL;
+}
+
+static unsigned long sun4m_load_kernel(const char *kernel_filename,
+                                       const char *initrd_filename,
+                                       ram_addr_t RAM_size)
+{
+    int linux_boot;
+    unsigned int i;
+    long initrd_size, kernel_size;
+    uint8_t *ptr;
+
+    linux_boot = (kernel_filename != NULL);
+
+    kernel_size = 0;
+    if (linux_boot) {
+        int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+        bswap_needed = 1;
+#else
+        bswap_needed = 0;
+#endif
+        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
+                               NULL, NULL, NULL, 1, ELF_MACHINE, 0);
+        if (kernel_size < 0)
+            kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
+                                    RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+                                    TARGET_PAGE_SIZE);
+        if (kernel_size < 0)
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              RAM_size - KERNEL_LOAD_ADDR);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+
+        /* load initrd */
+        initrd_size = 0;
+        if (initrd_filename) {
+            initrd_size = load_image_targphys(initrd_filename,
+                                              INITRD_LOAD_ADDR,
+                                              RAM_size - INITRD_LOAD_ADDR);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        }
+        if (initrd_size > 0) {
+            for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
+                ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
+                if (ldl_p(ptr) == 0x48647253) { // HdrS
+                    stl_p(ptr + 16, INITRD_LOAD_ADDR);
+                    stl_p(ptr + 20, initrd_size);
+                    break;
+                }
+            }
+        }
+    }
+    return kernel_size;
+}
+
+static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "iommu");
+    qdev_prop_set_uint32(dev, "version", version);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, irq);
+    sysbus_mmio_map(s, 0, addr);
+
+    return s;
+}
+
+static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq,
+                              void *iommu, qemu_irq *dev_irq, int is_ledma)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "sparc32_dma");
+    qdev_prop_set_ptr(dev, "iommu_opaque", iommu);
+    qdev_prop_set_uint32(dev, "is_ledma", is_ledma);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, parent_irq);
+    *dev_irq = qdev_get_gpio_in(dev, 0);
+    sysbus_mmio_map(s, 0, daddr);
+
+    return s;
+}
+
+static void lance_init(NICInfo *nd, hwaddr leaddr,
+                       void *dma_opaque, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    qemu_irq reset;
+
+    qemu_check_nic_model(&nd_table[0], "lance");
+
+    dev = qdev_create(NULL, "lance");
+    qdev_set_nic_properties(dev, nd);
+    qdev_prop_set_ptr(dev, "dma", dma_opaque);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(s, 0, leaddr);
+    sysbus_connect_irq(s, 0, irq);
+    reset = qdev_get_gpio_in(dev, 0);
+    qdev_connect_gpio_out(dma_opaque, 0, reset);
+}
+
+static DeviceState *slavio_intctl_init(hwaddr addr,
+                                       hwaddr addrg,
+                                       qemu_irq **parent_irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    unsigned int i, j;
+
+    dev = qdev_create(NULL, "slavio_intctl");
+    qdev_init_nofail(dev);
+
+    s = SYS_BUS_DEVICE(dev);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        for (j = 0; j < MAX_PILS; j++) {
+            sysbus_connect_irq(s, i * MAX_PILS + j, parent_irq[i][j]);
+        }
+    }
+    sysbus_mmio_map(s, 0, addrg);
+    for (i = 0; i < MAX_CPUS; i++) {
+        sysbus_mmio_map(s, i + 1, addr + i * TARGET_PAGE_SIZE);
+    }
+
+    return dev;
+}
+
+#define SYS_TIMER_OFFSET      0x10000ULL
+#define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu)
+
+static void slavio_timer_init_all(hwaddr addr, qemu_irq master_irq,
+                                  qemu_irq *cpu_irqs, unsigned int num_cpus)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    unsigned int i;
+
+    dev = qdev_create(NULL, "slavio_timer");
+    qdev_prop_set_uint32(dev, "num_cpus", num_cpus);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, master_irq);
+    sysbus_mmio_map(s, 0, addr + SYS_TIMER_OFFSET);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        sysbus_mmio_map(s, i + 1, addr + (hwaddr)CPU_TIMER_OFFSET(i));
+        sysbus_connect_irq(s, i + 1, cpu_irqs[i]);
+    }
+}
+
+static qemu_irq  slavio_system_powerdown;
+
+static void slavio_powerdown_req(Notifier *n, void *opaque)
+{
+    qemu_irq_raise(slavio_system_powerdown);
+}
+
+static Notifier slavio_system_powerdown_notifier = {
+    .notify = slavio_powerdown_req
+};
+
+#define MISC_LEDS 0x01600000
+#define MISC_CFG  0x01800000
+#define MISC_DIAG 0x01a00000
+#define MISC_MDM  0x01b00000
+#define MISC_SYS  0x01f00000
+
+static void slavio_misc_init(hwaddr base,
+                             hwaddr aux1_base,
+                             hwaddr aux2_base, qemu_irq irq,
+                             qemu_irq fdc_tc)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "slavio_misc");
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    if (base) {
+        /* 8 bit registers */
+        /* Slavio control */
+        sysbus_mmio_map(s, 0, base + MISC_CFG);
+        /* Diagnostics */
+        sysbus_mmio_map(s, 1, base + MISC_DIAG);
+        /* Modem control */
+        sysbus_mmio_map(s, 2, base + MISC_MDM);
+        /* 16 bit registers */
+        /* ss600mp diag LEDs */
+        sysbus_mmio_map(s, 3, base + MISC_LEDS);
+        /* 32 bit registers */
+        /* System control */
+        sysbus_mmio_map(s, 4, base + MISC_SYS);
+    }
+    if (aux1_base) {
+        /* AUX 1 (Misc System Functions) */
+        sysbus_mmio_map(s, 5, aux1_base);
+    }
+    if (aux2_base) {
+        /* AUX 2 (Software Powerdown Control) */
+        sysbus_mmio_map(s, 6, aux2_base);
+    }
+    sysbus_connect_irq(s, 0, irq);
+    sysbus_connect_irq(s, 1, fdc_tc);
+    slavio_system_powerdown = qdev_get_gpio_in(dev, 0);
+    qemu_register_powerdown_notifier(&slavio_system_powerdown_notifier);
+}
+
+static void ecc_init(hwaddr base, qemu_irq irq, uint32_t version)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "eccmemctl");
+    qdev_prop_set_uint32(dev, "version", version);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, irq);
+    sysbus_mmio_map(s, 0, base);
+    if (version == 0) { // SS-600MP only
+        sysbus_mmio_map(s, 1, base + 0x1000);
+    }
+}
+
+static void apc_init(hwaddr power_base, qemu_irq cpu_halt)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "apc");
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    /* Power management (APC) XXX: not a Slavio device */
+    sysbus_mmio_map(s, 0, power_base);
+    sysbus_connect_irq(s, 0, cpu_halt);
+}
+
+static void tcx_init(hwaddr addr, int vram_size, int width,
+                     int height, int depth)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "SUNW,tcx");
+    qdev_prop_set_taddr(dev, "addr", addr);
+    qdev_prop_set_uint32(dev, "vram_size", vram_size);
+    qdev_prop_set_uint16(dev, "width", width);
+    qdev_prop_set_uint16(dev, "height", height);
+    qdev_prop_set_uint16(dev, "depth", depth);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    /* 8-bit plane */
+    sysbus_mmio_map(s, 0, addr + 0x00800000ULL);
+    /* DAC */
+    sysbus_mmio_map(s, 1, addr + 0x00200000ULL);
+    /* TEC (dummy) */
+    sysbus_mmio_map(s, 2, addr + 0x00700000ULL);
+    /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */
+    sysbus_mmio_map(s, 3, addr + 0x00301000ULL);
+    if (depth == 24) {
+        /* 24-bit plane */
+        sysbus_mmio_map(s, 4, addr + 0x02000000ULL);
+        /* Control plane */
+        sysbus_mmio_map(s, 5, addr + 0x0a000000ULL);
+    } else {
+        /* THC 8 bit (dummy) */
+        sysbus_mmio_map(s, 4, addr + 0x00300000ULL);
+    }
+}
+
+/* NCR89C100/MACIO Internal ID register */
+static const uint8_t idreg_data[] = { 0xfe, 0x81, 0x01, 0x03 };
+
+static void idreg_init(hwaddr addr)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "macio_idreg");
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+    cpu_physical_memory_write_rom(addr, idreg_data, sizeof(idreg_data));
+}
+
+typedef struct IDRegState {
+    SysBusDevice busdev;
+    MemoryRegion mem;
+} IDRegState;
+
+static int idreg_init1(SysBusDevice *dev)
+{
+    IDRegState *s = FROM_SYSBUS(IDRegState, dev);
+
+    memory_region_init_ram(&s->mem, "sun4m.idreg", sizeof(idreg_data));
+    vmstate_register_ram_global(&s->mem);
+    memory_region_set_readonly(&s->mem, true);
+    sysbus_init_mmio(dev, &s->mem);
+    return 0;
+}
+
+static void idreg_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = idreg_init1;
+}
+
+static const TypeInfo idreg_info = {
+    .name          = "macio_idreg",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IDRegState),
+    .class_init    = idreg_class_init,
+};
+
+typedef struct AFXState {
+    SysBusDevice busdev;
+    MemoryRegion mem;
+} AFXState;
+
+/* SS-5 TCX AFX register */
+static void afx_init(hwaddr addr)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "tcx_afx");
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+}
+
+static int afx_init1(SysBusDevice *dev)
+{
+    AFXState *s = FROM_SYSBUS(AFXState, dev);
+
+    memory_region_init_ram(&s->mem, "sun4m.afx", 4);
+    vmstate_register_ram_global(&s->mem);
+    sysbus_init_mmio(dev, &s->mem);
+    return 0;
+}
+
+static void afx_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = afx_init1;
+}
+
+static const TypeInfo afx_info = {
+    .name          = "tcx_afx",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(AFXState),
+    .class_init    = afx_class_init,
+};
+
+typedef struct PROMState {
+    SysBusDevice busdev;
+    MemoryRegion prom;
+} PROMState;
+
+/* Boot PROM (OpenBIOS) */
+static uint64_t translate_prom_address(void *opaque, uint64_t addr)
+{
+    hwaddr *base_addr = (hwaddr *)opaque;
+    return addr + *base_addr - PROM_VADDR;
+}
+
+static void prom_init(hwaddr addr, const char *bios_name)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    char *filename;
+    int ret;
+
+    dev = qdev_create(NULL, "openprom");
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+
+    /* load boot prom */
+    if (bios_name == NULL) {
+        bios_name = PROM_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        ret = load_elf(filename, translate_prom_address, &addr, NULL,
+                       NULL, NULL, 1, ELF_MACHINE, 0);
+        if (ret < 0 || ret > PROM_SIZE_MAX) {
+            ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
+        }
+        g_free(filename);
+    } else {
+        ret = -1;
+    }
+    if (ret < 0 || ret > PROM_SIZE_MAX) {
+        fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name);
+        exit(1);
+    }
+}
+
+static int prom_init1(SysBusDevice *dev)
+{
+    PROMState *s = FROM_SYSBUS(PROMState, dev);
+
+    memory_region_init_ram(&s->prom, "sun4m.prom", PROM_SIZE_MAX);
+    vmstate_register_ram_global(&s->prom);
+    memory_region_set_readonly(&s->prom, true);
+    sysbus_init_mmio(dev, &s->prom);
+    return 0;
+}
+
+static Property prom_properties[] = {
+    {/* end of property list */},
+};
+
+static void prom_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = prom_init1;
+    dc->props = prom_properties;
+}
+
+static const TypeInfo prom_info = {
+    .name          = "openprom",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PROMState),
+    .class_init    = prom_class_init,
+};
+
+typedef struct RamDevice
+{
+    SysBusDevice busdev;
+    MemoryRegion ram;
+    uint64_t size;
+} RamDevice;
+
+/* System RAM */
+static int ram_init1(SysBusDevice *dev)
+{
+    RamDevice *d = FROM_SYSBUS(RamDevice, dev);
+
+    memory_region_init_ram(&d->ram, "sun4m.ram", d->size);
+    vmstate_register_ram_global(&d->ram);
+    sysbus_init_mmio(dev, &d->ram);
+    return 0;
+}
+
+static void ram_init(hwaddr addr, ram_addr_t RAM_size,
+                     uint64_t max_mem)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    RamDevice *d;
+
+    /* allocate RAM */
+    if ((uint64_t)RAM_size > max_mem) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d, maximum %d\n",
+                (unsigned int)(RAM_size / (1024 * 1024)),
+                (unsigned int)(max_mem / (1024 * 1024)));
+        exit(1);
+    }
+    dev = qdev_create(NULL, "memory");
+    s = SYS_BUS_DEVICE(dev);
+
+    d = FROM_SYSBUS(RamDevice, s);
+    d->size = RAM_size;
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+}
+
+static Property ram_properties[] = {
+    DEFINE_PROP_UINT64("size", RamDevice, size, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ram_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ram_init1;
+    dc->props = ram_properties;
+}
+
+static const TypeInfo ram_info = {
+    .name          = "memory",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RamDevice),
+    .class_init    = ram_class_init,
+};
+
+static void cpu_devinit(const char *cpu_model, unsigned int id,
+                        uint64_t prom_addr, qemu_irq **cpu_irqs)
+{
+    SPARCCPU *cpu;
+    CPUSPARCState *env;
+
+    cpu = cpu_sparc_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
+    env = &cpu->env;
+
+    cpu_sparc_set_id(env, id);
+    if (id == 0) {
+        qemu_register_reset(main_cpu_reset, cpu);
+    } else {
+        qemu_register_reset(secondary_cpu_reset, cpu);
+        env->halted = 1;
+    }
+    *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS);
+    env->prom_addr = prom_addr;
+}
+
+static void dummy_fdc_tc(void *opaque, int irq, int level)
+{
+}
+
+static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, 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)
+{
+    unsigned int i;
+    void *iommu, *espdma, *ledma, *nvram;
+    qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS],
+        espdma_irq, ledma_irq;
+    qemu_irq esp_reset, dma_enable;
+    qemu_irq fdc_tc;
+    qemu_irq *cpu_halt;
+    unsigned long kernel_size;
+    DriveInfo *fd[MAX_FD];
+    void *fw_cfg;
+    unsigned int num_vsimms;
+
+    /* init CPUs */
+    if (!cpu_model)
+        cpu_model = hwdef->default_cpu_model;
+
+    for(i = 0; i < smp_cpus; i++) {
+        cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]);
+    }
+
+    for (i = smp_cpus; i < MAX_CPUS; i++)
+        cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS);
+
+
+    /* set up devices */
+    ram_init(0, RAM_size, hwdef->max_mem);
+    /* models without ECC don't trap when missing ram is accessed */
+    if (!hwdef->ecc_base) {
+        empty_slot_init(RAM_size, hwdef->max_mem - RAM_size);
+    }
+
+    prom_init(hwdef->slavio_base, bios_name);
+
+    slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
+                                       hwdef->intctl_base + 0x10000ULL,
+                                       cpu_irqs);
+
+    for (i = 0; i < 32; i++) {
+        slavio_irq[i] = qdev_get_gpio_in(slavio_intctl, i);
+    }
+    for (i = 0; i < MAX_CPUS; i++) {
+        slavio_cpu_irq[i] = qdev_get_gpio_in(slavio_intctl, 32 + i);
+    }
+
+    if (hwdef->idreg_base) {
+        idreg_init(hwdef->idreg_base);
+    }
+
+    if (hwdef->afx_base) {
+        afx_init(hwdef->afx_base);
+    }
+
+    iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version,
+                       slavio_irq[30]);
+
+    if (hwdef->iommu_pad_base) {
+        /* On the real hardware (SS-5, LX) the MMU is not padded, but aliased.
+           Software shouldn't use aliased addresses, neither should it crash
+           when does. Using empty_slot instead of aliasing can help with
+           debugging such accesses */
+        empty_slot_init(hwdef->iommu_pad_base,hwdef->iommu_pad_len);
+    }
+
+    espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[18],
+                              iommu, &espdma_irq, 0);
+
+    ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
+                             slavio_irq[16], iommu, &ledma_irq, 1);
+
+    if (graphic_depth != 8 && graphic_depth != 24) {
+        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+        exit (1);
+    }
+    num_vsimms = 0;
+    if (num_vsimms == 0) {
+        tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+                 graphic_depth);
+    }
+
+    for (i = num_vsimms; i < MAX_VSIMMS; i++) {
+        /* vsimm registers probed by OBP */
+        if (hwdef->vsimm[i].reg_base) {
+            empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000);
+        }
+    }
+
+    if (hwdef->sx_base) {
+        empty_slot_init(hwdef->sx_base, 0x2000);
+    }
+
+    lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
+
+    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 8);
+
+    slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus);
+
+    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[14],
+                              display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
+    /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
+       Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
+    escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15],
+              serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
+
+    cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1);
+    if (hwdef->apc_base) {
+        apc_init(hwdef->apc_base, cpu_halt[0]);
+    }
+
+    if (hwdef->fd_base) {
+        /* there is zero or one floppy drive */
+        memset(fd, 0, sizeof(fd));
+        fd[0] = drive_get(IF_FLOPPY, 0, 0);
+        sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd,
+                          &fdc_tc);
+    } else {
+        fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1);
+    }
+
+    slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base,
+                     slavio_irq[30], fdc_tc);
+
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
+
+    esp_init(hwdef->esp_base, 2,
+             espdma_memory_read, espdma_memory_write,
+             espdma, espdma_irq, &esp_reset, &dma_enable);
+
+    qdev_connect_gpio_out(espdma, 0, esp_reset);
+    qdev_connect_gpio_out(espdma, 1, dma_enable);
+
+    if (hwdef->cs_base) {
+        sysbus_create_simple("SUNW,CS4231", hwdef->cs_base,
+                             slavio_irq[5]);
+    }
+
+    if (hwdef->dbri_base) {
+        /* ISDN chip with attached CS4215 audio codec */
+        /* prom space */
+        empty_slot_init(hwdef->dbri_base+0x1000, 0x30);
+        /* reg space */
+        empty_slot_init(hwdef->dbri_base+0x10000, 0x100);
+    }
+
+    if (hwdef->bpp_base) {
+        /* parallel port */
+        empty_slot_init(hwdef->bpp_base, 0x20);
+    }
+
+    kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
+                                    RAM_size);
+
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+               boot_device, RAM_size, kernel_size, graphic_width,
+               graphic_height, graphic_depth, hwdef->nvram_machine_id,
+               "Sun4m");
+
+    if (hwdef->ecc_base)
+        ecc_init(hwdef->ecc_base, slavio_irq[28],
+                 hwdef->ecc_version);
+
+    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    if (kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+                       strlen(kernel_cmdline) + 1);
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
+    }
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+enum {
+    ss2_id = 0,
+    ss5_id = 32,
+    vger_id,
+    lx_id,
+    ss4_id,
+    scls_id,
+    sbook_id,
+    ss10_id = 64,
+    ss20_id,
+    ss600mp_id,
+    ss1000_id = 96,
+    ss2000_id,
+};
+
+static const struct sun4m_hwdef sun4m_hwdefs[] = {
+    /* SS-5 */
+    {
+        .iommu_base   = 0x10000000,
+        .iommu_pad_base = 0x10004000,
+        .iommu_pad_len  = 0x0fffb000,
+        .tcx_base     = 0x50000000,
+        .cs_base      = 0x6c000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .apc_base     = 0x6a000000,
+        .afx_base     = 0x6e000000,
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = ss5_id,
+        .iommu_version = 0x05000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "Fujitsu MB86904",
+    },
+    /* SS-10 */
+    {
+        .iommu_base   = 0xfe0000000ULL,
+        .tcx_base     = 0xe20000000ULL,
+        .slavio_base  = 0xff0000000ULL,
+        .ms_kb_base   = 0xff1000000ULL,
+        .serial_base  = 0xff1100000ULL,
+        .nvram_base   = 0xff1200000ULL,
+        .fd_base      = 0xff1700000ULL,
+        .counter_base = 0xff1300000ULL,
+        .intctl_base  = 0xff1400000ULL,
+        .idreg_base   = 0xef0000000ULL,
+        .dma_base     = 0xef0400000ULL,
+        .esp_base     = 0xef0800000ULL,
+        .le_base      = 0xef0c00000ULL,
+        .apc_base     = 0xefa000000ULL, // XXX should not exist
+        .aux1_base    = 0xff1800000ULL,
+        .aux2_base    = 0xff1a01000ULL,
+        .ecc_base     = 0xf00000000ULL,
+        .ecc_version  = 0x10000000, // version 0, implementation 1
+        .nvram_machine_id = 0x72,
+        .machine_id = ss10_id,
+        .iommu_version = 0x03000000,
+        .max_mem = 0xf00000000ULL,
+        .default_cpu_model = "TI SuperSparc II",
+    },
+    /* SS-600MP */
+    {
+        .iommu_base   = 0xfe0000000ULL,
+        .tcx_base     = 0xe20000000ULL,
+        .slavio_base  = 0xff0000000ULL,
+        .ms_kb_base   = 0xff1000000ULL,
+        .serial_base  = 0xff1100000ULL,
+        .nvram_base   = 0xff1200000ULL,
+        .counter_base = 0xff1300000ULL,
+        .intctl_base  = 0xff1400000ULL,
+        .dma_base     = 0xef0081000ULL,
+        .esp_base     = 0xef0080000ULL,
+        .le_base      = 0xef0060000ULL,
+        .apc_base     = 0xefa000000ULL, // XXX should not exist
+        .aux1_base    = 0xff1800000ULL,
+        .aux2_base    = 0xff1a01000ULL, // XXX should not exist
+        .ecc_base     = 0xf00000000ULL,
+        .ecc_version  = 0x00000000, // version 0, implementation 0
+        .nvram_machine_id = 0x71,
+        .machine_id = ss600mp_id,
+        .iommu_version = 0x01000000,
+        .max_mem = 0xf00000000ULL,
+        .default_cpu_model = "TI SuperSparc II",
+    },
+    /* SS-20 */
+    {
+        .iommu_base   = 0xfe0000000ULL,
+        .tcx_base     = 0xe20000000ULL,
+        .slavio_base  = 0xff0000000ULL,
+        .ms_kb_base   = 0xff1000000ULL,
+        .serial_base  = 0xff1100000ULL,
+        .nvram_base   = 0xff1200000ULL,
+        .fd_base      = 0xff1700000ULL,
+        .counter_base = 0xff1300000ULL,
+        .intctl_base  = 0xff1400000ULL,
+        .idreg_base   = 0xef0000000ULL,
+        .dma_base     = 0xef0400000ULL,
+        .esp_base     = 0xef0800000ULL,
+        .le_base      = 0xef0c00000ULL,
+        .bpp_base     = 0xef4800000ULL,
+        .apc_base     = 0xefa000000ULL, // XXX should not exist
+        .aux1_base    = 0xff1800000ULL,
+        .aux2_base    = 0xff1a01000ULL,
+        .dbri_base    = 0xee0000000ULL,
+        .sx_base      = 0xf80000000ULL,
+        .vsimm        = {
+            {
+                .reg_base  = 0x9c000000ULL,
+                .vram_base = 0xfc000000ULL
+            }, {
+                .reg_base  = 0x90000000ULL,
+                .vram_base = 0xf0000000ULL
+            }, {
+                .reg_base  = 0x94000000ULL
+            }, {
+                .reg_base  = 0x98000000ULL
+            }
+        },
+        .ecc_base     = 0xf00000000ULL,
+        .ecc_version  = 0x20000000, // version 0, implementation 2
+        .nvram_machine_id = 0x72,
+        .machine_id = ss20_id,
+        .iommu_version = 0x13000000,
+        .max_mem = 0xf00000000ULL,
+        .default_cpu_model = "TI SuperSparc II",
+    },
+    /* Voyager */
+    {
+        .iommu_base   = 0x10000000,
+        .tcx_base     = 0x50000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .apc_base     = 0x71300000, // pmc
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = vger_id,
+        .iommu_version = 0x05000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "Fujitsu MB86904",
+    },
+    /* LX */
+    {
+        .iommu_base   = 0x10000000,
+        .iommu_pad_base = 0x10004000,
+        .iommu_pad_len  = 0x0fffb000,
+        .tcx_base     = 0x50000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = lx_id,
+        .iommu_version = 0x04000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "TI MicroSparc I",
+    },
+    /* SS-4 */
+    {
+        .iommu_base   = 0x10000000,
+        .tcx_base     = 0x50000000,
+        .cs_base      = 0x6c000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .apc_base     = 0x6a000000,
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = ss4_id,
+        .iommu_version = 0x05000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "Fujitsu MB86904",
+    },
+    /* SPARCClassic */
+    {
+        .iommu_base   = 0x10000000,
+        .tcx_base     = 0x50000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .apc_base     = 0x6a000000,
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = scls_id,
+        .iommu_version = 0x05000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "TI MicroSparc I",
+    },
+    /* SPARCbook */
+    {
+        .iommu_base   = 0x10000000,
+        .tcx_base     = 0x50000000, // XXX
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .apc_base     = 0x6a000000,
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = sbook_id,
+        .iommu_version = 0x05000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "TI MicroSparc I",
+    },
+};
+
+/* SPARCstation 5 hardware initialisation */
+static void ss5_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4m_hw_init(&sun4m_hwdefs[0], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCstation 10 hardware initialisation */
+static void ss10_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4m_hw_init(&sun4m_hwdefs[1], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCserver 600MP hardware initialisation */
+static void ss600mp_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4m_hw_init(&sun4m_hwdefs[2], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCstation 20 hardware initialisation */
+static void ss20_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4m_hw_init(&sun4m_hwdefs[3], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCstation Voyager hardware initialisation */
+static void vger_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4m_hw_init(&sun4m_hwdefs[4], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCstation LX hardware initialisation */
+static void ss_lx_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4m_hw_init(&sun4m_hwdefs[5], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCstation 4 hardware initialisation */
+static void ss4_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4m_hw_init(&sun4m_hwdefs[6], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCClassic hardware initialisation */
+static void scls_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4m_hw_init(&sun4m_hwdefs[7], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCbook hardware initialisation */
+static void sbook_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4m_hw_init(&sun4m_hwdefs[8], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+static QEMUMachine ss5_machine = {
+    .name = "SS-5",
+    .desc = "Sun4m platform, SPARCstation 5",
+    .init = ss5_init,
+    .block_default_type = IF_SCSI,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine ss10_machine = {
+    .name = "SS-10",
+    .desc = "Sun4m platform, SPARCstation 10",
+    .init = ss10_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine ss600mp_machine = {
+    .name = "SS-600MP",
+    .desc = "Sun4m platform, SPARCserver 600MP",
+    .init = ss600mp_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine ss20_machine = {
+    .name = "SS-20",
+    .desc = "Sun4m platform, SPARCstation 20",
+    .init = ss20_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine voyager_machine = {
+    .name = "Voyager",
+    .desc = "Sun4m platform, SPARCstation Voyager",
+    .init = vger_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine ss_lx_machine = {
+    .name = "LX",
+    .desc = "Sun4m platform, SPARCstation LX",
+    .init = ss_lx_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine ss4_machine = {
+    .name = "SS-4",
+    .desc = "Sun4m platform, SPARCstation 4",
+    .init = ss4_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine scls_machine = {
+    .name = "SPARCClassic",
+    .desc = "Sun4m platform, SPARCClassic",
+    .init = scls_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine sbook_machine = {
+    .name = "SPARCbook",
+    .desc = "Sun4m platform, SPARCbook",
+    .init = sbook_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static const struct sun4d_hwdef sun4d_hwdefs[] = {
+    /* SS-1000 */
+    {
+        .iounit_bases   = {
+            0xfe0200000ULL,
+            0xfe1200000ULL,
+            0xfe2200000ULL,
+            0xfe3200000ULL,
+            -1,
+        },
+        .tcx_base     = 0x820000000ULL,
+        .slavio_base  = 0xf00000000ULL,
+        .ms_kb_base   = 0xf00240000ULL,
+        .serial_base  = 0xf00200000ULL,
+        .nvram_base   = 0xf00280000ULL,
+        .counter_base = 0xf00300000ULL,
+        .espdma_base  = 0x800081000ULL,
+        .esp_base     = 0x800080000ULL,
+        .ledma_base   = 0x800040000ULL,
+        .le_base      = 0x800060000ULL,
+        .sbi_base     = 0xf02800000ULL,
+        .nvram_machine_id = 0x80,
+        .machine_id = ss1000_id,
+        .iounit_version = 0x03000000,
+        .max_mem = 0xf00000000ULL,
+        .default_cpu_model = "TI SuperSparc II",
+    },
+    /* SS-2000 */
+    {
+        .iounit_bases   = {
+            0xfe0200000ULL,
+            0xfe1200000ULL,
+            0xfe2200000ULL,
+            0xfe3200000ULL,
+            0xfe4200000ULL,
+        },
+        .tcx_base     = 0x820000000ULL,
+        .slavio_base  = 0xf00000000ULL,
+        .ms_kb_base   = 0xf00240000ULL,
+        .serial_base  = 0xf00200000ULL,
+        .nvram_base   = 0xf00280000ULL,
+        .counter_base = 0xf00300000ULL,
+        .espdma_base  = 0x800081000ULL,
+        .esp_base     = 0x800080000ULL,
+        .ledma_base   = 0x800040000ULL,
+        .le_base      = 0x800060000ULL,
+        .sbi_base     = 0xf02800000ULL,
+        .nvram_machine_id = 0x80,
+        .machine_id = ss2000_id,
+        .iounit_version = 0x03000000,
+        .max_mem = 0xf00000000ULL,
+        .default_cpu_model = "TI SuperSparc II",
+    },
+};
+
+static DeviceState *sbi_init(hwaddr addr, qemu_irq **parent_irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    unsigned int i;
+
+    dev = qdev_create(NULL, "sbi");
+    qdev_init_nofail(dev);
+
+    s = SYS_BUS_DEVICE(dev);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        sysbus_connect_irq(s, i, *parent_irq[i]);
+    }
+
+    sysbus_mmio_map(s, 0, addr);
+
+    return dev;
+}
+
+static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, 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)
+{
+    unsigned int i;
+    void *iounits[MAX_IOUNITS], *espdma, *ledma, *nvram;
+    qemu_irq *cpu_irqs[MAX_CPUS], sbi_irq[32], sbi_cpu_irq[MAX_CPUS],
+        espdma_irq, ledma_irq;
+    qemu_irq esp_reset, dma_enable;
+    unsigned long kernel_size;
+    void *fw_cfg;
+    DeviceState *dev;
+
+    /* init CPUs */
+    if (!cpu_model)
+        cpu_model = hwdef->default_cpu_model;
+
+    for(i = 0; i < smp_cpus; i++) {
+        cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]);
+    }
+
+    for (i = smp_cpus; i < MAX_CPUS; i++)
+        cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS);
+
+    /* set up devices */
+    ram_init(0, RAM_size, hwdef->max_mem);
+
+    prom_init(hwdef->slavio_base, bios_name);
+
+    dev = sbi_init(hwdef->sbi_base, cpu_irqs);
+
+    for (i = 0; i < 32; i++) {
+        sbi_irq[i] = qdev_get_gpio_in(dev, i);
+    }
+    for (i = 0; i < MAX_CPUS; i++) {
+        sbi_cpu_irq[i] = qdev_get_gpio_in(dev, 32 + i);
+    }
+
+    for (i = 0; i < MAX_IOUNITS; i++)
+        if (hwdef->iounit_bases[i] != (hwaddr)-1)
+            iounits[i] = iommu_init(hwdef->iounit_bases[i],
+                                    hwdef->iounit_version,
+                                    sbi_irq[0]);
+
+    espdma = sparc32_dma_init(hwdef->espdma_base, sbi_irq[3],
+                              iounits[0], &espdma_irq, 0);
+
+    /* should be lebuffer instead */
+    ledma = sparc32_dma_init(hwdef->ledma_base, sbi_irq[4],
+                             iounits[0], &ledma_irq, 0);
+
+    if (graphic_depth != 8 && graphic_depth != 24) {
+        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+        exit (1);
+    }
+    tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+             graphic_depth);
+
+    lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
+
+    nvram = m48t59_init(sbi_irq[0], hwdef->nvram_base, 0, 0x2000, 8);
+
+    slavio_timer_init_all(hwdef->counter_base, sbi_irq[10], sbi_cpu_irq, smp_cpus);
+
+    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, sbi_irq[12],
+                              display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
+    /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
+       Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
+    escc_init(hwdef->serial_base, sbi_irq[12], sbi_irq[12],
+              serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
+
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
+
+    esp_init(hwdef->esp_base, 2,
+             espdma_memory_read, espdma_memory_write,
+             espdma, espdma_irq, &esp_reset, &dma_enable);
+
+    qdev_connect_gpio_out(espdma, 0, esp_reset);
+    qdev_connect_gpio_out(espdma, 1, dma_enable);
+
+    kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
+                                    RAM_size);
+
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+               boot_device, RAM_size, kernel_size, graphic_width,
+               graphic_height, graphic_depth, hwdef->nvram_machine_id,
+               "Sun4d");
+
+    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    if (kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+    }
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+/* SPARCserver 1000 hardware initialisation */
+static void ss1000_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4d_hw_init(&sun4d_hwdefs[0], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCcenter 2000 hardware initialisation */
+static void ss2000_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4d_hw_init(&sun4d_hwdefs[1], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+static QEMUMachine ss1000_machine = {
+    .name = "SS-1000",
+    .desc = "Sun4d platform, SPARCserver 1000",
+    .init = ss1000_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 8,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine ss2000_machine = {
+    .name = "SS-2000",
+    .desc = "Sun4d platform, SPARCcenter 2000",
+    .init = ss2000_init,
+    .block_default_type = IF_SCSI,
+    .max_cpus = 20,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static const struct sun4c_hwdef sun4c_hwdefs[] = {
+    /* SS-2 */
+    {
+        .iommu_base   = 0xf8000000,
+        .tcx_base     = 0xfe000000,
+        .slavio_base  = 0xf6000000,
+        .intctl_base  = 0xf5000000,
+        .counter_base = 0xf3000000,
+        .ms_kb_base   = 0xf0000000,
+        .serial_base  = 0xf1000000,
+        .nvram_base   = 0xf2000000,
+        .fd_base      = 0xf7200000,
+        .dma_base     = 0xf8400000,
+        .esp_base     = 0xf8800000,
+        .le_base      = 0xf8c00000,
+        .aux1_base    = 0xf7400003,
+        .nvram_machine_id = 0x55,
+        .machine_id = ss2_id,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "Cypress CY7C601",
+    },
+};
+
+static DeviceState *sun4c_intctl_init(hwaddr addr,
+                                      qemu_irq *parent_irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    unsigned int i;
+
+    dev = qdev_create(NULL, "sun4c_intctl");
+    qdev_init_nofail(dev);
+
+    s = SYS_BUS_DEVICE(dev);
+
+    for (i = 0; i < MAX_PILS; i++) {
+        sysbus_connect_irq(s, i, parent_irq[i]);
+    }
+    sysbus_mmio_map(s, 0, addr);
+
+    return dev;
+}
+
+static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, 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)
+{
+    void *iommu, *espdma, *ledma, *nvram;
+    qemu_irq *cpu_irqs, slavio_irq[8], espdma_irq, ledma_irq;
+    qemu_irq esp_reset, dma_enable;
+    qemu_irq fdc_tc;
+    unsigned long kernel_size;
+    DriveInfo *fd[MAX_FD];
+    void *fw_cfg;
+    DeviceState *dev;
+    unsigned int i;
+
+    /* init CPU */
+    if (!cpu_model)
+        cpu_model = hwdef->default_cpu_model;
+
+    cpu_devinit(cpu_model, 0, hwdef->slavio_base, &cpu_irqs);
+
+    /* set up devices */
+    ram_init(0, RAM_size, hwdef->max_mem);
+
+    prom_init(hwdef->slavio_base, bios_name);
+
+    dev = sun4c_intctl_init(hwdef->intctl_base, cpu_irqs);
+
+    for (i = 0; i < 8; i++) {
+        slavio_irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version,
+                       slavio_irq[1]);
+
+    espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[2],
+                              iommu, &espdma_irq, 0);
+
+    ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
+                             slavio_irq[3], iommu, &ledma_irq, 1);
+
+    if (graphic_depth != 8 && graphic_depth != 24) {
+        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+        exit (1);
+    }
+    tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+             graphic_depth);
+
+    lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
+
+    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x800, 2);
+
+    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[1],
+                              display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
+    /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
+       Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
+    escc_init(hwdef->serial_base, slavio_irq[1],
+              slavio_irq[1], serial_hds[0], serial_hds[1],
+              ESCC_CLOCK, 1);
+
+    if (hwdef->fd_base != (hwaddr)-1) {
+        /* there is zero or one floppy drive */
+        memset(fd, 0, sizeof(fd));
+        fd[0] = drive_get(IF_FLOPPY, 0, 0);
+        sun4m_fdctrl_init(slavio_irq[1], hwdef->fd_base, fd,
+                          &fdc_tc);
+    } else {
+        fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1);
+    }
+
+    slavio_misc_init(0, hwdef->aux1_base, 0, slavio_irq[1], fdc_tc);
+
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
+
+    esp_init(hwdef->esp_base, 2,
+             espdma_memory_read, espdma_memory_write,
+             espdma, espdma_irq, &esp_reset, &dma_enable);
+
+    qdev_connect_gpio_out(espdma, 0, esp_reset);
+    qdev_connect_gpio_out(espdma, 1, dma_enable);
+
+    kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
+                                    RAM_size);
+
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+               boot_device, RAM_size, kernel_size, graphic_width,
+               graphic_height, graphic_depth, hwdef->nvram_machine_id,
+               "Sun4c");
+
+    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    if (kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+    }
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+/* SPARCstation 2 hardware initialisation */
+static void ss2_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_device = args->boot_device;
+    sun4c_hw_init(&sun4c_hwdefs[0], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+static QEMUMachine ss2_machine = {
+    .name = "SS-2",
+    .desc = "Sun4c platform, SPARCstation 2",
+    .init = ss2_init,
+    .block_default_type = IF_SCSI,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void sun4m_register_types(void)
+{
+    type_register_static(&idreg_info);
+    type_register_static(&afx_info);
+    type_register_static(&prom_info);
+    type_register_static(&ram_info);
+}
+
+static void ss2_machine_init(void)
+{
+    qemu_register_machine(&ss5_machine);
+    qemu_register_machine(&ss10_machine);
+    qemu_register_machine(&ss600mp_machine);
+    qemu_register_machine(&ss20_machine);
+    qemu_register_machine(&voyager_machine);
+    qemu_register_machine(&ss_lx_machine);
+    qemu_register_machine(&ss4_machine);
+    qemu_register_machine(&scls_machine);
+    qemu_register_machine(&sbook_machine);
+    qemu_register_machine(&ss1000_machine);
+    qemu_register_machine(&ss2000_machine);
+    qemu_register_machine(&ss2_machine);
+}
+
+type_init(sun4m_register_types)
+machine_init(ss2_machine_init);
index 8c65fc4215484f31f52a4afeeacd160b9eb8675b..4df0d90ec24cdacc3a294751839bd39c7909dbe6 100644 (file)
@@ -1,4 +1,6 @@
-obj-y = sun4u.o apb_pci.o
+obj-y = apb_pci.o
 obj-y += mc146818rtc.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-y += sun4u.o
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
new file mode 100644 (file)
index 0000000..51ffa1c
--- /dev/null
@@ -0,0 +1,1014 @@
+/*
+ * QEMU Sun4u/Sun4v System Emulator
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hw/apb_pci.h"
+#include "hw/pc.h"
+#include "hw/serial.h"
+#include "hw/nvram.h"
+#include "hw/fdc.h"
+#include "net/net.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/firmware_abi.h"
+#include "hw/fw_cfg.h"
+#include "hw/sysbus.h"
+#include "hw/ide.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG_IRQ
+//#define DEBUG_EBUS
+//#define DEBUG_TIMER
+
+#ifdef DEBUG_IRQ
+#define CPUIRQ_DPRINTF(fmt, ...)                                \
+    do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define CPUIRQ_DPRINTF(fmt, ...)
+#endif
+
+#ifdef DEBUG_EBUS
+#define EBUS_DPRINTF(fmt, ...)                                  \
+    do { printf("EBUS: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define EBUS_DPRINTF(fmt, ...)
+#endif
+
+#ifdef DEBUG_TIMER
+#define TIMER_DPRINTF(fmt, ...)                                  \
+    do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define TIMER_DPRINTF(fmt, ...)
+#endif
+
+#define KERNEL_LOAD_ADDR     0x00404000
+#define CMDLINE_ADDR         0x003ff000
+#define PROM_SIZE_MAX        (4 * 1024 * 1024)
+#define PROM_VADDR           0x000ffd00000ULL
+#define APB_SPECIAL_BASE     0x1fe00000000ULL
+#define APB_MEM_BASE         0x1ff00000000ULL
+#define APB_PCI_IO_BASE      (APB_SPECIAL_BASE + 0x02000000ULL)
+#define PROM_FILENAME        "openbios-sparc64"
+#define NVRAM_SIZE           0x2000
+#define MAX_IDE_BUS          2
+#define BIOS_CFG_IOPORT      0x510
+#define FW_CFG_SPARC64_WIDTH (FW_CFG_ARCH_LOCAL + 0x00)
+#define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
+#define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
+
+#define IVEC_MAX             0x30
+
+#define TICK_MAX             0x7fffffffffffffffULL
+
+struct hwdef {
+    const char * const default_cpu_model;
+    uint16_t machine_id;
+    uint64_t prom_addr;
+    uint64_t console_serial_base;
+};
+
+typedef struct EbusState {
+    PCIDevice pci_dev;
+    MemoryRegion bar0;
+    MemoryRegion bar1;
+} EbusState;
+
+int DMA_get_channel_mode (int nchan)
+{
+    return 0;
+}
+int DMA_read_memory (int nchan, void *buf, int pos, int size)
+{
+    return 0;
+}
+int DMA_write_memory (int nchan, void *buf, int pos, int size)
+{
+    return 0;
+}
+void DMA_hold_DREQ (int nchan) {}
+void DMA_release_DREQ (int nchan) {}
+void DMA_schedule(int nchan) {}
+
+void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit)
+{
+}
+
+void DMA_register_channel (int nchan,
+                           DMA_transfer_handler transfer_handler,
+                           void *opaque)
+{
+}
+
+static int fw_cfg_boot_set(void *opaque, const char *boot_device)
+{
+    fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    return 0;
+}
+
+static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size,
+                                  const char *arch, ram_addr_t RAM_size,
+                                  const char *boot_devices,
+                                  uint32_t kernel_image, uint32_t kernel_size,
+                                  const char *cmdline,
+                                  uint32_t initrd_image, uint32_t initrd_size,
+                                  uint32_t NVRAM_image,
+                                  int width, int height, int depth,
+                                  const uint8_t *macaddr)
+{
+    unsigned int i;
+    uint32_t start, end;
+    uint8_t image[0x1ff0];
+    struct OpenBIOS_nvpart_v1 *part_header;
+
+    memset(image, '\0', sizeof(image));
+
+    start = 0;
+
+    // OpenBIOS nvram variables
+    // Variable partition
+    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
+    part_header->signature = OPENBIOS_PART_SYSTEM;
+    pstrcpy(part_header->name, sizeof(part_header->name), "system");
+
+    end = start + sizeof(struct OpenBIOS_nvpart_v1);
+    for (i = 0; i < nb_prom_envs; i++)
+        end = OpenBIOS_set_var(image, end, prom_envs[i]);
+
+    // End marker
+    image[end++] = '\0';
+
+    end = start + ((end - start + 15) & ~15);
+    OpenBIOS_finish_partition(part_header, end - start);
+
+    // free partition
+    start = end;
+    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
+    part_header->signature = OPENBIOS_PART_FREE;
+    pstrcpy(part_header->name, sizeof(part_header->name), "free");
+
+    end = 0x1fd0;
+    OpenBIOS_finish_partition(part_header, end - start);
+
+    Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80);
+
+    for (i = 0; i < sizeof(image); i++)
+        m48t59_write(nvram, i, image[i]);
+
+    return 0;
+}
+
+static uint64_t sun4u_load_kernel(const char *kernel_filename,
+                                  const char *initrd_filename,
+                                  ram_addr_t RAM_size, uint64_t *initrd_size,
+                                  uint64_t *initrd_addr, uint64_t *kernel_addr,
+                                  uint64_t *kernel_entry)
+{
+    int linux_boot;
+    unsigned int i;
+    long kernel_size;
+    uint8_t *ptr;
+    uint64_t kernel_top;
+
+    linux_boot = (kernel_filename != NULL);
+
+    kernel_size = 0;
+    if (linux_boot) {
+        int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+        bswap_needed = 1;
+#else
+        bswap_needed = 0;
+#endif
+        kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry,
+                               kernel_addr, &kernel_top, 1, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            *kernel_addr = KERNEL_LOAD_ADDR;
+            *kernel_entry = KERNEL_LOAD_ADDR;
+            kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
+                                    RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+                                    TARGET_PAGE_SIZE);
+        }
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              RAM_size - KERNEL_LOAD_ADDR);
+        }
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        /* load initrd above kernel */
+        *initrd_size = 0;
+        if (initrd_filename) {
+            *initrd_addr = TARGET_PAGE_ALIGN(kernel_top);
+
+            *initrd_size = load_image_targphys(initrd_filename,
+                                               *initrd_addr,
+                                               RAM_size - *initrd_addr);
+            if ((int)*initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        }
+        if (*initrd_size > 0) {
+            for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
+                ptr = rom_ptr(*kernel_addr + i);
+                if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
+                    stl_p(ptr + 24, *initrd_addr + *kernel_addr);
+                    stl_p(ptr + 28, *initrd_size);
+                    break;
+                }
+            }
+        }
+    }
+    return kernel_size;
+}
+
+void cpu_check_irqs(CPUSPARCState *env)
+{
+    uint32_t pil = env->pil_in |
+                  (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER));
+
+    /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */
+    if (env->ivec_status & 0x20) {
+        return;
+    }
+    /* check if TM or SM in SOFTINT are set
+       setting these also causes interrupt 14 */
+    if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) {
+        pil |= 1 << 14;
+    }
+
+    /* The bit corresponding to psrpil is (1<< psrpil), the next bit
+       is (2 << psrpil). */
+    if (pil < (2 << env->psrpil)){
+        if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+            CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
+                           env->interrupt_index);
+            env->interrupt_index = 0;
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        }
+        return;
+    }
+
+    if (cpu_interrupts_enabled(env)) {
+
+        unsigned int i;
+
+        for (i = 15; i > env->psrpil; i--) {
+            if (pil & (1 << i)) {
+                int old_interrupt = env->interrupt_index;
+                int new_interrupt = TT_EXTINT | i;
+
+                if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt
+                  && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) {
+                    CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d "
+                                   "current %x >= pending %x\n",
+                                   env->tl, cpu_tsptr(env)->tt, new_interrupt);
+                } else if (old_interrupt != new_interrupt) {
+                    env->interrupt_index = new_interrupt;
+                    CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i,
+                                   old_interrupt, new_interrupt);
+                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                }
+                break;
+            }
+        }
+    } else if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+        CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
+                       "current interrupt %x\n",
+                       pil, env->pil_in, env->softint, env->interrupt_index);
+        env->interrupt_index = 0;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void cpu_kick_irq(SPARCCPU *cpu)
+{
+    CPUSPARCState *env = &cpu->env;
+
+    env->halted = 0;
+    cpu_check_irqs(env);
+    qemu_cpu_kick(CPU(cpu));
+}
+
+static void cpu_set_ivec_irq(void *opaque, int irq, int level)
+{
+    SPARCCPU *cpu = opaque;
+    CPUSPARCState *env = &cpu->env;
+
+    if (level) {
+        if (!(env->ivec_status & 0x20)) {
+            CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
+            env->halted = 0;
+            env->interrupt_index = TT_IVEC;
+            env->ivec_status |= 0x20;
+            env->ivec_data[0] = (0x1f << 6) | irq;
+            env->ivec_data[1] = 0;
+            env->ivec_data[2] = 0;
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        }
+    } else {
+        if (env->ivec_status & 0x20) {
+            CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
+            env->ivec_status &= ~0x20;
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        }
+    }
+}
+
+typedef struct ResetData {
+    SPARCCPU *cpu;
+    uint64_t prom_addr;
+} ResetData;
+
+void cpu_put_timer(QEMUFile *f, CPUTimer *s)
+{
+    qemu_put_be32s(f, &s->frequency);
+    qemu_put_be32s(f, &s->disabled);
+    qemu_put_be64s(f, &s->disabled_mask);
+    qemu_put_sbe64s(f, &s->clock_offset);
+
+    qemu_put_timer(f, s->qtimer);
+}
+
+void cpu_get_timer(QEMUFile *f, CPUTimer *s)
+{
+    qemu_get_be32s(f, &s->frequency);
+    qemu_get_be32s(f, &s->disabled);
+    qemu_get_be64s(f, &s->disabled_mask);
+    qemu_get_sbe64s(f, &s->clock_offset);
+
+    qemu_get_timer(f, s->qtimer);
+}
+
+static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu,
+                                  QEMUBHFunc *cb, uint32_t frequency,
+                                  uint64_t disabled_mask)
+{
+    CPUTimer *timer = g_malloc0(sizeof (CPUTimer));
+
+    timer->name = name;
+    timer->frequency = frequency;
+    timer->disabled_mask = disabled_mask;
+
+    timer->disabled = 1;
+    timer->clock_offset = qemu_get_clock_ns(vm_clock);
+
+    timer->qtimer = qemu_new_timer_ns(vm_clock, cb, cpu);
+
+    return timer;
+}
+
+static void cpu_timer_reset(CPUTimer *timer)
+{
+    timer->disabled = 1;
+    timer->clock_offset = qemu_get_clock_ns(vm_clock);
+
+    qemu_del_timer(timer->qtimer);
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *)opaque;
+    CPUSPARCState *env = &s->cpu->env;
+    static unsigned int nr_resets;
+
+    cpu_reset(CPU(s->cpu));
+
+    cpu_timer_reset(env->tick);
+    cpu_timer_reset(env->stick);
+    cpu_timer_reset(env->hstick);
+
+    env->gregs[1] = 0; // Memory start
+    env->gregs[2] = ram_size; // Memory size
+    env->gregs[3] = 0; // Machine description XXX
+    if (nr_resets++ == 0) {
+        /* Power on reset */
+        env->pc = s->prom_addr + 0x20ULL;
+    } else {
+        env->pc = s->prom_addr + 0x40ULL;
+    }
+    env->npc = env->pc + 4;
+}
+
+static void tick_irq(void *opaque)
+{
+    SPARCCPU *cpu = opaque;
+    CPUSPARCState *env = &cpu->env;
+
+    CPUTimer* timer = env->tick;
+
+    if (timer->disabled) {
+        CPUIRQ_DPRINTF("tick_irq: softint disabled\n");
+        return;
+    } else {
+        CPUIRQ_DPRINTF("tick: fire\n");
+    }
+
+    env->softint |= SOFTINT_TIMER;
+    cpu_kick_irq(cpu);
+}
+
+static void stick_irq(void *opaque)
+{
+    SPARCCPU *cpu = opaque;
+    CPUSPARCState *env = &cpu->env;
+
+    CPUTimer* timer = env->stick;
+
+    if (timer->disabled) {
+        CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
+        return;
+    } else {
+        CPUIRQ_DPRINTF("stick: fire\n");
+    }
+
+    env->softint |= SOFTINT_STIMER;
+    cpu_kick_irq(cpu);
+}
+
+static void hstick_irq(void *opaque)
+{
+    SPARCCPU *cpu = opaque;
+    CPUSPARCState *env = &cpu->env;
+
+    CPUTimer* timer = env->hstick;
+
+    if (timer->disabled) {
+        CPUIRQ_DPRINTF("hstick_irq: softint disabled\n");
+        return;
+    } else {
+        CPUIRQ_DPRINTF("hstick: fire\n");
+    }
+
+    env->softint |= SOFTINT_STIMER;
+    cpu_kick_irq(cpu);
+}
+
+static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
+{
+    return muldiv64(cpu_ticks, get_ticks_per_sec(), frequency);
+}
+
+static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
+{
+    return muldiv64(timer_ticks, frequency, get_ticks_per_sec());
+}
+
+void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
+{
+    uint64_t real_count = count & ~timer->disabled_mask;
+    uint64_t disabled_bit = count & timer->disabled_mask;
+
+    int64_t vm_clock_offset = qemu_get_clock_ns(vm_clock) -
+                    cpu_to_timer_ticks(real_count, timer->frequency);
+
+    TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n",
+                  timer->name, real_count,
+                  timer->disabled?"disabled":"enabled", timer);
+
+    timer->disabled = disabled_bit ? 1 : 0;
+    timer->clock_offset = vm_clock_offset;
+}
+
+uint64_t cpu_tick_get_count(CPUTimer *timer)
+{
+    uint64_t real_count = timer_to_cpu_ticks(
+                    qemu_get_clock_ns(vm_clock) - timer->clock_offset,
+                    timer->frequency);
+
+    TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n",
+           timer->name, real_count,
+           timer->disabled?"disabled":"enabled", timer);
+
+    if (timer->disabled)
+        real_count |= timer->disabled_mask;
+
+    return real_count;
+}
+
+void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
+{
+    int64_t now = qemu_get_clock_ns(vm_clock);
+
+    uint64_t real_limit = limit & ~timer->disabled_mask;
+    timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
+
+    int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
+                    timer->clock_offset;
+
+    if (expires < now) {
+        expires = now + 1;
+    }
+
+    TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p "
+                  "called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n",
+                  timer->name, real_limit,
+                  timer->disabled?"disabled":"enabled",
+                  timer, limit,
+                  timer_to_cpu_ticks(now - timer->clock_offset,
+                                     timer->frequency),
+                  timer_to_cpu_ticks(expires - now, timer->frequency));
+
+    if (!real_limit) {
+        TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n",
+                timer->name);
+        qemu_del_timer(timer->qtimer);
+    } else if (timer->disabled) {
+        qemu_del_timer(timer->qtimer);
+    } else {
+        qemu_mod_timer(timer->qtimer, expires);
+    }
+}
+
+static void isa_irq_handler(void *opaque, int n, int level)
+{
+    static const int isa_irq_to_ivec[16] = {
+        [1] = 0x29, /* keyboard */
+        [4] = 0x2b, /* serial */
+        [6] = 0x27, /* floppy */
+        [7] = 0x22, /* parallel */
+        [12] = 0x2a, /* mouse */
+    };
+    qemu_irq *irqs = opaque;
+    int ivec;
+
+    assert(n < 16);
+    ivec = isa_irq_to_ivec[n];
+    EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec);
+    if (ivec) {
+        qemu_set_irq(irqs[ivec], level);
+    }
+}
+
+/* EBUS (Eight bit bus) bridge */
+static ISABus *
+pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs)
+{
+    qemu_irq *isa_irq;
+    PCIDevice *pci_dev;
+    ISABus *isa_bus;
+
+    pci_dev = pci_create_simple(bus, devfn, "ebus");
+    isa_bus = DO_UPCAST(ISABus, qbus,
+                        qdev_get_child_bus(&pci_dev->qdev, "isa.0"));
+    isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
+    isa_bus_irqs(isa_bus, isa_irq);
+    return isa_bus;
+}
+
+static int
+pci_ebus_init1(PCIDevice *pci_dev)
+{
+    EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev);
+
+    isa_bus_new(&pci_dev->qdev, pci_address_space_io(pci_dev));
+
+    pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
+    pci_dev->config[0x05] = 0x00;
+    pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
+    pci_dev->config[0x07] = 0x03; // status = medium devsel
+    pci_dev->config[0x09] = 0x00; // programming i/f
+    pci_dev->config[0x0D] = 0x0a; // latency_timer
+
+    isa_mmio_setup(&s->bar0, 0x1000000);
+    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
+    isa_mmio_setup(&s->bar1, 0x800000);
+    pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1);
+    return 0;
+}
+
+static void ebus_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_ebus_init1;
+    k->vendor_id = PCI_VENDOR_ID_SUN;
+    k->device_id = PCI_DEVICE_ID_SUN_EBUS;
+    k->revision = 0x01;
+    k->class_id = PCI_CLASS_BRIDGE_OTHER;
+}
+
+static const TypeInfo ebus_info = {
+    .name          = "ebus",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(EbusState),
+    .class_init    = ebus_class_init,
+};
+
+typedef struct PROMState {
+    SysBusDevice busdev;
+    MemoryRegion prom;
+} PROMState;
+
+static uint64_t translate_prom_address(void *opaque, uint64_t addr)
+{
+    hwaddr *base_addr = (hwaddr *)opaque;
+    return addr + *base_addr - PROM_VADDR;
+}
+
+/* Boot PROM (OpenBIOS) */
+static void prom_init(hwaddr addr, const char *bios_name)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    char *filename;
+    int ret;
+
+    dev = qdev_create(NULL, "openprom");
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+
+    /* load boot prom */
+    if (bios_name == NULL) {
+        bios_name = PROM_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        ret = load_elf(filename, translate_prom_address, &addr,
+                       NULL, NULL, NULL, 1, ELF_MACHINE, 0);
+        if (ret < 0 || ret > PROM_SIZE_MAX) {
+            ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
+        }
+        g_free(filename);
+    } else {
+        ret = -1;
+    }
+    if (ret < 0 || ret > PROM_SIZE_MAX) {
+        fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name);
+        exit(1);
+    }
+}
+
+static int prom_init1(SysBusDevice *dev)
+{
+    PROMState *s = FROM_SYSBUS(PROMState, dev);
+
+    memory_region_init_ram(&s->prom, "sun4u.prom", PROM_SIZE_MAX);
+    vmstate_register_ram_global(&s->prom);
+    memory_region_set_readonly(&s->prom, true);
+    sysbus_init_mmio(dev, &s->prom);
+    return 0;
+}
+
+static Property prom_properties[] = {
+    {/* end of property list */},
+};
+
+static void prom_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = prom_init1;
+    dc->props = prom_properties;
+}
+
+static const TypeInfo prom_info = {
+    .name          = "openprom",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PROMState),
+    .class_init    = prom_class_init,
+};
+
+
+typedef struct RamDevice
+{
+    SysBusDevice busdev;
+    MemoryRegion ram;
+    uint64_t size;
+} RamDevice;
+
+/* System RAM */
+static int ram_init1(SysBusDevice *dev)
+{
+    RamDevice *d = FROM_SYSBUS(RamDevice, dev);
+
+    memory_region_init_ram(&d->ram, "sun4u.ram", d->size);
+    vmstate_register_ram_global(&d->ram);
+    sysbus_init_mmio(dev, &d->ram);
+    return 0;
+}
+
+static void ram_init(hwaddr addr, ram_addr_t RAM_size)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    RamDevice *d;
+
+    /* allocate RAM */
+    dev = qdev_create(NULL, "memory");
+    s = SYS_BUS_DEVICE(dev);
+
+    d = FROM_SYSBUS(RamDevice, s);
+    d->size = RAM_size;
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+}
+
+static Property ram_properties[] = {
+    DEFINE_PROP_UINT64("size", RamDevice, size, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ram_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ram_init1;
+    dc->props = ram_properties;
+}
+
+static const TypeInfo ram_info = {
+    .name          = "memory",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RamDevice),
+    .class_init    = ram_class_init,
+};
+
+static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
+{
+    SPARCCPU *cpu;
+    CPUSPARCState *env;
+    ResetData *reset_info;
+
+    uint32_t   tick_frequency = 100*1000000;
+    uint32_t  stick_frequency = 100*1000000;
+    uint32_t hstick_frequency = 100*1000000;
+
+    if (cpu_model == NULL) {
+        cpu_model = hwdef->default_cpu_model;
+    }
+    cpu = cpu_sparc_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
+    env = &cpu->env;
+
+    env->tick = cpu_timer_create("tick", cpu, tick_irq,
+                                  tick_frequency, TICK_NPT_MASK);
+
+    env->stick = cpu_timer_create("stick", cpu, stick_irq,
+                                   stick_frequency, TICK_INT_DIS);
+
+    env->hstick = cpu_timer_create("hstick", cpu, hstick_irq,
+                                    hstick_frequency, TICK_INT_DIS);
+
+    reset_info = g_malloc0(sizeof(ResetData));
+    reset_info->cpu = cpu;
+    reset_info->prom_addr = hwdef->prom_addr;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    return cpu;
+}
+
+static void sun4uv_init(MemoryRegion *address_space_mem,
+                        ram_addr_t RAM_size,
+                        const char *boot_devices,
+                        const char *kernel_filename, const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model,
+                        const struct hwdef *hwdef)
+{
+    SPARCCPU *cpu;
+    M48t59State *nvram;
+    unsigned int i;
+    uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry;
+    PCIBus *pci_bus, *pci_bus2, *pci_bus3;
+    ISABus *isa_bus;
+    qemu_irq *ivec_irqs, *pbm_irqs;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    DriveInfo *fd[MAX_FD];
+    void *fw_cfg;
+
+    /* init CPUs */
+    cpu = cpu_devinit(cpu_model, hwdef);
+
+    /* set up devices */
+    ram_init(0, RAM_size);
+
+    prom_init(hwdef->prom_addr, bios_name);
+
+    ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, cpu, IVEC_MAX);
+    pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2,
+                           &pci_bus3, &pbm_irqs);
+    pci_vga_init(pci_bus);
+
+    // XXX Should be pci_bus3
+    isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs);
+
+    i = 0;
+    if (hwdef->console_serial_base) {
+        serial_mm_init(address_space_mem, hwdef->console_serial_base, 0,
+                       NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN);
+        i++;
+    }
+    for(; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_isa_init(isa_bus, i, serial_hds[i]);
+        }
+    }
+
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        if (parallel_hds[i]) {
+            parallel_init(isa_bus, i, parallel_hds[i]);
+        }
+    }
+
+    for(i = 0; i < nb_nics; i++)
+        pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
+
+    ide_drive_get(hd, MAX_IDE_BUS);
+
+    pci_cmd646_ide_init(pci_bus, hd, 1);
+
+    isa_create_simple(isa_bus, "i8042");
+    for(i = 0; i < MAX_FD; i++) {
+        fd[i] = drive_get(IF_FLOPPY, 0, i);
+    }
+    fdctrl_init_isa(isa_bus, fd);
+    nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59);
+
+    initrd_size = 0;
+    initrd_addr = 0;
+    kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename,
+                                    ram_size, &initrd_size, &initrd_addr,
+                                    &kernel_addr, &kernel_entry);
+
+    sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices,
+                           kernel_addr, kernel_size,
+                           kernel_cmdline,
+                           initrd_addr, initrd_size,
+                           /* XXX: need an option to load a NVRAM image */
+                           0,
+                           graphic_width, graphic_height, graphic_depth,
+                           (uint8_t *)&nd_table[0].macaddr);
+
+    fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    if (kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+                       strlen(kernel_cmdline) + 1);
+        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
+    }
+    fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]);
+
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_DEPTH, graphic_depth);
+
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+enum {
+    sun4u_id = 0,
+    sun4v_id = 64,
+    niagara_id,
+};
+
+static const struct hwdef hwdefs[] = {
+    /* Sun4u generic PC-like machine */
+    {
+        .default_cpu_model = "TI UltraSparc IIi",
+        .machine_id = sun4u_id,
+        .prom_addr = 0x1fff0000000ULL,
+        .console_serial_base = 0,
+    },
+    /* Sun4v generic PC-like machine */
+    {
+        .default_cpu_model = "Sun UltraSparc T1",
+        .machine_id = sun4v_id,
+        .prom_addr = 0x1fff0000000ULL,
+        .console_serial_base = 0,
+    },
+    /* Sun4v generic Niagara machine */
+    {
+        .default_cpu_model = "Sun UltraSparc T1",
+        .machine_id = niagara_id,
+        .prom_addr = 0xfff0000000ULL,
+        .console_serial_base = 0xfff0c2c000ULL,
+    },
+};
+
+/* Sun4u hardware initialisation */
+static void sun4u_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_devices = args->boot_device;
+    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]);
+}
+
+/* Sun4v hardware initialisation */
+static void sun4v_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_devices = args->boot_device;
+    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]);
+}
+
+/* Niagara hardware initialisation */
+static void niagara_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t RAM_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    const char *boot_devices = args->boot_device;
+    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]);
+}
+
+static QEMUMachine sun4u_machine = {
+    .name = "sun4u",
+    .desc = "Sun4u platform",
+    .init = sun4u_init,
+    .max_cpus = 1, // XXX for now
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine sun4v_machine = {
+    .name = "sun4v",
+    .desc = "Sun4v platform",
+    .init = sun4v_init,
+    .max_cpus = 1, // XXX for now
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine niagara_machine = {
+    .name = "Niagara",
+    .desc = "Sun4v platform, Niagara",
+    .init = niagara_init,
+    .max_cpus = 1, // XXX for now
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void sun4u_register_types(void)
+{
+    type_register_static(&ebus_info);
+    type_register_static(&prom_info);
+    type_register_static(&ram_info);
+}
+
+static void sun4u_machine_init(void)
+{
+    qemu_register_machine(&sun4u_machine);
+    qemu_register_machine(&sun4v_machine);
+    qemu_register_machine(&niagara_machine);
+}
+
+type_init(sun4u_register_types)
+machine_init(sun4u_machine_init);
diff --git a/hw/spitz.c b/hw/spitz.c
deleted file mode 100644 (file)
index f5832be..0000000
+++ /dev/null
@@ -1,1138 +0,0 @@
-/*
- * PXA270-based Clamshell PDA platforms.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "hw/hw.h"
-#include "hw/pxa.h"
-#include "hw/arm-misc.h"
-#include "sysemu/sysemu.h"
-#include "hw/pcmcia.h"
-#include "hw/i2c.h"
-#include "hw/ssi.h"
-#include "hw/flash.h"
-#include "qemu/timer.h"
-#include "hw/devices.h"
-#include "hw/sharpsl.h"
-#include "ui/console.h"
-#include "block/block.h"
-#include "audio/audio.h"
-#include "hw/boards.h"
-#include "sysemu/blockdev.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-#undef REG_FMT
-#define REG_FMT                        "0x%02lx"
-
-/* Spitz Flash */
-#define FLASH_BASE             0x0c000000
-#define FLASH_ECCLPLB          0x00    /* Line parity 7 - 0 bit */
-#define FLASH_ECCLPUB          0x04    /* Line parity 15 - 8 bit */
-#define FLASH_ECCCP            0x08    /* Column parity 5 - 0 bit */
-#define FLASH_ECCCNTR          0x0c    /* ECC byte counter */
-#define FLASH_ECCCLRR          0x10    /* Clear ECC */
-#define FLASH_FLASHIO          0x14    /* Flash I/O */
-#define FLASH_FLASHCTL         0x18    /* Flash Control */
-
-#define FLASHCTL_CE0           (1 << 0)
-#define FLASHCTL_CLE           (1 << 1)
-#define FLASHCTL_ALE           (1 << 2)
-#define FLASHCTL_WP            (1 << 3)
-#define FLASHCTL_CE1           (1 << 4)
-#define FLASHCTL_RYBY          (1 << 5)
-#define FLASHCTL_NCE           (FLASHCTL_CE0 | FLASHCTL_CE1)
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    DeviceState *nand;
-    uint8_t ctl;
-    uint8_t manf_id;
-    uint8_t chip_id;
-    ECCState ecc;
-} SLNANDState;
-
-static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size)
-{
-    SLNANDState *s = (SLNANDState *) opaque;
-    int ryby;
-
-    switch (addr) {
-#define BSHR(byte, from, to)   ((s->ecc.lp[byte] >> (from - to)) & (1 << to))
-    case FLASH_ECCLPLB:
-        return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) |
-                BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7);
-
-#define BSHL(byte, from, to)   ((s->ecc.lp[byte] << (to - from)) & (1 << to))
-    case FLASH_ECCLPUB:
-        return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) |
-                BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7);
-
-    case FLASH_ECCCP:
-        return s->ecc.cp;
-
-    case FLASH_ECCCNTR:
-        return s->ecc.count & 0xff;
-
-    case FLASH_FLASHCTL:
-        nand_getpins(s->nand, &ryby);
-        if (ryby)
-            return s->ctl | FLASHCTL_RYBY;
-        else
-            return s->ctl;
-
-    case FLASH_FLASHIO:
-        if (size == 4) {
-            return ecc_digest(&s->ecc, nand_getio(s->nand)) |
-                (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
-        }
-        return ecc_digest(&s->ecc, nand_getio(s->nand));
-
-    default:
-        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
-    }
-    return 0;
-}
-
-static void sl_write(void *opaque, hwaddr addr,
-                     uint64_t value, unsigned size)
-{
-    SLNANDState *s = (SLNANDState *) opaque;
-
-    switch (addr) {
-    case FLASH_ECCCLRR:
-        /* Value is ignored.  */
-        ecc_reset(&s->ecc);
-        break;
-
-    case FLASH_FLASHCTL:
-        s->ctl = value & 0xff & ~FLASHCTL_RYBY;
-        nand_setpins(s->nand,
-                        s->ctl & FLASHCTL_CLE,
-                        s->ctl & FLASHCTL_ALE,
-                        s->ctl & FLASHCTL_NCE,
-                        s->ctl & FLASHCTL_WP,
-                        0);
-        break;
-
-    case FLASH_FLASHIO:
-        nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff));
-        break;
-
-    default:
-        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
-    }
-}
-
-enum {
-    FLASH_128M,
-    FLASH_1024M,
-};
-
-static const MemoryRegionOps sl_ops = {
-    .read = sl_read,
-    .write = sl_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void sl_flash_register(PXA2xxState *cpu, int size)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "sl-nand");
-
-    qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG);
-    if (size == FLASH_128M)
-        qdev_prop_set_uint8(dev, "chip_id", 0x73);
-    else if (size == FLASH_1024M)
-        qdev_prop_set_uint8(dev, "chip_id", 0xf1);
-
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE);
-}
-
-static int sl_nand_init(SysBusDevice *dev) {
-    SLNANDState *s;
-    DriveInfo *nand;
-
-    s = FROM_SYSBUS(SLNANDState, dev);
-
-    s->ctl = 0;
-    nand = drive_get(IF_MTD, 0, 0);
-    s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id);
-
-    memory_region_init_io(&s->iomem, &sl_ops, s, "sl", 0x40);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-/* Spitz Keyboard */
-
-#define SPITZ_KEY_STROBE_NUM   11
-#define SPITZ_KEY_SENSE_NUM    7
-
-static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = {
-    12, 17, 91, 34, 36, 38, 39
-};
-
-static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = {
-    88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114
-};
-
-/* Eighth additional row maps the special keys */
-static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = {
-    { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 },
-    {  -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 },
-    { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25,  -1 ,  -1 ,  -1  },
-    { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26,  -1 , 0x36,  -1  },
-    { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34,  -1 , 0x1c, 0x2a,  -1  },
-    { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33,  -1 , 0x48,  -1 ,  -1 , 0x38 },
-    { 0x37, 0x3d,  -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d,  -1 ,  -1  },
-    { 0x52, 0x43, 0x01, 0x47, 0x49,  -1 ,  -1 ,  -1 ,  -1 ,  -1 ,  -1  },
-};
-
-#define SPITZ_GPIO_AK_INT      13      /* Remote control */
-#define SPITZ_GPIO_SYNC                16      /* Sync button */
-#define SPITZ_GPIO_ON_KEY      95      /* Power button */
-#define SPITZ_GPIO_SWA         97      /* Lid */
-#define SPITZ_GPIO_SWB         96      /* Tablet mode */
-
-/* The special buttons are mapped to unused keys */
-static const int spitz_gpiomap[5] = {
-    SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY,
-    SPITZ_GPIO_SWA, SPITZ_GPIO_SWB,
-};
-
-typedef struct {
-    SysBusDevice busdev;
-    qemu_irq sense[SPITZ_KEY_SENSE_NUM];
-    qemu_irq gpiomap[5];
-    int keymap[0x80];
-    uint16_t keyrow[SPITZ_KEY_SENSE_NUM];
-    uint16_t strobe_state;
-    uint16_t sense_state;
-
-    uint16_t pre_map[0x100];
-    uint16_t modifiers;
-    uint16_t imodifiers;
-    uint8_t fifo[16];
-    int fifopos, fifolen;
-    QEMUTimer *kbdtimer;
-} SpitzKeyboardState;
-
-static void spitz_keyboard_sense_update(SpitzKeyboardState *s)
-{
-    int i;
-    uint16_t strobe, sense = 0;
-    for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) {
-        strobe = s->keyrow[i] & s->strobe_state;
-        if (strobe) {
-            sense |= 1 << i;
-            if (!(s->sense_state & (1 << i)))
-                qemu_irq_raise(s->sense[i]);
-        } else if (s->sense_state & (1 << i))
-            qemu_irq_lower(s->sense[i]);
-    }
-
-    s->sense_state = sense;
-}
-
-static void spitz_keyboard_strobe(void *opaque, int line, int level)
-{
-    SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
-    if (level)
-        s->strobe_state |= 1 << line;
-    else
-        s->strobe_state &= ~(1 << line);
-    spitz_keyboard_sense_update(s);
-}
-
-static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
-{
-    int spitz_keycode = s->keymap[keycode & 0x7f];
-    if (spitz_keycode == -1)
-        return;
-
-    /* Handle the additional keys */
-    if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) {
-        qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80));
-        return;
-    }
-
-    if (keycode & 0x80)
-        s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf));
-    else
-        s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf);
-
-    spitz_keyboard_sense_update(s);
-}
-
-#define SHIFT  (1 << 7)
-#define CTRL   (1 << 8)
-#define FN     (1 << 9)
-
-#define QUEUE_KEY(c)   s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
-
-static void spitz_keyboard_handler(void *opaque, int keycode)
-{
-    SpitzKeyboardState *s = opaque;
-    uint16_t code;
-    int mapcode;
-    switch (keycode) {
-    case 0x2a: /* Left Shift */
-        s->modifiers |= 1;
-        break;
-    case 0xaa:
-        s->modifiers &= ~1;
-        break;
-    case 0x36: /* Right Shift */
-        s->modifiers |= 2;
-        break;
-    case 0xb6:
-        s->modifiers &= ~2;
-        break;
-    case 0x1d: /* Control */
-        s->modifiers |= 4;
-        break;
-    case 0x9d:
-        s->modifiers &= ~4;
-        break;
-    case 0x38: /* Alt */
-        s->modifiers |= 8;
-        break;
-    case 0xb8:
-        s->modifiers &= ~8;
-        break;
-    }
-
-    code = s->pre_map[mapcode = ((s->modifiers & 3) ?
-            (keycode | SHIFT) :
-            (keycode & ~SHIFT))];
-
-    if (code != mapcode) {
-#if 0
-        if ((code & SHIFT) && !(s->modifiers & 1))
-            QUEUE_KEY(0x2a | (keycode & 0x80));
-        if ((code & CTRL ) && !(s->modifiers & 4))
-            QUEUE_KEY(0x1d | (keycode & 0x80));
-        if ((code & FN   ) && !(s->modifiers & 8))
-            QUEUE_KEY(0x38 | (keycode & 0x80));
-        if ((code & FN   ) && (s->modifiers & 1))
-            QUEUE_KEY(0x2a | (~keycode & 0x80));
-        if ((code & FN   ) && (s->modifiers & 2))
-            QUEUE_KEY(0x36 | (~keycode & 0x80));
-#else
-        if (keycode & 0x80) {
-            if ((s->imodifiers & 1   ) && !(s->modifiers & 1))
-                QUEUE_KEY(0x2a | 0x80);
-            if ((s->imodifiers & 4   ) && !(s->modifiers & 4))
-                QUEUE_KEY(0x1d | 0x80);
-            if ((s->imodifiers & 8   ) && !(s->modifiers & 8))
-                QUEUE_KEY(0x38 | 0x80);
-            if ((s->imodifiers & 0x10) && (s->modifiers & 1))
-                QUEUE_KEY(0x2a);
-            if ((s->imodifiers & 0x20) && (s->modifiers & 2))
-                QUEUE_KEY(0x36);
-            s->imodifiers = 0;
-        } else {
-            if ((code & SHIFT) && !((s->modifiers | s->imodifiers) & 1)) {
-                QUEUE_KEY(0x2a);
-                s->imodifiers |= 1;
-            }
-            if ((code & CTRL ) && !((s->modifiers | s->imodifiers) & 4)) {
-                QUEUE_KEY(0x1d);
-                s->imodifiers |= 4;
-            }
-            if ((code & FN   ) && !((s->modifiers | s->imodifiers) & 8)) {
-                QUEUE_KEY(0x38);
-                s->imodifiers |= 8;
-            }
-            if ((code & FN   ) && (s->modifiers & 1) &&
-                            !(s->imodifiers & 0x10)) {
-                QUEUE_KEY(0x2a | 0x80);
-                s->imodifiers |= 0x10;
-            }
-            if ((code & FN   ) && (s->modifiers & 2) &&
-                            !(s->imodifiers & 0x20)) {
-                QUEUE_KEY(0x36 | 0x80);
-                s->imodifiers |= 0x20;
-            }
-        }
-#endif
-    }
-
-    QUEUE_KEY((code & 0x7f) | (keycode & 0x80));
-}
-
-static void spitz_keyboard_tick(void *opaque)
-{
-    SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
-    if (s->fifolen) {
-        spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]);
-        s->fifolen --;
-        if (s->fifopos >= 16)
-            s->fifopos = 0;
-    }
-
-    qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock) +
-                   get_ticks_per_sec() / 32);
-}
-
-static void spitz_keyboard_pre_map(SpitzKeyboardState *s)
-{
-    int i;
-    for (i = 0; i < 0x100; i ++)
-        s->pre_map[i] = i;
-    s->pre_map[0x02 | SHIFT    ] = 0x02 | SHIFT;       /* exclam */
-    s->pre_map[0x28 | SHIFT    ] = 0x03 | SHIFT;       /* quotedbl */
-    s->pre_map[0x04 | SHIFT    ] = 0x04 | SHIFT;       /* numbersign */
-    s->pre_map[0x05 | SHIFT    ] = 0x05 | SHIFT;       /* dollar */
-    s->pre_map[0x06 | SHIFT    ] = 0x06 | SHIFT;       /* percent */
-    s->pre_map[0x08 | SHIFT    ] = 0x07 | SHIFT;       /* ampersand */
-    s->pre_map[0x28            ] = 0x08 | SHIFT;       /* apostrophe */
-    s->pre_map[0x0a | SHIFT    ] = 0x09 | SHIFT;       /* parenleft */
-    s->pre_map[0x0b | SHIFT    ] = 0x0a | SHIFT;       /* parenright */
-    s->pre_map[0x29 | SHIFT    ] = 0x0b | SHIFT;       /* asciitilde */
-    s->pre_map[0x03 | SHIFT    ] = 0x0c | SHIFT;       /* at */
-    s->pre_map[0xd3            ] = 0x0e | FN;          /* Delete */
-    s->pre_map[0x3a            ] = 0x0f | FN;          /* Caps_Lock */
-    s->pre_map[0x07 | SHIFT    ] = 0x11 | FN;          /* asciicircum */
-    s->pre_map[0x0d            ] = 0x12 | FN;          /* equal */
-    s->pre_map[0x0d | SHIFT    ] = 0x13 | FN;          /* plus */
-    s->pre_map[0x1a            ] = 0x14 | FN;          /* bracketleft */
-    s->pre_map[0x1b            ] = 0x15 | FN;          /* bracketright */
-    s->pre_map[0x1a | SHIFT    ] = 0x16 | FN;          /* braceleft */
-    s->pre_map[0x1b | SHIFT    ] = 0x17 | FN;          /* braceright */
-    s->pre_map[0x27            ] = 0x22 | FN;          /* semicolon */
-    s->pre_map[0x27 | SHIFT    ] = 0x23 | FN;          /* colon */
-    s->pre_map[0x09 | SHIFT    ] = 0x24 | FN;          /* asterisk */
-    s->pre_map[0x2b            ] = 0x25 | FN;          /* backslash */
-    s->pre_map[0x2b | SHIFT    ] = 0x26 | FN;          /* bar */
-    s->pre_map[0x0c | SHIFT    ] = 0x30 | FN;          /* underscore */
-    s->pre_map[0x33 | SHIFT    ] = 0x33 | FN;          /* less */
-    s->pre_map[0x35            ] = 0x33 | SHIFT;       /* slash */
-    s->pre_map[0x34 | SHIFT    ] = 0x34 | FN;          /* greater */
-    s->pre_map[0x35 | SHIFT    ] = 0x34 | SHIFT;       /* question */
-    s->pre_map[0x49            ] = 0x48 | FN;          /* Page_Up */
-    s->pre_map[0x51            ] = 0x50 | FN;          /* Page_Down */
-
-    s->modifiers = 0;
-    s->imodifiers = 0;
-    s->fifopos = 0;
-    s->fifolen = 0;
-}
-
-#undef SHIFT
-#undef CTRL
-#undef FN
-
-static int spitz_keyboard_post_load(void *opaque, int version_id)
-{
-    SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
-    /* Release all pressed keys */
-    memset(s->keyrow, 0, sizeof(s->keyrow));
-    spitz_keyboard_sense_update(s);
-    s->modifiers = 0;
-    s->imodifiers = 0;
-    s->fifopos = 0;
-    s->fifolen = 0;
-
-    return 0;
-}
-
-static void spitz_keyboard_register(PXA2xxState *cpu)
-{
-    int i;
-    DeviceState *dev;
-    SpitzKeyboardState *s;
-
-    dev = sysbus_create_simple("spitz-keyboard", -1, NULL);
-    s = FROM_SYSBUS(SpitzKeyboardState, SYS_BUS_DEVICE(dev));
-
-    for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++)
-        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i]));
-
-    for (i = 0; i < 5; i ++)
-        s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]);
-
-    if (!graphic_rotate)
-        s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]);
-
-    for (i = 0; i < 5; i++)
-        qemu_set_irq(s->gpiomap[i], 0);
-
-    for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
-        qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i],
-                qdev_get_gpio_in(dev, i));
-
-    qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock));
-
-    qemu_add_kbd_event_handler(spitz_keyboard_handler, s);
-}
-
-static int spitz_keyboard_init(SysBusDevice *dev)
-{
-    SpitzKeyboardState *s;
-    int i, j;
-
-    s = FROM_SYSBUS(SpitzKeyboardState, dev);
-
-    for (i = 0; i < 0x80; i ++)
-        s->keymap[i] = -1;
-    for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++)
-        for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++)
-            if (spitz_keymap[i][j] != -1)
-                s->keymap[spitz_keymap[i][j]] = (i << 4) | j;
-
-    spitz_keyboard_pre_map(s);
-
-    s->kbdtimer = qemu_new_timer_ns(vm_clock, spitz_keyboard_tick, s);
-    qdev_init_gpio_in(&dev->qdev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM);
-    qdev_init_gpio_out(&dev->qdev, s->sense, SPITZ_KEY_SENSE_NUM);
-
-    return 0;
-}
-
-/* LCD backlight controller */
-
-#define LCDTG_RESCTL   0x00
-#define LCDTG_PHACTRL  0x01
-#define LCDTG_DUTYCTRL 0x02
-#define LCDTG_POWERREG0        0x03
-#define LCDTG_POWERREG1        0x04
-#define LCDTG_GPOR3    0x05
-#define LCDTG_PICTRL   0x06
-#define LCDTG_POLCTRL  0x07
-
-typedef struct {
-    SSISlave ssidev;
-    uint32_t bl_intensity;
-    uint32_t bl_power;
-} SpitzLCDTG;
-
-static void spitz_bl_update(SpitzLCDTG *s)
-{
-    if (s->bl_power && s->bl_intensity)
-        zaurus_printf("LCD Backlight now at %i/63\n", s->bl_intensity);
-    else
-        zaurus_printf("LCD Backlight now off\n");
-}
-
-/* FIXME: Implement GPIO properly and remove this hack.  */
-static SpitzLCDTG *spitz_lcdtg;
-
-static inline void spitz_bl_bit5(void *opaque, int line, int level)
-{
-    SpitzLCDTG *s = spitz_lcdtg;
-    int prev = s->bl_intensity;
-
-    if (level)
-        s->bl_intensity &= ~0x20;
-    else
-        s->bl_intensity |= 0x20;
-
-    if (s->bl_power && prev != s->bl_intensity)
-        spitz_bl_update(s);
-}
-
-static inline void spitz_bl_power(void *opaque, int line, int level)
-{
-    SpitzLCDTG *s = spitz_lcdtg;
-    s->bl_power = !!level;
-    spitz_bl_update(s);
-}
-
-static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
-{
-    SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
-    int addr;
-    addr = value >> 5;
-    value &= 0x1f;
-
-    switch (addr) {
-    case LCDTG_RESCTL:
-        if (value)
-            zaurus_printf("LCD in QVGA mode\n");
-        else
-            zaurus_printf("LCD in VGA mode\n");
-        break;
-
-    case LCDTG_DUTYCTRL:
-        s->bl_intensity &= ~0x1f;
-        s->bl_intensity |= value;
-        if (s->bl_power)
-            spitz_bl_update(s);
-        break;
-
-    case LCDTG_POWERREG0:
-        /* Set common voltage to M62332FP */
-        break;
-    }
-    return 0;
-}
-
-static int spitz_lcdtg_init(SSISlave *dev)
-{
-    SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
-
-    spitz_lcdtg = s;
-    s->bl_power = 0;
-    s->bl_intensity = 0x20;
-
-    return 0;
-}
-
-/* SSP devices */
-
-#define CORGI_SSP_PORT         2
-
-#define SPITZ_GPIO_LCDCON_CS   53
-#define SPITZ_GPIO_ADS7846_CS  14
-#define SPITZ_GPIO_MAX1111_CS  20
-#define SPITZ_GPIO_TP_INT      11
-
-static DeviceState *max1111;
-
-/* "Demux" the signal based on current chipselect */
-typedef struct {
-    SSISlave ssidev;
-    SSIBus *bus[3];
-    uint32_t enable[3];
-} CorgiSSPState;
-
-static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value)
-{
-    CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
-    int i;
-
-    for (i = 0; i < 3; i++) {
-        if (s->enable[i]) {
-            return ssi_transfer(s->bus[i], value);
-        }
-    }
-    return 0;
-}
-
-static void corgi_ssp_gpio_cs(void *opaque, int line, int level)
-{
-    CorgiSSPState *s = (CorgiSSPState *)opaque;
-    assert(line >= 0 && line < 3);
-    s->enable[line] = !level;
-}
-
-#define MAX1111_BATT_VOLT      1
-#define MAX1111_BATT_TEMP      2
-#define MAX1111_ACIN_VOLT      3
-
-#define SPITZ_BATTERY_TEMP     0xe0    /* About 2.9V */
-#define SPITZ_BATTERY_VOLT     0xd0    /* About 4.0V */
-#define SPITZ_CHARGEON_ACIN    0x80    /* About 5.0V */
-
-static void spitz_adc_temp_on(void *opaque, int line, int level)
-{
-    if (!max1111)
-        return;
-
-    if (level)
-        max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP);
-    else
-        max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
-}
-
-static int corgi_ssp_init(SSISlave *dev)
-{
-    CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
-
-    qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3);
-    s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
-    s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
-    s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2");
-
-    return 0;
-}
-
-static void spitz_ssp_attach(PXA2xxState *cpu)
-{
-    DeviceState *mux;
-    DeviceState *dev;
-    void *bus;
-
-    mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp");
-
-    bus = qdev_get_child_bus(mux, "ssi0");
-    ssi_create_slave(bus, "spitz-lcdtg");
-
-    bus = qdev_get_child_bus(mux, "ssi1");
-    dev = ssi_create_slave(bus, "ads7846");
-    qdev_connect_gpio_out(dev, 0,
-                          qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT));
-
-    bus = qdev_get_child_bus(mux, "ssi2");
-    max1111 = ssi_create_slave(bus, "max1111");
-    max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT);
-    max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
-    max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN);
-
-    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS,
-                        qdev_get_gpio_in(mux, 0));
-    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS,
-                        qdev_get_gpio_in(mux, 1));
-    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS,
-                        qdev_get_gpio_in(mux, 2));
-}
-
-/* CF Microdrive */
-
-static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
-{
-    PCMCIACardState *md;
-    DriveInfo *dinfo;
-
-    dinfo = drive_get(IF_IDE, 0, 0);
-    if (!dinfo || dinfo->media_cd)
-        return;
-    md = dscm1xxxx_init(dinfo);
-    pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
-}
-
-/* Wm8750 and Max7310 on I2C */
-
-#define AKITA_MAX_ADDR 0x18
-#define SPITZ_WM_ADDRL 0x1b
-#define SPITZ_WM_ADDRH 0x1a
-
-#define SPITZ_GPIO_WM  5
-
-static void spitz_wm8750_addr(void *opaque, int line, int level)
-{
-    I2CSlave *wm = (I2CSlave *) opaque;
-    if (level)
-        i2c_set_slave_address(wm, SPITZ_WM_ADDRH);
-    else
-        i2c_set_slave_address(wm, SPITZ_WM_ADDRL);
-}
-
-static void spitz_i2c_setup(PXA2xxState *cpu)
-{
-    /* Attach the CPU on one end of our I2C bus.  */
-    i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
-
-    DeviceState *wm;
-
-    /* Attach a WM8750 to the bus */
-    wm = i2c_create_slave(bus, "wm8750", 0);
-
-    spitz_wm8750_addr(wm, 0, 0);
-    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM,
-                    qemu_allocate_irqs(spitz_wm8750_addr, wm, 1)[0]);
-    /* .. and to the sound interface.  */
-    cpu->i2s->opaque = wm;
-    cpu->i2s->codec_out = wm8750_dac_dat;
-    cpu->i2s->codec_in = wm8750_adc_dat;
-    wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
-}
-
-static void spitz_akita_i2c_setup(PXA2xxState *cpu)
-{
-    /* Attach a Max7310 to Akita I2C bus.  */
-    i2c_create_slave(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310",
-                     AKITA_MAX_ADDR);
-}
-
-/* Other peripherals */
-
-static void spitz_out_switch(void *opaque, int line, int level)
-{
-    switch (line) {
-    case 0:
-        zaurus_printf("Charging %s.\n", level ? "off" : "on");
-        break;
-    case 1:
-        zaurus_printf("Discharging %s.\n", level ? "on" : "off");
-        break;
-    case 2:
-        zaurus_printf("Green LED %s.\n", level ? "on" : "off");
-        break;
-    case 3:
-        zaurus_printf("Orange LED %s.\n", level ? "on" : "off");
-        break;
-    case 4:
-        spitz_bl_bit5(opaque, line, level);
-        break;
-    case 5:
-        spitz_bl_power(opaque, line, level);
-        break;
-    case 6:
-        spitz_adc_temp_on(opaque, line, level);
-        break;
-    }
-}
-
-#define SPITZ_SCP_LED_GREEN            1
-#define SPITZ_SCP_JK_B                 2
-#define SPITZ_SCP_CHRG_ON              3
-#define SPITZ_SCP_MUTE_L               4
-#define SPITZ_SCP_MUTE_R               5
-#define SPITZ_SCP_CF_POWER             6
-#define SPITZ_SCP_LED_ORANGE           7
-#define SPITZ_SCP_JK_A                 8
-#define SPITZ_SCP_ADC_TEMP_ON          9
-#define SPITZ_SCP2_IR_ON               1
-#define SPITZ_SCP2_AKIN_PULLUP         2
-#define SPITZ_SCP2_BACKLIGHT_CONT      7
-#define SPITZ_SCP2_BACKLIGHT_ON                8
-#define SPITZ_SCP2_MIC_BIAS            9
-
-static void spitz_scoop_gpio_setup(PXA2xxState *cpu,
-                DeviceState *scp0, DeviceState *scp1)
-{
-    qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8);
-
-    qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]);
-    qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]);
-    qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]);
-    qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]);
-
-    if (scp1) {
-        qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]);
-        qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]);
-    }
-
-    qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]);
-}
-
-#define SPITZ_GPIO_HSYNC               22
-#define SPITZ_GPIO_SD_DETECT           9
-#define SPITZ_GPIO_SD_WP               81
-#define SPITZ_GPIO_ON_RESET            89
-#define SPITZ_GPIO_BAT_COVER           90
-#define SPITZ_GPIO_CF1_IRQ             105
-#define SPITZ_GPIO_CF1_CD              94
-#define SPITZ_GPIO_CF2_IRQ             106
-#define SPITZ_GPIO_CF2_CD              93
-
-static int spitz_hsync;
-
-static void spitz_lcd_hsync_handler(void *opaque, int line, int level)
-{
-    PXA2xxState *cpu = (PXA2xxState *) opaque;
-    qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync);
-    spitz_hsync ^= 1;
-}
-
-static void spitz_gpio_setup(PXA2xxState *cpu, int slots)
-{
-    qemu_irq lcd_hsync;
-    /*
-     * Bad hack: We toggle the LCD hsync GPIO on every GPIO status
-     * read to satisfy broken guests that poll-wait for hsync.
-     * Simulating a real hsync event would be less practical and
-     * wouldn't guarantee that a guest ever exits the loop.
-     */
-    spitz_hsync = 0;
-    lcd_hsync = qemu_allocate_irqs(spitz_lcd_hsync_handler, cpu, 1)[0];
-    pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync);
-    pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync);
-
-    /* MMC/SD host */
-    pxa2xx_mmci_handlers(cpu->mmc,
-                    qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP),
-                    qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT));
-
-    /* Battery lock always closed */
-    qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER));
-
-    /* Handle reset */
-    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset);
-
-    /* PCMCIA signals: card's IRQ and Card-Detect */
-    if (slots >= 1)
-        pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
-                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ),
-                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD));
-    if (slots >= 2)
-        pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
-                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ),
-                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD));
-}
-
-/* Board init.  */
-enum spitz_model_e { spitz, akita, borzoi, terrier };
-
-#define SPITZ_RAM      0x04000000
-#define SPITZ_ROM      0x00800000
-
-static struct arm_boot_info spitz_binfo = {
-    .loader_start = PXA2XX_SDRAM_BASE,
-    .ram_size = 0x04000000,
-};
-
-static void spitz_common_init(QEMUMachineInitArgs *args,
-                              enum spitz_model_e model, int arm_id)
-{
-    PXA2xxState *mpu;
-    DeviceState *scp0, *scp1 = NULL;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *rom = g_new(MemoryRegion, 1);
-    const char *cpu_model = args->cpu_model;
-
-    if (!cpu_model)
-        cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
-
-    /* Setup CPU & memory */
-    mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model);
-
-    sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
-
-    memory_region_init_ram(rom, "spitz.rom", SPITZ_ROM);
-    vmstate_register_ram_global(rom);
-    memory_region_set_readonly(rom, true);
-    memory_region_add_subregion(address_space_mem, 0, rom);
-
-    /* Setup peripherals */
-    spitz_keyboard_register(mpu);
-
-    spitz_ssp_attach(mpu);
-
-    scp0 = sysbus_create_simple("scoop", 0x10800000, NULL);
-    if (model != akita) {
-        scp1 = sysbus_create_simple("scoop", 0x08800040, NULL);
-    }
-
-    spitz_scoop_gpio_setup(mpu, scp0, scp1);
-
-    spitz_gpio_setup(mpu, (model == akita) ? 1 : 2);
-
-    spitz_i2c_setup(mpu);
-
-    if (model == akita)
-        spitz_akita_i2c_setup(mpu);
-
-    if (model == terrier)
-        /* A 6.0 GB microdrive is permanently sitting in CF slot 1.  */
-        spitz_microdrive_attach(mpu, 1);
-    else if (model != akita)
-        /* A 4.0 GB microdrive is permanently sitting in CF slot 0.  */
-        spitz_microdrive_attach(mpu, 0);
-
-    spitz_binfo.kernel_filename = args->kernel_filename;
-    spitz_binfo.kernel_cmdline = args->kernel_cmdline;
-    spitz_binfo.initrd_filename = args->initrd_filename;
-    spitz_binfo.board_id = arm_id;
-    arm_load_kernel(mpu->cpu, &spitz_binfo);
-    sl_bootparam_write(SL_PXA_PARAM_BASE);
-}
-
-static void spitz_init(QEMUMachineInitArgs *args)
-{
-    spitz_common_init(args, spitz, 0x2c9);
-}
-
-static void borzoi_init(QEMUMachineInitArgs *args)
-{
-    spitz_common_init(args, borzoi, 0x33f);
-}
-
-static void akita_init(QEMUMachineInitArgs *args)
-{
-    spitz_common_init(args, akita, 0x2e8);
-}
-
-static void terrier_init(QEMUMachineInitArgs *args)
-{
-    spitz_common_init(args, terrier, 0x33f);
-}
-
-static QEMUMachine akitapda_machine = {
-    .name = "akita",
-    .desc = "Akita PDA (PXA270)",
-    .init = akita_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine spitzpda_machine = {
-    .name = "spitz",
-    .desc = "Spitz PDA (PXA270)",
-    .init = spitz_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine borzoipda_machine = {
-    .name = "borzoi",
-    .desc = "Borzoi PDA (PXA270)",
-    .init = borzoi_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine terrierpda_machine = {
-    .name = "terrier",
-    .desc = "Terrier PDA (PXA270)",
-    .init = terrier_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void spitz_machine_init(void)
-{
-    qemu_register_machine(&akitapda_machine);
-    qemu_register_machine(&spitzpda_machine);
-    qemu_register_machine(&borzoipda_machine);
-    qemu_register_machine(&terrierpda_machine);
-}
-
-machine_init(spitz_machine_init);
-
-static bool is_version_0(void *opaque, int version_id)
-{
-    return version_id == 0;
-}
-
-static VMStateDescription vmstate_sl_nand_info = {
-    .name = "sl-nand",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields = (VMStateField []) {
-        VMSTATE_UINT8(ctl, SLNANDState),
-        VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static Property sl_nand_properties[] = {
-    DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
-    DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sl_nand_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = sl_nand_init;
-    dc->vmsd = &vmstate_sl_nand_info;
-    dc->props = sl_nand_properties;
-}
-
-static const TypeInfo sl_nand_info = {
-    .name          = "sl-nand",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SLNANDState),
-    .class_init    = sl_nand_class_init,
-};
-
-static VMStateDescription vmstate_spitz_kbd = {
-    .name = "spitz-keyboard",
-    .version_id = 1,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = spitz_keyboard_post_load,
-    .fields = (VMStateField []) {
-        VMSTATE_UINT16(sense_state, SpitzKeyboardState),
-        VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
-        VMSTATE_UNUSED_TEST(is_version_0, 5),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static Property spitz_keyboard_properties[] = {
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = spitz_keyboard_init;
-    dc->vmsd = &vmstate_spitz_kbd;
-    dc->props = spitz_keyboard_properties;
-}
-
-static const TypeInfo spitz_keyboard_info = {
-    .name          = "spitz-keyboard",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SpitzKeyboardState),
-    .class_init    = spitz_keyboard_class_init,
-};
-
-static const VMStateDescription vmstate_corgi_ssp_regs = {
-    .name = "corgi-ssp",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields = (VMStateField []) {
-        VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState),
-        VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
-        VMSTATE_END_OF_LIST(),
-    }
-};
-
-static void corgi_ssp_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
-    k->init = corgi_ssp_init;
-    k->transfer = corgi_ssp_transfer;
-    dc->vmsd = &vmstate_corgi_ssp_regs;
-}
-
-static const TypeInfo corgi_ssp_info = {
-    .name          = "corgi-ssp",
-    .parent        = TYPE_SSI_SLAVE,
-    .instance_size = sizeof(CorgiSSPState),
-    .class_init    = corgi_ssp_class_init,
-};
-
-static const VMStateDescription vmstate_spitz_lcdtg_regs = {
-    .name = "spitz-lcdtg",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField []) {
-        VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG),
-        VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
-        VMSTATE_UINT32(bl_power, SpitzLCDTG),
-        VMSTATE_END_OF_LIST(),
-    }
-};
-
-static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
-    k->init = spitz_lcdtg_init;
-    k->transfer = spitz_lcdtg_transfer;
-    dc->vmsd = &vmstate_spitz_lcdtg_regs;
-}
-
-static const TypeInfo spitz_lcdtg_info = {
-    .name          = "spitz-lcdtg",
-    .parent        = TYPE_SSI_SLAVE,
-    .instance_size = sizeof(SpitzLCDTG),
-    .class_init    = spitz_lcdtg_class_init,
-};
-
-static void spitz_register_types(void)
-{
-    type_register_static(&corgi_ssp_info);
-    type_register_static(&spitz_lcdtg_info);
-    type_register_static(&spitz_keyboard_info);
-    type_register_static(&sl_nand_info);
-}
-
-type_init(spitz_register_types)
diff --git a/hw/stellaris.c b/hw/stellaris.c
deleted file mode 100644 (file)
index f4ce794..0000000
+++ /dev/null
@@ -1,1401 +0,0 @@
-/*
- * Luminary Micro Stellaris peripherals
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-#include "hw/ssi.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
-#include "qemu/timer.h"
-#include "hw/i2c.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "exec/address-spaces.h"
-
-#define GPIO_A 0
-#define GPIO_B 1
-#define GPIO_C 2
-#define GPIO_D 3
-#define GPIO_E 4
-#define GPIO_F 5
-#define GPIO_G 6
-
-#define BP_OLED_I2C  0x01
-#define BP_OLED_SSI  0x02
-#define BP_GAMEPAD   0x04
-
-typedef const struct {
-    const char *name;
-    uint32_t did0;
-    uint32_t did1;
-    uint32_t dc0;
-    uint32_t dc1;
-    uint32_t dc2;
-    uint32_t dc3;
-    uint32_t dc4;
-    uint32_t peripherals;
-} stellaris_board_info;
-
-/* General purpose timer module.  */
-
-typedef struct gptm_state {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t config;
-    uint32_t mode[2];
-    uint32_t control;
-    uint32_t state;
-    uint32_t mask;
-    uint32_t load[2];
-    uint32_t match[2];
-    uint32_t prescale[2];
-    uint32_t match_prescale[2];
-    uint32_t rtc;
-    int64_t tick[2];
-    struct gptm_state *opaque[2];
-    QEMUTimer *timer[2];
-    /* The timers have an alternate output used to trigger the ADC.  */
-    qemu_irq trigger;
-    qemu_irq irq;
-} gptm_state;
-
-static void gptm_update_irq(gptm_state *s)
-{
-    int level;
-    level = (s->state & s->mask) != 0;
-    qemu_set_irq(s->irq, level);
-}
-
-static void gptm_stop(gptm_state *s, int n)
-{
-    qemu_del_timer(s->timer[n]);
-}
-
-static void gptm_reload(gptm_state *s, int n, int reset)
-{
-    int64_t tick;
-    if (reset)
-        tick = qemu_get_clock_ns(vm_clock);
-    else
-        tick = s->tick[n];
-
-    if (s->config == 0) {
-        /* 32-bit CountDown.  */
-        uint32_t count;
-        count = s->load[0] | (s->load[1] << 16);
-        tick += (int64_t)count * system_clock_scale;
-    } else if (s->config == 1) {
-        /* 32-bit RTC.  1Hz tick.  */
-        tick += get_ticks_per_sec();
-    } else if (s->mode[n] == 0xa) {
-        /* PWM mode.  Not implemented.  */
-    } else {
-        hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
-    }
-    s->tick[n] = tick;
-    qemu_mod_timer(s->timer[n], tick);
-}
-
-static void gptm_tick(void *opaque)
-{
-    gptm_state **p = (gptm_state **)opaque;
-    gptm_state *s;
-    int n;
-
-    s = *p;
-    n = p - s->opaque;
-    if (s->config == 0) {
-        s->state |= 1;
-        if ((s->control & 0x20)) {
-            /* Output trigger.  */
-           qemu_irq_pulse(s->trigger);
-        }
-        if (s->mode[0] & 1) {
-            /* One-shot.  */
-            s->control &= ~1;
-        } else {
-            /* Periodic.  */
-            gptm_reload(s, 0, 0);
-        }
-    } else if (s->config == 1) {
-        /* RTC.  */
-        uint32_t match;
-        s->rtc++;
-        match = s->match[0] | (s->match[1] << 16);
-        if (s->rtc > match)
-            s->rtc = 0;
-        if (s->rtc == 0) {
-            s->state |= 8;
-        }
-        gptm_reload(s, 0, 0);
-    } else if (s->mode[n] == 0xa) {
-        /* PWM mode.  Not implemented.  */
-    } else {
-        hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
-    }
-    gptm_update_irq(s);
-}
-
-static uint64_t gptm_read(void *opaque, hwaddr offset,
-                          unsigned size)
-{
-    gptm_state *s = (gptm_state *)opaque;
-
-    switch (offset) {
-    case 0x00: /* CFG */
-        return s->config;
-    case 0x04: /* TAMR */
-        return s->mode[0];
-    case 0x08: /* TBMR */
-        return s->mode[1];
-    case 0x0c: /* CTL */
-        return s->control;
-    case 0x18: /* IMR */
-        return s->mask;
-    case 0x1c: /* RIS */
-        return s->state;
-    case 0x20: /* MIS */
-        return s->state & s->mask;
-    case 0x24: /* CR */
-        return 0;
-    case 0x28: /* TAILR */
-        return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0);
-    case 0x2c: /* TBILR */
-        return s->load[1];
-    case 0x30: /* TAMARCHR */
-        return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0);
-    case 0x34: /* TBMATCHR */
-        return s->match[1];
-    case 0x38: /* TAPR */
-        return s->prescale[0];
-    case 0x3c: /* TBPR */
-        return s->prescale[1];
-    case 0x40: /* TAPMR */
-        return s->match_prescale[0];
-    case 0x44: /* TBPMR */
-        return s->match_prescale[1];
-    case 0x48: /* TAR */
-        if (s->control == 1)
-            return s->rtc;
-    case 0x4c: /* TBR */
-        hw_error("TODO: Timer value read\n");
-    default:
-        hw_error("gptm_read: Bad offset 0x%x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void gptm_write(void *opaque, hwaddr offset,
-                       uint64_t value, unsigned size)
-{
-    gptm_state *s = (gptm_state *)opaque;
-    uint32_t oldval;
-
-    /* The timers should be disabled before changing the configuration.
-       We take advantage of this and defer everything until the timer
-       is enabled.  */
-    switch (offset) {
-    case 0x00: /* CFG */
-        s->config = value;
-        break;
-    case 0x04: /* TAMR */
-        s->mode[0] = value;
-        break;
-    case 0x08: /* TBMR */
-        s->mode[1] = value;
-        break;
-    case 0x0c: /* CTL */
-        oldval = s->control;
-        s->control = value;
-        /* TODO: Implement pause.  */
-        if ((oldval ^ value) & 1) {
-            if (value & 1) {
-                gptm_reload(s, 0, 1);
-            } else {
-                gptm_stop(s, 0);
-            }
-        }
-        if (((oldval ^ value) & 0x100) && s->config >= 4) {
-            if (value & 0x100) {
-                gptm_reload(s, 1, 1);
-            } else {
-                gptm_stop(s, 1);
-            }
-        }
-        break;
-    case 0x18: /* IMR */
-        s->mask = value & 0x77;
-        gptm_update_irq(s);
-        break;
-    case 0x24: /* CR */
-        s->state &= ~value;
-        break;
-    case 0x28: /* TAILR */
-        s->load[0] = value & 0xffff;
-        if (s->config < 4) {
-            s->load[1] = value >> 16;
-        }
-        break;
-    case 0x2c: /* TBILR */
-        s->load[1] = value & 0xffff;
-        break;
-    case 0x30: /* TAMARCHR */
-        s->match[0] = value & 0xffff;
-        if (s->config < 4) {
-            s->match[1] = value >> 16;
-        }
-        break;
-    case 0x34: /* TBMATCHR */
-        s->match[1] = value >> 16;
-        break;
-    case 0x38: /* TAPR */
-        s->prescale[0] = value;
-        break;
-    case 0x3c: /* TBPR */
-        s->prescale[1] = value;
-        break;
-    case 0x40: /* TAPMR */
-        s->match_prescale[0] = value;
-        break;
-    case 0x44: /* TBPMR */
-        s->match_prescale[0] = value;
-        break;
-    default:
-        hw_error("gptm_write: Bad offset 0x%x\n", (int)offset);
-    }
-    gptm_update_irq(s);
-}
-
-static const MemoryRegionOps gptm_ops = {
-    .read = gptm_read,
-    .write = gptm_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_stellaris_gptm = {
-    .name = "stellaris_gptm",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(config, gptm_state),
-        VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
-        VMSTATE_UINT32(control, gptm_state),
-        VMSTATE_UINT32(state, gptm_state),
-        VMSTATE_UINT32(mask, gptm_state),
-        VMSTATE_UNUSED(8),
-        VMSTATE_UINT32_ARRAY(load, gptm_state, 2),
-        VMSTATE_UINT32_ARRAY(match, gptm_state, 2),
-        VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2),
-        VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2),
-        VMSTATE_UINT32(rtc, gptm_state),
-        VMSTATE_INT64_ARRAY(tick, gptm_state, 2),
-        VMSTATE_TIMER_ARRAY(timer, gptm_state, 2),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int stellaris_gptm_init(SysBusDevice *dev)
-{
-    gptm_state *s = FROM_SYSBUS(gptm_state, dev);
-
-    sysbus_init_irq(dev, &s->irq);
-    qdev_init_gpio_out(&dev->qdev, &s->trigger, 1);
-
-    memory_region_init_io(&s->iomem, &gptm_ops, s,
-                          "gptm", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    s->opaque[0] = s->opaque[1] = s;
-    s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]);
-    s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]);
-    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s);
-    return 0;
-}
-
-
-/* System controller.  */
-
-typedef struct {
-    MemoryRegion iomem;
-    uint32_t pborctl;
-    uint32_t ldopctl;
-    uint32_t int_status;
-    uint32_t int_mask;
-    uint32_t resc;
-    uint32_t rcc;
-    uint32_t rcc2;
-    uint32_t rcgc[3];
-    uint32_t scgc[3];
-    uint32_t dcgc[3];
-    uint32_t clkvclr;
-    uint32_t ldoarst;
-    uint32_t user0;
-    uint32_t user1;
-    qemu_irq irq;
-    stellaris_board_info *board;
-} ssys_state;
-
-static void ssys_update(ssys_state *s)
-{
-  qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
-}
-
-static uint32_t pllcfg_sandstorm[16] = {
-    0x31c0, /* 1 Mhz */
-    0x1ae0, /* 1.8432 Mhz */
-    0x18c0, /* 2 Mhz */
-    0xd573, /* 2.4576 Mhz */
-    0x37a6, /* 3.57954 Mhz */
-    0x1ae2, /* 3.6864 Mhz */
-    0x0c40, /* 4 Mhz */
-    0x98bc, /* 4.906 Mhz */
-    0x935b, /* 4.9152 Mhz */
-    0x09c0, /* 5 Mhz */
-    0x4dee, /* 5.12 Mhz */
-    0x0c41, /* 6 Mhz */
-    0x75db, /* 6.144 Mhz */
-    0x1ae6, /* 7.3728 Mhz */
-    0x0600, /* 8 Mhz */
-    0x585b /* 8.192 Mhz */
-};
-
-static uint32_t pllcfg_fury[16] = {
-    0x3200, /* 1 Mhz */
-    0x1b20, /* 1.8432 Mhz */
-    0x1900, /* 2 Mhz */
-    0xf42b, /* 2.4576 Mhz */
-    0x37e3, /* 3.57954 Mhz */
-    0x1b21, /* 3.6864 Mhz */
-    0x0c80, /* 4 Mhz */
-    0x98ee, /* 4.906 Mhz */
-    0xd5b4, /* 4.9152 Mhz */
-    0x0a00, /* 5 Mhz */
-    0x4e27, /* 5.12 Mhz */
-    0x1902, /* 6 Mhz */
-    0xec1c, /* 6.144 Mhz */
-    0x1b23, /* 7.3728 Mhz */
-    0x0640, /* 8 Mhz */
-    0xb11c /* 8.192 Mhz */
-};
-
-#define DID0_VER_MASK        0x70000000
-#define DID0_VER_0           0x00000000
-#define DID0_VER_1           0x10000000
-
-#define DID0_CLASS_MASK      0x00FF0000
-#define DID0_CLASS_SANDSTORM 0x00000000
-#define DID0_CLASS_FURY      0x00010000
-
-static int ssys_board_class(const ssys_state *s)
-{
-    uint32_t did0 = s->board->did0;
-    switch (did0 & DID0_VER_MASK) {
-    case DID0_VER_0:
-        return DID0_CLASS_SANDSTORM;
-    case DID0_VER_1:
-        switch (did0 & DID0_CLASS_MASK) {
-        case DID0_CLASS_SANDSTORM:
-        case DID0_CLASS_FURY:
-            return did0 & DID0_CLASS_MASK;
-        }
-        /* for unknown classes, fall through */
-    default:
-        hw_error("ssys_board_class: Unknown class 0x%08x\n", did0);
-    }
-}
-
-static uint64_t ssys_read(void *opaque, hwaddr offset,
-                          unsigned size)
-{
-    ssys_state *s = (ssys_state *)opaque;
-
-    switch (offset) {
-    case 0x000: /* DID0 */
-        return s->board->did0;
-    case 0x004: /* DID1 */
-        return s->board->did1;
-    case 0x008: /* DC0 */
-        return s->board->dc0;
-    case 0x010: /* DC1 */
-        return s->board->dc1;
-    case 0x014: /* DC2 */
-        return s->board->dc2;
-    case 0x018: /* DC3 */
-        return s->board->dc3;
-    case 0x01c: /* DC4 */
-        return s->board->dc4;
-    case 0x030: /* PBORCTL */
-        return s->pborctl;
-    case 0x034: /* LDOPCTL */
-        return s->ldopctl;
-    case 0x040: /* SRCR0 */
-        return 0;
-    case 0x044: /* SRCR1 */
-        return 0;
-    case 0x048: /* SRCR2 */
-        return 0;
-    case 0x050: /* RIS */
-        return s->int_status;
-    case 0x054: /* IMC */
-        return s->int_mask;
-    case 0x058: /* MISC */
-        return s->int_status & s->int_mask;
-    case 0x05c: /* RESC */
-        return s->resc;
-    case 0x060: /* RCC */
-        return s->rcc;
-    case 0x064: /* PLLCFG */
-        {
-            int xtal;
-            xtal = (s->rcc >> 6) & 0xf;
-            switch (ssys_board_class(s)) {
-            case DID0_CLASS_FURY:
-                return pllcfg_fury[xtal];
-            case DID0_CLASS_SANDSTORM:
-                return pllcfg_sandstorm[xtal];
-            default:
-                hw_error("ssys_read: Unhandled class for PLLCFG read.\n");
-                return 0;
-            }
-        }
-    case 0x070: /* RCC2 */
-        return s->rcc2;
-    case 0x100: /* RCGC0 */
-        return s->rcgc[0];
-    case 0x104: /* RCGC1 */
-        return s->rcgc[1];
-    case 0x108: /* RCGC2 */
-        return s->rcgc[2];
-    case 0x110: /* SCGC0 */
-        return s->scgc[0];
-    case 0x114: /* SCGC1 */
-        return s->scgc[1];
-    case 0x118: /* SCGC2 */
-        return s->scgc[2];
-    case 0x120: /* DCGC0 */
-        return s->dcgc[0];
-    case 0x124: /* DCGC1 */
-        return s->dcgc[1];
-    case 0x128: /* DCGC2 */
-        return s->dcgc[2];
-    case 0x150: /* CLKVCLR */
-        return s->clkvclr;
-    case 0x160: /* LDOARST */
-        return s->ldoarst;
-    case 0x1e0: /* USER0 */
-        return s->user0;
-    case 0x1e4: /* USER1 */
-        return s->user1;
-    default:
-        hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
-        return 0;
-    }
-}
-
-static bool ssys_use_rcc2(ssys_state *s)
-{
-    return (s->rcc2 >> 31) & 0x1;
-}
-
-/*
- * Caculate the sys. clock period in ms.
- */
-static void ssys_calculate_system_clock(ssys_state *s)
-{
-    if (ssys_use_rcc2(s)) {
-        system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
-    } else {
-        system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
-    }
-}
-
-static void ssys_write(void *opaque, hwaddr offset,
-                       uint64_t value, unsigned size)
-{
-    ssys_state *s = (ssys_state *)opaque;
-
-    switch (offset) {
-    case 0x030: /* PBORCTL */
-        s->pborctl = value & 0xffff;
-        break;
-    case 0x034: /* LDOPCTL */
-        s->ldopctl = value & 0x1f;
-        break;
-    case 0x040: /* SRCR0 */
-    case 0x044: /* SRCR1 */
-    case 0x048: /* SRCR2 */
-        fprintf(stderr, "Peripheral reset not implemented\n");
-        break;
-    case 0x054: /* IMC */
-        s->int_mask = value & 0x7f;
-        break;
-    case 0x058: /* MISC */
-        s->int_status &= ~value;
-        break;
-    case 0x05c: /* RESC */
-        s->resc = value & 0x3f;
-        break;
-    case 0x060: /* RCC */
-        if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
-            /* PLL enable.  */
-            s->int_status |= (1 << 6);
-        }
-        s->rcc = value;
-        ssys_calculate_system_clock(s);
-        break;
-    case 0x070: /* RCC2 */
-        if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
-            break;
-        }
-
-        if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
-            /* PLL enable.  */
-            s->int_status |= (1 << 6);
-        }
-        s->rcc2 = value;
-        ssys_calculate_system_clock(s);
-        break;
-    case 0x100: /* RCGC0 */
-        s->rcgc[0] = value;
-        break;
-    case 0x104: /* RCGC1 */
-        s->rcgc[1] = value;
-        break;
-    case 0x108: /* RCGC2 */
-        s->rcgc[2] = value;
-        break;
-    case 0x110: /* SCGC0 */
-        s->scgc[0] = value;
-        break;
-    case 0x114: /* SCGC1 */
-        s->scgc[1] = value;
-        break;
-    case 0x118: /* SCGC2 */
-        s->scgc[2] = value;
-        break;
-    case 0x120: /* DCGC0 */
-        s->dcgc[0] = value;
-        break;
-    case 0x124: /* DCGC1 */
-        s->dcgc[1] = value;
-        break;
-    case 0x128: /* DCGC2 */
-        s->dcgc[2] = value;
-        break;
-    case 0x150: /* CLKVCLR */
-        s->clkvclr = value;
-        break;
-    case 0x160: /* LDOARST */
-        s->ldoarst = value;
-        break;
-    default:
-        hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
-    }
-    ssys_update(s);
-}
-
-static const MemoryRegionOps ssys_ops = {
-    .read = ssys_read,
-    .write = ssys_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ssys_reset(void *opaque)
-{
-    ssys_state *s = (ssys_state *)opaque;
-
-    s->pborctl = 0x7ffd;
-    s->rcc = 0x078e3ac0;
-
-    if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
-        s->rcc2 = 0;
-    } else {
-        s->rcc2 = 0x07802810;
-    }
-    s->rcgc[0] = 1;
-    s->scgc[0] = 1;
-    s->dcgc[0] = 1;
-    ssys_calculate_system_clock(s);
-}
-
-static int stellaris_sys_post_load(void *opaque, int version_id)
-{
-    ssys_state *s = opaque;
-
-    ssys_calculate_system_clock(s);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_stellaris_sys = {
-    .name = "stellaris_sys",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = stellaris_sys_post_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(pborctl, ssys_state),
-        VMSTATE_UINT32(ldopctl, ssys_state),
-        VMSTATE_UINT32(int_mask, ssys_state),
-        VMSTATE_UINT32(int_status, ssys_state),
-        VMSTATE_UINT32(resc, ssys_state),
-        VMSTATE_UINT32(rcc, ssys_state),
-        VMSTATE_UINT32_V(rcc2, ssys_state, 2),
-        VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3),
-        VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3),
-        VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
-        VMSTATE_UINT32(clkvclr, ssys_state),
-        VMSTATE_UINT32(ldoarst, ssys_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int stellaris_sys_init(uint32_t base, qemu_irq irq,
-                              stellaris_board_info * board,
-                              uint8_t *macaddr)
-{
-    ssys_state *s;
-
-    s = (ssys_state *)g_malloc0(sizeof(ssys_state));
-    s->irq = irq;
-    s->board = board;
-    /* Most devices come preprogrammed with a MAC address in the user data. */
-    s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
-    s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
-
-    memory_region_init_io(&s->iomem, &ssys_ops, s, "ssys", 0x00001000);
-    memory_region_add_subregion(get_system_memory(), base, &s->iomem);
-    ssys_reset(s);
-    vmstate_register(NULL, -1, &vmstate_stellaris_sys, s);
-    return 0;
-}
-
-
-/* I2C controller.  */
-
-typedef struct {
-    SysBusDevice busdev;
-    i2c_bus *bus;
-    qemu_irq irq;
-    MemoryRegion iomem;
-    uint32_t msa;
-    uint32_t mcs;
-    uint32_t mdr;
-    uint32_t mtpr;
-    uint32_t mimr;
-    uint32_t mris;
-    uint32_t mcr;
-} stellaris_i2c_state;
-
-#define STELLARIS_I2C_MCS_BUSY    0x01
-#define STELLARIS_I2C_MCS_ERROR   0x02
-#define STELLARIS_I2C_MCS_ADRACK  0x04
-#define STELLARIS_I2C_MCS_DATACK  0x08
-#define STELLARIS_I2C_MCS_ARBLST  0x10
-#define STELLARIS_I2C_MCS_IDLE    0x20
-#define STELLARIS_I2C_MCS_BUSBSY  0x40
-
-static uint64_t stellaris_i2c_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
-
-    switch (offset) {
-    case 0x00: /* MSA */
-        return s->msa;
-    case 0x04: /* MCS */
-        /* We don't emulate timing, so the controller is never busy.  */
-        return s->mcs | STELLARIS_I2C_MCS_IDLE;
-    case 0x08: /* MDR */
-        return s->mdr;
-    case 0x0c: /* MTPR */
-        return s->mtpr;
-    case 0x10: /* MIMR */
-        return s->mimr;
-    case 0x14: /* MRIS */
-        return s->mris;
-    case 0x18: /* MMIS */
-        return s->mris & s->mimr;
-    case 0x20: /* MCR */
-        return s->mcr;
-    default:
-        hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void stellaris_i2c_update(stellaris_i2c_state *s)
-{
-    int level;
-
-    level = (s->mris & s->mimr) != 0;
-    qemu_set_irq(s->irq, level);
-}
-
-static void stellaris_i2c_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-    stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
-
-    switch (offset) {
-    case 0x00: /* MSA */
-        s->msa = value & 0xff;
-        break;
-    case 0x04: /* MCS */
-        if ((s->mcr & 0x10) == 0) {
-            /* Disabled.  Do nothing.  */
-            break;
-        }
-        /* Grab the bus if this is starting a transfer.  */
-        if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
-            if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
-                s->mcs |= STELLARIS_I2C_MCS_ARBLST;
-            } else {
-                s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
-                s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
-            }
-        }
-        /* If we don't have the bus then indicate an error.  */
-        if (!i2c_bus_busy(s->bus)
-                || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
-            s->mcs |= STELLARIS_I2C_MCS_ERROR;
-            break;
-        }
-        s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
-        if (value & 1) {
-            /* Transfer a byte.  */
-            /* TODO: Handle errors.  */
-            if (s->msa & 1) {
-                /* Recv */
-                s->mdr = i2c_recv(s->bus) & 0xff;
-            } else {
-                /* Send */
-                i2c_send(s->bus, s->mdr);
-            }
-            /* Raise an interrupt.  */
-            s->mris |= 1;
-        }
-        if (value & 4) {
-            /* Finish transfer.  */
-            i2c_end_transfer(s->bus);
-            s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
-        }
-        break;
-    case 0x08: /* MDR */
-        s->mdr = value & 0xff;
-        break;
-    case 0x0c: /* MTPR */
-        s->mtpr = value & 0xff;
-        break;
-    case 0x10: /* MIMR */
-        s->mimr = 1;
-        break;
-    case 0x1c: /* MICR */
-        s->mris &= ~value;
-        break;
-    case 0x20: /* MCR */
-        if (value & 1)
-            hw_error(
-                      "stellaris_i2c_write: Loopback not implemented\n");
-        if (value & 0x20)
-            hw_error(
-                      "stellaris_i2c_write: Slave mode not implemented\n");
-        s->mcr = value & 0x31;
-        break;
-    default:
-        hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
-                  (int)offset);
-    }
-    stellaris_i2c_update(s);
-}
-
-static void stellaris_i2c_reset(stellaris_i2c_state *s)
-{
-    if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
-        i2c_end_transfer(s->bus);
-
-    s->msa = 0;
-    s->mcs = 0;
-    s->mdr = 0;
-    s->mtpr = 1;
-    s->mimr = 0;
-    s->mris = 0;
-    s->mcr = 0;
-    stellaris_i2c_update(s);
-}
-
-static const MemoryRegionOps stellaris_i2c_ops = {
-    .read = stellaris_i2c_read,
-    .write = stellaris_i2c_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_stellaris_i2c = {
-    .name = "stellaris_i2c",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(msa, stellaris_i2c_state),
-        VMSTATE_UINT32(mcs, stellaris_i2c_state),
-        VMSTATE_UINT32(mdr, stellaris_i2c_state),
-        VMSTATE_UINT32(mtpr, stellaris_i2c_state),
-        VMSTATE_UINT32(mimr, stellaris_i2c_state),
-        VMSTATE_UINT32(mris, stellaris_i2c_state),
-        VMSTATE_UINT32(mcr, stellaris_i2c_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int stellaris_i2c_init(SysBusDevice * dev)
-{
-    stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
-    i2c_bus *bus;
-
-    sysbus_init_irq(dev, &s->irq);
-    bus = i2c_init_bus(&dev->qdev, "i2c");
-    s->bus = bus;
-
-    memory_region_init_io(&s->iomem, &stellaris_i2c_ops, s,
-                          "i2c", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    /* ??? For now we only implement the master interface.  */
-    stellaris_i2c_reset(s);
-    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s);
-    return 0;
-}
-
-/* Analogue to Digital Converter.  This is only partially implemented,
-   enough for applications that use a combined ADC and timer tick.  */
-
-#define STELLARIS_ADC_EM_CONTROLLER 0
-#define STELLARIS_ADC_EM_COMP       1
-#define STELLARIS_ADC_EM_EXTERNAL   4
-#define STELLARIS_ADC_EM_TIMER      5
-#define STELLARIS_ADC_EM_PWM0       6
-#define STELLARIS_ADC_EM_PWM1       7
-#define STELLARIS_ADC_EM_PWM2       8
-
-#define STELLARIS_ADC_FIFO_EMPTY    0x0100
-#define STELLARIS_ADC_FIFO_FULL     0x1000
-
-typedef struct
-{
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t actss;
-    uint32_t ris;
-    uint32_t im;
-    uint32_t emux;
-    uint32_t ostat;
-    uint32_t ustat;
-    uint32_t sspri;
-    uint32_t sac;
-    struct {
-        uint32_t state;
-        uint32_t data[16];
-    } fifo[4];
-    uint32_t ssmux[4];
-    uint32_t ssctl[4];
-    uint32_t noise;
-    qemu_irq irq[4];
-} stellaris_adc_state;
-
-static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n)
-{
-    int tail;
-
-    tail = s->fifo[n].state & 0xf;
-    if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
-        s->ustat |= 1 << n;
-    } else {
-        s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
-        s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
-        if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
-            s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
-    }
-    return s->fifo[n].data[tail];
-}
-
-static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n,
-                                     uint32_t value)
-{
-    int head;
-
-    /* TODO: Real hardware has limited size FIFOs.  We have a full 16 entry 
-       FIFO fir each sequencer.  */
-    head = (s->fifo[n].state >> 4) & 0xf;
-    if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
-        s->ostat |= 1 << n;
-        return;
-    }
-    s->fifo[n].data[head] = value;
-    head = (head + 1) & 0xf;
-    s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
-    s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
-    if ((s->fifo[n].state & 0xf) == head)
-        s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
-}
-
-static void stellaris_adc_update(stellaris_adc_state *s)
-{
-    int level;
-    int n;
-
-    for (n = 0; n < 4; n++) {
-        level = (s->ris & s->im & (1 << n)) != 0;
-        qemu_set_irq(s->irq[n], level);
-    }
-}
-
-static void stellaris_adc_trigger(void *opaque, int irq, int level)
-{
-    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
-    int n;
-
-    for (n = 0; n < 4; n++) {
-        if ((s->actss & (1 << n)) == 0) {
-            continue;
-        }
-
-        if (((s->emux >> (n * 4)) & 0xff) != 5) {
-            continue;
-        }
-
-        /* Some applications use the ADC as a random number source, so introduce
-           some variation into the signal.  */
-        s->noise = s->noise * 314159 + 1;
-        /* ??? actual inputs not implemented.  Return an arbitrary value.  */
-        stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
-        s->ris |= (1 << n);
-        stellaris_adc_update(s);
-    }
-}
-
-static void stellaris_adc_reset(stellaris_adc_state *s)
-{
-    int n;
-
-    for (n = 0; n < 4; n++) {
-        s->ssmux[n] = 0;
-        s->ssctl[n] = 0;
-        s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
-    }
-}
-
-static uint64_t stellaris_adc_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
-
-    /* TODO: Implement this.  */
-    if (offset >= 0x40 && offset < 0xc0) {
-        int n;
-        n = (offset - 0x40) >> 5;
-        switch (offset & 0x1f) {
-        case 0x00: /* SSMUX */
-            return s->ssmux[n];
-        case 0x04: /* SSCTL */
-            return s->ssctl[n];
-        case 0x08: /* SSFIFO */
-            return stellaris_adc_fifo_read(s, n);
-        case 0x0c: /* SSFSTAT */
-            return s->fifo[n].state;
-        default:
-            break;
-        }
-    }
-    switch (offset) {
-    case 0x00: /* ACTSS */
-        return s->actss;
-    case 0x04: /* RIS */
-        return s->ris;
-    case 0x08: /* IM */
-        return s->im;
-    case 0x0c: /* ISC */
-        return s->ris & s->im;
-    case 0x10: /* OSTAT */
-        return s->ostat;
-    case 0x14: /* EMUX */
-        return s->emux;
-    case 0x18: /* USTAT */
-        return s->ustat;
-    case 0x20: /* SSPRI */
-        return s->sspri;
-    case 0x30: /* SAC */
-        return s->sac;
-    default:
-        hw_error("strllaris_adc_read: Bad offset 0x%x\n",
-                  (int)offset);
-        return 0;
-    }
-}
-
-static void stellaris_adc_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
-
-    /* TODO: Implement this.  */
-    if (offset >= 0x40 && offset < 0xc0) {
-        int n;
-        n = (offset - 0x40) >> 5;
-        switch (offset & 0x1f) {
-        case 0x00: /* SSMUX */
-            s->ssmux[n] = value & 0x33333333;
-            return;
-        case 0x04: /* SSCTL */
-            if (value != 6) {
-                hw_error("ADC: Unimplemented sequence %" PRIx64 "\n",
-                          value);
-            }
-            s->ssctl[n] = value;
-            return;
-        default:
-            break;
-        }
-    }
-    switch (offset) {
-    case 0x00: /* ACTSS */
-        s->actss = value & 0xf;
-        break;
-    case 0x08: /* IM */
-        s->im = value;
-        break;
-    case 0x0c: /* ISC */
-        s->ris &= ~value;
-        break;
-    case 0x10: /* OSTAT */
-        s->ostat &= ~value;
-        break;
-    case 0x14: /* EMUX */
-        s->emux = value;
-        break;
-    case 0x18: /* USTAT */
-        s->ustat &= ~value;
-        break;
-    case 0x20: /* SSPRI */
-        s->sspri = value;
-        break;
-    case 0x28: /* PSSI */
-        hw_error("Not implemented:  ADC sample initiate\n");
-        break;
-    case 0x30: /* SAC */
-        s->sac = value;
-        break;
-    default:
-        hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
-    }
-    stellaris_adc_update(s);
-}
-
-static const MemoryRegionOps stellaris_adc_ops = {
-    .read = stellaris_adc_read,
-    .write = stellaris_adc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_stellaris_adc = {
-    .name = "stellaris_adc",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(actss, stellaris_adc_state),
-        VMSTATE_UINT32(ris, stellaris_adc_state),
-        VMSTATE_UINT32(im, stellaris_adc_state),
-        VMSTATE_UINT32(emux, stellaris_adc_state),
-        VMSTATE_UINT32(ostat, stellaris_adc_state),
-        VMSTATE_UINT32(ustat, stellaris_adc_state),
-        VMSTATE_UINT32(sspri, stellaris_adc_state),
-        VMSTATE_UINT32(sac, stellaris_adc_state),
-        VMSTATE_UINT32(fifo[0].state, stellaris_adc_state),
-        VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16),
-        VMSTATE_UINT32(ssmux[0], stellaris_adc_state),
-        VMSTATE_UINT32(ssctl[0], stellaris_adc_state),
-        VMSTATE_UINT32(fifo[1].state, stellaris_adc_state),
-        VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16),
-        VMSTATE_UINT32(ssmux[1], stellaris_adc_state),
-        VMSTATE_UINT32(ssctl[1], stellaris_adc_state),
-        VMSTATE_UINT32(fifo[2].state, stellaris_adc_state),
-        VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16),
-        VMSTATE_UINT32(ssmux[2], stellaris_adc_state),
-        VMSTATE_UINT32(ssctl[2], stellaris_adc_state),
-        VMSTATE_UINT32(fifo[3].state, stellaris_adc_state),
-        VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16),
-        VMSTATE_UINT32(ssmux[3], stellaris_adc_state),
-        VMSTATE_UINT32(ssctl[3], stellaris_adc_state),
-        VMSTATE_UINT32(noise, stellaris_adc_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int stellaris_adc_init(SysBusDevice *dev)
-{
-    stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev);
-    int n;
-
-    for (n = 0; n < 4; n++) {
-        sysbus_init_irq(dev, &s->irq[n]);
-    }
-
-    memory_region_init_io(&s->iomem, &stellaris_adc_ops, s,
-                          "adc", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    stellaris_adc_reset(s);
-    qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
-    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s);
-    return 0;
-}
-
-/* Board init.  */
-static stellaris_board_info stellaris_boards[] = {
-  { "LM3S811EVB",
-    0,
-    0x0032000e,
-    0x001f001f, /* dc0 */
-    0x001132bf,
-    0x01071013,
-    0x3f0f01ff,
-    0x0000001f,
-    BP_OLED_I2C
-  },
-  { "LM3S6965EVB",
-    0x10010002,
-    0x1073402e,
-    0x00ff007f, /* dc0 */
-    0x001133ff,
-    0x030f5317,
-    0x0f0f87ff,
-    0x5000007f,
-    BP_OLED_SSI | BP_GAMEPAD
-  }
-};
-
-static void stellaris_init(const char *kernel_filename, const char *cpu_model,
-                           stellaris_board_info *board)
-{
-    static const int uart_irq[] = {5, 6, 33, 34};
-    static const int timer_irq[] = {19, 21, 23, 35};
-    static const uint32_t gpio_addr[7] =
-      { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
-        0x40024000, 0x40025000, 0x40026000};
-    static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
-
-    MemoryRegion *address_space_mem = get_system_memory();
-    qemu_irq *pic;
-    DeviceState *gpio_dev[7];
-    qemu_irq gpio_in[7][8];
-    qemu_irq gpio_out[7][8];
-    qemu_irq adc;
-    int sram_size;
-    int flash_size;
-    i2c_bus *i2c;
-    DeviceState *dev;
-    int i;
-    int j;
-
-    flash_size = ((board->dc0 & 0xffff) + 1) << 1;
-    sram_size = (board->dc0 >> 18) + 1;
-    pic = armv7m_init(address_space_mem,
-                      flash_size, sram_size, kernel_filename, cpu_model);
-
-    if (board->dc1 & (1 << 16)) {
-        dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
-                                    pic[14], pic[15], pic[16], pic[17], NULL);
-        adc = qdev_get_gpio_in(dev, 0);
-    } else {
-        adc = NULL;
-    }
-    for (i = 0; i < 4; i++) {
-        if (board->dc2 & (0x10000 << i)) {
-            dev = sysbus_create_simple("stellaris-gptm",
-                                       0x40030000 + i * 0x1000,
-                                       pic[timer_irq[i]]);
-            /* TODO: This is incorrect, but we get away with it because
-               the ADC output is only ever pulsed.  */
-            qdev_connect_gpio_out(dev, 0, adc);
-        }
-    }
-
-    stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a);
-
-    for (i = 0; i < 7; i++) {
-        if (board->dc4 & (1 << i)) {
-            gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
-                                               pic[gpio_irq[i]]);
-            for (j = 0; j < 8; j++) {
-                gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
-                gpio_out[i][j] = NULL;
-            }
-        }
-    }
-
-    if (board->dc2 & (1 << 12)) {
-        dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
-        i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
-        if (board->peripherals & BP_OLED_I2C) {
-            i2c_create_slave(i2c, "ssd0303", 0x3d);
-        }
-    }
-
-    for (i = 0; i < 4; i++) {
-        if (board->dc2 & (1 << i)) {
-            sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
-                                 pic[uart_irq[i]]);
-        }
-    }
-    if (board->dc2 & (1 << 4)) {
-        dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
-        if (board->peripherals & BP_OLED_SSI) {
-            void *bus;
-            DeviceState *sddev;
-            DeviceState *ssddev;
-
-            /* Some boards have both an OLED controller and SD card connected to
-             * the same SSI port, with the SD card chip select connected to a
-             * GPIO pin.  Technically the OLED chip select is connected to the
-             * SSI Fss pin.  We do not bother emulating that as both devices
-             * should never be selected simultaneously, and our OLED controller
-             * ignores stray 0xff commands that occur when deselecting the SD
-             * card.
-             */
-            bus = qdev_get_child_bus(dev, "ssi");
-
-            sddev = ssi_create_slave(bus, "ssi-sd");
-            ssddev = ssi_create_slave(bus, "ssd0323");
-            gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0),
-                                                 qdev_get_gpio_in(ssddev, 0));
-            gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1);
-
-            /* Make sure the select pin is high.  */
-            qemu_irq_raise(gpio_out[GPIO_D][0]);
-        }
-    }
-    if (board->dc4 & (1 << 28)) {
-        DeviceState *enet;
-
-        qemu_check_nic_model(&nd_table[0], "stellaris");
-
-        enet = qdev_create(NULL, "stellaris_enet");
-        qdev_set_nic_properties(enet, &nd_table[0]);
-        qdev_init_nofail(enet);
-        sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000);
-        sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, pic[42]);
-    }
-    if (board->peripherals & BP_GAMEPAD) {
-        qemu_irq gpad_irq[5];
-        static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
-
-        gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
-        gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
-        gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
-        gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
-        gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
-
-        stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
-    }
-    for (i = 0; i < 7; i++) {
-        if (board->dc4 & (1 << i)) {
-            for (j = 0; j < 8; j++) {
-                if (gpio_out[i][j]) {
-                    qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
-                }
-            }
-        }
-    }
-}
-
-/* FIXME: Figure out how to generate these from stellaris_boards.  */
-static void lm3s811evb_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
-}
-
-static void lm3s6965evb_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
-}
-
-static QEMUMachine lm3s811evb_machine = {
-    .name = "lm3s811evb",
-    .desc = "Stellaris LM3S811EVB",
-    .init = lm3s811evb_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine lm3s6965evb_machine = {
-    .name = "lm3s6965evb",
-    .desc = "Stellaris LM3S6965EVB",
-    .init = lm3s6965evb_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void stellaris_machine_init(void)
-{
-    qemu_register_machine(&lm3s811evb_machine);
-    qemu_register_machine(&lm3s6965evb_machine);
-}
-
-machine_init(stellaris_machine_init);
-
-static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = stellaris_i2c_init;
-}
-
-static const TypeInfo stellaris_i2c_info = {
-    .name          = "stellaris-i2c",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(stellaris_i2c_state),
-    .class_init    = stellaris_i2c_class_init,
-};
-
-static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = stellaris_gptm_init;
-}
-
-static const TypeInfo stellaris_gptm_info = {
-    .name          = "stellaris-gptm",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(gptm_state),
-    .class_init    = stellaris_gptm_class_init,
-};
-
-static void stellaris_adc_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = stellaris_adc_init;
-}
-
-static const TypeInfo stellaris_adc_info = {
-    .name          = "stellaris-adc",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(stellaris_adc_state),
-    .class_init    = stellaris_adc_class_init,
-};
-
-static void stellaris_register_types(void)
-{
-    type_register_static(&stellaris_i2c_info);
-    type_register_static(&stellaris_gptm_info);
-    type_register_static(&stellaris_adc_info);
-}
-
-type_init(stellaris_register_types)
diff --git a/hw/sun4m.c b/hw/sun4m.c
deleted file mode 100644 (file)
index 37bd041..0000000
+++ /dev/null
@@ -1,1936 +0,0 @@
-/*
- * QEMU Sun4m & Sun4d & Sun4c System Emulator
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "hw/sun4m.h"
-#include "hw/nvram.h"
-#include "hw/sparc32_dma.h"
-#include "hw/fdc.h"
-#include "sysemu/sysemu.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/firmware_abi.h"
-#include "hw/esp.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
-#include "hw/fw_cfg.h"
-#include "hw/escc.h"
-#include "hw/empty_slot.h"
-#include "hw/qdev-addr.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/blockdev.h"
-#include "trace.h"
-
-/*
- * Sun4m architecture was used in the following machines:
- *
- * SPARCserver 6xxMP/xx
- * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15),
- * SPARCclassic X (4/10)
- * SPARCstation LX/ZX (4/30)
- * SPARCstation Voyager
- * SPARCstation 10/xx, SPARCserver 10/xx
- * SPARCstation 5, SPARCserver 5
- * SPARCstation 20/xx, SPARCserver 20
- * SPARCstation 4
- *
- * Sun4d architecture was used in the following machines:
- *
- * SPARCcenter 2000
- * SPARCserver 1000
- *
- * Sun4c architecture was used in the following machines:
- * SPARCstation 1/1+, SPARCserver 1/1+
- * SPARCstation SLC
- * SPARCstation IPC
- * SPARCstation ELC
- * SPARCstation IPX
- *
- * See for example: http://www.sunhelp.org/faq/sunref1.html
- */
-
-#define KERNEL_LOAD_ADDR     0x00004000
-#define CMDLINE_ADDR         0x007ff000
-#define INITRD_LOAD_ADDR     0x00800000
-#define PROM_SIZE_MAX        (1024 * 1024)
-#define PROM_VADDR           0xffd00000
-#define PROM_FILENAME        "openbios-sparc32"
-#define CFG_ADDR             0xd00000510ULL
-#define FW_CFG_SUN4M_DEPTH   (FW_CFG_ARCH_LOCAL + 0x00)
-
-#define MAX_CPUS 16
-#define MAX_PILS 16
-#define MAX_VSIMMS 4
-
-#define ESCC_CLOCK 4915200
-
-struct sun4m_hwdef {
-    hwaddr iommu_base, iommu_pad_base, iommu_pad_len, slavio_base;
-    hwaddr intctl_base, counter_base, nvram_base, ms_kb_base;
-    hwaddr serial_base, fd_base;
-    hwaddr afx_base, idreg_base, dma_base, esp_base, le_base;
-    hwaddr tcx_base, cs_base, apc_base, aux1_base, aux2_base;
-    hwaddr bpp_base, dbri_base, sx_base;
-    struct {
-        hwaddr reg_base, vram_base;
-    } vsimm[MAX_VSIMMS];
-    hwaddr ecc_base;
-    uint64_t max_mem;
-    const char * const default_cpu_model;
-    uint32_t ecc_version;
-    uint32_t iommu_version;
-    uint16_t machine_id;
-    uint8_t nvram_machine_id;
-};
-
-#define MAX_IOUNITS 5
-
-struct sun4d_hwdef {
-    hwaddr iounit_bases[MAX_IOUNITS], slavio_base;
-    hwaddr counter_base, nvram_base, ms_kb_base;
-    hwaddr serial_base;
-    hwaddr espdma_base, esp_base;
-    hwaddr ledma_base, le_base;
-    hwaddr tcx_base;
-    hwaddr sbi_base;
-    uint64_t max_mem;
-    const char * const default_cpu_model;
-    uint32_t iounit_version;
-    uint16_t machine_id;
-    uint8_t nvram_machine_id;
-};
-
-struct sun4c_hwdef {
-    hwaddr iommu_base, slavio_base;
-    hwaddr intctl_base, counter_base, nvram_base, ms_kb_base;
-    hwaddr serial_base, fd_base;
-    hwaddr idreg_base, dma_base, esp_base, le_base;
-    hwaddr tcx_base, aux1_base;
-    uint64_t max_mem;
-    const char * const default_cpu_model;
-    uint32_t iommu_version;
-    uint16_t machine_id;
-    uint8_t nvram_machine_id;
-};
-
-int DMA_get_channel_mode (int nchan)
-{
-    return 0;
-}
-int DMA_read_memory (int nchan, void *buf, int pos, int size)
-{
-    return 0;
-}
-int DMA_write_memory (int nchan, void *buf, int pos, int size)
-{
-    return 0;
-}
-void DMA_hold_DREQ (int nchan) {}
-void DMA_release_DREQ (int nchan) {}
-void DMA_schedule(int nchan) {}
-
-void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit)
-{
-}
-
-void DMA_register_channel (int nchan,
-                           DMA_transfer_handler transfer_handler,
-                           void *opaque)
-{
-}
-
-static int fw_cfg_boot_set(void *opaque, const char *boot_device)
-{
-    fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
-    return 0;
-}
-
-static void nvram_init(M48t59State *nvram, uint8_t *macaddr,
-                       const char *cmdline, const char *boot_devices,
-                       ram_addr_t RAM_size, uint32_t kernel_size,
-                       int width, int height, int depth,
-                       int nvram_machine_id, const char *arch)
-{
-    unsigned int i;
-    uint32_t start, end;
-    uint8_t image[0x1ff0];
-    struct OpenBIOS_nvpart_v1 *part_header;
-
-    memset(image, '\0', sizeof(image));
-
-    start = 0;
-
-    // OpenBIOS nvram variables
-    // Variable partition
-    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
-    part_header->signature = OPENBIOS_PART_SYSTEM;
-    pstrcpy(part_header->name, sizeof(part_header->name), "system");
-
-    end = start + sizeof(struct OpenBIOS_nvpart_v1);
-    for (i = 0; i < nb_prom_envs; i++)
-        end = OpenBIOS_set_var(image, end, prom_envs[i]);
-
-    // End marker
-    image[end++] = '\0';
-
-    end = start + ((end - start + 15) & ~15);
-    OpenBIOS_finish_partition(part_header, end - start);
-
-    // free partition
-    start = end;
-    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
-    part_header->signature = OPENBIOS_PART_FREE;
-    pstrcpy(part_header->name, sizeof(part_header->name), "free");
-
-    end = 0x1fd0;
-    OpenBIOS_finish_partition(part_header, end - start);
-
-    Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr,
-                    nvram_machine_id);
-
-    for (i = 0; i < sizeof(image); i++)
-        m48t59_write(nvram, i, image[i]);
-}
-
-static DeviceState *slavio_intctl;
-
-void sun4m_pic_info(Monitor *mon, const QDict *qdict)
-{
-    if (slavio_intctl)
-        slavio_pic_info(mon, slavio_intctl);
-}
-
-void sun4m_irq_info(Monitor *mon, const QDict *qdict)
-{
-    if (slavio_intctl)
-        slavio_irq_info(mon, slavio_intctl);
-}
-
-void cpu_check_irqs(CPUSPARCState *env)
-{
-    if (env->pil_in && (env->interrupt_index == 0 ||
-                        (env->interrupt_index & ~15) == TT_EXTINT)) {
-        unsigned int i;
-
-        for (i = 15; i > 0; i--) {
-            if (env->pil_in & (1 << i)) {
-                int old_interrupt = env->interrupt_index;
-
-                env->interrupt_index = TT_EXTINT | i;
-                if (old_interrupt != env->interrupt_index) {
-                    trace_sun4m_cpu_interrupt(i);
-                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
-                }
-                break;
-            }
-        }
-    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
-        trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15);
-        env->interrupt_index = 0;
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
-}
-
-static void cpu_kick_irq(SPARCCPU *cpu)
-{
-    CPUSPARCState *env = &cpu->env;
-
-    env->halted = 0;
-    cpu_check_irqs(env);
-    qemu_cpu_kick(CPU(cpu));
-}
-
-static void cpu_set_irq(void *opaque, int irq, int level)
-{
-    SPARCCPU *cpu = opaque;
-    CPUSPARCState *env = &cpu->env;
-
-    if (level) {
-        trace_sun4m_cpu_set_irq_raise(irq);
-        env->pil_in |= 1 << irq;
-        cpu_kick_irq(cpu);
-    } else {
-        trace_sun4m_cpu_set_irq_lower(irq);
-        env->pil_in &= ~(1 << irq);
-        cpu_check_irqs(env);
-    }
-}
-
-static void dummy_cpu_set_irq(void *opaque, int irq, int level)
-{
-}
-
-static void main_cpu_reset(void *opaque)
-{
-    SPARCCPU *cpu = opaque;
-    CPUSPARCState *env = &cpu->env;
-
-    cpu_reset(CPU(cpu));
-    env->halted = 0;
-}
-
-static void secondary_cpu_reset(void *opaque)
-{
-    SPARCCPU *cpu = opaque;
-    CPUSPARCState *env = &cpu->env;
-
-    cpu_reset(CPU(cpu));
-    env->halted = 1;
-}
-
-static void cpu_halt_signal(void *opaque, int irq, int level)
-{
-    if (level && cpu_single_env)
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
-    return addr - 0xf0000000ULL;
-}
-
-static unsigned long sun4m_load_kernel(const char *kernel_filename,
-                                       const char *initrd_filename,
-                                       ram_addr_t RAM_size)
-{
-    int linux_boot;
-    unsigned int i;
-    long initrd_size, kernel_size;
-    uint8_t *ptr;
-
-    linux_boot = (kernel_filename != NULL);
-
-    kernel_size = 0;
-    if (linux_boot) {
-        int bswap_needed;
-
-#ifdef BSWAP_NEEDED
-        bswap_needed = 1;
-#else
-        bswap_needed = 0;
-#endif
-        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
-                               NULL, NULL, NULL, 1, ELF_MACHINE, 0);
-        if (kernel_size < 0)
-            kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
-                                    RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
-                                    TARGET_PAGE_SIZE);
-        if (kernel_size < 0)
-            kernel_size = load_image_targphys(kernel_filename,
-                                              KERNEL_LOAD_ADDR,
-                                              RAM_size - KERNEL_LOAD_ADDR);
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-
-        /* load initrd */
-        initrd_size = 0;
-        if (initrd_filename) {
-            initrd_size = load_image_targphys(initrd_filename,
-                                              INITRD_LOAD_ADDR,
-                                              RAM_size - INITRD_LOAD_ADDR);
-            if (initrd_size < 0) {
-                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                        initrd_filename);
-                exit(1);
-            }
-        }
-        if (initrd_size > 0) {
-            for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
-                ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
-                if (ldl_p(ptr) == 0x48647253) { // HdrS
-                    stl_p(ptr + 16, INITRD_LOAD_ADDR);
-                    stl_p(ptr + 20, initrd_size);
-                    break;
-                }
-            }
-        }
-    }
-    return kernel_size;
-}
-
-static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "iommu");
-    qdev_prop_set_uint32(dev, "version", version);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(s, 0, irq);
-    sysbus_mmio_map(s, 0, addr);
-
-    return s;
-}
-
-static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq,
-                              void *iommu, qemu_irq *dev_irq, int is_ledma)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "sparc32_dma");
-    qdev_prop_set_ptr(dev, "iommu_opaque", iommu);
-    qdev_prop_set_uint32(dev, "is_ledma", is_ledma);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(s, 0, parent_irq);
-    *dev_irq = qdev_get_gpio_in(dev, 0);
-    sysbus_mmio_map(s, 0, daddr);
-
-    return s;
-}
-
-static void lance_init(NICInfo *nd, hwaddr leaddr,
-                       void *dma_opaque, qemu_irq irq)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    qemu_irq reset;
-
-    qemu_check_nic_model(&nd_table[0], "lance");
-
-    dev = qdev_create(NULL, "lance");
-    qdev_set_nic_properties(dev, nd);
-    qdev_prop_set_ptr(dev, "dma", dma_opaque);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(s, 0, leaddr);
-    sysbus_connect_irq(s, 0, irq);
-    reset = qdev_get_gpio_in(dev, 0);
-    qdev_connect_gpio_out(dma_opaque, 0, reset);
-}
-
-static DeviceState *slavio_intctl_init(hwaddr addr,
-                                       hwaddr addrg,
-                                       qemu_irq **parent_irq)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    unsigned int i, j;
-
-    dev = qdev_create(NULL, "slavio_intctl");
-    qdev_init_nofail(dev);
-
-    s = SYS_BUS_DEVICE(dev);
-
-    for (i = 0; i < MAX_CPUS; i++) {
-        for (j = 0; j < MAX_PILS; j++) {
-            sysbus_connect_irq(s, i * MAX_PILS + j, parent_irq[i][j]);
-        }
-    }
-    sysbus_mmio_map(s, 0, addrg);
-    for (i = 0; i < MAX_CPUS; i++) {
-        sysbus_mmio_map(s, i + 1, addr + i * TARGET_PAGE_SIZE);
-    }
-
-    return dev;
-}
-
-#define SYS_TIMER_OFFSET      0x10000ULL
-#define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu)
-
-static void slavio_timer_init_all(hwaddr addr, qemu_irq master_irq,
-                                  qemu_irq *cpu_irqs, unsigned int num_cpus)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    unsigned int i;
-
-    dev = qdev_create(NULL, "slavio_timer");
-    qdev_prop_set_uint32(dev, "num_cpus", num_cpus);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(s, 0, master_irq);
-    sysbus_mmio_map(s, 0, addr + SYS_TIMER_OFFSET);
-
-    for (i = 0; i < MAX_CPUS; i++) {
-        sysbus_mmio_map(s, i + 1, addr + (hwaddr)CPU_TIMER_OFFSET(i));
-        sysbus_connect_irq(s, i + 1, cpu_irqs[i]);
-    }
-}
-
-static qemu_irq  slavio_system_powerdown;
-
-static void slavio_powerdown_req(Notifier *n, void *opaque)
-{
-    qemu_irq_raise(slavio_system_powerdown);
-}
-
-static Notifier slavio_system_powerdown_notifier = {
-    .notify = slavio_powerdown_req
-};
-
-#define MISC_LEDS 0x01600000
-#define MISC_CFG  0x01800000
-#define MISC_DIAG 0x01a00000
-#define MISC_MDM  0x01b00000
-#define MISC_SYS  0x01f00000
-
-static void slavio_misc_init(hwaddr base,
-                             hwaddr aux1_base,
-                             hwaddr aux2_base, qemu_irq irq,
-                             qemu_irq fdc_tc)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "slavio_misc");
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    if (base) {
-        /* 8 bit registers */
-        /* Slavio control */
-        sysbus_mmio_map(s, 0, base + MISC_CFG);
-        /* Diagnostics */
-        sysbus_mmio_map(s, 1, base + MISC_DIAG);
-        /* Modem control */
-        sysbus_mmio_map(s, 2, base + MISC_MDM);
-        /* 16 bit registers */
-        /* ss600mp diag LEDs */
-        sysbus_mmio_map(s, 3, base + MISC_LEDS);
-        /* 32 bit registers */
-        /* System control */
-        sysbus_mmio_map(s, 4, base + MISC_SYS);
-    }
-    if (aux1_base) {
-        /* AUX 1 (Misc System Functions) */
-        sysbus_mmio_map(s, 5, aux1_base);
-    }
-    if (aux2_base) {
-        /* AUX 2 (Software Powerdown Control) */
-        sysbus_mmio_map(s, 6, aux2_base);
-    }
-    sysbus_connect_irq(s, 0, irq);
-    sysbus_connect_irq(s, 1, fdc_tc);
-    slavio_system_powerdown = qdev_get_gpio_in(dev, 0);
-    qemu_register_powerdown_notifier(&slavio_system_powerdown_notifier);
-}
-
-static void ecc_init(hwaddr base, qemu_irq irq, uint32_t version)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "eccmemctl");
-    qdev_prop_set_uint32(dev, "version", version);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(s, 0, irq);
-    sysbus_mmio_map(s, 0, base);
-    if (version == 0) { // SS-600MP only
-        sysbus_mmio_map(s, 1, base + 0x1000);
-    }
-}
-
-static void apc_init(hwaddr power_base, qemu_irq cpu_halt)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "apc");
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    /* Power management (APC) XXX: not a Slavio device */
-    sysbus_mmio_map(s, 0, power_base);
-    sysbus_connect_irq(s, 0, cpu_halt);
-}
-
-static void tcx_init(hwaddr addr, int vram_size, int width,
-                     int height, int depth)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "SUNW,tcx");
-    qdev_prop_set_taddr(dev, "addr", addr);
-    qdev_prop_set_uint32(dev, "vram_size", vram_size);
-    qdev_prop_set_uint16(dev, "width", width);
-    qdev_prop_set_uint16(dev, "height", height);
-    qdev_prop_set_uint16(dev, "depth", depth);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    /* 8-bit plane */
-    sysbus_mmio_map(s, 0, addr + 0x00800000ULL);
-    /* DAC */
-    sysbus_mmio_map(s, 1, addr + 0x00200000ULL);
-    /* TEC (dummy) */
-    sysbus_mmio_map(s, 2, addr + 0x00700000ULL);
-    /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */
-    sysbus_mmio_map(s, 3, addr + 0x00301000ULL);
-    if (depth == 24) {
-        /* 24-bit plane */
-        sysbus_mmio_map(s, 4, addr + 0x02000000ULL);
-        /* Control plane */
-        sysbus_mmio_map(s, 5, addr + 0x0a000000ULL);
-    } else {
-        /* THC 8 bit (dummy) */
-        sysbus_mmio_map(s, 4, addr + 0x00300000ULL);
-    }
-}
-
-/* NCR89C100/MACIO Internal ID register */
-static const uint8_t idreg_data[] = { 0xfe, 0x81, 0x01, 0x03 };
-
-static void idreg_init(hwaddr addr)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "macio_idreg");
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-
-    sysbus_mmio_map(s, 0, addr);
-    cpu_physical_memory_write_rom(addr, idreg_data, sizeof(idreg_data));
-}
-
-typedef struct IDRegState {
-    SysBusDevice busdev;
-    MemoryRegion mem;
-} IDRegState;
-
-static int idreg_init1(SysBusDevice *dev)
-{
-    IDRegState *s = FROM_SYSBUS(IDRegState, dev);
-
-    memory_region_init_ram(&s->mem, "sun4m.idreg", sizeof(idreg_data));
-    vmstate_register_ram_global(&s->mem);
-    memory_region_set_readonly(&s->mem, true);
-    sysbus_init_mmio(dev, &s->mem);
-    return 0;
-}
-
-static void idreg_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = idreg_init1;
-}
-
-static const TypeInfo idreg_info = {
-    .name          = "macio_idreg",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IDRegState),
-    .class_init    = idreg_class_init,
-};
-
-typedef struct AFXState {
-    SysBusDevice busdev;
-    MemoryRegion mem;
-} AFXState;
-
-/* SS-5 TCX AFX register */
-static void afx_init(hwaddr addr)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "tcx_afx");
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-
-    sysbus_mmio_map(s, 0, addr);
-}
-
-static int afx_init1(SysBusDevice *dev)
-{
-    AFXState *s = FROM_SYSBUS(AFXState, dev);
-
-    memory_region_init_ram(&s->mem, "sun4m.afx", 4);
-    vmstate_register_ram_global(&s->mem);
-    sysbus_init_mmio(dev, &s->mem);
-    return 0;
-}
-
-static void afx_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = afx_init1;
-}
-
-static const TypeInfo afx_info = {
-    .name          = "tcx_afx",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(AFXState),
-    .class_init    = afx_class_init,
-};
-
-typedef struct PROMState {
-    SysBusDevice busdev;
-    MemoryRegion prom;
-} PROMState;
-
-/* Boot PROM (OpenBIOS) */
-static uint64_t translate_prom_address(void *opaque, uint64_t addr)
-{
-    hwaddr *base_addr = (hwaddr *)opaque;
-    return addr + *base_addr - PROM_VADDR;
-}
-
-static void prom_init(hwaddr addr, const char *bios_name)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    char *filename;
-    int ret;
-
-    dev = qdev_create(NULL, "openprom");
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-
-    sysbus_mmio_map(s, 0, addr);
-
-    /* load boot prom */
-    if (bios_name == NULL) {
-        bios_name = PROM_FILENAME;
-    }
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    if (filename) {
-        ret = load_elf(filename, translate_prom_address, &addr, NULL,
-                       NULL, NULL, 1, ELF_MACHINE, 0);
-        if (ret < 0 || ret > PROM_SIZE_MAX) {
-            ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
-        }
-        g_free(filename);
-    } else {
-        ret = -1;
-    }
-    if (ret < 0 || ret > PROM_SIZE_MAX) {
-        fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name);
-        exit(1);
-    }
-}
-
-static int prom_init1(SysBusDevice *dev)
-{
-    PROMState *s = FROM_SYSBUS(PROMState, dev);
-
-    memory_region_init_ram(&s->prom, "sun4m.prom", PROM_SIZE_MAX);
-    vmstate_register_ram_global(&s->prom);
-    memory_region_set_readonly(&s->prom, true);
-    sysbus_init_mmio(dev, &s->prom);
-    return 0;
-}
-
-static Property prom_properties[] = {
-    {/* end of property list */},
-};
-
-static void prom_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = prom_init1;
-    dc->props = prom_properties;
-}
-
-static const TypeInfo prom_info = {
-    .name          = "openprom",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PROMState),
-    .class_init    = prom_class_init,
-};
-
-typedef struct RamDevice
-{
-    SysBusDevice busdev;
-    MemoryRegion ram;
-    uint64_t size;
-} RamDevice;
-
-/* System RAM */
-static int ram_init1(SysBusDevice *dev)
-{
-    RamDevice *d = FROM_SYSBUS(RamDevice, dev);
-
-    memory_region_init_ram(&d->ram, "sun4m.ram", d->size);
-    vmstate_register_ram_global(&d->ram);
-    sysbus_init_mmio(dev, &d->ram);
-    return 0;
-}
-
-static void ram_init(hwaddr addr, ram_addr_t RAM_size,
-                     uint64_t max_mem)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    RamDevice *d;
-
-    /* allocate RAM */
-    if ((uint64_t)RAM_size > max_mem) {
-        fprintf(stderr,
-                "qemu: Too much memory for this machine: %d, maximum %d\n",
-                (unsigned int)(RAM_size / (1024 * 1024)),
-                (unsigned int)(max_mem / (1024 * 1024)));
-        exit(1);
-    }
-    dev = qdev_create(NULL, "memory");
-    s = SYS_BUS_DEVICE(dev);
-
-    d = FROM_SYSBUS(RamDevice, s);
-    d->size = RAM_size;
-    qdev_init_nofail(dev);
-
-    sysbus_mmio_map(s, 0, addr);
-}
-
-static Property ram_properties[] = {
-    DEFINE_PROP_UINT64("size", RamDevice, size, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ram_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = ram_init1;
-    dc->props = ram_properties;
-}
-
-static const TypeInfo ram_info = {
-    .name          = "memory",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(RamDevice),
-    .class_init    = ram_class_init,
-};
-
-static void cpu_devinit(const char *cpu_model, unsigned int id,
-                        uint64_t prom_addr, qemu_irq **cpu_irqs)
-{
-    SPARCCPU *cpu;
-    CPUSPARCState *env;
-
-    cpu = cpu_sparc_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
-        exit(1);
-    }
-    env = &cpu->env;
-
-    cpu_sparc_set_id(env, id);
-    if (id == 0) {
-        qemu_register_reset(main_cpu_reset, cpu);
-    } else {
-        qemu_register_reset(secondary_cpu_reset, cpu);
-        env->halted = 1;
-    }
-    *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS);
-    env->prom_addr = prom_addr;
-}
-
-static void dummy_fdc_tc(void *opaque, int irq, int level)
-{
-}
-
-static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, 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)
-{
-    unsigned int i;
-    void *iommu, *espdma, *ledma, *nvram;
-    qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS],
-        espdma_irq, ledma_irq;
-    qemu_irq esp_reset, dma_enable;
-    qemu_irq fdc_tc;
-    qemu_irq *cpu_halt;
-    unsigned long kernel_size;
-    DriveInfo *fd[MAX_FD];
-    void *fw_cfg;
-    unsigned int num_vsimms;
-
-    /* init CPUs */
-    if (!cpu_model)
-        cpu_model = hwdef->default_cpu_model;
-
-    for(i = 0; i < smp_cpus; i++) {
-        cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]);
-    }
-
-    for (i = smp_cpus; i < MAX_CPUS; i++)
-        cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS);
-
-
-    /* set up devices */
-    ram_init(0, RAM_size, hwdef->max_mem);
-    /* models without ECC don't trap when missing ram is accessed */
-    if (!hwdef->ecc_base) {
-        empty_slot_init(RAM_size, hwdef->max_mem - RAM_size);
-    }
-
-    prom_init(hwdef->slavio_base, bios_name);
-
-    slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
-                                       hwdef->intctl_base + 0x10000ULL,
-                                       cpu_irqs);
-
-    for (i = 0; i < 32; i++) {
-        slavio_irq[i] = qdev_get_gpio_in(slavio_intctl, i);
-    }
-    for (i = 0; i < MAX_CPUS; i++) {
-        slavio_cpu_irq[i] = qdev_get_gpio_in(slavio_intctl, 32 + i);
-    }
-
-    if (hwdef->idreg_base) {
-        idreg_init(hwdef->idreg_base);
-    }
-
-    if (hwdef->afx_base) {
-        afx_init(hwdef->afx_base);
-    }
-
-    iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version,
-                       slavio_irq[30]);
-
-    if (hwdef->iommu_pad_base) {
-        /* On the real hardware (SS-5, LX) the MMU is not padded, but aliased.
-           Software shouldn't use aliased addresses, neither should it crash
-           when does. Using empty_slot instead of aliasing can help with
-           debugging such accesses */
-        empty_slot_init(hwdef->iommu_pad_base,hwdef->iommu_pad_len);
-    }
-
-    espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[18],
-                              iommu, &espdma_irq, 0);
-
-    ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
-                             slavio_irq[16], iommu, &ledma_irq, 1);
-
-    if (graphic_depth != 8 && graphic_depth != 24) {
-        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
-        exit (1);
-    }
-    num_vsimms = 0;
-    if (num_vsimms == 0) {
-        tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
-                 graphic_depth);
-    }
-
-    for (i = num_vsimms; i < MAX_VSIMMS; i++) {
-        /* vsimm registers probed by OBP */
-        if (hwdef->vsimm[i].reg_base) {
-            empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000);
-        }
-    }
-
-    if (hwdef->sx_base) {
-        empty_slot_init(hwdef->sx_base, 0x2000);
-    }
-
-    lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
-
-    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 8);
-
-    slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus);
-
-    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[14],
-                              display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
-    /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
-       Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
-    escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15],
-              serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
-
-    cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1);
-    if (hwdef->apc_base) {
-        apc_init(hwdef->apc_base, cpu_halt[0]);
-    }
-
-    if (hwdef->fd_base) {
-        /* there is zero or one floppy drive */
-        memset(fd, 0, sizeof(fd));
-        fd[0] = drive_get(IF_FLOPPY, 0, 0);
-        sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd,
-                          &fdc_tc);
-    } else {
-        fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1);
-    }
-
-    slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base,
-                     slavio_irq[30], fdc_tc);
-
-    if (drive_get_max_bus(IF_SCSI) > 0) {
-        fprintf(stderr, "qemu: too many SCSI bus\n");
-        exit(1);
-    }
-
-    esp_init(hwdef->esp_base, 2,
-             espdma_memory_read, espdma_memory_write,
-             espdma, espdma_irq, &esp_reset, &dma_enable);
-
-    qdev_connect_gpio_out(espdma, 0, esp_reset);
-    qdev_connect_gpio_out(espdma, 1, dma_enable);
-
-    if (hwdef->cs_base) {
-        sysbus_create_simple("SUNW,CS4231", hwdef->cs_base,
-                             slavio_irq[5]);
-    }
-
-    if (hwdef->dbri_base) {
-        /* ISDN chip with attached CS4215 audio codec */
-        /* prom space */
-        empty_slot_init(hwdef->dbri_base+0x1000, 0x30);
-        /* reg space */
-        empty_slot_init(hwdef->dbri_base+0x10000, 0x100);
-    }
-
-    if (hwdef->bpp_base) {
-        /* parallel port */
-        empty_slot_init(hwdef->bpp_base, 0x20);
-    }
-
-    kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
-                                    RAM_size);
-
-    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
-               boot_device, RAM_size, kernel_size, graphic_width,
-               graphic_height, graphic_depth, hwdef->nvram_machine_id,
-               "Sun4m");
-
-    if (hwdef->ecc_base)
-        ecc_init(hwdef->ecc_base, slavio_irq[28],
-                 hwdef->ecc_version);
-
-    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
-    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
-    if (kernel_cmdline) {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
-        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
-        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
-                       strlen(kernel_cmdline) + 1);
-    } else {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
-        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
-    }
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
-    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]);
-    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
-}
-
-enum {
-    ss2_id = 0,
-    ss5_id = 32,
-    vger_id,
-    lx_id,
-    ss4_id,
-    scls_id,
-    sbook_id,
-    ss10_id = 64,
-    ss20_id,
-    ss600mp_id,
-    ss1000_id = 96,
-    ss2000_id,
-};
-
-static const struct sun4m_hwdef sun4m_hwdefs[] = {
-    /* SS-5 */
-    {
-        .iommu_base   = 0x10000000,
-        .iommu_pad_base = 0x10004000,
-        .iommu_pad_len  = 0x0fffb000,
-        .tcx_base     = 0x50000000,
-        .cs_base      = 0x6c000000,
-        .slavio_base  = 0x70000000,
-        .ms_kb_base   = 0x71000000,
-        .serial_base  = 0x71100000,
-        .nvram_base   = 0x71200000,
-        .fd_base      = 0x71400000,
-        .counter_base = 0x71d00000,
-        .intctl_base  = 0x71e00000,
-        .idreg_base   = 0x78000000,
-        .dma_base     = 0x78400000,
-        .esp_base     = 0x78800000,
-        .le_base      = 0x78c00000,
-        .apc_base     = 0x6a000000,
-        .afx_base     = 0x6e000000,
-        .aux1_base    = 0x71900000,
-        .aux2_base    = 0x71910000,
-        .nvram_machine_id = 0x80,
-        .machine_id = ss5_id,
-        .iommu_version = 0x05000000,
-        .max_mem = 0x10000000,
-        .default_cpu_model = "Fujitsu MB86904",
-    },
-    /* SS-10 */
-    {
-        .iommu_base   = 0xfe0000000ULL,
-        .tcx_base     = 0xe20000000ULL,
-        .slavio_base  = 0xff0000000ULL,
-        .ms_kb_base   = 0xff1000000ULL,
-        .serial_base  = 0xff1100000ULL,
-        .nvram_base   = 0xff1200000ULL,
-        .fd_base      = 0xff1700000ULL,
-        .counter_base = 0xff1300000ULL,
-        .intctl_base  = 0xff1400000ULL,
-        .idreg_base   = 0xef0000000ULL,
-        .dma_base     = 0xef0400000ULL,
-        .esp_base     = 0xef0800000ULL,
-        .le_base      = 0xef0c00000ULL,
-        .apc_base     = 0xefa000000ULL, // XXX should not exist
-        .aux1_base    = 0xff1800000ULL,
-        .aux2_base    = 0xff1a01000ULL,
-        .ecc_base     = 0xf00000000ULL,
-        .ecc_version  = 0x10000000, // version 0, implementation 1
-        .nvram_machine_id = 0x72,
-        .machine_id = ss10_id,
-        .iommu_version = 0x03000000,
-        .max_mem = 0xf00000000ULL,
-        .default_cpu_model = "TI SuperSparc II",
-    },
-    /* SS-600MP */
-    {
-        .iommu_base   = 0xfe0000000ULL,
-        .tcx_base     = 0xe20000000ULL,
-        .slavio_base  = 0xff0000000ULL,
-        .ms_kb_base   = 0xff1000000ULL,
-        .serial_base  = 0xff1100000ULL,
-        .nvram_base   = 0xff1200000ULL,
-        .counter_base = 0xff1300000ULL,
-        .intctl_base  = 0xff1400000ULL,
-        .dma_base     = 0xef0081000ULL,
-        .esp_base     = 0xef0080000ULL,
-        .le_base      = 0xef0060000ULL,
-        .apc_base     = 0xefa000000ULL, // XXX should not exist
-        .aux1_base    = 0xff1800000ULL,
-        .aux2_base    = 0xff1a01000ULL, // XXX should not exist
-        .ecc_base     = 0xf00000000ULL,
-        .ecc_version  = 0x00000000, // version 0, implementation 0
-        .nvram_machine_id = 0x71,
-        .machine_id = ss600mp_id,
-        .iommu_version = 0x01000000,
-        .max_mem = 0xf00000000ULL,
-        .default_cpu_model = "TI SuperSparc II",
-    },
-    /* SS-20 */
-    {
-        .iommu_base   = 0xfe0000000ULL,
-        .tcx_base     = 0xe20000000ULL,
-        .slavio_base  = 0xff0000000ULL,
-        .ms_kb_base   = 0xff1000000ULL,
-        .serial_base  = 0xff1100000ULL,
-        .nvram_base   = 0xff1200000ULL,
-        .fd_base      = 0xff1700000ULL,
-        .counter_base = 0xff1300000ULL,
-        .intctl_base  = 0xff1400000ULL,
-        .idreg_base   = 0xef0000000ULL,
-        .dma_base     = 0xef0400000ULL,
-        .esp_base     = 0xef0800000ULL,
-        .le_base      = 0xef0c00000ULL,
-        .bpp_base     = 0xef4800000ULL,
-        .apc_base     = 0xefa000000ULL, // XXX should not exist
-        .aux1_base    = 0xff1800000ULL,
-        .aux2_base    = 0xff1a01000ULL,
-        .dbri_base    = 0xee0000000ULL,
-        .sx_base      = 0xf80000000ULL,
-        .vsimm        = {
-            {
-                .reg_base  = 0x9c000000ULL,
-                .vram_base = 0xfc000000ULL
-            }, {
-                .reg_base  = 0x90000000ULL,
-                .vram_base = 0xf0000000ULL
-            }, {
-                .reg_base  = 0x94000000ULL
-            }, {
-                .reg_base  = 0x98000000ULL
-            }
-        },
-        .ecc_base     = 0xf00000000ULL,
-        .ecc_version  = 0x20000000, // version 0, implementation 2
-        .nvram_machine_id = 0x72,
-        .machine_id = ss20_id,
-        .iommu_version = 0x13000000,
-        .max_mem = 0xf00000000ULL,
-        .default_cpu_model = "TI SuperSparc II",
-    },
-    /* Voyager */
-    {
-        .iommu_base   = 0x10000000,
-        .tcx_base     = 0x50000000,
-        .slavio_base  = 0x70000000,
-        .ms_kb_base   = 0x71000000,
-        .serial_base  = 0x71100000,
-        .nvram_base   = 0x71200000,
-        .fd_base      = 0x71400000,
-        .counter_base = 0x71d00000,
-        .intctl_base  = 0x71e00000,
-        .idreg_base   = 0x78000000,
-        .dma_base     = 0x78400000,
-        .esp_base     = 0x78800000,
-        .le_base      = 0x78c00000,
-        .apc_base     = 0x71300000, // pmc
-        .aux1_base    = 0x71900000,
-        .aux2_base    = 0x71910000,
-        .nvram_machine_id = 0x80,
-        .machine_id = vger_id,
-        .iommu_version = 0x05000000,
-        .max_mem = 0x10000000,
-        .default_cpu_model = "Fujitsu MB86904",
-    },
-    /* LX */
-    {
-        .iommu_base   = 0x10000000,
-        .iommu_pad_base = 0x10004000,
-        .iommu_pad_len  = 0x0fffb000,
-        .tcx_base     = 0x50000000,
-        .slavio_base  = 0x70000000,
-        .ms_kb_base   = 0x71000000,
-        .serial_base  = 0x71100000,
-        .nvram_base   = 0x71200000,
-        .fd_base      = 0x71400000,
-        .counter_base = 0x71d00000,
-        .intctl_base  = 0x71e00000,
-        .idreg_base   = 0x78000000,
-        .dma_base     = 0x78400000,
-        .esp_base     = 0x78800000,
-        .le_base      = 0x78c00000,
-        .aux1_base    = 0x71900000,
-        .aux2_base    = 0x71910000,
-        .nvram_machine_id = 0x80,
-        .machine_id = lx_id,
-        .iommu_version = 0x04000000,
-        .max_mem = 0x10000000,
-        .default_cpu_model = "TI MicroSparc I",
-    },
-    /* SS-4 */
-    {
-        .iommu_base   = 0x10000000,
-        .tcx_base     = 0x50000000,
-        .cs_base      = 0x6c000000,
-        .slavio_base  = 0x70000000,
-        .ms_kb_base   = 0x71000000,
-        .serial_base  = 0x71100000,
-        .nvram_base   = 0x71200000,
-        .fd_base      = 0x71400000,
-        .counter_base = 0x71d00000,
-        .intctl_base  = 0x71e00000,
-        .idreg_base   = 0x78000000,
-        .dma_base     = 0x78400000,
-        .esp_base     = 0x78800000,
-        .le_base      = 0x78c00000,
-        .apc_base     = 0x6a000000,
-        .aux1_base    = 0x71900000,
-        .aux2_base    = 0x71910000,
-        .nvram_machine_id = 0x80,
-        .machine_id = ss4_id,
-        .iommu_version = 0x05000000,
-        .max_mem = 0x10000000,
-        .default_cpu_model = "Fujitsu MB86904",
-    },
-    /* SPARCClassic */
-    {
-        .iommu_base   = 0x10000000,
-        .tcx_base     = 0x50000000,
-        .slavio_base  = 0x70000000,
-        .ms_kb_base   = 0x71000000,
-        .serial_base  = 0x71100000,
-        .nvram_base   = 0x71200000,
-        .fd_base      = 0x71400000,
-        .counter_base = 0x71d00000,
-        .intctl_base  = 0x71e00000,
-        .idreg_base   = 0x78000000,
-        .dma_base     = 0x78400000,
-        .esp_base     = 0x78800000,
-        .le_base      = 0x78c00000,
-        .apc_base     = 0x6a000000,
-        .aux1_base    = 0x71900000,
-        .aux2_base    = 0x71910000,
-        .nvram_machine_id = 0x80,
-        .machine_id = scls_id,
-        .iommu_version = 0x05000000,
-        .max_mem = 0x10000000,
-        .default_cpu_model = "TI MicroSparc I",
-    },
-    /* SPARCbook */
-    {
-        .iommu_base   = 0x10000000,
-        .tcx_base     = 0x50000000, // XXX
-        .slavio_base  = 0x70000000,
-        .ms_kb_base   = 0x71000000,
-        .serial_base  = 0x71100000,
-        .nvram_base   = 0x71200000,
-        .fd_base      = 0x71400000,
-        .counter_base = 0x71d00000,
-        .intctl_base  = 0x71e00000,
-        .idreg_base   = 0x78000000,
-        .dma_base     = 0x78400000,
-        .esp_base     = 0x78800000,
-        .le_base      = 0x78c00000,
-        .apc_base     = 0x6a000000,
-        .aux1_base    = 0x71900000,
-        .aux2_base    = 0x71910000,
-        .nvram_machine_id = 0x80,
-        .machine_id = sbook_id,
-        .iommu_version = 0x05000000,
-        .max_mem = 0x10000000,
-        .default_cpu_model = "TI MicroSparc I",
-    },
-};
-
-/* SPARCstation 5 hardware initialisation */
-static void ss5_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4m_hw_init(&sun4m_hwdefs[0], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-/* SPARCstation 10 hardware initialisation */
-static void ss10_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4m_hw_init(&sun4m_hwdefs[1], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-/* SPARCserver 600MP hardware initialisation */
-static void ss600mp_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4m_hw_init(&sun4m_hwdefs[2], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-/* SPARCstation 20 hardware initialisation */
-static void ss20_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4m_hw_init(&sun4m_hwdefs[3], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-/* SPARCstation Voyager hardware initialisation */
-static void vger_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4m_hw_init(&sun4m_hwdefs[4], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-/* SPARCstation LX hardware initialisation */
-static void ss_lx_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4m_hw_init(&sun4m_hwdefs[5], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-/* SPARCstation 4 hardware initialisation */
-static void ss4_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4m_hw_init(&sun4m_hwdefs[6], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-/* SPARCClassic hardware initialisation */
-static void scls_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4m_hw_init(&sun4m_hwdefs[7], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-/* SPARCbook hardware initialisation */
-static void sbook_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4m_hw_init(&sun4m_hwdefs[8], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-static QEMUMachine ss5_machine = {
-    .name = "SS-5",
-    .desc = "Sun4m platform, SPARCstation 5",
-    .init = ss5_init,
-    .block_default_type = IF_SCSI,
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine ss10_machine = {
-    .name = "SS-10",
-    .desc = "Sun4m platform, SPARCstation 10",
-    .init = ss10_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine ss600mp_machine = {
-    .name = "SS-600MP",
-    .desc = "Sun4m platform, SPARCserver 600MP",
-    .init = ss600mp_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine ss20_machine = {
-    .name = "SS-20",
-    .desc = "Sun4m platform, SPARCstation 20",
-    .init = ss20_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine voyager_machine = {
-    .name = "Voyager",
-    .desc = "Sun4m platform, SPARCstation Voyager",
-    .init = vger_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine ss_lx_machine = {
-    .name = "LX",
-    .desc = "Sun4m platform, SPARCstation LX",
-    .init = ss_lx_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine ss4_machine = {
-    .name = "SS-4",
-    .desc = "Sun4m platform, SPARCstation 4",
-    .init = ss4_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine scls_machine = {
-    .name = "SPARCClassic",
-    .desc = "Sun4m platform, SPARCClassic",
-    .init = scls_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine sbook_machine = {
-    .name = "SPARCbook",
-    .desc = "Sun4m platform, SPARCbook",
-    .init = sbook_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static const struct sun4d_hwdef sun4d_hwdefs[] = {
-    /* SS-1000 */
-    {
-        .iounit_bases   = {
-            0xfe0200000ULL,
-            0xfe1200000ULL,
-            0xfe2200000ULL,
-            0xfe3200000ULL,
-            -1,
-        },
-        .tcx_base     = 0x820000000ULL,
-        .slavio_base  = 0xf00000000ULL,
-        .ms_kb_base   = 0xf00240000ULL,
-        .serial_base  = 0xf00200000ULL,
-        .nvram_base   = 0xf00280000ULL,
-        .counter_base = 0xf00300000ULL,
-        .espdma_base  = 0x800081000ULL,
-        .esp_base     = 0x800080000ULL,
-        .ledma_base   = 0x800040000ULL,
-        .le_base      = 0x800060000ULL,
-        .sbi_base     = 0xf02800000ULL,
-        .nvram_machine_id = 0x80,
-        .machine_id = ss1000_id,
-        .iounit_version = 0x03000000,
-        .max_mem = 0xf00000000ULL,
-        .default_cpu_model = "TI SuperSparc II",
-    },
-    /* SS-2000 */
-    {
-        .iounit_bases   = {
-            0xfe0200000ULL,
-            0xfe1200000ULL,
-            0xfe2200000ULL,
-            0xfe3200000ULL,
-            0xfe4200000ULL,
-        },
-        .tcx_base     = 0x820000000ULL,
-        .slavio_base  = 0xf00000000ULL,
-        .ms_kb_base   = 0xf00240000ULL,
-        .serial_base  = 0xf00200000ULL,
-        .nvram_base   = 0xf00280000ULL,
-        .counter_base = 0xf00300000ULL,
-        .espdma_base  = 0x800081000ULL,
-        .esp_base     = 0x800080000ULL,
-        .ledma_base   = 0x800040000ULL,
-        .le_base      = 0x800060000ULL,
-        .sbi_base     = 0xf02800000ULL,
-        .nvram_machine_id = 0x80,
-        .machine_id = ss2000_id,
-        .iounit_version = 0x03000000,
-        .max_mem = 0xf00000000ULL,
-        .default_cpu_model = "TI SuperSparc II",
-    },
-};
-
-static DeviceState *sbi_init(hwaddr addr, qemu_irq **parent_irq)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    unsigned int i;
-
-    dev = qdev_create(NULL, "sbi");
-    qdev_init_nofail(dev);
-
-    s = SYS_BUS_DEVICE(dev);
-
-    for (i = 0; i < MAX_CPUS; i++) {
-        sysbus_connect_irq(s, i, *parent_irq[i]);
-    }
-
-    sysbus_mmio_map(s, 0, addr);
-
-    return dev;
-}
-
-static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, 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)
-{
-    unsigned int i;
-    void *iounits[MAX_IOUNITS], *espdma, *ledma, *nvram;
-    qemu_irq *cpu_irqs[MAX_CPUS], sbi_irq[32], sbi_cpu_irq[MAX_CPUS],
-        espdma_irq, ledma_irq;
-    qemu_irq esp_reset, dma_enable;
-    unsigned long kernel_size;
-    void *fw_cfg;
-    DeviceState *dev;
-
-    /* init CPUs */
-    if (!cpu_model)
-        cpu_model = hwdef->default_cpu_model;
-
-    for(i = 0; i < smp_cpus; i++) {
-        cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]);
-    }
-
-    for (i = smp_cpus; i < MAX_CPUS; i++)
-        cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS);
-
-    /* set up devices */
-    ram_init(0, RAM_size, hwdef->max_mem);
-
-    prom_init(hwdef->slavio_base, bios_name);
-
-    dev = sbi_init(hwdef->sbi_base, cpu_irqs);
-
-    for (i = 0; i < 32; i++) {
-        sbi_irq[i] = qdev_get_gpio_in(dev, i);
-    }
-    for (i = 0; i < MAX_CPUS; i++) {
-        sbi_cpu_irq[i] = qdev_get_gpio_in(dev, 32 + i);
-    }
-
-    for (i = 0; i < MAX_IOUNITS; i++)
-        if (hwdef->iounit_bases[i] != (hwaddr)-1)
-            iounits[i] = iommu_init(hwdef->iounit_bases[i],
-                                    hwdef->iounit_version,
-                                    sbi_irq[0]);
-
-    espdma = sparc32_dma_init(hwdef->espdma_base, sbi_irq[3],
-                              iounits[0], &espdma_irq, 0);
-
-    /* should be lebuffer instead */
-    ledma = sparc32_dma_init(hwdef->ledma_base, sbi_irq[4],
-                             iounits[0], &ledma_irq, 0);
-
-    if (graphic_depth != 8 && graphic_depth != 24) {
-        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
-        exit (1);
-    }
-    tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
-             graphic_depth);
-
-    lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
-
-    nvram = m48t59_init(sbi_irq[0], hwdef->nvram_base, 0, 0x2000, 8);
-
-    slavio_timer_init_all(hwdef->counter_base, sbi_irq[10], sbi_cpu_irq, smp_cpus);
-
-    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, sbi_irq[12],
-                              display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
-    /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
-       Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
-    escc_init(hwdef->serial_base, sbi_irq[12], sbi_irq[12],
-              serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
-
-    if (drive_get_max_bus(IF_SCSI) > 0) {
-        fprintf(stderr, "qemu: too many SCSI bus\n");
-        exit(1);
-    }
-
-    esp_init(hwdef->esp_base, 2,
-             espdma_memory_read, espdma_memory_write,
-             espdma, espdma_irq, &esp_reset, &dma_enable);
-
-    qdev_connect_gpio_out(espdma, 0, esp_reset);
-    qdev_connect_gpio_out(espdma, 1, dma_enable);
-
-    kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
-                                    RAM_size);
-
-    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
-               boot_device, RAM_size, kernel_size, graphic_width,
-               graphic_height, graphic_depth, hwdef->nvram_machine_id,
-               "Sun4d");
-
-    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
-    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
-    if (kernel_cmdline) {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
-        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
-    } else {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
-    }
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
-    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]);
-    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
-}
-
-/* SPARCserver 1000 hardware initialisation */
-static void ss1000_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4d_hw_init(&sun4d_hwdefs[0], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-/* SPARCcenter 2000 hardware initialisation */
-static void ss2000_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4d_hw_init(&sun4d_hwdefs[1], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-static QEMUMachine ss1000_machine = {
-    .name = "SS-1000",
-    .desc = "Sun4d platform, SPARCserver 1000",
-    .init = ss1000_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 8,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine ss2000_machine = {
-    .name = "SS-2000",
-    .desc = "Sun4d platform, SPARCcenter 2000",
-    .init = ss2000_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 20,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static const struct sun4c_hwdef sun4c_hwdefs[] = {
-    /* SS-2 */
-    {
-        .iommu_base   = 0xf8000000,
-        .tcx_base     = 0xfe000000,
-        .slavio_base  = 0xf6000000,
-        .intctl_base  = 0xf5000000,
-        .counter_base = 0xf3000000,
-        .ms_kb_base   = 0xf0000000,
-        .serial_base  = 0xf1000000,
-        .nvram_base   = 0xf2000000,
-        .fd_base      = 0xf7200000,
-        .dma_base     = 0xf8400000,
-        .esp_base     = 0xf8800000,
-        .le_base      = 0xf8c00000,
-        .aux1_base    = 0xf7400003,
-        .nvram_machine_id = 0x55,
-        .machine_id = ss2_id,
-        .max_mem = 0x10000000,
-        .default_cpu_model = "Cypress CY7C601",
-    },
-};
-
-static DeviceState *sun4c_intctl_init(hwaddr addr,
-                                      qemu_irq *parent_irq)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    unsigned int i;
-
-    dev = qdev_create(NULL, "sun4c_intctl");
-    qdev_init_nofail(dev);
-
-    s = SYS_BUS_DEVICE(dev);
-
-    for (i = 0; i < MAX_PILS; i++) {
-        sysbus_connect_irq(s, i, parent_irq[i]);
-    }
-    sysbus_mmio_map(s, 0, addr);
-
-    return dev;
-}
-
-static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, 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)
-{
-    void *iommu, *espdma, *ledma, *nvram;
-    qemu_irq *cpu_irqs, slavio_irq[8], espdma_irq, ledma_irq;
-    qemu_irq esp_reset, dma_enable;
-    qemu_irq fdc_tc;
-    unsigned long kernel_size;
-    DriveInfo *fd[MAX_FD];
-    void *fw_cfg;
-    DeviceState *dev;
-    unsigned int i;
-
-    /* init CPU */
-    if (!cpu_model)
-        cpu_model = hwdef->default_cpu_model;
-
-    cpu_devinit(cpu_model, 0, hwdef->slavio_base, &cpu_irqs);
-
-    /* set up devices */
-    ram_init(0, RAM_size, hwdef->max_mem);
-
-    prom_init(hwdef->slavio_base, bios_name);
-
-    dev = sun4c_intctl_init(hwdef->intctl_base, cpu_irqs);
-
-    for (i = 0; i < 8; i++) {
-        slavio_irq[i] = qdev_get_gpio_in(dev, i);
-    }
-
-    iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version,
-                       slavio_irq[1]);
-
-    espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[2],
-                              iommu, &espdma_irq, 0);
-
-    ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
-                             slavio_irq[3], iommu, &ledma_irq, 1);
-
-    if (graphic_depth != 8 && graphic_depth != 24) {
-        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
-        exit (1);
-    }
-    tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
-             graphic_depth);
-
-    lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
-
-    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x800, 2);
-
-    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[1],
-                              display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
-    /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
-       Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
-    escc_init(hwdef->serial_base, slavio_irq[1],
-              slavio_irq[1], serial_hds[0], serial_hds[1],
-              ESCC_CLOCK, 1);
-
-    if (hwdef->fd_base != (hwaddr)-1) {
-        /* there is zero or one floppy drive */
-        memset(fd, 0, sizeof(fd));
-        fd[0] = drive_get(IF_FLOPPY, 0, 0);
-        sun4m_fdctrl_init(slavio_irq[1], hwdef->fd_base, fd,
-                          &fdc_tc);
-    } else {
-        fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1);
-    }
-
-    slavio_misc_init(0, hwdef->aux1_base, 0, slavio_irq[1], fdc_tc);
-
-    if (drive_get_max_bus(IF_SCSI) > 0) {
-        fprintf(stderr, "qemu: too many SCSI bus\n");
-        exit(1);
-    }
-
-    esp_init(hwdef->esp_base, 2,
-             espdma_memory_read, espdma_memory_write,
-             espdma, espdma_irq, &esp_reset, &dma_enable);
-
-    qdev_connect_gpio_out(espdma, 0, esp_reset);
-    qdev_connect_gpio_out(espdma, 1, dma_enable);
-
-    kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
-                                    RAM_size);
-
-    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
-               boot_device, RAM_size, kernel_size, graphic_width,
-               graphic_height, graphic_depth, hwdef->nvram_machine_id,
-               "Sun4c");
-
-    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
-    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
-    if (kernel_cmdline) {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
-        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
-    } else {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
-    }
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
-    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]);
-    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
-}
-
-/* SPARCstation 2 hardware initialisation */
-static void ss2_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_device;
-    sun4c_hw_init(&sun4c_hwdefs[0], RAM_size, boot_device, kernel_filename,
-                  kernel_cmdline, initrd_filename, cpu_model);
-}
-
-static QEMUMachine ss2_machine = {
-    .name = "SS-2",
-    .desc = "Sun4c platform, SPARCstation 2",
-    .init = ss2_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void sun4m_register_types(void)
-{
-    type_register_static(&idreg_info);
-    type_register_static(&afx_info);
-    type_register_static(&prom_info);
-    type_register_static(&ram_info);
-}
-
-static void ss2_machine_init(void)
-{
-    qemu_register_machine(&ss5_machine);
-    qemu_register_machine(&ss10_machine);
-    qemu_register_machine(&ss600mp_machine);
-    qemu_register_machine(&ss20_machine);
-    qemu_register_machine(&voyager_machine);
-    qemu_register_machine(&ss_lx_machine);
-    qemu_register_machine(&ss4_machine);
-    qemu_register_machine(&scls_machine);
-    qemu_register_machine(&sbook_machine);
-    qemu_register_machine(&ss1000_machine);
-    qemu_register_machine(&ss2000_machine);
-    qemu_register_machine(&ss2_machine);
-}
-
-type_init(sun4m_register_types)
-machine_init(ss2_machine_init);
diff --git a/hw/sun4u.c b/hw/sun4u.c
deleted file mode 100644 (file)
index 51ffa1c..0000000
+++ /dev/null
@@ -1,1014 +0,0 @@
-/*
- * QEMU Sun4u/Sun4v System Emulator
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/apb_pci.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/nvram.h"
-#include "hw/fdc.h"
-#include "net/net.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/firmware_abi.h"
-#include "hw/fw_cfg.h"
-#include "hw/sysbus.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_IRQ
-//#define DEBUG_EBUS
-//#define DEBUG_TIMER
-
-#ifdef DEBUG_IRQ
-#define CPUIRQ_DPRINTF(fmt, ...)                                \
-    do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define CPUIRQ_DPRINTF(fmt, ...)
-#endif
-
-#ifdef DEBUG_EBUS
-#define EBUS_DPRINTF(fmt, ...)                                  \
-    do { printf("EBUS: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define EBUS_DPRINTF(fmt, ...)
-#endif
-
-#ifdef DEBUG_TIMER
-#define TIMER_DPRINTF(fmt, ...)                                  \
-    do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define TIMER_DPRINTF(fmt, ...)
-#endif
-
-#define KERNEL_LOAD_ADDR     0x00404000
-#define CMDLINE_ADDR         0x003ff000
-#define PROM_SIZE_MAX        (4 * 1024 * 1024)
-#define PROM_VADDR           0x000ffd00000ULL
-#define APB_SPECIAL_BASE     0x1fe00000000ULL
-#define APB_MEM_BASE         0x1ff00000000ULL
-#define APB_PCI_IO_BASE      (APB_SPECIAL_BASE + 0x02000000ULL)
-#define PROM_FILENAME        "openbios-sparc64"
-#define NVRAM_SIZE           0x2000
-#define MAX_IDE_BUS          2
-#define BIOS_CFG_IOPORT      0x510
-#define FW_CFG_SPARC64_WIDTH (FW_CFG_ARCH_LOCAL + 0x00)
-#define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
-#define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
-
-#define IVEC_MAX             0x30
-
-#define TICK_MAX             0x7fffffffffffffffULL
-
-struct hwdef {
-    const char * const default_cpu_model;
-    uint16_t machine_id;
-    uint64_t prom_addr;
-    uint64_t console_serial_base;
-};
-
-typedef struct EbusState {
-    PCIDevice pci_dev;
-    MemoryRegion bar0;
-    MemoryRegion bar1;
-} EbusState;
-
-int DMA_get_channel_mode (int nchan)
-{
-    return 0;
-}
-int DMA_read_memory (int nchan, void *buf, int pos, int size)
-{
-    return 0;
-}
-int DMA_write_memory (int nchan, void *buf, int pos, int size)
-{
-    return 0;
-}
-void DMA_hold_DREQ (int nchan) {}
-void DMA_release_DREQ (int nchan) {}
-void DMA_schedule(int nchan) {}
-
-void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit)
-{
-}
-
-void DMA_register_channel (int nchan,
-                           DMA_transfer_handler transfer_handler,
-                           void *opaque)
-{
-}
-
-static int fw_cfg_boot_set(void *opaque, const char *boot_device)
-{
-    fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
-    return 0;
-}
-
-static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size,
-                                  const char *arch, ram_addr_t RAM_size,
-                                  const char *boot_devices,
-                                  uint32_t kernel_image, uint32_t kernel_size,
-                                  const char *cmdline,
-                                  uint32_t initrd_image, uint32_t initrd_size,
-                                  uint32_t NVRAM_image,
-                                  int width, int height, int depth,
-                                  const uint8_t *macaddr)
-{
-    unsigned int i;
-    uint32_t start, end;
-    uint8_t image[0x1ff0];
-    struct OpenBIOS_nvpart_v1 *part_header;
-
-    memset(image, '\0', sizeof(image));
-
-    start = 0;
-
-    // OpenBIOS nvram variables
-    // Variable partition
-    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
-    part_header->signature = OPENBIOS_PART_SYSTEM;
-    pstrcpy(part_header->name, sizeof(part_header->name), "system");
-
-    end = start + sizeof(struct OpenBIOS_nvpart_v1);
-    for (i = 0; i < nb_prom_envs; i++)
-        end = OpenBIOS_set_var(image, end, prom_envs[i]);
-
-    // End marker
-    image[end++] = '\0';
-
-    end = start + ((end - start + 15) & ~15);
-    OpenBIOS_finish_partition(part_header, end - start);
-
-    // free partition
-    start = end;
-    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
-    part_header->signature = OPENBIOS_PART_FREE;
-    pstrcpy(part_header->name, sizeof(part_header->name), "free");
-
-    end = 0x1fd0;
-    OpenBIOS_finish_partition(part_header, end - start);
-
-    Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80);
-
-    for (i = 0; i < sizeof(image); i++)
-        m48t59_write(nvram, i, image[i]);
-
-    return 0;
-}
-
-static uint64_t sun4u_load_kernel(const char *kernel_filename,
-                                  const char *initrd_filename,
-                                  ram_addr_t RAM_size, uint64_t *initrd_size,
-                                  uint64_t *initrd_addr, uint64_t *kernel_addr,
-                                  uint64_t *kernel_entry)
-{
-    int linux_boot;
-    unsigned int i;
-    long kernel_size;
-    uint8_t *ptr;
-    uint64_t kernel_top;
-
-    linux_boot = (kernel_filename != NULL);
-
-    kernel_size = 0;
-    if (linux_boot) {
-        int bswap_needed;
-
-#ifdef BSWAP_NEEDED
-        bswap_needed = 1;
-#else
-        bswap_needed = 0;
-#endif
-        kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry,
-                               kernel_addr, &kernel_top, 1, ELF_MACHINE, 0);
-        if (kernel_size < 0) {
-            *kernel_addr = KERNEL_LOAD_ADDR;
-            *kernel_entry = KERNEL_LOAD_ADDR;
-            kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
-                                    RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
-                                    TARGET_PAGE_SIZE);
-        }
-        if (kernel_size < 0) {
-            kernel_size = load_image_targphys(kernel_filename,
-                                              KERNEL_LOAD_ADDR,
-                                              RAM_size - KERNEL_LOAD_ADDR);
-        }
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-        /* load initrd above kernel */
-        *initrd_size = 0;
-        if (initrd_filename) {
-            *initrd_addr = TARGET_PAGE_ALIGN(kernel_top);
-
-            *initrd_size = load_image_targphys(initrd_filename,
-                                               *initrd_addr,
-                                               RAM_size - *initrd_addr);
-            if ((int)*initrd_size < 0) {
-                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                        initrd_filename);
-                exit(1);
-            }
-        }
-        if (*initrd_size > 0) {
-            for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
-                ptr = rom_ptr(*kernel_addr + i);
-                if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
-                    stl_p(ptr + 24, *initrd_addr + *kernel_addr);
-                    stl_p(ptr + 28, *initrd_size);
-                    break;
-                }
-            }
-        }
-    }
-    return kernel_size;
-}
-
-void cpu_check_irqs(CPUSPARCState *env)
-{
-    uint32_t pil = env->pil_in |
-                  (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER));
-
-    /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */
-    if (env->ivec_status & 0x20) {
-        return;
-    }
-    /* check if TM or SM in SOFTINT are set
-       setting these also causes interrupt 14 */
-    if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) {
-        pil |= 1 << 14;
-    }
-
-    /* The bit corresponding to psrpil is (1<< psrpil), the next bit
-       is (2 << psrpil). */
-    if (pil < (2 << env->psrpil)){
-        if (env->interrupt_request & CPU_INTERRUPT_HARD) {
-            CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
-                           env->interrupt_index);
-            env->interrupt_index = 0;
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-        }
-        return;
-    }
-
-    if (cpu_interrupts_enabled(env)) {
-
-        unsigned int i;
-
-        for (i = 15; i > env->psrpil; i--) {
-            if (pil & (1 << i)) {
-                int old_interrupt = env->interrupt_index;
-                int new_interrupt = TT_EXTINT | i;
-
-                if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt
-                  && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) {
-                    CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d "
-                                   "current %x >= pending %x\n",
-                                   env->tl, cpu_tsptr(env)->tt, new_interrupt);
-                } else if (old_interrupt != new_interrupt) {
-                    env->interrupt_index = new_interrupt;
-                    CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i,
-                                   old_interrupt, new_interrupt);
-                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
-                }
-                break;
-            }
-        }
-    } else if (env->interrupt_request & CPU_INTERRUPT_HARD) {
-        CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
-                       "current interrupt %x\n",
-                       pil, env->pil_in, env->softint, env->interrupt_index);
-        env->interrupt_index = 0;
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
-}
-
-static void cpu_kick_irq(SPARCCPU *cpu)
-{
-    CPUSPARCState *env = &cpu->env;
-
-    env->halted = 0;
-    cpu_check_irqs(env);
-    qemu_cpu_kick(CPU(cpu));
-}
-
-static void cpu_set_ivec_irq(void *opaque, int irq, int level)
-{
-    SPARCCPU *cpu = opaque;
-    CPUSPARCState *env = &cpu->env;
-
-    if (level) {
-        if (!(env->ivec_status & 0x20)) {
-            CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
-            env->halted = 0;
-            env->interrupt_index = TT_IVEC;
-            env->ivec_status |= 0x20;
-            env->ivec_data[0] = (0x1f << 6) | irq;
-            env->ivec_data[1] = 0;
-            env->ivec_data[2] = 0;
-            cpu_interrupt(env, CPU_INTERRUPT_HARD);
-        }
-    } else {
-        if (env->ivec_status & 0x20) {
-            CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
-            env->ivec_status &= ~0x20;
-            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-        }
-    }
-}
-
-typedef struct ResetData {
-    SPARCCPU *cpu;
-    uint64_t prom_addr;
-} ResetData;
-
-void cpu_put_timer(QEMUFile *f, CPUTimer *s)
-{
-    qemu_put_be32s(f, &s->frequency);
-    qemu_put_be32s(f, &s->disabled);
-    qemu_put_be64s(f, &s->disabled_mask);
-    qemu_put_sbe64s(f, &s->clock_offset);
-
-    qemu_put_timer(f, s->qtimer);
-}
-
-void cpu_get_timer(QEMUFile *f, CPUTimer *s)
-{
-    qemu_get_be32s(f, &s->frequency);
-    qemu_get_be32s(f, &s->disabled);
-    qemu_get_be64s(f, &s->disabled_mask);
-    qemu_get_sbe64s(f, &s->clock_offset);
-
-    qemu_get_timer(f, s->qtimer);
-}
-
-static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu,
-                                  QEMUBHFunc *cb, uint32_t frequency,
-                                  uint64_t disabled_mask)
-{
-    CPUTimer *timer = g_malloc0(sizeof (CPUTimer));
-
-    timer->name = name;
-    timer->frequency = frequency;
-    timer->disabled_mask = disabled_mask;
-
-    timer->disabled = 1;
-    timer->clock_offset = qemu_get_clock_ns(vm_clock);
-
-    timer->qtimer = qemu_new_timer_ns(vm_clock, cb, cpu);
-
-    return timer;
-}
-
-static void cpu_timer_reset(CPUTimer *timer)
-{
-    timer->disabled = 1;
-    timer->clock_offset = qemu_get_clock_ns(vm_clock);
-
-    qemu_del_timer(timer->qtimer);
-}
-
-static void main_cpu_reset(void *opaque)
-{
-    ResetData *s = (ResetData *)opaque;
-    CPUSPARCState *env = &s->cpu->env;
-    static unsigned int nr_resets;
-
-    cpu_reset(CPU(s->cpu));
-
-    cpu_timer_reset(env->tick);
-    cpu_timer_reset(env->stick);
-    cpu_timer_reset(env->hstick);
-
-    env->gregs[1] = 0; // Memory start
-    env->gregs[2] = ram_size; // Memory size
-    env->gregs[3] = 0; // Machine description XXX
-    if (nr_resets++ == 0) {
-        /* Power on reset */
-        env->pc = s->prom_addr + 0x20ULL;
-    } else {
-        env->pc = s->prom_addr + 0x40ULL;
-    }
-    env->npc = env->pc + 4;
-}
-
-static void tick_irq(void *opaque)
-{
-    SPARCCPU *cpu = opaque;
-    CPUSPARCState *env = &cpu->env;
-
-    CPUTimer* timer = env->tick;
-
-    if (timer->disabled) {
-        CPUIRQ_DPRINTF("tick_irq: softint disabled\n");
-        return;
-    } else {
-        CPUIRQ_DPRINTF("tick: fire\n");
-    }
-
-    env->softint |= SOFTINT_TIMER;
-    cpu_kick_irq(cpu);
-}
-
-static void stick_irq(void *opaque)
-{
-    SPARCCPU *cpu = opaque;
-    CPUSPARCState *env = &cpu->env;
-
-    CPUTimer* timer = env->stick;
-
-    if (timer->disabled) {
-        CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
-        return;
-    } else {
-        CPUIRQ_DPRINTF("stick: fire\n");
-    }
-
-    env->softint |= SOFTINT_STIMER;
-    cpu_kick_irq(cpu);
-}
-
-static void hstick_irq(void *opaque)
-{
-    SPARCCPU *cpu = opaque;
-    CPUSPARCState *env = &cpu->env;
-
-    CPUTimer* timer = env->hstick;
-
-    if (timer->disabled) {
-        CPUIRQ_DPRINTF("hstick_irq: softint disabled\n");
-        return;
-    } else {
-        CPUIRQ_DPRINTF("hstick: fire\n");
-    }
-
-    env->softint |= SOFTINT_STIMER;
-    cpu_kick_irq(cpu);
-}
-
-static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
-{
-    return muldiv64(cpu_ticks, get_ticks_per_sec(), frequency);
-}
-
-static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
-{
-    return muldiv64(timer_ticks, frequency, get_ticks_per_sec());
-}
-
-void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
-{
-    uint64_t real_count = count & ~timer->disabled_mask;
-    uint64_t disabled_bit = count & timer->disabled_mask;
-
-    int64_t vm_clock_offset = qemu_get_clock_ns(vm_clock) -
-                    cpu_to_timer_ticks(real_count, timer->frequency);
-
-    TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n",
-                  timer->name, real_count,
-                  timer->disabled?"disabled":"enabled", timer);
-
-    timer->disabled = disabled_bit ? 1 : 0;
-    timer->clock_offset = vm_clock_offset;
-}
-
-uint64_t cpu_tick_get_count(CPUTimer *timer)
-{
-    uint64_t real_count = timer_to_cpu_ticks(
-                    qemu_get_clock_ns(vm_clock) - timer->clock_offset,
-                    timer->frequency);
-
-    TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n",
-           timer->name, real_count,
-           timer->disabled?"disabled":"enabled", timer);
-
-    if (timer->disabled)
-        real_count |= timer->disabled_mask;
-
-    return real_count;
-}
-
-void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
-{
-    int64_t now = qemu_get_clock_ns(vm_clock);
-
-    uint64_t real_limit = limit & ~timer->disabled_mask;
-    timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
-
-    int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
-                    timer->clock_offset;
-
-    if (expires < now) {
-        expires = now + 1;
-    }
-
-    TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p "
-                  "called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n",
-                  timer->name, real_limit,
-                  timer->disabled?"disabled":"enabled",
-                  timer, limit,
-                  timer_to_cpu_ticks(now - timer->clock_offset,
-                                     timer->frequency),
-                  timer_to_cpu_ticks(expires - now, timer->frequency));
-
-    if (!real_limit) {
-        TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n",
-                timer->name);
-        qemu_del_timer(timer->qtimer);
-    } else if (timer->disabled) {
-        qemu_del_timer(timer->qtimer);
-    } else {
-        qemu_mod_timer(timer->qtimer, expires);
-    }
-}
-
-static void isa_irq_handler(void *opaque, int n, int level)
-{
-    static const int isa_irq_to_ivec[16] = {
-        [1] = 0x29, /* keyboard */
-        [4] = 0x2b, /* serial */
-        [6] = 0x27, /* floppy */
-        [7] = 0x22, /* parallel */
-        [12] = 0x2a, /* mouse */
-    };
-    qemu_irq *irqs = opaque;
-    int ivec;
-
-    assert(n < 16);
-    ivec = isa_irq_to_ivec[n];
-    EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec);
-    if (ivec) {
-        qemu_set_irq(irqs[ivec], level);
-    }
-}
-
-/* EBUS (Eight bit bus) bridge */
-static ISABus *
-pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs)
-{
-    qemu_irq *isa_irq;
-    PCIDevice *pci_dev;
-    ISABus *isa_bus;
-
-    pci_dev = pci_create_simple(bus, devfn, "ebus");
-    isa_bus = DO_UPCAST(ISABus, qbus,
-                        qdev_get_child_bus(&pci_dev->qdev, "isa.0"));
-    isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
-    isa_bus_irqs(isa_bus, isa_irq);
-    return isa_bus;
-}
-
-static int
-pci_ebus_init1(PCIDevice *pci_dev)
-{
-    EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev);
-
-    isa_bus_new(&pci_dev->qdev, pci_address_space_io(pci_dev));
-
-    pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
-    pci_dev->config[0x05] = 0x00;
-    pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
-    pci_dev->config[0x07] = 0x03; // status = medium devsel
-    pci_dev->config[0x09] = 0x00; // programming i/f
-    pci_dev->config[0x0D] = 0x0a; // latency_timer
-
-    isa_mmio_setup(&s->bar0, 0x1000000);
-    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
-    isa_mmio_setup(&s->bar1, 0x800000);
-    pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1);
-    return 0;
-}
-
-static void ebus_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = pci_ebus_init1;
-    k->vendor_id = PCI_VENDOR_ID_SUN;
-    k->device_id = PCI_DEVICE_ID_SUN_EBUS;
-    k->revision = 0x01;
-    k->class_id = PCI_CLASS_BRIDGE_OTHER;
-}
-
-static const TypeInfo ebus_info = {
-    .name          = "ebus",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(EbusState),
-    .class_init    = ebus_class_init,
-};
-
-typedef struct PROMState {
-    SysBusDevice busdev;
-    MemoryRegion prom;
-} PROMState;
-
-static uint64_t translate_prom_address(void *opaque, uint64_t addr)
-{
-    hwaddr *base_addr = (hwaddr *)opaque;
-    return addr + *base_addr - PROM_VADDR;
-}
-
-/* Boot PROM (OpenBIOS) */
-static void prom_init(hwaddr addr, const char *bios_name)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    char *filename;
-    int ret;
-
-    dev = qdev_create(NULL, "openprom");
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-
-    sysbus_mmio_map(s, 0, addr);
-
-    /* load boot prom */
-    if (bios_name == NULL) {
-        bios_name = PROM_FILENAME;
-    }
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    if (filename) {
-        ret = load_elf(filename, translate_prom_address, &addr,
-                       NULL, NULL, NULL, 1, ELF_MACHINE, 0);
-        if (ret < 0 || ret > PROM_SIZE_MAX) {
-            ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
-        }
-        g_free(filename);
-    } else {
-        ret = -1;
-    }
-    if (ret < 0 || ret > PROM_SIZE_MAX) {
-        fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name);
-        exit(1);
-    }
-}
-
-static int prom_init1(SysBusDevice *dev)
-{
-    PROMState *s = FROM_SYSBUS(PROMState, dev);
-
-    memory_region_init_ram(&s->prom, "sun4u.prom", PROM_SIZE_MAX);
-    vmstate_register_ram_global(&s->prom);
-    memory_region_set_readonly(&s->prom, true);
-    sysbus_init_mmio(dev, &s->prom);
-    return 0;
-}
-
-static Property prom_properties[] = {
-    {/* end of property list */},
-};
-
-static void prom_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = prom_init1;
-    dc->props = prom_properties;
-}
-
-static const TypeInfo prom_info = {
-    .name          = "openprom",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PROMState),
-    .class_init    = prom_class_init,
-};
-
-
-typedef struct RamDevice
-{
-    SysBusDevice busdev;
-    MemoryRegion ram;
-    uint64_t size;
-} RamDevice;
-
-/* System RAM */
-static int ram_init1(SysBusDevice *dev)
-{
-    RamDevice *d = FROM_SYSBUS(RamDevice, dev);
-
-    memory_region_init_ram(&d->ram, "sun4u.ram", d->size);
-    vmstate_register_ram_global(&d->ram);
-    sysbus_init_mmio(dev, &d->ram);
-    return 0;
-}
-
-static void ram_init(hwaddr addr, ram_addr_t RAM_size)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    RamDevice *d;
-
-    /* allocate RAM */
-    dev = qdev_create(NULL, "memory");
-    s = SYS_BUS_DEVICE(dev);
-
-    d = FROM_SYSBUS(RamDevice, s);
-    d->size = RAM_size;
-    qdev_init_nofail(dev);
-
-    sysbus_mmio_map(s, 0, addr);
-}
-
-static Property ram_properties[] = {
-    DEFINE_PROP_UINT64("size", RamDevice, size, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ram_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = ram_init1;
-    dc->props = ram_properties;
-}
-
-static const TypeInfo ram_info = {
-    .name          = "memory",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(RamDevice),
-    .class_init    = ram_class_init,
-};
-
-static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
-{
-    SPARCCPU *cpu;
-    CPUSPARCState *env;
-    ResetData *reset_info;
-
-    uint32_t   tick_frequency = 100*1000000;
-    uint32_t  stick_frequency = 100*1000000;
-    uint32_t hstick_frequency = 100*1000000;
-
-    if (cpu_model == NULL) {
-        cpu_model = hwdef->default_cpu_model;
-    }
-    cpu = cpu_sparc_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "Unable to find Sparc CPU definition\n");
-        exit(1);
-    }
-    env = &cpu->env;
-
-    env->tick = cpu_timer_create("tick", cpu, tick_irq,
-                                  tick_frequency, TICK_NPT_MASK);
-
-    env->stick = cpu_timer_create("stick", cpu, stick_irq,
-                                   stick_frequency, TICK_INT_DIS);
-
-    env->hstick = cpu_timer_create("hstick", cpu, hstick_irq,
-                                    hstick_frequency, TICK_INT_DIS);
-
-    reset_info = g_malloc0(sizeof(ResetData));
-    reset_info->cpu = cpu;
-    reset_info->prom_addr = hwdef->prom_addr;
-    qemu_register_reset(main_cpu_reset, reset_info);
-
-    return cpu;
-}
-
-static void sun4uv_init(MemoryRegion *address_space_mem,
-                        ram_addr_t RAM_size,
-                        const char *boot_devices,
-                        const char *kernel_filename, const char *kernel_cmdline,
-                        const char *initrd_filename, const char *cpu_model,
-                        const struct hwdef *hwdef)
-{
-    SPARCCPU *cpu;
-    M48t59State *nvram;
-    unsigned int i;
-    uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry;
-    PCIBus *pci_bus, *pci_bus2, *pci_bus3;
-    ISABus *isa_bus;
-    qemu_irq *ivec_irqs, *pbm_irqs;
-    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
-    DriveInfo *fd[MAX_FD];
-    void *fw_cfg;
-
-    /* init CPUs */
-    cpu = cpu_devinit(cpu_model, hwdef);
-
-    /* set up devices */
-    ram_init(0, RAM_size);
-
-    prom_init(hwdef->prom_addr, bios_name);
-
-    ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, cpu, IVEC_MAX);
-    pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2,
-                           &pci_bus3, &pbm_irqs);
-    pci_vga_init(pci_bus);
-
-    // XXX Should be pci_bus3
-    isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs);
-
-    i = 0;
-    if (hwdef->console_serial_base) {
-        serial_mm_init(address_space_mem, hwdef->console_serial_base, 0,
-                       NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN);
-        i++;
-    }
-    for(; i < MAX_SERIAL_PORTS; i++) {
-        if (serial_hds[i]) {
-            serial_isa_init(isa_bus, i, serial_hds[i]);
-        }
-    }
-
-    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
-        if (parallel_hds[i]) {
-            parallel_init(isa_bus, i, parallel_hds[i]);
-        }
-    }
-
-    for(i = 0; i < nb_nics; i++)
-        pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
-
-    ide_drive_get(hd, MAX_IDE_BUS);
-
-    pci_cmd646_ide_init(pci_bus, hd, 1);
-
-    isa_create_simple(isa_bus, "i8042");
-    for(i = 0; i < MAX_FD; i++) {
-        fd[i] = drive_get(IF_FLOPPY, 0, i);
-    }
-    fdctrl_init_isa(isa_bus, fd);
-    nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59);
-
-    initrd_size = 0;
-    initrd_addr = 0;
-    kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename,
-                                    ram_size, &initrd_size, &initrd_addr,
-                                    &kernel_addr, &kernel_entry);
-
-    sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices,
-                           kernel_addr, kernel_size,
-                           kernel_cmdline,
-                           initrd_addr, initrd_size,
-                           /* XXX: need an option to load a NVRAM image */
-                           0,
-                           graphic_width, graphic_height, graphic_depth,
-                           (uint8_t *)&nd_table[0].macaddr);
-
-    fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
-    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
-    fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry);
-    fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
-    if (kernel_cmdline) {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
-                       strlen(kernel_cmdline) + 1);
-        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
-    } else {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
-    }
-    fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
-    fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]);
-
-    fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_DEPTH, graphic_depth);
-
-    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
-}
-
-enum {
-    sun4u_id = 0,
-    sun4v_id = 64,
-    niagara_id,
-};
-
-static const struct hwdef hwdefs[] = {
-    /* Sun4u generic PC-like machine */
-    {
-        .default_cpu_model = "TI UltraSparc IIi",
-        .machine_id = sun4u_id,
-        .prom_addr = 0x1fff0000000ULL,
-        .console_serial_base = 0,
-    },
-    /* Sun4v generic PC-like machine */
-    {
-        .default_cpu_model = "Sun UltraSparc T1",
-        .machine_id = sun4v_id,
-        .prom_addr = 0x1fff0000000ULL,
-        .console_serial_base = 0,
-    },
-    /* Sun4v generic Niagara machine */
-    {
-        .default_cpu_model = "Sun UltraSparc T1",
-        .machine_id = niagara_id,
-        .prom_addr = 0xfff0000000ULL,
-        .console_serial_base = 0xfff0c2c000ULL,
-    },
-};
-
-/* Sun4u hardware initialisation */
-static void sun4u_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_devices = args->boot_device;
-    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
-                kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]);
-}
-
-/* Sun4v hardware initialisation */
-static void sun4v_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_devices = args->boot_device;
-    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
-                kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]);
-}
-
-/* Niagara hardware initialisation */
-static void niagara_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t RAM_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_devices = args->boot_device;
-    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
-                kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]);
-}
-
-static QEMUMachine sun4u_machine = {
-    .name = "sun4u",
-    .desc = "Sun4u platform",
-    .init = sun4u_init,
-    .max_cpus = 1, // XXX for now
-    .is_default = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine sun4v_machine = {
-    .name = "sun4v",
-    .desc = "Sun4v platform",
-    .init = sun4v_init,
-    .max_cpus = 1, // XXX for now
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine niagara_machine = {
-    .name = "Niagara",
-    .desc = "Sun4v platform, Niagara",
-    .init = niagara_init,
-    .max_cpus = 1, // XXX for now
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void sun4u_register_types(void)
-{
-    type_register_static(&ebus_info);
-    type_register_static(&prom_info);
-    type_register_static(&ram_info);
-}
-
-static void sun4u_machine_init(void)
-{
-    qemu_register_machine(&sun4u_machine);
-    qemu_register_machine(&sun4v_machine);
-    qemu_register_machine(&niagara_machine);
-}
-
-type_init(sun4u_register_types)
-machine_init(sun4u_machine_init);
diff --git a/hw/tosa.c b/hw/tosa.c
deleted file mode 100644 (file)
index 747888c..0000000
--- a/hw/tosa.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* vim:set shiftwidth=4 ts=4 et: */
-/*
- * PXA255 Sharp Zaurus SL-6000 PDA platform
- *
- * Copyright (c) 2008 Dmitry Baryshkov
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "hw/hw.h"
-#include "hw/pxa.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
-#include "hw/sharpsl.h"
-#include "hw/pcmcia.h"
-#include "block/block.h"
-#include "hw/boards.h"
-#include "hw/i2c.h"
-#include "hw/ssi.h"
-#include "sysemu/blockdev.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-#define TOSA_RAM    0x04000000
-#define TOSA_ROM       0x00800000
-
-#define TOSA_GPIO_USB_IN               (5)
-#define TOSA_GPIO_nSD_DETECT   (9)
-#define TOSA_GPIO_ON_RESET             (19)
-#define TOSA_GPIO_CF_IRQ               (21)    /* CF slot0 Ready */
-#define TOSA_GPIO_CF_CD                        (13)
-#define TOSA_GPIO_TC6393XB_INT  (15)
-#define TOSA_GPIO_JC_CF_IRQ            (36)    /* CF slot1 Ready */
-
-#define TOSA_SCOOP_GPIO_BASE   1
-#define TOSA_GPIO_IR_POWERDWN  (TOSA_SCOOP_GPIO_BASE + 2)
-#define TOSA_GPIO_SD_WP                        (TOSA_SCOOP_GPIO_BASE + 3)
-#define TOSA_GPIO_PWR_ON               (TOSA_SCOOP_GPIO_BASE + 4)
-
-#define TOSA_SCOOP_JC_GPIO_BASE                1
-#define TOSA_GPIO_BT_LED               (TOSA_SCOOP_JC_GPIO_BASE + 0)
-#define TOSA_GPIO_NOTE_LED             (TOSA_SCOOP_JC_GPIO_BASE + 1)
-#define TOSA_GPIO_CHRG_ERR_LED         (TOSA_SCOOP_JC_GPIO_BASE + 2)
-#define TOSA_GPIO_TC6393XB_L3V_ON      (TOSA_SCOOP_JC_GPIO_BASE + 5)
-#define TOSA_GPIO_WLAN_LED             (TOSA_SCOOP_JC_GPIO_BASE + 7)
-
-#define        DAC_BASE        0x4e
-#define DAC_CH1                0
-#define DAC_CH2                1
-
-static void tosa_microdrive_attach(PXA2xxState *cpu)
-{
-    PCMCIACardState *md;
-    DriveInfo *dinfo;
-
-    dinfo = drive_get(IF_IDE, 0, 0);
-    if (!dinfo || dinfo->media_cd)
-        return;
-    md = dscm1xxxx_init(dinfo);
-    pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
-}
-
-static void tosa_out_switch(void *opaque, int line, int level)
-{
-    switch (line) {
-        case 0:
-            fprintf(stderr, "blue LED %s.\n", level ? "on" : "off");
-            break;
-        case 1:
-            fprintf(stderr, "green LED %s.\n", level ? "on" : "off");
-            break;
-        case 2:
-            fprintf(stderr, "amber LED %s.\n", level ? "on" : "off");
-            break;
-        case 3:
-            fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off");
-            break;
-        default:
-            fprintf(stderr, "Uhandled out event: %d = %d\n", line, level);
-            break;
-    }
-}
-
-
-static void tosa_gpio_setup(PXA2xxState *cpu,
-                DeviceState *scp0,
-                DeviceState *scp1,
-                TC6393xbState *tmio)
-{
-    qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4);
-    /* MMC/SD host */
-    pxa2xx_mmci_handlers(cpu->mmc,
-                    qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP),
-                    qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT)));
-
-    /* Handle reset */
-    qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset);
-
-    /* PCMCIA signals: card's IRQ and Card-Detect */
-    pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
-                        qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ),
-                        qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD));
-
-    pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
-                        qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ),
-                        NULL);
-
-    qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, outsignals[0]);
-    qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]);
-    qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]);
-    qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]);
-
-    qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
-
-    /* UDC Vbus */
-    qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN));
-}
-
-static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value)
-{
-    fprintf(stderr, "TG: %d %02x\n", value >> 5, value & 0x1f);
-    return 0;
-}
-
-static int tosa_ssp_init(SSISlave *dev)
-{
-    /* Nothing to do.  */
-    return 0;
-}
-
-typedef struct {
-    I2CSlave i2c;
-    int len;
-    char buf[3];
-} TosaDACState;
-
-static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
-{
-    TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
-    s->buf[s->len] = data;
-    if (s->len ++ > 2) {
-#ifdef VERBOSE
-        fprintf(stderr, "%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
-#endif
-        return 1;
-    }
-
-    if (s->len == 2) {
-        fprintf(stderr, "dac: channel %d value 0x%02x\n",
-                s->buf[0], s->buf[1]);
-    }
-
-    return 0;
-}
-
-static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
-{
-    TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
-    s->len = 0;
-    switch (event) {
-    case I2C_START_SEND:
-        break;
-    case I2C_START_RECV:
-        printf("%s: recv not supported!!!\n", __FUNCTION__);
-        break;
-    case I2C_FINISH:
-#ifdef VERBOSE
-        if (s->len < 2)
-            printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
-        if (s->len > 2)
-            printf("%s: message too long\n", __FUNCTION__);
-#endif
-        break;
-    default:
-        break;
-    }
-}
-
-static int tosa_dac_recv(I2CSlave *s)
-{
-    printf("%s: recv not supported!!!\n", __FUNCTION__);
-    return -1;
-}
-
-static int tosa_dac_init(I2CSlave *i2c)
-{
-    /* Nothing to do.  */
-    return 0;
-}
-
-static void tosa_tg_init(PXA2xxState *cpu)
-{
-    i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
-    i2c_create_slave(bus, "tosa_dac", DAC_BASE);
-    ssi_create_slave(cpu->ssp[1], "tosa-ssp");
-}
-
-
-static struct arm_boot_info tosa_binfo = {
-    .loader_start = PXA2XX_SDRAM_BASE,
-    .ram_size = 0x04000000,
-};
-
-static void tosa_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *rom = g_new(MemoryRegion, 1);
-    PXA2xxState *mpu;
-    TC6393xbState *tmio;
-    DeviceState *scp0, *scp1;
-
-    if (!cpu_model)
-        cpu_model = "pxa255";
-
-    mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size);
-
-    memory_region_init_ram(rom, "tosa.rom", TOSA_ROM);
-    vmstate_register_ram_global(rom);
-    memory_region_set_readonly(rom, true);
-    memory_region_add_subregion(address_space_mem, 0, rom);
-
-    tmio = tc6393xb_init(address_space_mem, 0x10000000,
-            qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT));
-
-    scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
-    scp1 = sysbus_create_simple("scoop", 0x14800040, NULL);
-
-    tosa_gpio_setup(mpu, scp0, scp1, tmio);
-
-    tosa_microdrive_attach(mpu);
-
-    tosa_tg_init(mpu);
-
-    tosa_binfo.kernel_filename = kernel_filename;
-    tosa_binfo.kernel_cmdline = kernel_cmdline;
-    tosa_binfo.initrd_filename = initrd_filename;
-    tosa_binfo.board_id = 0x208;
-    arm_load_kernel(mpu->cpu, &tosa_binfo);
-    sl_bootparam_write(SL_PXA_PARAM_BASE);
-}
-
-static QEMUMachine tosapda_machine = {
-    .name = "tosa",
-    .desc = "Tosa PDA (PXA255)",
-    .init = tosa_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void tosapda_machine_init(void)
-{
-    qemu_register_machine(&tosapda_machine);
-}
-
-machine_init(tosapda_machine_init);
-
-static void tosa_dac_class_init(ObjectClass *klass, void *data)
-{
-    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
-    k->init = tosa_dac_init;
-    k->event = tosa_dac_event;
-    k->recv = tosa_dac_recv;
-    k->send = tosa_dac_send;
-}
-
-static const TypeInfo tosa_dac_info = {
-    .name          = "tosa_dac",
-    .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(TosaDACState),
-    .class_init    = tosa_dac_class_init,
-};
-
-static void tosa_ssp_class_init(ObjectClass *klass, void *data)
-{
-    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
-    k->init = tosa_ssp_init;
-    k->transfer = tosa_ssp_tansfer;
-}
-
-static const TypeInfo tosa_ssp_info = {
-    .name          = "tosa-ssp",
-    .parent        = TYPE_SSI_SLAVE,
-    .instance_size = sizeof(SSISlave),
-    .class_init    = tosa_ssp_class_init,
-};
-
-static void tosa_register_types(void)
-{
-    type_register_static(&tosa_dac_info);
-    type_register_static(&tosa_ssp_info);
-}
-
-type_init(tosa_register_types)
index 0725ce3ca7ca80aae854b974dbec64338496fd07..e0fd62852308e81f429a97a7770312b22724cb9f 100644 (file)
@@ -2,5 +2,3 @@
 
 # PKUnity-v3 SoC and board information
 obj-${CONFIG_PUV3} += puv3.o
-
-obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
new file mode 100644 (file)
index 0000000..f9d0c2b
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Generic PKUnity SoC machine and board descriptor
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "ui/console.h"
+#include "elf.h"
+#include "exec/address-spaces.h"
+#include "hw/sysbus.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "hw/pc.h"
+
+#undef DEBUG_PUV3
+#include "hw/puv3.h"
+
+#define KERNEL_LOAD_ADDR        0x03000000
+#define KERNEL_MAX_SIZE         0x00800000 /* Just a guess */
+
+static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
+{
+    CPUUniCore32State *env = opaque;
+
+    assert(irq == 0);
+    if (level) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void puv3_soc_init(CPUUniCore32State *env)
+{
+    qemu_irq *cpu_intc, irqs[PUV3_IRQS_NR];
+    DeviceState *dev;
+    MemoryRegion *i8042 = g_new(MemoryRegion, 1);
+    int i;
+
+    /* Initialize interrupt controller */
+    cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, env, 1);
+    dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc);
+    for (i = 0; i < PUV3_IRQS_NR; i++) {
+        irqs[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    /* Initialize minimal necessary devices for kernel booting */
+    sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL);
+    sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL);
+    sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]);
+    sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE,
+            irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1],
+            irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3],
+            irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5],
+            irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7],
+            irqs[PUV3_IRQS_GPIOHIGH], NULL);
+
+    /* Keyboard (i8042), mouse disabled for nographic */
+    i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4);
+    memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042);
+}
+
+static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size)
+{
+    MemoryRegion *ram_memory = g_new(MemoryRegion, 1);
+
+    /* SDRAM at address zero.  */
+    memory_region_init_ram(ram_memory, "puv3.ram", ram_size);
+    vmstate_register_ram_global(ram_memory);
+    memory_region_add_subregion(get_system_memory(), 0, ram_memory);
+}
+
+static void puv3_load_kernel(const char *kernel_filename)
+{
+    int size;
+
+    assert(kernel_filename != NULL);
+
+    /* only zImage format supported */
+    size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
+            KERNEL_MAX_SIZE);
+    if (size < 0) {
+        hw_error("Load kernel error: '%s'\n", kernel_filename);
+    }
+
+    /* cheat curses that we have a graphic console, only under ocd console */
+    graphic_console_init(NULL, NULL, NULL, NULL, NULL);
+}
+
+static void puv3_init(QEMUMachineInitArgs *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *initrd_filename = args->initrd_filename;
+    CPUUniCore32State *env;
+
+    if (initrd_filename) {
+        hw_error("Please use kernel built-in initramdisk.\n");
+    }
+
+    if (!cpu_model) {
+        cpu_model = "UniCore-II";
+    }
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        hw_error("Unable to find CPU definition\n");
+    }
+
+    puv3_soc_init(env);
+    puv3_board_init(env, ram_size);
+    puv3_load_kernel(kernel_filename);
+}
+
+static QEMUMachine puv3_machine = {
+    .name = "puv3",
+    .desc = "PKUnity Version-3 based on UniCore32",
+    .init = puv3_init,
+    .is_default = 1,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void puv3_machine_init(void)
+{
+    qemu_register_machine(&puv3_machine);
+}
+
+machine_init(puv3_machine_init)
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
deleted file mode 100644 (file)
index baaa265..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * ARM Versatile Platform/Application Baseboard System emulation.
- *
- * Copyright (c) 2005-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/pci/pci.h"
-#include "hw/i2c.h"
-#include "hw/boards.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-#include "hw/flash.h"
-
-#define VERSATILE_FLASH_ADDR 0x34000000
-#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
-#define VERSATILE_FLASH_SECT_SIZE (256 * 1024)
-
-/* Primary interrupt controller.  */
-
-typedef struct vpb_sic_state
-{
-  SysBusDevice busdev;
-  MemoryRegion iomem;
-  uint32_t level;
-  uint32_t mask;
-  uint32_t pic_enable;
-  qemu_irq parent[32];
-  int irq;
-} vpb_sic_state;
-
-static const VMStateDescription vmstate_vpb_sic = {
-    .name = "versatilepb_sic",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(level, vpb_sic_state),
-        VMSTATE_UINT32(mask, vpb_sic_state),
-        VMSTATE_UINT32(pic_enable, vpb_sic_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void vpb_sic_update(vpb_sic_state *s)
-{
-    uint32_t flags;
-
-    flags = s->level & s->mask;
-    qemu_set_irq(s->parent[s->irq], flags != 0);
-}
-
-static void vpb_sic_update_pic(vpb_sic_state *s)
-{
-    int i;
-    uint32_t mask;
-
-    for (i = 21; i <= 30; i++) {
-        mask = 1u << i;
-        if (!(s->pic_enable & mask))
-            continue;
-        qemu_set_irq(s->parent[i], (s->level & mask) != 0);
-    }
-}
-
-static void vpb_sic_set_irq(void *opaque, int irq, int level)
-{
-    vpb_sic_state *s = (vpb_sic_state *)opaque;
-    if (level)
-        s->level |= 1u << irq;
-    else
-        s->level &= ~(1u << irq);
-    if (s->pic_enable & (1u << irq))
-        qemu_set_irq(s->parent[irq], level);
-    vpb_sic_update(s);
-}
-
-static uint64_t vpb_sic_read(void *opaque, hwaddr offset,
-                             unsigned size)
-{
-    vpb_sic_state *s = (vpb_sic_state *)opaque;
-
-    switch (offset >> 2) {
-    case 0: /* STATUS */
-        return s->level & s->mask;
-    case 1: /* RAWSTAT */
-        return s->level;
-    case 2: /* ENABLE */
-        return s->mask;
-    case 4: /* SOFTINT */
-        return s->level & 1;
-    case 8: /* PICENABLE */
-        return s->pic_enable;
-    default:
-        printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void vpb_sic_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
-{
-    vpb_sic_state *s = (vpb_sic_state *)opaque;
-
-    switch (offset >> 2) {
-    case 2: /* ENSET */
-        s->mask |= value;
-        break;
-    case 3: /* ENCLR */
-        s->mask &= ~value;
-        break;
-    case 4: /* SOFTINTSET */
-        if (value)
-            s->mask |= 1;
-        break;
-    case 5: /* SOFTINTCLR */
-        if (value)
-            s->mask &= ~1u;
-        break;
-    case 8: /* PICENSET */
-        s->pic_enable |= (value & 0x7fe00000);
-        vpb_sic_update_pic(s);
-        break;
-    case 9: /* PICENCLR */
-        s->pic_enable &= ~value;
-        vpb_sic_update_pic(s);
-        break;
-    default:
-        printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
-        return;
-    }
-    vpb_sic_update(s);
-}
-
-static const MemoryRegionOps vpb_sic_ops = {
-    .read = vpb_sic_read,
-    .write = vpb_sic_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int vpb_sic_init(SysBusDevice *dev)
-{
-    vpb_sic_state *s = FROM_SYSBUS(vpb_sic_state, dev);
-    int i;
-
-    qdev_init_gpio_in(&dev->qdev, vpb_sic_set_irq, 32);
-    for (i = 0; i < 32; i++) {
-        sysbus_init_irq(dev, &s->parent[i]);
-    }
-    s->irq = 31;
-    memory_region_init_io(&s->iomem, &vpb_sic_ops, s, "vpb-sic", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-/* Board init.  */
-
-/* The AB and PB boards both use the same core, just with different
-   peripherals and expansion busses.  For now we emulate a subset of the
-   PB peripherals and just change the board ID.  */
-
-static struct arm_boot_info versatile_binfo;
-
-static void versatile_init(QEMUMachineInitArgs *args, int board_id)
-{
-    ARMCPU *cpu;
-    MemoryRegion *sysmem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    qemu_irq *cpu_pic;
-    qemu_irq pic[32];
-    qemu_irq sic[32];
-    DeviceState *dev, *sysctl;
-    SysBusDevice *busdev;
-    DeviceState *pl041;
-    PCIBus *pci_bus;
-    NICInfo *nd;
-    i2c_bus *i2c;
-    int n;
-    int done_smc = 0;
-    DriveInfo *dinfo;
-
-    if (!args->cpu_model) {
-        args->cpu_model = "arm926";
-    }
-    cpu = cpu_arm_init(args->cpu_model);
-    if (!cpu) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-    memory_region_init_ram(ram, "versatile.ram", args->ram_size);
-    vmstate_register_ram_global(ram);
-    /* ??? RAM should repeat to fill physical memory space.  */
-    /* SDRAM at address zero.  */
-    memory_region_add_subregion(sysmem, 0, ram);
-
-    sysctl = qdev_create(NULL, "realview_sysctl");
-    qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
-    qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
-    qdev_init_nofail(sysctl);
-    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
-
-    cpu_pic = arm_pic_init_cpu(cpu);
-    dev = sysbus_create_varargs("pl190", 0x10140000,
-                                cpu_pic[ARM_PIC_CPU_IRQ],
-                                cpu_pic[ARM_PIC_CPU_FIQ], NULL);
-    for (n = 0; n < 32; n++) {
-        pic[n] = qdev_get_gpio_in(dev, n);
-    }
-    dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL);
-    for (n = 0; n < 32; n++) {
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]);
-        sic[n] = qdev_get_gpio_in(dev, n);
-    }
-
-    sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]);
-    sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]);
-
-    dev = qdev_create(NULL, "versatile_pci");
-    busdev = SYS_BUS_DEVICE(dev);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(busdev, 0, 0x41000000); /* PCI self-config */
-    sysbus_mmio_map(busdev, 1, 0x42000000); /* PCI config */
-    sysbus_connect_irq(busdev, 0, sic[27]);
-    sysbus_connect_irq(busdev, 1, sic[28]);
-    sysbus_connect_irq(busdev, 2, sic[29]);
-    sysbus_connect_irq(busdev, 3, sic[30]);
-    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
-
-    /* The Versatile PCI bridge does not provide access to PCI IO space,
-       so many of the qemu PCI devices are not useable.  */
-    for(n = 0; n < nb_nics; n++) {
-        nd = &nd_table[n];
-
-        if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
-            smc91c111_init(nd, 0x10010000, sic[25]);
-            done_smc = 1;
-        } else {
-            pci_nic_init_nofail(nd, "rtl8139", NULL);
-        }
-    }
-    if (usb_enabled(false)) {
-        pci_create_simple(pci_bus, -1, "pci-ohci");
-    }
-    n = drive_get_max_bus(IF_SCSI);
-    while (n >= 0) {
-        pci_create_simple(pci_bus, -1, "lsi53c895a");
-        n--;
-    }
-
-    sysbus_create_simple("pl011", 0x101f1000, pic[12]);
-    sysbus_create_simple("pl011", 0x101f2000, pic[13]);
-    sysbus_create_simple("pl011", 0x101f3000, pic[14]);
-    sysbus_create_simple("pl011", 0x10009000, sic[6]);
-
-    sysbus_create_simple("pl080", 0x10130000, pic[17]);
-    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
-    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
-
-    sysbus_create_simple("pl061", 0x101e4000, pic[6]);
-    sysbus_create_simple("pl061", 0x101e5000, pic[7]);
-    sysbus_create_simple("pl061", 0x101e6000, pic[8]);
-    sysbus_create_simple("pl061", 0x101e7000, pic[9]);
-
-    /* The versatile/PB actually has a modified Color LCD controller
-       that includes hardware cursor support from the PL111.  */
-    dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
-    /* Wire up the mux control signals from the SYS_CLCD register */
-    qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0));
-
-    sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
-    sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
-
-    /* Add PL031 Real Time Clock. */
-    sysbus_create_simple("pl031", 0x101e8000, pic[10]);
-
-    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
-    i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
-    i2c_create_slave(i2c, "ds1338", 0x68);
-
-    /* Add PL041 AACI Interface to the LM4549 codec */
-    pl041 = qdev_create(NULL, "pl041");
-    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
-    qdev_init_nofail(pl041);
-    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
-    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
-
-    /* Memory map for Versatile/PB:  */
-    /* 0x10000000 System registers.  */
-    /* 0x10001000 PCI controller config registers.  */
-    /* 0x10002000 Serial bus interface.  */
-    /*  0x10003000 Secondary interrupt controller.  */
-    /* 0x10004000 AACI (audio).  */
-    /*  0x10005000 MMCI0.  */
-    /*  0x10006000 KMI0 (keyboard).  */
-    /*  0x10007000 KMI1 (mouse).  */
-    /* 0x10008000 Character LCD Interface.  */
-    /*  0x10009000 UART3.  */
-    /* 0x1000a000 Smart card 1.  */
-    /*  0x1000b000 MMCI1.  */
-    /*  0x10010000 Ethernet.  */
-    /* 0x10020000 USB.  */
-    /* 0x10100000 SSMC.  */
-    /* 0x10110000 MPMC.  */
-    /*  0x10120000 CLCD Controller.  */
-    /*  0x10130000 DMA Controller.  */
-    /*  0x10140000 Vectored interrupt controller.  */
-    /* 0x101d0000 AHB Monitor Interface.  */
-    /* 0x101e0000 System Controller.  */
-    /* 0x101e1000 Watchdog Interface.  */
-    /* 0x101e2000 Timer 0/1.  */
-    /* 0x101e3000 Timer 2/3.  */
-    /* 0x101e4000 GPIO port 0.  */
-    /* 0x101e5000 GPIO port 1.  */
-    /* 0x101e6000 GPIO port 2.  */
-    /* 0x101e7000 GPIO port 3.  */
-    /* 0x101e8000 RTC.  */
-    /* 0x101f0000 Smart card 0.  */
-    /*  0x101f1000 UART0.  */
-    /*  0x101f2000 UART1.  */
-    /*  0x101f3000 UART2.  */
-    /* 0x101f4000 SSPI.  */
-    /* 0x34000000 NOR Flash */
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
-                          VERSATILE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
-                          VERSATILE_FLASH_SECT_SIZE,
-                          VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
-                          4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
-        fprintf(stderr, "qemu: Error registering flash memory.\n");
-    }
-
-    versatile_binfo.ram_size = args->ram_size;
-    versatile_binfo.kernel_filename = args->kernel_filename;
-    versatile_binfo.kernel_cmdline = args->kernel_cmdline;
-    versatile_binfo.initrd_filename = args->initrd_filename;
-    versatile_binfo.board_id = board_id;
-    arm_load_kernel(cpu, &versatile_binfo);
-}
-
-static void vpb_init(QEMUMachineInitArgs *args)
-{
-    versatile_init(args, 0x183);
-}
-
-static void vab_init(QEMUMachineInitArgs *args)
-{
-    versatile_init(args, 0x25e);
-}
-
-static QEMUMachine versatilepb_machine = {
-    .name = "versatilepb",
-    .desc = "ARM Versatile/PB (ARM926EJ-S)",
-    .init = vpb_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine versatileab_machine = {
-    .name = "versatileab",
-    .desc = "ARM Versatile/AB (ARM926EJ-S)",
-    .init = vab_init,
-    .block_default_type = IF_SCSI,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void versatile_machine_init(void)
-{
-    qemu_register_machine(&versatilepb_machine);
-    qemu_register_machine(&versatileab_machine);
-}
-
-machine_init(versatile_machine_init);
-
-static void vpb_sic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = vpb_sic_init;
-    dc->no_user = 1;
-    dc->vmsd = &vmstate_vpb_sic;
-}
-
-static const TypeInfo vpb_sic_info = {
-    .name          = "versatilepb_sic",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(vpb_sic_state),
-    .class_init    = vpb_sic_class_init,
-};
-
-static void versatilepb_register_types(void)
-{
-    type_register_static(&vpb_sic_info);
-}
-
-type_init(versatilepb_register_types)
diff --git a/hw/vexpress.c b/hw/vexpress.c
deleted file mode 100644 (file)
index 02922c3..0000000
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * ARM Versatile Express emulation.
- *
- * Copyright (c) 2010 - 2011 B Labs Ltd.
- * Copyright (c) 2011 Linaro Limited
- * Written by Bahadir Balban, Amit Mahajan, Peter Maydell
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *  Contributions after 2012-01-13 are licensed under the terms of the
- *  GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "hw/primecell.h"
-#include "hw/devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "exec/address-spaces.h"
-#include "sysemu/blockdev.h"
-#include "hw/flash.h"
-
-#define VEXPRESS_BOARD_ID 0x8e0
-#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
-#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024)
-
-static struct arm_boot_info vexpress_binfo;
-
-/* Address maps for peripherals:
- * the Versatile Express motherboard has two possible maps,
- * the "legacy" one (used for A9) and the "Cortex-A Series"
- * map (used for newer cores).
- * Individual daughterboards can also have different maps for
- * their peripherals.
- */
-
-enum {
-    VE_SYSREGS,
-    VE_SP810,
-    VE_SERIALPCI,
-    VE_PL041,
-    VE_MMCI,
-    VE_KMI0,
-    VE_KMI1,
-    VE_UART0,
-    VE_UART1,
-    VE_UART2,
-    VE_UART3,
-    VE_WDT,
-    VE_TIMER01,
-    VE_TIMER23,
-    VE_SERIALDVI,
-    VE_RTC,
-    VE_COMPACTFLASH,
-    VE_CLCD,
-    VE_NORFLASH0,
-    VE_NORFLASH1,
-    VE_SRAM,
-    VE_VIDEORAM,
-    VE_ETHERNET,
-    VE_USB,
-    VE_DAPROM,
-};
-
-static hwaddr motherboard_legacy_map[] = {
-    /* CS7: 0x10000000 .. 0x10020000 */
-    [VE_SYSREGS] = 0x10000000,
-    [VE_SP810] = 0x10001000,
-    [VE_SERIALPCI] = 0x10002000,
-    [VE_PL041] = 0x10004000,
-    [VE_MMCI] = 0x10005000,
-    [VE_KMI0] = 0x10006000,
-    [VE_KMI1] = 0x10007000,
-    [VE_UART0] = 0x10009000,
-    [VE_UART1] = 0x1000a000,
-    [VE_UART2] = 0x1000b000,
-    [VE_UART3] = 0x1000c000,
-    [VE_WDT] = 0x1000f000,
-    [VE_TIMER01] = 0x10011000,
-    [VE_TIMER23] = 0x10012000,
-    [VE_SERIALDVI] = 0x10016000,
-    [VE_RTC] = 0x10017000,
-    [VE_COMPACTFLASH] = 0x1001a000,
-    [VE_CLCD] = 0x1001f000,
-    /* CS0: 0x40000000 .. 0x44000000 */
-    [VE_NORFLASH0] = 0x40000000,
-    /* CS1: 0x44000000 .. 0x48000000 */
-    [VE_NORFLASH1] = 0x44000000,
-    /* CS2: 0x48000000 .. 0x4a000000 */
-    [VE_SRAM] = 0x48000000,
-    /* CS3: 0x4c000000 .. 0x50000000 */
-    [VE_VIDEORAM] = 0x4c000000,
-    [VE_ETHERNET] = 0x4e000000,
-    [VE_USB] = 0x4f000000,
-};
-
-static hwaddr motherboard_aseries_map[] = {
-    /* CS0: 0x08000000 .. 0x0c000000 */
-    [VE_NORFLASH0] = 0x08000000,
-    /* CS4: 0x0c000000 .. 0x10000000 */
-    [VE_NORFLASH1] = 0x0c000000,
-    /* CS5: 0x10000000 .. 0x14000000 */
-    /* CS1: 0x14000000 .. 0x18000000 */
-    [VE_SRAM] = 0x14000000,
-    /* CS2: 0x18000000 .. 0x1c000000 */
-    [VE_VIDEORAM] = 0x18000000,
-    [VE_ETHERNET] = 0x1a000000,
-    [VE_USB] = 0x1b000000,
-    /* CS3: 0x1c000000 .. 0x20000000 */
-    [VE_DAPROM] = 0x1c000000,
-    [VE_SYSREGS] = 0x1c010000,
-    [VE_SP810] = 0x1c020000,
-    [VE_SERIALPCI] = 0x1c030000,
-    [VE_PL041] = 0x1c040000,
-    [VE_MMCI] = 0x1c050000,
-    [VE_KMI0] = 0x1c060000,
-    [VE_KMI1] = 0x1c070000,
-    [VE_UART0] = 0x1c090000,
-    [VE_UART1] = 0x1c0a0000,
-    [VE_UART2] = 0x1c0b0000,
-    [VE_UART3] = 0x1c0c0000,
-    [VE_WDT] = 0x1c0f0000,
-    [VE_TIMER01] = 0x1c110000,
-    [VE_TIMER23] = 0x1c120000,
-    [VE_SERIALDVI] = 0x1c160000,
-    [VE_RTC] = 0x1c170000,
-    [VE_COMPACTFLASH] = 0x1c1a0000,
-    [VE_CLCD] = 0x1c1f0000,
-};
-
-/* Structure defining the peculiarities of a specific daughterboard */
-
-typedef struct VEDBoardInfo VEDBoardInfo;
-
-typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
-                          ram_addr_t ram_size,
-                          const char *cpu_model,
-                          qemu_irq *pic, uint32_t *proc_id);
-
-struct VEDBoardInfo {
-    const hwaddr *motherboard_map;
-    hwaddr loader_start;
-    const hwaddr gic_cpu_if_addr;
-    DBoardInitFn *init;
-};
-
-static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
-                                  ram_addr_t ram_size,
-                                  const char *cpu_model,
-                                  qemu_irq *pic, uint32_t *proc_id)
-{
-    MemoryRegion *sysmem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *lowram = g_new(MemoryRegion, 1);
-    DeviceState *dev;
-    SysBusDevice *busdev;
-    qemu_irq *irqp;
-    int n;
-    qemu_irq cpu_irq[4];
-    ram_addr_t low_ram_size;
-
-    if (!cpu_model) {
-        cpu_model = "cortex-a9";
-    }
-
-    *proc_id = 0x0c000191;
-
-    for (n = 0; n < smp_cpus; n++) {
-        ARMCPU *cpu = cpu_arm_init(cpu_model);
-        if (!cpu) {
-            fprintf(stderr, "Unable to find CPU definition\n");
-            exit(1);
-        }
-        irqp = arm_pic_init_cpu(cpu);
-        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
-    }
-
-    if (ram_size > 0x40000000) {
-        /* 1GB is the maximum the address space permits */
-        fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n");
-        exit(1);
-    }
-
-    memory_region_init_ram(ram, "vexpress.highmem", ram_size);
-    vmstate_register_ram_global(ram);
-    low_ram_size = ram_size;
-    if (low_ram_size > 0x4000000) {
-        low_ram_size = 0x4000000;
-    }
-    /* RAM is from 0x60000000 upwards. The bottom 64MB of the
-     * address space should in theory be remappable to various
-     * things including ROM or RAM; we always map the RAM there.
-     */
-    memory_region_init_alias(lowram, "vexpress.lowmem", ram, 0, low_ram_size);
-    memory_region_add_subregion(sysmem, 0x0, lowram);
-    memory_region_add_subregion(sysmem, 0x60000000, ram);
-
-    /* 0x1e000000 A9MPCore (SCU) private memory region */
-    dev = qdev_create(NULL, "a9mpcore_priv");
-    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
-    qdev_init_nofail(dev);
-    busdev = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(busdev, 0, 0x1e000000);
-    for (n = 0; n < smp_cpus; n++) {
-        sysbus_connect_irq(busdev, n, cpu_irq[n]);
-    }
-    /* Interrupts [42:0] are from the motherboard;
-     * [47:43] are reserved; [63:48] are daughterboard
-     * peripherals. Note that some documentation numbers
-     * external interrupts starting from 32 (because the
-     * A9MP has internal interrupts 0..31).
-     */
-    for (n = 0; n < 64; n++) {
-        pic[n] = qdev_get_gpio_in(dev, n);
-    }
-
-    /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
-
-    /* 0x10020000 PL111 CLCD (daughterboard) */
-    sysbus_create_simple("pl111", 0x10020000, pic[44]);
-
-    /* 0x10060000 AXI RAM */
-    /* 0x100e0000 PL341 Dynamic Memory Controller */
-    /* 0x100e1000 PL354 Static Memory Controller */
-    /* 0x100e2000 System Configuration Controller */
-
-    sysbus_create_simple("sp804", 0x100e4000, pic[48]);
-    /* 0x100e5000 SP805 Watchdog module */
-    /* 0x100e6000 BP147 TrustZone Protection Controller */
-    /* 0x100e9000 PL301 'Fast' AXI matrix */
-    /* 0x100ea000 PL301 'Slow' AXI matrix */
-    /* 0x100ec000 TrustZone Address Space Controller */
-    /* 0x10200000 CoreSight debug APB */
-    /* 0x1e00a000 PL310 L2 Cache Controller */
-    sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
-}
-
-static const VEDBoardInfo a9_daughterboard = {
-    .motherboard_map = motherboard_legacy_map,
-    .loader_start = 0x60000000,
-    .gic_cpu_if_addr = 0x1e000100,
-    .init = a9_daughterboard_init,
-};
-
-static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
-                                   ram_addr_t ram_size,
-                                   const char *cpu_model,
-                                   qemu_irq *pic, uint32_t *proc_id)
-{
-    int n;
-    MemoryRegion *sysmem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    MemoryRegion *sram = g_new(MemoryRegion, 1);
-    qemu_irq cpu_irq[4];
-    DeviceState *dev;
-    SysBusDevice *busdev;
-
-    if (!cpu_model) {
-        cpu_model = "cortex-a15";
-    }
-
-    *proc_id = 0x14000237;
-
-    for (n = 0; n < smp_cpus; n++) {
-        ARMCPU *cpu;
-        qemu_irq *irqp;
-
-        cpu = cpu_arm_init(cpu_model);
-        if (!cpu) {
-            fprintf(stderr, "Unable to find CPU definition\n");
-            exit(1);
-        }
-        irqp = arm_pic_init_cpu(cpu);
-        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
-    }
-
-    {
-        /* We have to use a separate 64 bit variable here to avoid the gcc
-         * "comparison is always false due to limited range of data type"
-         * warning if we are on a host where ram_addr_t is 32 bits.
-         */
-        uint64_t rsz = ram_size;
-        if (rsz > (30ULL * 1024 * 1024 * 1024)) {
-            fprintf(stderr, "vexpress-a15: cannot model more than 30GB RAM\n");
-            exit(1);
-        }
-    }
-
-    memory_region_init_ram(ram, "vexpress.highmem", ram_size);
-    vmstate_register_ram_global(ram);
-    /* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */
-    memory_region_add_subregion(sysmem, 0x80000000, ram);
-
-    /* 0x2c000000 A15MPCore private memory region (GIC) */
-    dev = qdev_create(NULL, "a15mpcore_priv");
-    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
-    qdev_init_nofail(dev);
-    busdev = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(busdev, 0, 0x2c000000);
-    for (n = 0; n < smp_cpus; n++) {
-        sysbus_connect_irq(busdev, n, cpu_irq[n]);
-    }
-    /* Interrupts [42:0] are from the motherboard;
-     * [47:43] are reserved; [63:48] are daughterboard
-     * peripherals. Note that some documentation numbers
-     * external interrupts starting from 32 (because there
-     * are internal interrupts 0..31).
-     */
-    for (n = 0; n < 64; n++) {
-        pic[n] = qdev_get_gpio_in(dev, n);
-    }
-
-    /* A15 daughterboard peripherals: */
-
-    /* 0x20000000: CoreSight interfaces: not modelled */
-    /* 0x2a000000: PL301 AXI interconnect: not modelled */
-    /* 0x2a420000: SCC: not modelled */
-    /* 0x2a430000: system counter: not modelled */
-    /* 0x2b000000: HDLCD controller: not modelled */
-    /* 0x2b060000: SP805 watchdog: not modelled */
-    /* 0x2b0a0000: PL341 dynamic memory controller: not modelled */
-    /* 0x2e000000: system SRAM */
-    memory_region_init_ram(sram, "vexpress.a15sram", 0x10000);
-    vmstate_register_ram_global(sram);
-    memory_region_add_subregion(sysmem, 0x2e000000, sram);
-
-    /* 0x7ffb0000: DMA330 DMA controller: not modelled */
-    /* 0x7ffd0000: PL354 static memory controller: not modelled */
-}
-
-static const VEDBoardInfo a15_daughterboard = {
-    .motherboard_map = motherboard_aseries_map,
-    .loader_start = 0x80000000,
-    .gic_cpu_if_addr = 0x2c002000,
-    .init = a15_daughterboard_init,
-};
-
-static void vexpress_common_init(const VEDBoardInfo *daughterboard,
-                                 QEMUMachineInitArgs *args)
-{
-    DeviceState *dev, *sysctl, *pl041;
-    qemu_irq pic[64];
-    uint32_t proc_id;
-    uint32_t sys_id;
-    DriveInfo *dinfo;
-    ram_addr_t vram_size, sram_size;
-    MemoryRegion *sysmem = get_system_memory();
-    MemoryRegion *vram = g_new(MemoryRegion, 1);
-    MemoryRegion *sram = g_new(MemoryRegion, 1);
-    const hwaddr *map = daughterboard->motherboard_map;
-
-    daughterboard->init(daughterboard, args->ram_size, args->cpu_model,
-                        pic, &proc_id);
-
-    /* Motherboard peripherals: the wiring is the same but the
-     * addresses vary between the legacy and A-Series memory maps.
-     */
-
-    sys_id = 0x1190f500;
-
-    sysctl = qdev_create(NULL, "realview_sysctl");
-    qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
-    qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
-    qdev_init_nofail(sysctl);
-    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]);
-
-    /* VE_SP810: not modelled */
-    /* VE_SERIALPCI: not modelled */
-
-    pl041 = qdev_create(NULL, "pl041");
-    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
-    qdev_init_nofail(pl041);
-    sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]);
-    sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]);
-
-    dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL);
-    /* Wire up MMC card detect and read-only signals */
-    qdev_connect_gpio_out(dev, 0,
-                          qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT));
-    qdev_connect_gpio_out(dev, 1,
-                          qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN));
-
-    sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]);
-    sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]);
-
-    sysbus_create_simple("pl011", map[VE_UART0], pic[5]);
-    sysbus_create_simple("pl011", map[VE_UART1], pic[6]);
-    sysbus_create_simple("pl011", map[VE_UART2], pic[7]);
-    sysbus_create_simple("pl011", map[VE_UART3], pic[8]);
-
-    sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]);
-    sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]);
-
-    /* VE_SERIALDVI: not modelled */
-
-    sysbus_create_simple("pl031", map[VE_RTC], pic[4]); /* RTC */
-
-    /* VE_COMPACTFLASH: not modelled */
-
-    sysbus_create_simple("pl111", map[VE_CLCD], pic[14]);
-
-    dinfo = drive_get_next(IF_PFLASH);
-    if (!pflash_cfi01_register(map[VE_NORFLASH0], NULL, "vexpress.flash0",
-            VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
-            VEXPRESS_FLASH_SECT_SIZE,
-            VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4,
-            0x00, 0x89, 0x00, 0x18, 0)) {
-        fprintf(stderr, "vexpress: error registering flash 0.\n");
-        exit(1);
-    }
-
-    dinfo = drive_get_next(IF_PFLASH);
-    if (!pflash_cfi01_register(map[VE_NORFLASH1], NULL, "vexpress.flash1",
-            VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
-            VEXPRESS_FLASH_SECT_SIZE,
-            VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4,
-            0x00, 0x89, 0x00, 0x18, 0)) {
-        fprintf(stderr, "vexpress: error registering flash 1.\n");
-        exit(1);
-    }
-
-    sram_size = 0x2000000;
-    memory_region_init_ram(sram, "vexpress.sram", sram_size);
-    vmstate_register_ram_global(sram);
-    memory_region_add_subregion(sysmem, map[VE_SRAM], sram);
-
-    vram_size = 0x800000;
-    memory_region_init_ram(vram, "vexpress.vram", vram_size);
-    vmstate_register_ram_global(vram);
-    memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram);
-
-    /* 0x4e000000 LAN9118 Ethernet */
-    if (nd_table[0].used) {
-        lan9118_init(&nd_table[0], map[VE_ETHERNET], pic[15]);
-    }
-
-    /* VE_USB: not modelled */
-
-    /* VE_DAPROM: not modelled */
-
-    vexpress_binfo.ram_size = args->ram_size;
-    vexpress_binfo.kernel_filename = args->kernel_filename;
-    vexpress_binfo.kernel_cmdline = args->kernel_cmdline;
-    vexpress_binfo.initrd_filename = args->initrd_filename;
-    vexpress_binfo.nb_cpus = smp_cpus;
-    vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
-    vexpress_binfo.loader_start = daughterboard->loader_start;
-    vexpress_binfo.smp_loader_start = map[VE_SRAM];
-    vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
-    vexpress_binfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
-    arm_load_kernel(arm_env_get_cpu(first_cpu), &vexpress_binfo);
-}
-
-static void vexpress_a9_init(QEMUMachineInitArgs *args)
-{
-    vexpress_common_init(&a9_daughterboard, args);
-}
-
-static void vexpress_a15_init(QEMUMachineInitArgs *args)
-{
-    vexpress_common_init(&a15_daughterboard, args);
-}
-
-static QEMUMachine vexpress_a9_machine = {
-    .name = "vexpress-a9",
-    .desc = "ARM Versatile Express for Cortex-A9",
-    .init = vexpress_a9_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine vexpress_a15_machine = {
-    .name = "vexpress-a15",
-    .desc = "ARM Versatile Express for Cortex-A15",
-    .init = vexpress_a15_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void vexpress_machine_init(void)
-{
-    qemu_register_machine(&vexpress_a9_machine);
-    qemu_register_machine(&vexpress_a15_machine);
-}
-
-machine_init(vexpress_machine_init);
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
deleted file mode 100644 (file)
index 41eab16..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Model of Xilinx Virtex5 ML507 PPC-440 refdesign.
- *
- * Copyright (c) 2010 Edgar E. Iglesias.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/serial.h"
-#include "hw/flash.h"
-#include "sysemu/sysemu.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "sysemu/device_tree.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "qemu/log.h"
-#include "exec/address-spaces.h"
-
-#include "hw/ppc.h"
-#include "hw/ppc4xx.h"
-#include "hw/ppc405.h"
-
-#include "sysemu/blockdev.h"
-#include "hw/xilinx.h"
-
-#define EPAPR_MAGIC    (0x45504150)
-#define FLASH_SIZE     (16 * 1024 * 1024)
-
-static struct boot_info
-{
-    uint32_t bootstrap_pc;
-    uint32_t cmdline;
-    uint32_t fdt;
-    uint32_t ima_size;
-    void *vfdt;
-} boot_info;
-
-/* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
-                                     target_ulong va,
-                                     hwaddr pa)
-{
-    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
-
-    tlb->attr = 0;
-    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
-    tlb->size = 1 << 31; /* up to 0x80000000  */
-    tlb->EPN = va & TARGET_PAGE_MASK;
-    tlb->RPN = pa & TARGET_PAGE_MASK;
-    tlb->PID = 0;
-
-    tlb = &env->tlb.tlbe[1];
-    tlb->attr = 0;
-    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
-    tlb->size = 1 << 31; /* up to 0xffffffff  */
-    tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
-    tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
-    tlb->PID = 0;
-}
-
-static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size,
-                                      int do_init,
-                                      const char *cpu_model,
-                                      uint32_t sysclk)
-{
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-    qemu_irq *irqs;
-
-    cpu = cpu_ppc_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "Unable to initialize CPU!\n");
-        exit(1);
-    }
-    env = &cpu->env;
-
-    ppc_booke_timers_init(cpu, sysclk, 0/* no flags */);
-
-    ppc_dcr_init(env, NULL, NULL);
-
-    /* interrupt controller */
-    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
-    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
-    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    ppcuic_init(env, irqs, 0x0C0, 0, 1);
-    return cpu;
-}
-
-static void main_cpu_reset(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-    struct boot_info *bi = env->load_info;
-
-    cpu_reset(CPU(cpu));
-    /* Linux Kernel Parameters (passing device tree):
-       *   r3: pointer to the fdt
-       *   r4: 0
-       *   r5: 0
-       *   r6: epapr magic
-       *   r7: size of IMA in bytes
-       *   r8: 0
-       *   r9: 0
-    */
-    env->gpr[1] = (16<<20) - 8;
-    /* Provide a device-tree.  */
-    env->gpr[3] = bi->fdt;
-    env->nip = bi->bootstrap_pc;
-
-    /* Create a mapping for the kernel.  */
-    mmubooke_create_initial_mapping(env, 0, 0);
-    env->gpr[6] = tswap32(EPAPR_MAGIC);
-    env->gpr[7] = bi->ima_size;
-}
-
-#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb"
-static int xilinx_load_device_tree(hwaddr addr,
-                                      uint32_t ramsize,
-                                      hwaddr initrd_base,
-                                      hwaddr initrd_size,
-                                      const char *kernel_cmdline)
-{
-    char *path;
-    int fdt_size;
-#ifdef CONFIG_FDT
-    void *fdt;
-    int r;
-
-    /* Try the local "ppc.dtb" override.  */
-    fdt = load_device_tree("ppc.dtb", &fdt_size);
-    if (!fdt) {
-        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
-        if (path) {
-            fdt = load_device_tree(path, &fdt_size);
-            g_free(path);
-        }
-        if (!fdt) {
-            return 0;
-        }
-    }
-
-    r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
-    if (r < 0)
-        fprintf(stderr, "couldn't set /chosen/bootargs\n");
-    cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
-#else
-    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
-       to the kernel.  */
-    fdt_size = load_image_targphys("ppc.dtb", addr, 0x10000);
-    if (fdt_size < 0) {
-        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
-        if (path) {
-            fdt_size = load_image_targphys(path, addr, 0x10000);
-            g_free(path);
-        }
-    }
-
-    if (kernel_cmdline) {
-        fprintf(stderr,
-                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
-    }
-#endif
-    return fdt_size;
-}
-
-static void virtex_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    MemoryRegion *address_space_mem = get_system_memory();
-    DeviceState *dev;
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-    hwaddr ram_base = 0;
-    DriveInfo *dinfo;
-    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
-    qemu_irq irq[32], *cpu_irq;
-    int kernel_size;
-    int i;
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-        cpu_model = "440-Xilinx";
-    }
-
-    cpu = ppc440_init_xilinx(&ram_size, 1, cpu_model, 400000000);
-    env = &cpu->env;
-    qemu_register_reset(main_cpu_reset, cpu);
-
-    memory_region_init_ram(phys_ram, "ram", ram_size);
-    vmstate_register_ram_global(phys_ram);
-    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi01_register(0xfc000000, NULL, "virtex.flash", FLASH_SIZE,
-                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
-                          FLASH_SIZE >> 16,
-                          1, 0x89, 0x18, 0x0000, 0x0, 1);
-
-    cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT];
-    dev = xilinx_intc_create(0x81800000, cpu_irq[0], 0);
-    for (i = 0; i < 32; i++) {
-        irq[i] = qdev_get_gpio_in(dev, i);
-    }
-
-    serial_mm_init(address_space_mem, 0x83e01003ULL, 2, irq[9], 115200,
-                   serial_hds[0], DEVICE_LITTLE_ENDIAN);
-
-    /* 2 timers at irq 2 @ 62 Mhz.  */
-    xilinx_timer_create(0x83c00000, irq[3], 0, 62 * 1000000);
-
-    if (kernel_filename) {
-        uint64_t entry, low, high;
-        hwaddr boot_offset;
-
-        /* Boots a kernel elf binary.  */
-        kernel_size = load_elf(kernel_filename, NULL, NULL,
-                               &entry, &low, &high, 1, ELF_MACHINE, 0);
-        boot_info.bootstrap_pc = entry & 0x00ffffff;
-
-        if (kernel_size < 0) {
-            boot_offset = 0x1200000;
-            /* If we failed loading ELF's try a raw image.  */
-            kernel_size = load_image_targphys(kernel_filename,
-                                              boot_offset,
-                                              ram_size);
-            boot_info.bootstrap_pc = boot_offset;
-            high = boot_info.bootstrap_pc + kernel_size + 8192;
-        }
-
-        boot_info.ima_size = kernel_size;
-
-        /* Provide a device-tree.  */
-        boot_info.fdt = high + (8192 * 2);
-        boot_info.fdt &= ~8191;
-        xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline);
-    }
-    env->load_info = &boot_info;
-}
-
-static QEMUMachine virtex_machine = {
-    .name = "virtex-ml507",
-    .desc = "Xilinx Virtex ML507 reference design",
-    .init = virtex_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void virtex_machine_init(void)
-{
-    qemu_register_machine(&virtex_machine);
-}
-
-machine_init(virtex_machine_init);
diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c
deleted file mode 100644 (file)
index d477061..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-#include <signal.h>
-#include "hw/xen_backend.h"
-#include "hw/xen_domainbuild.h"
-#include "qemu/timer.h"
-#include "qemu/log.h"
-
-#include <xenguest.h>
-
-static int xenstore_domain_mkdir(char *path)
-{
-    struct xs_permissions perms_ro[] = {{
-            .id    = 0, /* set owner: dom0 */
-        },{
-            .id    = xen_domid,
-            .perms = XS_PERM_READ,
-        }};
-    struct xs_permissions perms_rw[] = {{
-            .id    = 0, /* set owner: dom0 */
-        },{
-            .id    = xen_domid,
-            .perms = XS_PERM_READ | XS_PERM_WRITE,
-        }};
-    const char *writable[] = { "device", "control", "error", NULL };
-    char subpath[256];
-    int i;
-
-    if (!xs_mkdir(xenstore, 0, path)) {
-        fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path);
-       return -1;
-    }
-    if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
-        fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
-       return -1;
-    }
-
-    for (i = 0; writable[i]; i++) {
-        snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
-        if (!xs_mkdir(xenstore, 0, subpath)) {
-            fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, subpath);
-            return -1;
-        }
-        if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
-            fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
-            return -1;
-        }
-    }
-    return 0;
-}
-
-int xenstore_domain_init1(const char *kernel, const char *ramdisk,
-                          const char *cmdline)
-{
-    char *dom, uuid_string[42], vm[256], path[256];
-    int i;
-
-    snprintf(uuid_string, sizeof(uuid_string), UUID_FMT,
-             qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3],
-             qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
-             qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11],
-             qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]);
-    dom = xs_get_domain_path(xenstore, xen_domid);
-    snprintf(vm,  sizeof(vm),  "/vm/%s", uuid_string);
-
-    xenstore_domain_mkdir(dom);
-
-    xenstore_write_str(vm, "image/ostype",  "linux");
-    if (kernel)
-        xenstore_write_str(vm, "image/kernel",  kernel);
-    if (ramdisk)
-        xenstore_write_str(vm, "image/ramdisk", ramdisk);
-    if (cmdline)
-        xenstore_write_str(vm, "image/cmdline", cmdline);
-
-    /* name + id */
-    xenstore_write_str(vm,  "name",   qemu_name ? qemu_name : "no-name");
-    xenstore_write_str(vm,  "uuid",   uuid_string);
-    xenstore_write_str(dom, "name",   qemu_name ? qemu_name : "no-name");
-    xenstore_write_int(dom, "domid",  xen_domid);
-    xenstore_write_str(dom, "vm",     vm);
-
-    /* memory */
-    xenstore_write_int(dom, "memory/target", ram_size >> 10);  // kB
-    xenstore_write_int(vm, "memory",         ram_size >> 20);  // MB
-    xenstore_write_int(vm, "maxmem",         ram_size >> 20);  // MB
-
-    /* cpus */
-    for (i = 0; i < smp_cpus; i++) {
-       snprintf(path, sizeof(path), "cpu/%d/availability",i);
-       xenstore_write_str(dom, path, "online");
-    }
-    xenstore_write_int(vm, "vcpu_avail",  smp_cpus);
-    xenstore_write_int(vm, "vcpus",       smp_cpus);
-
-    /* vnc password */
-    xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
-
-    free(dom);
-    return 0;
-}
-
-int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
-                          int console_port, int console_mfn)
-{
-    char *dom;
-
-    dom = xs_get_domain_path(xenstore, xen_domid);
-
-    /* signal new domain */
-    xs_introduce_domain(xenstore,
-                        xen_domid,
-                        xenstore_mfn,
-                        xenstore_port);
-
-    /* xenstore */
-    xenstore_write_int(dom, "store/ring-ref",   xenstore_mfn);
-    xenstore_write_int(dom, "store/port",       xenstore_port);
-
-    /* console */
-    xenstore_write_str(dom, "console/type",     "ioemu");
-    xenstore_write_int(dom, "console/limit",    128 * 1024);
-    xenstore_write_int(dom, "console/ring-ref", console_mfn);
-    xenstore_write_int(dom, "console/port",     console_port);
-    xen_config_dev_console(0);
-
-    free(dom);
-    return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-static QEMUTimer *xen_poll;
-
-/* check domain state once per second */
-static void xen_domain_poll(void *opaque)
-{
-    struct xc_dominfo info;
-    int rc;
-
-    rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
-    if ((rc != 1) || (info.domid != xen_domid)) {
-        qemu_log("xen: domain %d is gone\n", xen_domid);
-        goto quit;
-    }
-    if (info.dying) {
-        qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid,
-                 info.crashed  ? "crashed"  : "",
-                 info.shutdown ? "shutdown" : "");
-        goto quit;
-    }
-
-    qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000);
-    return;
-
-quit:
-    qemu_system_shutdown_request();
-}
-
-static int xen_domain_watcher(void)
-{
-    int qemu_running = 1;
-    int fd[2], i, n, rc;
-    char byte;
-
-    if (pipe(fd) != 0) {
-        qemu_log("%s: Huh? pipe error: %s\n", __FUNCTION__, strerror(errno));
-        return -1;
-    }
-    if (fork() != 0)
-        return 0; /* not child */
-
-    /* close all file handles, except stdio/out/err,
-     * our watch pipe and the xen interface handle */
-    n = getdtablesize();
-    for (i = 3; i < n; i++) {
-        if (i == fd[0])
-            continue;
-        if (i == xc_fd(xen_xc)) {
-            continue;
-        }
-        close(i);
-    }
-
-    /* ignore term signals */
-    signal(SIGINT,  SIG_IGN);
-    signal(SIGTERM, SIG_IGN);
-
-    /* wait for qemu exiting */
-    while (qemu_running) {
-        rc = read(fd[0], &byte, 1);
-        switch (rc) {
-        case -1:
-            if (errno == EINTR)
-                continue;
-            qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno));
-            qemu_running = 0;
-            break;
-        case 0:
-            /* EOF -> qemu exited */
-            qemu_running = 0;
-            break;
-        default:
-            qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__);
-            break;
-        }
-    }
-
-    /* cleanup */
-    qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid);
-    xc_domain_destroy(xen_xc, xen_domid);
-    _exit(0);
-}
-
-/* normal cleanup */
-static void xen_domain_cleanup(void)
-{
-    char *dom;
-
-    dom = xs_get_domain_path(xenstore, xen_domid);
-    if (dom) {
-        xs_rm(xenstore, 0, dom);
-        free(dom);
-    }
-    xs_release_domain(xenstore, xen_domid);
-}
-
-int xen_domain_build_pv(const char *kernel, const char *ramdisk,
-                        const char *cmdline)
-{
-    uint32_t ssidref = 0;
-    uint32_t flags = 0;
-    xen_domain_handle_t uuid;
-    unsigned int xenstore_port = 0, console_port = 0;
-    unsigned long xenstore_mfn = 0, console_mfn = 0;
-    int rc;
-
-    memcpy(uuid, qemu_uuid, sizeof(uuid));
-    rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
-    if (rc < 0) {
-        fprintf(stderr, "xen: xc_domain_create() failed\n");
-        goto err;
-    }
-    qemu_log("xen: created domain %d\n", xen_domid);
-    atexit(xen_domain_cleanup);
-    if (xen_domain_watcher() == -1) {
-        goto err;
-    }
-
-    xenstore_domain_init1(kernel, ramdisk, cmdline);
-
-    rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
-    if (rc < 0) {
-        fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
-        goto err;
-    }
-
-#if 0
-    rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
-    if (rc < 0) {
-        fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
-        goto err;
-    }
-#endif
-
-    rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10);
-    if (rc < 0) {
-        fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
-        goto err;
-    }
-
-    xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
-    console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
-
-    rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20,
-                        kernel, ramdisk, cmdline,
-                        0, flags,
-                        xenstore_port, &xenstore_mfn,
-                        console_port, &console_mfn);
-    if (rc < 0) {
-        fprintf(stderr, "xen: xc_linux_build() failed\n");
-        goto err;
-    }
-
-    xenstore_domain_init2(xenstore_port, xenstore_mfn,
-                          console_port, console_mfn);
-
-    qemu_log("xen: unpausing domain %d\n", xen_domid);
-    rc = xc_domain_unpause(xen_xc, xen_domid);
-    if (rc < 0) {
-        fprintf(stderr, "xen: xc_domain_unpause() failed\n");
-        goto err;
-    }
-
-    xen_poll = qemu_new_timer_ms(rt_clock, xen_domain_poll, NULL);
-    qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000);
-    return 0;
-
-err:
-    return -1;
-}
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
deleted file mode 100644 (file)
index a8177b6..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * QEMU Xen PV Machine
- *
- * Copyright (c) 2007 Red Hat
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/boards.h"
-#include "hw/xen_backend.h"
-#include "hw/xen_domainbuild.h"
-#include "sysemu/blockdev.h"
-
-static void xen_init_pv(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    X86CPU *cpu;
-    CPUX86State *env;
-    DriveInfo *dinfo;
-    int i;
-
-    /* Initialize a dummy CPU */
-    if (cpu_model == NULL) {
-#ifdef TARGET_X86_64
-        cpu_model = "qemu64";
-#else
-        cpu_model = "qemu32";
-#endif
-    }
-    cpu = cpu_x86_init(cpu_model);
-    env = &cpu->env;
-    env->halted = 1;
-
-    /* Initialize backend core & drivers */
-    if (xen_be_init() != 0) {
-        fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
-        exit(1);
-    }
-
-    switch (xen_mode) {
-    case XEN_ATTACH:
-        /* nothing to do, xend handles everything */
-        break;
-    case XEN_CREATE:
-        if (xen_domain_build_pv(kernel_filename, initrd_filename,
-                                kernel_cmdline) < 0) {
-            fprintf(stderr, "xen pv domain creation failed\n");
-            exit(1);
-        }
-        break;
-    case XEN_EMULATE:
-        fprintf(stderr, "xen emulation not implemented (yet)\n");
-        exit(1);
-        break;
-    }
-
-    xen_be_register("console", &xen_console_ops);
-    xen_be_register("vkbd", &xen_kbdmouse_ops);
-    xen_be_register("vfb", &xen_framebuffer_ops);
-    xen_be_register("qdisk", &xen_blkdev_ops);
-    xen_be_register("qnic", &xen_netdev_ops);
-
-    /* configure framebuffer */
-    if (xenfb_enabled) {
-        xen_config_dev_vfb(0, "vnc");
-        xen_config_dev_vkbd(0);
-    }
-
-    /* configure disks */
-    for (i = 0; i < 16; i++) {
-        dinfo = drive_get(IF_XEN, 0, i);
-        if (!dinfo)
-            continue;
-        xen_config_dev_blk(dinfo);
-    }
-
-    /* configure nics */
-    for (i = 0; i < nb_nics; i++) {
-        if (!nd_table[i].model || 0 != strcmp(nd_table[i].model, "xen"))
-            continue;
-        xen_config_dev_nic(nd_table + i);
-    }
-
-    /* config cleanup hook */
-    atexit(xen_config_cleanup);
-
-    /* setup framebuffer */
-    xen_init_display(xen_domid);
-}
-
-static QEMUMachine xenpv_machine = {
-    .name = "xenpv",
-    .desc = "Xen Para-virtualized PC",
-    .init = xen_init_pv,
-    .max_cpus = 1,
-    .default_machine_opts = "accel=xen",
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void xenpv_machine_init(void)
-{
-    qemu_register_machine(&xenpv_machine);
-}
-
-machine_init(xenpv_machine_init);
diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c
deleted file mode 100644 (file)
index f78c47e..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Xilinx Zynq Baseboard System emulation.
- *
- * Copyright (c) 2010 Xilinx.
- * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com)
- * Copyright (c) 2012 Petalogix Pty Ltd.
- * Written by Haibing Ma
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "net/net.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/flash.h"
-#include "sysemu/blockdev.h"
-#include "hw/loader.h"
-#include "hw/ssi.h"
-
-#define NUM_SPI_FLASHES 4
-#define NUM_QSPI_FLASHES 2
-#define NUM_QSPI_BUSSES 2
-
-#define FLASH_SIZE (64 * 1024 * 1024)
-#define FLASH_SECTOR_SIZE (128 * 1024)
-
-#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
-
-static struct arm_boot_info zynq_binfo = {};
-
-static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    qemu_check_nic_model(nd, "cadence_gem");
-    dev = qdev_create(NULL, "cadence_gem");
-    qdev_set_nic_properties(dev, nd);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(s, 0, base);
-    sysbus_connect_irq(s, 0, irq);
-}
-
-static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
-                                         bool is_qspi)
-{
-    DeviceState *dev;
-    SysBusDevice *busdev;
-    SSIBus *spi;
-    DeviceState *flash_dev;
-    int i, j;
-    int num_busses =  is_qspi ? NUM_QSPI_BUSSES : 1;
-    int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES;
-
-    dev = qdev_create(NULL, "xilinx,spips");
-    qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1);
-    qdev_prop_set_uint8(dev, "num-ss-bits", num_ss);
-    qdev_prop_set_uint8(dev, "num-busses", num_busses);
-    qdev_init_nofail(dev);
-    busdev = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(busdev, 0, base_addr);
-    if (is_qspi) {
-        sysbus_mmio_map(busdev, 1, 0xFC000000);
-    }
-    sysbus_connect_irq(busdev, 0, irq);
-
-    for (i = 0; i < num_busses; ++i) {
-        char bus_name[16];
-        qemu_irq cs_line;
-
-        snprintf(bus_name, 16, "spi%d", i);
-        spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
-
-        for (j = 0; j < num_ss; ++j) {
-            flash_dev = ssi_create_slave_no_init(spi, "n25q128");
-            qdev_init_nofail(flash_dev);
-
-            cs_line = qdev_get_gpio_in(flash_dev, 0);
-            sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
-        }
-    }
-
-}
-
-static void zynq_init(QEMUMachineInitArgs *args)
-{
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    ARMCPU *cpu;
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ext_ram = g_new(MemoryRegion, 1);
-    MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
-    DeviceState *dev;
-    SysBusDevice *busdev;
-    qemu_irq *irqp;
-    qemu_irq pic[64];
-    NICInfo *nd;
-    int n;
-    qemu_irq cpu_irq;
-
-    if (!cpu_model) {
-        cpu_model = "cortex-a9";
-    }
-
-    cpu = cpu_arm_init(cpu_model);
-    if (!cpu) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-    irqp = arm_pic_init_cpu(cpu);
-    cpu_irq = irqp[ARM_PIC_CPU_IRQ];
-
-    /* max 2GB ram */
-    if (ram_size > 0x80000000) {
-        ram_size = 0x80000000;
-    }
-
-    /* DDR remapped to address zero.  */
-    memory_region_init_ram(ext_ram, "zynq.ext_ram", ram_size);
-    vmstate_register_ram_global(ext_ram);
-    memory_region_add_subregion(address_space_mem, 0, ext_ram);
-
-    /* 256K of on-chip memory */
-    memory_region_init_ram(ocm_ram, "zynq.ocm_ram", 256 << 10);
-    vmstate_register_ram_global(ocm_ram);
-    memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
-
-    DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
-
-    /* AMD */
-    pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE,
-                          dinfo ? dinfo->bdrv : NULL, FLASH_SECTOR_SIZE,
-                          FLASH_SIZE/FLASH_SECTOR_SIZE, 1,
-                          1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa,
-                              0);
-
-    dev = qdev_create(NULL, "xilinx,zynq_slcr");
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000);
-
-    dev = qdev_create(NULL, "a9mpcore_priv");
-    qdev_prop_set_uint32(dev, "num-cpu", 1);
-    qdev_init_nofail(dev);
-    busdev = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(busdev, 0, 0xF8F00000);
-    sysbus_connect_irq(busdev, 0, cpu_irq);
-
-    for (n = 0; n < 64; n++) {
-        pic[n] = qdev_get_gpio_in(dev, n);
-    }
-
-    zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET], false);
-    zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false);
-    zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true);
-
-    sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]);
-    sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]);
-
-    sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]);
-    sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]);
-
-    sysbus_create_varargs("cadence_ttc", 0xF8001000,
-            pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL);
-    sysbus_create_varargs("cadence_ttc", 0xF8002000,
-            pic[69-IRQ_OFFSET], pic[70-IRQ_OFFSET], pic[71-IRQ_OFFSET], NULL);
-
-    for (n = 0; n < nb_nics; n++) {
-        nd = &nd_table[n];
-        if (n == 0) {
-            gem_init(nd, 0xE000B000, pic[54-IRQ_OFFSET]);
-        } else if (n == 1) {
-            gem_init(nd, 0xE000C000, pic[77-IRQ_OFFSET]);
-        }
-    }
-
-    dev = qdev_create(NULL, "generic-sdhci");
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]);
-
-    dev = qdev_create(NULL, "generic-sdhci");
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]);
-
-    zynq_binfo.ram_size = ram_size;
-    zynq_binfo.kernel_filename = kernel_filename;
-    zynq_binfo.kernel_cmdline = kernel_cmdline;
-    zynq_binfo.initrd_filename = initrd_filename;
-    zynq_binfo.nb_cpus = 1;
-    zynq_binfo.board_id = 0xd32;
-    zynq_binfo.loader_start = 0;
-    arm_load_kernel(arm_env_get_cpu(first_cpu), &zynq_binfo);
-}
-
-static QEMUMachine zynq_machine = {
-    .name = "xilinx-zynq-a9",
-    .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9",
-    .init = zynq_init,
-    .block_default_type = IF_SCSI,
-    .max_cpus = 1,
-    .no_sdcard = 1,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void zynq_machine_init(void)
-{
-    qemu_register_machine(&zynq_machine);
-}
-
-machine_init(zynq_machine_init);
index 79698e903d31058df06c93960fc76b86a5ecf54b..6ead7820c45ddb825b816ee87c1257fcaf2c9b05 100644 (file)
@@ -1,5 +1,3 @@
-obj-y += xtensa_pic.o
+obj-y += pic_cpu.o
 obj-y += xtensa_sim.o
 obj-y += xtensa_lx60.o
-
-obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c
new file mode 100644 (file)
index 0000000..f485a14
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw/hw.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
+
+void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d)
+{
+    uint32_t old_ccount = env->sregs[CCOUNT];
+
+    env->sregs[CCOUNT] += d;
+
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+        int i;
+        for (i = 0; i < env->config->nccompare; ++i) {
+            if (env->sregs[CCOMPARE + i] - old_ccount <= d) {
+                xtensa_timer_irq(env, i, 1);
+            }
+        }
+    }
+}
+
+void check_interrupts(CPUXtensaState *env)
+{
+    int minlevel = xtensa_get_cintlevel(env);
+    uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
+    int level;
+
+    /* If the CPU is halted advance CCOUNT according to the vm_clock time
+     * elapsed since the moment when it was advanced last time.
+     */
+    if (env->halted) {
+        int64_t now = qemu_get_clock_ns(vm_clock);
+
+        xtensa_advance_ccount(env,
+                muldiv64(now - env->halt_clock,
+                    env->config->clock_freq_khz, 1000000));
+        env->halt_clock = now;
+    }
+    for (level = env->config->nlevel; level > minlevel; --level) {
+        if (env->config->level_mask[level] & int_set_enabled) {
+            env->pending_irq_level = level;
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+            qemu_log_mask(CPU_LOG_INT,
+                    "%s level = %d, cintlevel = %d, "
+                    "pc = %08x, a0 = %08x, ps = %08x, "
+                    "intset = %08x, intenable = %08x, "
+                    "ccount = %08x\n",
+                    __func__, level, xtensa_get_cintlevel(env),
+                    env->pc, env->regs[0], env->sregs[PS],
+                    env->sregs[INTSET], env->sregs[INTENABLE],
+                    env->sregs[CCOUNT]);
+            return;
+        }
+    }
+    env->pending_irq_level = 0;
+    cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+static void xtensa_set_irq(void *opaque, int irq, int active)
+{
+    CPUXtensaState *env = opaque;
+
+    if (irq >= env->config->ninterrupt) {
+        qemu_log("%s: bad IRQ %d\n", __func__, irq);
+    } else {
+        uint32_t irq_bit = 1 << irq;
+
+        if (active) {
+            env->sregs[INTSET] |= irq_bit;
+        } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
+            env->sregs[INTSET] &= ~irq_bit;
+        }
+
+        check_interrupts(env);
+    }
+}
+
+void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active)
+{
+    qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
+}
+
+void xtensa_rearm_ccompare_timer(CPUXtensaState *env)
+{
+    int i;
+    uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
+
+    for (i = 0; i < env->config->nccompare; ++i) {
+        if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
+                wake_ccount - env->sregs[CCOUNT]) {
+            wake_ccount = env->sregs[CCOMPARE + i];
+        }
+    }
+    env->wake_ccount = wake_ccount;
+    qemu_mod_timer(env->ccompare_timer, env->halt_clock +
+            muldiv64(wake_ccount - env->sregs[CCOUNT],
+                1000000, env->config->clock_freq_khz));
+}
+
+static void xtensa_ccompare_cb(void *opaque)
+{
+    XtensaCPU *cpu = opaque;
+    CPUXtensaState *env = &cpu->env;
+
+    if (env->halted) {
+        env->halt_clock = qemu_get_clock_ns(vm_clock);
+        xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
+        if (!cpu_has_work(CPU(cpu))) {
+            env->sregs[CCOUNT] = env->wake_ccount + 1;
+            xtensa_rearm_ccompare_timer(env);
+        }
+    }
+}
+
+void xtensa_irq_init(CPUXtensaState *env)
+{
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+
+    env->irq_inputs = (void **)qemu_allocate_irqs(
+            xtensa_set_irq, env, env->config->ninterrupt);
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
+            env->config->nccompare > 0) {
+        env->ccompare_timer =
+            qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, cpu);
+    }
+}
+
+void *xtensa_get_extint(CPUXtensaState *env, unsigned extint)
+{
+    if (extint < env->config->nextint) {
+        unsigned irq = env->config->extint[extint];
+        return env->irq_inputs[irq];
+    } else {
+        qemu_log("%s: trying to acquire invalid external interrupt %d\n",
+                __func__, extint);
+        return NULL;
+    }
+}
diff --git a/hw/xtensa/xtensa_lx60.c b/hw/xtensa/xtensa_lx60.c
new file mode 100644 (file)
index 0000000..f2a63d8
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+#include "hw/serial.h"
+#include "net/net.h"
+#include "hw/sysbus.h"
+#include "hw/flash.h"
+#include "sysemu/blockdev.h"
+#include "char/char.h"
+#include "hw/xtensa_bootparam.h"
+
+typedef struct LxBoardDesc {
+    size_t flash_size;
+    size_t flash_sector_size;
+    size_t sram_size;
+} LxBoardDesc;
+
+typedef struct Lx60FpgaState {
+    MemoryRegion iomem;
+    uint32_t leds;
+    uint32_t switches;
+} Lx60FpgaState;
+
+static void lx60_fpga_reset(void *opaque)
+{
+    Lx60FpgaState *s = opaque;
+
+    s->leds = 0;
+    s->switches = 0;
+}
+
+static uint64_t lx60_fpga_read(void *opaque, hwaddr addr,
+        unsigned size)
+{
+    Lx60FpgaState *s = opaque;
+
+    switch (addr) {
+    case 0x0: /*build date code*/
+        return 0x09272011;
+
+    case 0x4: /*processor clock frequency, Hz*/
+        return 10000000;
+
+    case 0x8: /*LEDs (off = 0, on = 1)*/
+        return s->leds;
+
+    case 0xc: /*DIP switches (off = 0, on = 1)*/
+        return s->switches;
+    }
+    return 0;
+}
+
+static void lx60_fpga_write(void *opaque, hwaddr addr,
+        uint64_t val, unsigned size)
+{
+    Lx60FpgaState *s = opaque;
+
+    switch (addr) {
+    case 0x8: /*LEDs (off = 0, on = 1)*/
+        s->leds = val;
+        break;
+
+    case 0x10: /*board reset*/
+        if (val == 0xdead) {
+            qemu_system_reset_request();
+        }
+        break;
+    }
+}
+
+static const MemoryRegionOps lx60_fpga_ops = {
+    .read = lx60_fpga_read,
+    .write = lx60_fpga_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static Lx60FpgaState *lx60_fpga_init(MemoryRegion *address_space,
+        hwaddr base)
+{
+    Lx60FpgaState *s = g_malloc(sizeof(Lx60FpgaState));
+
+    memory_region_init_io(&s->iomem, &lx60_fpga_ops, s,
+            "lx60.fpga", 0x10000);
+    memory_region_add_subregion(address_space, base, &s->iomem);
+    lx60_fpga_reset(s);
+    qemu_register_reset(lx60_fpga_reset, s);
+    return s;
+}
+
+static void lx60_net_init(MemoryRegion *address_space,
+        hwaddr base,
+        hwaddr descriptors,
+        hwaddr buffers,
+        qemu_irq irq, NICInfo *nd)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    MemoryRegion *ram;
+
+    dev = qdev_create(NULL, "open_eth");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, irq);
+    memory_region_add_subregion(address_space, base,
+            sysbus_mmio_get_region(s, 0));
+    memory_region_add_subregion(address_space, descriptors,
+            sysbus_mmio_get_region(s, 1));
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, "open_eth.ram", 16384);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(address_space, buffers, ram);
+}
+
+static uint64_t translate_phys_addr(void *env, uint64_t addr)
+{
+    return cpu_get_phys_page_debug(env, addr);
+}
+
+static void lx60_reset(void *opaque)
+{
+    XtensaCPU *cpu = opaque;
+
+    cpu_reset(CPU(cpu));
+}
+
+static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    int be = 1;
+#else
+    int be = 0;
+#endif
+    MemoryRegion *system_memory = get_system_memory();
+    XtensaCPU *cpu = NULL;
+    CPUXtensaState *env = NULL;
+    MemoryRegion *ram, *rom, *system_io;
+    DriveInfo *dinfo;
+    pflash_t *flash = NULL;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    int n;
+
+    if (!cpu_model) {
+        cpu_model = XTENSA_DEFAULT_CPU_MODEL;
+    }
+
+    for (n = 0; n < smp_cpus; n++) {
+        cpu = cpu_xtensa_init(cpu_model);
+        if (cpu == NULL) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        env = &cpu->env;
+
+        env->sregs[PRID] = n;
+        qemu_register_reset(lx60_reset, cpu);
+        /* Need MMU initialized prior to ELF loading,
+         * so that ELF gets loaded into virtual addresses
+         */
+        cpu_reset(CPU(cpu));
+    }
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, "lx60.dram", args->ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(system_memory, 0, ram);
+
+    system_io = g_malloc(sizeof(*system_io));
+    memory_region_init(system_io, "lx60.io", 224 * 1024 * 1024);
+    memory_region_add_subregion(system_memory, 0xf0000000, system_io);
+    lx60_fpga_init(system_io, 0x0d020000);
+    if (nd_table[0].used) {
+        lx60_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000,
+                xtensa_get_extint(env, 1), nd_table);
+    }
+
+    if (!serial_hds[0]) {
+        serial_hds[0] = qemu_chr_new("serial0", "null", NULL);
+    }
+
+    serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0),
+            115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (dinfo) {
+        flash = pflash_cfi01_register(0xf8000000,
+                NULL, "lx60.io.flash", board->flash_size,
+                dinfo->bdrv, board->flash_sector_size,
+                board->flash_size / board->flash_sector_size,
+                4, 0x0000, 0x0000, 0x0000, 0x0000, be);
+        if (flash == NULL) {
+            fprintf(stderr, "Unable to mount pflash\n");
+            exit(1);
+        }
+    }
+
+    /* Use presence of kernel file name as 'boot from SRAM' switch. */
+    if (kernel_filename) {
+        rom = g_malloc(sizeof(*rom));
+        memory_region_init_ram(rom, "lx60.sram", board->sram_size);
+        vmstate_register_ram_global(rom);
+        memory_region_add_subregion(system_memory, 0xfe000000, rom);
+
+        /* Put kernel bootparameters to the end of that SRAM */
+        if (kernel_cmdline) {
+            size_t cmdline_size = strlen(kernel_cmdline) + 1;
+            size_t bp_size = sizeof(BpTag[4]) + cmdline_size;
+            uint32_t tagptr = (0xfe000000 + board->sram_size - bp_size) & ~0xff;
+
+            env->regs[2] = tagptr;
+
+            tagptr = put_tag(tagptr, 0x7b0b, 0, NULL);
+            if (cmdline_size > 1) {
+                tagptr = put_tag(tagptr, 0x1001,
+                        cmdline_size, kernel_cmdline);
+            }
+            tagptr = put_tag(tagptr, 0x7e0b, 0, NULL);
+        }
+        uint64_t elf_entry;
+        uint64_t elf_lowaddr;
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, be, ELF_MACHINE, 0);
+        if (success > 0) {
+            env->pc = elf_entry;
+        }
+    } else {
+        if (flash) {
+            MemoryRegion *flash_mr = pflash_cfi01_get_memory(flash);
+            MemoryRegion *flash_io = g_malloc(sizeof(*flash_io));
+
+            memory_region_init_alias(flash_io, "lx60.flash",
+                    flash_mr, 0, board->flash_size);
+            memory_region_add_subregion(system_memory, 0xfe000000,
+                    flash_io);
+        }
+    }
+}
+
+static void xtensa_lx60_init(QEMUMachineInitArgs *args)
+{
+    static const LxBoardDesc lx60_board = {
+        .flash_size = 0x400000,
+        .flash_sector_size = 0x10000,
+        .sram_size = 0x20000,
+    };
+    lx_init(&lx60_board, args);
+}
+
+static void xtensa_lx200_init(QEMUMachineInitArgs *args)
+{
+    static const LxBoardDesc lx200_board = {
+        .flash_size = 0x1000000,
+        .flash_sector_size = 0x20000,
+        .sram_size = 0x2000000,
+    };
+    lx_init(&lx200_board, args);
+}
+
+static QEMUMachine xtensa_lx60_machine = {
+    .name = "lx60",
+    .desc = "lx60 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
+    .init = xtensa_lx60_init,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static QEMUMachine xtensa_lx200_machine = {
+    .name = "lx200",
+    .desc = "lx200 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
+    .init = xtensa_lx200_init,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void xtensa_lx_machines_init(void)
+{
+    qemu_register_machine(&xtensa_lx60_machine);
+    qemu_register_machine(&xtensa_lx200_machine);
+}
+
+machine_init(xtensa_lx_machines_init);
diff --git a/hw/xtensa/xtensa_sim.c b/hw/xtensa/xtensa_sim.c
new file mode 100644 (file)
index 0000000..5241f8d
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+
+static uint64_t translate_phys_addr(void *env, uint64_t addr)
+{
+    return cpu_get_phys_page_debug(env, addr);
+}
+
+static void sim_reset(void *opaque)
+{
+    XtensaCPU *cpu = opaque;
+
+    cpu_reset(CPU(cpu));
+}
+
+static void xtensa_sim_init(QEMUMachineInitArgs *args)
+{
+    XtensaCPU *cpu = NULL;
+    CPUXtensaState *env = NULL;
+    MemoryRegion *ram, *rom;
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    int n;
+
+    if (!cpu_model) {
+        cpu_model = XTENSA_DEFAULT_CPU_MODEL;
+    }
+
+    for (n = 0; n < smp_cpus; n++) {
+        cpu = cpu_xtensa_init(cpu_model);
+        if (cpu == NULL) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        env = &cpu->env;
+
+        env->sregs[PRID] = n;
+        qemu_register_reset(sim_reset, cpu);
+        /* Need MMU initialized prior to ELF loading,
+         * so that ELF gets loaded into virtual addresses
+         */
+        sim_reset(cpu);
+    }
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, "xtensa.sram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(get_system_memory(), 0, ram);
+
+    rom = g_malloc(sizeof(*rom));
+    memory_region_init_ram(rom, "xtensa.rom", 0x1000);
+    vmstate_register_ram_global(rom);
+    memory_region_add_subregion(get_system_memory(), 0xfe000000, rom);
+
+    if (kernel_filename) {
+        uint64_t elf_entry;
+        uint64_t elf_lowaddr;
+#ifdef TARGET_WORDS_BIGENDIAN
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+#else
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, 0, ELF_MACHINE, 0);
+#endif
+        if (success > 0) {
+            env->pc = elf_entry;
+        }
+    }
+}
+
+static QEMUMachine xtensa_sim_machine = {
+    .name = "sim",
+    .desc = "sim machine (" XTENSA_DEFAULT_CPU_MODEL ")",
+    .is_default = true,
+    .init = xtensa_sim_init,
+    .max_cpus = 4,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void xtensa_sim_machine_init(void)
+{
+    qemu_register_machine(&xtensa_sim_machine);
+}
+
+machine_init(xtensa_sim_machine_init);
diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c
deleted file mode 100644 (file)
index f2a63d8..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the Open Source and Linux Lab nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "hw/serial.h"
-#include "net/net.h"
-#include "hw/sysbus.h"
-#include "hw/flash.h"
-#include "sysemu/blockdev.h"
-#include "char/char.h"
-#include "hw/xtensa_bootparam.h"
-
-typedef struct LxBoardDesc {
-    size_t flash_size;
-    size_t flash_sector_size;
-    size_t sram_size;
-} LxBoardDesc;
-
-typedef struct Lx60FpgaState {
-    MemoryRegion iomem;
-    uint32_t leds;
-    uint32_t switches;
-} Lx60FpgaState;
-
-static void lx60_fpga_reset(void *opaque)
-{
-    Lx60FpgaState *s = opaque;
-
-    s->leds = 0;
-    s->switches = 0;
-}
-
-static uint64_t lx60_fpga_read(void *opaque, hwaddr addr,
-        unsigned size)
-{
-    Lx60FpgaState *s = opaque;
-
-    switch (addr) {
-    case 0x0: /*build date code*/
-        return 0x09272011;
-
-    case 0x4: /*processor clock frequency, Hz*/
-        return 10000000;
-
-    case 0x8: /*LEDs (off = 0, on = 1)*/
-        return s->leds;
-
-    case 0xc: /*DIP switches (off = 0, on = 1)*/
-        return s->switches;
-    }
-    return 0;
-}
-
-static void lx60_fpga_write(void *opaque, hwaddr addr,
-        uint64_t val, unsigned size)
-{
-    Lx60FpgaState *s = opaque;
-
-    switch (addr) {
-    case 0x8: /*LEDs (off = 0, on = 1)*/
-        s->leds = val;
-        break;
-
-    case 0x10: /*board reset*/
-        if (val == 0xdead) {
-            qemu_system_reset_request();
-        }
-        break;
-    }
-}
-
-static const MemoryRegionOps lx60_fpga_ops = {
-    .read = lx60_fpga_read,
-    .write = lx60_fpga_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static Lx60FpgaState *lx60_fpga_init(MemoryRegion *address_space,
-        hwaddr base)
-{
-    Lx60FpgaState *s = g_malloc(sizeof(Lx60FpgaState));
-
-    memory_region_init_io(&s->iomem, &lx60_fpga_ops, s,
-            "lx60.fpga", 0x10000);
-    memory_region_add_subregion(address_space, base, &s->iomem);
-    lx60_fpga_reset(s);
-    qemu_register_reset(lx60_fpga_reset, s);
-    return s;
-}
-
-static void lx60_net_init(MemoryRegion *address_space,
-        hwaddr base,
-        hwaddr descriptors,
-        hwaddr buffers,
-        qemu_irq irq, NICInfo *nd)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    MemoryRegion *ram;
-
-    dev = qdev_create(NULL, "open_eth");
-    qdev_set_nic_properties(dev, nd);
-    qdev_init_nofail(dev);
-
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(s, 0, irq);
-    memory_region_add_subregion(address_space, base,
-            sysbus_mmio_get_region(s, 0));
-    memory_region_add_subregion(address_space, descriptors,
-            sysbus_mmio_get_region(s, 1));
-
-    ram = g_malloc(sizeof(*ram));
-    memory_region_init_ram(ram, "open_eth.ram", 16384);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(address_space, buffers, ram);
-}
-
-static uint64_t translate_phys_addr(void *env, uint64_t addr)
-{
-    return cpu_get_phys_page_debug(env, addr);
-}
-
-static void lx60_reset(void *opaque)
-{
-    XtensaCPU *cpu = opaque;
-
-    cpu_reset(CPU(cpu));
-}
-
-static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
-    int be = 1;
-#else
-    int be = 0;
-#endif
-    MemoryRegion *system_memory = get_system_memory();
-    XtensaCPU *cpu = NULL;
-    CPUXtensaState *env = NULL;
-    MemoryRegion *ram, *rom, *system_io;
-    DriveInfo *dinfo;
-    pflash_t *flash = NULL;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    int n;
-
-    if (!cpu_model) {
-        cpu_model = XTENSA_DEFAULT_CPU_MODEL;
-    }
-
-    for (n = 0; n < smp_cpus; n++) {
-        cpu = cpu_xtensa_init(cpu_model);
-        if (cpu == NULL) {
-            fprintf(stderr, "Unable to find CPU definition\n");
-            exit(1);
-        }
-        env = &cpu->env;
-
-        env->sregs[PRID] = n;
-        qemu_register_reset(lx60_reset, cpu);
-        /* Need MMU initialized prior to ELF loading,
-         * so that ELF gets loaded into virtual addresses
-         */
-        cpu_reset(CPU(cpu));
-    }
-
-    ram = g_malloc(sizeof(*ram));
-    memory_region_init_ram(ram, "lx60.dram", args->ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(system_memory, 0, ram);
-
-    system_io = g_malloc(sizeof(*system_io));
-    memory_region_init(system_io, "lx60.io", 224 * 1024 * 1024);
-    memory_region_add_subregion(system_memory, 0xf0000000, system_io);
-    lx60_fpga_init(system_io, 0x0d020000);
-    if (nd_table[0].used) {
-        lx60_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000,
-                xtensa_get_extint(env, 1), nd_table);
-    }
-
-    if (!serial_hds[0]) {
-        serial_hds[0] = qemu_chr_new("serial0", "null", NULL);
-    }
-
-    serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0),
-            115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
-
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    if (dinfo) {
-        flash = pflash_cfi01_register(0xf8000000,
-                NULL, "lx60.io.flash", board->flash_size,
-                dinfo->bdrv, board->flash_sector_size,
-                board->flash_size / board->flash_sector_size,
-                4, 0x0000, 0x0000, 0x0000, 0x0000, be);
-        if (flash == NULL) {
-            fprintf(stderr, "Unable to mount pflash\n");
-            exit(1);
-        }
-    }
-
-    /* Use presence of kernel file name as 'boot from SRAM' switch. */
-    if (kernel_filename) {
-        rom = g_malloc(sizeof(*rom));
-        memory_region_init_ram(rom, "lx60.sram", board->sram_size);
-        vmstate_register_ram_global(rom);
-        memory_region_add_subregion(system_memory, 0xfe000000, rom);
-
-        /* Put kernel bootparameters to the end of that SRAM */
-        if (kernel_cmdline) {
-            size_t cmdline_size = strlen(kernel_cmdline) + 1;
-            size_t bp_size = sizeof(BpTag[4]) + cmdline_size;
-            uint32_t tagptr = (0xfe000000 + board->sram_size - bp_size) & ~0xff;
-
-            env->regs[2] = tagptr;
-
-            tagptr = put_tag(tagptr, 0x7b0b, 0, NULL);
-            if (cmdline_size > 1) {
-                tagptr = put_tag(tagptr, 0x1001,
-                        cmdline_size, kernel_cmdline);
-            }
-            tagptr = put_tag(tagptr, 0x7e0b, 0, NULL);
-        }
-        uint64_t elf_entry;
-        uint64_t elf_lowaddr;
-        int success = load_elf(kernel_filename, translate_phys_addr, env,
-                &elf_entry, &elf_lowaddr, NULL, be, ELF_MACHINE, 0);
-        if (success > 0) {
-            env->pc = elf_entry;
-        }
-    } else {
-        if (flash) {
-            MemoryRegion *flash_mr = pflash_cfi01_get_memory(flash);
-            MemoryRegion *flash_io = g_malloc(sizeof(*flash_io));
-
-            memory_region_init_alias(flash_io, "lx60.flash",
-                    flash_mr, 0, board->flash_size);
-            memory_region_add_subregion(system_memory, 0xfe000000,
-                    flash_io);
-        }
-    }
-}
-
-static void xtensa_lx60_init(QEMUMachineInitArgs *args)
-{
-    static const LxBoardDesc lx60_board = {
-        .flash_size = 0x400000,
-        .flash_sector_size = 0x10000,
-        .sram_size = 0x20000,
-    };
-    lx_init(&lx60_board, args);
-}
-
-static void xtensa_lx200_init(QEMUMachineInitArgs *args)
-{
-    static const LxBoardDesc lx200_board = {
-        .flash_size = 0x1000000,
-        .flash_sector_size = 0x20000,
-        .sram_size = 0x2000000,
-    };
-    lx_init(&lx200_board, args);
-}
-
-static QEMUMachine xtensa_lx60_machine = {
-    .name = "lx60",
-    .desc = "lx60 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
-    .init = xtensa_lx60_init,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static QEMUMachine xtensa_lx200_machine = {
-    .name = "lx200",
-    .desc = "lx200 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
-    .init = xtensa_lx200_init,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void xtensa_lx_machines_init(void)
-{
-    qemu_register_machine(&xtensa_lx60_machine);
-    qemu_register_machine(&xtensa_lx200_machine);
-}
-
-machine_init(xtensa_lx_machines_init);
diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c
deleted file mode 100644 (file)
index f485a14..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the Open Source and Linux Lab nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "hw/hw.h"
-#include "qemu/log.h"
-#include "qemu/timer.h"
-
-void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d)
-{
-    uint32_t old_ccount = env->sregs[CCOUNT];
-
-    env->sregs[CCOUNT] += d;
-
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
-        int i;
-        for (i = 0; i < env->config->nccompare; ++i) {
-            if (env->sregs[CCOMPARE + i] - old_ccount <= d) {
-                xtensa_timer_irq(env, i, 1);
-            }
-        }
-    }
-}
-
-void check_interrupts(CPUXtensaState *env)
-{
-    int minlevel = xtensa_get_cintlevel(env);
-    uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
-    int level;
-
-    /* If the CPU is halted advance CCOUNT according to the vm_clock time
-     * elapsed since the moment when it was advanced last time.
-     */
-    if (env->halted) {
-        int64_t now = qemu_get_clock_ns(vm_clock);
-
-        xtensa_advance_ccount(env,
-                muldiv64(now - env->halt_clock,
-                    env->config->clock_freq_khz, 1000000));
-        env->halt_clock = now;
-    }
-    for (level = env->config->nlevel; level > minlevel; --level) {
-        if (env->config->level_mask[level] & int_set_enabled) {
-            env->pending_irq_level = level;
-            cpu_interrupt(env, CPU_INTERRUPT_HARD);
-            qemu_log_mask(CPU_LOG_INT,
-                    "%s level = %d, cintlevel = %d, "
-                    "pc = %08x, a0 = %08x, ps = %08x, "
-                    "intset = %08x, intenable = %08x, "
-                    "ccount = %08x\n",
-                    __func__, level, xtensa_get_cintlevel(env),
-                    env->pc, env->regs[0], env->sregs[PS],
-                    env->sregs[INTSET], env->sregs[INTENABLE],
-                    env->sregs[CCOUNT]);
-            return;
-        }
-    }
-    env->pending_irq_level = 0;
-    cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-}
-
-static void xtensa_set_irq(void *opaque, int irq, int active)
-{
-    CPUXtensaState *env = opaque;
-
-    if (irq >= env->config->ninterrupt) {
-        qemu_log("%s: bad IRQ %d\n", __func__, irq);
-    } else {
-        uint32_t irq_bit = 1 << irq;
-
-        if (active) {
-            env->sregs[INTSET] |= irq_bit;
-        } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
-            env->sregs[INTSET] &= ~irq_bit;
-        }
-
-        check_interrupts(env);
-    }
-}
-
-void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active)
-{
-    qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
-}
-
-void xtensa_rearm_ccompare_timer(CPUXtensaState *env)
-{
-    int i;
-    uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
-
-    for (i = 0; i < env->config->nccompare; ++i) {
-        if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
-                wake_ccount - env->sregs[CCOUNT]) {
-            wake_ccount = env->sregs[CCOMPARE + i];
-        }
-    }
-    env->wake_ccount = wake_ccount;
-    qemu_mod_timer(env->ccompare_timer, env->halt_clock +
-            muldiv64(wake_ccount - env->sregs[CCOUNT],
-                1000000, env->config->clock_freq_khz));
-}
-
-static void xtensa_ccompare_cb(void *opaque)
-{
-    XtensaCPU *cpu = opaque;
-    CPUXtensaState *env = &cpu->env;
-
-    if (env->halted) {
-        env->halt_clock = qemu_get_clock_ns(vm_clock);
-        xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
-        if (!cpu_has_work(CPU(cpu))) {
-            env->sregs[CCOUNT] = env->wake_ccount + 1;
-            xtensa_rearm_ccompare_timer(env);
-        }
-    }
-}
-
-void xtensa_irq_init(CPUXtensaState *env)
-{
-    XtensaCPU *cpu = xtensa_env_get_cpu(env);
-
-    env->irq_inputs = (void **)qemu_allocate_irqs(
-            xtensa_set_irq, env, env->config->ninterrupt);
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
-            env->config->nccompare > 0) {
-        env->ccompare_timer =
-            qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, cpu);
-    }
-}
-
-void *xtensa_get_extint(CPUXtensaState *env, unsigned extint)
-{
-    if (extint < env->config->nextint) {
-        unsigned irq = env->config->extint[extint];
-        return env->irq_inputs[irq];
-    } else {
-        qemu_log("%s: trying to acquire invalid external interrupt %d\n",
-                __func__, extint);
-        return NULL;
-    }
-}
diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c
deleted file mode 100644 (file)
index 5241f8d..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the Open Source and Linux Lab nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-
-static uint64_t translate_phys_addr(void *env, uint64_t addr)
-{
-    return cpu_get_phys_page_debug(env, addr);
-}
-
-static void sim_reset(void *opaque)
-{
-    XtensaCPU *cpu = opaque;
-
-    cpu_reset(CPU(cpu));
-}
-
-static void xtensa_sim_init(QEMUMachineInitArgs *args)
-{
-    XtensaCPU *cpu = NULL;
-    CPUXtensaState *env = NULL;
-    MemoryRegion *ram, *rom;
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    int n;
-
-    if (!cpu_model) {
-        cpu_model = XTENSA_DEFAULT_CPU_MODEL;
-    }
-
-    for (n = 0; n < smp_cpus; n++) {
-        cpu = cpu_xtensa_init(cpu_model);
-        if (cpu == NULL) {
-            fprintf(stderr, "Unable to find CPU definition\n");
-            exit(1);
-        }
-        env = &cpu->env;
-
-        env->sregs[PRID] = n;
-        qemu_register_reset(sim_reset, cpu);
-        /* Need MMU initialized prior to ELF loading,
-         * so that ELF gets loaded into virtual addresses
-         */
-        sim_reset(cpu);
-    }
-
-    ram = g_malloc(sizeof(*ram));
-    memory_region_init_ram(ram, "xtensa.sram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(get_system_memory(), 0, ram);
-
-    rom = g_malloc(sizeof(*rom));
-    memory_region_init_ram(rom, "xtensa.rom", 0x1000);
-    vmstate_register_ram_global(rom);
-    memory_region_add_subregion(get_system_memory(), 0xfe000000, rom);
-
-    if (kernel_filename) {
-        uint64_t elf_entry;
-        uint64_t elf_lowaddr;
-#ifdef TARGET_WORDS_BIGENDIAN
-        int success = load_elf(kernel_filename, translate_phys_addr, env,
-                &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
-#else
-        int success = load_elf(kernel_filename, translate_phys_addr, env,
-                &elf_entry, &elf_lowaddr, NULL, 0, ELF_MACHINE, 0);
-#endif
-        if (success > 0) {
-            env->pc = elf_entry;
-        }
-    }
-}
-
-static QEMUMachine xtensa_sim_machine = {
-    .name = "sim",
-    .desc = "sim machine (" XTENSA_DEFAULT_CPU_MODEL ")",
-    .is_default = true,
-    .init = xtensa_sim_init,
-    .max_cpus = 4,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void xtensa_sim_machine_init(void)
-{
-    qemu_register_machine(&xtensa_sim_machine);
-}
-
-machine_init(xtensa_sim_machine_init);
diff --git a/hw/z2.c b/hw/z2.c
deleted file mode 100644 (file)
index cbb6d80..0000000
--- a/hw/z2.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * PXA270-based Zipit Z2 device
- *
- * Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com>
- *
- * Code is based on mainstone platform.
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "hw/hw.h"
-#include "hw/pxa.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
-#include "hw/i2c.h"
-#include "hw/ssi.h"
-#include "hw/boards.h"
-#include "sysemu/sysemu.h"
-#include "hw/flash.h"
-#include "sysemu/blockdev.h"
-#include "ui/console.h"
-#include "audio/audio.h"
-#include "exec/address-spaces.h"
-
-#ifdef DEBUG_Z2
-#define DPRINTF(fmt, ...) \
-        printf(fmt, ## __VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-static struct keymap map[0x100] = {
-    [0 ... 0xff] = { -1, -1 },
-    [0x3b] = {0, 0}, /* Option = F1 */
-    [0xc8] = {0, 1}, /* Up */
-    [0xd0] = {0, 2}, /* Down */
-    [0xcb] = {0, 3}, /* Left */
-    [0xcd] = {0, 4}, /* Right */
-    [0xcf] = {0, 5}, /* End */
-    [0x0d] = {0, 6}, /* KPPLUS */
-    [0xc7] = {1, 0}, /* Home */
-    [0x10] = {1, 1}, /* Q */
-    [0x17] = {1, 2}, /* I */
-    [0x22] = {1, 3}, /* G */
-    [0x2d] = {1, 4}, /* X */
-    [0x1c] = {1, 5}, /* Enter */
-    [0x0c] = {1, 6}, /* KPMINUS */
-    [0xc9] = {2, 0}, /* PageUp */
-    [0x11] = {2, 1}, /* W */
-    [0x18] = {2, 2}, /* O */
-    [0x23] = {2, 3}, /* H */
-    [0x2e] = {2, 4}, /* C */
-    [0x38] = {2, 5}, /* LeftAlt */
-    [0xd1] = {3, 0}, /* PageDown */
-    [0x12] = {3, 1}, /* E */
-    [0x19] = {3, 2}, /* P */
-    [0x24] = {3, 3}, /* J */
-    [0x2f] = {3, 4}, /* V */
-    [0x2a] = {3, 5}, /* LeftShift */
-    [0x01] = {4, 0}, /* Esc */
-    [0x13] = {4, 1}, /* R */
-    [0x1e] = {4, 2}, /* A */
-    [0x25] = {4, 3}, /* K */
-    [0x30] = {4, 4}, /* B */
-    [0x1d] = {4, 5}, /* LeftCtrl */
-    [0x0f] = {5, 0}, /* Tab */
-    [0x14] = {5, 1}, /* T */
-    [0x1f] = {5, 2}, /* S */
-    [0x26] = {5, 3}, /* L */
-    [0x31] = {5, 4}, /* N */
-    [0x39] = {5, 5}, /* Space */
-    [0x3c] = {6, 0}, /* Stop = F2 */
-    [0x15] = {6, 1}, /* Y */
-    [0x20] = {6, 2}, /* D */
-    [0x0e] = {6, 3}, /* Backspace */
-    [0x32] = {6, 4}, /* M */
-    [0x33] = {6, 5}, /* Comma */
-    [0x3d] = {7, 0}, /* Play = F3 */
-    [0x16] = {7, 1}, /* U */
-    [0x21] = {7, 2}, /* F */
-    [0x2c] = {7, 3}, /* Z */
-    [0x27] = {7, 4}, /* Semicolon */
-    [0x34] = {7, 5}, /* Dot */
-};
-
-#define Z2_RAM_SIZE     0x02000000
-#define Z2_FLASH_BASE   0x00000000
-#define Z2_FLASH_SIZE   0x00800000
-
-static struct arm_boot_info z2_binfo = {
-    .loader_start   = PXA2XX_SDRAM_BASE,
-    .ram_size       = Z2_RAM_SIZE,
-};
-
-#define Z2_GPIO_SD_DETECT   96
-#define Z2_GPIO_AC_IN       0
-#define Z2_GPIO_KEY_ON      1
-#define Z2_GPIO_LCD_CS      88
-
-typedef struct {
-    SSISlave ssidev;
-    int32_t selected;
-    int32_t enabled;
-    uint8_t buf[3];
-    uint32_t cur_reg;
-    int pos;
-} ZipitLCD;
-
-static uint32_t zipit_lcd_transfer(SSISlave *dev, uint32_t value)
-{
-    ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
-    uint16_t val;
-    if (z->selected) {
-        z->buf[z->pos] = value & 0xff;
-        z->pos++;
-    }
-    if (z->pos == 3) {
-        switch (z->buf[0]) {
-        case 0x74:
-            DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]);
-            z->cur_reg = z->buf[2];
-            break;
-        case 0x76:
-            val = z->buf[1] << 8 | z->buf[2];
-            DPRINTF("%s: value: 0x%.4x\n", __func__, val);
-            if (z->cur_reg == 0x22 && val == 0x0000) {
-                z->enabled = 1;
-                printf("%s: LCD enabled\n", __func__);
-            } else if (z->cur_reg == 0x10 && val == 0x0000) {
-                z->enabled = 0;
-                printf("%s: LCD disabled\n", __func__);
-            }
-            break;
-        default:
-            DPRINTF("%s: unknown command!\n", __func__);
-            break;
-        }
-        z->pos = 0;
-    }
-    return 0;
-}
-
-static void z2_lcd_cs(void *opaque, int line, int level)
-{
-    ZipitLCD *z2_lcd = opaque;
-    z2_lcd->selected = !level;
-}
-
-static int zipit_lcd_init(SSISlave *dev)
-{
-    ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
-    z->selected = 0;
-    z->enabled = 0;
-    z->pos = 0;
-
-    return 0;
-}
-
-static VMStateDescription vmstate_zipit_lcd_state = {
-    .name = "zipit-lcd",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_SSI_SLAVE(ssidev, ZipitLCD),
-        VMSTATE_INT32(selected, ZipitLCD),
-        VMSTATE_INT32(enabled, ZipitLCD),
-        VMSTATE_BUFFER(buf, ZipitLCD),
-        VMSTATE_UINT32(cur_reg, ZipitLCD),
-        VMSTATE_INT32(pos, ZipitLCD),
-        VMSTATE_END_OF_LIST(),
-    }
-};
-
-static void zipit_lcd_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
-    k->init = zipit_lcd_init;
-    k->transfer = zipit_lcd_transfer;
-    dc->vmsd = &vmstate_zipit_lcd_state;
-}
-
-static const TypeInfo zipit_lcd_info = {
-    .name          = "zipit-lcd",
-    .parent        = TYPE_SSI_SLAVE,
-    .instance_size = sizeof(ZipitLCD),
-    .class_init    = zipit_lcd_class_init,
-};
-
-typedef struct {
-    I2CSlave i2c;
-    int len;
-    uint8_t buf[3];
-} AER915State;
-
-static int aer915_send(I2CSlave *i2c, uint8_t data)
-{
-    AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
-    s->buf[s->len] = data;
-    if (s->len++ > 2) {
-        DPRINTF("%s: message too long (%i bytes)\n",
-            __func__, s->len);
-        return 1;
-    }
-
-    if (s->len == 2) {
-        DPRINTF("%s: reg %d value 0x%02x\n", __func__,
-                s->buf[0], s->buf[1]);
-    }
-
-    return 0;
-}
-
-static void aer915_event(I2CSlave *i2c, enum i2c_event event)
-{
-    AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
-    switch (event) {
-    case I2C_START_SEND:
-        s->len = 0;
-        break;
-    case I2C_START_RECV:
-        if (s->len != 1) {
-            DPRINTF("%s: short message!?\n", __func__);
-        }
-        break;
-    case I2C_FINISH:
-        break;
-    default:
-        break;
-    }
-}
-
-static int aer915_recv(I2CSlave *slave)
-{
-    int retval = 0x00;
-    AER915State *s = FROM_I2C_SLAVE(AER915State, slave);
-
-    switch (s->buf[0]) {
-    /* Return hardcoded battery voltage,
-     * 0xf0 means ~4.1V
-     */
-    case 0x02:
-        retval = 0xf0;
-        break;
-    /* Return 0x00 for other regs,
-     * we don't know what they are for,
-     * anyway they return 0x00 on real hardware.
-     */
-    default:
-        break;
-    }
-
-    return retval;
-}
-
-static int aer915_init(I2CSlave *i2c)
-{
-    /* Nothing to do.  */
-    return 0;
-}
-
-static VMStateDescription vmstate_aer915_state = {
-    .name = "aer915",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT32(len, AER915State),
-        VMSTATE_BUFFER(buf, AER915State),
-        VMSTATE_END_OF_LIST(),
-    }
-};
-
-static void aer915_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
-    k->init = aer915_init;
-    k->event = aer915_event;
-    k->recv = aer915_recv;
-    k->send = aer915_send;
-    dc->vmsd = &vmstate_aer915_state;
-}
-
-static const TypeInfo aer915_info = {
-    .name          = "aer915",
-    .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(AER915State),
-    .class_init    = aer915_class_init,
-};
-
-static void z2_init(QEMUMachineInitArgs *args)
-{
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    MemoryRegion *address_space_mem = get_system_memory();
-    uint32_t sector_len = 0x10000;
-    PXA2xxState *mpu;
-    DriveInfo *dinfo;
-    int be;
-    void *z2_lcd;
-    i2c_bus *bus;
-    DeviceState *wm;
-
-    if (!cpu_model) {
-        cpu_model = "pxa270-c5";
-    }
-
-    /* Setup CPU & memory */
-    mpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model);
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    be = 1;
-#else
-    be = 0;
-#endif
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    if (!dinfo) {
-        fprintf(stderr, "Flash image must be given with the "
-                "'pflash' parameter\n");
-        exit(1);
-    }
-
-    if (!pflash_cfi01_register(Z2_FLASH_BASE,
-                               NULL, "z2.flash0", Z2_FLASH_SIZE,
-                               dinfo->bdrv, sector_len,
-                               Z2_FLASH_SIZE / sector_len, 4, 0, 0, 0, 0,
-                               be)) {
-        fprintf(stderr, "qemu: Error registering flash memory.\n");
-        exit(1);
-    }
-
-    /* setup keypad */
-    pxa27x_register_keypad(mpu->kp, map, 0x100);
-
-    /* MMC/SD host */
-    pxa2xx_mmci_handlers(mpu->mmc,
-        NULL,
-        qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT));
-
-    type_register_static(&zipit_lcd_info);
-    type_register_static(&aer915_info);
-    z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd");
-    bus = pxa2xx_i2c_bus(mpu->i2c[0]);
-    i2c_create_slave(bus, "aer915", 0x55);
-    wm = i2c_create_slave(bus, "wm8750", 0x1b);
-    mpu->i2s->opaque = wm;
-    mpu->i2s->codec_out = wm8750_dac_dat;
-    mpu->i2s->codec_in = wm8750_adc_dat;
-    wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s);
-
-    qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS,
-        qemu_allocate_irqs(z2_lcd_cs, z2_lcd, 1)[0]);
-
-    if (kernel_filename) {
-        z2_binfo.kernel_filename = kernel_filename;
-        z2_binfo.kernel_cmdline = kernel_cmdline;
-        z2_binfo.initrd_filename = initrd_filename;
-        z2_binfo.board_id = 0x6dd;
-        arm_load_kernel(mpu->cpu, &z2_binfo);
-    }
-}
-
-static QEMUMachine z2_machine = {
-    .name = "z2",
-    .desc = "Zipit Z2 (PXA27x)",
-    .init = z2_init,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void z2_machine_init(void)
-{
-    qemu_register_machine(&z2_machine);
-}
-
-machine_init(z2_machine_init);