- PSIM - model of a PowerPC platform
+ PSIM - model a PowerPC platform
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>.
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-This directory contains the program PSIM that implements a model of a
-PowerPC platform. PSIM can either be built standalone or as part of
-the debugger GDB.
+This directory contains the source code to the program PSIM that
+implements a model of a PowerPC platform. PSIM can either be built
+standalone or as part of the debugger GDB.
What is PSIM?
- PSIM is an ANSI C program that models a PowerPC platform.
- The platform it implements can vary from:
+ PSIM is an ANSI C program that can be configured to model
+ various PowerPC platforms.
+
+ The platform that is modeled can vary from:
o A user program environment (UEA) complete
with emulated system calls
to
o A hardware platform with several processors
- interacting with each other and modeled hardware.
+ interacting with each other and various
+ modeled hardware devices.
+
+
+Is the source code available?
+
+ Yes.
+
+ The source code to PSIM is available under the terms of
+ the GNU Public Licence. This allows you to distribute
+ the source code for free but with certain conditions.
What motivated PSIM?
ENDIAN SUPORT
- PSIM implements all of Big-endian, little-endian
- and PowerPC little endian (XOR endian).
+ PSIM implements the PowerPC's big and little (xor
+ endian) modes and correctly simulates code that
+ switches between these two modes.
+
+ In addition, psim can model a true little-endian
+ machine.
- ISA models
+ ISA models (Instruction Set Architecture)
- PSIM includes a model of UEA, VEA and OEA. This
+ PSIM includes a model of the UEA, VEA and OEA. This
inclues the time base registers (VEA) and HTAB
and BATS (OEA).
In addition, a preliminary model of the 64 bit
- PowerPC architecture is included.
+ PowerPC architecture is implemented.
Hardware
PSIM's internals are based around the concept
of a Device Tree. This tree intentionaly
resembles that of the Device Tree found in
- OpenBoot firmware. Psim is flexable enough
+ OpenBoot firmware. PSIM is flexable enough
to allow the user to fully configure the
actual hardware model from a device tree
- specification taken from a file.
+ specification that is read in from a file.
+
+ A user can either run a program using one of
+ PSIM's built in hardware models specify a
+ custom hardware model that should be simulated.
+
+ A user is also able to quickly add a model
+ of new hardware devices so that they can be
+ included in a custom hardware model.
- PSIM also contains several built in device
- trees.
-
Emulation
PSIM is able (UEA) to emulate UNIX calls
the ROM rom calls found in common firmware
(OpenBoot and BUGAPI).
- floating point
+ Floating point
Preliminary suport for floating point is included.
Real kernels don't need floating point.
-Can PSIM model a CHRP a.k.a. PowerPC Platform machine?
+Is PSIM CHRP Compliant?
+
+ No.
+
+ However, PSIM does include all the hooks that are needed to
+ construct a model of a CHRP compliant platform.
+
+ That is:
+
+ o OpenBoot client software
+
+ o OpenPIC interrupt controller
+
+ o Hooks to implement a RTAS interface
- No. but that is now one of its main objectives. (Did you notice
- it was written PowerPC Platform instead of PowerPC platform?).
+ o the ability to add a model of each of the
+ hardware devices required by a CHRP compliant
+ desktop.
How do I build PSIM?
- To build PSIM you will need the following:
+ To build PSIM you will need the following files:
+
gdb-4.15.tar.gz From your favorite GNU ftp site.
I've also tested psim-951016 with
- gdb-4.15.1.
+ gdb-4.15.1. If you would prefer
+ a graphical development environment
+ then PSIM can also be built with
+ gdbtk.
ftp://ftp.ci.com.au/pub/clayton/README.pim
This file.
+
ftp://ftp.ci.com.au/pub/clayton/gdb-4.15+psim-951016.diff.gz
This contains a few minor patches to
gdb-4.15 so that will include psim
when it is built.
- ftp://ftp.ci.com.au/pub/clayton/gdb-4.15+psim-951016.tar.gz
-
- This contains the psim files propper.
ftp://ftp.ci.com.au/pub/clayton/psim-test-951016.tar.gz
(Optional) A scattering of pre-compiled
programs that run under the simulator.
+
+ ftp://ftp.ci.com.au/pub/clayton/gdb-4.15+psim-951016.tar.gz
+
+ This contains the psim files proper.
+
+
gcc Again available from your favorite
GNU ftp site.
+
patch Sun's patch behaves a little wierd
and doesn't appear to like creating
- empty files.
-
-
- Since PSIM is still being developed, from time to time, to meet
- a specific analysts needsfurther psim snap shots are occasionally
- made available. These snapshots may or may not work with GDB-4.15.
- Several of the more recent snapshots are:
+ empty files. You may want to consider
+ installing gnu's patch.
- ftp://ftp.ci.com.au/pub/clayton/psim-951218.tar.gz
- Hopefully merges in Michael stuff
- with mine, adds multiple emulations
- (OpenBoot and NetBSD), revamps
- inline stuff, rearanges devices so
- that phandls and ihandles can be
- implemented.
+ In addition, I'm slowly building up a set of useful patches
+ to gdb-4.15 that are useful. You will want to also apply
+ these patches:
- ftp://ftp.ci.com.au/pub/clayton/psim-951203.tar.gz
- A good snapshot
+ ftp://ftp.ci.com.au/pub/clayton/gdb-4.15+attach.diff.gz
- This includes extensions from Michael
- Meissner that add monitoring of the
- PowerPC's register and bus architectures.
+ Patch to gdb that allows the `attach'
+ command to be used when connecting to a
+ simulator.
+ See that file for more information.
- ftp://ftp.ci.com.au/pub/clayton/psim-test-951218.tar.gz
+ ftp://ftp.ci.com.au/pub/clayton/gdb-4.15+note.diff.gz
- Prebuilt test programs for PSIM.
- Includes examples of UEA, VEA and
- OEA code.
- Requires gcc-2.7.2 and binutils-2.6
- to rebuild.
+ Patch to gdb's bfd that adds basic support
+ for a .note section. OpenBoot makes
+ use of a .note section when loading a
+ boot image.
Procedure:
$ gunzip < ../gdb-4.15+psim-951016.tar.gz | tar tvf -
$ gunzip < ../gdb-4.15+psim-951016.tar.gz | tar xvf -
+ You may also want to consider applying the `attach' and
+ `note' patches that are available vis:
+
+ $ gunzip < ../gdb-4.15+attach.diff.gz | more
+ $ gunzip < ../gdb-4.15+attach.diff.gz | patch -p
+
+ $ gunzip < ../gdb-4.15+note.diff.gz | more
+ $ gunzip < ../gdb-4.15+note.diff.gz | patch -p
+
3. Configure gdb
$ cp sim/ppc/run ~/bin/powerpc-unknown-eabisim-run
+Is there a more recent version of PSIM and if so, how would I build it?
+
+ A PSIM is an ongoing development, occasional snapshots
+ (that include new features) are made available. Several of
+ the more recent snapshots are:
+
+ ftp://ftp.ci.com.au/pub/clayton/psim-951219.tar.gz
+
+ Hopefully merges in Michael stuff
+ with mine, adds multiple emulations
+ (OpenBoot and NetBSD), revamps
+ inline stuff, rearanges devices so
+ that phandls and ihandles can be
+ implemented.
+
+ ftp://ftp.ci.com.au/pub/clayton/psim-951203.tar.gz
+
+ A good snapshot
+
+ This includes extensions from Michael
+ Meissner that add monitoring of the
+ PowerPC's register and bus architectures.
+
+
+ To build/install one of these snapshots, you replace the
+ current gdb/sim/ppc directory with the one in the update,
+ re-configure and rebuild.
+
+ Procedure:
+
+ 0. A starting point
+
+ $ cd gdb-4.15
+
+
+ 1. Remove the old psim directory
+
+ $ mv sim/ppc sim/old.ppc
+
+
+ 2. Unpack the new one
+
+ $ gunzip < ../psim-960105.tar.gz | tar tf -
+ $ gunzip < ../psim-960105.tar.gz | tar tf -
+
+
+ 3. Reconfig/rebuild (as seen above):
+
+ $ CC=gcc ./configure --target=powerpc-unknown-eabisim
+ $ make CC=gcc
+
+
+Are there any example programs that can be run on PSIM?
+
+ Psim has a simple test suite that is used to ensure
+ that fixes do not introduce new bugs. This test suite
+ like psim is updated:
+
+ ftp://ftp.ci.com.au/pub/clayton/psim-test-951218.tar.gz
+
+ Prebuilt test programs for PSIM.
+ Includes examples of UEA, VEA and
+ OEA code.
+ Requires gcc-2.7.2 and binutils-2.6
+ to rebuild.
+
+ ftp://ftp.ci.com.au/pub/clayton/psim-test-951016.tar.gz
+
+ (Optional) A scattering of pre-compiled
+ programs that run under the simulator.
+
+
How do I use the simulator?
- (I assume that you've unpacked the psim-test archive).
+ I assume that you've unpacked a psim-test archive.
+
1. As a standalone program
Print out the users environment:
- $ powerpc-unknown-eabisim-run envp
+ $ powerpc-unknown-eabisim-run psim-test/uea/envp
Print out the arguments:
- $ powerpc-unknown-eabisim-run argv a b c
+ $ powerpc-unknown-eabisim-run psim-test/uea/argv a b c
Check that sbrk works:
- $ powerpc-unknown-eabisim-run break
+ $ powerpc-unknown-eabisim-run psim-test/uea/break
2. Example of running GDB:
The main thing to note is that before you can run the simulator
you must enable it. The example below illustrates this:
- $ powerpc-unknown-eabisim-gdb envp
+ $ powerpc-unknown-eabisim-gdb psim-test/uea/envp
(gdb) target sim
(gdb) load
(gdb) break main
.
+ 3. Using a device tree as a description of a machine
+ (I assume that you have applied the attach bug).
+
+ $ cd psim-test/tree
+ $ powerpc-unknown-eabisim-gdb
+ (gdb) target sim
+ (gdb) attach device-tree
+ (gdb) run
+
+ or
+
+ $ cd psim-test/tree
+ $ powerpc-unknown-eabisim-run device-tree
+
+
Where do I send bugs or report problems?
There is a mailing list (subscribe through majordomo@ci.com.au) (that
that e-mail list.
-Are there any known problems?
-
- See the ChangeLog file looking for lines taged with the word FIXME.
-
- COREFILE.C: The implementation of corefile.c (defined by
- corefile.h) isn't the best. It is intended to be functionaly
- correct rather than fast. One option being considered
- is to add a data cache to reduce the overhead of the most
- common case of data read/writes.
-
- HTAB (page) code for OEA model untested. Some of the vm code
- instructions unimplemented.
-
- Lacks PowerOpen (a.k.a. XCOFF a.k.a. AIX) and NT startups. The
- PowerOpen worked until I added the ELF one.
-
- Missing VEA system calls.
-
- Missing or commented out instructions.
-
- 64bit target untested.
-
- 64bit host broken. For instance use of scanf "%x", &long long.
-
- Event code for pending events from within signal handlers not
- finished/tested.
-
- Better and more devices.
+Does PSIM have any limitations or problems?
- PORTABILITY (Notes taken from Michael Meissner): Heavy use of the ##
- operator - fix using the clasic X/**/Y hack; Use of the signed
- keyword. In particular, signed char has no analogue in classic C
- (though most implementations of classic C use signed chars); Use of
- long long which restricts the target compiler to be GCC.
+ See the file PROBLEMS (included in the distribution) for any
+ outstanding issues.
Who helped?
unsigned_word catching_instruction_ea;
cap *phandles;
device *root;
+ chirp_services *services;
};
+/* Read in the argument list and make the most basic check that number
+ of argumnets are consistent with what was expected */
+
+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)
+{
+ 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)));
+ return -1;
+ }
+ return 0;
+}
+
+
/* OpenBoot emulation functions */
+/* client interface */
+
+static int
+chirp_emul_test(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ struct test_args {
+ unsigned32 service;
+ unsigned32 n_args;
+ unsigned32 n_returns;
+ /*in*/
+ unsigned32 name; /*string*/
+ /*out*/
+ unsigned32 missing;
+ } args;
+ char name[32];
+ chirp_services *service = data->services;
+ /* read in the arguments */
+ if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
+ return -1;
+ emul_read_string(name, T2H_4(args.name), sizeof(name),
+ processor, cia);
+ TRACE(trace_os_emul, ("test - in - name=`%s'\n", name));
+ /* see if we know about the service */
+ while (service->name != NULL && strcmp(service->name, name) != 0) {
+ service++;
+ }
+ if (service->name == NULL)
+ args.missing = -1;
+ else
+ args.missing = 0;
+ /* 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);
+ return 0;
+}
+
+
+/* Device tree */
+
+static int
+chirp_emul_peer(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ struct peer_args {
+ unsigned32 service;
+ unsigned32 n_args;
+ unsigned32 n_returns;
+ /*in*/
+ unsigned32 phandle;
+ /*out*/
+ unsigned32 sibling_phandle;
+ } args;
+ device *dev;
+ device *sibling_dev = NULL;
+ /* read in the arguments */
+ if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
+ return -1;
+ dev = cap_internal(data->phandles, 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))));
+ /* 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);
+ /* 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);
+ return 0;
+}
+
static int
chirp_emul_child(os_emul_data *data,
cpu *processor,
} args;
device *dev;
device *child_dev;
- emul_read_buffer(&args, data->arguments,
- sizeof(args),
- processor, cia);
- if (T2H_4(args.n_args) != 1 || T2H_4(args.n_returns) != 1) {
- TRACE(trace_os_emul, ("child - invalid nr - n_args=%ld, n_returns=%ld\n",
- (long)T2H_4(args.n_args),
- (long)T2H_4(args.n_returns)));
+ /* read the arguments in */
+ if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
return -1;
- }
- /* read in the arguments */
dev = cap_internal(data->phandles, 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))));
+ /* find a child */
if (dev == (device*)0)
return -1;
child_dev = device_child(dev);
args.child_phandle = 0;
else
args.child_phandle = cap_external(data->phandles, child_dev);
+ /* 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,
}
static int
-chirp_emul_exit(os_emul_data *data,
- cpu *processor,
- unsigned_word cia)
+chirp_emul_parent(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
{
- cpu_halt(processor, cia, was_exited, 0); /* always succeeds */
+ struct parent_args {
+ unsigned32 service;
+ unsigned32 n_args;
+ unsigned32 n_returns;
+ /*in*/
+ unsigned32 phandle;
+ /*out*/
+ unsigned32 parent_phandle;
+ } args;
+ device *dev;
+ device *parent_dev;
+ /* read the args in */
+ if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
+ return -1;
+ dev = cap_internal(data->phandles, 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))));
+ /* 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);
+ /* 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);
return 0;
}
static int
-chirp_emul_finddevice(os_emul_data *data,
+chirp_emul_instance_to_package(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: instance-to-package unimplemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_getproplen(os_emul_data *data,
cpu *processor,
unsigned_word cia)
{
- struct finddevice_args {
+ struct getproplen_args {
unsigned32 service;
unsigned32 n_args;
unsigned32 n_returns;
/*in*/
- unsigned32 device_specifier;
- /*out*/
unsigned32 phandle;
+ unsigned32 name;
+ /*out*/
+ unsigned32 proplen;
} args;
- char device_specifier[1024];
+ char name[32];
device *dev;
- emul_read_buffer(&args, data->arguments,
- sizeof(args),
- processor, cia);
- if (T2H_4(args.n_args) != 1 || T2H_4(args.n_returns) != 1) {
- TRACE(trace_os_emul, ("finddevice - invalid nr - n_args=%ld, n_returns=%ld\n",
- (long)T2H_4(args.n_args),
- (long)T2H_4(args.n_returns)));
+ const device_property *prop;
+ /* read the args in */
+ if (chirp_read_args(&args, sizeof(args), 2, 1, data, processor, cia))
return -1;
- }
- emul_read_string(device_specifier,
- T2H_4(args.device_specifier),
- sizeof(device_specifier),
- processor, cia);
- TRACE(trace_os_emul, ("finddevice - in - device_specifier=`%s'\n",
- device_specifier));
- dev = device_tree_find_device(data->root,
- device_specifier);
+ dev = cap_internal(data->phandles, args.phandle);
+ /* find our prop and get its length */
if (dev == (device*)0)
- args.phandle = -1;
- else
- args.phandle = cap_external(data->phandles, dev);
- TRACE(trace_os_emul, ("finddevice - out - phandle=0x%lx(0x%lx`%s')\n",
+ return -1;
+ emul_read_string(name,
+ T2H_4(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))));
+ (dev == NULL ? "" : device_name(dev)),
+ name));
+ prop = device_find_property(dev, name);
+ if (prop == (device_property*)0) {
+ args.proplen = -1;
+ }
+ else {
+ args.proplen = H2T_4(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);
char name[32];
device *dev;
const device_property *prop;
- emul_read_buffer(&args, data->arguments,
- sizeof(args),
- processor, cia);
- if (T2H_4(args.n_args) != 4 || T2H_4(args.n_returns) != 1) {
- TRACE(trace_os_emul, ("getprop - invalid nr - n_args=%ld, n_returns=%ld\n",
- (long)T2H_4(args.n_args),
- (long)T2H_4(args.n_returns)));
+ /* read in the args */
+ if (chirp_read_args(&args, sizeof(args), 4, 1, data, processor, cia))
return -1;
- }
- /* read in the arguments */
dev = cap_internal(data->phandles, args.phandle);
emul_read_string(name,
T2H_4(args.name),
name,
(unsigned long)T2H_4(args.buf),
(unsigned long)T2H_4(args.buflen)));
+ /* get the property */
if (dev == (device*)0)
return -1;
prop = device_find_property(dev, name);
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,
}
static int
-chirp_emul_getproplen(os_emul_data *data,
+chirp_emul_nextprop(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: nextprop not implemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_setprop(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: setprop not implemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_canon(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: canon not implemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_finddevice(os_emul_data *data,
cpu *processor,
unsigned_word cia)
{
- struct getproplen_args {
+ struct finddevice_args {
unsigned32 service;
unsigned32 n_args;
unsigned32 n_returns;
/*in*/
- unsigned32 phandle;
- unsigned32 name;
+ unsigned32 device_specifier;
/*out*/
- unsigned32 proplen;
+ unsigned32 phandle;
} args;
- char name[32];
+ char device_specifier[1024];
device *dev;
- const device_property *prop;
- emul_read_buffer(&args, data->arguments,
- sizeof(args),
- processor, cia);
- if (T2H_4(args.n_args) != 2 || T2H_4(args.n_returns) != 1) {
- TRACE(trace_os_emul, ("getproplen - invalid nr - n_args=%ld, n_returns=%ld\n",
- (long)T2H_4(args.n_args),
- (long)T2H_4(args.n_returns)));
+ /* get the args */
+ if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
return -1;
- }
- /* read in the arguments */
- dev = cap_internal(data->phandles, args.phandle);
- if (dev == (device*)0)
- return -1;
- emul_read_string(name,
- T2H_4(args.name),
- sizeof(name),
+ emul_read_string(device_specifier,
+ T2H_4(args.device_specifier),
+ sizeof(device_specifier),
processor, cia);
- TRACE(trace_os_emul, ("getproplen - in - phandle=0x%lx(0x%lx`%s') name=`%s'\n",
+ 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)
+ args.phandle = -1;
+ else
+ args.phandle = cap_external(data->phandles, dev);
+ /* 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)),
- name));
- prop = device_find_property(dev, name);
- if (prop == (device_property*)0) {
- args.proplen = -1;
- }
- else {
- args.proplen = H2T_4(prop->sizeof_array);
- }
- TRACE(trace_os_emul, ("getproplen - out - proplen=%ld\n",
- (unsigned long)T2H_4(args.proplen)));
+ (dev == NULL ? "" : device_name(dev))));
emul_write_buffer(&args, data->arguments,
sizeof(args),
processor, cia);
}
static int
+chirp_emul_instance_to_path(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: instance_to_path not implemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_package_to_path(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: package_to_path not implemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_call_method(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: call-method implemented\n");
+ return 0;
+}
+
+
+/* Device I/O */
+
+static int
chirp_emul_open(os_emul_data *data,
cpu *processor,
unsigned_word cia)
unsigned32 ihandle;
} args;
char name[1024];
- emul_read_buffer(&args, data->arguments,
- sizeof(args),
- processor, cia);
- if (T2H_4(args.n_args) != 1 || T2H_4(args.n_returns) != 1) {
- TRACE(trace_os_emul, ("open - invalid nr - n_args=%ld, n_returns=%ld\n",
- (long)T2H_4(args.n_args),
- (long)T2H_4(args.n_returns)));
+ /* read the args */
+ if (chirp_read_args(&args, sizeof(args), 1, 1, data, processor, cia))
return -1;
- }
- /* read in the arguments */
emul_read_string(name,
T2H_4(args.device_specifier),
sizeof(name),
processor, cia);
TRACE(trace_os_emul, ("open - in - device_specifier=`%s'\n",
name));
+ /* open the device */
printf_filtered("OpenBoot - open unimplemented for %s\n", name);
args.ihandle = -1;
+ /* 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,
}
static int
-chirp_emul_parent(os_emul_data *data,
- cpu *processor,
- unsigned_word cia)
+chirp_emul_close(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
{
- struct parent_args {
- unsigned32 service;
- unsigned32 n_args;
- unsigned32 n_returns;
- /*in*/
- unsigned32 phandle;
- /*out*/
- unsigned32 parent_phandle;
- } args;
- device *dev;
- device *parent_dev;
- emul_read_buffer(&args, data->arguments,
- sizeof(args),
- processor, cia);
- if (T2H_4(args.n_args) != 1 || T2H_4(args.n_returns) != 1) {
- TRACE(trace_os_emul, ("parent - invalid nr - n_args=%ld, n_returns=%ld\n",
- (long)T2H_4(args.n_args),
- (long)T2H_4(args.n_returns)));
- return -1;
- }
- /* read in the arguments */
- dev = cap_internal(data->phandles, 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))));
- 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);
- 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);
+ error("chirp: close not implemented\n");
return 0;
}
static int
-chirp_emul_peer(os_emul_data *data,
+chirp_emul_read(os_emul_data *data,
cpu *processor,
unsigned_word cia)
{
- struct peer_args {
+ struct read_args {
unsigned32 service;
unsigned32 n_args;
unsigned32 n_returns;
/*in*/
- unsigned32 phandle;
+ unsigned32 ihandle;
+ unsigned32 addr;
+ unsigned32 len;
/*out*/
- unsigned32 sibling_phandle;
+ unsigned32 actual;
} args;
- device *dev;
- device *sibling_dev = NULL;
- emul_read_buffer(&args, data->arguments,
- sizeof(args),
- processor, cia);
- if (T2H_4(args.n_args) != 1 || T2H_4(args.n_returns) != 1) {
- TRACE(trace_os_emul, ("peer - invalid nr - n_args=%ld, n_returns=%ld\n",
- (long)T2H_4(args.n_args),
- (long)T2H_4(args.n_returns)));
+ char buf[1024];
+ int actual;
+ /* read the args */
+ if (chirp_read_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",
+ (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';
}
- /* read in the arguments */
- dev = cap_internal(data->phandles, 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))));
- 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);
- 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))));
+ else {
+ args.actual = 0;
+ }
+ /* 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);
}
static int
-chirp_emul_read(os_emul_data *data,
+chirp_emul_write(os_emul_data *data,
cpu *processor,
unsigned_word cia)
{
- struct read_args {
+ struct write_args {
unsigned32 service;
unsigned32 n_args;
unsigned32 n_returns;
} args;
char buf[1024];
int actual;
- emul_read_buffer(&args, data->arguments,
- sizeof(args),
- processor, cia);
- if (T2H_4(args.n_args) != 3 || T2H_4(args.n_returns) != 1) {
- TRACE(trace_os_emul, ("read - invalid nr - n_args=%ld, n_returns=%ld\n",
- (long)T2H_4(args.n_args),
- (long)T2H_4(args.n_returns)));
+ /* get the args */
+ if (chirp_read_args(&args, sizeof(args), 3, 1, data, processor, cia))
return -1;
- }
- /* read in the arguments */
actual = T2H_4(args.len);
if (actual >= sizeof(buf))
actual = sizeof(buf) - 1;
actual,
processor, cia);
buf[actual] = '\0';
- /* read it in */
- TRACE(trace_os_emul, ("read - in - ihandle=0x%lx `%s' (%ld)\n",
+ TRACE(trace_os_emul, ("write - in - ihandle=0x%lx `%s' (%ld)\n",
(unsigned long)args.ihandle, buf, (long)actual));
- read(BE2H_4(args.ihandle), buf, actual);
- args.actual = H2T_4(actual);
- TRACE(trace_os_emul, ("read - out - actual=%ld\n",
+ /* write it out */
+ actual = write(BE2H_4(args.ihandle), buf, actual);
+ if (actual < 0)
+ args.actual = 0;
+ else
+ args.actual = H2T_4(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),
}
static int
-chirp_emul_write(os_emul_data *data,
+chirp_emul_seek(os_emul_data *data,
cpu *processor,
unsigned_word cia)
{
- struct write_args {
+ error("chirp: seek not implemented\n");
+ return 0;
+}
+
+
+/* memory */
+
+static int
+chirp_emul_claim(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: claim not implemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_release(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: release not implemented\n");
+ return 0;
+}
+
+
+/* Control transfer */
+
+static int
+chirp_emul_boot(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: boot not implemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_enter(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: enter not implemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_exit(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ cpu_halt(processor, cia, was_exited, 0); /* always succeeds */
+ return 0;
+}
+
+static int
+chirp_emul_chain(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: chain not implemented\n");
+ return 0;
+}
+
+
+/* user interface */
+
+static int
+chirp_emul_interpret(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: interpret not implemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_set_callback(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: set_callback not implemented\n");
+ return 0;
+}
+
+static int
+chirp_emul_set_symbol_lookup(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("chirp: set_symbol_lookup not implemented\n");
+ return 0;
+}
+
+
+/* Time */
+
+static int
+chirp_emul_milliseconds(os_emul_data *data,
+ cpu *processor,
+ unsigned_word cia)
+{
+ struct test_args {
unsigned32 service;
unsigned32 n_args;
unsigned32 n_returns;
/*in*/
- unsigned32 ihandle;
- unsigned32 addr;
- unsigned32 len;
/*out*/
- unsigned32 actual;
+ unsigned32 ms;
} args;
- char buf[1024];
- int actual;
- emul_read_buffer(&args, data->arguments,
- sizeof(args),
- processor, cia);
- if (T2H_4(args.n_args) != 3 || T2H_4(args.n_returns) != 1) {
- TRACE(trace_os_emul, ("write - invalid nr - n_args=%ld, n_returns=%ld\n",
- (long)T2H_4(args.n_args),
- (long)T2H_4(args.n_returns)));
- return -1;
- }
+ unsigned64 time;
/* read in the arguments */
- actual = T2H_4(args.len);
- if (actual >= sizeof(buf))
- actual = sizeof(buf) - 1;
- emul_read_buffer(buf,
- T2H_4(args.addr),
- actual,
- processor, cia);
- buf[actual] = '\0';
- /* write it out */
- TRACE(trace_os_emul, ("write - in - ihandle=0x%lx `%s' (%ld)\n",
- (unsigned long)args.ihandle, buf, (long)actual));
- write(BE2H_4(args.ihandle), buf, actual);
- args.actual = H2T_4(actual);
- TRACE(trace_os_emul, ("write - out - actual=%ld\n",
- (long)T2H_4(args.actual)));
+ if (chirp_read_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);
+ /* 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);
}
-chirp_services services[] = {
+
+
+static chirp_services services[] = {
+
+ /* client interface */
+ { "test", chirp_emul_test },
+
+ /* device tree */
+ { "peer", chirp_emul_peer },
{ "child", chirp_emul_child },
- { "exit", chirp_emul_exit },
- { "finddevice", chirp_emul_finddevice },
- { "getprop", chirp_emul_getprop },
+ { "parent", chirp_emul_parent },
+ { "instance-to-package", chirp_emul_instance_to_package },
{ "getproplen", chirp_emul_getproplen },
+ { "getprop", chirp_emul_getprop },
+ { "nextprop", chirp_emul_nextprop },
+ { "setprop", chirp_emul_setprop },
+ { "canon", chirp_emul_canon },
+ { "finddevice", chirp_emul_finddevice },
+ { "instance-to-path", chirp_emul_instance_to_path },
+ { "package-to-path", chirp_emul_package_to_path },
+ { "call-method", chirp_emul_call_method },
+
+ /* device I/O */
{ "open", chirp_emul_open },
- { "parent", chirp_emul_parent },
- { "peer", chirp_emul_peer },
+ { "close", chirp_emul_close },
{ "read", chirp_emul_read },
{ "write", chirp_emul_write },
+ { "seek", chirp_emul_seek },
+ { "write", chirp_emul_write },
+
+ /* memory */
+ { "claim", chirp_emul_claim },
+ { "release", chirp_emul_release },
+
+ /* control transfer */
+ { "boot", chirp_emul_boot },
+ { "enter", chirp_emul_enter },
+ { "exit", chirp_emul_exit },
+ { "chain", chirp_emul_chain },
+
+ /* user interface */
+ { "interpret", chirp_emul_interpret },
+ { "set_callback", chirp_emul_set_callback },
+ { "set_symbol_lookup", chirp_emul_set_symbol_lookup },
+
+ /* time */
+ { "milliseconds", chirp_emul_milliseconds },
+
{ 0, /* sentinal */ },
};
return;
note->found = 1;
/* check the name field */
- if (head.namesz > sizeof(name))
+ if (head.namesz > sizeof(name)) {
+ printf_filtered("open-boot warning: note name too long (%ld)\n",
+ (long)head.namesz);
return;
+ }
if (!bfd_get_section_contents(image, sect,
- name, sizeof(head), head.namesz))
+ name, sizeof(head), head.namesz)) {
+ printf_filtered("open-boot warning: note name unreadable\n");
return;
- if (strcmp(name, "PowerPC") != 0)
+ }
+ if (strcmp(name, "PowerPC") != 0) {
+ printf_filtered("open-boot warning: note name (%s) not `PowerPC'\n",
+ name);
return;
+ }
/* get the contents */
+ if (head.descsz != sizeof(note->desc)) {
+ printf_filtered("open-boot warning: note descriptor of wrong size\n");
+ return;
+ }
if (!bfd_get_section_contents(image, sect,
- ¬e->desc, sizeof(head) + head.namesz,
- head.descsz))
+ ¬e->desc, /* page align start */
+ ((sizeof(head) + head.namesz) + 3) & ~3,
+ head.descsz)) {
+ printf_filtered("open-boot warning: note descriptor unreadable\n");
return;
+ }
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);
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, 0x1); /*emul-call*/
+ 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, 0x1); /*emul-call*/
+ 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, 0x48000000); /*b .*/
+ 4, emul_loop_instruction);
device_add_integer_property(init_register,
"msr",
(msr_machine_check_enable
data->catching_instruction_ea = code_callback_va;
data->phandles = cap_create("chirp");
data->root = root;
+ data->services = services;
return data;
}
}
}
- /* return to caller */
- cpu_registers(processor)->gpr[3] = result;
- cpu_restart(processor, emul_data->return_address);
+ /* return to caller - instruction following this is a function return */
return 1;
}