Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc32 / openbios.c
diff --git a/qemu/roms/openbios/arch/sparc32/openbios.c b/qemu/roms/openbios/arch/sparc32/openbios.c
new file mode 100644 (file)
index 0000000..6f4ee45
--- /dev/null
@@ -0,0 +1,1005 @@
+/* tag: openbios forth environment, executable code
+ *
+ * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer
+ *
+ * See the file "COPYING" for further information about
+ * the copyright and warranty status of this work.
+ */
+
+#include "config.h"
+#include "libopenbios/openbios.h"
+#include "libopenbios/bindings.h"
+#include "libopenbios/console.h"
+#include "drivers/drivers.h"
+#include "asm/types.h"
+#include "dict.h"
+#include "kernel/kernel.h"
+#include "kernel/stack.h"
+#include "arch/common/nvram.h"
+#include "packages/nvram.h"
+#include "../../drivers/timer.h" // XXX
+#include "libopenbios/sys_info.h"
+#include "openbios.h"
+#include "boot.h"
+#include "romvec.h"
+#include "openprom.h"
+#include "psr.h"
+#include "libopenbios/video.h"
+#define NO_QEMU_PROTOS
+#include "arch/common/fw_cfg.h"
+#include "arch/sparc32/ofmem_sparc32.h"
+
+#define MEMORY_SIZE     (128*1024)       /* 128K ram for hosted system */
+#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+#define FW_CFG_SUN4M_DEPTH   (FW_CFG_ARCH_LOCAL + 0x00)
+
+int qemu_machine_type;
+
+struct hwdef {
+    uint64_t iommu_base, slavio_base;
+    uint64_t intctl_base, counter_base, nvram_base, ms_kb_base, serial_base;
+    unsigned long fd_offset, counter_offset, intr_offset;
+    unsigned long aux1_offset, aux2_offset;
+    uint64_t dma_base, esp_base, le_base;
+    uint64_t tcx_base;
+    int intr_ncpu;
+    int mid_offset;
+    int machine_id_low, machine_id_high;
+};
+
+static const struct hwdef hwdefs[] = {
+    /* SS-5 */
+    {
+        .iommu_base   = 0x10000000,
+        .tcx_base     = 0x50000000,
+        .slavio_base  = 0x71000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_offset    = 0x00400000,
+        .counter_offset = 0x00d00000,
+        .intr_offset  = 0x00e00000,
+        .intr_ncpu    = 1,
+        .aux1_offset  = 0x00900000,
+        .aux2_offset  = 0x00910000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .mid_offset   = 0,
+        .machine_id_low = 32,
+        .machine_id_high = 63,
+    },
+    /* SS-10, SS-20 */
+    {
+        .iommu_base   = 0xfe0000000ULL,
+        .tcx_base     = 0xe20000000ULL,
+        .slavio_base  = 0xff1000000ULL,
+        .ms_kb_base   = 0xff1000000ULL,
+        .serial_base  = 0xff1100000ULL,
+        .nvram_base   = 0xff1200000ULL,
+        .fd_offset    = 0x00700000, // 0xff1700000ULL,
+        .counter_offset = 0x00300000, // 0xff1300000ULL,
+        .intr_offset  = 0x00400000, // 0xff1400000ULL,
+        .intr_ncpu    = 4,
+        .aux1_offset  = 0x00800000, // 0xff1800000ULL,
+        .aux2_offset  = 0x00a01000, // 0xff1a01000ULL,
+        .dma_base     = 0xef0400000ULL,
+        .esp_base     = 0xef0800000ULL,
+        .le_base      = 0xef0c00000ULL,
+        .mid_offset   = 8,
+        .machine_id_low = 64,
+        .machine_id_high = 65,
+    },
+    /* SS-600MP */
+    {
+        .iommu_base   = 0xfe0000000ULL,
+        .tcx_base     = 0xe20000000ULL,
+        .slavio_base  = 0xff1000000ULL,
+        .ms_kb_base   = 0xff1000000ULL,
+        .serial_base  = 0xff1100000ULL,
+        .nvram_base   = 0xff1200000ULL,
+        .fd_offset    = -1,
+        .counter_offset = 0x00300000, // 0xff1300000ULL,
+        .intr_offset  = 0x00400000, // 0xff1400000ULL,
+        .intr_ncpu    = 4,
+        .aux1_offset  = 0x00800000, // 0xff1800000ULL,
+        .aux2_offset  = 0x00a01000, // 0xff1a01000ULL, XXX should not exist
+        .dma_base     = 0xef0081000ULL,
+        .esp_base     = 0xef0080000ULL,
+        .le_base      = 0xef0060000ULL,
+        .mid_offset   = 8,
+        .machine_id_low = 66,
+        .machine_id_high = 66,
+    },
+};
+
+static const struct hwdef *hwdef;
+
+void setup_timers(void)
+{
+}
+
+void udelay(unsigned int usecs)
+{
+}
+
+void mdelay(unsigned int msecs)
+{
+}
+
+static void mb86904_init(void)
+{
+    PUSH(32);
+    fword("encode-int");
+    push_str("cache-line-size");
+    fword("property");
+
+    PUSH(512);
+    fword("encode-int");
+    push_str("cache-nlines");
+    fword("property");
+
+    PUSH(0x23);
+    fword("encode-int");
+    push_str("mask_rev");
+    fword("property");
+}
+
+static void tms390z55_init(void)
+{
+    push_str("");
+    fword("encode-string");
+    push_str("ecache-parity?");
+    fword("property");
+
+    push_str("");
+    fword("encode-string");
+    push_str("bfill?");
+    fword("property");
+
+    push_str("");
+    fword("encode-string");
+    push_str("bcopy?");
+    fword("property");
+
+    push_str("");
+    fword("encode-string");
+    push_str("cache-physical?");
+    fword("property");
+
+    PUSH(0xf);
+    fword("encode-int");
+    PUSH(0xf8fffffc);
+    fword("encode-int");
+    fword("encode+");
+    PUSH(4);
+    fword("encode-int");
+    fword("encode+");
+
+    PUSH(0xf);
+    fword("encode-int");
+    fword("encode+");
+    PUSH(0xf8c00000);
+    fword("encode-int");
+    fword("encode+");
+    PUSH(0x1000);
+    fword("encode-int");
+    fword("encode+");
+
+    PUSH(0xf);
+    fword("encode-int");
+    fword("encode+");
+    PUSH(0xf8000000);
+    fword("encode-int");
+    fword("encode+");
+    PUSH(0x1000);
+    fword("encode-int");
+    fword("encode+");
+
+    PUSH(0xf);
+    fword("encode-int");
+    fword("encode+");
+    PUSH(0xf8800000);
+    fword("encode-int");
+    fword("encode+");
+    PUSH(0x1000);
+    fword("encode-int");
+    fword("encode+");
+    push_str("reg");
+    fword("property");
+}
+
+static void rt625_init(void)
+{
+    PUSH(32);
+    fword("encode-int");
+    push_str("cache-line-size");
+    fword("property");
+
+    PUSH(512);
+    fword("encode-int");
+    push_str("cache-nlines");
+    fword("property");
+
+}
+
+static void bad_cpu_init(void)
+{
+    printk("This CPU is not supported yet, freezing.\n");
+    for(;;);
+}
+
+struct cpudef {
+    unsigned long iu_version;
+    const char *name;
+    int psr_impl, psr_vers, impl, vers;
+    int dcache_line_size, dcache_lines, dcache_assoc;
+    int icache_line_size, icache_lines, icache_assoc;
+    int ecache_line_size, ecache_lines, ecache_assoc;
+    int mmu_nctx;
+    void (*initfn)(void);
+};
+
+static const struct cpudef sparc_defs[] = {
+    {
+        .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
+        .name = "FMI,MB86900",
+        .initfn = bad_cpu_init,
+    },
+    {
+        .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
+        .name = "FMI,MB86904",
+        .psr_impl = 0,
+        .psr_vers = 4,
+        .impl = 0,
+        .vers = 4,
+        .dcache_line_size = 0x10,
+        .dcache_lines = 0x200,
+        .dcache_assoc = 1,
+        .icache_line_size = 0x20,
+        .icache_lines = 0x200,
+        .icache_assoc = 1,
+        .ecache_line_size = 0x20,
+        .ecache_lines = 0x4000,
+        .ecache_assoc = 1,
+        .mmu_nctx = 0x100,
+        .initfn = mb86904_init,
+    },
+    {
+        .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
+        .name = "FMI,MB86907",
+        .psr_impl = 0,
+        .psr_vers = 5,
+        .impl = 0,
+        .vers = 5,
+        .dcache_line_size = 0x20,
+        .dcache_lines = 0x200,
+        .dcache_assoc = 1,
+        .icache_line_size = 0x20,
+        .icache_lines = 0x200,
+        .icache_assoc = 1,
+        .ecache_line_size = 0x20,
+        .ecache_lines = 0x4000,
+        .ecache_assoc = 1,
+        .mmu_nctx = 0x100,
+        .initfn = mb86904_init,
+    },
+    {
+        .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
+        .name = "LSI,L64811",
+        .initfn = bad_cpu_init,
+    },
+    {
+        .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
+        .name = "CY,CY7C601",
+        .psr_impl = 1,
+        .psr_vers = 1,
+        .impl = 1,
+        .vers = 1,
+        .mmu_nctx = 0x10,
+        .initfn = bad_cpu_init,
+    },
+    {
+        .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
+        .name = "CY,CY7C611",
+        .initfn = bad_cpu_init,
+    },
+    {
+        .iu_version = 0x40000000,
+        .name = "TI,TMS390Z55",
+        .psr_impl = 4,
+        .psr_vers = 0,
+        .impl = 0,
+        .vers = 4,
+        .dcache_line_size = 0x20,
+        .dcache_lines = 0x80,
+        .dcache_assoc = 4,
+        .icache_line_size = 0x40,
+        .icache_lines = 0x40,
+        .icache_assoc = 5,
+        .ecache_line_size = 0x20,
+        .ecache_lines = 0x8000,
+        .ecache_assoc = 1,
+        .mmu_nctx = 0x10000,
+        .initfn = tms390z55_init,
+    },
+    {
+        .iu_version = 0x41000000,
+        .name = "TI,TMS390S10",
+        .psr_impl = 4,
+        .psr_vers = 1,
+        .impl = 4,
+        .vers = 1,
+        .dcache_line_size = 0x10,
+        .dcache_lines = 0x80,
+        .dcache_assoc = 4,
+        .icache_line_size = 0x20,
+        .icache_lines = 0x80,
+        .icache_assoc = 5,
+        .ecache_line_size = 0x20,
+        .ecache_lines = 0x8000,
+        .ecache_assoc = 1,
+        .mmu_nctx = 0x10000,
+        .initfn = tms390z55_init,
+    },
+    {
+        .iu_version = 0x42000000,
+        .name = "TI,TMS390S10",
+        .psr_impl = 4,
+        .psr_vers = 2,
+        .impl = 4,
+        .vers = 2,
+        .dcache_line_size = 0x10,
+        .dcache_lines = 0x80,
+        .dcache_assoc = 4,
+        .icache_line_size = 0x20,
+        .icache_lines = 0x80,
+        .icache_assoc = 5,
+        .ecache_line_size = 0x20,
+        .ecache_lines = 0x8000,
+        .ecache_assoc = 1,
+        .mmu_nctx = 0x10000,
+        .initfn = tms390z55_init,
+    },
+    {
+        .iu_version = 0x43000000,
+        .name = "TI,TMS390S10",
+        .psr_impl = 4,
+        .psr_vers = 3,
+        .impl = 4,
+        .vers = 3,
+        .dcache_line_size = 0x10,
+        .dcache_lines = 0x80,
+        .dcache_assoc = 4,
+        .icache_line_size = 0x20,
+        .icache_lines = 0x80,
+        .icache_assoc = 5,
+        .ecache_line_size = 0x20,
+        .ecache_lines = 0x8000,
+        .ecache_assoc = 1,
+        .mmu_nctx = 0x10000,
+        .initfn = tms390z55_init,
+    },
+    {
+        .iu_version = 0x44000000,
+        .name = "TI,TMS390S10",
+        .psr_impl = 4,
+        .psr_vers = 4,
+        .impl = 4,
+        .vers = 4,
+        .dcache_line_size = 0x10,
+        .dcache_lines = 0x80,
+        .dcache_assoc = 4,
+        .icache_line_size = 0x20,
+        .icache_lines = 0x80,
+        .icache_assoc = 5,
+        .ecache_line_size = 0x20,
+        .ecache_lines = 0x8000,
+        .ecache_assoc = 1,
+        .mmu_nctx = 0x10000,
+        .initfn = tms390z55_init,
+    },
+    {
+        .iu_version = 0x1e000000,
+        .name = "Ross,RT625",
+        .psr_impl = 1,
+        .psr_vers = 14,
+        .impl = 1,
+        .vers = 7,
+        .dcache_line_size = 0x20,
+        .dcache_lines = 0x80,
+        .dcache_assoc = 4,
+        .icache_line_size = 0x40,
+        .icache_lines = 0x40,
+        .icache_assoc = 5,
+        .ecache_line_size = 0x20,
+        .ecache_lines = 0x8000,
+        .ecache_assoc = 1,
+        .mmu_nctx = 0x10000,
+        .initfn = rt625_init,
+    },
+    {
+        .iu_version = 0x1f000000,
+        .name = "Ross,RT620",
+        .psr_impl = 1,
+        .psr_vers = 15,
+        .impl = 1,
+        .vers = 7,
+        .dcache_line_size = 0x20,
+        .dcache_lines = 0x80,
+        .dcache_assoc = 4,
+        .icache_line_size = 0x40,
+        .icache_lines = 0x40,
+        .icache_assoc = 5,
+        .ecache_line_size = 0x20,
+        .ecache_lines = 0x8000,
+        .ecache_assoc = 1,
+        .mmu_nctx = 0x10000,
+        .initfn = rt625_init,
+    },
+    {
+        .iu_version = 0x20000000,
+        .name = "BIT,B5010",
+        .initfn = bad_cpu_init,
+    },
+    {
+        .iu_version = 0x50000000,
+        .name = "MC,MN10501",
+        .initfn = bad_cpu_init,
+    },
+    {
+        .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
+        .name = "Weitek,W8601",
+        .initfn = bad_cpu_init,
+    },
+    {
+        .iu_version = 0xf2000000,
+        .name = "GR,LEON2",
+        .initfn = bad_cpu_init,
+    },
+    {
+        .iu_version = 0xf3000000,
+        .name = "GR,LEON3",
+        .initfn = bad_cpu_init,
+    },
+};
+
+static const struct cpudef *
+id_cpu(void)
+{
+    unsigned long iu_version;
+    unsigned int i;
+
+    asm("rd %%psr, %0\n"
+        : "=r"(iu_version) :);
+    iu_version &= 0xff000000;
+
+    for (i = 0; i < sizeof(sparc_defs)/sizeof(struct cpudef); i++) {
+        if (iu_version == sparc_defs[i].iu_version)
+            return &sparc_defs[i];
+    }
+    printk("Unknown cpu (psr %lx), freezing!\n", iu_version);
+    for (;;);
+}
+
+static void setup_cpu(int mid_offset)
+{
+    uint32_t temp;
+    unsigned int i;
+    const struct cpudef *cpu;
+
+    // Add cpus
+    temp = fw_cfg_read_i32(FW_CFG_NB_CPUS);
+
+    printk("CPUs: %x", temp);
+    cpu = id_cpu();
+    printk(" x %s\n", cpu->name);
+    for (i = 0; i < temp; i++) {
+        push_str("/");
+        fword("find-device");
+
+        fword("new-device");
+
+        push_str(cpu->name);
+        fword("device-name");
+
+        push_str("cpu");
+        fword("device-type");
+
+        PUSH(cpu->psr_impl);
+        fword("encode-int");
+        push_str("psr-implementation");
+        fword("property");
+
+        PUSH(cpu->psr_vers);
+        fword("encode-int");
+        push_str("psr-version");
+        fword("property");
+
+        PUSH(cpu->impl);
+        fword("encode-int");
+        push_str("implementation");
+        fword("property");
+
+        PUSH(cpu->vers);
+        fword("encode-int");
+        push_str("version");
+        fword("property");
+
+        PUSH(4096);
+        fword("encode-int");
+        push_str("page-size");
+        fword("property");
+
+        PUSH(cpu->dcache_line_size);
+        fword("encode-int");
+        push_str("dcache-line-size");
+        fword("property");
+
+        PUSH(cpu->dcache_lines);
+        fword("encode-int");
+        push_str("dcache-nlines");
+        fword("property");
+
+        PUSH(cpu->dcache_assoc);
+        fword("encode-int");
+        push_str("dcache-associativity");
+        fword("property");
+
+        PUSH(cpu->icache_line_size);
+        fword("encode-int");
+        push_str("icache-line-size");
+        fword("property");
+
+        PUSH(cpu->icache_lines);
+        fword("encode-int");
+        push_str("icache-nlines");
+        fword("property");
+
+        PUSH(cpu->icache_assoc);
+        fword("encode-int");
+        push_str("icache-associativity");
+        fword("property");
+
+        PUSH(cpu->ecache_line_size);
+        fword("encode-int");
+        push_str("ecache-line-size");
+        fword("property");
+
+        PUSH(cpu->ecache_lines);
+        fword("encode-int");
+        push_str("ecache-nlines");
+        fword("property");
+
+        PUSH(cpu->ecache_assoc);
+        fword("encode-int");
+        push_str("ecache-associativity");
+        fword("property");
+
+        PUSH(2);
+        fword("encode-int");
+        push_str("ncaches");
+        fword("property");
+
+        PUSH(cpu->mmu_nctx);
+        fword("encode-int");
+        push_str("mmu-nctx");
+        fword("property");
+
+        PUSH(8);
+        fword("encode-int");
+        push_str("sparc-version");
+        fword("property");
+
+        push_str("");
+        fword("encode-string");
+        push_str("cache-coherence?");
+        fword("property");
+
+        PUSH(i + mid_offset);
+        fword("encode-int");
+        push_str("mid");
+        fword("property");
+
+        cpu->initfn();
+
+        fword("finish-device");
+    }
+}
+
+static void dummy_mach_init(uint64_t base)
+{
+}
+
+struct machdef {
+    uint16_t machine_id;
+    const char *banner_name;
+    const char *model;
+    const char *name;
+    void (*initfn)(uint64_t base);
+};
+
+static const struct machdef sun4m_defs[] = {
+    {
+        .machine_id = 32,
+        .banner_name = "SPARCstation 5",
+        .model = "SUNW,501-3059",
+        .name = "SUNW,SPARCstation-5",
+        .initfn = ss5_init,
+    },
+    {
+        .machine_id = 33,
+        .banner_name = "SPARCstation Voyager",
+        .model = "SUNW,501-2581",
+        .name = "SUNW,SPARCstation-Voyager",
+        .initfn = dummy_mach_init,
+    },
+    {
+        .machine_id = 34,
+        .banner_name = "SPARCstation LX",
+        .model = "SUNW,501-2031",
+        .name = "SUNW,SPARCstation-LX",
+        .initfn = dummy_mach_init,
+    },
+    {
+        .machine_id = 35,
+        .banner_name = "SPARCstation 4",
+        .model = "SUNW,501-2572",
+        .name = "SUNW,SPARCstation-4",
+        .initfn = ss5_init,
+    },
+    {
+        .machine_id = 36,
+        .banner_name = "SPARCstation Classic",
+        .model = "SUNW,501-2326",
+        .name = "SUNW,SPARCstation-Classic",
+        .initfn = dummy_mach_init,
+    },
+    {
+        .machine_id = 37,
+        .banner_name = "Tadpole S3 GX",
+        .model = "S3",
+        .name = "Tadpole_S3GX",
+        .initfn = ss5_init,
+    },
+    {
+        .machine_id = 64,
+        .banner_name = "SPARCstation 10 (1 X 390Z55)",
+        .model = "SUNW,S10,501-2365",
+        .name = "SUNW,SPARCstation-10",
+        .initfn = ob_eccmemctl_init,
+    },
+    {
+        .machine_id = 65,
+        .banner_name = "SPARCstation 20 (1 X 390Z55)",
+        .model = "SUNW,S20,501-2324",
+        .name = "SUNW,SPARCstation-20",
+        .initfn = ob_eccmemctl_init,
+    },
+    {
+        .machine_id = 66,
+        .banner_name = "SPARCsystem 600(1 X 390Z55)",
+        .model = NULL,
+        .name = "SUNW,SPARCsystem-600",
+        .initfn = ob_eccmemctl_init,
+    },
+};
+
+static const struct machdef *
+id_machine(uint16_t machine_id)
+{
+    unsigned int i;
+
+    for (i = 0; i < sizeof(sun4m_defs)/sizeof(struct machdef); i++) {
+        if (machine_id == sun4m_defs[i].machine_id)
+            return &sun4m_defs[i];
+    }
+    printk("Unknown machine (ID %d), freezing!\n", machine_id);
+    for (;;);
+}
+
+static void setup_machine(uint64_t base)
+{
+    uint16_t machine_id;
+    const struct machdef *mach;
+
+    machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
+    mach = id_machine(machine_id);
+
+    push_str("/");
+    fword("find-device");
+    push_str(mach->banner_name);
+    fword("encode-string");
+    push_str("banner-name");
+    fword("property");
+
+    if (mach->model) {
+        push_str(mach->model);
+        fword("encode-string");
+        push_str("model");
+        fword("property");
+    }
+    push_str(mach->name);
+    fword("encode-string");
+    push_str("name");
+    fword("property");
+
+    mach->initfn(base);
+}
+
+/* Add /uuid */
+static void setup_uuid(void)
+{
+    static uint8_t qemu_uuid[16];
+
+    fw_cfg_read(FW_CFG_UUID, (char *)qemu_uuid, 16);
+
+    printk("UUID: " UUID_FMT "\n", 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]);
+
+    push_str("/");
+    fword("find-device");
+
+    PUSH((long)&qemu_uuid);
+    PUSH(16);
+    fword("encode-bytes");
+    push_str("uuid");
+    fword("property");
+}
+
+static void setup_stdio(void)
+{
+    char nographic;
+    const char *stdin, *stdout;
+
+    fw_cfg_read(FW_CFG_NOGRAPHIC, &nographic, 1);
+    if (nographic) {
+        obp_stdin = PROMDEV_TTYA;
+        obp_stdout = PROMDEV_TTYA;
+        stdin = "ttya";
+        stdout = "ttya";
+    } else {
+        obp_stdin = PROMDEV_KBD;
+        obp_stdout = PROMDEV_SCREEN;
+        stdin = "keyboard";
+        stdout = "screen";
+    }
+
+    push_str(stdin);
+    push_str("input-device");
+    fword("$setenv");
+
+    push_str(stdout);
+    push_str("output-device");
+    fword("$setenv");
+
+    obp_stdin_path = stdin;
+    obp_stdout_path = stdout;
+}
+
+static void init_memory(void)
+{
+    phys_addr_t phys;
+    ucell virt;
+    
+    /* Claim the memory from OFMEM */
+    phys = ofmem_claim_phys(-1, MEMORY_SIZE, PAGE_SIZE);
+    if (!phys)
+        printk("panic: not enough physical memory on host system.\n");
+    
+    virt = ofmem_claim_virt(OF_CODE_START - MEMORY_SIZE, MEMORY_SIZE, 0);
+    if (!virt)
+        printk("panic: not enough virtual memory on host system.\n");
+
+    /* Generate the mapping (and lock translation into the TLBs) */
+    ofmem_map(phys, virt, MEMORY_SIZE, ofmem_arch_default_translation_mode(phys));
+
+    /* we push start and end of memory to the stack
+     * so that it can be used by the forth word QUIT
+     * to initialize the memory allocator
+     */
+    
+    PUSH(virt);
+    PUSH(virt + MEMORY_SIZE);
+}
+
+static void
+arch_init( void )
+{
+       char *cmdline;
+        const char *kernel_cmdline;
+        uint32_t temp;
+        uint16_t machine_id;
+        char buf[256];
+        unsigned long mem_size;
+
+        fw_cfg_init();
+
+        fw_cfg_read(FW_CFG_SIGNATURE, buf, 4);
+        buf[4] = '\0';
+
+        printk("Configuration device id %s", buf);
+
+        temp = fw_cfg_read_i32(FW_CFG_ID);
+        machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
+
+        printk(" version %d machine id %d\n", temp, machine_id);
+
+        if (temp != 1) {
+            printk("Incompatible configuration device version, freezing\n");
+            for(;;);
+        }
+
+        graphic_depth = fw_cfg_read_i16(FW_CFG_SUN4M_DEPTH);
+
+       openbios_init();
+       modules_init();
+        ob_init_mmu();
+        ob_init_iommu(hwdef->iommu_base);
+#ifdef CONFIG_DRIVER_OBIO
+        mem_size = fw_cfg_read_i32(FW_CFG_RAM_SIZE);
+       ob_obio_init(hwdef->slavio_base, hwdef->fd_offset,
+                     hwdef->counter_offset, hwdef->intr_offset, hwdef->intr_ncpu,
+                     hwdef->aux1_offset, hwdef->aux2_offset,
+                     mem_size);
+
+        setup_machine(hwdef->slavio_base);
+
+        nvconf_init();
+#endif
+#ifdef CONFIG_DRIVER_SBUS
+#ifdef CONFIG_DEBUG_CONSOLE_VIDEO
+       setup_video();
+#endif
+       ob_sbus_init(hwdef->iommu_base + 0x1000ULL, qemu_machine_type);
+#endif
+       device_end();
+
+        setup_cpu(hwdef->mid_offset);
+
+        setup_stdio();
+       /* Initialiase openprom romvec */
+        romvec = init_openprom();
+
+       kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE);
+       if (kernel_size) {
+               kernel_image = fw_cfg_read_i32(FW_CFG_KERNEL_ADDR);
+
+               /* Mark the kernel memory as in use */
+               ofmem_claim_phys(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), 0);
+               ofmem_claim_virt(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), 0);
+       }
+
+        kernel_cmdline = (const char *) fw_cfg_read_i32(FW_CFG_KERNEL_CMDLINE);
+        if (kernel_cmdline) {
+            cmdline = strdup(kernel_cmdline);
+            obp_arg.argv[1] = cmdline;
+        } else {
+           cmdline = strdup("");
+       }
+       qemu_cmdline = (uint32_t)cmdline;
+
+        /* Setup nvram variables */
+        push_str("/options");
+        fword("find-device");
+        push_str(cmdline);
+        fword("encode-string");
+        push_str("boot-file");
+        fword("property");
+
+       boot_device = fw_cfg_read_i16(FW_CFG_BOOT_DEVICE);
+
+       switch (boot_device) {
+       case 'a':
+               push_str("floppy");
+               break;
+       case 'c':
+               push_str("disk");
+               break;
+       default:
+       case 'd':
+               push_str("cdrom:d cdrom");
+               break;
+       case 'n':
+               push_str("net");
+               break;
+       }
+
+       fword("encode-string");
+       push_str("boot-device");
+       fword("property");
+
+       device_end();
+       
+       bind_func("platform-boot", boot );
+       bind_func("(go)", go );
+       
+       /* Set up other properties */
+        push_str("/chosen");
+        fword("find-device");
+
+        setup_uuid();
+
+       /* Enable interrupts */
+       temp = get_psr();
+       temp = (temp & ~PSR_PIL) | (13 << 8); /* Enable CPU timer interrupt (level 14) */
+       put_psr(temp);
+}
+
+extern struct _console_ops arch_console_ops;
+
+int openbios(void)
+{
+        unsigned int i;
+
+        for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) {
+            if (hwdefs[i].machine_id_low <= qemu_machine_type &&
+                hwdefs[i].machine_id_high >= qemu_machine_type) {
+                hwdef = &hwdefs[i];
+                break;
+            }
+        }
+        if (!hwdef)
+            for(;;); // Internal inconsistency, hang
+
+#ifdef CONFIG_DEBUG_CONSOLE
+        init_console(arch_console_ops);
+#endif
+        /* Make sure we setup OFMEM before the MMU as we need malloc() to setup page tables */
+        ofmem_init();
+
+#ifdef CONFIG_DRIVER_SBUS
+        init_mmu_swift();
+#endif
+#ifdef CONFIG_DEBUG_CONSOLE
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+       escc_uart_init(hwdef->serial_base | (CONFIG_SERIAL_PORT? 0ULL: 4ULL),
+                  CONFIG_SERIAL_SPEED);
+#endif
+#ifdef CONFIG_DEBUG_CONSOLE_VIDEO
+       kbd_init(hwdef->ms_kb_base);
+#endif
+#endif
+
+        collect_sys_info(&sys_info);
+
+        dict = (unsigned char *)sys_info.dict_start;
+        dicthead = (cell)sys_info.dict_end;
+        last = sys_info.dict_last;
+        dictlimit = sys_info.dict_limit;
+
+       forth_init();
+
+#ifdef CONFIG_DEBUG_BOOT
+       printk("forth started.\n");
+       printk("initializing memory...");
+#endif
+
+       init_memory();
+
+#ifdef CONFIG_DEBUG_BOOT
+       printk("done\n");
+#endif
+
+       PUSH_xt( bind_noname_func(arch_init) );
+       fword("PREPOST-initializer");
+
+       PC = (ucell)findword("initialize-of");
+
+       if (!PC) {
+               printk("panic: no dictionary entry point.\n");
+               return -1;
+       }
+#ifdef CONFIG_DEBUG_DICTIONARY
+       printk("done (%d bytes).\n", dicthead);
+       printk("Jumping to dictionary...\n");
+#endif
+
+       enterforth((xt_t)PC);
+
+        free(dict);
+       return 0;
+}