Fix TCL error in gdb.python/py-format-string.exp.
[deliverable/binutils-gdb.git] / sim / ppc / emul_chirp.c
index 9eb3a4e15aa9b0789182bab2b07120df1c368198..f326410b060ddb16922261eaf967402d88504cbd 100644 (file)
@@ -1,21 +1,20 @@
 /*  This file is part of the program psim.
 
 /*  This file is part of the program psim.
 
-    Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+    Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney
 
     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
 
     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; either version 2 of the License, or
+    the Free Software Foundation; either version 3 of the License, or
     (at your option) any later version.
 
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
     (at your option) any later version.
 
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
+
     You should have received a copy of the GNU General Public License
     You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+
     */
 
 
     */
 
 
@@ -28,8 +27,6 @@
 #include "emul_generic.h"
 #include "emul_chirp.h"
 
 #include "emul_generic.h"
 #include "emul_chirp.h"
 
-#include "cap.h"
-
 #ifdef HAVE_STRING_H
 #include <string.h>
 #else
 #ifdef HAVE_STRING_H
 #include <string.h>
 #else
 #endif
 #endif
 
 #endif
 #endif
 
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #include <unistd.h>
+#endif
 
 #ifndef STATIC_INLINE_EMUL_CHIRP
 #define STATIC_INLINE_EMUL_CHIRP STATIC_INLINE
 #endif
 
 
 
 #ifndef STATIC_INLINE_EMUL_CHIRP
 #define STATIC_INLINE_EMUL_CHIRP STATIC_INLINE
 #endif
 
 
+/* EMULATION
+
+
+   OpenFirmware - IEEE Standard for Boot (Initialization
+   Configuration) Firmware.
+
+
+   DESCRIPTION
+
+
+   BUGS
+
+   
+   This code assumes that the memory node has #address-cells and
+   #size-cells set to one.  For future implementations, this may not
+   be the case.
+
+   */
+
+
+
+
 /* Descriptor of the open boot services being emulated */
 
 typedef int (chirp_handler)
      (os_emul_data *data,
       cpu *processor,
       unsigned_word cia);
 /* Descriptor of the open boot services being emulated */
 
 typedef int (chirp_handler)
      (os_emul_data *data,
       cpu *processor,
       unsigned_word cia);
+
 typedef struct _chirp_services {
   const char *name;
   chirp_handler *handler;
 typedef struct _chirp_services {
   const char *name;
   chirp_handler *handler;
@@ -61,53 +83,127 @@ typedef struct _chirp_services {
    request or waiting on a client callback */
 typedef enum {
   serving,
    request or waiting on a client callback */
 typedef enum {
   serving,
+  emulating,
   faulting,
   faulting,
-  catching,
 } chirp_emul_state;
 
 struct _os_emul_data {
   chirp_emul_state state;
   unsigned_word return_address;
   unsigned_word arguments;
 } chirp_emul_state;
 
 struct _os_emul_data {
   chirp_emul_state state;
   unsigned_word return_address;
   unsigned_word arguments;
+  unsigned_word n_args;
+  unsigned_word n_returns;
   chirp_services *service;
   chirp_services *service;
-  unsigned_word serving_instruction_ea;
-  unsigned_word catching_instruction_ea;
-  cap *phandles;
   device *root;
   chirp_services *services;
   device *root;
   chirp_services *services;
+  /* configuration */
+  unsigned_word memory_size;
+  unsigned_word real_base;
+  unsigned_word real_size;
+  unsigned_word virt_base;
+  unsigned_word virt_size;
+  int real_mode;
+  int little_endian;
+  int floating_point_available;
+  int interrupt_prefix;
+  unsigned_word load_base;
+  /* hash table */
+  unsigned_word nr_page_table_entry_groups;
+  unsigned_word htab_offset;
+  unsigned_word htab_ra;
+  unsigned_word htab_va;
+  unsigned_word sizeof_htab;
+  /* virtual address of htab */
+  unsigned_word stack_offset;
+  unsigned_word stack_ra;
+  unsigned_word stack_va;
+  unsigned_word sizeof_stack;
+  /* addresses of emulation instructions virtual/real */
+  unsigned_word code_offset;
+  unsigned_word code_va;
+  unsigned_word code_ra;
+  unsigned_word sizeof_code;
+  unsigned_word code_client_va;
+  unsigned_word code_client_ra;
+  unsigned_word code_callback_va;
+  unsigned_word code_callback_ra;
+  unsigned_word code_loop_va;
+  unsigned_word code_loop_ra;
 };
 
 
 };
 
 
-/* Read in the argument list and make the most basic check that number
-   of argumnets are consistent with what was expected */
+/* returns the name of the corresponding Ihandle */
+static const char *
+ihandle_name(device_instance *ihandle)
+{
+  if (ihandle == NULL)
+    return "";
+  else
+    return device_name(device_instance_device(ihandle));
+}
+
+
+
+/* Read/write the argument list making certain that all values are
+   converted to/from host byte order.
+
+   In the below only n_args+n_returns is read/written */
 
 static int
 
 static int
-chirp_read_args(void *args,
-               int sizeof_args,
-               int n_args,
-               int n_returns,
-               os_emul_data *data,
-               cpu *processor,
-               unsigned_word cia)
+chirp_read_t2h_args(void *args,
+                   int sizeof_args,
+                   int n_args,
+                   int n_returns,
+                   os_emul_data *data,
+                   cpu *processor,
+                   unsigned_word cia)
 {
 {
-  struct base_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
-  } *base;
-  emul_read_buffer(args, data->arguments,
-                  sizeof_args,
-                  processor, cia);
-  base = (struct base_args*)args;
-  if (T2H_4(base->n_args) != n_args || T2H_4(base->n_returns) != n_returns) {
-    TRACE(trace_os_emul, ("invalid nr of args - n_args=%ld, n_returns=%ld\n",
-                         (long)T2H_4(base->n_args),
-                         (long)T2H_4(base->n_returns)));
+  unsigned_cell *words;
+  int i;
+  /* check against the number of arguments specified by the client
+     program */
+  if ((n_args >= 0 && data->n_args != n_args)
+      || (n_returns >= 0 && data->n_returns != n_returns)) {
+    TRACE(trace_os_emul, ("%s - invalid nr of args - n_args=%ld, n_returns=%ld\n",
+                         data->service->name,
+                         (long)data->n_args,
+                         (long)data->n_returns));
     return -1;
   }
     return -1;
   }
+  /* check that there is enough space */
+  if (sizeof(unsigned_cell) * (data->n_args + data->n_returns) > sizeof_args)
+    return -1;
+  /* bring in the data */
+  memset(args, 0, sizeof_args);
+  emul_read_buffer(args, data->arguments + 3 * sizeof(unsigned_cell),
+                  sizeof(unsigned_cell) * (data->n_args + data->n_returns),
+                  processor, cia);
+  /* convert all words to host format */
+  words = args;
+  for (i = 0; i < (sizeof_args / sizeof(unsigned_cell)); i++)
+    words[i] = T2H_cell(words[i]);
   return 0;
 }
 
   return 0;
 }
 
+static void
+chirp_write_h2t_args(void *args,
+                    int sizeof_args,
+                    os_emul_data *data,
+                    cpu *processor,
+                    unsigned_word cia)
+{
+  int i;
+  unsigned_cell *words;
+  /* convert to target everything */
+  words = args;
+  for (i = 0; i < (sizeof_args / sizeof(unsigned_cell)); i++)
+    words[i] = H2T_cell(words[i]);
+  /* bring in the data */
+  emul_write_buffer(args, data->arguments + 3 * sizeof(unsigned_cell),
+                   sizeof(unsigned_cell) * (data->n_args + data->n_returns),
+                   processor, cia);
+}
+
 
 /* OpenBoot emulation functions */
 
 
 /* OpenBoot emulation functions */
 
@@ -119,23 +215,21 @@ chirp_emul_test(os_emul_data *data,
                unsigned_word cia)
 {
   struct test_args {
                unsigned_word cia)
 {
   struct test_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*in*/
-    unsigned32 name; /*string*/
+    unsigned_cell name; /*string*/
     /*out*/
     /*out*/
-    unsigned32 missing;
+    unsigned_cell missing;
   } args;
   char name[32];
   } args;
   char name[32];
-  chirp_services *service = data->services;
+  chirp_services *service = NULL;
   /* read in the arguments */
   /* read in the arguments */
-  if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
+  if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
     return -1;
     return -1;
-  emul_read_string(name, T2H_4(args.name), sizeof(name),
+  emul_read_string(name, args.name, sizeof(name),
                   processor, cia);
   TRACE(trace_os_emul, ("test - in - name=`%s'\n", name));
   /* see if we know about the service */
                   processor, cia);
   TRACE(trace_os_emul, ("test - in - name=`%s'\n", name));
   /* see if we know about the service */
+  service = data->services;
   while (service->name != NULL && strcmp(service->name, name) != 0) {
     service++;
   }
   while (service->name != NULL && strcmp(service->name, name) != 0) {
     service++;
   }
@@ -146,9 +240,10 @@ chirp_emul_test(os_emul_data *data,
   /* write the arguments back out */
   TRACE(trace_os_emul, ("test - out - missing=%ld\n",
                        (long)args.missing));
   /* write the arguments back out */
   TRACE(trace_os_emul, ("test - out - missing=%ld\n",
                        (long)args.missing));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -161,45 +256,46 @@ chirp_emul_peer(os_emul_data *data,
                unsigned_word cia)
 {
   struct peer_args {
                unsigned_word cia)
 {
   struct peer_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*in*/
-    unsigned32 phandle;
+    unsigned_cell phandle;
     /*out*/
     /*out*/
-    unsigned32 sibling_phandle;
+    unsigned_cell sibling_phandle;
   } args;
   } args;
-  device *dev;
-  device *sibling_dev = NULL;
+  device *phandle;
+  device *sibling_phandle = NULL;
   /* read in the arguments */
   /* read in the arguments */
-  if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
+  if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
     return -1;
     return -1;
-  dev = cap_internal(data->phandles, args.phandle);
+  phandle = external_to_device(data->root, args.phandle);
   TRACE(trace_os_emul, ("peer - in - phandle=0x%lx(0x%lx`%s')\n",
   TRACE(trace_os_emul, ("peer - in - phandle=0x%lx(0x%lx`%s')\n",
-                       (unsigned long)T2H_4(args.phandle),
-                       (unsigned long)dev,
-                       (dev == NULL ? "" : device_name(dev))));
+                       (unsigned long)args.phandle,
+                       (unsigned long)phandle,
+                       (phandle == NULL ? "" : device_name(phandle))));
   /* find the peer */
   /* find the peer */
-  if (dev == NULL && args.phandle != 0)
-    return -1;
-  if (args.phandle == 0)
-    sibling_dev = data->root;
-  else
-    sibling_dev = device_sibling(dev);
-  if (sibling_dev == NULL)
-    args.sibling_phandle = 0;
-  else
-    args.sibling_phandle = cap_external(data->phandles, sibling_dev);
+  if (args.phandle == 0) {
+    sibling_phandle = data->root;
+    args.sibling_phandle = device_to_external(sibling_phandle);
+  }
+  else if (phandle == NULL) {
+    sibling_phandle = NULL;
+    args.sibling_phandle = -1;
+  }
+  else {
+    sibling_phandle = device_sibling(phandle);
+    if (sibling_phandle == NULL)
+      args.sibling_phandle = 0;
+    else
+      args.sibling_phandle = device_to_external(sibling_phandle);
+  }
   /* write the arguments back out */
   TRACE(trace_os_emul, ("peer - out - sibling_phandle=0x%lx(0x%lx`%s')\n",
   /* write the arguments back out */
   TRACE(trace_os_emul, ("peer - out - sibling_phandle=0x%lx(0x%lx`%s')\n",
-                       (unsigned long)T2H_4(args.sibling_phandle),
-                       (unsigned long)sibling_dev,
-                       (sibling_dev == NULL
-                        ? ""
-                        : device_name(sibling_dev))));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+                       (unsigned long)args.sibling_phandle,
+                       (unsigned long)sibling_phandle,
+                       (sibling_phandle == NULL ? "" : device_name(sibling_phandle))));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -209,40 +305,43 @@ chirp_emul_child(os_emul_data *data,
                 unsigned_word cia)
 {
   struct child_args {
                 unsigned_word cia)
 {
   struct child_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*in*/
-    unsigned32 phandle;
+    unsigned_cell phandle;
     /*out*/
     /*out*/
-    unsigned32 child_phandle;
+    unsigned_cell child_phandle;
   } args;
   } args;
-  device *dev;
-  device *child_dev;
+  device *phandle;
+  device *child_phandle;
   /* read the arguments in */
   /* read the arguments in */
-  if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
+  if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
     return -1;
     return -1;
-  dev = cap_internal(data->phandles, args.phandle);
+  phandle = external_to_device(data->root, args.phandle);
   TRACE(trace_os_emul, ("child - in - phandle=0x%lx(0x%lx`%s')\n",
   TRACE(trace_os_emul, ("child - in - phandle=0x%lx(0x%lx`%s')\n",
-                       (unsigned long)T2H_4(args.phandle),
-                       (unsigned long)dev,
-                       (dev == NULL ? "" : device_name(dev))));
+                       (unsigned long)args.phandle,
+                       (unsigned long)phandle,
+                       (phandle == NULL ? "" : device_name(phandle))));
   /* find a child */
   /* find a child */
-  if (dev == (device*)0)
-    return -1;
-  child_dev = device_child(dev);
-  if (child_dev == NULL)
-    args.child_phandle = 0;
-  else
-    args.child_phandle = cap_external(data->phandles, child_dev);
+  if (args.phandle == 0
+      || phandle == NULL) {
+    child_phandle = NULL;
+    args.child_phandle = -1;
+  }
+  else {
+    child_phandle = device_child(phandle);
+    if (child_phandle == NULL)
+      args.child_phandle = 0;
+    else
+      args.child_phandle = device_to_external(child_phandle);
+  }
   /* write the result out */
   TRACE(trace_os_emul, ("child - out - child_phandle=0x%lx(0x%lx`%s')\n",
   /* write the result out */
   TRACE(trace_os_emul, ("child - out - child_phandle=0x%lx(0x%lx`%s')\n",
-                       (unsigned long)T2H_4(args.child_phandle),
-                       (unsigned long)child_dev,
-                       (child_dev == NULL ? "" : device_name(child_dev))));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+                       (unsigned long)args.child_phandle,
+                       (unsigned long)child_phandle,
+                       (child_phandle == NULL ? "" : device_name(child_phandle))));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -252,40 +351,43 @@ chirp_emul_parent(os_emul_data *data,
                  unsigned_word cia)
 {
   struct parent_args {
                  unsigned_word cia)
 {
   struct parent_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*in*/
-    unsigned32 phandle;
+    unsigned_cell phandle;
     /*out*/
     /*out*/
-    unsigned32 parent_phandle;
+    unsigned_cell parent_phandle;
   } args;
   } args;
-  device *dev;
-  device *parent_dev;
+  device *phandle;
+  device *parent_phandle;
   /* read the args in */
   /* read the args in */
-  if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
+  if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
     return -1;
     return -1;
-  dev = cap_internal(data->phandles, args.phandle);
+  phandle = external_to_device(data->root, args.phandle);
   TRACE(trace_os_emul, ("parent - in - phandle=0x%lx(0x%lx`%s')\n",
   TRACE(trace_os_emul, ("parent - in - phandle=0x%lx(0x%lx`%s')\n",
-                       (unsigned long)T2H_4(args.phandle),
-                       (unsigned long)dev,
-                       (dev == NULL ? "" : device_name(dev))));
+                       (unsigned long)args.phandle,
+                       (unsigned long)phandle,
+                       (phandle == NULL ? "" : device_name(phandle))));
   /* find a parent */
   /* find a parent */
-  if (dev == (device*)0)
-    return -1;
-  parent_dev = device_parent(dev);
-  if (parent_dev == NULL)
-    args.parent_phandle = 0;
-  else
-    args.parent_phandle = cap_external(data->phandles, parent_dev);
+  if (args.phandle == 0
+      || phandle == NULL) {
+    parent_phandle = NULL;
+    args.parent_phandle = -1;
+  }
+  else {
+    parent_phandle = device_parent(phandle);
+    if (parent_phandle == NULL)
+      args.parent_phandle = 0;
+    else
+      args.parent_phandle = device_to_external(parent_phandle);
+  }
   /* return the result */
   TRACE(trace_os_emul, ("parent - out - parent_phandle=0x%lx(0x%lx`%s')\n",
   /* return the result */
   TRACE(trace_os_emul, ("parent - out - parent_phandle=0x%lx(0x%lx`%s')\n",
-                       (unsigned long)T2H_4(args.parent_phandle),
-                       (unsigned long)parent_dev,
-                       (parent_dev == NULL ? "" : device_name(parent_dev))));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+                       (unsigned long)args.parent_phandle,
+                       (unsigned long)parent_phandle,
+                       (parent_phandle == NULL ? "" : device_name(parent_phandle))));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -294,7 +396,40 @@ chirp_emul_instance_to_package(os_emul_data *data,
                               cpu *processor,
                               unsigned_word cia)
 {
                               cpu *processor,
                               unsigned_word cia)
 {
-  error("chirp: instance-to-package unimplemented\n");
+  struct instance_to_package_args {
+    /*in*/
+    unsigned_cell ihandle;
+    /*out*/
+    unsigned_cell phandle;
+  } args;
+  device_instance *ihandle;
+  device *phandle = NULL;
+  /* read the args in */
+  if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
+    return -1;
+  ihandle = external_to_device_instance(data->root, args.ihandle);
+  TRACE(trace_os_emul, ("instance-to-package - in - ihandle=0x%lx(0x%lx`%s')\n",
+                       (unsigned long)args.ihandle,
+                       (unsigned long)ihandle,
+                       ihandle_name(ihandle)));
+  /* find the corresponding phandle */
+  if (ihandle == NULL) {
+    phandle = NULL;
+    args.phandle = -1;
+  }
+  else {
+    phandle = device_instance_device(ihandle);
+    args.phandle = device_to_external(phandle);
+  }
+  /* return the result */
+  TRACE(trace_os_emul, ("instance-to-package - out - phandle=0x%lx(0x%lx`%s')\n",
+                       (unsigned long)args.phandle,
+                       (unsigned long)phandle,
+                       (phandle == NULL ? "" : device_name(phandle))));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -304,47 +439,48 @@ chirp_emul_getproplen(os_emul_data *data,
                      unsigned_word cia)
 {
   struct getproplen_args {
                      unsigned_word cia)
 {
   struct getproplen_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*in*/
-    unsigned32 phandle;
-    unsigned32 name;
+    unsigned_cell phandle;
+    unsigned_cell name;
     /*out*/
     /*out*/
-    unsigned32 proplen;
+    unsigned_cell proplen;
   } args;
   char name[32];
   } args;
   char name[32];
-  device *dev;
-  const device_property *prop;
+  device *phandle;
   /* read the args in */
   /* read the args in */
-  if (chirp_read_args(&args, sizeof(args), 2, 1, data, processor, cia))
-    return -1;
-  dev = cap_internal(data->phandles, args.phandle);
-  /* find our prop and get its length */
-  if (dev == (device*)0)
+  if (chirp_read_t2h_args(&args, sizeof(args), 2, 1, data, processor, cia))
     return -1;
     return -1;
+  phandle = external_to_device(data->root, args.phandle);
   emul_read_string(name,
   emul_read_string(name,
-                  T2H_4(args.name),
+                  args.name,
                   sizeof(name),
                   processor, cia);
   TRACE(trace_os_emul, ("getproplen - in - phandle=0x%lx(0x%lx`%s') name=`%s'\n",
                   sizeof(name),
                   processor, cia);
   TRACE(trace_os_emul, ("getproplen - in - phandle=0x%lx(0x%lx`%s') name=`%s'\n",
-                       (unsigned long)T2H_4(args.phandle),
-                       (unsigned long)dev,
-                       (dev == NULL ? "" : device_name(dev)),
+                       (unsigned long)args.phandle,
+                       (unsigned long)phandle,
+                       (phandle == NULL ? "" : device_name(phandle)),
                        name));
                        name));
-  prop = device_find_property(dev, name);
-  if (prop == (device_property*)0) {
+  /* find our prop and get its length */
+  if (args.phandle == 0
+      || phandle == NULL) {
     args.proplen = -1;
   }
   else {
     args.proplen = -1;
   }
   else {
-    args.proplen = H2T_4(prop->sizeof_array);
+    const device_property *prop = device_find_property(phandle, name);
+    if (prop == (device_property*)0) {
+      args.proplen = -1;
+    }
+    else {
+      args.proplen = prop->sizeof_array;
+    }
   }
   /* return the result */
   TRACE(trace_os_emul, ("getproplen - out - proplen=%ld\n",
   }
   /* return the result */
   TRACE(trace_os_emul, ("getproplen - out - proplen=%ld\n",
-                       (unsigned long)T2H_4(args.proplen)));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+                       (unsigned long)args.proplen));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -354,65 +490,77 @@ chirp_emul_getprop(os_emul_data *data,
                   unsigned_word cia)
 {
   struct getprop_args {
                   unsigned_word cia)
 {
   struct getprop_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*in*/
-    unsigned32 phandle;
-    unsigned32 name;
-    unsigned32 buf;
-    unsigned32 buflen;
+    unsigned_cell phandle;
+    unsigned_cell name;
+    unsigned_cell buf;
+    unsigned_cell buflen;
     /*out*/
     /*out*/
-    unsigned32 size;
+    unsigned_cell size;
   } args;
   char name[32];
   } args;
   char name[32];
-  device *dev;
-  const device_property *prop;
-  /* read in the args */
-  if (chirp_read_args(&args, sizeof(args), 4, 1, data, processor, cia))
+  device *phandle;
+  /* read in the args, the return is optional */
+  if (chirp_read_t2h_args(&args, sizeof(args), 4, -1, data, processor, cia))
     return -1;
     return -1;
-  dev = cap_internal(data->phandles, args.phandle);
+  phandle = external_to_device(data->root, args.phandle);
   emul_read_string(name,
   emul_read_string(name,
-                  T2H_4(args.name),
+                  args.name,
                   sizeof(name),
                   processor, cia);
   TRACE(trace_os_emul, ("getprop - in - phandle=0x%lx(0x%lx`%s') name=`%s' buf=0x%lx buflen=%ld\n",
                   sizeof(name),
                   processor, cia);
   TRACE(trace_os_emul, ("getprop - in - phandle=0x%lx(0x%lx`%s') name=`%s' buf=0x%lx buflen=%ld\n",
-                       (unsigned long)T2H_4(args.phandle),
-                       (unsigned long)dev,
-                       (dev == NULL ? "" : device_name(dev)),
+                       (unsigned long)args.phandle,
+                       (unsigned long)phandle,
+                       (phandle == NULL ? "" : device_name(phandle)),
                        name,
                        name,
-                       (unsigned long)T2H_4(args.buf),
-                       (unsigned long)T2H_4(args.buflen)));
+                       (unsigned long)args.buf,
+                       (unsigned long)args.buflen));
   /* get the property */
   /* get the property */
-  if (dev == (device*)0)
-    return -1;
-  prop = device_find_property(dev, name);
-  if (prop == (device_property*)0) {
+  if (args.phandle == 0
+      || phandle == NULL) {
     args.size = -1;
   }
   else {
     args.size = -1;
   }
   else {
-    int size = T2H_4(args.buflen);
-    if (size > prop->sizeof_array)
-      size = prop->sizeof_array;
-    emul_write_buffer(prop->array, T2H_4(args.buf),
-                     size,
-                     processor, cia);
-    args.size = H2T_4(size);
-  }
-  switch (prop->type) {
-  case string_property:
-    TRACE(trace_os_emul, ("getprop - value=`%s' (string)\n",
-                         (char*)prop->array));
-    break;
-  default:
-    break;
+    const device_property *prop = device_find_property(phandle, name);
+    if (prop == NULL) {
+      args.size = -1;
+    }
+    else {
+      int size = args.buflen;
+      if (size > prop->sizeof_array)
+       size = prop->sizeof_array;
+      emul_write_buffer(prop->array, args.buf,
+                       size,
+                       processor, cia);
+      args.size = size;
+      switch (prop->type) {
+      case string_property:
+       TRACE(trace_os_emul, ("getprop - string `%s'\n",
+                             device_find_string_property(phandle, name)));
+       break;
+      case ihandle_property:
+       TRACE(trace_os_emul, ("getprop - ihandle=0x%lx(0x%lx`%s')\n",
+                             BE2H_cell(*(unsigned_cell*)prop->array),
+                             (unsigned long)device_find_ihandle_property(phandle, name),
+                             ihandle_name(device_find_ihandle_property(phandle, name))));
+       break;
+      default:
+       break;
+      }
+    }
   }
   /* write back the result */
   }
   /* write back the result */
-  TRACE(trace_os_emul, ("getprop - out - size=%ld\n",
-                       (unsigned long)T2H_4(args.size)));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+  if (data->n_returns == 0)
+    TRACE(trace_os_emul, ("getprop - out - size=%ld (not returned)\n",
+                         (unsigned long)args.size));
+  else {
+    TRACE(trace_os_emul, ("getprop - out - size=%ld\n",
+                         (unsigned long)args.size));
+    chirp_write_h2t_args(&args,
+                        sizeof(args),
+                        data,
+                        processor, cia);
+  }
   return 0;
 }
 
   return 0;
 }
 
@@ -421,25 +569,140 @@ chirp_emul_nextprop(os_emul_data *data,
                    cpu *processor,
                    unsigned_word cia)
 {
                    cpu *processor,
                    unsigned_word cia)
 {
-  error("chirp: nextprop not implemented\n");
+  struct nextprop_args {
+    /*in*/
+    unsigned_cell phandle;
+    unsigned_cell previous;
+    unsigned_cell buf;
+    /*out*/
+    unsigned_cell flag;
+  } args;
+  char previous[32];
+  device *phandle;
+  /* read in the args */
+  if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
+    return -1;
+  phandle = external_to_device(data->root, args.phandle);
+  if (args.previous != 0)
+    emul_read_string(previous,
+                    args.previous,
+                    sizeof(previous),
+                    processor, cia);
+  else
+    /* If previous is NULL, make it look like the empty string.  The
+       next property after the empty string is the first property.  */
+    strcpy (previous, "");
+  TRACE(trace_os_emul, ("nextprop - in - phandle=0x%lx(0x%lx`%s') previous=`%s' buf=0x%lx\n",
+                       (unsigned long)args.phandle,
+                       (unsigned long)phandle,
+                       (phandle == NULL ? "" : device_name(phandle)),
+                       previous,
+                       (unsigned long)args.buf));
+  /* find the next property */
+  if (args.phandle == 0
+      || phandle == NULL) {
+    args.flag = -1;
+  }
+  else {
+    const device_property *prev_prop = device_find_property(phandle, previous);
+    if (prev_prop == NULL) {
+      if (strcmp (previous, "") == 0)
+       args.flag = 0; /* No properties */
+      else
+       args.flag = -1; /* name invalid */
+    }
+    else {
+      const device_property *next_prop;
+      if (strcmp (previous, "") == 0) {
+       next_prop = prev_prop;  /* The first property.  */
+      }
+      else {
+       next_prop = device_next_property(prev_prop);
+      }
+      if (next_prop == NULL) {
+       args.flag = 0; /* last property */
+      }
+      else {
+       emul_write_buffer(next_prop->name, args.buf, strlen(next_prop->name),
+                         processor, cia);
+       TRACE(trace_os_emul, ("nextprop - name=`%s'\n", next_prop->name));
+       args.flag = 1; /* worked ok */
+      }
+    }
+  }
+  /* write back the result */
+  TRACE(trace_os_emul, ("nextprop - out - flag=%ld\n",
+                       (unsigned long)args.flag));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
+#if 0
 static int
 chirp_emul_setprop(os_emul_data *data,
                   cpu *processor,
                   unsigned_word cia)
 {
 static int
 chirp_emul_setprop(os_emul_data *data,
                   cpu *processor,
                   unsigned_word cia)
 {
-  error("chirp: setprop not implemented\n");
+  error("chirp: setprop method not implemented\n");
   return 0;
 }
   return 0;
 }
+#endif
 
 static int
 chirp_emul_canon(os_emul_data *data,
 
 static int
 chirp_emul_canon(os_emul_data *data,
-                 cpu *processor,
-                 unsigned_word cia)
+                cpu *processor,
+                unsigned_word cia)
 {
 {
-  error("chirp: canon not implemented\n");
+  struct canon_args {
+    /*in*/
+    unsigned_cell device_specifier;
+    unsigned_cell buf;
+    unsigned_cell buflen;
+    /*out*/
+    unsigned_cell length;
+  } args;
+  char device_specifier[1024];
+  device *phandle;
+  const char *path;
+  int length;
+  /* read in the args */
+  if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
+    return -1;
+  emul_read_string(device_specifier,
+                  args.device_specifier,
+                  sizeof(device_specifier),
+                  processor, cia);
+  TRACE(trace_os_emul, ("canon - in - device_specifier=`%s' buf=0x%lx buflen=%lx\n",
+                       device_specifier,
+                       (unsigned long)args.buf,
+                       (unsigned long)args.buflen));
+  /* canon the name */
+  phandle = tree_find_device(data->root, device_specifier);
+  if (phandle == NULL) {
+    length = -1;
+    path = "";
+    args.length = -1;
+  }
+  else {
+    path = device_path(phandle);
+    length = strlen(path);
+    if (length >= args.buflen)
+      length = args.buflen - 1;
+    emul_write_buffer(path, args.buf, length,
+                     processor, cia);
+    args.length = length;
+  }
+  /* write back the result */
+  TRACE(trace_os_emul, ("canon - out - length=%ld buf=`%s'\n",
+                       (unsigned long)args.length,
+                       path));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -449,40 +712,37 @@ chirp_emul_finddevice(os_emul_data *data,
                      unsigned_word cia)
 {
   struct finddevice_args {
                      unsigned_word cia)
 {
   struct finddevice_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*in*/
-    unsigned32 device_specifier;
+    unsigned_cell device_specifier;
     /*out*/
     /*out*/
-    unsigned32 phandle;
+    unsigned_cell phandle;
   } args;
   char device_specifier[1024];
   } args;
   char device_specifier[1024];
-  device *dev;
+  device *phandle;
   /* get the args */
   /* get the args */
-  if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
+  if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
     return -1;
   emul_read_string(device_specifier,
     return -1;
   emul_read_string(device_specifier,
-                  T2H_4(args.device_specifier),
+                  args.device_specifier,
                   sizeof(device_specifier),
                   processor, cia);
   TRACE(trace_os_emul, ("finddevice - in - device_specifier=`%s'\n",
                        device_specifier));
   /* find the device */
                   sizeof(device_specifier),
                   processor, cia);
   TRACE(trace_os_emul, ("finddevice - in - device_specifier=`%s'\n",
                        device_specifier));
   /* find the device */
-  dev = device_tree_find_device(data->root,
-                               device_specifier);
-  if (dev == (device*)0)
+  phandle = tree_find_device(data->root, device_specifier);
+  if (phandle == NULL)
     args.phandle = -1;
   else
     args.phandle = -1;
   else
-    args.phandle = cap_external(data->phandles, dev);
+    args.phandle = device_to_external(phandle);
   /* return its phandle */
   TRACE(trace_os_emul, ("finddevice - out - phandle=0x%lx(0x%lx`%s')\n",
   /* return its phandle */
   TRACE(trace_os_emul, ("finddevice - out - phandle=0x%lx(0x%lx`%s')\n",
-                       (unsigned long)T2H_4(args.phandle),
-                       (unsigned long)dev,
-                       (dev == NULL ? "" : device_name(dev))));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+                       (unsigned long)args.phandle,
+                       (unsigned long)phandle,
+                       (phandle == NULL ? "" : device_name(phandle))));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -491,25 +751,162 @@ chirp_emul_instance_to_path(os_emul_data *data,
                            cpu *processor,
                            unsigned_word cia)
 {
                            cpu *processor,
                            unsigned_word cia)
 {
-  error("chirp: instance_to_path not implemented\n");
+  struct instance_to_path_args {
+    /*in*/
+    unsigned_cell ihandle;
+    unsigned_cell buf;
+    unsigned_cell buflen;
+    /*out*/
+    unsigned_cell length;
+  } args;
+  device_instance *ihandle;
+  const char *path;
+  int length;
+  /* get the args */
+  if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
+    return -1;
+  ihandle = external_to_device_instance(data->root, args.ihandle);
+  TRACE(trace_os_emul, ("instance-to-path - in - ihandle=0x%lx(0x%lx`%s') buf=0x%lx buflen=%ld\n",
+                       (unsigned long)args.ihandle,
+                       (unsigned long)ihandle,
+                       ihandle_name(ihandle),
+                       (unsigned long)args.buf,
+                       (unsigned long)args.buflen));
+  /* get the devices name */
+  if (ihandle == NULL) {
+    args.length = -1;
+    path = "(null)";
+  }
+  else {
+    path = device_instance_path(ihandle);
+    length = strlen(path);
+    if (length >= args.buflen)
+      length = args.buflen - 1;
+    emul_write_buffer(path, args.buf, length,
+                     processor, cia);
+    args.length = length;
+  }
+  /* return its phandle */
+  TRACE(trace_os_emul, ("instance-to-path - out - length=%ld buf=`%s')\n",
+                       (unsigned long)args.length,
+                       path));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
 static int
 chirp_emul_package_to_path(os_emul_data *data,
   return 0;
 }
 
 static int
 chirp_emul_package_to_path(os_emul_data *data,
-                           cpu *processor,
-                           unsigned_word cia)
+                          cpu *processor,
+                          unsigned_word cia)
 {
 {
-  error("chirp: package_to_path not implemented\n");
+  struct package_to_path_args {
+    /*in*/
+    unsigned_cell phandle;
+    unsigned_cell buf;
+    unsigned_cell buflen;
+    /*out*/
+    unsigned_cell length;
+  } args;
+  device *phandle;
+  const char *path;
+  /* get the args */
+  if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
+    return -1;
+  phandle = external_to_device(data->root, args.phandle);
+  TRACE(trace_os_emul, ("package-to-path - in - phandle=0x%lx(0x%lx`%s') buf=0x%lx buflen=%ld\n",
+                       (unsigned long)args.phandle,
+                       (unsigned long)phandle,
+                       (phandle == NULL ? "" : device_name(phandle)),
+                       (unsigned long)args.buf,
+                       (unsigned long)args.buflen));
+  /* get the devices name */
+  if (phandle == NULL) {
+    args.length = -1;
+    path = "(null)";
+  }
+  else {
+    int length;
+    path = device_path(phandle);
+    length = strlen(path);
+    if (length >= args.buflen)
+      length = args.buflen - 1;
+    emul_write_buffer(path, args.buf, length,
+                     processor, cia);
+    args.length = length;
+  }
+  /* return its phandle */
+  TRACE(trace_os_emul, ("package-to-path - out - length=%ld buf=`%s')\n",
+                       (unsigned long)args.length,
+                       path));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
 static int
 chirp_emul_call_method(os_emul_data *data,
   return 0;
 }
 
 static int
 chirp_emul_call_method(os_emul_data *data,
-                           cpu *processor,
-                           unsigned_word cia)
+                      cpu *processor,
+                      unsigned_word cia)
 {
 {
-  error("chirp: call-method implemented\n");
+  struct call_method_args {
+    /*in*/
+    unsigned_cell method;
+    unsigned_cell ihandle;
+    /*in/out*/
+    unsigned_cell stack[13]; /*6in + 6out + catch */
+  } args;
+  char method[32];
+  device_instance *ihandle;
+  /* some useful info about our mini stack */
+  int n_stack_args;
+  int n_stack_returns;
+  int stack_catch_result;
+  int stack_returns;
+  /* read the args */
+  if (chirp_read_t2h_args(&args, sizeof(args), -1, -1, data, processor, cia))
+    return -1;
+  emul_read_string(method,
+                  args.method,
+                  sizeof(method),
+                  processor, cia);
+  ihandle = external_to_device_instance(data->root, args.ihandle);
+  n_stack_args = data->n_args - 2;
+  n_stack_returns = data->n_returns - 1;
+  stack_catch_result = n_stack_args;
+  stack_returns = stack_catch_result + 1;
+  TRACE(trace_os_emul, ("call-method - in - n_args=%ld n_returns=%ld method=`%s' ihandle=0x%lx(0x%lx`%s')\n",
+                       (unsigned long)data->n_args,
+                       (unsigned long)data->n_returns,
+                       method,
+                       (unsigned long)args.ihandle,
+                       (unsigned long)ihandle,
+                       ihandle_name(ihandle)));
+  /* see if we can emulate this method */
+  if (ihandle == NULL) {
+    /* OpenFirmware doesn't define this error */
+    error("chirp: invalid ihandle passed to call-method method");
+  }
+  else {
+    args.stack[stack_catch_result] =
+      device_instance_call_method(ihandle,
+                                 method,
+                                 n_stack_args,
+                                 &args.stack[0],
+                                 n_stack_returns,
+                                 &args.stack[stack_returns]);
+  }
+  /* finished */
+  TRACE(trace_os_emul, ("call-method - out - catch-result=%ld\n",
+                       (unsigned long)args.stack[stack_catch_result]));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -522,33 +919,37 @@ chirp_emul_open(os_emul_data *data,
                unsigned_word cia)
 {
   struct open_args {
                unsigned_word cia)
 {
   struct open_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*in*/
-    unsigned32 device_specifier;
+    unsigned_cell device_specifier;
     /*out*/
     /*out*/
-    unsigned32 ihandle;
+    unsigned_cell ihandle;
   } args;
   } args;
-  char name[1024];
+  char device_specifier[1024];
+  device_instance *ihandle;
   /* read the args */
   /* read the args */
-  if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
+  if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
     return -1;
     return -1;
-  emul_read_string(name,
-                  T2H_4(args.device_specifier),
-                  sizeof(name),
+  emul_read_string(device_specifier,
+                  args.device_specifier,
+                  sizeof(device_specifier),
                   processor, cia);
   TRACE(trace_os_emul, ("open - in - device_specifier=`%s'\n",
                   processor, cia);
   TRACE(trace_os_emul, ("open - in - device_specifier=`%s'\n",
-                       name));
+                       device_specifier));
   /* open the device */
   /* open the device */
-  printf_filtered("OpenBoot - open unimplemented for %s\n", name);
-  args.ihandle = -1;
+  ihandle = tree_instance(data->root, device_specifier);
+  if (ihandle == NULL)
+    args.ihandle = -1;
+  else
+    args.ihandle = device_instance_to_external(ihandle);
   /* return the ihandle result */
   /* return the ihandle result */
-  TRACE(trace_os_emul, ("open - out - ihandle=0x%lx\n",
-                       (unsigned long)T2H_4(args.ihandle)));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+  TRACE(trace_os_emul, ("open - out - ihandle=0x%lx(0x%lx`%s')\n",
+                       (unsigned long)args.ihandle,
+                       (unsigned long)ihandle,
+                       ihandle_name(ihandle)));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -557,7 +958,34 @@ chirp_emul_close(os_emul_data *data,
                 cpu *processor,
                 unsigned_word cia)
 {
                 cpu *processor,
                 unsigned_word cia)
 {
-  error("chirp: close not implemented\n");
+  struct close_args {
+    /*in*/
+    unsigned_cell ihandle;
+    /*out*/
+  } args;
+  device_instance *ihandle;
+  /* read the args */
+  if (chirp_read_t2h_args(&args, sizeof(args), 1, 0, data, processor, cia))
+    return -1;
+  ihandle = external_to_device_instance(data->root, args.ihandle);
+  TRACE(trace_os_emul, ("close - in - ihandle=0x%lx(0x%lx`%s')\n",
+                       (unsigned long)args.ihandle,
+                       (unsigned long)ihandle,
+                       ihandle_name(ihandle)));
+  /* close the device */
+  if (ihandle == NULL) {
+    /* OpenFirmware doesn't define this error */
+    error("chirp: invalid ihandle passed to close method");
+  }
+  else {
+    device_instance_delete(ihandle);
+  }
+  /* return the ihandle result */
+  TRACE(trace_os_emul, ("close - out\n"));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -567,94 +995,135 @@ chirp_emul_read(os_emul_data *data,
                unsigned_word cia)
 {
   struct read_args {
                unsigned_word cia)
 {
   struct read_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*in*/
-    unsigned32 ihandle;
-    unsigned32 addr;
-    unsigned32 len;
+    unsigned_cell ihandle;
+    unsigned_cell addr;
+    unsigned_cell len;
     /*out*/
     /*out*/
-    unsigned32 actual;
+    unsigned_cell actual;
   } args;
   char buf[1024];
   } args;
   char buf[1024];
-  int actual;
+  device_instance *ihandle;
   /* read the args */
   /* read the args */
-  if (chirp_read_args(&args, sizeof(args), 3, 1, data, processor, cia))
+  if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
     return -1;
     return -1;
-  TRACE(trace_os_emul, ("read - in - ihandle=0x%lx addr=0x%lx len=%ld\n",
+  ihandle = external_to_device_instance(data->root, args.ihandle);
+  TRACE(trace_os_emul, ("read - in - ihandle=0x%lx(0x%lx`%s') addr=0x%lx len=%ld\n",
                        (unsigned long)args.ihandle,
                        (unsigned long)args.ihandle,
-                       (unsigned long)T2H_4(args.addr),
-                       (unsigned long)T2H_4(args.len)));
-  /* do the read */
-  actual = T2H_4(args.len);
-  if (actual >= sizeof(buf))
-    actual = sizeof(buf) - 1;
-  actual = read(BE2H_4(args.ihandle), buf, actual);
-  if (actual >= 0) {
-    emul_write_buffer(buf,
-                     T2H_4(args.addr),
-                     actual,
-                     processor, cia);
-    args.actual = H2T_4(actual);
-    buf[actual] = '\0';
+                       (unsigned long)ihandle,
+                       ihandle_name(ihandle),
+                       (unsigned long)args.addr,
+                       (unsigned long)args.len));
+  if (ihandle == NULL) {
+    /* OpenFirmware doesn't define this error */
+    error("chirp: invalid ihandle passed to read method");
   }
   else {
   }
   else {
-    args.actual = 0;
+    /* do the reads */
+    int actual = 0;
+    while (actual < args.len) {
+      int remaining = args.len - actual;
+      int to_read = (remaining <= sizeof(buf) ? remaining : sizeof(buf));
+      int nr_read = device_instance_read(ihandle, buf, to_read);
+      if (nr_read < 0) {
+       actual = nr_read; /* the error */
+       break;
+      }
+      else if (nr_read == 0) {
+       break;
+      }
+      emul_write_buffer(buf,
+                       args.addr + actual,
+                       nr_read,
+                       processor, cia);
+      actual += nr_read;
+    }
+    if (actual >= 0) {
+      args.actual = actual;
+      if (actual < sizeof(buf))
+       buf[actual] = '\0';
+      else
+       buf[sizeof(buf) - 1] = '\0';
+    }
+    else {
+      switch (actual) {
+      case sim_io_eof:
+       args.actual = 0;
+       break;
+      case sim_io_not_ready:
+       ASSERT(sim_io_not_ready == -2);
+       args.actual = sim_io_not_ready;
+       break;
+      default:
+       error("Bad error value %ld", (long)actual);
+       break;
+      }
+    }
   }
   /* return the result */
   TRACE(trace_os_emul, ("read - out - actual=%ld `%s'\n",
   }
   /* return the result */
   TRACE(trace_os_emul, ("read - out - actual=%ld `%s'\n",
-                       (long)T2H_4(args.actual),
-                       (actual >= 0 ? buf : "")));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+                       (long)args.actual,
+                       ((args.actual > 0 && args.actual < sizeof(buf)) ? buf : "")
+                       ));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
 static int
 chirp_emul_write(os_emul_data *data,
   return 0;
 }
 
 static int
 chirp_emul_write(os_emul_data *data,
-               cpu *processor,
-               unsigned_word cia)
+                cpu *processor,
+                unsigned_word cia)
 {
   struct write_args {
 {
   struct write_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*in*/
-    unsigned32 ihandle;
-    unsigned32 addr;
-    unsigned32 len;
+    unsigned_cell ihandle;
+    unsigned_cell addr;
+    unsigned_cell len;
     /*out*/
     /*out*/
-    unsigned32 actual;
+    unsigned_cell actual;
   } args;
   char buf[1024];
   } args;
   char buf[1024];
+  device_instance *ihandle;
   int actual;
   /* get the args */
   int actual;
   /* get the args */
-  if (chirp_read_args(&args, sizeof(args), 3, 1, data, processor, cia))
+  if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
     return -1;
     return -1;
-  actual = T2H_4(args.len);
+  actual = args.len;
   if (actual >= sizeof(buf))
     actual = sizeof(buf) - 1;
   emul_read_buffer(buf,
   if (actual >= sizeof(buf))
     actual = sizeof(buf) - 1;
   emul_read_buffer(buf,
-                  T2H_4(args.addr),
+                  args.addr,
                   actual,
                   processor, cia);
   buf[actual] = '\0';
                   actual,
                   processor, cia);
   buf[actual] = '\0';
-  TRACE(trace_os_emul, ("write - in - ihandle=0x%lx `%s' (%ld)\n",
-                       (unsigned long)args.ihandle, buf, (long)actual));
-  /* write it out */
-  actual = write(BE2H_4(args.ihandle), buf, actual);
-  if (actual < 0)
-    args.actual = 0;
-  else
-    args.actual = H2T_4(actual);
+  ihandle = external_to_device_instance(data->root, args.ihandle);
+  TRACE(trace_os_emul, ("write - in - ihandle=0x%lx(0x%lx`%s') `%s' (%ld)\n",
+                       (unsigned long)args.ihandle,
+                       (unsigned long)ihandle,
+                       ihandle_name(ihandle),
+                       buf, (long)actual));
+  if (ihandle == NULL) {
+    /* OpenFirmware doesn't define this error */
+    error("chirp: invalid ihandle passed to write method");
+  }
+  else {
+    /* write it out */
+    actual = device_instance_write(ihandle, buf, actual);
+    if (actual < 0)
+      args.actual = 0;
+    else
+      args.actual = actual;
+  }
   /* return the result */
   TRACE(trace_os_emul, ("write - out - actual=%ld\n",
   /* return the result */
   TRACE(trace_os_emul, ("write - out - actual=%ld\n",
-                       (long)T2H_4(args.actual)));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+                       (long)args.actual));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -663,7 +1132,41 @@ chirp_emul_seek(os_emul_data *data,
                cpu *processor,
                unsigned_word cia)
 {
                cpu *processor,
                unsigned_word cia)
 {
-  error("chirp: seek not implemented\n");
+  struct seek_args {
+    /*in*/
+    unsigned_cell ihandle;
+    unsigned_cell pos_hi;
+    unsigned_cell pos_lo;
+    /*out*/
+    unsigned_cell status;
+  } args;
+  int status;
+  device_instance *ihandle;
+  /* get the args */
+  if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
+    return -1;
+  ihandle = external_to_device_instance(data->root, args.ihandle);
+  TRACE(trace_os_emul, ("seek - in - ihandle=0x%lx(0x%lx`%s') pos.hi=0x%lx pos.lo=0x%lx\n",
+                       (unsigned long)args.ihandle,
+                       (unsigned long)ihandle,
+                       ihandle_name(ihandle),
+                       args.pos_hi, args.pos_lo));
+  if (ihandle == NULL) {
+    /* OpenFirmware doesn't define this error */
+    error("chirp: invalid ihandle passed to seek method");
+  }
+  else {
+    /* seek it out */
+    status = device_instance_seek(ihandle, args.pos_hi, args.pos_lo);
+    args.status = status;
+  }
+  /* return the result */
+  TRACE(trace_os_emul, ("seek - out - status=%ld\n",
+                       (long)args.status));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -675,7 +1178,55 @@ chirp_emul_claim(os_emul_data *data,
                 cpu *processor,
                 unsigned_word cia)
 {
                 cpu *processor,
                 unsigned_word cia)
 {
-  error("chirp: claim not implemented\n");
+  /* NOTE: the client interface claim routine is *very* different to
+     the "claim" method described in IEEE-1275 appendix A.  The latter
+     uses real addresses while this uses virtual (effective)
+     addresses. */
+  struct claim_args {
+    /* in */
+    unsigned_cell virt;
+    unsigned_cell size;
+    unsigned_cell align;
+    /* out */
+    unsigned_cell baseaddr;
+  } args;
+  /* read the args */
+  if (chirp_read_t2h_args(&args, sizeof(args),
+                         3 /*n_args*/, 1 /*n_returns*/,
+                         data, processor, cia))
+    return -1;
+  TRACE(trace_os_emul, ("claim - in - virt=0x%lx size=%ld align=%d\n",
+                       (unsigned long)args.virt,
+                       (long int)args.size,
+                       (int)args.align));
+  /* use the memory device to allocate (real) memory at the requested
+     address */
+  {
+    device_instance *memory = tree_find_ihandle_property(data->root, "/chosen/memory");
+    unsigned_cell mem_in[3];
+    unsigned_cell mem_out[1];
+    mem_in[0] = args.align; /*top-of-stack*/
+    mem_in[1] = args.size;
+    mem_in[2] = args.virt;
+    if (device_instance_call_method(memory, "claim",
+                                   3, mem_in, 1, mem_out) < 0)
+      error("chirp: claim failed to allocate memory virt=0x%lx size=%ld align=%d",
+           (unsigned long)args.virt,
+           (long int)args.size,
+           (int)args.align);
+    args.baseaddr = mem_out[0];
+  }
+  /* if using virtual addresses, create a 1-1 map of this address space */
+  if (!data->real_mode) {
+    error("chirp: claim method does not support virtual mode");
+  }
+  /* return the base address */
+  TRACE(trace_os_emul, ("claim - out - baseaddr=0x%lx\n",
+                       (unsigned long)args.baseaddr));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -684,7 +1235,47 @@ chirp_emul_release(os_emul_data *data,
                   cpu *processor,
                   unsigned_word cia)
 {
                   cpu *processor,
                   unsigned_word cia)
 {
-  error("chirp: release not implemented\n");
+  /* NOTE: the client interface release routine is *very* different to
+     the "claim" method described in IEEE-1275 appendix A.  The latter
+     uses real addresses while this uses virtual (effective)
+     addresses. */
+  struct claim_args {
+    /* in */
+    unsigned_cell virt;
+    unsigned_cell size;
+    /* out */
+  } args;
+  /* read the args */
+  if (chirp_read_t2h_args(&args, sizeof(args),
+                         2 /*n_args*/, 0 /*n_returns*/,
+                         data, processor, cia))
+    return -1;
+  TRACE(trace_os_emul, ("release - in - virt=0x%lx size=%ld\n",
+                       (unsigned long)args.virt,
+                       (long int)args.size));
+  /* use the memory device to release (real) memory at the requested
+     address */
+  {
+    device_instance *memory = tree_find_ihandle_property(data->root, "/chosen/memory");
+    unsigned_cell mem_in[2];
+    mem_in[0] = args.size;
+    mem_in[1] = args.virt;
+    if (device_instance_call_method(memory, "release",
+                                   2, mem_in, 0, NULL) < 0)
+      error("chirp: claim failed to release memory virt=0x%lx size=%ld",
+           (unsigned long)args.virt,
+           (long int)args.size);
+  }
+  /* if using virtual addresses, remove the 1-1 map of this address space */
+  if (!data->real_mode) {
+    error("chirp: release method does not support virtual mode");
+  }
+  /* return the base address */
+  TRACE(trace_os_emul, ("release - out\n"));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -696,7 +1287,25 @@ chirp_emul_boot(os_emul_data *data,
                cpu *processor,
                unsigned_word cia)
 {
                cpu *processor,
                unsigned_word cia)
 {
-  error("chirp: boot not implemented\n");
+  /* unlike OpenFirmware this one can take an argument */
+  struct boot_args {
+    /*in*/
+    unsigned_cell bootspec;
+    /*out*/
+  } args;
+  char bootspec[1024];
+  /* read in the arguments */
+  if (chirp_read_t2h_args(&args, sizeof(args), -1, 0, data, processor, cia))
+    cpu_halt(processor, cia, was_exited, -1);
+  if (args.bootspec != 0)
+    emul_read_string(bootspec, args.bootspec, sizeof(bootspec),
+                    processor, cia);
+  else
+    strcpy(bootspec, "(null)");
+  TRACE(trace_os_emul, ("boot - in bootspec=`%s'\n", bootspec));
+  /* just report this and exit */
+  printf_filtered("chrp: boot %s called, exiting.\n", bootspec);
+  cpu_halt(processor, cia, was_exited, 0);
   return 0;
 }
 
   return 0;
 }
 
@@ -705,7 +1314,7 @@ chirp_emul_enter(os_emul_data *data,
                 cpu *processor,
                 unsigned_word cia)
 {
                 cpu *processor,
                 unsigned_word cia)
 {
-  error("chirp: enter not implemented\n");
+  error("chirp: enter method not implemented\n");
   return 0;
 }
 
   return 0;
 }
 
@@ -714,7 +1323,15 @@ chirp_emul_exit(os_emul_data *data,
                cpu *processor,
                unsigned_word cia)
 {
                cpu *processor,
                unsigned_word cia)
 {
-  cpu_halt(processor, cia, was_exited, 0); /* always succeeds */
+  /* unlike OpenBoot this one can take an argument */
+  struct exit_args {
+    /*in*/
+    signed_cell status;
+    /*out*/
+  } args;
+  if (chirp_read_t2h_args(&args, sizeof(args), -1, 0, data, processor, cia))
+    cpu_halt(processor, cia, was_exited, -1);
+  cpu_halt(processor, cia, was_exited, args.status);
   return 0;
 }
 
   return 0;
 }
 
@@ -723,7 +1340,7 @@ chirp_emul_chain(os_emul_data *data,
                 cpu *processor,
                 unsigned_word cia)
 {
                 cpu *processor,
                 unsigned_word cia)
 {
-  error("chirp: chain not implemented\n");
+  error("chirp: chain method not implemented\n");
   return 0;
 }
 
   return 0;
 }
 
@@ -735,7 +1352,7 @@ chirp_emul_interpret(os_emul_data *data,
                     cpu *processor,
                     unsigned_word cia)
 {
                     cpu *processor,
                     unsigned_word cia)
 {
-  error("chirp: interpret not implemented\n");
+  error("chirp: interpret method not implemented\n");
   return 0;
 }
 
   return 0;
 }
 
@@ -744,7 +1361,7 @@ chirp_emul_set_callback(os_emul_data *data,
                        cpu *processor,
                        unsigned_word cia)
 {
                        cpu *processor,
                        unsigned_word cia)
 {
-  error("chirp: set_callback not implemented\n");
+  error("chirp: set_callback method not implemented\n");
   return 0;
 }
 
   return 0;
 }
 
@@ -753,7 +1370,7 @@ chirp_emul_set_symbol_lookup(os_emul_data *data,
                             cpu *processor,
                             unsigned_word cia)
 {
                             cpu *processor,
                             unsigned_word cia)
 {
-  error("chirp: set_symbol_lookup not implemented\n");
+  error("chirp: set_symbol_lookup method not implemented\n");
   return 0;
 }
 
   return 0;
 }
 
@@ -766,26 +1383,24 @@ chirp_emul_milliseconds(os_emul_data *data,
                        unsigned_word cia)
 {
   struct test_args {
                        unsigned_word cia)
 {
   struct test_args {
-    unsigned32 service;
-    unsigned32 n_args;
-    unsigned32 n_returns;
     /*in*/
     /*out*/
     /*in*/
     /*out*/
-    unsigned32 ms;
+    unsigned_cell ms;
   } args;
   unsigned64 time;
   /* read in the arguments */
   } args;
   unsigned64 time;
   /* read in the arguments */
-  if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
+  if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
     return -1;
   /* make up a number */
     return -1;
   /* make up a number */
-  time = event_queue_time(cpu_event_queue(processor)) / 1000000;
-  args.ms = H2T_4(time);
+  time = event_queue_time(psim_event_queue(cpu_system(processor))) / 1000000;
+  args.ms = time;
   /* write the arguments back out */
   TRACE(trace_os_emul, ("milliseconds - out - ms=%ld\n",
   /* write the arguments back out */
   TRACE(trace_os_emul, ("milliseconds - out - ms=%ld\n",
-                       (unsigned long)T2H_4(args.ms)));
-  emul_write_buffer(&args, data->arguments,
-                   sizeof(args),
-                   processor, cia);
+                       (unsigned long)args.ms));
+  chirp_write_h2t_args(&args,
+                      sizeof(args),
+                      data,
+                      processor, cia);
   return 0;
 }
 
   return 0;
 }
 
@@ -805,7 +1420,7 @@ static chirp_services services[] = {
   { "getproplen", chirp_emul_getproplen },
   { "getprop", chirp_emul_getprop },
   { "nextprop", chirp_emul_nextprop },
   { "getproplen", chirp_emul_getproplen },
   { "getprop", chirp_emul_getprop },
   { "nextprop", chirp_emul_nextprop },
-  { "setprop", chirp_emul_setprop },
+  /* { "setprop", chirp_emul_setprop }, */
   { "canon", chirp_emul_canon },
   { "finddevice", chirp_emul_finddevice },
   { "instance-to-path", chirp_emul_instance_to_path },
   { "canon", chirp_emul_canon },
   { "finddevice", chirp_emul_finddevice },
   { "instance-to-path", chirp_emul_instance_to_path },
@@ -850,6 +1465,10 @@ static chirp_services services[] = {
 #ifndef CHIRP_START_ADDRESS
 #define CHIRP_START_ADDRESS 0x80000000
 #endif
 #ifndef CHIRP_START_ADDRESS
 #define CHIRP_START_ADDRESS 0x80000000
 #endif
+#ifndef CHIRP_LOAD_BASE
+#define CHIRP_LOAD_BASE -1
+#endif
+
 
 typedef struct _chirp_note_desc {
   signed32 real_mode;
 
 typedef struct _chirp_note_desc {
   signed32 real_mode;
@@ -857,11 +1476,17 @@ typedef struct _chirp_note_desc {
   signed32 real_size;
   signed32 virt_base;
   signed32 virt_size;
   signed32 real_size;
   signed32 virt_base;
   signed32 virt_size;
+  signed32 load_base;
 } chirp_note_desc;
 
 } chirp_note_desc;
 
+typedef enum {
+  note_missing,
+  note_found,
+  note_correct,
+} note_found_status;
 typedef struct _chirp_note {
   chirp_note_desc desc;
 typedef struct _chirp_note {
   chirp_note_desc desc;
-  int found;
+  note_found_status found;
 } chirp_note;
 
 typedef struct _chirp_note_head {
 } chirp_note;
 
 typedef struct _chirp_note_head {
@@ -888,41 +1513,43 @@ map_over_chirp_note(bfd *image,
     head.type = bfd_get_32(image, (void*)&head.type);
     if (head.type != 0x1275)
       return;
     head.type = bfd_get_32(image, (void*)&head.type);
     if (head.type != 0x1275)
       return;
-    note->found = 1;
     /* check the name field */
     if (head.namesz > sizeof(name)) {
     /* check the name field */
     if (head.namesz > sizeof(name)) {
-      printf_filtered("open-boot warning: note name too long (%ld)\n",
-                     (long)head.namesz);
-      return;
+      error("chirp: note name too long (%d > %d)\n", (int)head.namesz, sizeof(name));
     }
     if (!bfd_get_section_contents(image, sect,
                                  name, sizeof(head), head.namesz)) {
     }
     if (!bfd_get_section_contents(image, sect,
                                  name, sizeof(head), head.namesz)) {
-      printf_filtered("open-boot warning: note name unreadable\n");
-      return;
+      error("chirp: note name unreadable\n");
     }
     if (strcmp(name, "PowerPC") != 0) {
     }
     if (strcmp(name, "PowerPC") != 0) {
-      printf_filtered("open-boot warning: note name (%s) not `PowerPC'\n",
-                     name);
-      return;
+      printf_filtered("chirp: note name (%s) not `PowerPC'\n", name);
     }
     }
-    /* get the contents */
-    if (head.descsz != sizeof(note->desc)) {
-      printf_filtered("open-boot warning: note descriptor of wrong size\n");
+    /* check the size */
+    if (head.descsz == sizeof(note->desc) - sizeof(signed32)) {
+      sim_io_printf_filtered("chirp: note descriptor missing load-base\n");
+    }
+    else if (head.descsz != sizeof(note->desc)) {
+      sim_io_printf_filtered("chirp: note descriptor of wrong size\n");
+      note->found = note_found;
       return;
     }
       return;
     }
+    note->found = note_correct;
+    /* get the contents */
     if (!bfd_get_section_contents(image, sect,
                                  &note->desc, /* page align start */
                                  ((sizeof(head) + head.namesz) + 3) & ~3,
                                  head.descsz)) {
     if (!bfd_get_section_contents(image, sect,
                                  &note->desc, /* page align start */
                                  ((sizeof(head) + head.namesz) + 3) & ~3,
                                  head.descsz)) {
-      printf_filtered("open-boot warning: note descriptor unreadable\n");
-      return;
+      error("chirp: note descriptor unreadable\n");
     }
     note->desc.real_mode = bfd_get_32(image, (void*)&note->desc.real_mode);
     note->desc.real_base = bfd_get_32(image, (void*)&note->desc.real_base);
     note->desc.real_size = bfd_get_32(image, (void*)&note->desc.real_size);
     note->desc.virt_base = bfd_get_32(image, (void*)&note->desc.virt_base);
     note->desc.virt_size = bfd_get_32(image, (void*)&note->desc.virt_size);
     }
     note->desc.real_mode = bfd_get_32(image, (void*)&note->desc.real_mode);
     note->desc.real_base = bfd_get_32(image, (void*)&note->desc.real_base);
     note->desc.real_size = bfd_get_32(image, (void*)&note->desc.real_size);
     note->desc.virt_base = bfd_get_32(image, (void*)&note->desc.virt_base);
     note->desc.virt_size = bfd_get_32(image, (void*)&note->desc.virt_size);
-    note->found = 2;
+    if (head.descsz == sizeof(note->desc))
+      note->desc.load_base = bfd_get_32(image, (void*)&note->desc.load_base);
+    else
+      note->desc.load_base = (signed32)-1;
   }
 }
 
   }
 }
 
@@ -932,9 +1559,10 @@ emul_chirp_create(device *root,
                  bfd *image,
                  const char *name)
 {
                  bfd *image,
                  const char *name)
 {
-  os_emul_data *data;
+  os_emul_data *chirp;
+  device *node;
   chirp_note note;
   chirp_note note;
-  int big_endian;
+  int i;
 
   /* Sanity check that this really is the chosen emulation */
   if (name == NULL && image == NULL)
 
   /* Sanity check that this really is the chosen emulation */
   if (name == NULL && image == NULL)
@@ -947,204 +1575,360 @@ emul_chirp_create(device *root,
       && strcmp(name, "openboot") != 0)
     return NULL;
 
       && strcmp(name, "openboot") != 0)
     return NULL;
 
-  /* look for an elf note section */
+  /* look for an elf note section, enter its values into the device tree */
   memset(&note, 0, sizeof(note));
   if (image != NULL)
     bfd_map_over_sections(image, map_over_chirp_note, &note);
   memset(&note, 0, sizeof(note));
   if (image != NULL)
     bfd_map_over_sections(image, map_over_chirp_note, &note);
-  if (name == NULL && image != NULL && !note.found)
+  if (name == NULL && image != NULL && note.found == note_missing)
     return NULL;
 
     return NULL;
 
+  /* Assume that it is a chirp emulation */
+
+  chirp = ZALLOC(os_emul_data);
+  chirp->root = root;
+  chirp->services = services;
+
   /* the root node */
   /* the root node */
-  device_add_string_property(root,
-                            "name",
-                            "gpl,clayton");
+  tree_parse(root, "/name \"gpl,clayton");
 
 
-  {
-    const unsigned_word memory_size = 0x200000;
-    
-    /* the hash table */
-    const unsigned nr_page_table_entry_groups = (memory_size < 0x800000
-                                                ? 1024 /* min allowed */
-                                                : (memory_size / 4096 / 2));
-    const unsigned sizeof_htab = nr_page_table_entry_groups * 64;
-    const unsigned_word htab_ra = memory_size - sizeof_htab;
-    
-    /* a page for firmware calls */
-    const unsigned_word sizeof_code = 4096;
-    const unsigned_word code_ra = htab_ra - sizeof_code;
-
-    /* the stack */
-    const unsigned sizeof_stack = 32 * 1024;
-    const unsigned_word stack_ra = code_ra - sizeof_stack;
-    
-    /* the firmware's home */
-    const int real_mode = 0;
-    /*  const unsigned_word real_base = stack_ra; */
-    /*  const unsigned real_size = memory_size - real_base; */
-    const unsigned_word virt_base = CHIRP_START_ADDRESS;
-    /*  const unsigned virt_size = real_size;*/
-    
-    /* the virtual addresses */
-    const unsigned_word stack_va = virt_base;
-    const unsigned_word code_va = stack_va + sizeof_stack;
-    const unsigned_word code_client_va = code_va;
-    const unsigned_word code_callback_va = code_client_va + 16;
-    const unsigned_word code_loop_va = code_callback_va + 16;
-    const unsigned_word htab_va = code_va + sizeof_code;
-
-#ifdef bfd_big_endian  /* new bfd */
-    big_endian = bfd_big_endian(image);
-#else
-    big_endian = image->xvec->byteorder_big_p;
-#endif
+  /* default options */
+  emul_add_tree_options(root, image, "chirp", "oea",
+                       0 /*oea-interrupt-prefix*/);
 
 
-    /* options */
-    {
-      device *options = device_tree_add_found(root, "/", "options");
-      device_add_integer_property(options,
-                                 "smp",
-                                 MAX_NR_PROCESSORS);
-      device_add_boolean_property(options,
-                                 "little-endian?",
-                                 !big_endian);
-      device_add_string_property(options, 
-                                "env",
-                                "operating");
-      device_add_boolean_property(options,
-                                 "strict-alignment?",
-                                 (WITH_ALIGNMENT == STRICT_ALIGNMENT
-                                  || !big_endian));
-      device_add_boolean_property(options,
-                                 "floating-point?",
-                                 WITH_FLOATING_POINT);
-      device_add_string_property(options,
-                                "os-emul",
-                                "chirp");
-    }
-    
-    /* hardware */
-    device_tree_add_found_uw_u_u(root, "/", "memory",
-                                0, memory_size, access_read_write_exec);
-    
-    /* initialization */
-    {
-      device *init = device_tree_add_found(root, "/", "init");
-      {
-       device *init_register = device_tree_add_found(init, "", "register");
-       device_add_integer_property(init_register,
-                                   "pc",
-                                   code_loop_va);
-       device_add_integer_property(init_register,
-                                   "0.pc",
-                                   bfd_get_start_address(image));
-       device_add_integer_property(init_register,
-                                   "sp",
-                                   stack_va + sizeof_stack - 16);
-       
-       /* init the code callback along with a loop for the unused cpu's */
-       device_add_integer_property(init_register,
-                                   "r5",
-                                   code_client_va);
-       /* client interface */
-       device_tree_add_found_uw_u_u(init, "",
-                                    "data",
-                                    code_ra + (code_client_va - code_va),
-                                    4, emul_call_instruction);
-       device_tree_add_found_uw_u_u(init, "",
-                                    "data",
-                                    code_ra + (code_client_va - code_va) + 4,
-                                    4, emul_blr_instruction);
-       /* callback return address */
-       device_tree_add_found_uw_u_u(init, "",
-                                    "data",
-                                    code_ra + (code_callback_va - code_va),
-                                    4, emul_call_instruction);
-       /* loop to keep other processors busy */
-       device_tree_add_found_uw_u_u(init, "",
-                                    "data",
-                                    code_ra + (code_loop_va - code_va),
-                                    4, emul_loop_instruction);
-       device_add_integer_property(init_register,
-                                   "msr",
-                                   (msr_machine_check_enable
-                                    | (real_mode
-                                       ? 0 
-                                       : (msr_instruction_relocate
-                                          | msr_data_relocate))
-                                    | (big_endian
-                                       ? 0
-                                       : (msr_little_endian_mode
-                                          | msr_interrupt_little_endian_mode
-                                          ))));
-       device_add_integer_property(init_register,
-                                   "sdr1",
-                                   (htab_ra
-                                    | MASK32(16, 22)
-                                    | ((sizeof_htab - 1) >> 16)));
-       /* FIXME */
-       device_add_integer_property(init_register,
-                                   "sr8",
-                                   0x00fffff8);
-       device_add_integer_property(init_register,
-                                   "sr9",
-                                   0x00fffff9);
-       
-       { /* hash table and vm */
-         device *htab_root = device_tree_add_found_uw_u(init, "", "htab",
-                                                        htab_ra, sizeof_htab);
-         device_tree_add_found_uw_uw_u_u_u(htab_root, "", "pte",
-                                           stack_ra, stack_va, sizeof_stack,
-                                           0x7/*wimg*/, 0x2/*pp*/);
-         device_tree_add_found_uw_uw_u_u_u(htab_root, "", "pte",
-                                           code_ra, code_va, sizeof_code,
-                                           0x7/*wimg*/, 0x2/*pp*/);
-         device_tree_add_found_uw_uw_u_u_u(htab_root, "", "pte",
-                                           htab_ra, htab_va, sizeof_htab,
-                                           0x7/*wimg*/, 0x2/*pp*/);
-         device_tree_add_found_uw_u_u_c(htab_root, "", "pte",
-                                        0x4000, /*magic*/
-                                        0x7/*wimg*/, 0x2/*pp*/,
-                                        bfd_get_filename (image));
-       }
-      }
-    }
-    
-    { /* chosen options */
-      device *chosen = device_tree_add_found(root, "/", "chosen");
-      device_add_string_property(chosen,
-                                "name",
-                                "chosen");
-      device_add_integer_property(chosen,
-                                 "stdin",
-                                 0); /* FIXME: ihandle of stdin */
-      device_add_integer_property(chosen,
-                                 "stdout",
-                                 1); /* FIXME: ihandle of stdout */
-      device_add_string_property(chosen,
-                                "bootpath",
-                                "/disk@0:\\boot");
-      device_add_string_property(chosen,
-                                "bootargs",
-                                "");
-#if 0
-      device_add_integer_property(chosen,
-                                 "memory",
-                                 0); /* FIXME: ihandle of memory */
-      device_add_integer_property(chosen,
-                                 "mmu",
-                                 0);
-#endif
-    }
-    
-    /* FIXME - should come from the device tree */
-    data = ZALLOC(os_emul_data);
-    data->serving_instruction_ea = code_client_va;
-    data->catching_instruction_ea = code_callback_va;
-    data->phandles = cap_create("chirp");
-    data->root = root;
-    data->services = services;
-    return data;
+  /* hardware */
+  emul_add_tree_hardware(root);
+
+  /* basic information */
+  chirp->memory_size
+    = tree_find_integer_property(root, "/openprom/options/oea-memory-size");
+  chirp->little_endian
+    = tree_find_boolean_property(root, "/options/little-endian?");
+  chirp->floating_point_available
+    = tree_find_boolean_property(root, "/openprom/options/floating-point?");
+  chirp->interrupt_prefix =
+    tree_find_integer_property(root, "/openprom/options/oea-interrupt-prefix");
+
+
+  /* Perform an interum layout of the openboot firmware in memory */
+
+
+  /* a page for firmware calls */
+  chirp->sizeof_code = 4096;
+  chirp->code_offset = 0x4000; /* possible space for interrupt table */
+
+  /* the stack */
+  chirp->sizeof_stack = 32 * 1024;
+  chirp->stack_offset = chirp->code_offset + chirp->sizeof_code;
+
+  /* the hash table */
+  if (!note.desc.real_mode) {
+    chirp->nr_page_table_entry_groups = (chirp->memory_size < 0x800000
+                                        ? 1024 /* min allowed */
+                                        : (chirp->memory_size / 4096 / 2));
+    chirp->sizeof_htab = chirp->nr_page_table_entry_groups * 64;
+  }
+  chirp->htab_offset = chirp->stack_offset + chirp->sizeof_stack;
+
+  /* the actual amount of space needed */
+  chirp->real_size = chirp->htab_offset + chirp->sizeof_htab;
+
+
+  /* now go through and see if it fits in what is available */
+
+
+  /* resolve real-mode? */
+  if (note.found == note_correct)
+    chirp->real_mode = note.desc.real_mode;
+  else if (tree_find_property(root, "/options/real-mode?") != NULL)
+    chirp->real_mode = tree_find_boolean_property(root, "/options/real-mode?");
+  else
+    chirp->real_mode = 0;
+  if (tree_find_property(root, "/options/real-mode?") != NULL) {
+    if (!chirp->real_mode
+       != !tree_find_boolean_property(root, "/options/real-mode?"))
+      error("chirp: /options/real-mode? conflicts with note section\n");
+  }
+  else
+    tree_parse(root, "/options/real-mode? %s",
+              chirp->real_mode ? "true" : "false");
+
+  /* resolve real-base */
+  if (note.found == note_correct
+      && note.desc.real_base != (signed32)-1)
+    chirp->real_base = note.desc.real_base;
+  else if (tree_find_property(root, "/options/real-base") != NULL)
+    chirp->real_base = tree_find_integer_property(root, "/options/real-base");
+  else
+    chirp->real_base = chirp->memory_size - chirp->real_size;
+  if (tree_find_property(root, "/options/real-base") != NULL) {
+    if (chirp->real_base != tree_find_integer_property(root, "/options/real-base"))
+      error("chirp: /options/real-base conflicts with note section\n");
+  }
+  else
+    tree_parse(root, "/options/real-base 0x%lx",
+              (unsigned long)chirp->real_base);
+
+  /* resolve real-size */
+  if (note.found == note_correct
+      && note.desc.real_size != (signed32)-1
+      && note.desc.real_size != 0
+      && chirp->real_size > note.desc.real_size)
+    error("chirp: insufficient physical memory for firmware\n");
+  if (tree_find_property(root, "/options/real-size") != NULL) {
+    if (chirp->real_size > tree_find_integer_property(root, "/options/real-size"))
+      error("chirp: /options/real-size conflicts with note section\n");
   }
   }
+  else
+    tree_parse(root, "/options/real-size 0x%lx",
+              (unsigned long)chirp->real_size);
+
+  /* resolve virt-base */
+  if (chirp->real_mode)
+    chirp->virt_base = chirp->real_base;
+  else if (note.found == note_correct && note.desc.virt_base != -1)
+    chirp->virt_base = note.desc.virt_base;
+  else if (tree_find_property(root, "/options/virt-base") != NULL)
+    chirp->virt_base = tree_find_integer_property(root, "/options/virt-base");
+  else
+    chirp->virt_base = CHIRP_START_ADDRESS;
+  if (tree_find_property(root, "/options/virt-base") != NULL) {
+    unsigned_word virt_base = tree_find_integer_property(root, "/options/virt-base");
+    if (virt_base != -1 && chirp->virt_base != virt_base)
+      error("chirp: /options/virt-base conflicts with note section\n");
+  }
+  else
+    tree_parse(root, "/options/virt-base 0x%lx",
+              chirp->real_mode ? -1 : (unsigned long)chirp->virt_base);
+
+  /* resolve virt-size */
+  chirp->virt_size = chirp->real_size;
+  if (note.found == note_correct
+     && note.desc.virt_size != (signed32)-1
+      && note.desc.virt_size != 0
+      && !chirp->real_mode
+      && chirp->virt_size > note.desc.virt_size)
+    error("chirp: insufficent virtual memory for firmware\n");
+  if (tree_find_property(root, "/options/virt-size") != NULL) {
+    if (chirp->virt_size > tree_find_integer_property(root, "/options/virt-size"))
+      error("chirp: /options/virt-size conflicts with note section\n");
+  }
+  else
+    tree_parse(root, "/options/virt-size 0x%lx",
+              chirp->real_mode ? -1 : (unsigned long)chirp->virt_size);
+
+  /* resolve load-base */
+  if (note.found == note_correct
+      && note.desc.load_base != (signed32)-1)
+    chirp->load_base = note.desc.load_base;
+  else if (tree_find_property(root, "/options/load-base") != NULL)
+    chirp->load_base = tree_find_integer_property(root, "/options/load-base");
+  else
+    chirp->load_base = CHIRP_LOAD_BASE;
+  if (tree_find_property(root, "/options/load-base") != NULL) {
+    if (chirp->load_base != tree_find_integer_property(root, "/options/load-base"))
+      error("chirp: /options/load-base conflicts with note section\n");
+  }
+  else
+    tree_parse(root, "/options/load-base 0x%lx",
+              (unsigned long)chirp->load_base);
+
+  /* now adjust the preliminary firmware addresses to final values */
+  chirp->code_ra = chirp->code_offset + chirp->real_base;
+  chirp->stack_ra = chirp->stack_offset + chirp->real_base;
+  chirp->htab_ra = chirp->htab_offset + chirp->real_base;
+
+  /* the virtual addresses.  In real mode these are real addresses. */
+
+  chirp->code_va = chirp->code_offset + chirp->virt_base;
+  chirp->stack_va = chirp->stack_offset + chirp->virt_base;
+  chirp->htab_va = chirp->htab_offset + chirp->virt_base;
+
+  chirp->code_client_va = chirp->code_va;
+  chirp->code_client_ra = chirp->code_ra;
+
+  chirp->code_callback_va = chirp->code_client_va + 16;
+  chirp->code_callback_ra = chirp->code_client_ra + 16;
+
+  chirp->code_loop_va = chirp->code_callback_va + 16;
+  chirp->code_loop_ra = chirp->code_callback_ra + 16;
+
+  /* initialization */
+
+  tree_parse(root, "/openprom/init");
+  tree_parse(root, "/openprom/init/register");
+  tree_parse(root, "/openprom/init/register/0.pc 0x%lx",
+            (unsigned long)bfd_get_start_address(image));
+  tree_parse(root, "/openprom/init/register/pc 0x%lx",
+            (unsigned long)chirp->code_loop_va);
+  tree_parse(root, "/openprom/init/register/msr 0x%x",
+            (msr_machine_check_enable
+             | (chirp->real_mode
+                ? 0
+                : (msr_instruction_relocate
+                   | msr_data_relocate))
+             | (chirp->little_endian
+                ? (msr_little_endian_mode
+                   | msr_interrupt_little_endian_mode)
+                : 0)
+             | (chirp->floating_point_available
+                ? msr_floating_point_available
+                : 0)
+             | (chirp->interrupt_prefix
+                ? msr_interrupt_prefix
+                : 0)
+             ));
+  tree_parse(root, "/openprom/init/register/sdr1 0x%lx",
+            (unsigned long)(chirp->htab_ra
+                            | MASK32(16, 22)
+                            | ((chirp->sizeof_htab - 1) >> 16)));
+  /* make certain that the segment registers map straight through */
+  for (i = 0; i < 16; i++) {
+    tree_parse(root, "/openprom/init/register/sr%d 0x%lx",
+              i, (unsigned long)i);
+  }
+
+  /* establish an initial state for all processors */
+
+
+  /* the client interface address */
+  tree_parse(root, "/openprom/init/register/r5 0x%lx",
+            (unsigned long)chirp->code_client_va);
+  /* a stack */
+  tree_parse(root, "/openprom/init/register/sp 0x%lx",
+            (unsigned long)(chirp->stack_va + chirp->sizeof_stack - 16));
+  /* in chrp mode any arguments end up being concatinated */
+  tree_parse(root, "/openprom/init/stack/stack-type chirp");
+
+
+  /* client interface - emul-call followed by return instruction */
+
+
+  node = tree_parse(root, "/openprom/init/data@0x%lx",
+                   (unsigned long)chirp->code_client_ra);
+  tree_parse(node, "./psim,description \"client-interface instruction");
+  tree_parse(node, "./real-address 0x%lx",
+            (unsigned long)chirp->code_client_ra);
+  tree_parse(node, "./data 0x%lx",
+            (unsigned long)emul_call_instruction);
+
+  node = tree_parse(root, "/openprom/init/data@0x%lx",
+                   (unsigned long)(chirp->code_client_ra + 4));
+  tree_parse(node, "./psim,description \"client-interface return instruction");
+  tree_parse(node, "./real-address 0x%lx",
+            (unsigned long)(chirp->code_client_ra + 4));
+  tree_parse(node, "./data 0x%lx",
+            (unsigned long)emul_blr_instruction);
+
+
+  /* return address for client callbacks - an emul-call instruction
+     that is again followed by a return instruction */
+
+
+  node = tree_parse(root, "/openprom/init/data@0x%lx",
+                   (unsigned long)chirp->code_callback_ra);
+  tree_parse(node, "./psim,description \"client-callback instruction");
+  tree_parse(node, "./real-address 0x%lx",
+            (unsigned long)chirp->code_callback_ra);
+  tree_parse(node, "./data 0x%lx",
+            (unsigned long)emul_call_instruction);
+
+  node = tree_parse(root, "/openprom/init/data@0x%lx",
+                   (unsigned long)(chirp->code_callback_ra + 4));
+  tree_parse(node, "./psim,description \"client-callback return instruction");
+  tree_parse(node, "./real-address 0x%lx",
+            (unsigned long)(chirp->code_callback_ra + 4));
+  tree_parse(node, "./data 0x%lx",
+            (unsigned long)emul_blr_instruction);
+
+  /* loop to keep other processors busy */
+
+  node = tree_parse(root, "/openprom/init/data@0x%lx",
+                   (unsigned long)chirp->code_loop_ra);
+  tree_parse(node, "./psim,description \"processor busy loop");
+  tree_parse(node, "./real-address 0x%lx",
+            (unsigned long)chirp->code_loop_ra);
+  tree_parse(node, "./data 0x%lx",
+            (unsigned long)emul_loop_instruction);
+
+  /* hash table */
+
+  /* create a hash table */
+
+  if (!chirp->real_mode) {
+    node = tree_parse(root, "/openprom/init/htab@0x%lx",
+                     (unsigned long)chirp->htab_ra);
+    tree_parse(node, "./claim 0");
+    tree_parse(node, "./real-address 0x%lx",
+              (unsigned long)chirp->htab_ra);
+    tree_parse(node, "./nr-bytes 0x%lx",
+              (unsigned long)chirp->sizeof_htab);
+  }
+
+  /* map in the stack */
+
+  if (!chirp->real_mode) {
+    node = tree_parse(root, "/openprom/init/htab/pte@0x%lx",
+                     (unsigned long)chirp->stack_ra);
+    tree_parse(node, "./psim,description \"map in the stack");
+    tree_parse(node, "./claim 1");
+    tree_parse(node, "./virtual-address 0x%lx",
+              (unsigned long)chirp->stack_va);
+    tree_parse(node, "./real-address 0x%lx",
+              (unsigned long)chirp->stack_ra);
+    tree_parse(node, "./nr-bytes 0x%lx",
+              (unsigned long)chirp->sizeof_stack);
+    tree_parse(node, "./wimg %d", 0x7);
+    tree_parse(node, "./pp %d", 0x2);
+  }
+
+  /* map in the chrp openboot callback code */
+
+  if (!chirp->real_mode) {
+    node = tree_parse(root, "/openprom/init/htab/pte@0x%lx",
+                     (unsigned long)chirp->code_ra);
+    tree_parse(node, "./psim,description \"map in chrp openboot callback code");
+    tree_parse(node, "./claim 1");
+    tree_parse(node, "./virtual-address 0x%lx",
+              (unsigned long)chirp->code_va);
+    tree_parse(node, "./real-address 0x%lx",
+              (unsigned long)chirp->code_ra);
+    tree_parse(node, "./nr-bytes 0x%lx",
+              (unsigned long)chirp->sizeof_code);
+    tree_parse(node, "./wimg %d", 0x7);
+    tree_parse(node, "./pp %d", 0x2);
+  }
+
+  /* map in the program to run */
+
+  if (chirp->real_mode) {
+    node = tree_parse(node, "/openprom/init/load-binary");
+    tree_parse(node, "./psim,description \"load the binary");
+    tree_parse(node, "./file-name %s", bfd_get_filename(image));
+    tree_parse(node, "./claim 1");
+  }
+  else {
+    node = tree_parse(root, "/openprom/init/htab/pte@0x%lx",
+                     (unsigned long)chirp->load_base);
+    tree_parse(node, "./psim,description \"load & map the binary");
+    tree_parse(node, "./claim 1");
+    tree_parse(node, "./file-name \"%s", bfd_get_filename(image));
+    tree_parse(node, "./wimg %d", 0x7);
+    tree_parse(node, "./pp %d", 0x2);
+  }
+
+  /* map in the interrupt vectors */
+
+  if (!chirp->real_mode) {
+    node = tree_parse(root, "/openprom/init/htab/pte@0x0");
+    tree_parse(node, "./psim,description \"map in interrupt vectors");
+    tree_parse(node, "./virtual-address 0x0");
+    tree_parse(node, "./real-address 0x0");
+    tree_parse(node, "./nr-bytes 0x3000");
+    tree_parse(node, "./wimg %d", 0x7);
+    tree_parse(node, "./pp %d", 0x2);
+  }
+
+  return chirp;
 }
 
 static void
 }
 
 static void
@@ -1152,7 +1936,6 @@ emul_chirp_init(os_emul_data *emul_data,
                int nr_cpus)
 {
   emul_data->state = serving;
                int nr_cpus)
 {
   emul_data->state = serving;
-  cap_init(emul_data->phandles);
 }
 
 static int
 }
 
 static int
@@ -1172,7 +1955,7 @@ emul_chirp_instruction_call(cpu *processor,
   case serving:
     /* we are waiting on an OpenBoot request from the client program
        via the client interface */
   case serving:
     /* we are waiting on an OpenBoot request from the client program
        via the client interface */
-    if (cia != emul_data->serving_instruction_ea)
+    if (cia != emul_data->code_client_va)
       return 0;
     emul_data->return_address = LR;
     emul_data->arguments = cpu_registers(processor)->gpr[3];
       return 0;
     emul_data->return_address = LR;
     emul_data->arguments = cpu_registers(processor)->gpr[3];
@@ -1181,39 +1964,51 @@ emul_chirp_instruction_call(cpu *processor,
                                       processor, cia);
     service_name = emul_read_string(service_buf, service_name_addr,
                                    sizeof(service_buf), processor, cia);
                                       processor, cia);
     service_name = emul_read_string(service_buf, service_name_addr,
                                    sizeof(service_buf), processor, cia);
+    emul_data->n_args = emul_read_word(emul_data->arguments + sizeof(unsigned_cell),
+                                      processor, cia);
+    emul_data->n_returns = emul_read_word(emul_data->arguments + 2 * sizeof(unsigned_cell),
+                                         processor, cia);
+    /* verify what was passed */
+    if (service_name_addr == 0
+       || service_name == NULL) {
+      error("OpenFirmware called with invalid (NULL) service name from 0x%lx with args 0x%lx\n",
+           (unsigned long)emul_data->return_address,
+           (unsigned long)emul_data->arguments);
+    }
+    if (emul_data->n_args > 6) { /* See iee1275 requirements on nr returns */
+      error("OpenFirmware service %s called from 0x%lx with args 0x%lx, too many args (%d)\n",
+           (unsigned long)emul_data->return_address,
+           (unsigned long)emul_data->arguments,
+           emul_data->n_returns);
+    }
+    if (emul_data->n_returns > 6) {
+      error("OpenFirmware service %s called from 0x%lx with args 0x%lx,  with too many returns (%d)\n",
+           (unsigned long)emul_data->return_address,
+           (unsigned long)emul_data->arguments,
+           emul_data->n_args);
+    }
+    /* look it up */
     TRACE(trace_os_emul, ("%s called from 0x%lx with args 0x%lx\n",
                          service_name,
                          (unsigned long)emul_data->return_address,
                          (unsigned long)emul_data->arguments));
     TRACE(trace_os_emul, ("%s called from 0x%lx with args 0x%lx\n",
                          service_name,
                          (unsigned long)emul_data->return_address,
                          (unsigned long)emul_data->arguments));
-    /* look it up */
     service = services;
     while (service->name != NULL && strcmp(service->name, service_name) != 0)
       service++;
     service = services;
     while (service->name != NULL && strcmp(service->name, service_name) != 0)
       service++;
+    /* found or not? */
     if (service->name == NULL) {
       error("OpenBoot service `%s' not found\n", service_name);
       TRACE(trace_os_emul, ("%s not found\n", service_name));
     if (service->name == NULL) {
       error("OpenBoot service `%s' not found\n", service_name);
       TRACE(trace_os_emul, ("%s not found\n", service_name));
-      cpu_registers(processor)->gpr[3] = 0;
-      cpu_restart(processor, emul_data->return_address);
+      cpu_registers(processor)->gpr[3] = -1;
+    }
+    else {
+      emul_data->service = service;
+      /* call upon it */
+      result = service->handler(emul_data, processor, cia);
+      if (result != 0)
+       TRACE(trace_os_emul, ("%s aborted with %ld\n", service_name, (long)result));
+      cpu_registers(processor)->gpr[3] = result;
     }
     }
-    emul_data->service = service;
-    /* call upon it */
-    result = service->handler(emul_data, processor, cia);
-    break;
-
-  case faulting:
-    /* We were handling a client request but encountered a page fault
-       (or other exception).  The fault needs to be passed back to the
-       client using the the client suplied call back interface */
-    error("emul_chirp_instruction_call() faulting unimplemented\n");
-    result = -1;
-    break;
-
-  case catching:
-    /* Have called the client (via the callback interface) because
-       some fault (hash table miss) occured.  The client has finished
-       handling this and is now returning */
-    error("emul_chirp_instruction_call() catching unimplemented\n");
-    result = -1;
     break;
 
   default:
     break;
 
   default:
This page took 0.052751 seconds and 4 git commands to generate.