summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/arch/ppc/mol
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/arch/ppc/mol')
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/console.c30
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/init.c119
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/kernel.c16
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/main.c370
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/methods.c470
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/mol.c165
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/mol.fs107
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/mol.h44
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/osi-blk.c119
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/osi-scsi.c271
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/prom.c175
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/prom.h47
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/pseudodisk.c178
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/tree.c165
-rw-r--r--qemu/roms/openbios/arch/ppc/mol/tree.fs103
15 files changed, 2379 insertions, 0 deletions
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>
+ *
+ * <console.c>
+ *
+ * Simple text console
+ *
+ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
+ * 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 "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>
+ *
+ * <init.c>
+ *
+ * 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>
+ *
+ * <mol/kernel.c>
+ *
+ * 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>
+ *
+ * <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/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<ehdr.e_phnum; i++ ) {
+ /* p_memsz, p_flags */
+ s = MIN( phdr[i].p_filesz, phdr[i].p_memsz );
+ seek_io( fd, elf_offs + phdr[i].p_offset );
+
+ /* printk("filesz: %08lX memsz: %08lX p_offset: %08lX p_vaddr %08lX\n",
+ phdr[i].p_filesz, phdr[i].p_memsz, phdr[i].p_offset,
+ phdr[i].p_vaddr ); */
+
+ if( phdr[i].p_vaddr != phdr[i].p_paddr )
+ printk("WARNING: ELF segment virtual addr != physical addr\n");
+ lszz_offs = MAX( lszz_offs, elf_offs + phdr[i].p_offset + phdr[i].p_filesz );
+ if( !s )
+ continue;
+ if( ofmem_claim( phdr[i].p_vaddr, phdr[i].p_memsz, 0 ) == -1 )
+ fatal_error("Claim failed!\n");
+
+ addr = (char*)phdr[i].p_vaddr;
+ if( read_io(fd, addr, s) != s )
+ fatal_error("read failed\n");
+
+ /* patch CODE segment */
+ if( *entry >= 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<size-sizeof(mark); s+=4 )
+ if( memcmp( start+s, mark, sizeof(mark)) == 0 ) {
+ printk("FIXING ROM BUG @ %X!\n", s+12);
+ ((unsigned long*)(start+s))[3] = 0x38860008; /* addi r4,r6,8 */
+ }
+}
+
+/* This hack is only needed on machines with a timebase slower than 12.5 MHz
+ * (50 MHz bus frequency). Typically only old, accelerated machines fall
+ * into this category. The cause of the problem is an overflow in Apple's
+ * calibration routine.
+ */
+static void
+newworld_timer_hack( char *start, size_t size )
+{
+ int s;
+ unsigned long mark[] = { 0x7d0000a6, 0x5507045e, 0x7ce00124, 0x4c00012c,
+ 0x38e00000, 0x3c80000f, 0x6084ffff, 0x98830c00,
+ 0x7c0006ac, 0x98830a00, 0x7c0006ac, 0x7c9603a6,
+ 0x4c00012c, 0x7cb602a6, 0x2c050000, 0x4181fff8,
+ 0x7c0004ac, 0x88830a00, 0x7c0006ac, 0x88a30800,
+ 0x7c0006ac, 0x88c30a00, 0x7c0006ac, 0x7c043040,
+ 0x40a2ffe4, 0x5085442e, 0x7ca500d0, 0x54a5043e,
+ 0x7c053840, 0x7ca72b78, 0x4082ff9c, 0x7ca32b78,
+ 0x7d000124, 0x4c00012c, 0x4e800020
+ };
+
+ /* return #via ticks corresponding to 0xfffff DEC ticks (VIA frequency == 47/60 MHz) */
+ for( s=0; s < size-sizeof(mark); s+=4 ) {
+ if( !memcmp( start+s, mark, sizeof(mark)) ) {
+ extern char timer_calib_start[], timer_calib_end[];
+ extern unsigned long nw_dec_calibration;
+ int hz = OSI_UsecsToMticks(1000);
+ nw_dec_calibration = OSI_MticksToUsecs(0xfffff*47)/60;
+ memcpy( start + s, timer_calib_start, timer_calib_end - timer_calib_start );
+
+ printk("Timer calibration fix: %d.%02d MHz [%ld]\n",
+ hz/1000, (hz/10)%100, nw_dec_calibration );
+ break;
+ }
+ }
+}
+
+static unsigned long
+load_newworld_rom( int fd )
+{
+ int lszz_offs, lszz_size;
+ unsigned long entry, data[2];
+ phandle_t ph;
+
+ lszz_offs = load_elf_rom( &entry, fd );
+ seek_io( fd, -1 );
+ lszz_size = tell(fd) - lszz_offs;
+ seek_io( fd, lszz_offs );
+
+ /* printk("Compressed ROM image: offset %08X, size %08X loaded at %08x\n",
+ lszz_offs, lszz_size, ROM_BASE ); */
+
+ if( ofmem_claim(ROM_BASE, lszz_size, 0) == -1 )
+ fatal_error("Claim failure (lszz)!\n");
+
+ read_io( fd, (char*)ROM_BASE, lszz_size );
+
+ /* Fix the /rom/macos/AAPL,toolbox-image,lzss property (phys, size) */
+#if 0
+ if( (ph=prom_create_node("/rom/macos/")) == -1 )
+ fatal_error("Failed creating /rom/macos/");
+#else
+ ph = find_dev("/rom/macos");
+#endif
+ data[0] = ROM_BASE;
+ data[1] = lszz_size;
+ set_property( ph, "AAPL,toolbox-image,lzss", (char*)data, sizeof(data) );
+
+ /* The 7.8 rom (MacOS 9.2) uses AAPL,toolbox-parcels instead of
+ * AAPL,toolbox-image,lzss. It probably doesn't hurt to have it
+ * always present (we don't have an easy way to determine ROM version...)
+ */
+ set_property( ph, "AAPL,toolbox-parcels", (char*)data, sizeof(data) );
+ return entry;
+}
+
+static int
+search_nwrom( int fd, int fast )
+{
+ char *s, buf[128];
+ int found = 0;
+
+ if( fast ) {
+ int ind;
+ found = !reopen( fd, "\\\\:tbxi" );
+ for( ind=0; !found && (s=BootHGetStrResInd("macos_rompath", buf, sizeof(buf), ind++, 0)) ; )
+ found = !reopen( fd, s );
+ for( ind=0; !found && (s=BootHGetStrResInd("macos_rompath_", buf, sizeof(buf), ind++, 0)) ; )
+ found = !reopen( fd, s );
+ } else {
+ printk("Searching %s for a 'Mac OS ROM' file\n", get_volume_name(fd) );
+ if( !(found=reopen_nwrom(fd)) ) {
+ printk(" \n**** HINT ***************************************************\n");
+ printk("* The booting can be speeded up by adding the line\n");
+ printk("* macos_rompath: '%s'\n", get_file_path(fd) );
+ printk("* to the /etc/mol/molrc.macos (recommended).\n");
+ printk("*************************************************************\n \n");
+ }
+ }
+ return found;
+}
+
+static void
+encode_bootpath( const char *spec, const char *args )
+{
+ phandle_t chosen_ph = find_dev("/chosen");
+ set_property( chosen_ph, "bootpath", spec, strlen(spec)+1 );
+ set_property( chosen_ph, "bootargs", args, strlen(args)+1 );
+}
+
+static char *
+newworld_load( const char *node_path, const char *spec, int do_search )
+{
+ char *p, *entry, buf[80];
+ int fd, len;
+
+ if( (fd=open_io(spec)) == -1 )
+ return NULL;
+
+ if( !search_nwrom(fd, do_search) ) {
+ close_io(fd);
+ return NULL;
+ }
+ printk("Boot Disk: %s [%s]\n", spec, get_fstype(fd) );
+
+ entry = (char*)load_newworld_rom( fd );
+
+#if 1
+ PUSH_ih( get_ih_from_fd(fd) );
+ fword("get-instance-path");
+ len = POP();
+ p = (char*)POP();
+ buf[0] = 0;
+ if( len < sizeof(buf) ) {
+ memcpy( buf, p, len );
+ buf[len] =0;
+ }
+ strcat( buf, "/x@:" );
+ printk("boot_path: %s\n", buf );
+ encode_bootpath( buf, "" );
+#endif
+ close_io( fd );
+ return entry;
+}
+
+static void
+newworld_startup( void )
+{
+ int i, j, bootunit, type, fd;
+ ablk_disk_info_t info;
+ char *entry = NULL;
+ char spec[80];
+ phandle_t ph;
+
+ char path[]="/pci/pci-bridge/mol-blk";
+ if( !(ph=find_dev(path)) )
+ fatal_error("MOLBlockDriver node not found\n");
+
+ /* user-specified newworld ROMs take precedence */
+ if( (fd=open_io("pseudo:,nwrom")) >= 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>
+ *
+ * <methods.c>
+ *
+ * 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<len; i++ )
+ OSI_TTYPutc( *p++ );
+ RET( len );
+}
+
+NODE_METHODS( tty ) = {
+ { "read", tty_read },
+ { "write", tty_write },
+};
+
+
+/************************************************************************/
+/* keyboard */
+/************************************************************************/
+
+typedef struct {
+ int cntrl;
+ int shift;
+ int meta;
+ int alt;
+ int save_key;
+ char keytable[32];
+} kbd_state_t;
+
+static const unsigned char adb_ascii_table[128] =
+ /* 0x00 */ "asdfhgzxcv`bqwer"
+ /* 0x10 */ "yt123465=97-80]o"
+ /* 0x20 */ "u[ip\nlj'k;\\,/nm."
+ /* 0x30 */ "\t <\b \e "
+ /* 0x40 */ " . * + / - "
+ /* 0x50 */ " =01234567 89 "
+ /* 0x60 */ " "
+ /* 0x70 */ " ";
+
+static const unsigned char adb_shift_table[128] =
+ /* 0x00 */ "ASDFHGZXCV~BQWER"
+ /* 0x10 */ "YT!@#$^%+(&_*)}O"
+ /* 0x20 */ "U{IP\nLJ\"K:|<?NM>"
+ /* 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>
+ *
+ * <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 "libc/vsprintf.h"
+#include "libc/string.h"
+#include "mol/mol.h"
+#include "osi_calls.h"
+#include <stdarg.h>
+
+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<size; i++ )
+ OSI_WriteNVRamByte( i, buf[i] );
+}
+
+void
+arch_nvram_get( char *buf )
+{
+ int i, size = arch_nvram_size();
+
+ /* support for zapping the nvram */
+ if( get_bool_res("zap_nvram") == 1 ) {
+ memset( buf, 0, size );
+ return;
+ }
+
+ for( i=0; i<size; i++ )
+ buf[i] = OSI_ReadNVRamByte( i );
+}
diff --git a/qemu/roms/openbios/arch/ppc/mol/mol.fs b/qemu/roms/openbios/arch/ppc/mol/mol.fs
new file mode 100644
index 000000000..10c99bd79
--- /dev/null
+++ b/qemu/roms/openbios/arch/ppc/mol/mol.fs
@@ -0,0 +1,107 @@
+
+
+\ -------------------------------------------------------------------------
+\ 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
+ " memory" " /memory" preopen
+ " mmu" " /cpus/@0" preopen
+ " stdout" " /packages/mol-stdout" preopen
+ " stdin" " keyboard" preopen
+ " nvram" " /pci/pci-bridge/mac-io/nvram" preopen
+ " nvram" " /mol/nvram" preopen
+
+; SYSTEM-initializer
+
+
+\ -------------------------------------------------------------------------
+\ device tree fixing
+\ -------------------------------------------------------------------------
+
+\ add decode-address methods
+: (make-decodable) ( phandle -- )
+
+ dup " #address-cells" rot get-package-property 0= if
+ decode-int nip nip
+ over " decode-unit" rot find-method if 2drop else
+ ( save phandle ncells )
+
+ over active-package!
+ case
+ 1 of ['] parse-hex " decode-unit" is-xt-func endof
+ 3 of
+ " bus-range" active-package get-package-property 0= if
+ decode-int nip nip
+ ['] encode-unit-pci " encode-unit" is-xt-func
+ " decode-unit" is-func-begin
+ ['] (lit) , ,
+ ['] decode-unit-pci-bus ,
+ is-func-end
+ then
+ endof
+ endcase
+ then
+ then
+ drop
+;
+
+: tree-fixes ( -- )
+ active-package
+
+ iterate-tree-begin
+ begin ?dup while
+
+ dup (make-decodable)
+
+ iterate-tree
+ repeat
+
+ active-package!
+;
+
+\ use the tty interface if available
+: activate-tty-interface
+ " /mol/mol-tty" find-dev if drop
+ " /mol/mol-tty" " input-device" $setenv
+ " /mol/mol-tty" " output-device" $setenv
+ then
+;
+
+:noname
+ " keyboard" input
+; CONSOLE-IN-initializer
+
+
+\ -------------------------------------------------------------------------
+\ pre-booting
+\ -------------------------------------------------------------------------
+
+: update-chosen
+ " /chosen" find-device
+ stdin @ encode-int " stdin" property
+ stdout @ encode-int " stdout" property
+ device-end
+;
diff --git a/qemu/roms/openbios/arch/ppc/mol/mol.h b/qemu/roms/openbios/arch/ppc/mol/mol.h
new file mode 100644
index 000000000..cea15a350
--- /dev/null
+++ b/qemu/roms/openbios/arch/ppc/mol/mol.h
@@ -0,0 +1,44 @@
+/*
+ * Creation Date: <2003/12/20 00:20:12 samuel>
+ * Time-stamp: <2004/03/27 01:52:50 samuel>
+ *
+ * <mol.h>
+ *
+ *
+ *
+ * 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-blk.c>
+ *
+ * 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; i<n; ) {
+ char buf[4096];
+ int m = MIN( n-i, sizeof(buf)/512 );
+
+ if( OSI_ABlkSyncRead(pb->channel, 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>
+ *
+ * <osi-scsi.c>
+ *
+ * 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>
+ *
+ * <prom.c>
+ *
+ * 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>
+ *
+ * <prom.h>
+ *
+ * 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.c>
+ *
+ * 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; cnt<len; ) {
+ char buf[2048];
+ int n = MIN( len-cnt, sizeof(buf) );
+
+ n = PseudoFSRead( pb->fd, 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>
+ *
+ * <tree.c>
+ *
+ * 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<len; i++ ) {
+ phandle_t ch_ph;
+ int ch_acells, ch_icells;
+
+ i += acells + icells;
+ if( !(ch_ph=translate_molph(map[i])) )
+ break;
+ map[i] = (int)ch_ph;
+ ch_acells = get_int_property(ch_ph, "#address-cells", NULL);
+ ch_icells = get_int_property(ch_ph, "#interrupt-cells", NULL);
+ i += ch_acells + icells;
+ }
+ if( i != len )
+ printk("interrupt map fixing failure\n");
+ }
+ }
+ /* delete MOL,phandle properties */
+ for( ph=0; (ph=dt_iterate(ph)) ; ) {
+ push_str("MOL,phandle");
+ PUSH_ph(ph);
+ fword("(delete-property)");
+ }
+ fword("device-end");
+}
+
+void
+devtree_init( void )
+{
+ activate_device("/");
+ copy_node( prom_peer(0) );
+ fix_phandles();
+ fword("tree-fixes");
+}
diff --git a/qemu/roms/openbios/arch/ppc/mol/tree.fs b/qemu/roms/openbios/arch/ppc/mol/tree.fs
new file mode 100644
index 000000000..228163ffc
--- /dev/null
+++ b/qemu/roms/openbios/arch/ppc/mol/tree.fs
@@ -0,0 +1,103 @@
+
+: int-property ( val name -- )
+ rot encode-int 2swap property
+;
+
+
+\ -------------------------------------------------------------
+\ device-tree
+\ -------------------------------------------------------------
+
+" /" find-device
+
+ " device-tree" device-name
+ " bootrom" device-type
+
+\ -------------------------------------------------------------
+\ /memory
+\ -------------------------------------------------------------
+
+new-device
+ " memory" device-name
+ \ 12230 encode-int " reg" property
+ external
+ : open true ;
+ : close ;
+ \ claim ( phys size align -- base )
+ \ release ( phys size -- )
+finish-device
+
+\ -------------------------------------------------------------
+\ /mol/
+\ -------------------------------------------------------------
+
+new-device
+ " mol" device-name
+ 1 " #address-cells" int-property
+ 0 " #size-cells" int-property
+
+ external
+ : open true ;
+ : close ;
+
+new-device
+ " test" device-name
+
+ external
+ : open
+ ." /mol/test opened" cr
+ " argument-str" " ipose" find-package drop interpose
+ true
+ ;
+finish-device
+finish-device
+
+\ -------------------------------------------------------------
+\ /cpus/
+\ -------------------------------------------------------------
+
+new-device
+ " cpus" device-name
+ 1 " #address-cells" int-property
+ 0 " #size-cells" int-property
+
+ external
+ : open true ;
+ : close ;
+ : decode-unit parse-hex ;
+
+finish-device
+
+\ -------------------------------------------------------------
+\ /packages
+\ -------------------------------------------------------------
+
+" /packages" find-device
+
+ " packages" device-name
+ external
+ \ allow packages to be opened with open-dev
+ : open true ;
+ : close ;
+
+\ /packages/mol-stdout
+new-device
+ " mol-stdout" device-name
+ external
+ : open true ;
+ : close ;
+ : write ( addr len -- actual )
+ dup -rot type
+ ;
+finish-device
+
+\ XXXXXXXXXXXXXXXXXXXXXXX TESTING
+" /" find-device
+new-device
+ " test" device-name
+finish-device
+
+\ -------------------------------------------------------------
+\ The END
+\ -------------------------------------------------------------
+device-end