diff options
Diffstat (limited to 'src/roms/openbios/arch/ppc/qemu')
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/console.c | 88 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/init.c | 1013 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/kernel.c | 115 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/kernel.h | 42 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/ldscript | 68 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/main.c | 85 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/methods.c | 329 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/mmutypes.h | 97 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/ofmem.c | 563 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/qemu.c | 106 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/qemu.fs | 123 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/qemu.h | 24 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/start.S | 729 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/tree.fs | 79 | ||||
-rw-r--r-- | src/roms/openbios/arch/ppc/qemu/vfd.c | 42 |
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; +} |