summaryrefslogtreecommitdiffstats
path: root/src/roms/openbios/arch/ppc/qemu
diff options
context:
space:
mode:
Diffstat (limited to 'src/roms/openbios/arch/ppc/qemu')
-rw-r--r--src/roms/openbios/arch/ppc/qemu/console.c88
-rw-r--r--src/roms/openbios/arch/ppc/qemu/init.c1013
-rw-r--r--src/roms/openbios/arch/ppc/qemu/kernel.c115
-rw-r--r--src/roms/openbios/arch/ppc/qemu/kernel.h42
-rw-r--r--src/roms/openbios/arch/ppc/qemu/ldscript68
-rw-r--r--src/roms/openbios/arch/ppc/qemu/main.c85
-rw-r--r--src/roms/openbios/arch/ppc/qemu/methods.c329
-rw-r--r--src/roms/openbios/arch/ppc/qemu/mmutypes.h97
-rw-r--r--src/roms/openbios/arch/ppc/qemu/ofmem.c563
-rw-r--r--src/roms/openbios/arch/ppc/qemu/qemu.c106
-rw-r--r--src/roms/openbios/arch/ppc/qemu/qemu.fs123
-rw-r--r--src/roms/openbios/arch/ppc/qemu/qemu.h24
-rw-r--r--src/roms/openbios/arch/ppc/qemu/start.S729
-rw-r--r--src/roms/openbios/arch/ppc/qemu/tree.fs79
-rw-r--r--src/roms/openbios/arch/ppc/qemu/vfd.c42
15 files changed, 3503 insertions, 0 deletions
diff --git a/src/roms/openbios/arch/ppc/qemu/console.c b/src/roms/openbios/arch/ppc/qemu/console.c
new file mode 100644
index 0000000..53a3215
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/console.c
@@ -0,0 +1,88 @@
+/*
+ * <console.c>
+ *
+ * Simple text console
+ *
+ * Copyright (C) 2005 Stefan Reinauer <stepan@openbios.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
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "libopenbios/console.h"
+#include "drivers/drivers.h"
+
+#ifdef CONFIG_DEBUG_CONSOLE
+/* ******************************************************************
+ * common functions, implementing simple concurrent console
+ * ****************************************************************** */
+
+static int mac_putchar(int c)
+{
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ escc_uart_putchar(c & 0xff);
+#endif
+ return c;
+}
+
+static int mac_availchar(void)
+{
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ if (escc_uart_charav(CONFIG_SERIAL_PORT))
+ return 1;
+#endif
+ return 0;
+}
+
+static int mac_getchar(void)
+{
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ if (escc_uart_charav(CONFIG_SERIAL_PORT))
+ return (escc_uart_getchar(CONFIG_SERIAL_PORT));
+#endif
+ return 0;
+}
+
+struct _console_ops mac_console_ops = {
+ .putchar = mac_putchar,
+ .availchar = mac_availchar,
+ .getchar = mac_getchar
+};
+
+static int prep_putchar(int c)
+{
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ uart_putchar(c & 0xff);
+#endif
+ return c;
+}
+
+static int prep_availchar(void)
+{
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ if (uart_charav(CONFIG_SERIAL_PORT))
+ return 1;
+#endif
+ return 0;
+}
+
+static int prep_getchar(void)
+{
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ if (uart_charav(CONFIG_SERIAL_PORT))
+ return (uart_getchar(CONFIG_SERIAL_PORT));
+#endif
+ return 0;
+}
+
+struct _console_ops prep_console_ops = {
+ .putchar = prep_putchar,
+ .availchar = prep_availchar,
+ .getchar = prep_getchar
+};
+
+#endif // CONFIG_DEBUG_CONSOLE
diff --git a/src/roms/openbios/arch/ppc/qemu/init.c b/src/roms/openbios/arch/ppc/qemu/init.c
new file mode 100644
index 0000000..2b5b8e1
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/init.c
@@ -0,0 +1,1013 @@
+/*
+ * Creation Date: <2004/08/28 18:38:22 greg>
+ * Time-stamp: <2004/08/28 18:38:22 greg>
+ *
+ * <init.c>
+ *
+ * Initialization for qemu
+ *
+ * Copyright (C) 2004 Greg Watson
+ * Copyright (C) 2005 Stefan Reinauer
+ *
+ * based on mol/init.c:
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Samuel & David Rydh
+ * (samuel@ibrium.se, dary@lindesign.se)
+ *
+ * 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
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/openbios.h"
+#include "libopenbios/bindings.h"
+#include "libopenbios/console.h"
+#include "drivers/pci.h"
+#include "arch/common/nvram.h"
+#include "drivers/drivers.h"
+#include "qemu/qemu.h"
+#include "libopenbios/ofmem.h"
+#include "openbios-version.h"
+#include "libc/byteorder.h"
+#include "libc/vsprintf.h"
+#define NO_QEMU_PROTOS
+#include "arch/common/fw_cfg.h"
+#include "arch/ppc/processor.h"
+
+#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+
+struct cpudef {
+ unsigned int iu_version;
+ const char *name;
+ int icache_size, dcache_size;
+ int icache_sets, dcache_sets;
+ int icache_block_size, dcache_block_size;
+ int tlb_sets, tlb_size;
+ void (*initfn)(const struct cpudef *cpu);
+};
+
+static uint16_t machine_id = 0;
+
+extern void unexpected_excep(int vector);
+
+void
+unexpected_excep(int vector)
+{
+ printk("openbios panic: Unexpected exception %x\n", vector);
+ for (;;) {
+ }
+}
+
+extern void __divide_error(void);
+
+void
+__divide_error(void)
+{
+ return;
+}
+
+enum {
+ ARCH_PREP = 0,
+ ARCH_MAC99,
+ ARCH_HEATHROW,
+ ARCH_MAC99_U3,
+};
+
+int is_apple(void)
+{
+ return is_oldworld() || is_newworld();
+}
+
+int is_oldworld(void)
+{
+ return machine_id == ARCH_HEATHROW;
+}
+
+int is_newworld(void)
+{
+ return (machine_id == ARCH_MAC99) ||
+ (machine_id == ARCH_MAC99_U3);
+}
+
+static const pci_arch_t known_arch[] = {
+ [ARCH_PREP] = {
+ .name = "PREP",
+ .vendor_id = PCI_VENDOR_ID_MOTOROLA,
+ .device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN,
+ .cfg_addr = 0x80000cf8,
+ .cfg_data = 0x80000cfc,
+ .cfg_base = 0x80000000,
+ .cfg_len = 0x00100000,
+ .host_pci_base = 0xc0000000,
+ .pci_mem_base = 0x100000, /* avoid VGA at 0xa0000 */
+ .mem_len = 0x10000000,
+ .io_base = 0x80000000,
+ .io_len = 0x00010000,
+ .rbase = 0x00000000,
+ .rlen = 0x00400000,
+ .irqs = { 9, 11, 9, 11 }
+ },
+ [ARCH_MAC99] = {
+ .name = "MAC99",
+ .vendor_id = PCI_VENDOR_ID_APPLE,
+ .device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI,
+ .cfg_addr = 0xf2800000,
+ .cfg_data = 0xf2c00000,
+ .cfg_base = 0xf2000000,
+ .cfg_len = 0x02000000,
+ .host_pci_base = 0x0,
+ .pci_mem_base = 0x80000000,
+ .mem_len = 0x10000000,
+ .io_base = 0xf2000000,
+ .io_len = 0x00800000,
+ .rbase = 0x00000000,
+ .rlen = 0x01000000,
+ .irqs = { 0x1b, 0x1c, 0x1d, 0x1e }
+ },
+ [ARCH_MAC99_U3] = {
+ .name = "MAC99_U3",
+ .vendor_id = PCI_VENDOR_ID_APPLE,
+ .device_id = PCI_DEVICE_ID_APPLE_U3_AGP,
+ .cfg_addr = 0xf0800000,
+ .cfg_data = 0xf0c00000,
+ .cfg_base = 0xf0000000,
+ .cfg_len = 0x02000000,
+ .host_pci_base = 0x0,
+ .pci_mem_base = 0x80000000,
+ .mem_len = 0x10000000,
+ .io_base = 0xf2000000,
+ .io_len = 0x00800000,
+ .rbase = 0x00000000,
+ .rlen = 0x01000000,
+ .irqs = { 0x1b, 0x1c, 0x1d, 0x1e }
+ },
+ [ARCH_HEATHROW] = {
+ .name = "HEATHROW",
+ .vendor_id = PCI_VENDOR_ID_MOTOROLA,
+ .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106,
+ .cfg_addr = 0xfec00000,
+ .cfg_data = 0xfee00000,
+ .cfg_base = 0x80000000,
+ .cfg_len = 0x7f000000,
+ .host_pci_base = 0x0,
+ .pci_mem_base = 0x80000000,
+ .mem_len = 0x10000000,
+ .io_base = 0xfe000000,
+ .io_len = 0x00800000,
+ .rbase = 0xfd000000,
+ .rlen = 0x01000000,
+ .irqs = { 21, 22, 23, 24 }
+ },
+};
+unsigned long isa_io_base;
+
+extern struct _console_ops mac_console_ops, prep_console_ops;
+
+void
+entry(void)
+{
+ uint32_t temp = 0;
+ char buf[5];
+
+ arch = &known_arch[ARCH_HEATHROW];
+
+ fw_cfg_init();
+
+ fw_cfg_read(FW_CFG_SIGNATURE, buf, 4);
+ buf[4] = '\0';
+ if (strncmp(buf, "QEMU", 4) == 0) {
+ temp = fw_cfg_read_i32(FW_CFG_ID);
+ if (temp == 1) {
+ machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
+ arch = &known_arch[machine_id];
+ }
+ }
+
+ isa_io_base = arch->io_base;
+
+#ifdef CONFIG_DEBUG_CONSOLE
+ if (is_apple()) {
+ init_console(mac_console_ops);
+ } else {
+ init_console(prep_console_ops);
+ }
+#endif
+
+ if (temp != 1) {
+ printk("Incompatible configuration device version, freezing\n");
+ for (;;) {
+ }
+ }
+
+ ofmem_init();
+ initialize_forth();
+ /* won't return */
+
+ printk("of_startup returned!\n");
+ for (;;) {
+ }
+}
+
+/* -- phys.lo ... phys.hi */
+static void
+push_physaddr(phys_addr_t value)
+{
+ PUSH(value);
+#ifdef CONFIG_PPC64
+ PUSH(value >> 32);
+#endif
+}
+
+/* From drivers/timer.c */
+extern unsigned long timer_freq;
+
+static void
+cpu_generic_init(const struct cpudef *cpu)
+{
+ push_str("/cpus");
+ fword("find-device");
+
+ fword("new-device");
+
+ push_str(cpu->name);
+ fword("device-name");
+
+ push_str("cpu");
+ fword("device-type");
+
+ PUSH(mfpvr());
+ fword("encode-int");
+ push_str("cpu-version");
+ fword("property");
+
+ PUSH(cpu->dcache_size);
+ fword("encode-int");
+ push_str("d-cache-size");
+ fword("property");
+
+ PUSH(cpu->icache_size);
+ fword("encode-int");
+ push_str("i-cache-size");
+ fword("property");
+
+ PUSH(cpu->dcache_sets);
+ fword("encode-int");
+ push_str("d-cache-sets");
+ fword("property");
+
+ PUSH(cpu->icache_sets);
+ fword("encode-int");
+ push_str("i-cache-sets");
+ fword("property");
+
+ PUSH(cpu->dcache_block_size);
+ fword("encode-int");
+ push_str("d-cache-block-size");
+ fword("property");
+
+ PUSH(cpu->icache_block_size);
+ fword("encode-int");
+ push_str("i-cache-block-size");
+ fword("property");
+
+ PUSH(cpu->tlb_sets);
+ fword("encode-int");
+ push_str("tlb-sets");
+ fword("property");
+
+ PUSH(cpu->tlb_size);
+ fword("encode-int");
+ push_str("tlb-size");
+ fword("property");
+
+ timer_freq = fw_cfg_read_i32(FW_CFG_PPC_TBFREQ);
+ PUSH(timer_freq);
+ fword("encode-int");
+ push_str("timebase-frequency");
+ fword("property");
+
+ PUSH(fw_cfg_read_i32(FW_CFG_PPC_CLOCKFREQ));
+ fword("encode-int");
+ push_str("clock-frequency");
+ fword("property");
+
+ PUSH(fw_cfg_read_i32(FW_CFG_PPC_BUSFREQ));
+ fword("encode-int");
+ push_str("bus-frequency");
+ fword("property");
+
+ push_str("running");
+ fword("encode-string");
+ push_str("state");
+ fword("property");
+
+ PUSH(0x20);
+ fword("encode-int");
+ push_str("reservation-granule-size");
+ fword("property");
+}
+
+static void
+cpu_add_pir_property(void)
+{
+ unsigned long pir;
+
+ asm("mfspr %0, 1023\n"
+ : "=r"(pir) :);
+ PUSH(pir);
+ fword("encode-int");
+ push_str("reg");
+ fword("property");
+}
+
+static void
+cpu_604_init(const struct cpudef *cpu)
+{
+ cpu_generic_init(cpu);
+ cpu_add_pir_property();
+
+ fword("finish-device");
+}
+
+static void
+cpu_750_init(const struct cpudef *cpu)
+{
+ cpu_generic_init(cpu);
+
+ PUSH(0);
+ fword("encode-int");
+ push_str("reg");
+ fword("property");
+
+ fword("finish-device");
+}
+
+static void
+cpu_g4_init(const struct cpudef *cpu)
+{
+ cpu_generic_init(cpu);
+ cpu_add_pir_property();
+
+ fword("finish-device");
+}
+
+#ifdef CONFIG_PPC_64BITSUPPORT
+/* In order to get 64 bit aware handlers that rescue all our
+ GPRs from getting truncated to 32 bits, we need to patch the
+ existing handlers so they jump to our 64 bit aware ones. */
+static void
+ppc64_patch_handlers(void)
+{
+ uint32_t *dsi = (uint32_t *)0x300UL;
+ uint32_t *isi = (uint32_t *)0x400UL;
+
+ // Patch the first DSI handler instruction to: ba 0x2000
+ *dsi = 0x48002002;
+
+ // Patch the first ISI handler instruction to: ba 0x2200
+ *isi = 0x48002202;
+
+ // Invalidate the cache lines
+ asm ("icbi 0, %0" : : "r"(dsi));
+ asm ("icbi 0, %0" : : "r"(isi));
+}
+#endif
+
+static void
+cpu_970_init(const struct cpudef *cpu)
+{
+ cpu_generic_init(cpu);
+
+ PUSH(0);
+ fword("encode-int");
+ push_str("reg");
+ fword("property");
+
+ PUSH(0);
+ PUSH(0);
+ fword("encode-bytes");
+ push_str("64-bit");
+ fword("property");
+
+ fword("finish-device");
+
+#ifdef CONFIG_PPC_64BITSUPPORT
+ /* The 970 is a PPC64 CPU, so we need to activate
+ * 64bit aware interrupt handlers */
+
+ ppc64_patch_handlers();
+#endif
+
+ /* The 970 also implements the HIOR which we need to set to 0 */
+
+ mtspr(S_HIOR, 0);
+}
+
+static const struct cpudef ppc_defs[] = {
+ {
+ .iu_version = 0x00040000,
+ .name = "PowerPC,604",
+ .icache_size = 0x4000,
+ .dcache_size = 0x4000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x20,
+ .dcache_block_size = 0x20,
+ .tlb_sets = 0x40,
+ .tlb_size = 0x80,
+ .initfn = cpu_604_init,
+ },
+ { // XXX find out real values
+ .iu_version = 0x00090000,
+ .name = "PowerPC,604e",
+ .icache_size = 0x4000,
+ .dcache_size = 0x4000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x20,
+ .dcache_block_size = 0x20,
+ .tlb_sets = 0x40,
+ .tlb_size = 0x80,
+ .initfn = cpu_604_init,
+ },
+ { // XXX find out real values
+ .iu_version = 0x000a0000,
+ .name = "PowerPC,604r",
+ .icache_size = 0x4000,
+ .dcache_size = 0x4000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x20,
+ .dcache_block_size = 0x20,
+ .tlb_sets = 0x40,
+ .tlb_size = 0x80,
+ .initfn = cpu_604_init,
+ },
+ { // XXX find out real values
+ .iu_version = 0x80040000,
+ .name = "PowerPC,MPC86xx",
+ .icache_size = 0x8000,
+ .dcache_size = 0x8000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x20,
+ .dcache_block_size = 0x20,
+ .tlb_sets = 0x40,
+ .tlb_size = 0x80,
+ .initfn = cpu_750_init,
+ },
+ {
+ .iu_version = 0x000080000,
+ .name = "PowerPC,750",
+ .icache_size = 0x8000,
+ .dcache_size = 0x8000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x20,
+ .dcache_block_size = 0x20,
+ .tlb_sets = 0x40,
+ .tlb_size = 0x80,
+ .initfn = cpu_750_init,
+ },
+ { // XXX find out real values
+ .iu_version = 0x10080000,
+ .name = "PowerPC,750",
+ .icache_size = 0x8000,
+ .dcache_size = 0x8000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x20,
+ .dcache_block_size = 0x20,
+ .tlb_sets = 0x40,
+ .tlb_size = 0x80,
+ .initfn = cpu_750_init,
+ },
+ { // XXX find out real values
+ .iu_version = 0x70000000,
+ .name = "PowerPC,750",
+ .icache_size = 0x8000,
+ .dcache_size = 0x8000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x20,
+ .dcache_block_size = 0x20,
+ .tlb_sets = 0x40,
+ .tlb_size = 0x80,
+ .initfn = cpu_750_init,
+ },
+ { // XXX find out real values
+ .iu_version = 0x70020000,
+ .name = "PowerPC,750",
+ .icache_size = 0x8000,
+ .dcache_size = 0x8000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x20,
+ .dcache_block_size = 0x20,
+ .tlb_sets = 0x40,
+ .tlb_size = 0x80,
+ .initfn = cpu_750_init,
+ },
+ { // XXX find out real values
+ .iu_version = 0x800c0000,
+ .name = "PowerPC,74xx",
+ .icache_size = 0x8000,
+ .dcache_size = 0x8000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x20,
+ .dcache_block_size = 0x20,
+ .tlb_sets = 0x40,
+ .tlb_size = 0x80,
+ .initfn = cpu_750_init,
+ },
+ {
+ .iu_version = 0x0000c0000,
+ .name = "PowerPC,G4",
+ .icache_size = 0x8000,
+ .dcache_size = 0x8000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x20,
+ .dcache_block_size = 0x20,
+ .tlb_sets = 0x40,
+ .tlb_size = 0x80,
+ .initfn = cpu_g4_init,
+ },
+ {
+ .iu_version = 0x00390000,
+ .name = "PowerPC,970",
+ .icache_size = 0x10000,
+ .dcache_size = 0x8000,
+ .icache_sets = 0x200,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x80,
+ .dcache_block_size = 0x80,
+ .tlb_sets = 0x100,
+ .tlb_size = 0x1000,
+ .initfn = cpu_970_init,
+ },
+ { // XXX find out real values
+ .iu_version = 0x003C0000,
+ .name = "PowerPC,970FX",
+ .icache_size = 0x10000,
+ .dcache_size = 0x8000,
+ .icache_sets = 0x80,
+ .dcache_sets = 0x80,
+ .icache_block_size = 0x80,
+ .dcache_block_size = 0x80,
+ .tlb_sets = 0x100,
+ .tlb_size = 0x1000,
+ .initfn = cpu_970_init,
+ },
+ {
+ .iu_version = 0x00350000,
+ .name = "PowerPC,POWER4",
+ .icache_size = 0x10000,
+ .dcache_size = 0x8000,
+ .icache_sets = 0x100,
+ .dcache_sets = 0x40,
+ .icache_block_size = 0x80,
+ .dcache_block_size = 0x80,
+ .tlb_sets = 0x100,
+ .tlb_size = 0x1000,
+ .initfn = cpu_970_init,
+ },
+};
+
+static const struct cpudef *
+id_cpu(void)
+{
+ unsigned int iu_version;
+ unsigned int i;
+
+ iu_version = mfpvr() & 0xffff0000;
+
+ for (i = 0; i < sizeof(ppc_defs) / sizeof(struct cpudef); i++) {
+ if (iu_version == ppc_defs[i].iu_version)
+ return &ppc_defs[i];
+ }
+ printk("Unknown cpu (pvr %x), freezing!\n", iu_version);
+ for (;;) {
+ }
+}
+
+static void go(void);
+
+static void
+go(void)
+{
+ ucell addr;
+
+ feval("saved-program-state >sps.entry @");
+ addr = POP();
+
+ call_elf(0, 0, addr);
+}
+
+static void kvm_of_init(void)
+{
+ char hypercall[4 * 4];
+ uint32_t *hc32;
+
+ /* Don't expose /hypervisor when not in KVM */
+ if (!fw_cfg_read_i32(FW_CFG_PPC_IS_KVM))
+ return;
+
+ push_str("/");
+ fword("find-device");
+
+ fword("new-device");
+
+ push_str("hypervisor");
+ fword("device-name");
+
+ push_str("hypervisor");
+ fword("device-type");
+
+ /* compatible */
+
+ push_str("linux,kvm");
+ fword("encode-string");
+ push_str("epapr,hypervisor-0.2");
+ fword("encode-string");
+ fword("encode+");
+ push_str("compatible");
+ fword("property");
+
+ /* Tell the guest about the hypercall instructions */
+ fw_cfg_read(FW_CFG_PPC_KVM_HC, hypercall, 4 * 4);
+ hc32 = (uint32_t*)hypercall;
+ PUSH(hc32[0]);
+ fword("encode-int");
+ PUSH(hc32[1]);
+ fword("encode-int");
+ fword("encode+");
+ PUSH(hc32[2]);
+ fword("encode-int");
+ fword("encode+");
+ PUSH(hc32[3]);
+ fword("encode-int");
+ fword("encode+");
+ push_str("hcall-instructions");
+ fword("property");
+
+ /* ePAPR requires us to provide a unique guest id */
+ PUSH(fw_cfg_read_i32(FW_CFG_PPC_KVM_PID));
+ fword("encode-int");
+ push_str("guest-id");
+ fword("property");
+
+ /* ePAPR requires us to provide a guest name */
+ push_str("KVM guest");
+ fword("encode-string");
+ push_str("guest-name");
+ fword("property");
+
+ fword("finish-device");
+}
+
+/*
+ * filll ( addr bytes quad -- )
+ */
+
+static void ffilll(void)
+{
+ const u32 longval = POP();
+ u32 bytes = POP();
+ u32 *laddr = (u32 *)cell2pointer(POP());
+ u32 len;
+
+ for (len = 0; len < bytes / sizeof(u32); len++) {
+ *laddr++ = longval;
+ }
+}
+
+/*
+ * adler32 ( adler buf len -- checksum )
+ *
+ * Adapted from Mark Adler's original implementation (zlib license)
+ *
+ * Both OS 9 and BootX require this word for payload validation.
+ */
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+static void adler32(void)
+{
+ uint32_t len = (uint32_t)POP();
+ char *buf = (char *)POP();
+ uint32_t adler = (uint32_t)POP();
+
+ if (buf == NULL) {
+ RET(-1);
+ }
+
+ uint32_t base = 65521;
+ uint32_t nmax = 5552;
+
+ uint32_t s1 = adler & 0xffff;
+ uint32_t s2 = (adler >> 16) & 0xffff;
+
+ uint32_t k;
+ while (len > 0) {
+ k = (len < nmax ? len : nmax);
+ len -= k;
+
+ while (k >= 16) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if (k != 0) {
+ do {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k);
+ }
+
+ s1 %= base;
+ s2 %= base;
+ }
+
+ RET(s2 << 16 | s1);
+}
+
+void
+arch_of_init(void)
+{
+#ifdef CONFIG_RTAS
+ phandle_t ph;
+#endif
+ uint64_t ram_size;
+ const struct cpudef *cpu;
+ char buf[64], qemu_uuid[16];
+ const char *stdin_path, *stdout_path, *boot_path;
+ uint32_t temp = 0;
+ char *boot_device;
+ ofmem_t *ofmem = ofmem_arch_get_private();
+
+ openbios_init();
+ modules_init();
+ setup_timers();
+#ifdef CONFIG_DRIVER_PCI
+ ob_pci_init();
+#endif
+
+ printk("\n");
+ printk("=============================================================\n");
+ printk(PROGRAM_NAME " " OPENBIOS_VERSION_STR " [%s]\n",
+ OPENBIOS_BUILD_DATE);
+
+ 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);
+ printk(" version %d machine id %d\n", temp, machine_id);
+
+ temp = fw_cfg_read_i32(FW_CFG_NB_CPUS);
+
+ printk("CPUs: %x\n", temp);
+
+ ram_size = ofmem->ramsize;
+
+ printk("Memory: %lldM\n", ram_size / 1024 / 1024);
+
+ fw_cfg_read(FW_CFG_UUID, 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]);
+
+ /* set device tree root info */
+
+ push_str("/");
+ fword("find-device");
+
+ switch(machine_id) {
+ case ARCH_HEATHROW: /* OldWorld */
+
+ /* model */
+
+ push_str("Power Macintosh");
+ fword("model");
+
+ /* compatible */
+
+ push_str("AAPL,PowerMac G3");
+ fword("encode-string");
+ push_str("MacRISC");
+ fword("encode-string");
+ fword("encode+");
+ push_str("compatible");
+ fword("property");
+
+ /* misc */
+
+ push_str("device-tree");
+ fword("encode-string");
+ push_str("AAPL,original-name");
+ fword("property");
+
+ PUSH(0);
+ fword("encode-int");
+ push_str("AAPL,cpu-id");
+ fword("property");
+
+ PUSH(66 * 1000 * 1000);
+ fword("encode-int");
+ push_str("clock-frequency");
+ fword("property");
+ break;
+
+ case ARCH_MAC99:
+ case ARCH_MAC99_U3:
+ case ARCH_PREP:
+ default:
+
+ /* model */
+
+ push_str("PowerMac3,1");
+ fword("model");
+
+ /* compatible */
+
+ push_str("PowerMac3,1");
+ fword("encode-string");
+ push_str("MacRISC");
+ fword("encode-string");
+ fword("encode+");
+ push_str("MacRISC2");
+ fword("encode-string");
+ fword("encode+");
+ push_str("Power Macintosh");
+ fword("encode-string");
+ fword("encode+");
+ push_str("compatible");
+ fword("property");
+
+ /* misc */
+
+ push_str("bootrom");
+ fword("device-type");
+
+ PUSH(100 * 1000 * 1000);
+ fword("encode-int");
+ push_str("clock-frequency");
+ fword("property");
+ break;
+ }
+
+ /* Perhaps we can store UUID here ? */
+
+ push_str("0000000000000");
+ fword("encode-string");
+ push_str("system-id");
+ fword("property");
+
+ /* memory info */
+
+ push_str("/memory");
+ fword("find-device");
+
+ /* all memory */
+
+ push_physaddr(0);
+ fword("encode-phys");
+ /* This needs adjusting if #size-cells gets increased.
+ Alternatively use multiple (address, size) tuples. */
+ PUSH(ram_size & 0xffffffff);
+ fword("encode-int");
+ fword("encode+");
+ push_str("reg");
+ fword("property");
+
+ cpu = id_cpu();
+ cpu->initfn(cpu);
+ printk("CPU type %s\n", cpu->name);
+
+ snprintf(buf, sizeof(buf), "/cpus/%s", cpu->name);
+ ofmem_register(find_dev("/memory"), find_dev(buf));
+ node_methods_init(buf);
+
+#ifdef CONFIG_RTAS
+ /* OldWorld Macs don't have an /rtas node. */
+ switch (machine_id) {
+ case ARCH_MAC99:
+ case ARCH_MAC99_U3:
+ if (!(ph = find_dev("/rtas"))) {
+ printk("Warning: No /rtas node\n");
+ } else {
+ unsigned long size = 0x1000;
+ while (size < (unsigned long)of_rtas_end - (unsigned long)of_rtas_start)
+ size *= 2;
+ set_property(ph, "rtas-size", (char*)&size, sizeof(size));
+ set_int_property(ph, "rtas-version", is_apple() ? 0x41 : 1);
+ }
+ break;
+ }
+#endif
+
+ if (fw_cfg_read_i16(FW_CFG_NOGRAPHIC)) {
+ if (is_apple()) {
+ if (CONFIG_SERIAL_PORT) {
+ stdin_path = "scca";
+ stdout_path = "scca";
+ } else {
+ stdin_path = "sccb";
+ stdout_path = "sccb";
+ }
+ } else {
+ stdin_path = "ttya";
+ stdout_path = "ttya";
+ }
+
+ /* Some bootloaders force the output to the screen device, so
+ let's create a screen alias for the serial device too */
+
+ push_str("/aliases");
+ fword("find-device");
+
+ push_str(stdout_path);
+ fword("pathres-resolve-aliases");
+ fword("encode-string");
+ push_str("screen");
+ fword("property");
+ } else {
+ if (is_apple()) {
+ stdin_path = "adb-keyboard";
+ stdout_path = "screen";
+ } else {
+ stdin_path = "keyboard";
+ stdout_path = "screen";
+ }
+ }
+
+ kvm_of_init();
+
+ /* Setup nvram variables */
+ push_str("/options");
+ fword("find-device");
+
+ /* Setup default boot devices (not overriding user settings) */
+ fword("boot-device");
+ boot_device = pop_fstr_copy();
+ if (boot_device && strcmp(boot_device, "disk") == 0) {
+ switch (fw_cfg_read_i16(FW_CFG_BOOT_DEVICE)) {
+ case 'c':
+ boot_path = "hd";
+ break;
+ default:
+ case 'd':
+ boot_path = "cd";
+ break;
+ }
+
+ snprintf(buf, sizeof(buf), "%s:,\\\\:tbxi %s:,\\ppc\\bootinfo.txt %s:,%%BOOT", boot_path, boot_path, boot_path);
+ push_str(buf);
+ fword("encode-string");
+ push_str("boot-device");
+ fword("property");
+ }
+ free(boot_device);
+
+ /* Set up other properties */
+
+ push_str("/chosen");
+ fword("find-device");
+
+ push_str(stdin_path);
+ fword("pathres-resolve-aliases");
+ push_str("input-device");
+ fword("$setenv");
+
+ push_str(stdout_path);
+ fword("pathres-resolve-aliases");
+ push_str("output-device");
+ fword("$setenv");
+
+#if 0
+ if(getbool("tty-interface?") == 1)
+#endif
+ fword("activate-tty-interface");
+
+ device_end();
+
+ /* Implementation of filll word (required by BootX) */
+ bind_func("filll", ffilll);
+
+ /* Implementation of adler32 word (required by OS 9, BootX) */
+ bind_func("(adler32)", adler32);
+
+ bind_func("platform-boot", boot);
+ bind_func("(go)", go);
+}
diff --git a/src/roms/openbios/arch/ppc/qemu/kernel.c b/src/roms/openbios/arch/ppc/qemu/kernel.c
new file mode 100644
index 0000000..b26fba5
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/kernel.c
@@ -0,0 +1,115 @@
+/*
+ * Creation Date: <2003/10/25 14:07:17 samuel>
+ * Time-stamp: <2004/08/28 17:48:19 stepan>
+ *
+ * <kernel.c>
+ *
+ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
+ * Copyright (C) 2003, 2004 Stefan Reinauer
+ *
+ * Based upon unix.c (from OpenBIOS):
+ *
+ * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2
+ *
+ */
+
+#include "config.h"
+#include "dict.h"
+#include "libopenbios/bindings.h"
+#include "kernel/stack.h"
+#include "kernel/kernel.h"
+#include "libc/string.h"
+#include "kernel.h"
+
+#define MEMORY_SIZE (256*1024) /* 256K ram for hosted system */
+/* 512K for the dictionary */
+#define DICTIONARY_SIZE (512 * 1024 / sizeof(ucell))
+#ifdef __powerpc64__
+#define DICTIONARY_BASE 0xfff08000 /* this must match the value in ldscript! */
+#define DICTIONARY_SECTION __attribute__((section(".data.dict")))
+#else
+#define DICTIONARY_BASE ((ucell)((char *)&forth_dictionary))
+#define DICTIONARY_SECTION
+#endif
+
+static ucell forth_dictionary[DICTIONARY_SIZE] DICTIONARY_SECTION = {
+#include "qemu-dict.h"
+};
+
+static ucell *memory;
+
+/************************************************************************/
+/* F U N C T I O N S */
+/************************************************************************/
+
+int
+forth_segv_handler( char *segv_addr )
+{
+ ucell addr = 0xdeadbeef;
+
+ if( PC >= pointer2cell(dict) && PC <= pointer2cell(dict) + dicthead )
+ addr = *(ucell *)cell2pointer(PC);
+
+ printk("panic: segmentation violation at 0x%p\n", segv_addr);
+ printk("dict=0x%p here=0x%p(dict+0x%x) pc=0x%x(dict+0x%x)\n",
+ dict, (char*)dict + dicthead, dicthead,
+ PC, PC - pointer2cell(dict));
+ printk("dstackcnt=%d rstackcnt=%d instruction=%x\n",
+ dstackcnt, rstackcnt, addr);
+
+#ifdef DEBUG_DSTACK
+ printdstack();
+#endif
+#ifdef DEBUG_RSTACK
+ printrstack();
+#endif
+ return -1;
+}
+
+/*
+ * allocate memory and prepare engine for memory management.
+ */
+
+static void
+init_memory( void )
+{
+ memory = malloc(MEMORY_SIZE);
+ if( !memory )
+ panic("panic: not enough memory on host system.\n");
+
+ /* 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( pointer2cell(memory) );
+ PUSH( pointer2cell(memory) + MEMORY_SIZE );
+}
+
+int
+initialize_forth( void )
+{
+ dict = (unsigned char *)forth_dictionary;
+ dicthead = (ucell)FORTH_DICTIONARY_END;
+ last = (ucell *)((unsigned char *)forth_dictionary +
+ FORTH_DICTIONARY_LAST);
+ dictlimit = sizeof(forth_dictionary);
+
+ forth_init();
+
+ PUSH_xt( bind_noname_func(arch_of_init) );
+ fword("PREPOST-initializer");
+
+ PC = (ucell)findword("initialize-of");
+ if( PC ) {
+ init_memory();
+ enterforth((xt_t)PC);
+ free( memory );
+ }
+ free( dict );
+ return 0;
+}
diff --git a/src/roms/openbios/arch/ppc/qemu/kernel.h b/src/roms/openbios/arch/ppc/qemu/kernel.h
new file mode 100644
index 0000000..fe9be83
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/kernel.h
@@ -0,0 +1,42 @@
+/*
+ * Creation Date: <2004/08/28 17:50:12 stepan>
+ * Time-stamp: <2004/08/28 17:50:12 stepan>
+ *
+ * <kernel.h>
+ *
+ * Copyright (C) 2004 Stefan Reinauer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2
+ *
+ */
+
+#ifndef __KERNEL_H__
+#define __KERNEL_H__
+
+/* misc.c */
+extern void fatal_error( const char *str );
+extern void exit( int status ) __attribute__ ((noreturn));
+
+/* start.S */
+extern void flush_icache_range( char *start, char *stop );
+extern char of_rtas_start[], of_rtas_end[];
+extern void call_elf( unsigned long arg1, unsigned long arg2, unsigned long elf_entry );
+
+/* methods.c */
+extern void node_methods_init( const char *cpuname );
+
+/* main.c */
+extern void boot( void );
+
+/* init.c */
+extern void entry( void );
+extern void arch_of_init( void );
+extern int get_bool_res( const char *str );
+
+/* tree.c */
+extern void devtree_init( void );
+
+
+#endif /* __KERNEL_H__ */
diff --git a/src/roms/openbios/arch/ppc/qemu/ldscript b/src/roms/openbios/arch/ppc/qemu/ldscript
new file mode 100644
index 0000000..8027b39
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/ldscript
@@ -0,0 +1,68 @@
+OUTPUT_FORMAT(elf32-powerpc)
+OUTPUT_ARCH(powerpc:common)
+
+/* Initial load address
+ */
+BASE_ADDR = 0xfff00000;
+
+/* As NVRAM is at 0xfff04000, the .text needs to be after that
+ */
+TEXT_ADDR = 0xfff08000;
+
+/* Hard reset vector address
+ */
+HRESET_ADDR = 0xfffffffc;
+
+CSTACK_SIZE = 32768; /* client stack size */
+
+SECTIONS
+{
+ . = BASE_ADDR;
+
+ _start = BASE_ADDR + 0x0100;
+ .text.vectors ALIGN(4096): {
+ *(.text.vectors)
+ }
+
+ . = TEXT_ADDR;
+ /* Normal sections */
+ .text ALIGN(4096): {
+ *(.text)
+ *(.text.*)
+ }
+
+ .rodata ALIGN(4096): {
+ _rodata = .;
+ *(.rodata)
+ *(.rodata.*)
+ *(.note.ELFBoot)
+ }
+ .data ALIGN(4096): {
+ _data = .;
+ *(.data)
+ *(.data.*)
+ _edata = .;
+ }
+
+ .bss ALIGN(4096): {
+ _bss = .;
+ *(.sbss)
+ *(.sbss.*)
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ _ebss = .;
+ }
+
+ . = HRESET_ADDR;
+
+ .romentry : { *(.romentry) }
+
+ . = ALIGN(4096);
+ _end = .;
+
+ /* We discard .note sections other than .note.ELFBoot,
+ * because some versions of GCC generates useless ones. */
+
+ /DISCARD/ : { *(.comment*) *(.note.*) }
+}
diff --git a/src/roms/openbios/arch/ppc/qemu/main.c b/src/roms/openbios/arch/ppc/qemu/main.c
new file mode 100644
index 0000000..44b1666
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/main.c
@@ -0,0 +1,85 @@
+/*
+ * Creation Date: <2002/10/02 22:24:24 samuel>
+ * Time-stamp: <2004/03/27 01:57:55 samuel>
+ *
+ * <main.c>
+ *
+ *
+ *
+ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
+ *
+ * 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
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "libopenbios/elf_load.h"
+#include "arch/common/nvram.h"
+#include "packages/nvram.h"
+#include "libc/diskio.h"
+#include "libc/vsprintf.h"
+#include "kernel.h"
+#include "drivers/drivers.h"
+#include "libopenbios/ofmem.h"
+#define NO_QEMU_PROTOS
+#include "arch/common/fw_cfg.h"
+
+//#define DEBUG_QEMU
+
+#ifdef DEBUG_QEMU
+#define SUBSYS_DPRINTF(subsys, fmt, args...) \
+ do { printk("%s - %s: " fmt, subsys, __func__ , ##args); } while (0)
+#else
+#define SUBSYS_DPRINTF(subsys, fmt, args...) \
+ do { } while (0)
+#endif
+#define CHRP_DPRINTF(fmt, args...) SUBSYS_DPRINTF("CHRP", fmt, ##args)
+#define ELF_DPRINTF(fmt, args...) SUBSYS_DPRINTF("ELF", fmt, ##args)
+#define NEWWORLD_DPRINTF(fmt, args...) SUBSYS_DPRINTF("NEWWORLD", fmt, ##args)
+
+static void check_preloaded_kernel(void)
+{
+ unsigned long kernel_image, kernel_size;
+ unsigned long initrd_image, initrd_size;
+ const char * kernel_cmdline;
+
+ kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE);
+ if (kernel_size) {
+ kernel_image = fw_cfg_read_i32(FW_CFG_KERNEL_ADDR);
+ kernel_cmdline = (const char *)(uintptr_t) fw_cfg_read_i32(FW_CFG_KERNEL_CMDLINE);
+ initrd_image = fw_cfg_read_i32(FW_CFG_INITRD_ADDR);
+ initrd_size = fw_cfg_read_i32(FW_CFG_INITRD_SIZE);
+ printk("[ppc] Kernel already loaded (0x%8.8lx + 0x%8.8lx) "
+ "(initrd 0x%8.8lx + 0x%8.8lx)\n",
+ kernel_image, kernel_size, initrd_image, initrd_size);
+ if (kernel_cmdline) {
+ phandle_t ph;
+ printk("[ppc] Kernel command line: %s\n", kernel_cmdline);
+ ph = find_dev("/chosen");
+ set_property(ph, "bootargs", strdup(kernel_cmdline), strlen(kernel_cmdline) + 1);
+ }
+ call_elf(initrd_image, initrd_size, kernel_image);
+ }
+}
+
+/************************************************************************/
+/* entry */
+/************************************************************************/
+
+void
+boot( void )
+{
+ uint16_t boot_device = fw_cfg_read_i16(FW_CFG_BOOT_DEVICE);
+
+ fword("update-chosen");
+ if (boot_device == 'm') {
+ check_preloaded_kernel();
+ }
+
+ if (is_apple()) {
+ update_nvram();
+ }
+}
diff --git a/src/roms/openbios/arch/ppc/qemu/methods.c b/src/roms/openbios/arch/ppc/qemu/methods.c
new file mode 100644
index 0000000..930b47c
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/methods.c
@@ -0,0 +1,329 @@
+/*
+ * Creation Date: <2004/08/28 18:38:22 greg>
+ * Time-stamp: <2004/08/28 18:38:22 greg>
+ *
+ * <methods.c>
+ *
+ * Misc device node methods
+ *
+ * Copyright (C) 2004 Greg Watson
+ *
+ * Based on MOL specific code which is
+ *
+ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "drivers/drivers.h"
+#include "libc/string.h"
+#include "qemu/qemu.h"
+#include "libopenbios/ofmem.h"
+#include "arch/ppc/processor.h"
+#include "drivers/usb.h"
+
+/************************************************************************/
+/* RTAS (run-time abstraction services) */
+/************************************************************************/
+
+#ifdef CONFIG_RTAS
+DECLARE_NODE( rtas, INSTALL_OPEN, 0, "+/rtas" );
+
+/* ( physbase -- rtas_callback ) */
+static void
+rtas_instantiate( void )
+{
+ ucell physbase = POP();
+ ucell s=0x1000, size = (ucell)of_rtas_end - (ucell)of_rtas_start;
+ unsigned long virt;
+
+ while( s < size )
+ s += 0x1000;
+ virt = ofmem_claim_virt( 0, s, 0x1000 );
+ ofmem_map( physbase, virt, s, -1 );
+ memcpy( (char*)virt, of_rtas_start, size );
+
+ printk("RTAS instantiated at %08x\n", physbase );
+ flush_icache_range( (char*)virt, (char*)virt + size );
+
+ PUSH( physbase );
+}
+
+NODE_METHODS( rtas ) = {
+ { "instantiate", rtas_instantiate },
+ { "instantiate-rtas", rtas_instantiate },
+};
+#endif
+
+
+/************************************************************************/
+/* tty */
+/************************************************************************/
+
+DECLARE_NODE( tty, INSTALL_OPEN, 0, "/packages/terminal-emulator" );
+
+/* ( addr len -- actual ) */
+static void
+tty_read( void )
+{
+ int ch, len = POP();
+ char *p = (char*)cell2pointer(POP());
+ int ret=0;
+
+ if( len > 0 ) {
+ ret = 1;
+ ch = getchar();
+ if( ch >= 0 ) {
+ *p = ch;
+ } else {
+ ret = 0;
+ }
+ }
+ PUSH( ret );
+}
+
+/* ( addr len -- actual ) */
+static void
+tty_write( void )
+{
+ int i, len = POP();
+ char *p = (char*)cell2pointer(POP());
+ for( i=0; i<len; i++ )
+ putchar( *p++ );
+ RET( len );
+}
+
+NODE_METHODS( tty ) = {
+ { "read", tty_read },
+ { "write", tty_write },
+};
+
+/************************************************************************/
+/* client interface 'quiesce' */
+/************************************************************************/
+
+DECLARE_NODE( ciface, 0, 0, "+/openprom/client-services" );
+
+/* ( -- ) */
+static void
+ciface_quiesce( unsigned long args[], unsigned long ret[] )
+{
+ usb_exit();
+
+ ob_ide_quiesce();
+#if 0
+ unsigned long msr;
+ /* This seems to be the correct thing to do - but I'm not sure */
+ asm volatile("mfmsr %0" : "=r" (msr) : );
+ msr &= ~(MSR_IR | MSR_DR);
+ asm volatile("mtmsr %0" :: "r" (msr) );
+#endif
+}
+
+/* ( -- ms ) */
+#define TIMER_FREQUENCY 16600000ULL
+
+static void
+ciface_milliseconds( unsigned long args[], unsigned long ret[] )
+{
+ unsigned long tbu, tbl, temp;
+ unsigned long long ticks, msecs;
+
+ asm volatile(
+ "1:\n"
+ "mftbu %2\n"
+ "mftb %0\n"
+ "mftbu %1\n"
+ "cmpw %2,%1\n"
+ "bne 1b\n"
+ : "=r"(tbl), "=r"(tbu), "=r"(temp)
+ :
+ : "cc");
+
+ ticks = (((unsigned long long)tbu) << 32) | (unsigned long long)tbl;
+ msecs = (1000 * ticks) / TIMER_FREQUENCY;
+ PUSH( msecs );
+}
+
+
+NODE_METHODS( ciface ) = {
+ { "quiesce", ciface_quiesce },
+ { "milliseconds", ciface_milliseconds },
+};
+
+
+/************************************************************************/
+/* MMU/memory methods */
+/************************************************************************/
+
+DECLARE_NODE( memory, INSTALL_OPEN, 0, "/memory" );
+DECLARE_UNNAMED_NODE( mmu, INSTALL_OPEN, 0 );
+DECLARE_NODE( mmu_ciface, 0, 0, "+/openprom/client-services" );
+
+
+/* ( [phys] size align --- base ) */
+static void
+mem_claim( void )
+{
+ ucell align = POP();
+ ucell size = POP();
+ phys_addr_t phys = -1;
+
+ if (!align) {
+ phys = POP();
+ }
+
+ phys = ofmem_claim_phys(phys, size, align);
+
+ PUSH(phys);
+}
+
+/* ( phys size --- ) */
+static void
+mem_release( void )
+{
+ POP(); POP();
+}
+
+/* ( [virt] size align --- base ) */
+static void
+mmu_claim( void )
+{
+ ucell align = POP();
+ ucell size = POP();
+ ucell virt = -1;
+
+ if (!align) {
+ virt = POP();
+ }
+
+ virt = ofmem_claim_virt(virt, size, align);
+
+ PUSH(virt);
+}
+
+/* ( virt size --- ) */
+static void
+mmu_release( void )
+{
+ POP(); POP();
+}
+
+/* ( phys virt size mode -- [ret???] ) */
+static void
+mmu_map( void )
+{
+ ucell mode = POP();
+ ucell size = POP();
+ ucell virt = POP();
+ ucell phys = POP();
+ ucell ret;
+
+ /* printk("mmu_map: %x %x %x %x\n", phys, virt, size, mode ); */
+ ret = ofmem_map( phys, virt, size, mode );
+
+ if( ret ) {
+ printk("MMU: map failure\n");
+ throw( -13 );
+ return;
+ }
+}
+
+/* ( virt size -- ) */
+static void
+mmu_unmap( void )
+{
+ POP(); POP();
+}
+
+/* ( virt -- false | phys mode true ) */
+static void
+mmu_translate( void )
+{
+ ucell mode;
+ ucell virt = POP();
+ ucell phys = ofmem_translate( virt, &mode );
+
+ if( phys == -1 ) {
+ PUSH( 0 );
+ } else {
+ PUSH( phys );
+ PUSH( mode );
+ PUSH( -1 );
+ }
+}
+
+/* ( virt size align -- baseaddr|-1 ) */
+static void
+ciface_claim( void )
+{
+ ucell align = POP();
+ ucell size = POP();
+ ucell virt = POP();
+ ucell ret = ofmem_claim( virt, size, align );
+
+ /* printk("ciface_claim: %08x %08x %x\n", virt, size, align ); */
+ PUSH( ret );
+}
+
+/* ( virt size -- ) */
+static void
+ciface_release( void )
+{
+ ucell size = POP();
+ ucell virt = POP();
+ ofmem_release(virt, size);
+}
+
+
+NODE_METHODS( memory ) = {
+ { "claim", mem_claim },
+ { "release", mem_release },
+};
+
+NODE_METHODS( mmu ) = {
+ { "claim", mmu_claim },
+ { "release", mmu_release },
+ { "map", mmu_map },
+ { "unmap", mmu_unmap },
+ { "translate", mmu_translate },
+};
+
+NODE_METHODS( mmu_ciface ) = {
+ { "cif-claim", ciface_claim },
+ { "cif-release", ciface_release },
+};
+
+
+/************************************************************************/
+/* init */
+/************************************************************************/
+
+void
+node_methods_init( const char *cpuname )
+{
+ phandle_t chosen, ph;
+#ifdef CONFIG_RTAS
+ if (is_newworld()) {
+ REGISTER_NODE( rtas );
+ }
+#endif
+ REGISTER_NODE( ciface );
+ REGISTER_NODE( memory );
+ REGISTER_NODE_METHODS( mmu, cpuname );
+ REGISTER_NODE( mmu_ciface );
+ REGISTER_NODE( tty );
+
+ chosen = find_dev("/chosen");
+ if (chosen) {
+ push_str(cpuname);
+ fword("open-dev");
+ ph = POP();
+ set_int_property(chosen, "mmu", ph);
+ }
+}
diff --git a/src/roms/openbios/arch/ppc/qemu/mmutypes.h b/src/roms/openbios/arch/ppc/qemu/mmutypes.h
new file mode 100644
index 0000000..512c23d
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/mmutypes.h
@@ -0,0 +1,97 @@
+/*
+ * Creation Date: <2002/01/13 13:53:14 samuel>
+ * Time-stamp: <2002/01/27 19:56:11 samuel>
+ *
+ * <mmutypes.h>
+ *
+ * MMU definitions
+ *
+ * Most of these declarations originate from the Linux Kernel
+ *
+ * Copyright (C) 2002 Samuel Rydh (samuel@ibrium.se)
+ *
+ * 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
+ *
+ */
+
+#ifndef _H_MMUTYPES
+#define _H_MMUTYPES
+
+/* Hardware Page Table Entry */
+typedef struct mPTE {
+ unsigned long v:1; /* Entry is valid */
+ unsigned long vsid:24; /* Virtual segment identifier */
+ unsigned long h:1; /* Hash algorithm indicator */
+ unsigned long api:6; /* Abbreviated page index */
+
+ unsigned long rpn:20; /* Real (physical) page number */
+ unsigned long :3; /* Unused */
+ unsigned long r:1; /* Referenced */
+ unsigned long c:1; /* Changed */
+ unsigned long w:1; /* Write-thru cache mode */
+ unsigned long i:1; /* Cache inhibited */
+ unsigned long m:1; /* Memory coherence */
+ unsigned long g:1; /* Guarded */
+ unsigned long :1; /* Unused */
+ unsigned long pp:2; /* Page protection */
+} mPTE_t;
+
+typedef struct mPTE_64 {
+ uint32_t avpn_low; /* Abbreviated Virtual Page Number (unused) */
+ uint32_t avpn:25; /* Abbreviated Virtual Page Number */
+ uint32_t sw:4; /* Software Use */
+ uint32_t :1; /* Reserved */
+ uint32_t h:1; /* Hash algorithm indicator */
+ uint32_t v:1; /* Entry is valid */
+
+ uint32_t rpn_low; /* Real (physical) page number (unused) */
+ uint32_t rpn:20; /* Real (physical) page number */
+ uint32_t :2; /* Reserved */
+ uint32_t ac:1; /* Address Compare*/
+ uint32_t r:1; /* Referenced */
+ uint32_t c:1; /* Changed */
+ uint32_t w:1; /* Write-thru cache mode */
+ uint32_t i:1; /* Cache inhibited */
+ uint32_t m:1; /* Memory coherence */
+ uint32_t g:1; /* Guarded */
+ uint32_t n:1; /* No-Execute */
+ uint32_t pp:2; /* Page protection */
+} mPTE_64_t;
+
+typedef struct _mBATU { /* Upper part of BAT (all except 601) */
+ unsigned long bepi:15; /* Effective page index (virtual address) */
+ unsigned long :4; /* Unused */
+ unsigned long bl:11; /* Block size mask */
+ unsigned long vs:1; /* Supervisor valid */
+ unsigned long vp:1; /* User valid */
+} mBATU;
+
+typedef struct _mBATL { /* Lower part of BAT (all except 601) */
+ unsigned long brpn:15; /* Real page index (physical address) */
+ unsigned long :10; /* Unused */
+ unsigned long w:1; /* Write-thru cache */
+ unsigned long i:1; /* Cache inhibit */
+ unsigned long m:1; /* Memory coherence */
+ unsigned long g:1; /* Guarded (MBZ in IBAT) */
+ unsigned long :1; /* Unused */
+ unsigned long pp:2; /* Page access protections */
+} mBATL;
+
+typedef struct _mBAT {
+ mBATU batu; /* Upper register */
+ mBATL batl; /* Lower register */
+} mBAT;
+
+typedef struct _mSEGREG {
+ unsigned long t:1; /* Normal or I/O type */
+ unsigned long ks:1; /* Supervisor 'key' (normally 0) */
+ unsigned long kp:1; /* User 'key' (normally 1) */
+ unsigned long n:1; /* No-execute */
+ unsigned long :4; /* Unused */
+ unsigned long vsid:24; /* Virtual Segment Identifier */
+} mSEGREG;
+
+
+#endif /* _H_MMUTYPES */
diff --git a/src/roms/openbios/arch/ppc/qemu/ofmem.c b/src/roms/openbios/arch/ppc/qemu/ofmem.c
new file mode 100644
index 0000000..6f346a3
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/ofmem.c
@@ -0,0 +1,563 @@
+/*
+ * Creation Date: <1999/11/07 19:02:11 samuel>
+ * Time-stamp: <2004/01/07 19:42:36 samuel>
+ *
+ * <ofmem.c>
+ *
+ * OF Memory manager
+ *
+ * Copyright (C) 1999-2004 Samuel Rydh (samuel@ibrium.se)
+ * Copyright (C) 2004 Stefan Reinauer
+ *
+ * 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
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "libc/string.h"
+#include "libopenbios/ofmem.h"
+#include "kernel.h"
+#include "mmutypes.h"
+#include "asm/processor.h"
+
+#define BIT(n) (1U << (31 - (n)))
+
+#define SLB_VSID_SHIFT 12
+
+/* called from assembly */
+extern void dsi_exception(void);
+extern void isi_exception(void);
+extern void setup_mmu(unsigned long code_base);
+
+/*
+ * From Apple's BootX source comments:
+ *
+ * 96 MB map (currently unused - 4363357 tracks re-adoption)
+ * 00000000 - 00003FFF : Exception Vectors
+ * 00004000 - 03FFFFFF : Kernel Image, Boot Struct and Drivers (~64 MB)
+ * 04000000 - 04FFFFFF : File Load Area (16 MB) [80 MB]
+ * 05000000 - 053FFFFF : FS Cache (4 MB) [84 MB]
+ * 05400000 - 055FFFFF : Malloc Zone (2 MB) [86 MB]
+ * 05600000 - 057FFFFF : BootX Image (2 MB) [88 MB]
+ * 05800000 - 05FFFFFF : Unused/OF (8 MB) [96 MB]
+ *
+ */
+
+#define FREE_BASE 0x00004000UL
+#define OF_CODE_START 0xfff00000UL
+#define OF_CODE_SIZE 0x00100000
+#define IO_BASE 0x80000000UL
+
+#ifdef __powerpc64__
+#define HASH_BITS 18
+#else
+#define HASH_BITS 15
+#endif
+#define HASH_SIZE (2 << HASH_BITS)
+#define OFMEM_SIZE (1 * 1024 * 1024 + 512 * 1024)
+
+#define SEGR_USER BIT(2)
+#define SEGR_BASE 0x0400
+
+static inline unsigned long
+get_hash_base(void)
+{
+ return (mfsdr1() & SDR1_HTABORG_MASK);
+}
+
+static inline unsigned long
+get_rom_base(void)
+{
+ ofmem_t *ofmem = ofmem_arch_get_private();
+ return ofmem->ramsize - OF_CODE_SIZE;
+}
+
+static unsigned long
+get_ram_top(void)
+{
+ return get_hash_base() - (32 + 64 + 64) * 1024 - OFMEM_SIZE;
+}
+
+static unsigned long
+get_ram_bottom(void)
+{
+ return FREE_BASE;
+}
+
+static unsigned long get_heap_top(void)
+{
+ return get_hash_base() - (32 + 64 + 64) * 1024;
+}
+
+static inline size_t ALIGN_SIZE(size_t x, size_t a)
+{
+ return (x + a - 1) & ~(a - 1);
+}
+
+ofmem_t* ofmem_arch_get_private(void)
+{
+ return (ofmem_t*)cell2pointer(get_heap_top() - OFMEM_SIZE);
+}
+
+void* ofmem_arch_get_malloc_base(void)
+{
+ return (char*)ofmem_arch_get_private() + ALIGN_SIZE(sizeof(ofmem_t), 4);
+}
+
+ucell ofmem_arch_get_heap_top(void)
+{
+ return get_heap_top();
+}
+
+ucell ofmem_arch_get_virt_top(void)
+{
+ return IO_BASE;
+}
+
+void ofmem_arch_unmap_pages(ucell virt, ucell size)
+{
+ /* kill page mappings in provided range */
+}
+
+void ofmem_arch_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
+{
+ /* none yet */
+}
+
+ucell ofmem_arch_get_iomem_base(void)
+{
+ /* Currently unused */
+ return 0;
+}
+
+ucell ofmem_arch_get_iomem_top(void)
+{
+ /* Currently unused */
+ return 0;
+}
+
+retain_t *ofmem_arch_get_retained(void)
+{
+ /* not implemented */
+ return NULL;
+}
+
+int ofmem_arch_get_physaddr_cellsize(void)
+{
+#ifdef CONFIG_PPC64
+ return 2;
+#else
+ return 1;
+#endif
+}
+
+int ofmem_arch_encode_physaddr(ucell *p, phys_addr_t value)
+{
+ int n = 0;
+#ifdef CONFIG_PPC64
+ p[n++] = value >> 32;
+#endif
+ p[n++] = value;
+ return n;
+}
+
+/* Return size of a single MMU package translation property entry in cells */
+int ofmem_arch_get_translation_entry_size(void)
+{
+ return 3 + ofmem_arch_get_physaddr_cellsize();
+}
+
+/* Generate translation property entry for PPC.
+ * According to the platform bindings for PPC
+ * (http://www.openfirmware.org/1275/bindings/ppc/release/ppc-2_1.html#REF34579)
+ * a translation property entry has the following layout:
+ *
+ * virtual address
+ * length
+ * physical address
+ * mode
+ */
+void ofmem_arch_create_translation_entry(ucell *transentry, translation_t *t)
+{
+ int i = 0;
+
+ transentry[i++] = t->virt;
+ transentry[i++] = t->size;
+ i += ofmem_arch_encode_physaddr(&transentry[i], t->phys);
+ transentry[i++] = t->mode;
+}
+
+/* Return the size of a memory available entry given the phandle in cells */
+int ofmem_arch_get_available_entry_size(phandle_t ph)
+{
+ if (ph == s_phandle_memory) {
+ return 1 + ofmem_arch_get_physaddr_cellsize();
+ } else {
+ return 1 + 1;
+ }
+}
+
+/* Generate memory available property entry for PPC */
+void ofmem_arch_create_available_entry(phandle_t ph, ucell *availentry, phys_addr_t start, ucell size)
+{
+ int i = 0;
+
+ if (ph == s_phandle_memory) {
+ i += ofmem_arch_encode_physaddr(availentry, start);
+ } else {
+ availentry[i++] = start;
+ }
+
+ availentry[i] = size;
+}
+
+/************************************************************************/
+/* OF private allocations */
+/************************************************************************/
+
+/* Private functions for mapping between physical/virtual addresses */
+phys_addr_t
+va2pa(unsigned long va)
+{
+ if (va >= OF_CODE_START && va < OF_CODE_START + OF_CODE_SIZE) {
+ return (phys_addr_t)get_rom_base() - OF_CODE_START + va;
+ } else {
+ return (phys_addr_t)va;
+ }
+}
+
+unsigned long
+pa2va(phys_addr_t pa)
+{
+ if ((pa - get_rom_base() + OF_CODE_START >= OF_CODE_START) &&
+ (pa - get_rom_base() + OF_CODE_START < OF_CODE_START + OF_CODE_SIZE))
+ return (unsigned long)pa - get_rom_base() + OF_CODE_START;
+ else
+ return (unsigned long)pa;
+}
+
+void *
+malloc(int size)
+{
+ return ofmem_malloc(size);
+}
+
+void
+free(void *ptr)
+{
+ ofmem_free(ptr);
+}
+
+void *
+realloc(void *ptr, size_t size)
+{
+ return ofmem_realloc(ptr, size);
+}
+
+
+/************************************************************************/
+/* misc */
+/************************************************************************/
+
+ucell ofmem_arch_default_translation_mode(phys_addr_t phys)
+{
+ /* XXX: Guard bit not set as it should! */
+ if (phys < IO_BASE)
+ return 0x02; /*0xa*/ /* wim GxPp */
+ return 0x6a; /* WIm GxPp, I/O */
+}
+
+ucell ofmem_arch_io_translation_mode(phys_addr_t phys)
+{
+ return 0x6a; /* WIm GxPp, I/O */
+}
+
+/************************************************************************/
+/* page fault handler */
+/************************************************************************/
+
+static phys_addr_t
+ea_to_phys(unsigned long ea, ucell *mode)
+{
+ phys_addr_t phys;
+
+ if (ea >= OF_CODE_START && ea <= 0xffffffffUL) {
+ /* ROM into RAM */
+ ea -= OF_CODE_START;
+ phys = get_rom_base() + ea;
+ *mode = 0x02;
+ return phys;
+ }
+
+ phys = ofmem_translate(ea, mode);
+ if (phys == -1) {
+ phys = ea;
+ *mode = ofmem_arch_default_translation_mode(phys);
+
+ /* print_virt_range(); */
+ /* print_phys_range(); */
+ /* print_trans(); */
+ }
+ return phys;
+}
+
+/* Converts a global variable (from .data or .bss) into a pointer that
+ can be accessed from real mode */
+static void *
+global_ptr_real(void *p)
+{
+ return (void*)((uintptr_t)p - OF_CODE_START + get_rom_base());
+}
+
+/* Return the next slot to evict, in the range of [0..7] */
+static int
+next_evicted_slot(void)
+{
+ static int next_grab_slot;
+ int *next_grab_slot_va;
+ int r;
+
+ next_grab_slot_va = global_ptr_real(&next_grab_slot);
+ r = *next_grab_slot_va;
+ *next_grab_slot_va = (r + 1) % 8;
+
+ return r;
+}
+
+static void
+hash_page_64(unsigned long ea, phys_addr_t phys, ucell mode)
+{
+ uint64_t vsid_mask, page_mask, pgidx, hash;
+ uint64_t htab_mask, mask, avpn;
+ unsigned long pgaddr;
+ int i, found;
+ unsigned int vsid, vsid_sh, sdr, sdr_sh, sdr_mask;
+ mPTE_64_t *pp;
+
+ vsid = (ea >> 28) + SEGR_BASE;
+ vsid_sh = 7;
+ vsid_mask = 0x00003FFFFFFFFF80ULL;
+ sdr = mfsdr1();
+ sdr_sh = 18;
+ sdr_mask = 0x3FF80;
+ page_mask = 0x0FFFFFFF; // XXX correct?
+ pgidx = (ea & page_mask) >> PAGE_SHIFT;
+ avpn = (vsid << 12) | ((pgidx >> 4) & 0x0F80);;
+
+ hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
+ htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F));
+ mask = (htab_mask << sdr_sh) | sdr_mask;
+ pgaddr = sdr | (hash & mask);
+ pp = (mPTE_64_t *)pgaddr;
+
+ /* replace old translation */
+ for (found = 0, i = 0; !found && i < 8; i++)
+ if (pp[i].avpn == avpn)
+ found = 1;
+
+ /* otherwise use a free slot */
+ for (i = 0; !found && i < 8; i++)
+ if (!pp[i].v)
+ found = 1;
+
+ /* out of slots, just evict one */
+ if (!found)
+ i = next_evicted_slot() + 1;
+ i--;
+ {
+ mPTE_64_t p = {
+ // .avpn_low = avpn,
+ .avpn = avpn >> 7,
+ .h = 0,
+ .v = 1,
+
+ .rpn = (phys & ~0xfffUL) >> 12,
+ .r = mode & (1 << 8) ? 1 : 0,
+ .c = mode & (1 << 7) ? 1 : 0,
+ .w = mode & (1 << 6) ? 1 : 0,
+ .i = mode & (1 << 5) ? 1 : 0,
+ .m = mode & (1 << 4) ? 1 : 0,
+ .g = mode & (1 << 3) ? 1 : 0,
+ .n = mode & (1 << 2) ? 1 : 0,
+ .pp = mode & 3,
+ };
+ pp[i] = p;
+ }
+
+ asm volatile("tlbie %0" :: "r"(ea));
+}
+
+static void
+hash_page_32(unsigned long ea, phys_addr_t phys, ucell mode)
+{
+#ifndef __powerpc64__
+ unsigned long *upte, cmp, hash1;
+ int i, vsid, found;
+ mPTE_t *pp;
+
+ vsid = (ea >> 28) + SEGR_BASE;
+ cmp = BIT(0) | (vsid << 7) | ((ea & 0x0fffffff) >> 22);
+
+ hash1 = vsid;
+ hash1 ^= (ea >> 12) & 0xffff;
+ hash1 &= (((mfsdr1() & 0x1ff) << 16) | 0xffff) >> 6;
+
+ pp = (mPTE_t*)(get_hash_base() + (hash1 << 6));
+ upte = (unsigned long*)pp;
+
+ /* replace old translation */
+ for (found = 0, i = 0; !found && i < 8; i++)
+ if (cmp == upte[i*2])
+ found = 1;
+
+ /* otherwise use a free slot */
+ for (i = 0; !found && i < 8; i++)
+ if (!pp[i].v)
+ found = 1;
+
+ /* out of slots, just evict one */
+ if (!found)
+ i = next_evicted_slot() + 1;
+ i--;
+ upte[i * 2] = cmp;
+ upte[i * 2 + 1] = (phys & ~0xfff) | mode;
+
+ asm volatile("tlbie %0" :: "r"(ea));
+#endif
+}
+
+static int is_ppc64(void)
+{
+#ifdef __powerpc64__
+ return 1;
+#elif defined(CONFIG_PPC_64BITSUPPORT)
+ unsigned int pvr = mfpvr();
+ return ((pvr >= 0x330000) && (pvr < 0x70330000));
+#else
+ return 0;
+#endif
+}
+
+/* XXX Remove these ugly constructs when legacy 64-bit support is dropped. */
+static void hash_page(unsigned long ea, phys_addr_t phys, ucell mode)
+{
+ if (is_ppc64())
+ hash_page_64(ea, phys, mode);
+ else
+ hash_page_32(ea, phys, mode);
+}
+
+void
+dsi_exception(void)
+{
+ unsigned long dar, dsisr;
+ ucell mode;
+ phys_addr_t phys;
+
+ asm volatile("mfdar %0" : "=r" (dar) : );
+ asm volatile("mfdsisr %0" : "=r" (dsisr) : );
+
+ phys = ea_to_phys(dar, &mode);
+ hash_page(dar, phys, mode);
+}
+
+void
+isi_exception(void)
+{
+ unsigned long nip, srr1;
+ ucell mode;
+ phys_addr_t phys;
+
+ asm volatile("mfsrr0 %0" : "=r" (nip) : );
+ asm volatile("mfsrr1 %0" : "=r" (srr1) : );
+
+ phys = ea_to_phys(nip, &mode);
+ hash_page(nip, phys, mode);
+}
+
+
+/************************************************************************/
+/* init / cleanup */
+/************************************************************************/
+
+void
+setup_mmu(unsigned long ramsize)
+{
+ ofmem_t *ofmem;
+#ifndef __powerpc64__
+ unsigned long sr_base;
+#endif
+ unsigned long hash_base;
+ unsigned long hash_mask = ~0x000fffffUL; /* alignment for ppc64 */
+ int i;
+
+ /* SDR1: Storage Description Register 1 */
+
+ hash_base = (ramsize - OF_CODE_SIZE - HASH_SIZE) & hash_mask;
+ memset((void *)hash_base, 0, HASH_SIZE);
+ if (is_ppc64())
+ mtsdr1(hash_base | MAX(HASH_BITS - 18, 0));
+ else
+ mtsdr1(hash_base | ((HASH_SIZE - 1) >> 16));
+
+#ifdef __powerpc64__
+
+ /* Segment Lookaside Buffer */
+
+ slbia(); /* Invalidate all SLBs except SLB 0 */
+ for (i = 0; i < 16; i++) {
+ unsigned long rs = (0x400 + i) << SLB_VSID_SHIFT;
+ unsigned long rb = ((unsigned long)i << 28) | (1 << 27) | i;
+ slbmte(rs, rb);
+ }
+
+#else
+
+ /* Segment Register */
+
+ sr_base = SEGR_USER | SEGR_BASE ;
+ for (i = 0; i < 16; i++) {
+ int j = i << 28;
+ asm volatile("mtsrin %0,%1" :: "r" (sr_base + i), "r" (j));
+ }
+
+#endif
+
+ ofmem = ofmem_arch_get_private();
+ memset(ofmem, 0, sizeof(ofmem_t));
+ ofmem->ramsize = ramsize;
+
+ memcpy((void *)get_rom_base(), (void *)OF_CODE_START, OF_CODE_SIZE);
+
+ /* Enable MMU */
+
+ mtmsr(mfmsr() | MSR_IR | MSR_DR);
+}
+
+void
+ofmem_init(void)
+{
+ ofmem_t *ofmem = ofmem_arch_get_private();
+
+ /* Map the memory (don't map page 0 to allow catching of NULL dereferences) */
+ ofmem_claim_phys(PAGE_SIZE, get_ram_bottom() - PAGE_SIZE, 0);
+ ofmem_claim_virt(PAGE_SIZE, get_ram_bottom() - PAGE_SIZE, 0);
+ ofmem_map(PAGE_SIZE, PAGE_SIZE, get_ram_bottom() - PAGE_SIZE, 0);
+
+ /* Mark the first page as non-free */
+ ofmem_claim_phys(0, PAGE_SIZE, 0);
+ ofmem_claim_virt(0, PAGE_SIZE, 0);
+
+ /* Map everything at the top of physical RAM 1:1, minus the OpenBIOS ROM in RAM copy */
+ ofmem_claim_phys(get_ram_top(), get_hash_base() + HASH_SIZE - get_ram_top(), 0);
+ ofmem_claim_virt(get_ram_top(), get_hash_base() + HASH_SIZE - get_ram_top(), 0);
+ ofmem_map(get_ram_top(), get_ram_top(), get_hash_base() + HASH_SIZE - get_ram_top(), 0);
+
+ /* Map the OpenBIOS ROM in RAM copy */
+ ofmem_claim_phys(ofmem->ramsize - OF_CODE_SIZE, OF_CODE_SIZE, 0);
+ ofmem_claim_virt(OF_CODE_START, OF_CODE_SIZE, 0);
+ ofmem_map(ofmem->ramsize - OF_CODE_SIZE, OF_CODE_START, OF_CODE_SIZE, 0);
+}
diff --git a/src/roms/openbios/arch/ppc/qemu/qemu.c b/src/roms/openbios/arch/ppc/qemu/qemu.c
new file mode 100644
index 0000000..381affb
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/qemu.c
@@ -0,0 +1,106 @@
+/*
+ * Creation Date: <2004/08/28 18:38:22 greg>
+ * Time-stamp: <2004/08/28 18:38:22 greg>
+ *
+ * <qemu.c>
+ *
+ * Copyright (C) 2004, Greg Watson
+ *
+ * derived from mol.c
+ *
+ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2
+ *
+ */
+
+#include "config.h"
+#include "kernel/kernel.h"
+#include "arch/common/nvram.h"
+#include "libopenbios/bindings.h"
+#include "drivers/drivers.h"
+#include "libc/vsprintf.h"
+#include "libc/string.h"
+#include "libc/byteorder.h"
+#include "qemu/qemu.h"
+#include <stdarg.h>
+
+//#define DUMP_NVRAM
+
+unsigned long virt_offset = 0;
+
+void
+exit( int status __attribute__ ((unused)))
+{
+ for (;;);
+}
+
+void
+fatal_error( const char *err )
+{
+ printk("Fatal error: %s\n", err );
+ exit(0);
+}
+
+void
+panic( const char *err )
+{
+ printk("Panic: %s\n", err );
+ exit(0);
+}
+
+static int do_indent;
+
+int
+printk( const char *fmt, ... )
+{
+ char *p, buf[1024];
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ for( p=buf; *p; p++ ) {
+ if( *p == '\n' )
+ do_indent = 0;
+ if( do_indent++ == 1 ) {
+ putchar( '>' );
+ putchar( '>' );
+ putchar( ' ' );
+ }
+ putchar( *p );
+ }
+ return i;
+}
+
+int arch_nvram_size(void)
+{
+ if (is_apple()) {
+ return macio_get_nvram_size();
+ } else {
+ // not implemented
+ }
+ return 0;
+}
+
+void arch_nvram_put(char *buf)
+{
+ if (is_apple()) {
+ macio_nvram_put(buf);
+ } else {
+ // not implemented
+ }
+}
+
+void arch_nvram_get(char *buf)
+{
+ if (is_apple()) {
+ macio_nvram_get(buf);
+ } else {
+ // not implemented
+ }
+}
diff --git a/src/roms/openbios/arch/ppc/qemu/qemu.fs b/src/roms/openbios/arch/ppc/qemu/qemu.fs
new file mode 100644
index 0000000..11e344a
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/qemu.fs
@@ -0,0 +1,123 @@
+\ qemu specific initialization code
+\
+\ Copyright (C) 2005 Stefan Reinauer
+\
+\ 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
+\
+
+
+\ -------------------------------------------------------------------------
+\ initialization
+\ -------------------------------------------------------------------------
+
+: make-openable ( path )
+ find-dev if
+ begin ?dup while
+ \ install trivial open and close methods
+ dup active-package! is-open
+ parent
+ repeat
+ then
+;
+
+: preopen ( chosen-str node-path )
+ 2dup make-openable
+
+ " /chosen" find-device
+ open-dev ?dup if
+ encode-int 2swap property
+ else
+ 2drop
+ then
+;
+
+\ preopen device nodes (and store the ihandles under /chosen)
+:noname
+ " rtc" " rtc" preopen
+ " memory" " /memory" preopen
+; SYSTEM-initializer
+
+
+\ use the tty interface if available
+: activate-tty-interface
+ " /packages/terminal-emulator" find-dev if drop
+ then
+;
+
+variable keyboard-phandle 0 keyboard-phandle !
+
+: (find-keyboard-device) ( phandle -- )
+ recursive
+ keyboard-phandle @ 0= if \ Return first match
+ >dn.child @
+ begin ?dup while
+ dup dup " device_type" rot get-package-property 0= if
+ drop dup cstrlen
+ " keyboard" strcmp 0= if
+ dup to keyboard-phandle
+ then
+ then
+ (find-keyboard-device)
+ >dn.peer @
+ repeat
+ else
+ drop
+ then
+;
+
+\ create the keyboard devalias
+:noname
+ device-tree @ (find-keyboard-device)
+ keyboard-phandle @ if
+ active-package
+ " /aliases" find-device
+ keyboard-phandle @ get-package-path
+ encode-string " keyboard" property
+ active-package!
+ then
+; SYSTEM-initializer
+
+\ -------------------------------------------------------------------------
+\ pre-booting
+\ -------------------------------------------------------------------------
+
+: update-chosen
+ " /chosen" find-device
+ stdin @ encode-int " stdin" property
+ stdout @ encode-int " stdout" property
+ device-end
+;
+
+:noname
+ set-defaults
+; PREPOST-initializer
+
+\ -------------------------------------------------------------------------
+\ Adler-32 wrapper
+\ -------------------------------------------------------------------------
+
+: adler32 ( adler buf len -- checksum )
+ \ Since Mac OS 9 is the only system using this word, we take this
+ \ opportunity to inject a copyright message that is necessary for the
+ \ system to boot.
+ " Copyright 1983-2001 Apple Computer, Inc. THIS MESSAGE FOR COMPATIBILITY ONLY"
+ encode-string " copyright"
+ " /" find-package if
+ " set-property" $find if
+ execute
+ else
+ 3drop drop
+ then
+ then
+
+ ( adler buf len )
+
+ " (adler32)" $find if
+ execute
+ else
+ ." Can't find " ( adler32-name ) type cr
+ 3drop 0
+ then
+;
diff --git a/src/roms/openbios/arch/ppc/qemu/qemu.h b/src/roms/openbios/arch/ppc/qemu/qemu.h
new file mode 100644
index 0000000..6edf4d4
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/qemu.h
@@ -0,0 +1,24 @@
+/*
+ * Creation Date: <2004/08/28 17:50:12 stepan>
+ * Time-stamp: <2004/08/28 17:50:12 stepan>
+ *
+ * <qemu.h>
+ *
+ * Copyright (C) 2005 Stefan Reinauer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2
+ *
+ */
+
+#ifndef _H_QEMU
+#define _H_QEMU
+
+/* vfd.c */
+extern int vfd_draw_str( const char *str );
+extern void vfd_close( void );
+
+#include "kernel.h"
+
+#endif /* _H_QEMU */
diff --git a/src/roms/openbios/arch/ppc/qemu/start.S b/src/roms/openbios/arch/ppc/qemu/start.S
new file mode 100644
index 0000000..ae2fd53
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/start.S
@@ -0,0 +1,729 @@
+/*
+ * Creation Date: <2001/06/16 21:30:18 samuel>
+ * Time-stamp: <2003/04/04 16:32:06 samuel>
+ *
+ * <init.S>
+ *
+ * Asm glue for ELF images
+ *
+ * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se)
+ *
+ * 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
+ *
+ */
+
+#include "autoconf.h"
+#include "asm/asmdefs.h"
+#include "asm/processor.h"
+
+/************************************************************************/
+/* Macros */
+/************************************************************************/
+
+#define ILLEGAL_VECTOR( v ) .org __vectors + v ; vector__##v: bl trap_error ;
+#define VECTOR( v, dummystr ) .org __vectors + v ; vector__##v
+
+#ifdef CONFIG_PPC_64BITSUPPORT
+
+/* We're trying to use the same code for the ppc32 and ppc64 handlers here.
+ * On ppc32 we only save/restore the registers, C considers volatile.
+ *
+ * On ppc64 on the other hand, we have to save/restore all registers, because
+ * all OF code is 32 bits, which only saves/restores the low 32 bits of the
+ * registers it clobbers.
+ */
+
+#define EXCEPTION_PREAMBLE_TEMPLATE \
+ mtsprg1 r1 ; /* scratch */ \
+ mfcr r1 ; \
+ mtsprg2 r1 ; /* scratch */ \
+ lis r1, 0x8000 ; /* r1=0x80000000 */ \
+ add. r1,r1,r1 ; /* r1=r1+r1 (high 32bit !0) */ \
+ beq 1f; \
+ \
+ mfmsr r1 ; /* unset MSR_SF */ \
+ clrldi r1,r1,1 ; \
+ mtmsrd r1 ; \
+1: \
+ mfsprg0 r1 ; /* exception stack in sprg0 */ \
+.ifc ULONG_SIZE, 8 ; \
+ addi r1,r1,-(40 * ULONG_SIZE) ; /* push exception frame */ \
+.else ; \
+ addi r1,r1,-(20 * ULONG_SIZE) ; /* push exception frame */ \
+.endif ; \
+ \
+ stl r0,(0 * ULONG_SIZE)(r1) ; /* save r0 */ \
+ mfsprg1 r0 ; \
+ stl r0,(1 * ULONG_SIZE)(r1) ; /* save r1 */ \
+ stl r2,(2 * ULONG_SIZE)(r1) ; /* save r2 */ \
+ stl r3,(3 * ULONG_SIZE)(r1) ; /* save r3 */ \
+ stl r4,(4 * ULONG_SIZE)(r1) ; \
+ stl r5,(5 * ULONG_SIZE)(r1) ; \
+ stl r6,(6 * ULONG_SIZE)(r1) ; \
+ stl r7,(7 * ULONG_SIZE)(r1) ; \
+ stl r8,(8 * ULONG_SIZE)(r1) ; \
+ stl r9,(9 * ULONG_SIZE)(r1) ; \
+ stl r10,(10 * ULONG_SIZE)(r1) ; \
+ stl r11,(11 * ULONG_SIZE)(r1) ; \
+ stl r12,(12 * ULONG_SIZE)(r1) ; \
+.ifc ULONG_SIZE, 8 ; \
+ stl r13,(17 * ULONG_SIZE)(r1) ; \
+ stl r14,(18 * ULONG_SIZE)(r1) ; \
+ stl r15,(19 * ULONG_SIZE)(r1) ; \
+ stl r16,(20 * ULONG_SIZE)(r1) ; \
+ stl r17,(21 * ULONG_SIZE)(r1) ; \
+ stl r18,(22 * ULONG_SIZE)(r1) ; \
+ stl r19,(23 * ULONG_SIZE)(r1) ; \
+ stl r20,(24 * ULONG_SIZE)(r1) ; \
+ stl r21,(25 * ULONG_SIZE)(r1) ; \
+ stl r22,(26 * ULONG_SIZE)(r1) ; \
+ stl r23,(27 * ULONG_SIZE)(r1) ; \
+ stl r24,(28 * ULONG_SIZE)(r1) ; \
+ stl r25,(29 * ULONG_SIZE)(r1) ; \
+ stl r26,(30 * ULONG_SIZE)(r1) ; \
+ stl r27,(31 * ULONG_SIZE)(r1) ; \
+ stl r28,(32 * ULONG_SIZE)(r1) ; \
+ stl r29,(33 * ULONG_SIZE)(r1) ; \
+ stl r30,(34 * ULONG_SIZE)(r1) ; \
+ stl r31,(35 * ULONG_SIZE)(r1) ; \
+.endif ; \
+ \
+ mflr r0 ; \
+ stl r0,(13 * ULONG_SIZE)(r1) ; \
+ mfsprg2 r0 ; \
+ stl r0,(14 * ULONG_SIZE)(r1) ; \
+ mfctr r0 ; \
+ stl r0,(15 * ULONG_SIZE)(r1) ; \
+ mfxer r0 ; \
+ stl r0,(16 * ULONG_SIZE)(r1) ; \
+ \
+ /* 76(r1) unused */ \
+ addi r1,r1,-16 ; /* C ABI uses 0(r1) and 4(r1)... */
+
+#define EXCEPTION_EPILOGUE_TEMPLATE \
+ addi r1,r1,16 ; /* pop ABI frame */ \
+\
+ ll r0,(13 * ULONG_SIZE)(r1) ; \
+ mtlr r0 ; \
+ ll r0,(14 * ULONG_SIZE)(r1) ; \
+ mtcr r0 ; \
+ ll r0,(15 * ULONG_SIZE)(r1) ; \
+ mtctr r0 ; \
+ ll r0,(16 * ULONG_SIZE)(r1) ; \
+ mtxer r0 ; \
+\
+ ll r0,(0 * ULONG_SIZE)(r1) ; \
+ ll r2,(2 * ULONG_SIZE)(r1) ; \
+ ll r3,(3 * ULONG_SIZE)(r1) ; \
+ ll r4,(4 * ULONG_SIZE)(r1) ; \
+ ll r5,(5 * ULONG_SIZE)(r1) ; \
+ ll r6,(6 * ULONG_SIZE)(r1) ; \
+ ll r7,(7 * ULONG_SIZE)(r1) ; \
+ ll r8,(8 * ULONG_SIZE)(r1) ; \
+ ll r9,(9 * ULONG_SIZE)(r1) ; \
+ ll r10,(10 * ULONG_SIZE)(r1) ; \
+ ll r11,(11 * ULONG_SIZE)(r1) ; \
+ ll r12,(12 * ULONG_SIZE)(r1) ; \
+.ifc ULONG_SIZE, 8 ; \
+ ll r13,(17 * ULONG_SIZE)(r1) ; \
+ ll r14,(18 * ULONG_SIZE)(r1) ; \
+ ll r15,(19 * ULONG_SIZE)(r1) ; \
+ ll r16,(20 * ULONG_SIZE)(r1) ; \
+ ll r17,(21 * ULONG_SIZE)(r1) ; \
+ ll r18,(22 * ULONG_SIZE)(r1) ; \
+ ll r19,(23 * ULONG_SIZE)(r1) ; \
+ ll r20,(24 * ULONG_SIZE)(r1) ; \
+ ll r21,(25 * ULONG_SIZE)(r1) ; \
+ ll r22,(26 * ULONG_SIZE)(r1) ; \
+ ll r23,(27 * ULONG_SIZE)(r1) ; \
+ ll r24,(28 * ULONG_SIZE)(r1) ; \
+ ll r25,(29 * ULONG_SIZE)(r1) ; \
+ ll r26,(30 * ULONG_SIZE)(r1) ; \
+ ll r27,(31 * ULONG_SIZE)(r1) ; \
+ ll r28,(32 * ULONG_SIZE)(r1) ; \
+ ll r29,(33 * ULONG_SIZE)(r1) ; \
+ ll r30,(34 * ULONG_SIZE)(r1) ; \
+ ll r31,(35 * ULONG_SIZE)(r1) ; \
+.endif ; \
+ ll r1,(1 * ULONG_SIZE)(r1) ; /* restore stack at last */ \
+ rfi
+
+// PPC32
+
+#define ULONG_SIZE 4
+#define stl stw
+#define ll lwz
+
+.macro EXCEPTION_PREAMBLE
+ EXCEPTION_PREAMBLE_TEMPLATE
+.endm
+
+.macro EXCEPTION_EPILOGUE
+ EXCEPTION_EPILOGUE_TEMPLATE
+.endm
+
+#undef ULONG_SIZE
+#undef stl
+#undef ll
+
+// PPC64
+
+#define ULONG_SIZE 8
+#define stl std
+#define ll ld
+
+.macro EXCEPTION_PREAMBLE_64
+ EXCEPTION_PREAMBLE_TEMPLATE
+.endm
+
+.macro EXCEPTION_EPILOGUE_64
+ EXCEPTION_EPILOGUE_TEMPLATE
+.endm
+
+#undef ULONG_SIZE
+#undef stl
+#undef ll
+
+#define ULONG_SIZE 4
+#define STACKFRAME_MINSIZE 16
+
+#else /* !CONFIG_PPC_64BITSUPPORT */
+
+#ifdef __powerpc64__
+
+#define ULONG_SIZE 8
+#define STACKFRAME_MINSIZE 48
+#define stl std
+#define ll ld
+
+#else
+
+#define ULONG_SIZE 4
+#define STACKFRAME_MINSIZE 16
+#define stl stw
+#define ll lwz
+
+#endif
+
+.macro EXCEPTION_PREAMBLE
+ mtsprg1 r1 /* scratch */
+ mfsprg0 r1 /* exception stack in sprg0 */
+ addi r1, r1, -(20 * ULONG_SIZE) /* push exception frame */
+
+ stl r0, ( 0 * ULONG_SIZE)(r1) /* save r0 */
+ mfsprg1 r0
+ stl r0, ( 1 * ULONG_SIZE)(r1) /* save r1 */
+ stl r2, ( 2 * ULONG_SIZE)(r1) /* save r2 */
+ stl r3, ( 3 * ULONG_SIZE)(r1) /* save r3 */
+ stl r4, ( 4 * ULONG_SIZE)(r1)
+ stl r5, ( 5 * ULONG_SIZE)(r1)
+ stl r6, ( 6 * ULONG_SIZE)(r1)
+ stl r7, ( 7 * ULONG_SIZE)(r1)
+ stl r8, ( 8 * ULONG_SIZE)(r1)
+ stl r9, ( 9 * ULONG_SIZE)(r1)
+ stl r10, (10 * ULONG_SIZE)(r1)
+ stl r11, (11 * ULONG_SIZE)(r1)
+ stl r12, (12 * ULONG_SIZE)(r1)
+
+ mflr r0
+ stl r0, (13 * ULONG_SIZE)(r1)
+ mfcr r0
+ stl r0, (14 * ULONG_SIZE)(r1)
+ mfctr r0
+ stl r0, (15 * ULONG_SIZE)(r1)
+ mfxer r0
+ stl r0, (16 * ULONG_SIZE)(r1)
+
+ addi r1, r1, -STACKFRAME_MINSIZE /* C ABI saves LR and SP */
+.endm
+
+.macro EXCEPTION_EPILOGUE
+ addi r1, r1, STACKFRAME_MINSIZE /* pop ABI frame */
+
+ ll r0, (13 * ULONG_SIZE)(r1)
+ mtlr r0
+ ll r0, (14 * ULONG_SIZE)(r1)
+ mtcr r0
+ ll r0, (15 * ULONG_SIZE)(r1)
+ mtctr r0
+ ll r0, (16 * ULONG_SIZE)(r1)
+ mtxer r0
+
+ ll r0, ( 0 * ULONG_SIZE)(r1)
+ ll r2, ( 2 * ULONG_SIZE)(r1)
+ ll r3, ( 3 * ULONG_SIZE)(r1)
+ ll r4, ( 4 * ULONG_SIZE)(r1)
+ ll r5, ( 5 * ULONG_SIZE)(r1)
+ ll r6, ( 6 * ULONG_SIZE)(r1)
+ ll r7, ( 7 * ULONG_SIZE)(r1)
+ ll r8, ( 8 * ULONG_SIZE)(r1)
+ ll r9, ( 9 * ULONG_SIZE)(r1)
+ ll r10, (10 * ULONG_SIZE)(r1)
+ ll r11, (11 * ULONG_SIZE)(r1)
+ ll r12, (12 * ULONG_SIZE)(r1)
+
+ ll r1, ( 1 * ULONG_SIZE)(r1) /* restore stack at last */
+ RFI
+.endm
+
+#endif /* !CONFIG_PPC_64BITSUPPORT */
+
+/************************************************************************/
+/* vectors */
+/************************************************************************/
+
+ .section .text.vectors, "ax"
+GLOBL(__vectors):
+ nop // NULL-jmp trap
+1: nop //
+ b 1b
+
+VECTOR( 0x100, "SRE" ):
+ b _entry
+
+trap_error:
+ lis r1, 0x8000 /* r1=0x80000000 */
+ add. r1,r1,r1 /* r1=r1+r1 (high 32bit !0) */
+ beq 1f
+
+ mfmsr r1 /* unset MSR_SF */
+ clrldi r1,r1,1
+ mtmsrd r1
+1:
+ mflr r3
+ LOAD_REG_FUNC(r4, unexpected_excep)
+ mtctr r4
+ bctr
+
+ILLEGAL_VECTOR( 0x200 )
+
+VECTOR( 0x300, "DSI" ):
+ b real_dsi
+
+ILLEGAL_VECTOR( 0x380 )
+
+VECTOR( 0x400, "ISI" ):
+ b real_isi
+
+ILLEGAL_VECTOR( 0x480 )
+
+ ILLEGAL_VECTOR( 0x500 )
+ ILLEGAL_VECTOR( 0x600 )
+ ILLEGAL_VECTOR( 0x700 )
+
+VECTOR( 0x800, "FPU" ):
+ mtsprg1 r3
+ mfsrr1 r3
+ ori r3,r3,0x2000
+ mtsrr1 r3
+ mfsprg1 r3
+ RFI
+
+ILLEGAL_VECTOR( 0x900 )
+ILLEGAL_VECTOR( 0xa00 )
+ILLEGAL_VECTOR( 0xb00 )
+ILLEGAL_VECTOR( 0xc00 )
+ILLEGAL_VECTOR( 0xd00 )
+ILLEGAL_VECTOR( 0xe00 )
+ILLEGAL_VECTOR( 0xf00 )
+ILLEGAL_VECTOR( 0xf20 )
+ILLEGAL_VECTOR( 0x1000 )
+ILLEGAL_VECTOR( 0x1100 )
+ILLEGAL_VECTOR( 0x1200 )
+ILLEGAL_VECTOR( 0x1300 )
+ILLEGAL_VECTOR( 0x1400 )
+ILLEGAL_VECTOR( 0x1500 )
+ILLEGAL_VECTOR( 0x1600 )
+ILLEGAL_VECTOR( 0x1700 )
+
+#ifdef CONFIG_PPC_64BITSUPPORT
+
+VECTOR( 0x2000, "DSI_64" ):
+ EXCEPTION_PREAMBLE_64
+ LOAD_REG_IMMEDIATE(r3, dsi_exception)
+ mtctr r3
+ bctrl
+ EXCEPTION_EPILOGUE_64
+
+VECTOR( 0x2200, "ISI_64" ):
+ EXCEPTION_PREAMBLE_64
+ LOAD_REG_IMMEDIATE(r3, isi_exception)
+ mtctr r3
+ bctrl
+ EXCEPTION_EPILOGUE_64
+
+#endif
+
+real_dsi:
+ EXCEPTION_PREAMBLE
+ LOAD_REG_FUNC(r3, dsi_exception)
+ mtctr r3
+ bctrl
+ b exception_return
+
+real_isi:
+ EXCEPTION_PREAMBLE
+ LOAD_REG_FUNC(r3, isi_exception)
+ mtctr r3
+ bctrl
+ b exception_return
+
+exception_return:
+ EXCEPTION_EPILOGUE
+
+GLOBL(__vectors_end):
+
+/************************************************************************/
+/* entry */
+/************************************************************************/
+
+GLOBL(_entry):
+
+#ifdef CONFIG_PPC_64BITSUPPORT
+ li r0,0
+
+ lis r3, 0x8000 /* r1=0x80000000 */
+ add. r3,r3,r3 /* r1=r1+r1 (high 32bit !0) */
+ beq no_64bit /* only true when !MSR_SF */
+
+ /* clear MSR, disable MMU, SF */
+ mtmsrd r0
+ b real_entry
+
+no_64bit:
+ /* clear MSR, disable MMU */
+ mtmsr r0
+
+real_entry:
+#endif
+
+ /* copy exception vectors */
+
+ LOAD_REG_IMMEDIATE(r3, __vectors)
+ li r4,0
+ li r5,__vectors_end - __vectors + 16
+ rlwinm r5,r5,0,0,28
+1: lwz r6,0(r3)
+ lwz r7,4(r3)
+ lwz r8,8(r3)
+ lwz r9,12(r3)
+ stw r6,0(r4)
+ stw r7,4(r4)
+ stw r8,8(r4)
+ stw r9,12(r4)
+ dcbst 0,r4
+ sync
+ icbi 0,r4
+ sync
+ addi r5,r5,-16
+ addi r3,r3,16
+ addi r4,r4,16
+ cmpwi r5,0
+ bgt 1b
+ isync
+
+ bl compute_ramsize
+
+ /* Memory map:
+ *
+ * Top +-------------------------+
+ * | |
+ * | ROM into RAM (1 MB) |
+ * | |
+ * +-------------------------+
+ * | |
+ * | MMU Hash Table (64 kB) |
+ * | |
+ * +-------------------------+
+ * | |
+ * | Exception Stack (32 kB) |
+ * | |
+ * +-------------------------+
+ * | |
+ * | Stack (64 kB) |
+ * | |
+ * +-------------------------+
+ * | |
+ * | Client Stack (64 kB) |
+ * | |
+ * +-------------------------+
+ * | |
+ * | Malloc Zone (2 MiB) |
+ * | |
+ * +-------------------------+
+ * : :
+ * Bottom
+ */
+
+ addis r1, r3, -16 /* ramsize - 1MB */
+
+ /* setup hash table */
+
+ addis r1, r1, -1 /* - 64 kB */
+ clrrwi r1, r1, 5*4 /* & ~0xfffff */
+
+ /* setup exception stack */
+
+ mtsprg0 r1
+
+ /* setup stack */
+
+ addi r1, r1, -32768 /* - 32 kB */
+
+ /* save memory size in stack */
+
+#ifdef __powerpc64__
+ /* set up TOC pointer */
+
+ LOAD_REG_IMMEDIATE(r2, setup_mmu)
+ ld r2, 8(r2)
+#endif
+
+ bl BRANCH_LABEL(setup_mmu)
+ bl BRANCH_LABEL(entry)
+1: nop
+ b 1b
+
+
+ /* According to IEEE 1275, PPC bindings:
+ *
+ * MSR = FP, ME + (DR|IR)
+ * r1 = stack (32 K + 32 bytes link area above)
+ * r5 = client interface handler
+ * r6 = address of client program arguments (unused)
+ * r7 = length of client program arguments (unused)
+ *
+ * Yaboot and Linux use r3 and r4 for initrd address and size
+ */
+ .data
+saved_stack:
+ DATA_LONG(0)
+ .previous
+ /* void call_elf( arg1, arg2, entry ) */
+_GLOBAL(call_elf):
+ mflr r0
+ PPC_STLU r1, -STACKFRAME_MINSIZE(r1)
+ PPC_STL r0, (STACKFRAME_MINSIZE + PPC_LR_STKOFF)(r1)
+ mtlr r5
+ LOAD_REG_IMMEDIATE(r8, saved_stack) // save our stack pointer
+ PPC_STL r1,0(r8)
+ mfsdr1 r1
+ addi r1, r1, -32768 /* - 32 KiB exception stack */
+ addis r1, r1, -1 /* - 64 KiB stack */
+ LOAD_REG_IMMEDIATE(r5, of_client_callback) // r5 = callback
+ li r6,0 // r6 = address of client program arguments (unused)
+ li r7,0 // r7 = length of client program arguments (unused)
+ li r0,MSR_FP | MSR_ME | MSR_DR | MSR_IR
+ MTMSRD(r0)
+ blrl
+
+#ifdef CONFIG_PPC64
+ /* Restore SF bit */
+ LOAD_REG_IMMEDIATE(r0, MSR_SF | MSR_FP | MSR_ME | MSR_DR | MSR_IR)
+ MTMSRD(r0)
+#endif
+ LOAD_REG_IMMEDIATE(r8, saved_stack) // restore stack pointer
+ mr r1,r8
+ PPC_LL r0, (STACKFRAME_MINSIZE + PPC_LR_STKOFF)(r1)
+ mtlr r0
+ addi r1, r1, STACKFRAME_MINSIZE
+ // XXX: should restore r12-r31 etc..
+ // we should not really come here though
+ blr
+
+#ifdef __powerpc64__
+#define STKOFF STACKFRAME_MINSIZE
+#define SAVE_SPACE 320
+#else
+#define STKOFF 8
+#define SAVE_SPACE 144
+#endif
+GLOBL(of_client_callback):
+
+#ifdef CONFIG_PPC64
+ PPC_STLU r1, -(STACKFRAME_MINSIZE + 16)(r1)
+#else
+ PPC_STLU r1, -STACKFRAME_MINSIZE(r1) /* fits within alignment */
+#endif
+
+ /* save r4 */
+
+ PPC_STL r4, STKOFF(r1)
+
+ /* save lr */
+
+ mflr r4
+ PPC_STL r4, PPC_LR_STKOFF(r1)
+
+ /* restore OF stack */
+
+ LOAD_REG_IMMEDIATE(r4, saved_stack)
+ PPC_LL r4, 0(r4)
+
+ PPC_STLU r4,-SAVE_SPACE(r4)
+ PPC_STL r1,(STKOFF)(r4) // save caller stack
+ mr r1,r4
+
+ PPC_STL r2, (STKOFF + 1 * ULONG_SIZE)(r1)
+ PPC_STL r0, (STKOFF + 2 * ULONG_SIZE)(r1)
+
+ /* save ctr, cr and xer */
+
+ mfctr r2
+ PPC_STL r2, (STKOFF + 3 * ULONG_SIZE)(r1)
+ mfcr r2
+ PPC_STL r2, (STKOFF + 4 * ULONG_SIZE)(r1)
+ mfxer r2
+ PPC_STL r2, (STKOFF + 5 * ULONG_SIZE)(r1)
+
+ /* save r5 - r31 */
+
+ PPC_STL r5, (STKOFF + 6 * ULONG_SIZE)(r1)
+ PPC_STL r6, (STKOFF + 7 * ULONG_SIZE)(r1)
+ PPC_STL r7, (STKOFF + 8 * ULONG_SIZE)(r1)
+ PPC_STL r8, (STKOFF + 9 * ULONG_SIZE)(r1)
+ PPC_STL r9, (STKOFF + 10 * ULONG_SIZE)(r1)
+ PPC_STL r10, (STKOFF + 11 * ULONG_SIZE)(r1)
+ PPC_STL r11, (STKOFF + 12 * ULONG_SIZE)(r1)
+ PPC_STL r12, (STKOFF + 13 * ULONG_SIZE)(r1)
+ PPC_STL r13, (STKOFF + 14 * ULONG_SIZE)(r1)
+ PPC_STL r14, (STKOFF + 15 * ULONG_SIZE)(r1)
+ PPC_STL r15, (STKOFF + 16 * ULONG_SIZE)(r1)
+ PPC_STL r16, (STKOFF + 17 * ULONG_SIZE)(r1)
+ PPC_STL r17, (STKOFF + 18 * ULONG_SIZE)(r1)
+ PPC_STL r18, (STKOFF + 19 * ULONG_SIZE)(r1)
+ PPC_STL r19, (STKOFF + 20 * ULONG_SIZE)(r1)
+ PPC_STL r20, (STKOFF + 21 * ULONG_SIZE)(r1)
+ PPC_STL r21, (STKOFF + 22 * ULONG_SIZE)(r1)
+ PPC_STL r22, (STKOFF + 23 * ULONG_SIZE)(r1)
+ PPC_STL r23, (STKOFF + 24 * ULONG_SIZE)(r1)
+ PPC_STL r24, (STKOFF + 25 * ULONG_SIZE)(r1)
+ PPC_STL r25, (STKOFF + 26 * ULONG_SIZE)(r1)
+ PPC_STL r26, (STKOFF + 27 * ULONG_SIZE)(r1)
+ PPC_STL r27, (STKOFF + 28 * ULONG_SIZE)(r1)
+ PPC_STL r28, (STKOFF + 29 * ULONG_SIZE)(r1)
+ PPC_STL r29, (STKOFF + 30 * ULONG_SIZE)(r1)
+ PPC_STL r30, (STKOFF + 31 * ULONG_SIZE)(r1)
+ PPC_STL r31, (STKOFF + 32 * ULONG_SIZE)(r1)
+
+#ifdef CONFIG_PPC64
+ LOAD_REG_IMMEDIATE(r2, of_client_interface)
+ ld r2, 8(r2)
+#endif
+ bl BRANCH_LABEL(of_client_interface)
+
+ /* restore r5 - r31 */
+
+ PPC_LL r5, (STKOFF + 6 * ULONG_SIZE)(r1)
+ PPC_LL r6, (STKOFF + 7 * ULONG_SIZE)(r1)
+ PPC_LL r7, (STKOFF + 8 * ULONG_SIZE)(r1)
+ PPC_LL r8, (STKOFF + 9 * ULONG_SIZE)(r1)
+ PPC_LL r9, (STKOFF + 10 * ULONG_SIZE)(r1)
+ PPC_LL r10, (STKOFF + 11 * ULONG_SIZE)(r1)
+ PPC_LL r11, (STKOFF + 12 * ULONG_SIZE)(r1)
+ PPC_LL r12, (STKOFF + 13 * ULONG_SIZE)(r1)
+ PPC_LL r13, (STKOFF + 14 * ULONG_SIZE)(r1)
+ PPC_LL r14, (STKOFF + 15 * ULONG_SIZE)(r1)
+ PPC_LL r15, (STKOFF + 16 * ULONG_SIZE)(r1)
+ PPC_LL r16, (STKOFF + 17 * ULONG_SIZE)(r1)
+ PPC_LL r17, (STKOFF + 18 * ULONG_SIZE)(r1)
+ PPC_LL r18, (STKOFF + 19 * ULONG_SIZE)(r1)
+ PPC_LL r19, (STKOFF + 20 * ULONG_SIZE)(r1)
+ PPC_LL r20, (STKOFF + 21 * ULONG_SIZE)(r1)
+ PPC_LL r21, (STKOFF + 22 * ULONG_SIZE)(r1)
+ PPC_LL r22, (STKOFF + 23 * ULONG_SIZE)(r1)
+ PPC_LL r23, (STKOFF + 24 * ULONG_SIZE)(r1)
+ PPC_LL r24, (STKOFF + 25 * ULONG_SIZE)(r1)
+ PPC_LL r25, (STKOFF + 26 * ULONG_SIZE)(r1)
+ PPC_LL r26, (STKOFF + 27 * ULONG_SIZE)(r1)
+ PPC_LL r27, (STKOFF + 28 * ULONG_SIZE)(r1)
+ PPC_LL r28, (STKOFF + 29 * ULONG_SIZE)(r1)
+ PPC_LL r29, (STKOFF + 30 * ULONG_SIZE)(r1)
+ PPC_LL r30, (STKOFF + 31 * ULONG_SIZE)(r1)
+ PPC_LL r31, (STKOFF + 32 * ULONG_SIZE)(r1)
+
+ /* restore ctr, cr and xer */
+
+ PPC_LL r2, (STKOFF + 3 * ULONG_SIZE)(r1)
+ mtctr r2
+ PPC_LL r2, (STKOFF + 4 * ULONG_SIZE)(r1)
+ mtcr r2
+ PPC_LL r2, (STKOFF + 5 * ULONG_SIZE)(r1)
+ mtxer r2
+
+ /* restore r0 and r2 */
+
+ PPC_LL r2, (STKOFF + 1 * ULONG_SIZE)(r1)
+ PPC_LL r0, (STKOFF + 2 * ULONG_SIZE)(r1)
+
+ /* restore caller stack */
+
+ PPC_LL r1, (STKOFF)(r1)
+
+ PPC_LL r4, PPC_LR_STKOFF(r1)
+ mtlr r4
+ PPC_LL r4, STKOFF(r1)
+ PPC_LL r1, 0(r1)
+
+ blr
+
+ /* rtas glue (must be reloctable) */
+GLOBL(of_rtas_start):
+ /* r3 = argument buffer, r4 = of_rtas_start */
+ /* according to the CHRP standard, cr must be preserved (cr0/cr1 too?) */
+ blr
+GLOBL(of_rtas_end):
+
+
+#define CACHE_LINE_SIZE 32
+#define LG_CACHE_LINE_SIZE 5
+
+/* flush_icache_range( unsigned long start, unsigned long stop) */
+_GLOBAL(flush_icache_range):
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 2b
+ sync /* additional sync needed on g4 */
+ isync
+ blr
+
+ /* Get RAM size from QEMU configuration device */
+
+#define CFG_ADDR 0xf0000510
+#define FW_CFG_RAM_SIZE 0x03
+
+compute_ramsize:
+ LOAD_REG_IMMEDIATE(r9, CFG_ADDR)
+ li r0,FW_CFG_RAM_SIZE
+ sth r0,0(r9)
+ LOAD_REG_IMMEDIATE(r9, CFG_ADDR + 2)
+ lbz r1,0(r9)
+ lbz r0,0(r9)
+ slwi r0,r0,8
+ or r1,r1,r0
+ lbz r0,0(r9)
+ slwi r0,r0,16
+ or r1,r1,r0
+ lbz r0,0(r9)
+ slwi r0,r0,24
+ or r3,r1,r0
+ blr
+
+ /* Hard reset vector */
+ .section .romentry,"ax"
+ bl _entry
diff --git a/src/roms/openbios/arch/ppc/qemu/tree.fs b/src/roms/openbios/arch/ppc/qemu/tree.fs
new file mode 100644
index 0000000..5b6bbc6
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/tree.fs
@@ -0,0 +1,79 @@
+\ QEMU specific initialization code
+\
+\ 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
+\
+
+include config.fs
+
+\ -------------------------------------------------------------
+\ device-tree
+\ -------------------------------------------------------------
+
+" /" find-device
+\ Apple calls the root node device-tree
+" device-tree" device-name
+[IFDEF] CONFIG_PPC64 2 [ELSE] 1 [THEN] encode-int " #address-cells" property
+1 encode-int " #size-cells" property
+h# 05f5e100 encode-int " clock-frequency" property
+
+new-device
+ " cpus" device-name
+ 1 encode-int " #address-cells" property
+ 0 encode-int " #size-cells" property
+ external
+
+ : encode-unit ( unit -- str len )
+ pocket tohexstr
+ ;
+
+ : decode-unit ( str len -- unit )
+ parse-hex
+ ;
+
+finish-device
+
+new-device
+ " memory" device-name
+ " memory" device-type
+ external
+ : open true ;
+ : close ;
+finish-device
+
+new-device
+ " rom" device-name
+ h# ff800000 encode-int 0 encode-int encode+ " reg" property
+ 1 encode-int " #address-cells" property
+ h# ff800000 encode-int h# 800000 encode-int encode+
+ h# ff800000 encode-int encode+ " ranges" property
+finish-device
+
+\ -------------------------------------------------------------
+\ /packages
+\ -------------------------------------------------------------
+
+" /packages" find-device
+
+ " packages" device-name
+ external
+ \ allow packages to be opened with open-dev
+ : open true ;
+ : close ;
+
+\ /packages/terminal-emulator
+new-device
+ " terminal-emulator" device-name
+ external
+ : open true ;
+ : close ;
+ \ : write ( addr len -- actual )
+ \ dup -rot type
+ \ ;
+finish-device
+
+\ -------------------------------------------------------------
+\ The END
+\ -------------------------------------------------------------
+device-end
diff --git a/src/roms/openbios/arch/ppc/qemu/vfd.c b/src/roms/openbios/arch/ppc/qemu/vfd.c
new file mode 100644
index 0000000..308d0e3
--- /dev/null
+++ b/src/roms/openbios/arch/ppc/qemu/vfd.c
@@ -0,0 +1,42 @@
+/*
+ * Creation Date: <2004/08/28 17:29:43 greg>
+ * Time-stamp: <2004/08/28 17:29:43 greg>
+ *
+ * <vfd.c>
+ *
+ * Simple text console
+ *
+ * Copyright (C) 2004 Greg Watson
+ *
+ * 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
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "qemu/qemu.h"
+
+static int vfd_is_open;
+
+static int
+vfd_init( void )
+{
+ vfd_is_open = 1;
+ return 0;
+}
+
+void
+vfd_close( void )
+{
+}
+
+int
+vfd_draw_str( const char *str )
+{
+ if (!vfd_is_open)
+ vfd_init();
+
+ return 0;
+}
OpenPOWER on IntegriCloud