diff options
author | Michael Meissner <gnu@the-meissners.org> | 1997-01-27 21:34:50 +0000 |
---|---|---|
committer | Michael Meissner <gnu@the-meissners.org> | 1997-01-27 21:34:50 +0000 |
commit | 5c04f4f7fced8f90816be87e9efde53441447d7a (patch) | |
tree | c6264a3954b4a33d053257abfe5bf2c01af4f737 /sim/ppc/emul_chirp.c | |
parent | 1d5c6cfdf01a498866d3b1662d30d75985c99fc4 (diff) | |
download | gdb-5c04f4f7fced8f90816be87e9efde53441447d7a.zip gdb-5c04f4f7fced8f90816be87e9efde53441447d7a.tar.gz gdb-5c04f4f7fced8f90816be87e9efde53441447d7a.tar.bz2 |
January 23rd merge
Diffstat (limited to 'sim/ppc/emul_chirp.c')
-rw-r--r-- | sim/ppc/emul_chirp.c | 1860 |
1 files changed, 1314 insertions, 546 deletions
diff --git a/sim/ppc/emul_chirp.c b/sim/ppc/emul_chirp.c index 9eb3a4e..e569dd7 100644 --- a/sim/ppc/emul_chirp.c +++ b/sim/ppc/emul_chirp.c @@ -1,6 +1,6 @@ /* This file is part of the program psim. - Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> + Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> 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 @@ -11,11 +11,11 @@ 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 along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - + */ @@ -28,8 +28,6 @@ #include "emul_generic.h" #include "emul_chirp.h" -#include "cap.h" - #ifdef HAVE_STRING_H #include <string.h> #else @@ -45,12 +43,35 @@ #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); + typedef struct _chirp_services { const char *name; chirp_handler *handler; @@ -61,53 +82,127 @@ typedef struct _chirp_services { request or waiting on a client callback */ typedef enum { serving, + emulating, faulting, - catching, } 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; - unsigned_word serving_instruction_ea; - unsigned_word catching_instruction_ea; - cap *phandles; 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 -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; } + /* 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; } +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 */ @@ -119,23 +214,21 @@ chirp_emul_test(os_emul_data *data, unsigned_word cia) { struct test_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ - unsigned32 name; /*string*/ + unsigned_cell name; /*string*/ /*out*/ - unsigned32 missing; + unsigned_cell missing; } args; char name[32]; - chirp_services *service = data->services; + chirp_services *service = NULL; /* 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; - 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 */ + service = data->services; while (service->name != NULL && strcmp(service->name, name) != 0) { service++; } @@ -146,9 +239,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)); - emul_write_buffer(&args, data->arguments, - sizeof(args), - processor, cia); + chirp_write_h2t_args(&args, + sizeof(args), + data, + processor, cia); return 0; } @@ -161,45 +255,46 @@ chirp_emul_peer(os_emul_data *data, unsigned_word cia) { struct peer_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ - unsigned32 phandle; + unsigned_cell phandle; /*out*/ - unsigned32 sibling_phandle; + unsigned_cell sibling_phandle; } args; - device *dev; - device *sibling_dev = NULL; + device *phandle; + device *sibling_phandle = NULL; /* 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; - 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", - (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 */ - 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", - (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; } @@ -209,40 +304,43 @@ chirp_emul_child(os_emul_data *data, unsigned_word cia) { struct child_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ - unsigned32 phandle; + unsigned_cell phandle; /*out*/ - unsigned32 child_phandle; + unsigned_cell child_phandle; } args; - device *dev; - device *child_dev; + device *phandle; + device *child_phandle; /* 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; - 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", - (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 */ - 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", - (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; } @@ -252,40 +350,43 @@ chirp_emul_parent(os_emul_data *data, unsigned_word cia) { struct parent_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ - unsigned32 phandle; + unsigned_cell phandle; /*out*/ - unsigned32 parent_phandle; + unsigned_cell parent_phandle; } args; - device *dev; - device *parent_dev; + device *phandle; + device *parent_phandle; /* 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; - 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", - (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 */ - 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", - (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; } @@ -294,7 +395,40 @@ chirp_emul_instance_to_package(os_emul_data *data, 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; } @@ -304,47 +438,48 @@ chirp_emul_getproplen(os_emul_data *data, unsigned_word cia) { struct getproplen_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ - unsigned32 phandle; - unsigned32 name; + unsigned_cell phandle; + unsigned_cell name; /*out*/ - unsigned32 proplen; + unsigned_cell proplen; } args; char name[32]; - device *dev; - const device_property *prop; + device *phandle; /* 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; + phandle = external_to_device(data->root, args.phandle); 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", - (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)); - 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 = 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", - (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; } @@ -354,65 +489,77 @@ chirp_emul_getprop(os_emul_data *data, unsigned_word cia) { struct getprop_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ - unsigned32 phandle; - unsigned32 name; - unsigned32 buf; - unsigned32 buflen; + unsigned_cell phandle; + unsigned_cell name; + unsigned_cell buf; + unsigned_cell buflen; /*out*/ - unsigned32 size; + unsigned_cell size; } 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; - dev = cap_internal(data->phandles, args.phandle); + phandle = external_to_device(data->root, args.phandle); 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", - (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, - (unsigned long)T2H_4(args.buf), - (unsigned long)T2H_4(args.buflen))); + (unsigned long)args.buf, + (unsigned long)args.buflen)); /* 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 { - 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 */ - 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; } @@ -421,25 +568,127 @@ chirp_emul_nextprop(os_emul_data *data, 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); + emul_read_string(previous, + args.previous, + sizeof(previous), + processor, cia); + 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) { + args.flag = -1; /* name invalid */ + } + else { + const device_property *next_prop; + 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; } +#if 0 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; } +#endif 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; } @@ -449,40 +698,37 @@ chirp_emul_finddevice(os_emul_data *data, unsigned_word cia) { struct finddevice_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ - unsigned32 device_specifier; + unsigned_cell device_specifier; /*out*/ - unsigned32 phandle; + unsigned_cell phandle; } args; char device_specifier[1024]; - device *dev; + device *phandle; /* 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, - 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 */ - 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 = 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", - (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; } @@ -491,25 +737,162 @@ chirp_emul_instance_to_path(os_emul_data *data, 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, - 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, - 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; } @@ -522,33 +905,37 @@ chirp_emul_open(os_emul_data *data, unsigned_word cia) { struct open_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ - unsigned32 device_specifier; + unsigned_cell device_specifier; /*out*/ - unsigned32 ihandle; + unsigned_cell ihandle; } args; - char name[1024]; + char device_specifier[1024]; + device_instance *ihandle; /* 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; - 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", - name)); + device_specifier)); /* 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 */ - 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; } @@ -557,7 +944,34 @@ chirp_emul_close(os_emul_data *data, 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; } @@ -567,94 +981,135 @@ chirp_emul_read(os_emul_data *data, unsigned_word cia) { struct read_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ - unsigned32 ihandle; - unsigned32 addr; - unsigned32 len; + unsigned_cell ihandle; + unsigned_cell addr; + unsigned_cell len; /*out*/ - unsigned32 actual; + unsigned_cell actual; } args; char buf[1024]; - int actual; + device_instance *ihandle; /* 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; - 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)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 { - 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", - (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, - cpu *processor, - unsigned_word cia) + cpu *processor, + unsigned_word cia) { struct write_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ - unsigned32 ihandle; - unsigned32 addr; - unsigned32 len; + unsigned_cell ihandle; + unsigned_cell addr; + unsigned_cell len; /*out*/ - unsigned32 actual; + unsigned_cell actual; } args; char buf[1024]; + device_instance *ihandle; 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; - actual = T2H_4(args.len); + actual = args.len; if (actual >= sizeof(buf)) actual = sizeof(buf) - 1; emul_read_buffer(buf, - T2H_4(args.addr), + args.addr, 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", - (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; } @@ -663,7 +1118,41 @@ chirp_emul_seek(os_emul_data *data, 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; } @@ -675,7 +1164,55 @@ chirp_emul_claim(os_emul_data *data, 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; } @@ -684,7 +1221,47 @@ chirp_emul_release(os_emul_data *data, 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; } @@ -696,7 +1273,25 @@ chirp_emul_boot(os_emul_data *data, 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; } @@ -705,7 +1300,7 @@ chirp_emul_enter(os_emul_data *data, cpu *processor, unsigned_word cia) { - error("chirp: enter not implemented\n"); + error("chirp: enter method not implemented\n"); return 0; } @@ -714,7 +1309,15 @@ chirp_emul_exit(os_emul_data *data, 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; } @@ -723,7 +1326,7 @@ chirp_emul_chain(os_emul_data *data, cpu *processor, unsigned_word cia) { - error("chirp: chain not implemented\n"); + error("chirp: chain method not implemented\n"); return 0; } @@ -735,7 +1338,7 @@ chirp_emul_interpret(os_emul_data *data, cpu *processor, unsigned_word cia) { - error("chirp: interpret not implemented\n"); + error("chirp: interpret method not implemented\n"); return 0; } @@ -744,7 +1347,7 @@ chirp_emul_set_callback(os_emul_data *data, cpu *processor, unsigned_word cia) { - error("chirp: set_callback not implemented\n"); + error("chirp: set_callback method not implemented\n"); return 0; } @@ -753,7 +1356,7 @@ chirp_emul_set_symbol_lookup(os_emul_data *data, cpu *processor, unsigned_word cia) { - error("chirp: set_symbol_lookup not implemented\n"); + error("chirp: set_symbol_lookup method not implemented\n"); return 0; } @@ -766,26 +1369,24 @@ chirp_emul_milliseconds(os_emul_data *data, unsigned_word cia) { struct test_args { - unsigned32 service; - unsigned32 n_args; - unsigned32 n_returns; /*in*/ /*out*/ - unsigned32 ms; + unsigned_cell ms; } 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 */ - 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", - (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; } @@ -805,7 +1406,7 @@ static chirp_services services[] = { { "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 }, @@ -850,6 +1451,10 @@ static chirp_services services[] = { #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; @@ -857,11 +1462,17 @@ typedef struct _chirp_note_desc { signed32 real_size; signed32 virt_base; signed32 virt_size; + signed32 load_base; } chirp_note_desc; +typedef enum { + note_missing, + note_found, + note_correct, +} note_found_status; typedef struct _chirp_note { chirp_note_desc desc; - int found; + note_found_status found; } chirp_note; typedef struct _chirp_note_head { @@ -888,41 +1499,43 @@ map_over_chirp_note(bfd *image, 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)) { - 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)) { - printf_filtered("open-boot warning: note name unreadable\n"); - return; + error("chirp: note name unreadable\n"); } 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; } + note->found = note_correct; + /* get the contents */ if (!bfd_get_section_contents(image, sect, ¬e->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*)¬e->desc.real_mode); note->desc.real_base = bfd_get_32(image, (void*)¬e->desc.real_base); note->desc.real_size = bfd_get_32(image, (void*)¬e->desc.real_size); note->desc.virt_base = bfd_get_32(image, (void*)¬e->desc.virt_base); note->desc.virt_size = bfd_get_32(image, (void*)¬e->desc.virt_size); - note->found = 2; + if (head.descsz == sizeof(note->desc)) + note->desc.load_base = bfd_get_32(image, (void*)¬e->desc.load_base); + else + note->desc.load_base = CHIRP_LOAD_BASE; } } @@ -932,9 +1545,10 @@ emul_chirp_create(device *root, bfd *image, const char *name) { - os_emul_data *data; + os_emul_data *chirp; + device *node; chirp_note note; - int big_endian; + int i; /* Sanity check that this really is the chosen emulation */ if (name == NULL && image == NULL) @@ -947,204 +1561,347 @@ emul_chirp_create(device *root, && 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(¬e, 0, sizeof(note)); if (image != NULL) bfd_map_over_sections(image, map_over_chirp_note, ¬e); - if (name == NULL && image != NULL && !note.found) + if (name == NULL && image != NULL && note.found == note_missing) return NULL; + /* Assume that it is a chirp emulation */ + + chirp = ZALLOC(os_emul_data); + chirp->root = root; + chirp->services = services; + /* 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 != (signed32)-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) { + if (chirp->virt_base != tree_find_integer_property(root, "/options/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); + } + + return chirp; } static void @@ -1152,7 +1909,6 @@ emul_chirp_init(os_emul_data *emul_data, int nr_cpus) { emul_data->state = serving; - cap_init(emul_data->phandles); } static int @@ -1172,7 +1928,7 @@ emul_chirp_instruction_call(cpu *processor, 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]; @@ -1181,39 +1937,51 @@ emul_chirp_instruction_call(cpu *processor, 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)); - /* look it up */ 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)); - 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: |