From e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Fri, 28 Aug 2015 09:58:54 +0800 Subject: Add qemu 2.4.0 Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang --- qemu/roms/openbios/arch/ppc/mol/console.c | 30 ++ qemu/roms/openbios/arch/ppc/mol/init.c | 119 +++++++ qemu/roms/openbios/arch/ppc/mol/kernel.c | 16 + qemu/roms/openbios/arch/ppc/mol/main.c | 370 +++++++++++++++++++++ qemu/roms/openbios/arch/ppc/mol/methods.c | 470 +++++++++++++++++++++++++++ qemu/roms/openbios/arch/ppc/mol/mol.c | 165 ++++++++++ qemu/roms/openbios/arch/ppc/mol/mol.fs | 107 ++++++ qemu/roms/openbios/arch/ppc/mol/mol.h | 44 +++ qemu/roms/openbios/arch/ppc/mol/osi-blk.c | 119 +++++++ qemu/roms/openbios/arch/ppc/mol/osi-scsi.c | 271 +++++++++++++++ qemu/roms/openbios/arch/ppc/mol/prom.c | 175 ++++++++++ qemu/roms/openbios/arch/ppc/mol/prom.h | 47 +++ qemu/roms/openbios/arch/ppc/mol/pseudodisk.c | 178 ++++++++++ qemu/roms/openbios/arch/ppc/mol/tree.c | 165 ++++++++++ qemu/roms/openbios/arch/ppc/mol/tree.fs | 103 ++++++ 15 files changed, 2379 insertions(+) create mode 100644 qemu/roms/openbios/arch/ppc/mol/console.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/init.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/kernel.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/main.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/methods.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/mol.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/mol.fs create mode 100644 qemu/roms/openbios/arch/ppc/mol/mol.h create mode 100644 qemu/roms/openbios/arch/ppc/mol/osi-blk.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/osi-scsi.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/prom.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/prom.h create mode 100644 qemu/roms/openbios/arch/ppc/mol/pseudodisk.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/tree.c create mode 100644 qemu/roms/openbios/arch/ppc/mol/tree.fs (limited to 'qemu/roms/openbios/arch/ppc/mol') diff --git a/qemu/roms/openbios/arch/ppc/mol/console.c b/qemu/roms/openbios/arch/ppc/mol/console.c new file mode 100644 index 000000000..966011e19 --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/console.c @@ -0,0 +1,30 @@ +/* + * Creation Date: <2002/10/29 18:59:05 samuel> + * Time-stamp: <2003/12/28 22:51:11 samuel> + * + * + * + * Simple text console + * + * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * 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 + * + */ + +#include "config.h" +#include "libopenbios/bindings.h" +#include "libc/diskio.h" +#include "osi_calls.h" +#include "libopenbios/ofmem.h" +#include "mol/mol.h" +#include "boothelper_sh.h" +#include "video_sh.h" + +#define openbios_GetFBInfo(x) OSI_GetFBInfo(x) + +#include "../../../packages/video.c" +#include "../../../libopenbios/console_common.c" diff --git a/qemu/roms/openbios/arch/ppc/mol/init.c b/qemu/roms/openbios/arch/ppc/mol/init.c new file mode 100644 index 000000000..15333b4e1 --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/init.c @@ -0,0 +1,119 @@ +/* + * Creation Date: <1999/11/16 00:49:26 samuel> + * Time-stamp: <2004/04/12 16:26:50 samuel> + * + * + * + * Initialization + * + * 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 "arch/common/nvram.h" +#include "mol/mol.h" +#include "libopenbios/ofmem.h" +#include "mol/prom.h" +#include "openbios-version.h" +#include "osi_calls.h" +#include "boothelper_sh.h" + +extern void unexpected_excep( int vector ); + +int +get_bool_res( const char *res ) +{ + char buf[8], *p; + + p = BootHGetStrRes( res, buf, sizeof(buf) ); + if( !p ) + return -1; + if( !strcasecmp(p,"true") || !strcasecmp(p,"yes") || !strcasecmp(p,"1") ) + return 1; + return 0; +} + +void +unexpected_excep( int vector ) +{ + printk("MOL panic: Unexpected exception %x\n", vector ); + for( ;; ) + ; +} + +unsigned long isa_io_base; + +void +entry( void ) +{ + isa_io_base = 0x80000000; + + printk("\n"); + printk("=============================================================\n"); + printk(PROGRAM_NAME " " OPENBIOS_VERSION_STR " [%s]\n", + OPENBIOS_BUILD_DATE); + + ofmem_init(); + initialize_forth(); + /* won't return */ + + printk("of_startup returned!\n"); + for( ;; ) + ; +} + +static void +setenv( char *env, char *value ) +{ + push_str( value ); + push_str( env ); + fword("$setenv"); +} + +void +arch_of_init( void ) +{ + mol_phandle_t ph; + int autoboot; + + devtree_init(); + node_methods_init(); + nvram_init("/pci/mac-io/nvram"); + openbios_init(); + modules_init(); + pseudodisk_init(); + osiblk_init(); + osiscsi_init(); + init_video(); + + if( (ph=prom_find_device("/rtas")) == -1 ) + 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; + prom_set_prop( ph, "rtas-size", (char*)&size, sizeof(size) ); + } + + /* tweak boot settings */ + autoboot = !!get_bool_res("autoboot"); + if( !autoboot ) + printk("Autobooting disabled - dropping into OpenFirmware\n"); + setenv("auto-boot?", autoboot ? "true" : "false" ); + setenv("boot-command", "molboot"); + + if( get_bool_res("tty-interface") == 1 ) + fword("activate-tty-interface"); + + /* hack */ + device_end(); + bind_func("molboot", boot ); +} diff --git a/qemu/roms/openbios/arch/ppc/mol/kernel.c b/qemu/roms/openbios/arch/ppc/mol/kernel.c new file mode 100644 index 000000000..1454b8a85 --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/kernel.c @@ -0,0 +1,16 @@ +/* + * Creation Date: <2004/08/28 18:03:25 stepan> + * Time-stamp: <2004/08/28 18:03:25 stepan> + * + * + * + * 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 + * + */ + +#include "mol-dict.h" +#include "../kernel.c" diff --git a/qemu/roms/openbios/arch/ppc/mol/main.c b/qemu/roms/openbios/arch/ppc/mol/main.c new file mode 100644 index 000000000..f6ed934d0 --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/main.c @@ -0,0 +1,370 @@ +/* + * Creation Date: <2002/10/02 22:24:24 samuel> + * Time-stamp: <2004/03/27 01:57:55 samuel> + * + * + * + * + * + * 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/elfload.h" +#include "arch/common/nvram.h" +#include "libc/diskio.h" +#include "libc/vsprintf.h" +#include "mol/mol.h" +#include "libopenbios/ofmem.h" +#include "osi_calls.h" +#include "ablk_sh.h" +#include "boothelper_sh.h" + + +static void patch_newworld_rom( char *start, size_t size ); +static void newworld_timer_hack( char *start, size_t size ); + +static void +transfer_control_to_elf( unsigned long entry ) +{ + extern void call_elf( unsigned long entry ); + printk("Starting ELF boot loader\n"); + call_elf( entry ); + + fatal_error("call_elf returned unexpectedly\n"); +} + +static int +load_elf_rom( unsigned long *entry, int fd ) +{ + int i, lszz_offs, elf_offs; + char buf[128], *addr; + Elf_ehdr ehdr; + Elf_phdr *phdr; + size_t s; + + printk("Loading '%s' from '%s'\n", get_file_path(fd), + get_volume_name(fd) ); + + /* the ELF-image (usually) starts at offset 0x4000 */ + if( (elf_offs=find_elf(fd)) < 0 ) { + printk("----> %s is not an ELF image\n", buf ); + exit(1); + } + if( !(phdr=elf_readhdrs(fd, elf_offs, &ehdr)) ) + fatal_error("elf_readhdrs failed\n"); + + *entry = ehdr.e_entry; + + /* load segments. Compressed ROM-image assumed to be located immediately + * after the last segment */ + lszz_offs = elf_offs; + for( i=0; i= phdr[i].p_vaddr && *entry < phdr[i].p_vaddr + s ) { + patch_newworld_rom( (char*)phdr[i].p_vaddr, s ); + newworld_timer_hack( (char*)phdr[i].p_vaddr, s ); + } + flush_icache_range( addr, addr+s ); + + /* printk("ELF ROM-section loaded at %08lX (size %08lX)\n", + (unsigned long)phdr[i].p_vaddr, (unsigned long)phdr[i].p_memsz );*/ + } + free( phdr ); + return lszz_offs; +} + + +/************************************************************************/ +/* newworld ROM loading */ +/************************************************************************/ + +#define ROM_BASE 0x1100000 /* where we decide to put things */ + +/* fix bug present in the 2.4 and the 3.0 Apple ROM */ +static void +patch_newworld_rom( char *start, size_t size ) +{ + int s; + unsigned long mark[] = { 0x7c7d1b78, /* mr r29,r3 */ + 0x7c9c2378, /* mr r28,r4 */ + 0x7cc33378, /* mr r3,r6 */ + 0x7c864214, /* add r4,r6,r8 <------ BUG -- */ + 0x80b10000, /* lwz r5,0(r17) */ + 0x38a500e8 }; /* addi r5,r5,232 */ + + /* Correcting add r4,r6,r8 ----> addi r4,r6,8 */ + for( s=0; s= 0 ) { + entry = (char*)load_newworld_rom( fd ); + close_io( fd ); + } + + /* determine boot volume */ + for( bootunit=-1, type=0; bootunit==-1 && type<3 ; type++ ) { + for( i=0; !OSI_ABlkDiskInfo(0, i, &info) ; i++ ) { + if( type<=1 && !(info.flags & ABLK_BOOT_HINT) ) + continue; + if( type>1 && (info.flags & ABLK_BOOT_HINT) ) + continue; + + for( j=0; !entry && j<32; j++ ) { + snprintf( spec, sizeof(spec), "%s/disk@%x:%d", + path, i, j ); + entry = newworld_load( path, spec, (!type || type==2) ); + } + if( entry ) { + bootunit = i; + break; + } + } + } + + if( entry ) { + OSI_ABlkBlessDisk( 0 /*channel*/, bootunit ); + + update_nvram(); + transfer_control_to_elf( (unsigned long)entry ); + /* won't come here */ + return; + } + + printk("\n--- No bootable disk was found! -----------------------------\n"); + printk("If this is an oldworld machine, try booting from the MacOS\n"); + printk("install CD and install MacOS from within MOL.\n"); + printk("-------------------------------------------------------------\n"); + exit(1); +} + + +/************************************************************************/ +/* yaboot booting */ +/************************************************************************/ + +static void +yaboot_startup( void ) +{ + const char *paths[] = { "pseudo:,ofclient", "pseudo:,yaboot", NULL }; + unsigned long entry; + int i, fd; + + for( i=0; paths[i]; i++ ) { + if( (fd=open_io(paths[i])) == -1 ) + continue; + (void) load_elf_rom( &entry, fd ); + close_io( fd ); + encode_bootpath( paths[i], "" ); + + update_nvram(); + transfer_control_to_elf( entry ); + /* won't come here */ + } + printk("*** Boot failure! No secondary bootloader specified ***\n"); + exit(1); +} + + +/************************************************************************/ +/* entry */ +/************************************************************************/ + +void +boot( void ) +{ + fword("update-chosen"); + if( find_dev("/mol-platform") ) + yaboot_startup(); + else + newworld_startup(); +} diff --git a/qemu/roms/openbios/arch/ppc/mol/methods.c b/qemu/roms/openbios/arch/ppc/mol/methods.c new file mode 100644 index 000000000..bfaf51506 --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/methods.c @@ -0,0 +1,470 @@ +/* + * Creation Date: <2003/10/18 13:24:29 samuel> + * Time-stamp: <2004/03/27 02:00:30 samuel> + * + * + * + * Misc device node methods + * + * 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 "libc/string.h" +#include "mol/mol.h" +#include "libopenbios/ofmem.h" +#include "mol/prom.h" +#include "osi_calls.h" +#include "kbd_sh.h" + +/************************************************************************/ +/* Power Management */ +/************************************************************************/ + +DECLARE_NODE( powermgt, INSTALL_OPEN, 0, "/pci/pci-bridge/mac-io/power-mgt" ); + +/* ( -- ) */ +static void +set_hybernot_flag( void ) +{ +} + +NODE_METHODS( powermgt ) = { + { "set-hybernot-flag", set_hybernot_flag }, +}; + + +/************************************************************************/ +/* RTAS (run-time abstraction services) */ +/************************************************************************/ + +DECLARE_NODE( rtas, INSTALL_OPEN, 0, "+/rtas" ); + +/* ( physbase -- rtas_callback ) */ +static void +rtas_instantiate( void ) +{ + int physbase = POP(); + int s=0x1000, size = (int)of_rtas_end - (int)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 }, +}; + + + +/************************************************************************/ +/* stdout */ +/************************************************************************/ + +DECLARE_NODE( video_stdout, INSTALL_OPEN, 0, "Tdisplay" ); + +/* ( addr len -- actual ) */ +static void +stdout_write( void ) +{ + int len = POP(); + char *addr = (char*)POP(); + + /* printk( "%s", s ); */ + console_draw_fstr(addr, len); + + PUSH( len ); +} + +NODE_METHODS( video_stdout ) = { + { "write", stdout_write }, +}; + + +/************************************************************************/ +/* tty */ +/************************************************************************/ + +DECLARE_NODE( tty, INSTALL_OPEN, 0, "+/mol/mol-tty" ); + +/* ( addr len -- actual ) */ +static void +tty_read( void ) +{ + int ch, len = POP(); + char *p = (char*)POP(); + int ret=0; + + if( len > 0 ) { + ret = 1; + ch = OSI_TTYGetc(); + if( ch >= 0 ) { + *p = ch; + } else { + ret = 0; + OSI_USleep(1); + } + } + PUSH( ret ); +} + +/* ( addr len -- actual ) */ +static void +tty_write( void ) +{ + int i, len = POP(); + char *p = (char*)POP(); + for( i=0; i" + /* 0x30 */ "\t <\b \e " + /* 0x40 */ " . * + / - " + /* 0x50 */ " =01234567 89 " + /* 0x60 */ " " + /* 0x70 */ " "; + +DECLARE_NODE( kbd, INSTALL_OPEN, sizeof(kbd_state_t), + "/psuedo-hid/keyboard", + "/mol/mol-keyboard", + "/mol/keyboard" +); + +/* ( -- keymap ) (?) */ +/* should return a pointer to an array with 32 bytes (256 bits) */ +static void +kbd_get_key_map( kbd_state_t *ks ) +{ + /* printk("met_kbd_get_key_map\n"); */ + + /* keytable[5] = 0x40; */ + PUSH( (int)ks->keytable ); +} + +/* ( buf len --- actlen ) */ +static void +kbd_read( kbd_state_t *ks ) +{ + int ret=0, len = POP(); + char *p = (char*)POP(); + int key; + + if( !p || !len ) { + PUSH( -1 ); + return; + } + + if( ks->save_key ) { + *p = ks->save_key; + ks->save_key = 0; + RET( 1 ); + } + OSI_USleep(1); /* be nice */ + + for( ; (key=OSI_GetAdbKey()) >= 0 ; ) { + int code = (key & 0x7f); + int down = !(key & 0x80); + + if( code == 0x36 /* ctrl */ ) { + ks->cntrl = down; + continue; + } + if( code == 0x38 /* shift */ || code == 0x7b) { + ks->shift = down; + continue; + } + if( code == 0x37 /* command */ ) { + ks->meta = down; + continue; + } + if( code == 0x3a /* alt */ ) { + ks->alt = down; + continue; + } + if( !down ) + continue; + + ret = 1; + if( ks->shift ) + key = adb_shift_table[ key & 0x7f ]; + else + key = adb_ascii_table[ key & 0x7f ]; + + if( ks->meta ) { + ks->save_key = key; + key = 27; + } else if( ks->cntrl ) { + key = key - 'a' + 1; + } + *p = key; + if( !*p ) + *p = 'x'; + break; + } + PUSH( ret ); +} + +NODE_METHODS( kbd ) = { + { "read", kbd_read }, + { "get-key-map", kbd_get_key_map }, +}; + + +/************************************************************************/ +/* client interface 'quiesce' */ +/************************************************************************/ + +DECLARE_NODE( ciface, 0, 0, "/packages/client-iface" ); + +/* ( -- ) */ +static void +ciface_quiesce( unsigned long args[], unsigned long ret[] ) +{ +#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 + printk("=============================================================\n\n"); + prom_close(); + + OSI_KbdCntrl( kKbdCntrlSuspend ); +} + +/* ( -- ms ) */ +static void +ciface_milliseconds( unsigned long args[], unsigned long ret[] ) +{ + static unsigned long mticks=0, usecs=0; + unsigned long t; + + asm volatile("mftb %0" : "=r" (t) : ); + if( mticks ) + usecs += OSI_MticksToUsecs( t-mticks ); + mticks = t; + + PUSH( usecs/1000 ); +} + + +NODE_METHODS( ciface ) = { + { "quiesce", ciface_quiesce }, + { "milliseconds", ciface_milliseconds }, +}; + + +/************************************************************************/ +/* MMU/memory methods */ +/************************************************************************/ + +DECLARE_NODE( memory, INSTALL_OPEN, 0, "/memory" ); +DECLARE_NODE( mmu, INSTALL_OPEN, 0, "/cpus/@0" ); +DECLARE_NODE( mmu_ciface, 0, 0, "/packages/client-iface" ); + + +/* ( phys size align --- base ) */ +static void +mem_claim( void ) +{ + ucell align = POP(); + ucell size = POP(); + ucell phys = POP(); + ucell ret = ofmem_claim_phys( phys, size, align ); + + if( ret == -1 ) { + printk("MEM: claim failure\n"); + throw( -13 ); + return; + } + PUSH( ret ); +} + +/* ( phys size --- ) */ +static void +mem_release( void ) +{ + POP(); POP(); +} + +/* ( phys size align --- base ) */ +static void +mmu_claim( void ) +{ + ucell align = POP(); + ucell size = POP(); + ucell phys = POP(); + ucell ret = ofmem_claim_virt( phys, size, align ); + + if( ret == -1 ) { + printk("MMU: CLAIM failure\n"); + throw( -13 ); + return; + } + PUSH( ret ); +} + +/* ( phys 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 ) +{ + POP(); + POP(); +} + + +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( void ) +{ + REGISTER_NODE( rtas ); + REGISTER_NODE( powermgt ); + REGISTER_NODE( kbd ); + REGISTER_NODE( video_stdout ); + REGISTER_NODE( ciface ); + REGISTER_NODE( memory ); + REGISTER_NODE( mmu ); + REGISTER_NODE( mmu_ciface ); + + if( OSI_CallAvailable(OSI_TTY_GETC) ) + REGISTER_NODE( tty ); + + OSI_KbdCntrl( kKbdCntrlActivate ); +} diff --git a/qemu/roms/openbios/arch/ppc/mol/mol.c b/qemu/roms/openbios/arch/ppc/mol/mol.c new file mode 100644 index 000000000..86b3b66bf --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/mol.c @@ -0,0 +1,165 @@ +/* + * Creation Date: <2003/12/19 18:46:21 samuel> + * Time-stamp: <2004/04/12 16:27:12 samuel> + * + * + * + * + * + * 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 "libc/vsprintf.h" +#include "libc/string.h" +#include "mol/mol.h" +#include "osi_calls.h" +#include + +void +exit( int status ) +{ + OSI_Exit(); +} + +void +fatal_error( const char *err ) +{ + printk("Fatal error: %s\n", err ); + OSI_Exit(); +} + +void +panic( const char *err ) +{ + printk("Panic: %s\n", err ); + OSI_Exit(); + + /* won't come here... this keeps the gcc happy */ + for( ;; ) + ; +} + + +/************************************************************************/ +/* print using OSI interface */ +/************************************************************************/ + +static int do_indent; + +int +printk( const char *fmt, ... ) +{ + char *p, buf[1024]; + va_list args; + int i; + + va_start(args, fmt); + i = vnsprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + for( p=buf; *p; p++ ) { + if( *p == '\n' ) + do_indent = 0; + if( do_indent++ == 1 ) { + OSI_PutC( '>' ); + OSI_PutC( '>' ); + OSI_PutC( ' ' ); + } + OSI_PutC( *p ); + } + return i; +} + + +/************************************************************************/ +/* TTY iface */ +/************************************************************************/ + +static int ttychar = -1; + +static int +tty_avail( void ) +{ + return OSI_CallAvailable( OSI_TTY_GETC ); +} + +int +availchar( void ) +{ + if( !tty_avail() ) + return 0; + + if( ttychar < 0 ) + ttychar = OSI_TTYGetc(); + if( ttychar < 0 ) + OSI_USleep(1); + return (ttychar >= 0); +} + +int +getchar( void ) +{ + int ch; + + if( !tty_avail() ) + return 0; + + if( ttychar < 0 ) + return OSI_TTYGetc(); + ch = ttychar; + ttychar = -1; + return ch; +} + +int +putchar( int c ) +{ + printk("%c", c ); + + if( tty_avail() ) + OSI_TTYPutc( c ); + return c; +} + + +/************************************************************************/ +/* MOL specific stuff */ +/************************************************************************/ + +int +arch_nvram_size( void ) +{ + return OSI_NVRamSize(); +} + +void +arch_nvram_put( char *buf ) +{ + int i, size = arch_nvram_size(); + + for( i=0; i + * Time-stamp: <2004/03/27 01:52:50 samuel> + * + * + * + * + * + * 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 + * + */ + +#ifndef _H_MOL +#define _H_MOL + +/* video.c */ +extern void init_video( void ); +extern int video_get_res( int *w, int *h ); +extern void draw_pixel( int x, int y, int colind ); +extern void set_color( int index, unsigned long color ); + +/* console.c */ +extern int console_draw_fstr(const char *str, int len); +extern void console_close( void ); + +/* pseudodisk.c */ +extern void pseudodisk_init( void ); + +/* osi-blk.c */ +extern void osiblk_init( void ); + +/* osi-scsi.c */ +extern void osiscsi_init( void ); + +/* pseudofs.c */ +extern void pseudofs_init( void ); + +#include "../kernel.h" + +#endif /* _H_MOL */ diff --git a/qemu/roms/openbios/arch/ppc/mol/osi-blk.c b/qemu/roms/openbios/arch/ppc/mol/osi-blk.c new file mode 100644 index 000000000..4ed1b5ab3 --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/osi-blk.c @@ -0,0 +1,119 @@ +/* + * Creation Date: <2003/12/07 19:08:33 samuel> + * Time-stamp: <2004/01/07 19:38:36 samuel> + * + * + * + * OSI-block interface + * + * 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 "mol/mol.h" +#include "osi_calls.h" + +typedef struct { + int unit; + int channel; +} osiblk_data_t; + + +DECLARE_NODE( osiblk, INSTALL_OPEN, sizeof(osiblk_data_t), + "/pci/pci-bridge/mol-blk/disk", "/mol/mol-blk" ); + + +static void +osiblk_open( osiblk_data_t *pb ) +{ + phandle_t ph; + + fword("my-unit"); + pb->unit = POP(); + pb->channel = 0; /* FIXME */ + + selfword("open-deblocker"); + + /* interpose disk-label */ + ph = find_dev("/packages/disk-label"); + fword("my-args"); + PUSH_ph( ph ); + fword("interpose"); + + /* printk("osi-blk: open %d\n", pb->unit ); */ + PUSH( -1 ); +} + +static void +osiblk_close( osiblk_data_t *pb ) +{ + selfword("close-deblocker"); +} + + +/* ( buf blk nblks -- actual ) */ +static void +osiblk_read_blocks( osiblk_data_t *pb ) +{ + int i, n = POP(); + int blk = POP(); + char *dest = (char*)POP(); + + /* printk("osiblk_read_blocks %x block=%d n=%d\n", (int)dest, blk, n ); */ + + for( i=0; ichannel, pb->unit, blk+i, (int)buf, m*512) < 0 ) { + printk("SyncRead: error\n"); + RET(0); + } + memcpy( dest, buf, m * 512 ); + i += m; + dest += m * 512; + } + PUSH( n ); +} + +/* ( -- bs ) */ +static void +osiblk_block_size( osiblk_data_t *pb ) +{ + PUSH( 512 ); +} + +/* ( -- maxbytes ) */ +static void +osiblk_max_transfer( osiblk_data_t *pb ) +{ + PUSH( 1024*1024 ); +} + +static void +osiblk_initialize( osiblk_data_t *pb ) +{ + fword("is-deblocker"); +} + + +NODE_METHODS( osiblk ) = { + { NULL, osiblk_initialize }, + { "open", osiblk_open }, + { "close", osiblk_close }, + { "read-blocks", osiblk_read_blocks }, + { "block-size", osiblk_block_size }, + { "max-transfer", osiblk_max_transfer }, +}; + +void +osiblk_init( void ) +{ + REGISTER_NODE( osiblk ); +} diff --git a/qemu/roms/openbios/arch/ppc/mol/osi-scsi.c b/qemu/roms/openbios/arch/ppc/mol/osi-scsi.c new file mode 100644 index 000000000..18f3dc577 --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/osi-scsi.c @@ -0,0 +1,271 @@ +/* + * Creation Date: <2003/12/11 21:23:54 samuel> + * Time-stamp: <2004/01/07 19:38:45 samuel> + * + * + * + * SCSI device node + * + * 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 "mol/mol.h" +#include "scsi_sh.h" +#include "osi_calls.h" + +#define MAX_TARGETS 32 + +typedef struct { + int probed; + int valid; /* a useable device found */ + + int is_cd; + int blocksize; +} target_info_t; + +static target_info_t scsi_devs[ MAX_TARGETS ]; + +typedef struct { + int target; + target_info_t *info; +} instance_data_t; + + +DECLARE_NODE( scsi, INSTALL_OPEN, sizeof(instance_data_t), + "/pci/pci-bridge/mol-scsi/sd", "/mol/mol-scsi/sd" ); + + +static int +scsi_cmd_( instance_data_t *sd, const char *cmd, int cmdlen, char *dest, + int len, int prelen, int postlen ) +{ + char prebuf[4096], postbuf[4096]; + scsi_req_t r[2]; /* the [2] is a hack to get space for the sg-list */ + char sb[32]; + + /* memset( dest, 0, len ); */ + + if( (unsigned int)prelen > sizeof(prebuf) || (unsigned int)postlen > sizeof(postbuf) ) { + printk("bad pre/post len %d %d\n", prelen, postlen ); + return 1; + } + + memset( r, 0, sizeof(r[0]) ); + r->lun = 0; + r->target = sd->target; + r->is_write = 0; + memcpy( r->cdb, cmd, cmdlen ); + r->client_addr = (int)&r; + r->cdb_len = cmdlen; + r->sense[0].base = (int)&sb; + r->sense[0].size = sizeof(sb); + r->size = prelen + len + postlen; + r->n_sg = 3; + r->sglist.n_el = 3; + r->sglist.vec[0].base = (int)prebuf; + r->sglist.vec[0].size = prelen; + r->sglist.vec[1].base = (int)dest; + r->sglist.vec[1].size = len; + r->sglist.vec[2].base = (int)postbuf; + r->sglist.vec[2].size = postlen; + + if( OSI_SCSISubmit((int)&r) ) { + printk("OSI_SCSISubmit: error!\n"); + return 1; + } + while( !OSI_SCSIAck() ) + OSI_USleep( 10 ); + + if( r->adapter_status ) + return -1; + if( r->scsi_status ) + return ((sb[2] & 0xf) << 16) | (sb[12] << 8) | sb[13]; + return 0; +} + +static int +scsi_cmd( instance_data_t *sd, const char *cmd, int cmdlen ) +{ + return scsi_cmd_( sd, cmd, cmdlen, NULL, 0, 0, 0 ); +} + +/* ( buf blk nblks -- actual ) */ +static void +scsi_read_blocks( instance_data_t *sd ) +{ + int nblks = POP(); + int blk = POP(); + char *dest = (char*)POP(); + unsigned char cmd[10]; + int len = nblks * sd->info->blocksize; + + memset( dest, 0, len ); + + /* printk("READ: blk: %d length %d\n", blk, len ); */ + memset( cmd, 0, sizeof(cmd) ); + cmd[0] = 0x28; /* READ_10 */ + cmd[2] = blk >> 24; + cmd[3] = blk >> 16; + cmd[4] = blk >> 8; + cmd[5] = blk; + cmd[7] = nblks >> 8; + cmd[8] = nblks; + + if( scsi_cmd_(sd, cmd, 10, dest, len, 0, 0) ) { + printk("read: scsi_cmd failed\n"); + RET( -1 ); + } + PUSH( nblks ); +} + +static int +inquiry( instance_data_t *sd ) +{ + char inquiry_cmd[6] = { 0x12, 0, 0, 0, 32, 0 }; + char start_stop_unit_cmd[6] = { 0x1b, 0, 0, 0, 1, 0 }; + char test_unit_ready_cmd[6] = { 0x00, 0, 0, 0, 0, 0 }; + char prev_allow_medium_removal[6] = { 0x1e, 0, 0, 0, 1, 0 }; + char set_cd_speed_cmd[12] = { 0xbb, 0, 0xff, 0xff, 0xff, 0xff, + 0, 0, 0, 0, 0, 0 }; + target_info_t *info = &scsi_devs[sd->target]; + char ret[32]; + int i, sense; + + if( sd->target >= MAX_TARGETS ) + return -1; + sd->info = info; + + if( info->probed ) + return info->valid ? 0:-1; + info->probed = 1; + + if( (sense=scsi_cmd_(sd, inquiry_cmd, 6, ret, 2, 0, 0)) ) { + if( sense < 0 ) + return -1; + printk("INQUIRY failed\n"); + return -1; + } + + /* medium present? */ + if( (scsi_cmd(sd, test_unit_ready_cmd, 6) >> 8) == 0x23a ) { + printk("no media\n"); + return -1; + } + + info->is_cd = 0; + info->blocksize = 512; + + if( ret[0] == 5 /* CD/DVD */ ) { + info->blocksize = 2048; + info->is_cd = 1; + + scsi_cmd( sd, prev_allow_medium_removal, 6 ); + scsi_cmd( sd, set_cd_speed_cmd, 12 ); + scsi_cmd( sd, start_stop_unit_cmd, 6 ); + + } else if( ret[0] == 0 /* DISK */ ) { + scsi_cmd( sd, test_unit_ready_cmd, 6 ); + scsi_cmd( sd, start_stop_unit_cmd, 6 ); + } else { + /* don't boot from this device (could be a scanner :-)) */ + return -1; + } + + /* wait for spin-up (or whatever) to complete */ + for( i=0; ; i++ ) { + if( i > 300 ) { + printk("SCSI timeout (sense %x)\n", sense ); + return -1; + } + sense = scsi_cmd( sd, test_unit_ready_cmd, 6 ); + if( (sense & 0xf0000) == 0x20000 ) { + OSI_USleep( 10000 ); + continue; + } + break; + } + + info->valid = 1; + return 0; +} + +/* ( -- success? ) */ +static void +scsi_open( instance_data_t *sd ) +{ + static int once = 0; + phandle_t ph; + + fword("my-unit"); + sd->target = POP(); + + if( !once ) { + once++; + OSI_SCSIControl( SCSI_CTRL_INIT, 0 ); + } + + /* obtiain device information */ + if( inquiry(sd) ) + RET(0); + + selfword("open-deblocker"); + + /* interpose disk-label */ + ph = find_dev("/packages/disk-label"); + fword("my-args"); + PUSH_ph( ph ); + fword("interpose"); + + PUSH( -1 ); +} + +/* ( -- ) */ +static void +scsi_close( instance_data_t *pb ) +{ + selfword("close-deblocker"); +} + + +/* ( -- bs ) */ +static void +scsi_block_size( instance_data_t *sd ) +{ + PUSH( sd->info->blocksize ); +} + +/* ( -- maxbytes ) */ +static void +scsi_max_transfer( instance_data_t *sd ) +{ + PUSH( 1024*1024 ); +} + +static void +scsi_initialize( instance_data_t *sd ) +{ + fword("is-deblocker"); +} + + +NODE_METHODS( scsi ) = { + { NULL, scsi_initialize }, + { "open", scsi_open }, + { "close", scsi_close }, + { "read-blocks", scsi_read_blocks }, + { "block-size", scsi_block_size }, + { "max-transfer", scsi_max_transfer }, +}; + +void +osiscsi_init( void ) +{ + REGISTER_NODE( scsi ); +} diff --git a/qemu/roms/openbios/arch/ppc/mol/prom.c b/qemu/roms/openbios/arch/ppc/mol/prom.c new file mode 100644 index 000000000..0bc8bcfbc --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/prom.c @@ -0,0 +1,175 @@ +/* + * Creation Date: <2002/10/03 20:55:02 samuel> + * Time-stamp: <2002/10/29 13:00:23 samuel> + * + * + * + * oftree interface + * + * Copyright (C) 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 "config.h" +#include "osi_calls.h" +#include "mol/prom.h" + +/* OSI_PromClose (free linux side device tree) */ +int +prom_close( void ) +{ + return OSI_PromIface( kPromClose, 0 ); +} + +/* ret: 0 no more peers, -1 if error */ +mol_phandle_t +prom_peer( mol_phandle_t phandle ) +{ + return OSI_PromIface( kPromPeer, phandle ); +} + +/* ret: 0 no child, -1 if error */ +mol_phandle_t +prom_child( mol_phandle_t phandle ) +{ + return OSI_PromIface( kPromChild, phandle ); +} + +/* ret: 0 if root node, -1 if error */ +mol_phandle_t +prom_parent( mol_phandle_t phandle ) +{ + return OSI_PromIface( kPromParent, phandle ); +} + +/* ret: -1 error */ +int +prom_package_to_path( mol_phandle_t phandle, char *buf, long buflen ) +{ + return OSI_PromIface2( kPromPackageToPath, phandle, (int)buf, buflen ); +} + +/* ret: -1 error */ +int +prom_get_prop_len( mol_phandle_t phandle, const char *name ) +{ + return OSI_PromIface1( kPromGetPropLen, phandle, (int)name ); +} + +/* ret: prop len or -1 if error */ +int +prom_get_prop( mol_phandle_t phandle, const char *name, char *buf, long buflen ) +{ + return OSI_PromIface3( kPromGetProp, phandle, (int)name, (int)buf, buflen ); +} + +/* ret: prop len or -1 if error */ +int +prom_get_prop_by_path( const char *path, const char *name, char *buf, long buflen ) +{ + mol_phandle_t ph = prom_find_device(path); + return (ph != -1)? prom_get_prop( ph, name, buf, buflen) : -1; +} + +/* ret: -1 error, 0 last prop, 1 otherwise */ +int +prom_next_prop( mol_phandle_t phandle, const char *prev, char *buf ) +{ + return OSI_PromIface2( kPromNextProp, phandle, (int)prev, (int)buf ); +} + +/* ret: -1 if error */ +int +prom_set_prop( mol_phandle_t phandle, const char *name, char *buf, long buflen ) +{ + return OSI_PromIface3( kPromSetProp, phandle, (int)name, (int)buf, buflen ); +} + +/* ret: -1 if error */ +mol_phandle_t +prom_create_node( const char *path ) +{ + return OSI_PromPathIface( kPromCreateNode, path ); +} + +/* ret: -1 if not found */ +mol_phandle_t +prom_find_device( const char *path ) +{ + mol_phandle_t ph; + char buf2[256], ch, *p; + + if( !path ) + return -1; + + if( (ph=OSI_PromPathIface( kPromFindDevice, path )) != -1 ) + return ph; + else if( path[0] == '/' ) + return -1; + + /* might be an alias */ + if( !(p=strpbrk(path, "@:/")) ) + p = (char*)path + strlen(path); + + ch = *p; + *p = 0; + if( (ph=prom_get_prop(prom_find_device("/aliases"), path, buf2, sizeof(buf2))) == -1 ) + return -1; + *p = ch; + strncat( buf2, p, sizeof(buf2) ); + + if( buf2[0] != '/' ) { + printk("Error: aliases must be absolute!\n"); + return -1; + } + ph = OSI_PromPathIface( kPromFindDevice, buf2 ); + return ph; +} + + + +/************************************************************************/ +/* search the tree for nodes with matching device_type */ +/************************************************************************/ + +static mol_phandle_t +prom_find_device_type_( mol_phandle_t ph, const char *type, int *icount, int index ) +{ + char buf[64]; + int ph2; + + if( ph == -1 || !ph ) + return -1; + if( prom_get_prop( ph, "device_type", buf, sizeof(buf)) > 0 ) + if( !strcmp(buf, type) ) + if( (*icount)++ == index ) + return ph; + if( (ph2=prom_find_device_type_( prom_peer(ph), type, icount, index )) != -1 ) + return ph2; + if( (ph2=prom_find_device_type_( prom_child(ph), type, icount, index )) != -1 ) + return ph2; + return -1; +} + +mol_phandle_t +prom_find_device_type( const char *type, int index ) +{ + int count = 0; + return prom_find_device_type_( prom_peer(0), type, &count, index ); +} + + +/************************************************************************/ +/* device tree tweaking */ +/************************************************************************/ + +/* -1 if error */ +int +prom_change_phandle( mol_phandle_t old_ph, mol_phandle_t new_ph ) +{ + return OSI_PromIface1( kPromChangePHandle, old_ph, (int)new_ph ); +} diff --git a/qemu/roms/openbios/arch/ppc/mol/prom.h b/qemu/roms/openbios/arch/ppc/mol/prom.h new file mode 100644 index 000000000..54a856c27 --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/prom.h @@ -0,0 +1,47 @@ +/* + * Creation Date: <2002/10/03 21:07:27 samuel> + * Time-stamp: <2003/10/22 22:45:26 samuel> + * + * + * + * device tree interface + * + * Copyright (C) 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 + * + */ + +#ifndef _H_PROM +#define _H_PROM + +/* Note 1: MOL uses -1 as the invalid phandle while OpenFirmware uses 0 as the + * invalid phandle (it is also the root node). + * + * Note 2: phandles might be negative. For instance, phandles originating from + * a real Open Firmware tree might look like 0xff123000 (a ROM address)... + */ + +typedef enum { kGetRootPhandle=0 } mol_phandle_t; /* must promote to int */ + +extern int prom_close( void ); + +extern mol_phandle_t prom_peer( mol_phandle_t phandle ); +extern mol_phandle_t prom_child( mol_phandle_t phandle ); +extern mol_phandle_t prom_parent( mol_phandle_t phandle ); +extern int prom_package_to_path( mol_phandle_t phandle, char *buf, long buflen ); +extern int prom_get_prop_len( mol_phandle_t phandle, const char *name ); +extern int prom_get_prop( mol_phandle_t phandle, const char *name, char *buf, long buflen ); +extern int prom_get_prop_by_path( const char *path, const char *name, char *buf, long buflen ); +extern int prom_next_prop( mol_phandle_t phandle, const char *prev, char *buf ); +extern int prom_set_prop( mol_phandle_t phandle, const char *name, char *buf, long buflen ); +extern mol_phandle_t prom_create_node( const char *path ); +extern mol_phandle_t prom_find_device( const char *path ); + +extern mol_phandle_t prom_find_device_type( const char *type, int index ); + +extern int prom_change_phandle( mol_phandle_t old_ph, mol_phandle_t new_ph ); + +#endif /* _H_PROM */ diff --git a/qemu/roms/openbios/arch/ppc/mol/pseudodisk.c b/qemu/roms/openbios/arch/ppc/mol/pseudodisk.c new file mode 100644 index 000000000..a98e54845 --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/pseudodisk.c @@ -0,0 +1,178 @@ +/* + * Creation Date: <2003/11/26 16:55:47 samuel> + * Time-stamp: <2004/01/07 19:41:54 samuel> + * + * + * + * pseudodisk (contains files exported from linux) + * + * 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 "osi_calls.h" +#include "libc/string.h" +#include "libopenbios/ofmem.h" +#include "mol/prom.h" +#include "mol/mol.h" +#include "osi_calls.h" +#include "pseudofs_sh.h" + +typedef struct { + int seekpos; + int fd; + char *myargs; + char *name; + int size; +} pdisk_data_t; + + +DECLARE_NODE( pdisk, INSTALL_OPEN, sizeof(pdisk_data_t), "/mol/pseudo-disk/disk" ); + +static void +pdisk_open( pdisk_data_t *pb ) +{ + char *ep, *name = NULL; + int part; + + pb->myargs = my_args_copy(); + /* printk("pdisk-open: %s\n", pb->myargs ); */ + + part = strtol( pb->myargs, &ep, 10 ); + if( *ep ) { + if( (name=strchr(pb->myargs, ',')) ) { + *name = 0; + name++; + } else { + name = pb->myargs; + } + } + if( part ) + goto err; + + if( !name || !strlen(name) ) + pb->fd = -1; + else { + if( (pb->fd=PseudoFSOpen(name)) < 0 ) + goto err; + pb->size = PseudoFSGetSize( pb->fd ); + } + pb->name = name; + RET( -1 ); + err: + free( pb->myargs ); + RET(0); +} + +/* ( addr len -- actual ) */ +static void +pdisk_read( pdisk_data_t *pb ) +{ + int len = POP(); + char *dest = (char*)POP(); + int cnt; + + if( pb->fd < 0 ) { + memset( dest, 0, len ); + PUSH(len); + return; + } + /* dest is not "mol-DMA" safe (might have a nontrivial mapping) */ + for( cnt=0; cntfd, pb->seekpos, buf, n ); + if( n <= 0 ) + break; + + memcpy( dest+cnt, buf, n ); + cnt += n; + pb->seekpos += n; + } + PUSH( cnt ); +} + +/* ( addr len -- actual ) */ +static void +pdisk_write( pdisk_data_t *pb ) +{ + POP(); POP(); PUSH(-1); + printk("pdisk write\n"); +} + +/* ( pos.lo pos.hi -- status ) */ +static void +pdisk_seek( pdisk_data_t *pb ) +{ + int pos_lo; + POP(); + pos_lo = POP(); + + if( pb->fd >= 0 ) { + if( pos_lo == -1 ) + pos_lo = pb->size; + } + + pb->seekpos = pos_lo; + + PUSH(0); /* ??? */ +} + +/* ( -- pos.d ) */ +static void +pdisk_tell( pdisk_data_t *pb ) +{ + DPUSH( pb->seekpos ); +} + +/* ( -- cstr ) */ +static void +pdisk_get_path( pdisk_data_t *pb ) +{ + PUSH( (int)pb->name ); +} + +/* ( -- cstr ) */ +static void +pdisk_get_fstype( pdisk_data_t *pb ) +{ + PUSH( (int)"PSEUDO" ); +} + +/* ( -- cstr ) */ +static void +pdisk_volume_name( pdisk_data_t *pb ) +{ + PUSH( (int)"Virtual Volume" ); +} + +static void +pdisk_block_size( pdisk_data_t *pb ) +{ + PUSH(1); +} + +NODE_METHODS( pdisk ) = { + { "open", pdisk_open }, + { "read", pdisk_read }, + { "write", pdisk_write }, + { "seek", pdisk_seek }, + { "tell", pdisk_tell }, + { "block-size", pdisk_block_size }, + { "get-path", pdisk_get_path }, + { "get-fstype", pdisk_get_fstype }, + { "volume-name", pdisk_volume_name }, +}; + +void +pseudodisk_init( void ) +{ + REGISTER_NODE( pdisk ); +} diff --git a/qemu/roms/openbios/arch/ppc/mol/tree.c b/qemu/roms/openbios/arch/ppc/mol/tree.c new file mode 100644 index 000000000..b82c8c2c8 --- /dev/null +++ b/qemu/roms/openbios/arch/ppc/mol/tree.c @@ -0,0 +1,165 @@ +/* + * Creation Date: <2003/11/18 14:55:05 samuel> + * Time-stamp: <2004/03/27 02:03:55 samuel> + * + * + * + * device tree setup + * + * 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 "mol/mol.h" +#include "mol/prom.h" + + +/************************************************************************/ +/* copy device tree */ +/************************************************************************/ + +static void +copy_node( mol_phandle_t molph ) +{ + char name[40], path[80]; + int exists; + phandle_t ph; + + if( !molph ) + return; + + prom_package_to_path( molph, path, sizeof(path) ); + + /* don't copy /options node */ + if( !strcmp("/options", path) ) { + copy_node( prom_peer(molph) ); + return; + } + + exists = 1; + if( !(ph=find_dev(path)) ) { + exists = 0; + fword("new-device"); + ph = get_cur_dev(); + } + activate_dev( ph ); + + name[0] = 0; + while( prom_next_prop(molph, name, name) > 0 ) { + int len = prom_get_prop_len( molph, name ); + char *p; +#if 0 + if( len > 0x1000 ) { + printk("prop to large (%d)\n", len ); + continue; + } +#endif + /* don't copy /chosen/{stdin,stdout} (XXX: ugly hack...) */ + if( !strcmp("/chosen", path) ) + if( !strcmp("stdio", name) || !strcmp("stdout", name) ) + continue; + + p = malloc( len ); + prom_get_prop( molph, name, p, len ); + set_property( ph, name, p, len ); + free( p ); + } + + set_int_property( ph, "MOL,phandle", molph ); + copy_node( prom_child(molph) ); + + if( !exists ) + fword("finish-device"); + else + activate_device(".."); + + copy_node( prom_peer(molph) ); +} + + + +/************************************************************************/ +/* device tree cloning and tweaking */ +/************************************************************************/ + +static phandle_t +translate_molph( mol_phandle_t molph ) +{ + static mol_phandle_t cached_molph; + static phandle_t cached_ph; + phandle_t ph=0; + + if( cached_molph == molph ) + return cached_ph; + + while( (ph=dt_iterate(ph)) ) + if( get_int_property(ph, "MOL,phandle", NULL) == molph ) + break; + cached_molph = molph; + cached_ph = ph; + + if( !ph ) + printk("failed to translate molph\n"); + return ph; +} + +static void +fix_phandles( void ) +{ + static char *pnames[] = { "interrupt-parent", "interrupt-controller", NULL } ; + int len, *map; + phandle_t ph=0; + char **pp; + + while( (ph=dt_iterate(ph)) ) { + for( pp=pnames; *pp; pp++ ) { + phandle_t *p = (phandle_t*)get_property( ph, *pp, &len ); + if( len == 4 ) + *p = translate_molph( *(int*)p ); + } + + /* need to fix interrupt map properties too */ + if( (map=(int*)get_property(ph, "interrupt-map", &len)) ) { + int i, acells = get_int_property(ph, "#address-cells", NULL); + int icells = get_int_property(ph, "#interrupt-cells", NULL); + + len /= sizeof(int); + for( i=0; i