Changes from Andrew
This commit is contained in:
parent
ee68a042d2
commit
93fac32455
@ -31,23 +31,29 @@ README.psim
|
||||
basics.h
|
||||
bits.c
|
||||
bits.h
|
||||
cap.c
|
||||
cap.h
|
||||
config.in
|
||||
configure
|
||||
configure.in
|
||||
corefile-n.h
|
||||
corefile.c
|
||||
corefile.h
|
||||
core_n.h
|
||||
cpu.c
|
||||
cpu.h
|
||||
debug.c
|
||||
debug.h
|
||||
device_tree.c
|
||||
device_tree.h
|
||||
devices.c
|
||||
devices.h
|
||||
device.c
|
||||
device.h
|
||||
device_table.c
|
||||
device_table.h
|
||||
dgen.c
|
||||
double.c
|
||||
dp-bit.c
|
||||
emul_bugapi.c
|
||||
emul_bugapi.h
|
||||
emul_chirp.c
|
||||
emul_chirp.h
|
||||
emul_generic.c
|
||||
emul_generic.h
|
||||
emul_netbsd.c
|
||||
@ -71,29 +77,28 @@ misc.c
|
||||
misc.h
|
||||
mon.c
|
||||
mon.h
|
||||
os_emul.c
|
||||
os_emul.h
|
||||
options.c
|
||||
options.h
|
||||
os_emul.c
|
||||
os_emul.h
|
||||
ppc-cache-rules
|
||||
ppc-instructions
|
||||
ppc-opcode-complex
|
||||
ppc-opcode-simple
|
||||
ppc-opcode-stupid
|
||||
ppc-opcode-test-1
|
||||
ppc-opcode-test-2
|
||||
ppc-spr-table
|
||||
ppc.mt
|
||||
psim.c
|
||||
psim.h
|
||||
registers.c
|
||||
registers.h
|
||||
sim_callbacks.h
|
||||
sim_calls.c
|
||||
sim-endian-n.h
|
||||
sim-endian.c
|
||||
sim-endian.h
|
||||
sim-endian-n.h
|
||||
spa-reporter.c
|
||||
spa-system-calls.c
|
||||
spa-system-calls.h
|
||||
sim_callbacks.h
|
||||
sim_calls.c
|
||||
std-config.h
|
||||
table.c
|
||||
table.h
|
||||
|
@ -1,3 +1,208 @@
|
||||
Thu Dec 14 18:49:34 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* lf.c (lf_print_function_type): New function. Munges a function
|
||||
type so that the prefix (eg INLINE...) is inserted after the type
|
||||
but before any `*'.
|
||||
|
||||
* igen.c: Change to output functions using this.
|
||||
|
||||
Wed Dec 13 23:47:00 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
FIXME: Emul CHIRP does not correctly implement the find device
|
||||
function.
|
||||
|
||||
FIXME: Emul CHIRP and device do not implement device instance
|
||||
operations.
|
||||
|
||||
Wed Dec 13 23:47:00 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* options.c (options_inline): Function to output meaningful
|
||||
description of the INLINE options.
|
||||
|
||||
* configure.in (inline): Replace inline magic numbers with macro
|
||||
names. Map 1->LOCALS_INLINE and 2->ALL_INLINE.
|
||||
|
||||
* inline.h, inline.c: update to use inline method.
|
||||
|
||||
* std-config.h (CPU_INLINE), cpu.h, inline.h, inline.c: make cpu.h
|
||||
inline always.
|
||||
|
||||
* std-config.h (EVENTS_INLINE): Inline events in psim.
|
||||
|
||||
Wed Dec 13 22:01:21 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* device_table.c (htab_sum_binary): DMA binaries to correct byte
|
||||
within a page.
|
||||
|
||||
Tue Dec 12 22:51:18 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* psim.c (psim_merge_device_file): Change `=' to `==', was this an
|
||||
error?
|
||||
|
||||
Tue Dec 5 11:56:14 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* ppc-instructions (ppc_nr_mtcrf_crs, ppc_branch_conditional_name,
|
||||
ppc_function_unit_name): Simplify by declaring these arrays as
|
||||
pure and simple static (instead of STATIC_MODEL).
|
||||
|
||||
Tue Dec 5 00:45:34 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* sim_calls.c (sim_create, sim_load), main.c (main), psim.c: Pass
|
||||
an options device into psim_create() so that options can be merged
|
||||
into the tree.
|
||||
|
||||
* device.c (*add*): Change semantics so the add functions only add
|
||||
when the new device (or property) doesn't already exist. This
|
||||
allows merging of options and data.
|
||||
|
||||
Mon Dec 4 17:12:13 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* Makefile.in (BASICS_H): Didn't include basics.h in the list of
|
||||
header files to depend on.
|
||||
|
||||
Mon Dec 4 17:12:13 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* std-config.h: (*_MODULE): Extend the <module>_inline macro's so
|
||||
that they also allow control over static functions. Rewrite
|
||||
document to reflect this.
|
||||
|
||||
* std-config.h: (INLINE): Simplify definition, the above and
|
||||
earlier changes to igen.h eliminate the need to be defensive about
|
||||
enabling the inline of static functions.
|
||||
|
||||
* std-config.h: (SIM_ENDIAN_INLINE, BITS_INLINE): Document limited
|
||||
suport for inlineing of modules for all callers. Adjust relevant
|
||||
macro's so that DEFAULT_INLINE will enable this.
|
||||
|
||||
* basics.h: Re-order #includes and definitions so that c-code for
|
||||
basic include files does not call functions delcared in later
|
||||
#includes.
|
||||
|
||||
* basics.h (__attribute__), sim_callbacks.h: Move attribute macro
|
||||
to basics.h and add hack (include <stdio.h>) to try and bring that
|
||||
and other possible conflicting macros into scope much earler.
|
||||
|
||||
* sim-endian.h,c (SIM_ENDIAN_INLINE) bits.h,c (BITS_INLINE):
|
||||
Change to use the updated inline definitions. If enabled
|
||||
immediatly include the corresponding c-code so that it will inline
|
||||
for all modules.
|
||||
|
||||
* inline.h, inline.c (SIM_ENDIAN_INLINE, BITS_INLINE): Remove
|
||||
these cases, moved to module specific header files.
|
||||
|
||||
Sat Dec 2 18:37:51 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* vm.c, vm_n.c: Fix htab code.
|
||||
|
||||
* vm.c (vm_data_map_read_buffer): Was using EA not RA when reading
|
||||
the data from core.
|
||||
|
||||
* device.c: Fix htab create code.
|
||||
|
||||
Fri Nov 24 23:10:09 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* bits.h, bits.c (EXTRACTED): Convert to function, fix - had &&
|
||||
instead of &.
|
||||
|
||||
* sim-endian.h (SWAP_N), sim-endian-n.h, sim-endian.c: How
|
||||
embarasing - fix yet another bug in the swap code! Simplify
|
||||
everything by using more functions. Add host to big-endian byte
|
||||
swapping support.
|
||||
|
||||
Fri Nov 24 23:10:09 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* devices.h, devices.c: delete, replaced by the files
|
||||
device_table.[ch] and device.[ch].
|
||||
* device_tree.h, device_tree.c: ditto
|
||||
|
||||
* device_table.h, device_table.c: New files. Contain a table of
|
||||
devices.
|
||||
|
||||
* device.h, device.c, Makefile.in, std-config.h (DEVICE_INLINE),
|
||||
options.c (print_options): New files. Define the device object
|
||||
along with any attached properties.
|
||||
|
||||
* device_tree.h, device_tree.c: Update to use new device object.
|
||||
For convenience, change the printd functions into device_tree_add
|
||||
functions.
|
||||
|
||||
* psim.c (create_*_tree): Use new device_tree create functions.
|
||||
|
||||
* corefile.h, corefile.c corefile-n.h (core_n.h): Update to use
|
||||
the new device.h / device_table.h interface. Rename core_n.h to
|
||||
corefile-n.h to be consistent with other n files.
|
||||
|
||||
* Makefile.in (run): add corefile-n.h to dependencies for
|
||||
corefile.
|
||||
|
||||
* basics.h (device_instance), device.h, device.c, device_table.h,
|
||||
device_table.c: Add the concept of a device instance and operators
|
||||
on these instances - corresponds to ihandle in OpenBoot speak.
|
||||
Don't yet implement it.
|
||||
|
||||
Tue Nov 14 12:27:08 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* emul_generic.h, emul_generic.c (emul_syscall_enter,
|
||||
emul_syscall_exit): rename from emul_enter_call /
|
||||
emul_exit_call. As only used by emul_do_system_call simplify
|
||||
associated code.
|
||||
|
||||
* os_emul.h, os_emul.c, emul_generic.h: Correct and fill an
|
||||
os_emul interface.
|
||||
|
||||
* os_emul.c, emul_bugapi.h, emul_bugapi.c, Makefile.in: Add
|
||||
preliminary hooks for a kernel mode rom emulation.
|
||||
|
||||
* cap.h (new), cap.c (new): Capability data base. Some emulations
|
||||
pass object identifiers (capabilities?) to/from the simulated code
|
||||
(for instance the phandle in OpenBoot). The cap object is able to
|
||||
check/map between internal and external (target program)
|
||||
representations of each identifier.
|
||||
|
||||
* os_emul.c, emul_chirp.h, emul_chirp.c, Makefile.in: Add
|
||||
preliminary hooks for a kernel mode IEEE-1275 emulation.
|
||||
|
||||
* cpu.h, cpu.c (cpu_create, cpu_os_emulation, cpu): Add os_emul to
|
||||
list of arguments passed in when creating a cpu. Grant access to
|
||||
the element.
|
||||
|
||||
* std-config.h (OS_EMUL_INLINE), options.c (print_options),
|
||||
inline.h, inline.c: New to allow control over inline of
|
||||
corresponding code files.
|
||||
|
||||
* ppc-instructions (instruction_call): Add illegal instruction to
|
||||
call the instruction-call emulation handler.
|
||||
|
||||
* interrupts.c (system_call_interrupt): Call renamed
|
||||
os_emul_system_call function().
|
||||
|
||||
* emul_netbsd.c: Update to interface to generic emulation. Since
|
||||
all its functions are called via a table don't worry about any
|
||||
inline.
|
||||
|
||||
* emul_generic.h, emul_generic.c, spa-*(delete): Remove references
|
||||
and code for spa, no longer to be used.
|
||||
|
||||
* psim.c (create_chirp_device_tree): Fill out what was previously
|
||||
the openboot create function so that it starts to create a full
|
||||
OpenBoot device tree.
|
||||
|
||||
Tue Nov 28 21:48:06 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* debug.h, debug.c: pte trace is made redundant by htab trace,
|
||||
delete it. Add vm to list of options. Simplify tracing output so
|
||||
lines are not as long.
|
||||
|
||||
Tue Nov 14 12:27:08 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
* events.h, events.c (event_queue_init), psim.c (psim_init): (re)
|
||||
initialize the event queue.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Tue Nov 28 13:38:26 1995 Michael Meissner <meissner@tiktok.cygnus.com>
|
||||
|
||||
* sim-endian.h: Look at WORDS_BIGENDIAN to determine if the host
|
||||
@ -1020,9 +1225,6 @@ Mon Oct 23 23:48:59 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
DEVICE_TREE_INLINE or INTERRUPTS_INLINE as none of these are on
|
||||
the instruction or data critical paths.
|
||||
|
||||
* FIXME: need to set up OS_EMUL_INLINE/EMUL_GENERIC_INLINE but
|
||||
not on critical path.
|
||||
|
||||
* FIXME: devices.c/emul_netbsd.c would benefit (slightly) from
|
||||
the inclusion of device_tree.c/emul_generic.c.
|
||||
|
||||
@ -1064,10 +1266,6 @@ Sun Oct 22 19:27:48 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
* NOTE: mon does not contain to count instruction loads as this
|
||||
information is already available from the mon_issue() hook.
|
||||
|
||||
* FIXME: mon doesn't have access to register usage information.
|
||||
This is needed if the user wants to monitor things like register
|
||||
stalls.
|
||||
|
||||
* igen.c (lf_print_c_semantic), vm_n.h: Add counting code.
|
||||
|
||||
* psim.h, psim.c (psim_create), cpu.h, cpu.c (cpu_create): Attach
|
||||
@ -1106,9 +1304,6 @@ Wed Oct 18 23:02:20 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
cache-rule and opcode-rule tables from macros found std-config.h.
|
||||
Delete corresponding macro's from std-config.h.
|
||||
|
||||
* FIXME: under this new igen scheme, when playing around with igen
|
||||
options, you'll find that depenencies don't work very well.
|
||||
|
||||
* igen.c (gen_itable_c, gen_itable_h), Makefile.in: code to output
|
||||
an table of all the instructions. Code to output a type
|
||||
enumerating all the instructin names.
|
||||
@ -1141,9 +1336,6 @@ Mon Oct 16 00:31:20 1995 Andrew Cagney <cagney@highland.com.au>
|
||||
doc in bits.h, remove dead code in bits.c, move ROTL32/ROTL64 into
|
||||
bits.h.
|
||||
|
||||
* FIXME: the bits.h/bits.c macro's should be replaced with
|
||||
(inline) c functions.
|
||||
|
||||
* cpu.c(cpu_add_commas), device_tree.h, device_tree.c(scand_*):
|
||||
Add size of buffer argument to functions writing a string into a
|
||||
buffer. Check for buffer overflow.
|
||||
|
@ -3,56 +3,52 @@
|
||||
|
||||
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
|
||||
|
||||
This directory contains the program PSIM that models the PowerPC(tm -
|
||||
IBM) architecture. It can either be run stand alone (psim or run) or
|
||||
This directory contains the program PSIM that models the PowerPC (tm -
|
||||
IBM) architecture. It can be run either standalone (psim or run) or
|
||||
used as part of GDB.
|
||||
|
||||
|
||||
KNOWN FEATURES
|
||||
KNOWN FEATURES:
|
||||
|
||||
|
||||
SMP: A Symetric Multi-Processor configuration is suported. This
|
||||
includes modeling of the PowerPC load word and reserve instructions
|
||||
(if intending to use this feature you are well advised to read the the
|
||||
source code for the reservation instructions so that you are aware of
|
||||
any potential limitations in the model). The number of processors is
|
||||
selected during startup.
|
||||
SMP: It is possible to configure this simulator so that it implements
|
||||
a restricted model of a Symetric Multi-Processor architecture. It is
|
||||
important to note that the SMP model has limitations. In particular,
|
||||
the PowerPC's load word and reserve (etc) instructions do not model
|
||||
the behavour defined in the Architecture manual. People intending to
|
||||
use this feature should read the code implementing those instructions.
|
||||
|
||||
DUAL-ENDIAN: Both little and big endian models are suported. The
|
||||
execution of instruction sequences that switch between the two modes,
|
||||
however, is not. The endianess is selected during startup.
|
||||
ENDIAN SUPORT: Pure big, pure little and PowerPC little endian (xor
|
||||
endian) models are suported.
|
||||
|
||||
UIEA, VEA and OEA: The PowerPC architecture defines three levels of
|
||||
the PowerPC architecture. This simulator, to a reasonable degree, is
|
||||
capable of modeling all three. That is the User Instruction Set
|
||||
Architecture, the Virtual Environment Architecture and finally the
|
||||
Operating Environment Architecture. The environment is selected
|
||||
during startup. The OEA model is still under development.
|
||||
Operating Environment Architecture.
|
||||
|
||||
HARDWARE DEVICE TREE: In the OEA, the model of the target machines
|
||||
hardware is built from a tree of devices (bit like Open Boot).
|
||||
Included in this is the ability to model bus hierachies and
|
||||
runtime-configurable devices (eg PCI). The device tree used to create
|
||||
the hardware model is created during startup. This device tree is
|
||||
still under development.
|
||||
runtime-configurable devices (eg PCI).
|
||||
|
||||
VEA SYSTEM CALLS: In user mode, basic system calls (read, write, open,
|
||||
close ...) are emulated. Under NetBSD (simply because that is what my
|
||||
machine at home runs) the list is more extensive.
|
||||
OS EMULATION: Suport for os/firmware emulations (system or rom-calls)
|
||||
is included. At present limited implemtations of two emulations are
|
||||
included:NetBSD (UEA model) and OpenBoot (OEA model).
|
||||
|
||||
PEDANTIC VEA MEMORY MODEL: This model implements the break (brk, sbrk)
|
||||
system calls. Further, the user model has very strict memory access
|
||||
controls. User programs can not assume that they can stray off the
|
||||
end of valid memory areas. This model defines valid memory addresses
|
||||
in strict accordance to the executable and does not page allign their
|
||||
values. At first this was a bug but since then has turned up several
|
||||
problems in user code so it is now described as a feature.
|
||||
PEDANTIC VEA MEMORY MODEL: In VEA/UEA NetBSD simulations, this model
|
||||
implements the break (brk, sbrk) system calls. Further, the user
|
||||
model has very strict memory access controls. User programs can not
|
||||
assume that they can stray off the end of valid memory areas. This
|
||||
model defines valid memory addresses in strict accordance to the
|
||||
executable and does not page allign their values. At first this was a
|
||||
bug but since then has turned up several problems in user code so it
|
||||
is now described as a feature.
|
||||
|
||||
PROFILING: The simulation is able to count the number and type of
|
||||
instructions issued and the number of loads and stores. This feature
|
||||
is still under development.
|
||||
PERFORMANCE MONITORING: This simulation is able to monitor things such
|
||||
as cpu/io read/writes and register allocation.
|
||||
|
||||
PERFORMANCE: In its default configuration PSIM is constructed so that
|
||||
PERFORMANCE: In its default configuration PSIM is configured so that
|
||||
it will compile fast and run slow. Through the enabling of more
|
||||
agressive compile options (and the disabling of unwanted features) the
|
||||
build can be changed to compile slow and run fast.
|
||||
@ -65,7 +61,14 @@ BUILDING PSIM:
|
||||
|
||||
To build PSIM you will need the following:
|
||||
|
||||
gdb-4.15.tar.gz From your favorite GNU ftp site
|
||||
gdb-4.15.tar.gz From your favorite GNU ftp site.
|
||||
I've also tested psim-951016 with
|
||||
gdb-4.15.1.
|
||||
|
||||
|
||||
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
|
||||
|
||||
@ -90,10 +93,32 @@ To build PSIM you will need the following:
|
||||
empty files.
|
||||
|
||||
|
||||
In the directory ftp.ci.com.au:pub/clayton you will also notice files
|
||||
named psim-NNNNNN.tar.gz. Those, more recent snapshots, may or may
|
||||
not work with gdb.
|
||||
Since PSIM is still being developed, from time to time, further psim
|
||||
snap shots are occasionally made available. These snapshots may or
|
||||
may not work with GDB-4.15. Several of the more significant snap
|
||||
shots are:
|
||||
|
||||
ftp://ftp.ci.com.au/pub/clayton/psim-951215.tar.gz
|
||||
|
||||
A dangerous snap shot
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Procedure:
|
||||
|
||||
0. A starting point
|
||||
|
||||
@ -148,7 +173,9 @@ not work with gdb.
|
||||
5. Install
|
||||
|
||||
$ make CC=gcc install
|
||||
|
||||
or just
|
||||
|
||||
$ cp gdb/gdb ~/bin/powerpc-unknown-eabisim-gdb
|
||||
$ cp sim/ppc/run ~/bin/powerpc-unknown-eabisim-run
|
||||
|
||||
@ -194,9 +221,9 @@ is almost never used) at:
|
||||
|
||||
powerpc-psim@ci.com.au
|
||||
|
||||
If I get the ftp archive updated I post a note to that news group. In
|
||||
addition your welcome to send bugs or problems either to me or to that
|
||||
e-mail list.
|
||||
If I get the ftp archive updated I post a note to that mailing list.
|
||||
In addition your welcome to send bugs or problems either to me or to
|
||||
that e-mail list.
|
||||
|
||||
|
||||
KNOWN PROBLEMS:
|
||||
@ -209,17 +236,9 @@ best. It is intended to be functionaly correct rather than fast.
|
||||
HTAB (page) code for OEA model untested. Some of the vm code
|
||||
instructions unimplemented.
|
||||
|
||||
Flush instruction cache instructions do nothing. Perhaphs they should
|
||||
(if there is an instruction cache) flush it.
|
||||
|
||||
Lacks PowerOpen (a.k.a. XCOFF a.k.a. AIX) and NT startups. The
|
||||
PowerOpen worked until I added the ELF one.
|
||||
|
||||
OpenBoot and PR*P interfaces missing. Open boot could be implemented
|
||||
by putting special instructions at the address of the OpenBoot
|
||||
callback functions. Those instructions could than emulate OpenBoot
|
||||
behavour.
|
||||
|
||||
Missing VEA system calls.
|
||||
|
||||
Missing or commented out instructions.
|
||||
@ -247,49 +266,3 @@ Thanks go to the following who each helped in some way.
|
||||
Allen Briggs, Bett Koch, David Edelsohn, Gordon Irlam,
|
||||
Michael Meissner, Bob Mercier, Richard Perini,
|
||||
Richard Stallman, Mitchele Walker
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
|
||||
Random notes on performance:
|
||||
|
||||
|
||||
$ cd test
|
||||
time ../psim count `expr 10000000 / 2`
|
||||
time ../psim volatile-count `expr 10000000 / 7`
|
||||
|
||||
Where 2 and 7 are the number of instructions in the main loop.
|
||||
|
||||
|
||||
611/729 - baseline
|
||||
|
||||
Tests:
|
||||
|
||||
CFLAGS= -c -O2 -m486 -fomit-frame-pointer
|
||||
|
||||
o different first/second level table/switch combinations
|
||||
|
||||
0 - use a table
|
||||
1 - use a simple switch
|
||||
2 - use an expanded switch
|
||||
|
||||
i486DX4/100 - AMD
|
||||
|
||||
1/108/140 - switch=0/0/0,expand=2,inline=2,nia=1,cache=1
|
||||
1/114/140 - switch=0/0/0,expand=2,inline=2,nia=1,cache=1
|
||||
1/137/149 - switch=0/0,expand=2,inline=1,nia=1,cache=1
|
||||
1/144/155 - switch=2/1,expand=2,inline=1,nia=1,cache=1
|
||||
1/153/159 - switch=2/1,expand=0,inline=1,nia=1,cache=1
|
||||
1/185/189 - switch=0/0,expand=0,inline=1,nia=1
|
||||
|
||||
i486DX2/66
|
||||
|
||||
1/572/695 - switch=1/1,expand=0,inline=0
|
||||
1/579/729 - switch=0/0,expand=0,inline=0
|
||||
1/570/682 - switch=2/2,expand=0,inline=0
|
||||
1/431/492 - switch=0/0,expand=0,inline=1,nia=0
|
||||
1/271/292 - switch=2/1,expand=0,inline=1,nia=0
|
||||
1/270/316 - switch=2/2,expand=0,inline=1,nia=0
|
||||
1/271/281 - switch=1/1,expand=0,inline=1,nia=1
|
||||
1/267/274 - switch=2/1,expand=0,inline=1,nia=1
|
||||
|
94
sim/ppc/cap.c
Normal file
94
sim/ppc/cap.c
Normal file
@ -0,0 +1,94 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CAP_C_
|
||||
#define _CAP_C_
|
||||
|
||||
#ifndef STATIC_INLINE_CAP
|
||||
#define STATIC_INLINE_CAP STATIC_INLINE
|
||||
#endif
|
||||
|
||||
#include "cap.h"
|
||||
|
||||
typedef struct _cap_mapping cap_mapping;
|
||||
struct _cap_mapping {
|
||||
unsigned32 external;
|
||||
void *internal;
|
||||
cap_mapping *next;
|
||||
};
|
||||
|
||||
struct _cap {
|
||||
int nr_mappings;
|
||||
cap_mapping *mappings;
|
||||
};
|
||||
|
||||
INLINE_CAP cap *
|
||||
cap_create(const char *key)
|
||||
{
|
||||
return ZALLOC(cap);
|
||||
}
|
||||
|
||||
INLINE_CAP void
|
||||
cap_init(cap *map)
|
||||
{
|
||||
cap_mapping *current_mapping = map->mappings;
|
||||
while (current_mapping != NULL) {
|
||||
cap_mapping *tbd = current_mapping;
|
||||
current_mapping = tbd->next;
|
||||
zfree(tbd);
|
||||
}
|
||||
map->nr_mappings = 0;
|
||||
map->mappings = (cap_mapping*)0;
|
||||
}
|
||||
|
||||
INLINE_CAP void *
|
||||
cap_internal(cap *db,
|
||||
signed32 external)
|
||||
{
|
||||
cap_mapping *current_map = db->mappings;
|
||||
while (current_map != NULL) {
|
||||
if (current_map->external == external)
|
||||
return current_map->internal;
|
||||
current_map = current_map->next;
|
||||
}
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
INLINE_CAP signed32
|
||||
cap_external(cap *db,
|
||||
void *internal)
|
||||
{
|
||||
cap_mapping *current_map = db->mappings;
|
||||
while (current_map != NULL) {
|
||||
if (current_map->internal == internal)
|
||||
return current_map->external;
|
||||
current_map = current_map->next;
|
||||
}
|
||||
current_map = ZALLOC(cap_mapping);
|
||||
current_map->next = db->mappings;
|
||||
current_map->internal = internal;
|
||||
db->nr_mappings += 1;
|
||||
current_map->external = db->nr_mappings;
|
||||
db->mappings = current_map;
|
||||
return current_map->external;
|
||||
}
|
||||
|
||||
#endif
|
50
sim/ppc/cap.h
Normal file
50
sim/ppc/cap.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* Export a capability data base that maps between internal data
|
||||
values and those given to a simulation */
|
||||
|
||||
#ifndef _CAP_H_
|
||||
#define _CAP_H_
|
||||
|
||||
#ifndef INLINE_CAP
|
||||
#define INLINE_CAP
|
||||
#endif
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
typedef struct _cap cap;
|
||||
|
||||
INLINE_CAP cap *cap_create
|
||||
(const char *name);
|
||||
|
||||
INLINE_CAP void cap_init
|
||||
(cap *db);
|
||||
|
||||
INLINE_CAP signed32 cap_external
|
||||
(cap *db,
|
||||
void *internal);
|
||||
|
||||
INLINE_CAP void *cap_internal
|
||||
(cap *db,
|
||||
signed32 external);
|
||||
|
||||
#endif
|
@ -128,15 +128,15 @@ AC_ARG_ENABLE(sim-inline,
|
||||
case "$enableval" in
|
||||
no) sim_inline="-DDEFAULT_INLINE=0 -DINLINE=";;
|
||||
0) sim_inline="-DDEFAULT_INLINE=0";;
|
||||
yes | 2) sim_inline="-DDEFAULT_INLINE=2";;
|
||||
1) sim_inline="-DDEFAULT_INLINE=1";;
|
||||
yes | 2) sim_inline="-DDEFAULT_INLINE=ALL_INLINE";;
|
||||
1) sim_inline="-DDEFAULT_INLINE=INLINE_LOCALS";;
|
||||
*) for x in `echo "$enableval" | sed -e "s/,/ /g"`; do
|
||||
new_flag=""
|
||||
case "$x" in
|
||||
*_INLINE=*) new_flag="-D$x";;
|
||||
*_INLINE) new_flag="-D$x=2";;
|
||||
*_INLINE) new_flag="-D$x=ALL_INLINE";;
|
||||
*=*) new_flag=`echo "$x" | sed -e "s/=/_INLINE=/" -e "s/^/-D/"`;;
|
||||
*) new_flag="-D$x""_INLINE=2";;
|
||||
*) new_flag="-D$x""_INLINE=ALL_INLINE";;
|
||||
esac
|
||||
if test x"$sim_inline" = x""; then
|
||||
sim_inline="$new_flag"
|
||||
@ -148,7 +148,7 @@ esac
|
||||
if test x"$silent" != x"yes" && test x"$sim_inline" != x""; then
|
||||
echo "Setting inline flags = $sim_inline" 6>&1
|
||||
fi],[if test x"$GCC" != ""; then
|
||||
sim_inline="-DDEFAULT_INLINE=1"
|
||||
sim_inline="-DDEFAULT_INLINE=INLINE_LOCALS"
|
||||
if test x"$silent" != x"yes"; then
|
||||
echo "Setting inline flags = $sim_inline" 6>&1
|
||||
fi
|
||||
|
@ -23,19 +23,19 @@
|
||||
#error "N must be #defined"
|
||||
#endif
|
||||
|
||||
#undef unsigned_N
|
||||
/* NOTE: see end of file for #undef of these macros */
|
||||
#define unsigned_N XCONCAT2(unsigned_,N)
|
||||
#undef T2H_N
|
||||
#define T2H_N XCONCAT2(T2H_,N)
|
||||
#undef H2T_N
|
||||
#define H2T_N XCONCAT2(H2T_,N)
|
||||
|
||||
#define core_map_read_N XCONCAT2(core_map_read_,N)
|
||||
#define core_map_write_N XCONCAT2(core_map_write_,N)
|
||||
|
||||
INLINE_CORE unsigned_N
|
||||
XCONCAT2(core_map_read_,N)(core_map *map,
|
||||
unsigned_word addr,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
unsigned_N INLINE_CORE
|
||||
core_map_read_N(core_map *map,
|
||||
unsigned_word addr,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
core_mapping *mapping = core_map_find_mapping(map,
|
||||
addr,
|
||||
@ -43,15 +43,15 @@ XCONCAT2(core_map_read_,N)(core_map *map,
|
||||
processor,
|
||||
cia,
|
||||
1); /*abort*/
|
||||
if (WITH_CALLBACK_MEMORY && mapping->reader != NULL) {
|
||||
if (WITH_CALLBACK_MEMORY && mapping->device != NULL) {
|
||||
unsigned_N data;
|
||||
if (mapping->reader(mapping->device,
|
||||
&data,
|
||||
mapping->space,
|
||||
addr - mapping->base,
|
||||
sizeof(unsigned_N), /* nr_bytes */
|
||||
processor,
|
||||
cia) != sizeof(unsigned_N))
|
||||
if (device_io_read_buffer(mapping->device,
|
||||
&data,
|
||||
mapping->space,
|
||||
addr - mapping->base,
|
||||
sizeof(unsigned_N), /* nr_bytes */
|
||||
processor,
|
||||
cia) != sizeof(unsigned_N))
|
||||
error("core_read_,N() reader should not fail\n");
|
||||
return T2H_N(data);
|
||||
}
|
||||
@ -61,12 +61,12 @@ XCONCAT2(core_map_read_,N)(core_map *map,
|
||||
|
||||
|
||||
|
||||
INLINE_CORE void
|
||||
XCONCAT2(core_map_write_,N)(core_map *map,
|
||||
unsigned_word addr,
|
||||
unsigned_N val,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
void INLINE_CORE
|
||||
core_map_write_N(core_map *map,
|
||||
unsigned_word addr,
|
||||
unsigned_N val,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
core_mapping *mapping = core_map_find_mapping(map,
|
||||
addr,
|
||||
@ -74,18 +74,24 @@ XCONCAT2(core_map_write_,N)(core_map *map,
|
||||
processor,
|
||||
cia,
|
||||
1); /*abort*/
|
||||
if (WITH_CALLBACK_MEMORY && mapping->writer != NULL) {
|
||||
if (WITH_CALLBACK_MEMORY && mapping->device != NULL) {
|
||||
unsigned_N data = H2T_N(val);
|
||||
if (mapping->writer(mapping->device,
|
||||
&data,
|
||||
mapping->space,
|
||||
addr - mapping->base,
|
||||
sizeof(unsigned_N), /* nr_bytes */
|
||||
processor,
|
||||
cia) != sizeof(unsigned_N))
|
||||
if (device_io_write_buffer(mapping->device,
|
||||
&data,
|
||||
mapping->space,
|
||||
addr - mapping->base,
|
||||
sizeof(unsigned_N), /* nr_bytes */
|
||||
processor,
|
||||
cia) != sizeof(unsigned_N))
|
||||
error("core_read_,N() writer should not fail\n");
|
||||
}
|
||||
else
|
||||
*(unsigned_N*)core_translate(mapping, addr) = H2T_N(val);
|
||||
}
|
||||
|
||||
/* NOTE: see start of file for #define of these macros */
|
||||
#undef unsigned_N
|
||||
#undef T2H_N
|
||||
#undef H2T_N
|
||||
#undef core_map_read_N
|
||||
#undef core_map_write_N
|
151
sim/ppc/corefile.h
Normal file
151
sim/ppc/corefile.h
Normal file
@ -0,0 +1,151 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CORE_H_
|
||||
#define _CORE_H_
|
||||
|
||||
/* basic types */
|
||||
|
||||
typedef struct _core core;
|
||||
typedef struct _core_map core_map;
|
||||
|
||||
/* constructor */
|
||||
|
||||
core INLINE_CORE *core_create
|
||||
(void);
|
||||
|
||||
device INLINE_CORE *core_device_create
|
||||
(core *);
|
||||
|
||||
|
||||
|
||||
/* the core has three sub mappings that the more efficient
|
||||
read/write fixed quantity functions use */
|
||||
|
||||
core_map INLINE_CORE *core_readable
|
||||
(core *memory);
|
||||
|
||||
core_map INLINE_CORE *core_writeable
|
||||
(core *memory);
|
||||
|
||||
core_map INLINE_CORE *core_executable
|
||||
(core *memory);
|
||||
|
||||
|
||||
|
||||
/* operators to add/remove a mapping in the core
|
||||
|
||||
callback-memory:
|
||||
|
||||
All access are passed onto the specified devices callback routines
|
||||
after being `translated'. DEFAULT indicates that the specified
|
||||
memory should be called if all other mappings fail.
|
||||
|
||||
For callback-memory, the device must be specified.
|
||||
|
||||
raw-memory:
|
||||
|
||||
While RAM could be implemented using the callback interface
|
||||
core instead treats it as the common case including the code
|
||||
directly in the read/write operators.
|
||||
|
||||
For raw-memory, the device is ignored and the core alloc's a
|
||||
block to act as the memory.
|
||||
|
||||
default-memory:
|
||||
|
||||
Should, for the core, there be no defined mapping for a given
|
||||
address then the default map (if present) is called.
|
||||
|
||||
For default-memory, the device must be specified. */
|
||||
|
||||
void INLINE_CORE core_attach
|
||||
(core *map,
|
||||
attach_type attach,
|
||||
int address_space,
|
||||
access_type access,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes, /* host limited */
|
||||
device *device); /*callback/default*/
|
||||
|
||||
void INLINE_CORE core_detach
|
||||
(core *map,
|
||||
attach_type attach,
|
||||
int address_space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes, /* host limited */
|
||||
access_type access,
|
||||
device *device); /*callback/default*/
|
||||
|
||||
|
||||
/* Variable sized read/write:
|
||||
|
||||
Transfer (zero) a variable size block of data between the host and
|
||||
target (possibly byte swapping it). Should any problems occure,
|
||||
the number of bytes actually transfered is returned. */
|
||||
|
||||
unsigned INLINE_CORE core_map_read_buffer
|
||||
(core_map *map,
|
||||
void *buffer,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes);
|
||||
|
||||
unsigned INLINE_CORE core_map_write_buffer
|
||||
(core_map *map,
|
||||
const void *buffer,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes);
|
||||
|
||||
|
||||
/* Fixed sized read/write:
|
||||
|
||||
Transfer a fixed amout of memory between the host and target. The
|
||||
memory always being translated and the operation always aborting
|
||||
should a problem occure */
|
||||
|
||||
#define DECLARE_CORE_WRITE_N(N) \
|
||||
void INLINE_CORE core_map_write_##N \
|
||||
(core_map *map, \
|
||||
unsigned_word addr, \
|
||||
unsigned_##N val, \
|
||||
cpu *processor, \
|
||||
unsigned_word cia);
|
||||
|
||||
DECLARE_CORE_WRITE_N(1)
|
||||
DECLARE_CORE_WRITE_N(2)
|
||||
DECLARE_CORE_WRITE_N(4)
|
||||
DECLARE_CORE_WRITE_N(8)
|
||||
DECLARE_CORE_WRITE_N(word)
|
||||
|
||||
#define DECLARE_CORE_READ_N(N) \
|
||||
unsigned_##N INLINE_CORE core_map_read_##N \
|
||||
(core_map *map, \
|
||||
unsigned_word addr, \
|
||||
cpu *processor, \
|
||||
unsigned_word cia);
|
||||
|
||||
DECLARE_CORE_READ_N(1)
|
||||
DECLARE_CORE_READ_N(2)
|
||||
DECLARE_CORE_READ_N(4)
|
||||
DECLARE_CORE_READ_N(8)
|
||||
DECLARE_CORE_READ_N(word)
|
||||
|
||||
#endif
|
1155
sim/ppc/device.c
Normal file
1155
sim/ppc/device.c
Normal file
File diff suppressed because it is too large
Load Diff
660
sim/ppc/device.h
Normal file
660
sim/ppc/device.h
Normal file
@ -0,0 +1,660 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _DEVICE_TREE_H_
|
||||
#define _DEVICE_TREE_H_
|
||||
|
||||
#ifndef INLINE_DEVICE
|
||||
#define INLINE_DEVICE
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* declared in basics.h, this object is used everywhere */
|
||||
/* typedef struct _device device; */
|
||||
|
||||
|
||||
|
||||
|
||||
/* Device Tree:
|
||||
|
||||
All the devices in this model live in a tree. The following allow
|
||||
the location/manipulation of this tree */
|
||||
|
||||
device INLINE_DEVICE *device_sibling
|
||||
(device *me);
|
||||
|
||||
device INLINE_DEVICE *device_child
|
||||
(device *me);
|
||||
|
||||
device INLINE_DEVICE *device_parent
|
||||
(device *me);
|
||||
|
||||
const char INLINE_DEVICE *device_name
|
||||
(device *me);
|
||||
|
||||
void INLINE_DEVICE *device_data
|
||||
(device *me);
|
||||
|
||||
|
||||
/* Grow the device tree adding either a specific device or
|
||||
alternativly a device found in the device table */
|
||||
|
||||
device INLINE_DEVICE *device_tree_add_device
|
||||
(device *root,
|
||||
const char *prefix,
|
||||
device *new_sub_tree);
|
||||
|
||||
device INLINE_DEVICE *device_tree_add_found
|
||||
(device *root,
|
||||
const char *prefix,
|
||||
const char *name);
|
||||
|
||||
device INLINE_DEVICE *device_tree_add_found_c
|
||||
(device *root,
|
||||
const char *prefix,
|
||||
const char *name,
|
||||
const char *c1);
|
||||
|
||||
device INLINE_DEVICE *device_tree_add_found_c_uw
|
||||
(device *root,
|
||||
const char *prefix,
|
||||
const char *name,
|
||||
const char *c1,
|
||||
unsigned_word uw2);
|
||||
|
||||
device INLINE_DEVICE *device_tree_add_found_uw_u
|
||||
(device *root,
|
||||
const char *prefix,
|
||||
const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned u2);
|
||||
|
||||
device INLINE_DEVICE *device_tree_add_found_uw_u_u
|
||||
(device *root,
|
||||
const char *prefix,
|
||||
const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned u2,
|
||||
unsigned u3);
|
||||
|
||||
device INLINE_DEVICE *device_tree_add_found_uw_u_u_c
|
||||
(device *root,
|
||||
const char *prefix,
|
||||
const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned u2,
|
||||
unsigned u3,
|
||||
const char *c4);
|
||||
|
||||
device INLINE_DEVICE *device_tree_add_found_uw_uw_u_u_c
|
||||
(device *root,
|
||||
const char *prefix,
|
||||
const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned_word uw2,
|
||||
unsigned u3,
|
||||
unsigned u4,
|
||||
const char *c5);
|
||||
|
||||
device INLINE_DEVICE *device_tree_add_found_uw_uw_u_u_u
|
||||
(device *root,
|
||||
const char *prefix,
|
||||
const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned_word uw2,
|
||||
unsigned u3,
|
||||
unsigned u4,
|
||||
unsigned u5);
|
||||
|
||||
|
||||
/* Query the device tree, null is returned if the specified device is
|
||||
not found */
|
||||
|
||||
device INLINE_DEVICE *device_tree_find_device
|
||||
(device *root,
|
||||
const char *path);
|
||||
|
||||
|
||||
/* traverse the device tree visiting all notes (either pre or post
|
||||
fix) */
|
||||
|
||||
typedef void (device_tree_traverse_function)
|
||||
(device *device,
|
||||
void *data);
|
||||
|
||||
void INLINE_DEVICE device_tree_traverse
|
||||
(device *root,
|
||||
device_tree_traverse_function *prefix,
|
||||
device_tree_traverse_function *postfix,
|
||||
void *data);
|
||||
|
||||
|
||||
/* dump a node, this can be passed to the device_tree_traverse()
|
||||
function to dump out the entire device tree */
|
||||
|
||||
void INLINE_DEVICE device_tree_dump
|
||||
(device *device,
|
||||
void *ignore_data_argument);
|
||||
|
||||
|
||||
|
||||
|
||||
/* Device Properties:
|
||||
|
||||
Attached to a device (typically by open boot firmware) are
|
||||
properties that profile the devices features. The below allow the
|
||||
manipulation of device properties */
|
||||
|
||||
/* Each device can have associated properties. Internal to
|
||||
psim those properties are strictly typed. Within the simulation,
|
||||
no such control exists */
|
||||
|
||||
typedef enum {
|
||||
integer_property,
|
||||
boolean_property,
|
||||
string_property,
|
||||
array_property,
|
||||
null_property,
|
||||
} device_property_type;
|
||||
|
||||
typedef struct _device_property device_property;
|
||||
struct _device_property {
|
||||
device *owner;
|
||||
device_property_type type;
|
||||
unsigned sizeof_array;
|
||||
const void *array;
|
||||
};
|
||||
|
||||
|
||||
/* Basic operations used by software */
|
||||
|
||||
const char INLINE_DEVICE *device_find_next_property
|
||||
(device *me,
|
||||
const char *previous);
|
||||
|
||||
void INLINE_DEVICE device_set_property
|
||||
(device *me,
|
||||
const char *property,
|
||||
const void *array,
|
||||
int sizeof_array);
|
||||
|
||||
|
||||
/* INLINE_DEVICE void device_add_property
|
||||
No such external function, all properties, when added are explictly
|
||||
typed */
|
||||
|
||||
void INLINE_DEVICE device_add_array_property
|
||||
(device *me,
|
||||
const char *property,
|
||||
const void *array,
|
||||
int sizeof_array);
|
||||
|
||||
void INLINE_DEVICE device_add_integer_property
|
||||
(device *me,
|
||||
const char *property,
|
||||
signed_word integer);
|
||||
|
||||
void INLINE_DEVICE device_add_boolean_property
|
||||
(device *me,
|
||||
const char *property,
|
||||
int bool);
|
||||
|
||||
void INLINE_DEVICE device_add_null_property
|
||||
(device *me,
|
||||
const char *property);
|
||||
|
||||
void INLINE_DEVICE device_add_string_property
|
||||
(device *me,
|
||||
const char *property,
|
||||
const char *string);
|
||||
|
||||
|
||||
/* Locate a property returning its description. Return NULL if the
|
||||
named property is not found */
|
||||
|
||||
const device_property INLINE_DEVICE *device_find_property
|
||||
(device *me,
|
||||
const char *property);
|
||||
|
||||
|
||||
/* Process all properties attached to the named device */
|
||||
|
||||
typedef void (device_traverse_property_function)
|
||||
(device *me,
|
||||
const char *name,
|
||||
void *data);
|
||||
|
||||
void INLINE_DEVICE device_traverse_properties
|
||||
(device *me,
|
||||
device_traverse_property_function *traverse,
|
||||
void *data);
|
||||
|
||||
|
||||
/* Similar to above except that the property *must* be in the device
|
||||
tree and *must* be of the specified type. */
|
||||
|
||||
const device_property INLINE_DEVICE *device_find_array_property
|
||||
(device *me,
|
||||
const char *property);
|
||||
|
||||
signed_word INLINE_DEVICE device_find_integer_property
|
||||
(device *me,
|
||||
const char *property);
|
||||
|
||||
const char INLINE_DEVICE *device_find_string_property
|
||||
(device *me,
|
||||
const char *property);
|
||||
|
||||
int INLINE_DEVICE device_find_boolean_property
|
||||
(device *me,
|
||||
const char *property);
|
||||
|
||||
|
||||
|
||||
/* Device Hardware:
|
||||
|
||||
A device principaly is modeling real hardware that a processor can
|
||||
directly interact with via load/stores dma's and interrupts. The
|
||||
interface below is used by the hardware side of the device
|
||||
model. */
|
||||
|
||||
/* Address access attributes that can be attached to a devices address
|
||||
range */
|
||||
typedef enum _access_type {
|
||||
access_invalid = 0,
|
||||
access_read = 1,
|
||||
access_write = 2,
|
||||
access_read_write = 3,
|
||||
access_exec = 4,
|
||||
access_read_exec = 5,
|
||||
access_write_exec = 6,
|
||||
access_read_write_exec = 7,
|
||||
} access_type;
|
||||
|
||||
|
||||
/* Address attachement types */
|
||||
typedef enum _attach_type {
|
||||
attach_invalid,
|
||||
attach_callback,
|
||||
attach_default,
|
||||
attach_raw_memory,
|
||||
} attach_type;
|
||||
|
||||
|
||||
/* Initialization:
|
||||
|
||||
A device is made fully functional in two stages.
|
||||
|
||||
1. It is created. A device is created _before_ it is entered into
|
||||
the device tree. During creation any permenant structures needed
|
||||
by the device should be created/initialized.
|
||||
|
||||
2. It is initialized. Before a simulation run, each device in the
|
||||
device tree is initialized in prefix order. As part of this
|
||||
initialization, a device should (re)attach its self to its parent
|
||||
as needed.
|
||||
|
||||
*/
|
||||
|
||||
device INLINE_DEVICE *device_create
|
||||
(const char *name,
|
||||
device *parent);
|
||||
|
||||
/* some external functions want to create things */
|
||||
typedef struct _device_callbacks device_callbacks;
|
||||
|
||||
device INLINE_DEVICE *device_create_from
|
||||
(const char *name,
|
||||
void *data,
|
||||
const device_callbacks *callbacks,
|
||||
device *parent);
|
||||
|
||||
void INLINE_DEVICE device_init
|
||||
(device *me,
|
||||
psim *system);
|
||||
|
||||
/* initialize the entire tree */
|
||||
|
||||
void INLINE_DEVICE device_tree_init
|
||||
(device *root,
|
||||
psim *system);
|
||||
|
||||
|
||||
/* Data transfers:
|
||||
|
||||
A device may permit the reading/writing (IO) of its registers in
|
||||
one or more address spaces. For instance, a PCI device may have
|
||||
config registers in its config space and control registers in both
|
||||
the io and memory spaces of a PCI bus.
|
||||
|
||||
Similarly, a device may initiate a data transfer (DMA) by passing
|
||||
such a request up to its parent.
|
||||
|
||||
Init:
|
||||
|
||||
As part of its initialization (not creation) and possibly also as a
|
||||
consequence of IO a device may attach its self to one or more of
|
||||
the address spaces of its parent device.
|
||||
|
||||
For instance, a PCI device, during initialization would attach its
|
||||
config registers (space=0?, base=0, nr_bytes=64) to its parent PCI
|
||||
bridge. Later, due to a write to this config space, the same
|
||||
device may in turn find it necessary to also attach its self to
|
||||
it's parent's `memory' or `io' space.
|
||||
|
||||
To perform these operations, a device will call upon its parent
|
||||
using either device_attach_address or device_detach_address.
|
||||
|
||||
* Any address specified is according to what the device expects to
|
||||
see.
|
||||
|
||||
* Any detach operation must exactly match a previous attach.
|
||||
|
||||
* included with the attach or detach is the devices name, the
|
||||
parent may use this as part of determining how to map map between a
|
||||
child's address + space and its own.
|
||||
|
||||
* at any time, at most one device can have a default mapping
|
||||
registered.
|
||||
|
||||
|
||||
IO:
|
||||
|
||||
A device receives requests to perform reads/writes to its registers
|
||||
or memory either A. from a processor or B. from a parent device.
|
||||
|
||||
The device may then in turn either A. resolve the IO request
|
||||
locally by processing the data or trigering an exception or
|
||||
B. re-mapping the access onto one of its local address spaces and
|
||||
then in turn passing that on to one of its children.
|
||||
|
||||
* Any address passed is relative to the local device. Eg for PCI
|
||||
config registers, the address would (normally) be in the range of 0
|
||||
to 63.
|
||||
|
||||
* Any exception situtation triggered by an IO operation (processor
|
||||
!= NULL) is handled in one of the following ways: 1. Machine check
|
||||
(and similar): issued immediatly by restarting the cpu; 2. External
|
||||
exception: issue delayed (using events.h) until the current
|
||||
instruction execution cycle is completed; 3. Slave device (and
|
||||
similar): the need for the interrupt is passed on to the devices
|
||||
parent (which being an interrupt control unit will in turn take one
|
||||
of the actions described here); 4. Forget it.
|
||||
|
||||
* Any exception situtation trigered by a non IO operation
|
||||
(processor == NULL) is handled buy returning 0.
|
||||
|
||||
* Transfers of size <= 8 and of a power of 2 *must* be correctly
|
||||
aligned and should be treated as a `single cycle' transfer.
|
||||
|
||||
DMA:
|
||||
|
||||
A device initiates a DMA transfer by calling its parent with the
|
||||
request. At the top level (if not done earlier) this is reflected
|
||||
back down the tree as io read/writes to the target device.
|
||||
|
||||
This function is subject to change ...
|
||||
|
||||
*/
|
||||
|
||||
void INLINE_DEVICE device_attach_address
|
||||
(device *me,
|
||||
const char *name,
|
||||
attach_type attach,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes,
|
||||
access_type access,
|
||||
device *who); /*callback/default*/
|
||||
|
||||
void INLINE_DEVICE device_detach_address
|
||||
(device *me,
|
||||
const char *name,
|
||||
attach_type attach,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes,
|
||||
access_type access,
|
||||
device *who); /*callback/default*/
|
||||
|
||||
unsigned INLINE_DEVICE device_io_read_buffer
|
||||
(device *me,
|
||||
void *dest,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes,
|
||||
cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
unsigned INLINE_DEVICE device_io_write_buffer
|
||||
(device *me,
|
||||
const void *source,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes,
|
||||
cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
unsigned INLINE_DEVICE device_dma_read_buffer
|
||||
(device *me,
|
||||
void *dest,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes);
|
||||
|
||||
unsigned INLINE_DEVICE device_dma_write_buffer
|
||||
(device *me,
|
||||
const void *source,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes,
|
||||
int violate_read_only_section);
|
||||
|
||||
|
||||
/* Interrupts:
|
||||
|
||||
As mentioned above. Instead of handling an interrupt directly, a
|
||||
device may instead pass the need to interrupt on to its parent.
|
||||
|
||||
Init:
|
||||
|
||||
Before passing interrupts up to is parent, a device must first
|
||||
attach its interrupt lines to the parent device. To do this, the
|
||||
device uses the parents attach/detach calls.
|
||||
|
||||
Interrupts:
|
||||
|
||||
A child notifies a parent of a change in an interrupt lines status
|
||||
using the interrupt call. Similarly, a parent may notify a child
|
||||
of any `interrupt ack' sequence using the interrupt_ack call.
|
||||
|
||||
*/
|
||||
|
||||
void INLINE_DEVICE device_attach_interrupt
|
||||
(device *me,
|
||||
device *who,
|
||||
int interrupt_line,
|
||||
const char *name);
|
||||
|
||||
void INLINE_DEVICE device_detach_interrupt
|
||||
(device *me,
|
||||
device *who,
|
||||
int interrupt_line,
|
||||
const char *name);
|
||||
|
||||
void INLINE_DEVICE device_interrupt
|
||||
(device *me,
|
||||
device *who,
|
||||
int interrupt_line,
|
||||
int interrupt_status,
|
||||
cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
void INLINE_DEVICE device_interrupt_ack
|
||||
(device *me,
|
||||
int interrupt_line,
|
||||
int interrupt_status);
|
||||
|
||||
|
||||
/* IOCTL:
|
||||
|
||||
Very simply, a catch all for any thing that turns up that until now
|
||||
either hasn't been thought of or doesn't justify an extra function. */
|
||||
|
||||
void EXTERN_DEVICE device_ioctl
|
||||
(device *me,
|
||||
psim *system,
|
||||
cpu *processor,
|
||||
unsigned_word cia,
|
||||
...);
|
||||
|
||||
|
||||
|
||||
/* Device software - the instance
|
||||
|
||||
Under development
|
||||
|
||||
In addition to the processor directly manipulating a device via
|
||||
read/write operations. A program may manipulate a device
|
||||
indirectly via OpenBoot calls. The following provide a higher
|
||||
level software interface to the devices */
|
||||
|
||||
device_instance INLINE_DEVICE *device_instance_open
|
||||
(device *me,
|
||||
const char *device_specifier);
|
||||
|
||||
void INLINE_DEVICE device_instance_close
|
||||
(device_instance *instance);
|
||||
|
||||
int INLINE_DEVICE device_instance_read
|
||||
(device_instance *instance,
|
||||
void *addr,
|
||||
unsigned_word len);
|
||||
|
||||
int INLINE_DEVICE device_instance_write
|
||||
(device_instance *instance,
|
||||
const void *addr,
|
||||
unsigned_word len);
|
||||
|
||||
int INLINE_DEVICE device_instance_seek
|
||||
(device_instance *instance,
|
||||
unsigned_word pos_hi,
|
||||
unsigned_word pos_lo);
|
||||
|
||||
device INLINE_DEVICE *device_instance_device
|
||||
(device_instance *instance);
|
||||
|
||||
const char INLINE_DEVICE *device_instance_name
|
||||
(device_instance *instance);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Device dregs... */
|
||||
|
||||
/* Parse a device name */
|
||||
|
||||
void INLINE_DEVICE device_tree_parse_name
|
||||
(const char *name,
|
||||
const char **driver_name,
|
||||
const char **unit_address,
|
||||
const char **device_arguments,
|
||||
const char **end);
|
||||
|
||||
|
||||
/* Parse a device name, various formats:
|
||||
|
||||
uw: unsigned_word
|
||||
u: unsigned
|
||||
c: string */
|
||||
|
||||
int INLINE_DEVICE scand_c
|
||||
(const char *name,
|
||||
char *c1,
|
||||
unsigned c1size);
|
||||
|
||||
int INLINE_DEVICE scand_c_uw_u
|
||||
(const char *name,
|
||||
char *c1,
|
||||
unsigned c1size,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3);
|
||||
|
||||
int INLINE_DEVICE scand_uw
|
||||
(const char *name,
|
||||
unsigned_word *uw1);
|
||||
|
||||
int INLINE_DEVICE scand_uw_c
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
char *c2,
|
||||
unsigned c2size);
|
||||
|
||||
int INLINE_DEVICE scand_uw_u
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned *u2);
|
||||
|
||||
int INLINE_DEVICE scand_uw_u_u
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned *u2,
|
||||
unsigned *u3);
|
||||
|
||||
int INLINE_DEVICE scand_uw_u_u_c
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned *u2,
|
||||
unsigned *u3,
|
||||
char *c4,
|
||||
unsigned c4size);
|
||||
|
||||
int INLINE_DEVICE scand_uw_uw
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2);
|
||||
|
||||
int INLINE_DEVICE scand_uw_uw_u
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3);
|
||||
|
||||
int INLINE_DEVICE scand_uw_uw_u_u_c
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3,
|
||||
unsigned *u4,
|
||||
char *c5,
|
||||
unsigned c5size);
|
||||
|
||||
int INLINE_DEVICE scand_uw_uw_u_u_u
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3,
|
||||
unsigned *u4,
|
||||
unsigned *u5);
|
||||
|
||||
#endif /* _DEVICE_TREE_H_ */
|
File diff suppressed because it is too large
Load Diff
@ -1,817 +0,0 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _DEVICE_TREE_C_
|
||||
#define _DEVICE_TREE_C_
|
||||
|
||||
#ifndef STATIC_INLINE_DEVICE_TREE
|
||||
#define STATIC_INLINE_DEVICE_TREE STATIC_INLINE
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "basics.h"
|
||||
#include "device_tree.h"
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#else
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
node_any = 0,
|
||||
node_device,
|
||||
node_integer,
|
||||
node_boolean,
|
||||
node_string
|
||||
} node_type;
|
||||
|
||||
static char *node_type_names[] = {
|
||||
"any",
|
||||
"device",
|
||||
"integer",
|
||||
"boolean",
|
||||
"string",
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct _device_tree {
|
||||
/* where i am */
|
||||
device_tree *parent;
|
||||
device_tree *children;
|
||||
device_tree *sibling;
|
||||
/* what i am */
|
||||
node_type type;
|
||||
const char *name;
|
||||
/* the value */
|
||||
const device *device;
|
||||
int boolean;
|
||||
const char *string;
|
||||
signed_word integer;
|
||||
};
|
||||
|
||||
|
||||
STATIC_INLINE_DEVICE_TREE device_tree *
|
||||
new_device_tree(device_tree *parent,
|
||||
const char *name,
|
||||
node_type type)
|
||||
{
|
||||
device_tree *new_node;
|
||||
new_node = ZALLOC(device_tree);
|
||||
new_node->parent = parent;
|
||||
new_node->name = strdup(name);
|
||||
new_node->type = type;
|
||||
if (parent != NULL) {
|
||||
device_tree **sibling = &parent->children;
|
||||
while ((*sibling) != NULL)
|
||||
sibling = &(*sibling)->sibling;
|
||||
*sibling = new_node;
|
||||
}
|
||||
return new_node;
|
||||
}
|
||||
|
||||
|
||||
/* find/create a node in the device tree */
|
||||
|
||||
typedef enum {
|
||||
device_tree_grow = 1,
|
||||
device_tree_return_null = 2,
|
||||
device_tree_abort = 3,
|
||||
} device_tree_action;
|
||||
|
||||
STATIC_INLINE_DEVICE_TREE device_tree *
|
||||
device_tree_find_node(device_tree *root,
|
||||
const char *path,
|
||||
const char *full_path,
|
||||
node_type type,
|
||||
device_tree_action action)
|
||||
{
|
||||
const char *chp;
|
||||
int name_len;
|
||||
device_tree *child;
|
||||
|
||||
/* strip off any leading `/', `../' or `./' */
|
||||
while (1) {
|
||||
if (strncmp(path, "/", strlen("/")) == 0) {
|
||||
while (root != NULL && root->parent != NULL)
|
||||
root = root->parent;
|
||||
path += strlen("/");
|
||||
}
|
||||
else if (strncmp(path, "./", strlen("./")) == 0) {
|
||||
root = root;
|
||||
path += strlen("./");
|
||||
}
|
||||
else if (strncmp(path, "../", strlen("../")) == 0) {
|
||||
if (root != NULL && root->parent != NULL)
|
||||
root = root->parent;
|
||||
path += strlen("../");
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* find the qualified (with @) and unqualified names in the path,
|
||||
remembering to skip any "\/" */
|
||||
chp = path;
|
||||
do {
|
||||
chp = strchr(chp+1, '/');
|
||||
} while (chp != NULL && chp[-1] == '\\');
|
||||
name_len = (chp == NULL
|
||||
? strlen(path)
|
||||
: chp - path);
|
||||
|
||||
/* leaf? and growing? */
|
||||
if (root != NULL) {
|
||||
for (child = root->children;
|
||||
child != NULL;
|
||||
child = child->sibling) {
|
||||
if (strncmp(path, child->name, name_len) == 0
|
||||
&& (strlen(child->name) == name_len
|
||||
|| (strchr(child->name, '@')
|
||||
== child->name + name_len))) {
|
||||
if (path[name_len] == '\0') {
|
||||
if (action == device_tree_grow)
|
||||
error("device_tree_find_node() node %s already present\n",
|
||||
full_path);
|
||||
if (type != node_any && child->type != type) {
|
||||
if (action == device_tree_return_null)
|
||||
return NULL;
|
||||
else
|
||||
error("device_tree_find_node() node %s is not of type %s\n",
|
||||
full_path, node_type_names[type]);
|
||||
}
|
||||
else
|
||||
return child;
|
||||
}
|
||||
else
|
||||
return device_tree_find_node(child,
|
||||
path + name_len + 1,
|
||||
full_path,
|
||||
type,
|
||||
action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* search failed, take default action */
|
||||
switch (action) {
|
||||
case device_tree_grow:
|
||||
if (path[name_len] != '\0')
|
||||
error("device_tree_find_node() a parent of %s missing\n",
|
||||
full_path);
|
||||
return new_device_tree(root, path, type);
|
||||
case device_tree_return_null:
|
||||
return NULL;
|
||||
case device_tree_abort:
|
||||
error("device_tree_find_node() could not find %s in tree\n",
|
||||
full_path);
|
||||
return NULL;
|
||||
default:
|
||||
error("device_tree_find_node() invalid default action %d\n", action);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* grow the device tree */
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *
|
||||
device_tree_add_passthrough(device_tree *root,
|
||||
const char *path)
|
||||
{
|
||||
device_tree *new_node;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_passthrough(root=0x%lx, path=%s)\n", (long)root, path));
|
||||
new_node = device_tree_find_node(root,
|
||||
path,
|
||||
path, /*full_path*/
|
||||
node_device,
|
||||
device_tree_grow);
|
||||
new_node->device = device_create_from(new_node->name,
|
||||
path,
|
||||
NULL,
|
||||
passthrough_device_callbacks(),
|
||||
new_node->parent->device);
|
||||
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_passthrough() = 0x%lx\n", (long)new_node));
|
||||
return new_node;
|
||||
}
|
||||
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *
|
||||
device_tree_add_device(device_tree *root,
|
||||
const char *path,
|
||||
const device *dev)
|
||||
{
|
||||
device_tree *new_node;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_device(root=0x%lx, path=%s, dev=0x%lx)\n",
|
||||
(long)root, path, (long)dev));
|
||||
new_node = device_tree_find_node(root,
|
||||
path,
|
||||
path, /* full-path */
|
||||
node_device,
|
||||
device_tree_grow);
|
||||
new_node->device = dev;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_device() = 0x%lx\n", (long)new_node));
|
||||
return new_node;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *
|
||||
device_tree_add_integer(device_tree *root,
|
||||
const char *path,
|
||||
signed_word integer)
|
||||
{
|
||||
device_tree *new_node;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_integer(root=0x%lx, path=%s, integer=%ld)\n",
|
||||
(long)root, path, (long)integer));
|
||||
new_node = device_tree_find_node(root,
|
||||
path,
|
||||
path, /* full-name */
|
||||
node_integer,
|
||||
device_tree_grow);
|
||||
new_node->integer = integer;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_integer() = 0x%lx\n", (long)new_node));
|
||||
return new_node;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *
|
||||
device_tree_add_string(device_tree *root,
|
||||
const char *path,
|
||||
const char *string)
|
||||
{
|
||||
device_tree *new_node;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_device(root=0x%lx, path=%s, string=%s)\n",
|
||||
(long)root, path, string));
|
||||
new_node = device_tree_find_node(root,
|
||||
path,
|
||||
path, /* full-name */
|
||||
node_string,
|
||||
device_tree_grow);
|
||||
new_node->string = strdup(string);
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_string() = 0x%lx\n", (long)new_node));
|
||||
return new_node;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *
|
||||
device_tree_add_boolean(device_tree *root,
|
||||
const char *path,
|
||||
int boolean)
|
||||
{
|
||||
device_tree *new_node;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_boolean(root=0x%lx, path=%s, boolean=%d)\n",
|
||||
(long)root, path, boolean));
|
||||
new_node = device_tree_find_node(root,
|
||||
path,
|
||||
path, /* full-name */
|
||||
node_boolean,
|
||||
device_tree_grow);
|
||||
new_node->boolean = boolean;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_boolean() = 0x%lx\n", (long)new_node));
|
||||
return new_node;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *
|
||||
device_tree_add_found_device(device_tree *root,
|
||||
const char *path)
|
||||
{
|
||||
device_tree *new_node;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_found_device(root=0x%lx, path=%s)\n",
|
||||
(long)root, path));
|
||||
new_node = device_tree_add_device(root, path, NULL);
|
||||
new_node->device = device_create(new_node->name,
|
||||
path,
|
||||
new_node->parent->device);
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_add_found_device() = 0x%lx\n", (long)new_node));
|
||||
return new_node;
|
||||
}
|
||||
|
||||
|
||||
/* look up the device tree */
|
||||
|
||||
INLINE_DEVICE_TREE const device *
|
||||
device_tree_find_device(device_tree *root,
|
||||
const char *path)
|
||||
{
|
||||
device_tree *node;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_find_device(root=0x%lx, path=%s)\n", (long)root, path));
|
||||
node = device_tree_find_node(root,
|
||||
path,
|
||||
path, /* full-name */
|
||||
node_device,
|
||||
device_tree_abort);
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_find_device() = 0x%lx\n", (long)node->device));
|
||||
return node->device;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE signed_word
|
||||
device_tree_find_integer(device_tree *root,
|
||||
const char *path)
|
||||
{
|
||||
device_tree *node;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_find_integer(root=0x%lx, path=%s)\n", (long)root, path));
|
||||
node = device_tree_find_node(root,
|
||||
path,
|
||||
path, /* full-name */
|
||||
node_integer,
|
||||
device_tree_abort);
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_find_integer() = %ld\n", (long)node->integer));
|
||||
return node->integer;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE const char *
|
||||
device_tree_find_string(device_tree *root,
|
||||
const char *path)
|
||||
{
|
||||
device_tree *node;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_find_string(root=0x%lx, path=%s)\n", (long)root, path));
|
||||
node = device_tree_find_node(root,
|
||||
path,
|
||||
path, /* full-name */
|
||||
node_string,
|
||||
device_tree_abort);
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_find_string() = 0x%lx\n", (long)node->string));
|
||||
return node->string;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
device_tree_find_boolean(device_tree *root,
|
||||
const char *path)
|
||||
{
|
||||
device_tree *node;
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_find_boolean(root=0x%lx, path=%s)\n", (long)root, path));
|
||||
node = device_tree_find_node(root,
|
||||
path,
|
||||
path, /* full-name */
|
||||
node_boolean,
|
||||
device_tree_abort);
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_find_boolean() = %ld\n", (long)node->boolean));
|
||||
return node->boolean;
|
||||
}
|
||||
|
||||
|
||||
/* init all the devices */
|
||||
|
||||
STATIC_INLINE_DEVICE_TREE void
|
||||
device_tree_init_device(device_tree *root,
|
||||
void *data)
|
||||
{
|
||||
psim *system;
|
||||
system = (psim*)data;
|
||||
if (root->type == node_device) {
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_init() initializing device=0x%lx:%s\n",
|
||||
(long)root->device, root->device->full_name));
|
||||
root->device->callback->init(root->device, system);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INLINE_DEVICE_TREE void
|
||||
device_tree_init(device_tree *root,
|
||||
psim *system)
|
||||
{
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_init(root=0x%lx, system=0x%lx)\n", (long)root, (long)system));
|
||||
device_tree_traverse(root, device_tree_init_device, NULL, system);
|
||||
TRACE(trace_device_tree,
|
||||
("device_tree_init() = void\n"));
|
||||
}
|
||||
|
||||
|
||||
/* traverse a device tree applying prefix/postfix functions to it */
|
||||
|
||||
INLINE_DEVICE_TREE void
|
||||
device_tree_traverse(device_tree *root,
|
||||
device_tree_traverse_function *prefix,
|
||||
device_tree_traverse_function *postfix,
|
||||
void *data)
|
||||
{
|
||||
device_tree *child;
|
||||
if (prefix != NULL)
|
||||
prefix(root, data);
|
||||
for (child = root->children; child != NULL; child = child->sibling) {
|
||||
device_tree_traverse(child, prefix, postfix, data);
|
||||
}
|
||||
if (postfix != NULL)
|
||||
postfix(root, data);
|
||||
}
|
||||
|
||||
|
||||
/* dump out a device node and addresses */
|
||||
|
||||
INLINE_DEVICE_TREE void
|
||||
device_tree_dump(device_tree *device,
|
||||
void *ignore_data_argument)
|
||||
{
|
||||
printf_filtered("(device_tree@0x%lx\n", (long)device);
|
||||
printf_filtered(" (parent 0x%lx)\n", (long)device->parent);
|
||||
printf_filtered(" (children 0x%lx)\n", (long)device->children);
|
||||
printf_filtered(" (sibling 0x%lx)\n", (long)device->sibling);
|
||||
printf_filtered(" (type %ld)\n", (long)device->type);
|
||||
printf_filtered(" (name %s)\n", device->name);
|
||||
printf_filtered(" (device 0x%lx)\n", (long)device->device);
|
||||
printf_filtered(" (boolean %ld)\n", (long)device->boolean);
|
||||
printf_filtered(" (string %s)\n", device->string);
|
||||
printf_filtered(" (integer %ld)\n", (long)device->integer);
|
||||
printf_filtered(")\n");
|
||||
}
|
||||
|
||||
|
||||
/* Parse a device name, various formats */
|
||||
|
||||
#define SCAN_INIT(NAME) \
|
||||
char *START = (char*)0; \
|
||||
char *END = (char*)0; \
|
||||
int COUNT = -1; \
|
||||
/* find the first element */ \
|
||||
END = strchr(NAME, '@'); \
|
||||
if (END == (char*)0) \
|
||||
return COUNT; \
|
||||
COUNT += 1; \
|
||||
START = END + 1
|
||||
|
||||
#define SCAN_END \
|
||||
return COUNT
|
||||
|
||||
#define SCAN_U(U) \
|
||||
do { \
|
||||
*U = strtoul(START, &END, 0); \
|
||||
if (START == END) \
|
||||
return COUNT; \
|
||||
COUNT += 1; \
|
||||
if (*END != ',') \
|
||||
return COUNT; \
|
||||
START = END + 1; \
|
||||
} while (0)
|
||||
|
||||
#define SCAN_P(P) \
|
||||
do { \
|
||||
*P = (void*)(unsigned)strtouq(START, END, 0); \
|
||||
if (START == END) \
|
||||
return COUNT; \
|
||||
COUNT += 1; \
|
||||
if (*END != ',') \
|
||||
return COUNT; \
|
||||
START = END + 1; \
|
||||
} while (0)
|
||||
|
||||
#define SCAN_C(C, SIZE) \
|
||||
do { \
|
||||
char *chp = C; \
|
||||
END = START; \
|
||||
while (*END != '\0' && *END != ',') { \
|
||||
if (*END == '\\') \
|
||||
END += 1; \
|
||||
*chp = *END; \
|
||||
chp += 1; \
|
||||
END += 1; \
|
||||
if ((SIZE) <= ((END) - (START))) \
|
||||
return COUNT; /* overflow */ \
|
||||
} \
|
||||
*chp = '\0'; \
|
||||
if (START == END) \
|
||||
return COUNT; \
|
||||
COUNT += 1; \
|
||||
if (*END != ',') \
|
||||
return COUNT; \
|
||||
START = END + 1; \
|
||||
} while (0)
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
scand_c(const char *name,
|
||||
char *c1,
|
||||
unsigned c1size)
|
||||
{
|
||||
SCAN_INIT(name);
|
||||
SCAN_C(c1, c1size);
|
||||
SCAN_END;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
scand_c_uw_u(const char *name,
|
||||
char *c1,
|
||||
unsigned c1size,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3)
|
||||
{
|
||||
SCAN_INIT(name);
|
||||
SCAN_C(c1, c1size);
|
||||
SCAN_U(uw2);
|
||||
SCAN_U(u3);
|
||||
SCAN_END;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
scand_uw(const char *name,
|
||||
unsigned_word *uw1)
|
||||
{
|
||||
SCAN_INIT(name);
|
||||
SCAN_U(uw1);
|
||||
SCAN_END;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
scand_uw_c(const char *name,
|
||||
unsigned_word *uw1,
|
||||
char *c2,
|
||||
unsigned c2size)
|
||||
{
|
||||
SCAN_INIT(name);
|
||||
SCAN_U(uw1);
|
||||
SCAN_C(c2, c2size);
|
||||
SCAN_END;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
scand_uw_u(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned *u2)
|
||||
{
|
||||
SCAN_INIT(name);
|
||||
SCAN_U(uw1);
|
||||
SCAN_U(u2);
|
||||
SCAN_END;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
scand_uw_u_u(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned *u2,
|
||||
unsigned *u3)
|
||||
{
|
||||
SCAN_INIT(name);
|
||||
SCAN_U(uw1);
|
||||
SCAN_U(u2);
|
||||
SCAN_U(u3);
|
||||
SCAN_END;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
scand_uw_uw(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2)
|
||||
{
|
||||
SCAN_INIT(name);
|
||||
SCAN_U(uw1);
|
||||
SCAN_U(uw2);
|
||||
SCAN_END;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
scand_uw_uw_u(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3)
|
||||
{
|
||||
SCAN_INIT(name);
|
||||
SCAN_U(uw1);
|
||||
SCAN_U(uw2);
|
||||
SCAN_U(u3);
|
||||
SCAN_END;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
scand_uw_uw_u_u_c(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3,
|
||||
unsigned *u4,
|
||||
char *c5,
|
||||
unsigned c5size)
|
||||
{
|
||||
SCAN_INIT(name);
|
||||
SCAN_U(uw1);
|
||||
SCAN_U(uw2);
|
||||
SCAN_U(u3);
|
||||
SCAN_U(u4);
|
||||
SCAN_C(c5, c5size);
|
||||
SCAN_END;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE int
|
||||
scand_uw_uw_u_u_u(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3,
|
||||
unsigned *u4,
|
||||
unsigned *u5)
|
||||
{
|
||||
SCAN_INIT(name);
|
||||
SCAN_U(uw1);
|
||||
SCAN_U(uw2);
|
||||
SCAN_U(u3);
|
||||
SCAN_U(u4);
|
||||
SCAN_U(u5);
|
||||
SCAN_END;
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_DEVICE_TREE void
|
||||
u_strcat(char *buf,
|
||||
unsigned_word uw)
|
||||
{
|
||||
if (MASKED64(uw, 32, 63) == uw
|
||||
|| WITH_HOST_WORD_BITSIZE == 64) {
|
||||
char *end = strchr(buf, '\0');
|
||||
sprintf(end, "0x%x", (unsigned)uw);
|
||||
}
|
||||
else {
|
||||
char *end = strchr(buf, '\0');
|
||||
sprintf(end, "0x%x%08x",
|
||||
(unsigned)EXTRACTED64(uw, 0, 31),
|
||||
(unsigned)EXTRACTED64(uw, 32, 63));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC_INLINE_DEVICE_TREE void
|
||||
c_strcat(char *buf,
|
||||
const char *c)
|
||||
{
|
||||
char *end = strchr(buf, '\0');
|
||||
while (*c) {
|
||||
if (*c == '/' || *c == ',')
|
||||
*end++ = '\\';
|
||||
*end++ = *c++;
|
||||
}
|
||||
*end = '\0';
|
||||
}
|
||||
|
||||
STATIC_INLINE_DEVICE_TREE int
|
||||
c_strlen(const char *c)
|
||||
{
|
||||
int len = 0;
|
||||
while (*c) {
|
||||
if (*c == '/' || *c == ',')
|
||||
len++;
|
||||
len++;
|
||||
c++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
enum {
|
||||
strlen_unsigned = 10,
|
||||
strlen_unsigned_word = 18,
|
||||
};
|
||||
|
||||
INLINE_DEVICE_TREE char *
|
||||
printd_c(const char *name,
|
||||
const char *c1)
|
||||
{
|
||||
int sizeof_buf = (strlen(name)
|
||||
+ strlen("@")
|
||||
+ c_strlen(c1)
|
||||
+ 1);
|
||||
char *buf = (char*)zalloc(sizeof_buf);
|
||||
strcpy(buf, name);
|
||||
strcat(buf, "@");
|
||||
c_strcat(buf, c1);
|
||||
ASSERT(strlen(buf) < sizeof_buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE char *
|
||||
printd_c_uw(const char *name,
|
||||
const char *c1,
|
||||
unsigned_word uw2)
|
||||
{
|
||||
int sizeof_buf = (strlen(name)
|
||||
+ strlen("@")
|
||||
+ c_strlen(c1)
|
||||
+ strlen(",")
|
||||
+ strlen_unsigned_word
|
||||
+ 1);
|
||||
char *buf = (char*)zalloc(sizeof_buf);
|
||||
strcpy(buf, name);
|
||||
strcat(buf, "@");
|
||||
c_strcat(buf, c1);
|
||||
strcat(buf, ",");
|
||||
u_strcat(buf, uw2);
|
||||
ASSERT(strlen(buf) < sizeof_buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE char *
|
||||
printd_uw_u(const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned u2)
|
||||
{
|
||||
int sizeof_buf = (strlen(name)
|
||||
+ strlen("@")
|
||||
+ strlen_unsigned_word
|
||||
+ strlen(",")
|
||||
+ strlen_unsigned
|
||||
+ 1);
|
||||
char *buf = (char*)zalloc(sizeof_buf);
|
||||
strcpy(buf, name);
|
||||
strcat(buf, "@");
|
||||
u_strcat(buf, uw1);
|
||||
strcat(buf, ",");
|
||||
u_strcat(buf, u2);
|
||||
ASSERT(strlen(buf) < sizeof_buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE char *
|
||||
printd_uw_u_u(const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned u2,
|
||||
unsigned u3)
|
||||
{
|
||||
int sizeof_buf = (strlen(name)
|
||||
+ strlen("@")
|
||||
+ strlen_unsigned_word
|
||||
+ strlen(",")
|
||||
+ strlen_unsigned
|
||||
+ strlen(",")
|
||||
+ strlen_unsigned
|
||||
+ 1);
|
||||
char *buf = (char*)zalloc(sizeof_buf);
|
||||
strcpy(buf, name);
|
||||
strcat(buf, "@");
|
||||
u_strcat(buf, uw1);
|
||||
strcat(buf, ",");
|
||||
u_strcat(buf, u2);
|
||||
strcat(buf, ",");
|
||||
u_strcat(buf, u3);
|
||||
ASSERT(strlen(buf) < sizeof_buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
INLINE_DEVICE_TREE char *
|
||||
printd_uw_u_u_c(const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned u2,
|
||||
unsigned u3,
|
||||
const char *c4)
|
||||
{
|
||||
int sizeof_buf = (strlen(name)
|
||||
+ strlen("@")
|
||||
+ strlen_unsigned_word
|
||||
+ strlen(",")
|
||||
+ strlen_unsigned
|
||||
+ strlen(",")
|
||||
+ strlen_unsigned
|
||||
+ strlen(",")
|
||||
+ c_strlen(c4)
|
||||
+ 1);
|
||||
char *buf = (char*)zalloc(sizeof_buf);
|
||||
strcpy(buf, name);
|
||||
strcat(buf, "@");
|
||||
u_strcat(buf, uw1);
|
||||
strcat(buf, ",");
|
||||
u_strcat(buf, u2);
|
||||
strcat(buf, ",");
|
||||
u_strcat(buf, u3);
|
||||
strcat(buf, ",");
|
||||
c_strcat(buf, c4);
|
||||
ASSERT(strlen(buf) < sizeof_buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif /* _DEVICE_TREE_C_ */
|
@ -1,207 +0,0 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _DEVICE_TREE_H_
|
||||
#define _DEVICE_TREE_H_
|
||||
|
||||
#ifndef INLINE_DEVICE_TREE
|
||||
#define INLINE_DEVICE_TREE
|
||||
#endif
|
||||
|
||||
|
||||
#include "devices.h"
|
||||
|
||||
typedef struct _device_tree device_tree;
|
||||
|
||||
|
||||
/* extend the device tree, each function returns the address of the
|
||||
new node */
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *device_tree_add_passthrough
|
||||
(device_tree *root,
|
||||
const char *path);
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *device_tree_add_device
|
||||
(device_tree *root,
|
||||
const char *path,
|
||||
const device *dev);
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *device_tree_add_integer
|
||||
(device_tree *root,
|
||||
const char *path,
|
||||
signed_word integer);
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *device_tree_add_string
|
||||
(device_tree *root,
|
||||
const char *path,
|
||||
const char *string);
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *device_tree_add_boolean
|
||||
(device_tree *root,
|
||||
const char *path,
|
||||
int bool);
|
||||
|
||||
INLINE_DEVICE_TREE device_tree *device_tree_add_found_device
|
||||
(device_tree *root,
|
||||
const char *path);
|
||||
|
||||
/* query the device tree */
|
||||
|
||||
INLINE_DEVICE_TREE const device *device_tree_find_device
|
||||
(device_tree *root,
|
||||
const char *path);
|
||||
|
||||
INLINE_DEVICE_TREE signed_word device_tree_find_integer
|
||||
(device_tree *root,
|
||||
const char *path);
|
||||
|
||||
INLINE_DEVICE_TREE const char *device_tree_find_string
|
||||
(device_tree *root,
|
||||
const char *path);
|
||||
|
||||
INLINE_DEVICE_TREE int device_tree_find_boolean
|
||||
(device_tree *root,
|
||||
const char *path);
|
||||
|
||||
|
||||
/* initialize the entire tree */
|
||||
|
||||
INLINE_DEVICE_TREE void device_tree_init
|
||||
(device_tree *root,
|
||||
psim *system);
|
||||
|
||||
|
||||
/* traverse the tree eiter pre or post fix */
|
||||
|
||||
typedef void (device_tree_traverse_function)
|
||||
(device_tree *device,
|
||||
void *data);
|
||||
|
||||
INLINE_DEVICE_TREE void device_tree_traverse
|
||||
(device_tree *root,
|
||||
device_tree_traverse_function *prefix,
|
||||
device_tree_traverse_function *postfix,
|
||||
void *data);
|
||||
|
||||
|
||||
/* dump a node, this can be passed to the device_tree_traverse()
|
||||
function to dump out the entire device tree */
|
||||
|
||||
INLINE_DEVICE_TREE void device_tree_dump
|
||||
(device_tree *device,
|
||||
void *ignore_data_argument);
|
||||
|
||||
|
||||
/* Parse a device name, various formats:
|
||||
|
||||
uw: unsigned_word
|
||||
u: unsigned
|
||||
c: string */
|
||||
|
||||
INLINE_DEVICE_TREE int scand_c
|
||||
(const char *name,
|
||||
char *c1,
|
||||
unsigned c1size);
|
||||
|
||||
INLINE_DEVICE_TREE int scand_c_uw_u
|
||||
(const char *name,
|
||||
char *c1,
|
||||
unsigned c1size,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3);
|
||||
|
||||
INLINE_DEVICE_TREE int scand_uw
|
||||
(const char *name,
|
||||
unsigned_word *uw1);
|
||||
|
||||
INLINE_DEVICE_TREE int scand_uw_c
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
char *c2,
|
||||
unsigned c2size);
|
||||
|
||||
INLINE_DEVICE_TREE int scand_uw_u
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned *u2);
|
||||
|
||||
INLINE_DEVICE_TREE int scand_uw_u_u
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned *u2,
|
||||
unsigned *u3);
|
||||
|
||||
INLINE_DEVICE_TREE int scand_uw_uw
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2);
|
||||
|
||||
INLINE_DEVICE_TREE int scand_uw_uw_u
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3);
|
||||
|
||||
INLINE_DEVICE_TREE int scand_uw_uw_u_u_c
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3,
|
||||
unsigned *u4,
|
||||
char *c5,
|
||||
unsigned c5size);
|
||||
|
||||
INLINE_DEVICE_TREE int scand_uw_uw_u_u_u
|
||||
(const char *name,
|
||||
unsigned_word *uw1,
|
||||
unsigned_word *uw2,
|
||||
unsigned *u3,
|
||||
unsigned *u4,
|
||||
unsigned *u5);
|
||||
|
||||
INLINE_DEVICE_TREE char *printd_c
|
||||
(const char *name,
|
||||
const char *c1);
|
||||
|
||||
INLINE_DEVICE_TREE char *printd_c_uw
|
||||
(const char *name,
|
||||
const char *c1,
|
||||
unsigned_word uw2);
|
||||
|
||||
INLINE_DEVICE_TREE char *printd_uw_u
|
||||
(const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned u2);
|
||||
|
||||
INLINE_DEVICE_TREE char *printd_uw_u_u
|
||||
(const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned u2,
|
||||
unsigned u3);
|
||||
|
||||
INLINE_DEVICE_TREE char *printd_uw_u_u_c
|
||||
(const char *name,
|
||||
unsigned_word uw1,
|
||||
unsigned u2,
|
||||
unsigned u3,
|
||||
const char *c4);
|
||||
|
||||
#endif /* _DEVICE_TREE_H_ */
|
@ -1,380 +0,0 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _DEVICES_H_
|
||||
#define _DEVICES_H_
|
||||
|
||||
#ifndef INLINE_DEVICES
|
||||
#define INLINE_DEVICES
|
||||
#endif
|
||||
|
||||
#ifndef STATIC_DEVICES
|
||||
#define STATIC_DEVICES
|
||||
#endif
|
||||
|
||||
|
||||
/* forward declaration of types */
|
||||
/* typedef struct _device device; -- in devices.h */
|
||||
|
||||
|
||||
/* Address access attributes that can be attached to a devices address
|
||||
range */
|
||||
typedef enum _access_type {
|
||||
access_invalid = 0,
|
||||
access_read = 1,
|
||||
access_write = 2,
|
||||
access_read_write = 3,
|
||||
access_exec = 4,
|
||||
access_read_exec = 5,
|
||||
access_write_exec = 6,
|
||||
access_read_write_exec = 7,
|
||||
} access_type;
|
||||
|
||||
/* Address attachement types */
|
||||
typedef enum _attach_type {
|
||||
attach_invalid,
|
||||
attach_callback,
|
||||
attach_default,
|
||||
attach_raw_memory,
|
||||
} attach_type;
|
||||
|
||||
|
||||
/* Operators on devices: */
|
||||
|
||||
|
||||
/* Initialization:
|
||||
|
||||
A device is made fully functional in two stages.
|
||||
|
||||
1. It is created. A device is created _before_ it is entered into
|
||||
the device tree. During creation any permenant structures needed
|
||||
by the device should be created/initialized.
|
||||
|
||||
2. It is initialized. Before a simulation run, each device in the
|
||||
device tree is initialized in prefix order. As part of this
|
||||
initialization, a device should (re)attach its self to its parent
|
||||
as needed.
|
||||
|
||||
*/
|
||||
|
||||
typedef void (device_init_callback)
|
||||
(const device *me,
|
||||
psim *system);
|
||||
|
||||
#define DTRACE_INIT(OBJECT) \
|
||||
DTRACE(OBJECT, \
|
||||
(#OBJECT "_init(me=0x%lx:%s system=0x%lx)\n", \
|
||||
(long)me, me->full_name, (long)system))
|
||||
|
||||
/* Data transfers:
|
||||
|
||||
A device may permit the reading/writing (IO) of its registers in
|
||||
one or more address spaces. For instance, a PCI device may have
|
||||
config registers in its config space and control registers in both
|
||||
the io and memory spaces of a PCI bus.
|
||||
|
||||
Similarly, a device may initiate a data transfer (DMA) by passing
|
||||
such a request up to its parent.
|
||||
|
||||
Init:
|
||||
|
||||
As part of its initialization (not creation) and possibly also as a
|
||||
consequence of IO a device may attach its self to one or more of
|
||||
the address spaces of its parent device.
|
||||
|
||||
For instance, a PCI device, during initialization would attach its
|
||||
config registers (space=0?, base=0, nr_bytes=64) to its parent PCI
|
||||
bridge. Later, due to a write to this config space, the same
|
||||
device may in turn find it necessary to also attach its self to
|
||||
it's parent's `memory' or `io' space.
|
||||
|
||||
To perform these operations, a device will call upon its parent
|
||||
using either device_attach_address or device_detach_address.
|
||||
|
||||
* Any address specified is according to what the device expects to
|
||||
see.
|
||||
|
||||
* Any detach operation must exactly match a previous attach.
|
||||
|
||||
* included with the attach or detach is the devices name, the
|
||||
parent may use this as part of determining how to map map between a
|
||||
child's address + space and its own.
|
||||
|
||||
* at any time, at most one device can have a default mapping
|
||||
registered.
|
||||
|
||||
|
||||
IO:
|
||||
|
||||
A device receives requests to perform reads/writes to its registers
|
||||
or memory either A. from a processor or B. from a parent device.
|
||||
|
||||
The device may then in turn either A. resolve the IO request
|
||||
locally by processing the data or trigering an exception or
|
||||
B. re-mapping the access onto one of its local address spaces and
|
||||
then in turn passing that on to one of its children.
|
||||
|
||||
* Any address passed is relative to the local device. Eg for PCI
|
||||
config registers, the address would (normally) be in the range of 0
|
||||
to 63.
|
||||
|
||||
* Any exception situtation triggered by an IO operation (processor
|
||||
!= NULL) is handled in one of the following ways: 1. Machine check
|
||||
(and similar): issued immediatly by restarting the cpu; 2. External
|
||||
exception: issue delayed (using events.h) until the current
|
||||
instruction execution cycle is completed; 3. Slave device (and
|
||||
similar): the need for the interrupt is passed on to the devices
|
||||
parent (which being an interrupt control unit will in turn take one
|
||||
of the actions described here); 4. Forget it.
|
||||
|
||||
* Any exception situtation trigered by a non IO operation
|
||||
(processor == NULL) is handled buy returning 0.
|
||||
|
||||
* Transfers of size <= 8 and of a power of 2 *must* be correctly
|
||||
aligned and should be treated as a `single cycle' transfer.
|
||||
|
||||
DMA:
|
||||
|
||||
A device initiates a DMA transfer by calling its parent with the
|
||||
request. At the top level (if not done earlier) this is reflected
|
||||
back down the tree as io read/writes to the target device.
|
||||
|
||||
This function is subject to change ...
|
||||
|
||||
*/
|
||||
|
||||
typedef void (device_config_address_callback)
|
||||
(const device *me,
|
||||
const char *name,
|
||||
attach_type attach,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes,
|
||||
access_type access,
|
||||
const device *who); /*callback/default*/
|
||||
|
||||
#define DTRACE_ATTACH_ADDRESS(OBJECT) \
|
||||
DTRACE(OBJECT, \
|
||||
(#OBJECT "_attach_address(me=0x%lx:%s, name=%s, attach=%ld, space=%ld, addr=0x%lx, nr_bytes=%ld, access=%ld, who=0x%lx)\n", \
|
||||
(long)me, me->full_name, name, (long)attach, (long)space, \
|
||||
(long)addr, (long)nr_bytes, (long)access, (long)who))
|
||||
#define DTRACE_DETACH_ADDRESS(OBJECT) \
|
||||
DTRACE(OBJECT, \
|
||||
(#OBJECT "_detach_address(me=0x%lx:%s, name=%s, attach=%ld, space=%ld, addr=0x%lx, nr_bytes=%ld, access=%ld, who=0x%lx)\n", \
|
||||
(long)me, me->full_name, name, (long)attach, (long)space, \
|
||||
(long)addr, (long)nr_bytes, (long)access, (long)who))
|
||||
|
||||
|
||||
typedef unsigned (device_io_read_buffer_callback)
|
||||
(const device *me,
|
||||
void *dest,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes,
|
||||
cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
typedef unsigned (device_io_write_buffer_callback)
|
||||
(const device *me,
|
||||
const void *source,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes,
|
||||
cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
#define DTRACE_IO_READ_BUFFER(OBJECT) \
|
||||
DTRACE(OBJECT, \
|
||||
(#OBJECT "_io_read_buffer(me=0x%lx:%s dest=0x%lx space=%ld addr=0x%lx nr_bytes=%ld processor=0x%lx cia=0x%lx)\n", \
|
||||
(long)me, me->full_name, (long)dest, (long)space, (long)addr, \
|
||||
(long)nr_bytes, (long)processor, (long)cia))
|
||||
#define DTRACE_IO_WRITE_BUFFER(OBJECT) \
|
||||
DTRACE(OBJECT, \
|
||||
(#OBJECT "_io_write_buffer(me=0x%lx:%s source=0x%lx space=%ld addr=0x%lx nr_bytes=%ld processor=0x%lx cia=0x%lx)\n", \
|
||||
(long)me, me->full_name, (long)source, (long)space, (long)addr, \
|
||||
(long)nr_bytes, (long)processor, (long)cia))
|
||||
|
||||
|
||||
typedef unsigned (device_dma_read_buffer_callback)
|
||||
(const device *me,
|
||||
void *dest,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes);
|
||||
|
||||
typedef unsigned (device_dma_write_buffer_callback)
|
||||
(const device *me,
|
||||
const void *source,
|
||||
int space,
|
||||
unsigned_word addr,
|
||||
unsigned nr_bytes,
|
||||
int violate_read_only_section);
|
||||
|
||||
#define DTRACE_DMA_READ_BUFFER(OBJECT) \
|
||||
DTRACE(OBJECT, \
|
||||
(#OBJECT "_dma_read_buffer(me=0x%lx:%s dest=0x%lx space=%ld addr=0x%lx nr_bytes=%ld)\n", \
|
||||
(long)me, me->full_name, (long)dest, (long)space, (long)addr, (long)nr_bytes))
|
||||
#define DTRACE_DMA_WRITE_BUFFER(OBJECT) \
|
||||
DTRACE(OBJECT, \
|
||||
(#OBJECT "_dma_write_buffer(me=0x%lx:%s source=0x%lx space=%ld addr=0x%lx nr_bytes=%ld)\n", \
|
||||
(long)me, me->full_name, (long)source, (long)space, (long)addr, (long)nr_bytes))
|
||||
|
||||
|
||||
/* Interrupts:
|
||||
|
||||
As mentioned above. Instead of handling an interrupt directly, a
|
||||
device may instead pass the need to interrupt on to its parent.
|
||||
|
||||
Init:
|
||||
|
||||
Before passing interrupts up to is parent, a device must first
|
||||
attach its interrupt lines to the parent device. To do this, the
|
||||
device uses the parents attach/detach calls.
|
||||
|
||||
Interrupts:
|
||||
|
||||
A child notifies a parent of a change in an interrupt lines status
|
||||
using the interrupt call. Similarly, a parent may notify a child
|
||||
of any `interrupt ack' sequence using the interrupt_ack call.
|
||||
|
||||
*/
|
||||
|
||||
typedef void (device_config_interrupt_callback)
|
||||
(const device *me,
|
||||
const device *who,
|
||||
int interrupt_line,
|
||||
const char *name);
|
||||
|
||||
typedef void (device_interrupt_ack_callback)
|
||||
(const device *me,
|
||||
int interrupt_line,
|
||||
int interrupt_status);
|
||||
|
||||
typedef void (device_interrupt_callback)
|
||||
(const device *me,
|
||||
const device *who,
|
||||
int interrupt_line,
|
||||
int interrupt_status,
|
||||
cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
|
||||
/* IOCTL:
|
||||
|
||||
Very simply, a catch all for any thing that turns up that until now
|
||||
either hasn't been thought of or doesn't justify an extra function. */
|
||||
|
||||
|
||||
typedef void (device_ioctl_callback)
|
||||
(const device *me,
|
||||
psim *system,
|
||||
cpu *processor,
|
||||
unsigned_word cia,
|
||||
...);
|
||||
|
||||
|
||||
|
||||
/* the callbacks */
|
||||
|
||||
typedef struct _device_callbacks {
|
||||
/* initialization */
|
||||
device_init_callback *init;
|
||||
/* address/data config - from child */
|
||||
device_config_address_callback *attach_address;
|
||||
device_config_address_callback *detach_address;
|
||||
/* address/data transfer - to child */
|
||||
device_io_read_buffer_callback *io_read_buffer;
|
||||
device_io_write_buffer_callback *io_write_buffer;
|
||||
/* address/data transfer - from child */
|
||||
device_dma_read_buffer_callback *dma_read_buffer;
|
||||
device_dma_write_buffer_callback *dma_write_buffer;
|
||||
/* interrupt config - from child */
|
||||
device_config_interrupt_callback *attach_interrupt;
|
||||
device_config_interrupt_callback *detach_interrupt;
|
||||
/* interrupt transfer - from child */
|
||||
device_interrupt_callback *interrupt;
|
||||
/* interrupt transfer - to child */
|
||||
device_interrupt_ack_callback *interrupt_ack;
|
||||
/* back door to anything we've forgot */
|
||||
device_ioctl_callback *ioctl;
|
||||
} device_callbacks;
|
||||
|
||||
/* A device */
|
||||
struct _device {
|
||||
const char *name; /* eg rom@0x1234,0x400 */
|
||||
const char *full_name; /* eg /isa/rom@0x1234,0x400 */
|
||||
void *data; /* device specific data */
|
||||
const device_callbacks *callback;
|
||||
const device *parent;
|
||||
};
|
||||
|
||||
|
||||
/* Create a new device, finding it in the builtin device table */
|
||||
|
||||
INLINE_DEVICES const device *device_create
|
||||
(const char *name,
|
||||
const char *full_name,
|
||||
const device *parent);
|
||||
|
||||
/* create a new device using the parameterized data */
|
||||
|
||||
INLINE_DEVICES const device *device_create_from
|
||||
(const char *name,
|
||||
const char *full_name,
|
||||
void *data,
|
||||
const device_callbacks *callback,
|
||||
const device *parent);
|
||||
|
||||
|
||||
/* Unimplemented call back functions. These abort the simulation */
|
||||
|
||||
INLINE_DEVICES device_init_callback unimp_device_init;
|
||||
INLINE_DEVICES device_config_address_callback unimp_device_attach_address;
|
||||
INLINE_DEVICES device_config_address_callback unimp_device_detach_address;
|
||||
INLINE_DEVICES device_io_read_buffer_callback unimp_device_io_read_buffer;
|
||||
INLINE_DEVICES device_io_write_buffer_callback unimp_device_io_write_buffer;
|
||||
INLINE_DEVICES device_dma_read_buffer_callback unimp_device_dma_read_buffer;
|
||||
INLINE_DEVICES device_dma_write_buffer_callback unimp_device_dma_write_buffer;
|
||||
INLINE_DEVICES device_config_interrupt_callback unimp_device_attach_interrupt;
|
||||
INLINE_DEVICES device_config_interrupt_callback unimp_device_detach_interrupt;
|
||||
INLINE_DEVICES device_interrupt_callback unimp_device_interrupt;
|
||||
INLINE_DEVICES device_interrupt_ack_callback unimp_device_interrupt_ack;
|
||||
STATIC_DEVICES device_ioctl_callback unimp_device_ioctl;
|
||||
|
||||
/* Pass through and ignore callback functions. A call going towards
|
||||
the root device are passed on up, local calls are ignored and call
|
||||
downs abort */
|
||||
|
||||
INLINE_DEVICES device_init_callback ignore_device_init;
|
||||
INLINE_DEVICES device_config_address_callback pass_device_attach_address;
|
||||
INLINE_DEVICES device_config_address_callback pass_device_detach_address;
|
||||
INLINE_DEVICES device_dma_read_buffer_callback pass_device_dma_read_buffer;
|
||||
INLINE_DEVICES device_dma_write_buffer_callback pass_device_dma_write_buffer;
|
||||
INLINE_DEVICES device_config_interrupt_callback pass_device_attach_interrupt;
|
||||
INLINE_DEVICES device_config_interrupt_callback pass_device_detach_interrupt;
|
||||
INLINE_DEVICES device_interrupt_callback pass_device_interrupt;
|
||||
|
||||
INLINE_DEVICES const device_callbacks *passthrough_device_callbacks
|
||||
(void);
|
||||
|
||||
|
||||
|
||||
#endif /* _DEVICES_H_ */
|
156
sim/ppc/emul_bugapi.c
Normal file
156
sim/ppc/emul_bugapi.c
Normal file
@ -0,0 +1,156 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _EMUL_BUGAPI_C_
|
||||
#define _EMUL_BUGAPI_C_
|
||||
|
||||
|
||||
/* Note: this module is called via a table. There is no benefit in
|
||||
making it inline */
|
||||
|
||||
#include "emul_generic.h"
|
||||
#include "emul_bugapi.h"
|
||||
|
||||
/* Any starting address less than this is assumed to be an OEA program
|
||||
rather than VEA. */
|
||||
#ifndef OEA_START_ADDRESS
|
||||
#define OEA_START_ADDRESS 4096
|
||||
#endif
|
||||
|
||||
#ifndef OEA_MEMORY_SIZE
|
||||
#define OEA_MEMORY_SIZE 0x100000
|
||||
#endif
|
||||
|
||||
static os_emul_data *
|
||||
emul_bugapi_create(device *root,
|
||||
bfd *image,
|
||||
const char *name)
|
||||
{
|
||||
|
||||
/* check it really is for us */
|
||||
if (name != NULL
|
||||
&& strcmp(name, "bugapi") != 0)
|
||||
return NULL;
|
||||
if (image != NULL
|
||||
&& bfd_get_start_address(image) > OEA_START_ADDRESS)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
|
||||
const memory_size = OEA_MEMORY_SIZE;
|
||||
const elf_binary = (image != NULL
|
||||
&& image->xvec->flavour == bfd_target_elf_flavour);
|
||||
const little_endian = (image != NULL
|
||||
&& !image->xvec->byteorder_big_p);
|
||||
|
||||
{ /* 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?",
|
||||
little_endian);
|
||||
device_add_string_property(options,
|
||||
"env",
|
||||
"operating");
|
||||
device_add_boolean_property(options,
|
||||
"strict-alignment?",
|
||||
(WITH_ALIGNMENT == STRICT_ALIGNMENT
|
||||
|| !image->xvec->byteorder_big_p));
|
||||
device_add_boolean_property(options,
|
||||
"floating-point?",
|
||||
WITH_FLOATING_POINT);
|
||||
device_add_string_property(options,
|
||||
"os-emul",
|
||||
"bugapi");
|
||||
}
|
||||
|
||||
/* hardware */
|
||||
device_tree_add_found_uw_u_u(root, "/", "memory",
|
||||
0, memory_size, access_read_write_exec);
|
||||
device_tree_add_found(root, "/", "iobus@0x400000");
|
||||
device_tree_add_found(root, "/iobus", "console@0x000000,16");
|
||||
device_tree_add_found(root, "/iobus", "halt@0x100000,4");
|
||||
device_tree_add_found(root, "/iobus", "icu@0x200000,4");
|
||||
|
||||
{ /* 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",
|
||||
0);
|
||||
device_add_integer_property(init_register,
|
||||
"sp",
|
||||
memory_size-16);
|
||||
device_add_integer_property(init_register,
|
||||
"msr",
|
||||
(little_endian
|
||||
? msr_little_endian_mode
|
||||
: 0));
|
||||
}
|
||||
{
|
||||
device *init_stack = device_tree_add_found(init, "", "stack");
|
||||
device_add_null_property(init_stack,
|
||||
(elf_binary
|
||||
? "elf"
|
||||
: "aix"));
|
||||
}
|
||||
{
|
||||
device *init_load_binary = device_tree_add_found(init, "",
|
||||
"load-binary");
|
||||
device_add_null_property(init_load_binary,
|
||||
bfd_get_filename(image));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (os_emul_data*)-1;
|
||||
}
|
||||
|
||||
static void
|
||||
emul_bugapi_init(os_emul_data *emul_data,
|
||||
int nr_cpus)
|
||||
{
|
||||
/* nothing happens here */
|
||||
}
|
||||
|
||||
static int
|
||||
emul_bugapi_instruction_call(cpu *processor,
|
||||
unsigned_word cia,
|
||||
unsigned_word ra,
|
||||
os_emul_data *emul_data)
|
||||
{
|
||||
error("emul_bugapi_instruction_call() not implemented\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const os_emul emul_bugapi = {
|
||||
"bugapi",
|
||||
emul_bugapi_create,
|
||||
emul_bugapi_init,
|
||||
0, /*system_call*/
|
||||
emul_bugapi_instruction_call,
|
||||
0 /*data*/
|
||||
};
|
||||
|
||||
#endif
|
27
sim/ppc/emul_bugapi.h
Normal file
27
sim/ppc/emul_bugapi.h
Normal file
@ -0,0 +1,27 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _EMUL_BUGAPI_H_
|
||||
#define _EMUL_BUGAPI_H_
|
||||
|
||||
extern const os_emul emul_bugapi;
|
||||
|
||||
#endif
|
530
sim/ppc/emul_chirp.c
Normal file
530
sim/ppc/emul_chirp.c
Normal file
@ -0,0 +1,530 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _EMUL_CHIRP_C_
|
||||
#define _EMUL_CHIRP_C_
|
||||
|
||||
/* Note: this module is called via a table. There is no benefit in
|
||||
making it inline */
|
||||
|
||||
#include "emul_generic.h"
|
||||
#include "emul_chirp.h"
|
||||
|
||||
#include "cap.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#else
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef STATIC_INLINE_EMUL_CHIRP
|
||||
#define STATIC_INLINE_EMUL_CHIRP STATIC_INLINE
|
||||
#endif
|
||||
|
||||
|
||||
/* Descriptor of the open boot services being emulated */
|
||||
|
||||
typedef unsigned_word (chirp_handler)
|
||||
(os_emul_data *data,
|
||||
cpu *processor,
|
||||
unsigned_word cia);
|
||||
typedef struct _chirp_services {
|
||||
const char *name;
|
||||
chirp_handler *handler;
|
||||
} chirp_services;
|
||||
|
||||
|
||||
/* The OpenBoot emulation is, at any time either waiting for a client
|
||||
request or waiting on a client callback */
|
||||
typedef enum {
|
||||
serving,
|
||||
catching,
|
||||
} chirp_emul_state;
|
||||
|
||||
struct _os_emul_data {
|
||||
chirp_emul_state state;
|
||||
unsigned_word return_address;
|
||||
unsigned_word arguments;
|
||||
chirp_services *service;
|
||||
unsigned_word serving_instruction_ea;
|
||||
unsigned_word catching_instruction_ea;
|
||||
cap *phandles;
|
||||
device *root;
|
||||
};
|
||||
|
||||
|
||||
/* OpenBoot emulation functions */
|
||||
|
||||
static unsigned_word
|
||||
chirp_emul_finddevice(os_emul_data *data,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
struct finddevice_args {
|
||||
unsigned32 service;
|
||||
unsigned32 n_args;
|
||||
unsigned32 n_returns;
|
||||
/*in*/
|
||||
unsigned32 device_specifier;
|
||||
/*out*/
|
||||
unsigned32 phandle;
|
||||
} args;
|
||||
char device_specifier[1024];
|
||||
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)
|
||||
return -1;
|
||||
emul_read_string(device_specifier,
|
||||
T2H_4(args.device_specifier),
|
||||
sizeof(device_specifier),
|
||||
processor, cia);
|
||||
dev = device_tree_find_device(data->root,
|
||||
device_specifier);
|
||||
if (dev == (device*)0)
|
||||
args.phandle = -1;
|
||||
else
|
||||
args.phandle = cap_external(data->phandles, dev);
|
||||
emul_write_buffer(&args, data->arguments,
|
||||
sizeof(args),
|
||||
processor, cia);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned_word
|
||||
chirp_emul_getprop(os_emul_data *data,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
struct getprop_args {
|
||||
unsigned32 service;
|
||||
unsigned32 n_args;
|
||||
unsigned32 n_returns;
|
||||
/*in*/
|
||||
unsigned32 phandle;
|
||||
unsigned32 name;
|
||||
unsigned32 buf;
|
||||
unsigned32 buflen;
|
||||
/*out*/
|
||||
unsigned32 size;
|
||||
} args;
|
||||
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)
|
||||
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),
|
||||
processor, cia);
|
||||
prop = device_find_property(dev, name);
|
||||
if (prop == (device_property*)0) {
|
||||
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);
|
||||
}
|
||||
emul_write_buffer(&args, data->arguments,
|
||||
sizeof(args),
|
||||
processor, cia);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned_word
|
||||
chirp_emul_write(os_emul_data *data,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
struct write_args {
|
||||
unsigned32 service;
|
||||
unsigned32 n_args;
|
||||
unsigned32 n_returns;
|
||||
/*in*/
|
||||
unsigned32 ihandle;
|
||||
unsigned32 addr;
|
||||
unsigned32 len;
|
||||
/*out*/
|
||||
unsigned32 actual;
|
||||
} 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)
|
||||
return -1;
|
||||
/* read in the arguments */
|
||||
actual = T2H_4(args.len);
|
||||
if (actual > sizeof(buf))
|
||||
actual = sizeof(buf);
|
||||
emul_read_buffer(buf,
|
||||
T2H_4(args.addr),
|
||||
actual,
|
||||
processor, cia);
|
||||
/* write it out */
|
||||
write(BE2H_4(args.ihandle), buf, actual);
|
||||
args.actual = H2T_4(actual);
|
||||
emul_write_buffer(&args, data->arguments,
|
||||
sizeof(args),
|
||||
processor, cia);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned_word
|
||||
chirp_emul_exit(os_emul_data *data,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
error("chirp_emul_exit not implemnented\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
chirp_services services[] = {
|
||||
{ "finddevice", chirp_emul_finddevice },
|
||||
{ "getprop", chirp_emul_getprop },
|
||||
{ "write", chirp_emul_write },
|
||||
{ "exit", chirp_emul_exit },
|
||||
{ 0, /* sentinal */ },
|
||||
};
|
||||
|
||||
|
||||
/* main handlers */
|
||||
|
||||
/* Any starting address greater than this is assumed to be an Chirp
|
||||
rather than VEA */
|
||||
|
||||
#ifndef CHIRP_START_ADDRESS
|
||||
#define CHIRP_START_ADDRESS 0x80000000
|
||||
#endif
|
||||
|
||||
typedef struct _chirp_note_desc {
|
||||
signed32 real_mode;
|
||||
signed32 real_base;
|
||||
signed32 real_size;
|
||||
signed32 virt_base;
|
||||
signed32 virt_size;
|
||||
} chirp_note_desc;
|
||||
|
||||
typedef struct _chirp_note {
|
||||
chirp_note_desc desc;
|
||||
int found;
|
||||
} chirp_note;
|
||||
|
||||
typedef struct _chirp_note_head {
|
||||
unsigned32 namesz;
|
||||
unsigned32 descsz;
|
||||
unsigned32 type;
|
||||
} chirp_note_head;
|
||||
|
||||
static void
|
||||
map_over_chirp_note(bfd *image,
|
||||
asection *sect,
|
||||
PTR obj)
|
||||
{
|
||||
chirp_note *note = (chirp_note*)obj;
|
||||
if (strcmp(sect->name, ".note") == 0) {
|
||||
chirp_note_head head;
|
||||
char name[16];
|
||||
/* check the head */
|
||||
if (!bfd_get_section_contents(image, sect,
|
||||
&head, 0, sizeof(head)))
|
||||
return;
|
||||
head.namesz = bfd_get_32(image, (void*)&head.namesz);
|
||||
head.descsz = bfd_get_32(image, (void*)&head.descsz);
|
||||
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))
|
||||
return;
|
||||
if (!bfd_get_section_contents(image, sect,
|
||||
name, sizeof(head), head.namesz))
|
||||
return;
|
||||
if (strcmp(name, "PowerPC") != 0)
|
||||
return;
|
||||
/* get the contents */
|
||||
if (!bfd_get_section_contents(image, sect,
|
||||
¬e->desc, sizeof(head) + head.namesz,
|
||||
head.descsz))
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static os_emul_data *
|
||||
emul_chirp_create(device *root,
|
||||
bfd *image,
|
||||
const char *name)
|
||||
{
|
||||
os_emul_data *data;
|
||||
chirp_note note;
|
||||
|
||||
/* Sanity check that this really is the chosen emulation */
|
||||
if (name == NULL && image == NULL)
|
||||
return NULL;
|
||||
if (name != NULL
|
||||
&& strcmp(name, "ob") != 0
|
||||
&& strcmp(name, "ieee1274") != 0
|
||||
&& strcmp(name, "chrp") != 0
|
||||
&& strcmp(name, "chirp") != 0
|
||||
&& strcmp(name, "openboot") != 0)
|
||||
return NULL;
|
||||
|
||||
/* look for an elf note section */
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
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 htab_va = code_va + sizeof_code;
|
||||
|
||||
/* 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?",
|
||||
!image->xvec->byteorder_big_p);
|
||||
device_add_string_property(options,
|
||||
"env",
|
||||
"operating");
|
||||
device_add_boolean_property(options,
|
||||
"strict-alignment?",
|
||||
(WITH_ALIGNMENT == STRICT_ALIGNMENT
|
||||
|| !image->xvec->byteorder_big_p));
|
||||
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",
|
||||
bfd_get_start_address(image));
|
||||
device_add_integer_property(init_register,
|
||||
"sp",
|
||||
stack_va + sizeof_stack - 16);
|
||||
|
||||
/* init the code callback */
|
||||
device_add_integer_property(init_register,
|
||||
"r5",
|
||||
code_va);
|
||||
device_tree_add_found_uw_u_u(init, "", "data", code_ra, 4, 0x1);
|
||||
device_tree_add_found_uw_u_u(init, "", "data", code_ra+16, 4, 0x1);
|
||||
device_add_integer_property(init_register,
|
||||
"msr",
|
||||
(msr_machine_check_enable
|
||||
| (real_mode
|
||||
? 0
|
||||
: (msr_instruction_relocate
|
||||
| msr_data_relocate))
|
||||
| (image->xvec->byteorder_big_p
|
||||
? 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_integer_property(chosen,
|
||||
"stdout",
|
||||
1);
|
||||
}
|
||||
|
||||
/* FIXME - should come from the device tree */
|
||||
data = ZALLOC(os_emul_data);
|
||||
data->serving_instruction_ea = CHIRP_START_ADDRESS + sizeof_stack;;
|
||||
data->catching_instruction_ea = CHIRP_START_ADDRESS + sizeof_stack + 16;
|
||||
data->phandles = cap_create("chirp");
|
||||
data->root = root;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
emul_chirp_init(os_emul_data *emul_data,
|
||||
int nr_cpus)
|
||||
{
|
||||
emul_data->state = serving;
|
||||
cap_init(emul_data->phandles);
|
||||
}
|
||||
|
||||
static int
|
||||
emul_chirp_instruction_call(cpu *processor,
|
||||
unsigned_word cia,
|
||||
unsigned_word ra,
|
||||
os_emul_data *emul_data)
|
||||
{
|
||||
unsigned_word service_name_addr;
|
||||
unsigned_word result;
|
||||
char service_buf[32];
|
||||
char *service_name;
|
||||
chirp_services *service;
|
||||
|
||||
switch (emul_data->state) {
|
||||
case serving:
|
||||
/* verify then capture the current request */
|
||||
if (cia != emul_data->serving_instruction_ea)
|
||||
return 0;
|
||||
emul_data->return_address = LR;
|
||||
emul_data->arguments = cpu_registers(processor)->gpr[3];
|
||||
/* try to determine what to do */
|
||||
service_name_addr = emul_read_word(cpu_registers(processor)->gpr[3],
|
||||
processor, cia);
|
||||
service_name = emul_read_string(service_buf, service_name_addr,
|
||||
sizeof(service_buf), processor, cia);
|
||||
/* look it up */
|
||||
service = services;
|
||||
while (service->name != NULL && strcmp(service->name, service_name) != 0)
|
||||
service++;
|
||||
if (service->name == NULL) {
|
||||
cpu_registers(processor)->gpr[3] = 0;
|
||||
cpu_restart(processor, emul_data->return_address);
|
||||
}
|
||||
emul_data->service = service;
|
||||
TRACE(trace_os_emul, ("%s called from 0x%lx\n",
|
||||
service->name, emul_data->return_address));
|
||||
/* call upon it */
|
||||
result = service->handler(emul_data, processor, cia);
|
||||
break;
|
||||
default:
|
||||
error("emul_chirp_instruction_call() unknown internal state\n");
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* return to caller */
|
||||
cpu_registers(processor)->gpr[3] = result;
|
||||
cpu_restart(processor, emul_data->return_address);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const os_emul emul_chirp = {
|
||||
"chirp",
|
||||
emul_chirp_create,
|
||||
emul_chirp_init,
|
||||
NULL, /*system_call*/
|
||||
emul_chirp_instruction_call,
|
||||
0 /*data*/
|
||||
};
|
||||
|
||||
#endif
|
27
sim/ppc/emul_chirp.h
Normal file
27
sim/ppc/emul_chirp.h
Normal file
@ -0,0 +1,27 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _EMUL_CHIRP_H_
|
||||
#define _EMUL_CHIRP_H_
|
||||
|
||||
extern const os_emul emul_chirp;
|
||||
|
||||
#endif
|
@ -22,7 +22,12 @@
|
||||
#ifndef _EMUL_NETBSD_C_
|
||||
#define _EMUL_NETBSD_C_
|
||||
|
||||
|
||||
/* Note: this module is called via a table. There is no benefit in
|
||||
making it inline */
|
||||
|
||||
#include "emul_generic.h"
|
||||
#include "emul_netbsd.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
@ -41,6 +46,8 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
int getrusage();
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/dirent.h>
|
||||
@ -82,6 +89,14 @@ extern int errno;
|
||||
#endif
|
||||
|
||||
|
||||
/* NetBSD's idea of what is needed to implement emulations */
|
||||
|
||||
struct _os_emul_data {
|
||||
emul_syscall *syscalls;
|
||||
};
|
||||
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
write_stat(unsigned_word addr,
|
||||
struct stat buf,
|
||||
@ -177,7 +192,7 @@ write_direntries(unsigned_word addr,
|
||||
struct dirent *in = (struct dirent*)buf;
|
||||
ASSERT(in->d_reclen <= nbytes);
|
||||
out = (struct dirent*)zalloc(in->d_reclen);
|
||||
bcopy(in, out, in->d_reclen);
|
||||
memcpy(out/*dest*/, in/*src*/, in->d_reclen);
|
||||
H2T(out->d_fileno);
|
||||
H2T(out->d_reclen);
|
||||
H2T(out->d_type);
|
||||
@ -220,8 +235,8 @@ write_rusage(unsigned_word addr,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_exit(emulation *emul,
|
||||
static void
|
||||
do_exit(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -236,8 +251,8 @@ do_exit(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_read(emulation *emul,
|
||||
static void
|
||||
do_read(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -282,8 +297,8 @@ do_read(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_write(emulation *emul,
|
||||
static void
|
||||
do_write(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -321,8 +336,8 @@ do_write(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_open(emulation *emul,
|
||||
static void
|
||||
do_open(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -342,8 +357,8 @@ do_open(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_close(emulation *emul,
|
||||
static void
|
||||
do_close(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -359,8 +374,8 @@ do_close(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_break(emulation *emul,
|
||||
static void
|
||||
do_break(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -368,23 +383,23 @@ do_break(emulation *emul,
|
||||
/* just pass this onto the `vm' device */
|
||||
{
|
||||
psim *system = cpu_system(processor);
|
||||
const device *vm = psim_device(system, "/vm");
|
||||
device *vm = psim_device(system, "/vm");
|
||||
|
||||
if (WITH_TRACE && ppc_trace[trace_os_emul])
|
||||
printf_filtered ("0x%lx", (long)cpu_registers(processor)->gpr[arg0]);
|
||||
|
||||
SYS(break);
|
||||
vm->callback->ioctl(vm,
|
||||
system,
|
||||
processor,
|
||||
cia,
|
||||
0, /*ioctl*/
|
||||
NULL); /*ioctl-data*/
|
||||
device_ioctl(vm,
|
||||
system,
|
||||
processor,
|
||||
cia,
|
||||
0, /*ioctl*/
|
||||
NULL); /*ioctl-data*/
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_getpid(emulation *emul,
|
||||
static void
|
||||
do_getpid(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -395,8 +410,8 @@ do_getpid(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_getuid(emulation *emul,
|
||||
static void
|
||||
do_getuid(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -407,8 +422,8 @@ do_getuid(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_geteuid(emulation *emul,
|
||||
static void
|
||||
do_geteuid(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -419,8 +434,8 @@ do_geteuid(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_kill(emulation *emul,
|
||||
static void
|
||||
do_kill(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -433,14 +448,14 @@ do_kill(emulation *emul,
|
||||
printf_filtered ("%d, %d", (int)pid, sig);
|
||||
|
||||
SYS(kill);
|
||||
printf_filtered("SYS_kill at 0x%x - more to this than just being killed\n",
|
||||
cia);
|
||||
printf_filtered("SYS_kill at 0x%lx - more to this than just being killed\n",
|
||||
(long)cia);
|
||||
cpu_halt(processor, cia, was_signalled, sig);
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_dup(emulation *emul,
|
||||
static void
|
||||
do_dup(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -457,8 +472,8 @@ do_dup(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_getegid(emulation *emul,
|
||||
static void
|
||||
do_getegid(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -469,8 +484,8 @@ do_getegid(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_getgid(emulation *emul,
|
||||
static void
|
||||
do_getgid(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -481,8 +496,8 @@ do_getgid(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_sigprocmask(emulation *emul,
|
||||
static void
|
||||
do_sigprocmask(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -501,8 +516,8 @@ do_sigprocmask(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_ioctl(emulation *emul,
|
||||
static void
|
||||
do_ioctl(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -515,11 +530,7 @@ do_ioctl(emulation *emul,
|
||||
#if !WITH_NetBSD_HOST
|
||||
cpu_registers(processor)->gpr[arg0] = 0; /* just succeed */
|
||||
#else
|
||||
unsigned param_len = IOCPARM_LEN(request);
|
||||
unsigned basecmd = IOCBASECMD(request);
|
||||
unsigned group = IOCGROUP(request);
|
||||
unsigned dir = request & IOC_DIRMASK;
|
||||
char *argp = NULL;
|
||||
int status;
|
||||
SYS(ioctl);
|
||||
/* what we haven't done */
|
||||
@ -536,8 +547,8 @@ do_ioctl(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_umask(emulation *emul,
|
||||
static void
|
||||
do_umask(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -553,8 +564,8 @@ do_umask(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_dup2(emulation *emul,
|
||||
static void
|
||||
do_dup2(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -572,8 +583,8 @@ do_dup2(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_fcntl(emulation *emul,
|
||||
static void
|
||||
do_fcntl(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -593,8 +604,8 @@ do_fcntl(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_gettimeofday(emulation *emul,
|
||||
static void
|
||||
do_gettimeofday(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -621,8 +632,8 @@ do_gettimeofday(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_getrusage(emulation *emul,
|
||||
static void
|
||||
do_getrusage(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -648,8 +659,8 @@ do_getrusage(emulation *emul,
|
||||
#if !WITH_NetBSD_HOST
|
||||
#define do_fstatfs 0
|
||||
#else
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_fstatfs(emulation *emul,
|
||||
static void
|
||||
do_fstatfs(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -674,8 +685,8 @@ do_fstatfs(emulation *emul,
|
||||
#endif
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_stat(emulation *emul,
|
||||
static void
|
||||
do_stat(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -695,8 +706,8 @@ do_stat(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_fstat(emulation *emul,
|
||||
static void
|
||||
do_fstat(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -711,8 +722,8 @@ do_fstat(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_lstat(emulation *emul,
|
||||
static void
|
||||
do_lstat(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -732,8 +743,8 @@ do_lstat(emulation *emul,
|
||||
#if !WITH_NetBSD_HOST
|
||||
#define do_getdirentries 0
|
||||
#else
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_getdirentries(emulation *emul,
|
||||
static void
|
||||
do_getdirentries(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -766,24 +777,25 @@ do_getdirentries(emulation *emul,
|
||||
#endif
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do___syscall(emulation *emul,
|
||||
static void
|
||||
do___syscall(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
SYS(__syscall);
|
||||
emul_do_call(emul,
|
||||
cpu_registers(processor)->gpr[arg0],
|
||||
arg0 + 1,
|
||||
processor,
|
||||
cia);
|
||||
emul_do_system_call(emul,
|
||||
emul->syscalls,
|
||||
cpu_registers(processor)->gpr[arg0],
|
||||
arg0 + 1,
|
||||
processor,
|
||||
cia);
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do_lseek(emulation *emul,
|
||||
static void
|
||||
do_lseek(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -803,8 +815,8 @@ do_lseek(emulation *emul,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_EMUL_NETBSD void
|
||||
do___sysctl(emulation *emul,
|
||||
static void
|
||||
do___sysctl(os_emul_data *emul,
|
||||
unsigned call,
|
||||
const int arg0,
|
||||
cpu *processor,
|
||||
@ -830,7 +842,7 @@ do___sysctl(emulation *emul,
|
||||
name += sizeof(mib);
|
||||
|
||||
/* see what to do with it ... */
|
||||
switch (mib) {
|
||||
switch ((int)mib) {
|
||||
case 6/*CTL_HW*/:
|
||||
#if WITH_NetBSD_HOST && (CTL_HW != 6)
|
||||
# error "CTL_HW"
|
||||
@ -842,7 +854,7 @@ do___sysctl(emulation *emul,
|
||||
processor,
|
||||
cia);
|
||||
name += sizeof(mib);
|
||||
switch (mib) {
|
||||
switch ((int)mib) {
|
||||
case 7/*HW_PAGESIZE*/:
|
||||
#if WITH_NetBSD_HOST && (HW_PAGESIZE != 7)
|
||||
# error "HW_PAGESIZE"
|
||||
@ -864,7 +876,7 @@ do___sysctl(emulation *emul,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("sysctl() name[0]=%s unknown\n", (int)mib);
|
||||
error("sysctl() name[0]=%d unknown\n", (int)mib);
|
||||
break;
|
||||
}
|
||||
cpu_registers(processor)->gpr[3] = 0;
|
||||
@ -872,179 +884,179 @@ do___sysctl(emulation *emul,
|
||||
|
||||
|
||||
|
||||
static emul_call_descriptor netbsd_descriptors[] = {
|
||||
/* 0 */ { 0, "syscall", { 0, }, 0 },
|
||||
/* 1 */ { do_exit, "exit", { 0, }, 0 },
|
||||
/* 2 */ { 0, "fork", { 0, }, 0 },
|
||||
/* 3 */ { do_read, "read", { 0, }, 0 },
|
||||
/* 4 */ { do_write, "write", { 0, }, 0 },
|
||||
/* 5 */ { do_open, "open", { 0, }, 0 },
|
||||
/* 6 */ { do_close, "close", { 0, }, 0 },
|
||||
/* 7 */ { 0, "wait4", { 0, }, 0 },
|
||||
static emul_syscall_descriptor netbsd_descriptors[] = {
|
||||
/* 0 */ { 0, "syscall" },
|
||||
/* 1 */ { do_exit, "exit" },
|
||||
/* 2 */ { 0, "fork" },
|
||||
/* 3 */ { do_read, "read" },
|
||||
/* 4 */ { do_write, "write" },
|
||||
/* 5 */ { do_open, "open" },
|
||||
/* 6 */ { do_close, "close" },
|
||||
/* 7 */ { 0, "wait4" },
|
||||
{ 0, }, /* 8 is old creat */
|
||||
/* 9 */ { 0, "link", { 0, }, 0 },
|
||||
/* 10 */ { 0, "unlink", { 0, }, 0 },
|
||||
/* 9 */ { 0, "link" },
|
||||
/* 10 */ { 0, "unlink" },
|
||||
{ 0, }, /* 11 is obsolete execv */
|
||||
/* 12 */ { 0, "chdir", { 0, }, 0 },
|
||||
/* 13 */ { 0, "fchdir", { 0, }, 0 },
|
||||
/* 14 */ { 0, "mknod", { 0, }, 0 },
|
||||
/* 15 */ { 0, "chmod", { 0, }, 0 },
|
||||
/* 16 */ { 0, "chown", { 0, }, 0 },
|
||||
/* 17 */ { do_break, "break", { 0, }, 0 },
|
||||
/* 18 */ { 0, "getfsstat", { 0, }, 0 },
|
||||
/* 12 */ { 0, "chdir" },
|
||||
/* 13 */ { 0, "fchdir" },
|
||||
/* 14 */ { 0, "mknod" },
|
||||
/* 15 */ { 0, "chmod" },
|
||||
/* 16 */ { 0, "chown" },
|
||||
/* 17 */ { do_break, "break" },
|
||||
/* 18 */ { 0, "getfsstat" },
|
||||
{ 0, }, /* 19 is old lseek */
|
||||
/* 20 */ { do_getpid, "getpid", { 0, }, 0 },
|
||||
/* 21 */ { 0, "mount", { 0, }, 0 },
|
||||
/* 22 */ { 0, "unmount", { 0, }, 0 },
|
||||
/* 23 */ { 0, "setuid", { 0, }, 0 },
|
||||
/* 24 */ { do_getuid, "getuid", { 0, }, 0 },
|
||||
/* 25 */ { do_geteuid, "geteuid", { 0, }, 0 },
|
||||
/* 26 */ { 0, "ptrace", { 0, }, 0 },
|
||||
/* 27 */ { 0, "recvmsg", { 0, }, 0 },
|
||||
/* 28 */ { 0, "sendmsg", { 0, }, 0 },
|
||||
/* 29 */ { 0, "recvfrom", { 0, }, 0 },
|
||||
/* 30 */ { 0, "accept", { 0, }, 0 },
|
||||
/* 31 */ { 0, "getpeername", { 0, }, 0 },
|
||||
/* 32 */ { 0, "getsockname", { 0, }, 0 },
|
||||
/* 33 */ { 0, "access", { 0, }, 0 },
|
||||
/* 34 */ { 0, "chflags", { 0, }, 0 },
|
||||
/* 35 */ { 0, "fchflags", { 0, }, 0 },
|
||||
/* 36 */ { 0, "sync", { 0, }, 0 },
|
||||
/* 37 */ { do_kill, "kill", { 0, }, 0 },
|
||||
/* 20 */ { do_getpid, "getpid" },
|
||||
/* 21 */ { 0, "mount" },
|
||||
/* 22 */ { 0, "unmount" },
|
||||
/* 23 */ { 0, "setuid" },
|
||||
/* 24 */ { do_getuid, "getuid" },
|
||||
/* 25 */ { do_geteuid, "geteuid" },
|
||||
/* 26 */ { 0, "ptrace" },
|
||||
/* 27 */ { 0, "recvmsg" },
|
||||
/* 28 */ { 0, "sendmsg" },
|
||||
/* 29 */ { 0, "recvfrom" },
|
||||
/* 30 */ { 0, "accept" },
|
||||
/* 31 */ { 0, "getpeername" },
|
||||
/* 32 */ { 0, "getsockname" },
|
||||
/* 33 */ { 0, "access" },
|
||||
/* 34 */ { 0, "chflags" },
|
||||
/* 35 */ { 0, "fchflags" },
|
||||
/* 36 */ { 0, "sync" },
|
||||
/* 37 */ { do_kill, "kill" },
|
||||
{ 0, }, /* 38 is old stat */
|
||||
/* 39 */ { 0, "getppid", { 0, }, 0 },
|
||||
/* 39 */ { 0, "getppid" },
|
||||
{ 0, }, /* 40 is old lstat */
|
||||
/* 41 */ { do_dup, "dup", { 0, }, 0 },
|
||||
/* 42 */ { 0, "pipe", { 0, }, 0 },
|
||||
/* 43 */ { do_getegid, "getegid", { 0, }, 0 },
|
||||
/* 44 */ { 0, "profil", { 0, }, 0 },
|
||||
/* 45 */ { 0, "ktrace", { 0, }, 0 },
|
||||
/* 46 */ { 0, "sigaction", { 0, }, 0 },
|
||||
/* 47 */ { do_getgid, "getgid", { 0, }, 0 },
|
||||
/* 48 */ { do_sigprocmask, "sigprocmask", { 0, }, 0 },
|
||||
/* 49 */ { 0, "getlogin", { 0, }, 0 },
|
||||
/* 50 */ { 0, "setlogin", { 0, }, 0 },
|
||||
/* 51 */ { 0, "acct", { 0, }, 0 },
|
||||
/* 52 */ { 0, "sigpending", { 0, }, 0 },
|
||||
/* 53 */ { 0, "sigaltstack", { 0, }, 0 },
|
||||
/* 54 */ { do_ioctl, "ioctl", { 0, }, 0 },
|
||||
/* 55 */ { 0, "reboot", { 0, }, 0 },
|
||||
/* 56 */ { 0, "revoke", { 0, }, 0 },
|
||||
/* 57 */ { 0, "symlink", { 0, }, 0 },
|
||||
/* 58 */ { 0, "readlink", { 0, }, 0 },
|
||||
/* 59 */ { 0, "execve", { 0, }, 0 },
|
||||
/* 60 */ { do_umask, "umask", { 0, }, 0 },
|
||||
/* 61 */ { 0, "chroot", { 0, }, 0 },
|
||||
/* 41 */ { do_dup, "dup" },
|
||||
/* 42 */ { 0, "pipe" },
|
||||
/* 43 */ { do_getegid, "getegid" },
|
||||
/* 44 */ { 0, "profil" },
|
||||
/* 45 */ { 0, "ktrace" },
|
||||
/* 46 */ { 0, "sigaction" },
|
||||
/* 47 */ { do_getgid, "getgid" },
|
||||
/* 48 */ { do_sigprocmask, "sigprocmask" },
|
||||
/* 49 */ { 0, "getlogin" },
|
||||
/* 50 */ { 0, "setlogin" },
|
||||
/* 51 */ { 0, "acct" },
|
||||
/* 52 */ { 0, "sigpending" },
|
||||
/* 53 */ { 0, "sigaltstack" },
|
||||
/* 54 */ { do_ioctl, "ioctl" },
|
||||
/* 55 */ { 0, "reboot" },
|
||||
/* 56 */ { 0, "revoke" },
|
||||
/* 57 */ { 0, "symlink" },
|
||||
/* 58 */ { 0, "readlink" },
|
||||
/* 59 */ { 0, "execve" },
|
||||
/* 60 */ { do_umask, "umask" },
|
||||
/* 61 */ { 0, "chroot" },
|
||||
{ 0, }, /* 62 is old fstat */
|
||||
{ 0, }, /* 63 is old getkerninfo */
|
||||
{ 0, }, /* 64 is old getpagesize */
|
||||
/* 65 */ { 0, "msync", { 0, }, 0 },
|
||||
/* 66 */ { 0, "vfork", { 0, }, 0 },
|
||||
/* 65 */ { 0, "msync" },
|
||||
/* 66 */ { 0, "vfork" },
|
||||
{ 0, }, /* 67 is obsolete vread */
|
||||
{ 0, }, /* 68 is obsolete vwrite */
|
||||
/* 69 */ { 0, "sbrk", { 0, }, 0 },
|
||||
/* 70 */ { 0, "sstk", { 0, }, 0 },
|
||||
/* 69 */ { 0, "sbrk" },
|
||||
/* 70 */ { 0, "sstk" },
|
||||
{ 0, }, /* 71 is old mmap */
|
||||
/* 72 */ { 0, "vadvise", { 0, }, 0 },
|
||||
/* 73 */ { 0, "munmap", { 0, }, 0 },
|
||||
/* 74 */ { 0, "mprotect", { 0, }, 0 },
|
||||
/* 75 */ { 0, "madvise", { 0, }, 0 },
|
||||
/* 72 */ { 0, "vadvise" },
|
||||
/* 73 */ { 0, "munmap" },
|
||||
/* 74 */ { 0, "mprotect" },
|
||||
/* 75 */ { 0, "madvise" },
|
||||
{ 0, }, /* 76 is obsolete vhangup */
|
||||
{ 0, }, /* 77 is obsolete vlimit */
|
||||
/* 78 */ { 0, "mincore", { 0, }, 0 },
|
||||
/* 79 */ { 0, "getgroups", { 0, }, 0 },
|
||||
/* 80 */ { 0, "setgroups", { 0, }, 0 },
|
||||
/* 81 */ { 0, "getpgrp", { 0, }, 0 },
|
||||
/* 82 */ { 0, "setpgid", { 0, }, 0 },
|
||||
/* 83 */ { 0, "setitimer", { 0, }, 0 },
|
||||
/* 78 */ { 0, "mincore" },
|
||||
/* 79 */ { 0, "getgroups" },
|
||||
/* 80 */ { 0, "setgroups" },
|
||||
/* 81 */ { 0, "getpgrp" },
|
||||
/* 82 */ { 0, "setpgid" },
|
||||
/* 83 */ { 0, "setitimer" },
|
||||
{ 0, }, /* 84 is old wait */
|
||||
/* 85 */ { 0, "swapon", { 0, }, 0 },
|
||||
/* 86 */ { 0, "getitimer", { 0, }, 0 },
|
||||
/* 85 */ { 0, "swapon" },
|
||||
/* 86 */ { 0, "getitimer" },
|
||||
{ 0, }, /* 87 is old gethostname */
|
||||
{ 0, }, /* 88 is old sethostname */
|
||||
{ 0, }, /* 89 is old getdtablesize */
|
||||
{ do_dup2, "dup2", { 0, }, 0 },
|
||||
{ do_dup2, "dup2" },
|
||||
{ 0, }, /* 91 */
|
||||
/* 92 */ { do_fcntl, "fcntl", { 0, }, 0 },
|
||||
/* 93 */ { 0, "select", { 0, }, 0 },
|
||||
/* 92 */ { do_fcntl, "fcntl" },
|
||||
/* 93 */ { 0, "select" },
|
||||
{ 0, }, /* 94 */
|
||||
/* 95 */ { 0, "fsync", { 0, }, 0 },
|
||||
/* 96 */ { 0, "setpriority", { 0, }, 0 },
|
||||
/* 97 */ { 0, "socket", { 0, }, 0 },
|
||||
/* 98 */ { 0, "connect", { 0, }, 0 },
|
||||
/* 95 */ { 0, "fsync" },
|
||||
/* 96 */ { 0, "setpriority" },
|
||||
/* 97 */ { 0, "socket" },
|
||||
/* 98 */ { 0, "connect" },
|
||||
{ 0, }, /* 99 is old accept */
|
||||
/* 100 */ { 0, "getpriority", { 0, }, 0 },
|
||||
/* 100 */ { 0, "getpriority" },
|
||||
{ 0, }, /* 101 is old send */
|
||||
{ 0, }, /* 102 is old recv */
|
||||
/* 103 */ { 0, "sigreturn", { 0, }, 0 },
|
||||
/* 104 */ { 0, "bind", { 0, }, 0 },
|
||||
/* 105 */ { 0, "setsockopt", { 0, }, 0 },
|
||||
/* 106 */ { 0, "listen", { 0, }, 0 },
|
||||
/* 103 */ { 0, "sigreturn" },
|
||||
/* 104 */ { 0, "bind" },
|
||||
/* 105 */ { 0, "setsockopt" },
|
||||
/* 106 */ { 0, "listen" },
|
||||
{ 0, }, /* 107 is obsolete vtimes */
|
||||
{ 0, }, /* 108 is old sigvec */
|
||||
{ 0, }, /* 109 is old sigblock */
|
||||
{ 0, }, /* 110 is old sigsetmask */
|
||||
/* 111 */ { 0, "sigsuspend", { 0, }, 0 },
|
||||
/* 111 */ { 0, "sigsuspend" },
|
||||
{ 0, }, /* 112 is old sigstack */
|
||||
{ 0, }, /* 113 is old recvmsg */
|
||||
{ 0, }, /* 114 is old sendmsg */
|
||||
/* - is obsolete vtrace */ { 0, "vtrace 115", { 0, }, 0 },
|
||||
/* 116 */ { do_gettimeofday, "gettimeofday", { 0, }, 0 },
|
||||
/* 117 */ { do_getrusage, "getrusage", { 0, }, 0 },
|
||||
/* 118 */ { 0, "getsockopt", { 0, }, 0 },
|
||||
/* 119 */ { 0, "resuba", { 0, }, 0 },
|
||||
/* 120 */ { 0, "readv", { 0, }, 0 },
|
||||
/* 121 */ { 0, "writev", { 0, }, 0 },
|
||||
/* 122 */ { 0, "settimeofday", { 0, }, 0 },
|
||||
/* 123 */ { 0, "fchown", { 0, }, 0 },
|
||||
/* 124 */ { 0, "fchmod", { 0, }, 0 },
|
||||
/* - is obsolete vtrace */ { 0, "vtrace 115" },
|
||||
/* 116 */ { do_gettimeofday, "gettimeofday" },
|
||||
/* 117 */ { do_getrusage, "getrusage" },
|
||||
/* 118 */ { 0, "getsockopt" },
|
||||
/* 119 */ { 0, "resuba" },
|
||||
/* 120 */ { 0, "readv" },
|
||||
/* 121 */ { 0, "writev" },
|
||||
/* 122 */ { 0, "settimeofday" },
|
||||
/* 123 */ { 0, "fchown" },
|
||||
/* 124 */ { 0, "fchmod" },
|
||||
{ 0, }, /* 125 is old recvfrom */
|
||||
{ 0, }, /* 126 is old setreuid */
|
||||
{ 0, }, /* 127 is old setregid */
|
||||
/* 128 */ { 0, "rename", { 0, }, 0 },
|
||||
/* 128 */ { 0, "rename" },
|
||||
{ 0, }, /* 129 is old truncate */
|
||||
{ 0, }, /* 130 is old ftruncate */
|
||||
/* 131 */ { 0, "flock", { 0, }, 0 },
|
||||
/* 132 */ { 0, "mkfifo", { 0, }, 0 },
|
||||
/* 133 */ { 0, "sendto", { 0, }, 0 },
|
||||
/* 134 */ { 0, "shutdown", { 0, }, 0 },
|
||||
/* 135 */ { 0, "socketpair", { 0, }, 0 },
|
||||
/* 136 */ { 0, "mkdir", { 0, }, 0 },
|
||||
/* 137 */ { 0, "rmdir", { 0, }, 0 },
|
||||
/* 138 */ { 0, "utimes", { 0, }, 0 },
|
||||
/* 131 */ { 0, "flock" },
|
||||
/* 132 */ { 0, "mkfifo" },
|
||||
/* 133 */ { 0, "sendto" },
|
||||
/* 134 */ { 0, "shutdown" },
|
||||
/* 135 */ { 0, "socketpair" },
|
||||
/* 136 */ { 0, "mkdir" },
|
||||
/* 137 */ { 0, "rmdir" },
|
||||
/* 138 */ { 0, "utimes" },
|
||||
{ 0, }, /* 139 is obsolete 4.2 sigreturn */
|
||||
/* 140 */ { 0, "adjtime", { 0, }, 0 },
|
||||
/* 140 */ { 0, "adjtime" },
|
||||
{ 0, }, /* 141 is old getpeername */
|
||||
{ 0, }, /* 142 is old gethostid */
|
||||
{ 0, }, /* 143 is old sethostid */
|
||||
{ 0, }, /* 144 is old getrlimit */
|
||||
{ 0, }, /* 145 is old setrlimit */
|
||||
{ 0, }, /* 146 is old killpg */
|
||||
/* 147 */ { 0, "setsid", { 0, }, 0 },
|
||||
/* 148 */ { 0, "quotactl", { 0, }, 0 },
|
||||
/* 147 */ { 0, "setsid" },
|
||||
/* 148 */ { 0, "quotactl" },
|
||||
{ 0, }, /* 149 is old quota */
|
||||
{ 0, }, /* 150 is old getsockname */
|
||||
{ 0, }, /* 151 */
|
||||
{ 0, }, /* 152 */
|
||||
{ 0, }, /* 153 */
|
||||
{ 0, }, /* 154 */
|
||||
/* 155 */ { 0, "nfssvc", { 0, }, 0 },
|
||||
/* 155 */ { 0, "nfssvc" },
|
||||
{ 0, }, /* 156 is old getdirentries */
|
||||
/* 157 */ { 0, "statfs", { 0, }, 0 },
|
||||
/* 158 */ { do_fstatfs, "fstatfs", { 0, }, 0 },
|
||||
/* 157 */ { 0, "statfs" },
|
||||
/* 158 */ { do_fstatfs, "fstatfs" },
|
||||
{ 0, }, /* 159 */
|
||||
{ 0, }, /* 160 */
|
||||
/* 161 */ { 0, "getfh", { 0, }, 0 },
|
||||
/* 161 */ { 0, "getfh" },
|
||||
{ 0, }, /* 162 is old getdomainname */
|
||||
{ 0, }, /* 163 is old setdomainname */
|
||||
{ 0, }, /* 164 is old uname */
|
||||
/* 165 */ { 0, "sysarch", { 0, }, 0 },
|
||||
/* 165 */ { 0, "sysarch" },
|
||||
{ 0, }, /* 166 */
|
||||
{ 0, }, /* 167 */
|
||||
{ 0, }, /* 168 */
|
||||
/* 169 */ { 0, "semsys", { 0, }, 0 },
|
||||
/* 170 */ { 0, "msgsys", { 0, }, 0 },
|
||||
/* 171 */ { 0, "shmsys", { 0, }, 0 },
|
||||
/* 169 */ { 0, "semsys" },
|
||||
/* 170 */ { 0, "msgsys" },
|
||||
/* 171 */ { 0, "shmsys" },
|
||||
{ 0, }, /* 172 */
|
||||
{ 0, }, /* 173 */
|
||||
{ 0, }, /* 174 */
|
||||
@ -1054,30 +1066,30 @@ static emul_call_descriptor netbsd_descriptors[] = {
|
||||
{ 0, }, /* 178 */
|
||||
{ 0, }, /* 179 */
|
||||
{ 0, }, /* 180 */
|
||||
/* 181 */ { 0, "setgid", { 0, }, 0 },
|
||||
/* 182 */ { 0, "setegid", { 0, }, 0 },
|
||||
/* 183 */ { 0, "seteuid", { 0, }, 0 },
|
||||
/* 184 */ { 0, "lfs_bmapv", { 0, }, 0 },
|
||||
/* 185 */ { 0, "lfs_markv", { 0, }, 0 },
|
||||
/* 186 */ { 0, "lfs_segclean", { 0, }, 0 },
|
||||
/* 187 */ { 0, "lfs_segwait", { 0, }, 0 },
|
||||
/* 188 */ { do_stat, "stat", { 0, }, 0 },
|
||||
/* 189 */ { do_fstat, "fstat", { 0, }, 0 },
|
||||
/* 190 */ { do_lstat, "lstat", { 0, }, 0 },
|
||||
/* 191 */ { 0, "pathconf", { 0, }, 0 },
|
||||
/* 192 */ { 0, "fpathconf", { 0, }, 0 },
|
||||
/* 181 */ { 0, "setgid" },
|
||||
/* 182 */ { 0, "setegid" },
|
||||
/* 183 */ { 0, "seteuid" },
|
||||
/* 184 */ { 0, "lfs_bmapv" },
|
||||
/* 185 */ { 0, "lfs_markv" },
|
||||
/* 186 */ { 0, "lfs_segclean" },
|
||||
/* 187 */ { 0, "lfs_segwait" },
|
||||
/* 188 */ { do_stat, "stat" },
|
||||
/* 189 */ { do_fstat, "fstat" },
|
||||
/* 190 */ { do_lstat, "lstat" },
|
||||
/* 191 */ { 0, "pathconf" },
|
||||
/* 192 */ { 0, "fpathconf" },
|
||||
{ 0, }, /* 193 */
|
||||
/* 194 */ { 0, "getrlimit", { 0, }, 0 },
|
||||
/* 195 */ { 0, "setrlimit", { 0, }, 0 },
|
||||
/* 196 */ { do_getdirentries, "getdirentries", { 0, }, 0 },
|
||||
/* 197 */ { 0, "mmap", { 0, }, 0 },
|
||||
/* 198 */ { do___syscall, "__syscall", { 0, }, 0 },
|
||||
/* 199 */ { do_lseek, "lseek", { 0, }, 0 },
|
||||
/* 200 */ { 0, "truncate", { 0, }, 0 },
|
||||
/* 201 */ { 0, "ftruncate", { 0, }, 0 },
|
||||
/* 202 */ { do___sysctl, "__sysctl", { 0, }, 0 },
|
||||
/* 203 */ { 0, "mlock", { 0, }, 0 },
|
||||
/* 204 */ { 0, "munlock", { 0, }, 0 },
|
||||
/* 194 */ { 0, "getrlimit" },
|
||||
/* 195 */ { 0, "setrlimit" },
|
||||
/* 196 */ { do_getdirentries, "getdirentries" },
|
||||
/* 197 */ { 0, "mmap" },
|
||||
/* 198 */ { do___syscall, "__syscall" },
|
||||
/* 199 */ { do_lseek, "lseek" },
|
||||
/* 200 */ { 0, "truncate" },
|
||||
/* 201 */ { 0, "ftruncate" },
|
||||
/* 202 */ { do___sysctl, "__sysctl" },
|
||||
/* 203 */ { 0, "mlock" },
|
||||
/* 204 */ { 0, "munlock" },
|
||||
};
|
||||
|
||||
static char *(netbsd_error_names[]) = {
|
||||
@ -1201,7 +1213,7 @@ static char *(netbsd_signal_names[]) = {
|
||||
/* 31 */ "SIGUSR2",
|
||||
};
|
||||
|
||||
emulation emul_netbsd = {
|
||||
static emul_syscall emul_netbsd_syscalls = {
|
||||
netbsd_descriptors,
|
||||
sizeof(netbsd_descriptors) / sizeof(netbsd_descriptors[0]),
|
||||
netbsd_error_names,
|
||||
@ -1210,4 +1222,127 @@ emulation emul_netbsd = {
|
||||
sizeof(netbsd_signal_names) / sizeof(netbsd_signal_names[0]),
|
||||
};
|
||||
|
||||
#endif /* _EMUL_NETBSD_C_ */
|
||||
|
||||
/* NetBSD's os_emul interface, most are just passed on to the generic
|
||||
syscall stuff */
|
||||
|
||||
static os_emul_data *
|
||||
emul_netbsd_create(device *root,
|
||||
bfd *image,
|
||||
const char *name)
|
||||
{
|
||||
unsigned_word top_of_stack;
|
||||
unsigned stack_size;
|
||||
int elf_binary;
|
||||
os_emul_data *bsd_data;
|
||||
|
||||
/* check that this emulation is really for us */
|
||||
if (name != NULL && strcmp(name, "netbsd") != 0)
|
||||
return NULL;
|
||||
if (image == NULL)
|
||||
return NULL;
|
||||
|
||||
|
||||
/* merge any emulation specific entries into the device tree */
|
||||
|
||||
/* establish a few defaults */
|
||||
if (image->xvec->flavour == bfd_target_elf_flavour) {
|
||||
elf_binary = 1;
|
||||
top_of_stack = 0xe0000000;
|
||||
stack_size = 0x00100000;
|
||||
}
|
||||
else {
|
||||
elf_binary = 0;
|
||||
top_of_stack = 0x20000000;
|
||||
stack_size = 0x00100000;
|
||||
}
|
||||
|
||||
/* options */
|
||||
{
|
||||
device *options = device_tree_add_found(root, "/", "options");
|
||||
device_add_integer_property(options, "smp", 1); /* always */
|
||||
device_add_boolean_property(options, "little-endian?",
|
||||
!image->xvec->byteorder_big_p);
|
||||
device_add_string_property(options, "env",
|
||||
(WITH_ENVIRONMENT == USER_ENVIRONMENT
|
||||
? "user" : "virtual"));
|
||||
device_add_boolean_property(options, "strict-alignment?",
|
||||
(WITH_ALIGNMENT == STRICT_ALIGNMENT
|
||||
|| !image->xvec->byteorder_big_p));
|
||||
device_add_boolean_property(options, "floating-point?",
|
||||
WITH_FLOATING_POINT);
|
||||
device_add_string_property(options, "os-emul", "netbsd");
|
||||
}
|
||||
|
||||
/* virtual memory - handles growth of stack/heap */
|
||||
{
|
||||
device *vm_node = device_tree_add_found_uw_u(root, "/", "vm",
|
||||
top_of_stack - stack_size,
|
||||
stack_size);
|
||||
device *vm_map_binary = device_tree_add_found(vm_node, "", "map-binary");
|
||||
device_add_null_property(vm_map_binary,
|
||||
bfd_get_filename(image));
|
||||
}
|
||||
|
||||
/* finish the init */
|
||||
{
|
||||
device *init = device_tree_add_found(root, "/", "init");
|
||||
{
|
||||
device *init_register = device_tree_add_found(init, "", "register");
|
||||
device_add_integer_property(init_register,
|
||||
"pc",
|
||||
bfd_get_start_address(image));
|
||||
device_add_integer_property(init_register,
|
||||
"sp",
|
||||
top_of_stack);
|
||||
device_add_integer_property(init_register,
|
||||
"msr",
|
||||
(image->xvec->byteorder_big_p
|
||||
? 0
|
||||
: msr_little_endian_mode));
|
||||
}
|
||||
{
|
||||
device *init_stack = device_tree_add_found(init, "", "stack");
|
||||
device_add_null_property(init_stack,
|
||||
(elf_binary
|
||||
? "elf"
|
||||
: "xcoff"));
|
||||
}
|
||||
}
|
||||
|
||||
/* finally our emulation data */
|
||||
bsd_data = ZALLOC(os_emul_data);
|
||||
bsd_data->syscalls = &emul_netbsd_syscalls;
|
||||
return bsd_data;
|
||||
}
|
||||
|
||||
static void
|
||||
emul_netbsd_init(os_emul_data *emul_data,
|
||||
int nr_cpus)
|
||||
{
|
||||
/* nothing yet */
|
||||
}
|
||||
|
||||
static void
|
||||
emul_netbsd_system_call(cpu *processor,
|
||||
unsigned_word cia,
|
||||
os_emul_data *emul_data)
|
||||
{
|
||||
emul_do_system_call(emul_data,
|
||||
emul_data->syscalls,
|
||||
cpu_registers(processor)->gpr[0],
|
||||
3, /*r3 contains arg0*/
|
||||
processor,
|
||||
cia);
|
||||
}
|
||||
|
||||
const os_emul emul_netbsd = {
|
||||
"netbsd",
|
||||
emul_netbsd_create,
|
||||
emul_netbsd_init,
|
||||
emul_netbsd_system_call,
|
||||
0, /*instruction_call*/
|
||||
0 /*data*/
|
||||
};
|
||||
|
||||
#endif _EMUL_NETBSD_C_
|
||||
|
@ -22,10 +22,6 @@
|
||||
#ifndef _INTERRUPTS_C_
|
||||
#define _INTERRUPTS_C_
|
||||
|
||||
#ifndef STATIC_INLINE_INTERRUPTS
|
||||
#define STATIC_INLINE_INTERRUPTS STATIC_INLINE
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "cpu.h"
|
||||
@ -42,7 +38,7 @@
|
||||
interrupts */
|
||||
|
||||
|
||||
STATIC_INLINE_INTERRUPTS msreg
|
||||
msreg STATIC_INLINE_INTERRUPTS
|
||||
interrupt_msr(msreg old_msr,
|
||||
msreg msr_clear,
|
||||
msreg msr_set)
|
||||
@ -67,7 +63,7 @@ interrupt_msr(msreg old_msr,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_INTERRUPTS msreg
|
||||
msreg STATIC_INLINE_INTERRUPTS
|
||||
interrupt_srr1(msreg old_msr,
|
||||
msreg srr1_clear,
|
||||
msreg srr1_set)
|
||||
@ -80,7 +76,7 @@ interrupt_srr1(msreg old_msr,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_INTERRUPTS unsigned_word
|
||||
unsigned_word STATIC_INLINE_INTERRUPTS
|
||||
interrupt_base_ea(msreg msr)
|
||||
{
|
||||
if (msr & msr_interrupt_prefix)
|
||||
@ -93,7 +89,7 @@ interrupt_base_ea(msreg msr)
|
||||
/* finish off an interrupt for the OEA model, updating all registers
|
||||
and forcing a restart of the processor */
|
||||
|
||||
STATIC_INLINE_INTERRUPTS unsigned_word
|
||||
unsigned_word STATIC_INLINE_INTERRUPTS
|
||||
perform_oea_interrupt(cpu *processor,
|
||||
unsigned_word cia,
|
||||
unsigned_word vector_offset,
|
||||
@ -117,9 +113,9 @@ perform_oea_interrupt(cpu *processor,
|
||||
}
|
||||
|
||||
|
||||
INLINE_INTERRUPTS void machine_check_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia)
|
||||
void INLINE_INTERRUPTS
|
||||
machine_check_interrupt(cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
switch (CURRENT_ENVIRONMENT) {
|
||||
|
||||
@ -139,7 +135,7 @@ INLINE_INTERRUPTS void machine_check_interrupt
|
||||
}
|
||||
|
||||
|
||||
INLINE_INTERRUPTS void
|
||||
void INLINE_INTERRUPTS
|
||||
data_storage_interrupt(cpu *processor,
|
||||
unsigned_word cia,
|
||||
unsigned_word ea,
|
||||
@ -190,7 +186,7 @@ data_storage_interrupt(cpu *processor,
|
||||
}
|
||||
|
||||
|
||||
INLINE_INTERRUPTS void
|
||||
void INLINE_INTERRUPTS
|
||||
instruction_storage_interrupt(cpu *processor,
|
||||
unsigned_word cia,
|
||||
storage_interrupt_reasons reason)
|
||||
@ -204,7 +200,6 @@ instruction_storage_interrupt(cpu *processor,
|
||||
|
||||
case OPERATING_ENVIRONMENT:
|
||||
{
|
||||
unsigned_word nia;
|
||||
msreg srr1_set;
|
||||
switch(reason) {
|
||||
case hash_table_miss_storage_interrupt:
|
||||
@ -236,10 +231,10 @@ instruction_storage_interrupt(cpu *processor,
|
||||
|
||||
|
||||
|
||||
INLINE_INTERRUPTS void alignment_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia,
|
||||
unsigned_word ra)
|
||||
void INLINE_INTERRUPTS
|
||||
alignment_interrupt(cpu *processor,
|
||||
unsigned_word cia,
|
||||
unsigned_word ra)
|
||||
{
|
||||
switch (CURRENT_ENVIRONMENT) {
|
||||
|
||||
@ -263,7 +258,7 @@ INLINE_INTERRUPTS void alignment_interrupt
|
||||
|
||||
|
||||
|
||||
INLINE_INTERRUPTS void
|
||||
void INLINE_INTERRUPTS
|
||||
program_interrupt(cpu *processor,
|
||||
unsigned_word cia,
|
||||
program_interrupt_reasons reason)
|
||||
@ -307,7 +302,7 @@ program_interrupt(cpu *processor,
|
||||
}
|
||||
|
||||
|
||||
INLINE_INTERRUPTS void
|
||||
void INLINE_INTERRUPTS
|
||||
floating_point_unavailable_interrupt(cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
@ -329,7 +324,7 @@ floating_point_unavailable_interrupt(cpu *processor,
|
||||
}
|
||||
|
||||
|
||||
INLINE_INTERRUPTS void
|
||||
void INLINE_INTERRUPTS
|
||||
system_call_interrupt(cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
@ -337,7 +332,7 @@ system_call_interrupt(cpu *processor,
|
||||
|
||||
case USER_ENVIRONMENT:
|
||||
case VIRTUAL_ENVIRONMENT:
|
||||
os_emul_call(processor, cia);
|
||||
os_emul_system_call(processor, cia);
|
||||
cpu_restart(processor, cia+4);
|
||||
|
||||
case OPERATING_ENVIRONMENT:
|
||||
@ -350,11 +345,11 @@ system_call_interrupt(cpu *processor,
|
||||
}
|
||||
}
|
||||
|
||||
INLINE_INTERRUPTS void
|
||||
void INLINE_INTERRUPTS
|
||||
trace_interrupt(cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
INLINE_INTERRUPTS void
|
||||
void INLINE_INTERRUPTS
|
||||
floating_point_assist_interrupt(cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
@ -379,7 +374,7 @@ floating_point_assist_interrupt(cpu *processor,
|
||||
|
||||
/* handle an externally generated event */
|
||||
|
||||
INLINE_INTERRUPTS int
|
||||
int INLINE_INTERRUPTS
|
||||
decrementer_interrupt(cpu *processor)
|
||||
{
|
||||
if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
|
||||
@ -394,7 +389,7 @@ decrementer_interrupt(cpu *processor)
|
||||
}
|
||||
}
|
||||
|
||||
INLINE_INTERRUPTS int
|
||||
int INLINE_INTERRUPTS
|
||||
external_interrupt(cpu *processor)
|
||||
{
|
||||
if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
|
||||
|
152
sim/ppc/interrupts.h
Normal file
152
sim/ppc/interrupts.h
Normal file
@ -0,0 +1,152 @@
|
||||
/* This file is part of the program psim.
|
||||
|
||||
Copyright (C) 1994-1995, 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _INTERRUPTS_H_
|
||||
#define _INTERRUPTS_H_
|
||||
|
||||
/* Interrupts:
|
||||
|
||||
The code below handles two different types of interrupts.
|
||||
Synchronous and Asynchronous.
|
||||
|
||||
Synchronous:
|
||||
|
||||
Interrupts that must immediately force either an abort or restart
|
||||
of a current instruction are implemented by forcing an instruction
|
||||
restart. (or to put it another way, long jump). In looking at the
|
||||
code it may occure to you that, for some interrupts, they could
|
||||
return instead of restarting the cpu (eg system_call). While true
|
||||
(it once was like that) I've decided to make the behavour of all
|
||||
interrupt routines roughly identical.
|
||||
|
||||
Because, a cpu's recorded state (ie what is in the cpu structure)
|
||||
is allowed to lag behind the cpu's true current state (eg PC not
|
||||
updated) sycnronous interrupt handers are parameterized with the
|
||||
the cpu being interrupted so that, as part of moddeling the
|
||||
interrupt, the cpu's state can be updated.
|
||||
|
||||
Asynchronous:
|
||||
|
||||
Interrupts such as reset or external exception are delivered using
|
||||
more normal (returning) functions. It is assumed that these
|
||||
functions are called out side of the normal processor execution
|
||||
cycle. */
|
||||
|
||||
|
||||
/* Software generated interrupts.
|
||||
|
||||
The below are generated by software driven events. For instance,
|
||||
an invalid instruction or access (virtual or physical) to an
|
||||
invalid address */
|
||||
|
||||
typedef enum {
|
||||
direct_store_storage_interrupt,
|
||||
hash_table_miss_storage_interrupt,
|
||||
protection_violation_storage_interrupt,
|
||||
earwax_violation_storage_interrupt,
|
||||
segment_table_miss_storage_interrupt,
|
||||
earwax_disabled_storage_interrupt,
|
||||
vea_storage_interrupt,
|
||||
} storage_interrupt_reasons;
|
||||
|
||||
|
||||
void INLINE_INTERRUPTS data_storage_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia,
|
||||
unsigned_word ea,
|
||||
storage_interrupt_reasons reason,
|
||||
int is_store);
|
||||
|
||||
void INLINE_INTERRUPTS instruction_storage_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia,
|
||||
storage_interrupt_reasons reason);
|
||||
|
||||
void INLINE_INTERRUPTS alignment_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia,
|
||||
unsigned_word ra);
|
||||
|
||||
typedef enum {
|
||||
floating_point_enabled_program_interrupt,
|
||||
illegal_instruction_program_interrupt,
|
||||
privileged_instruction_program_interrupt,
|
||||
trap_program_interrupt,
|
||||
nr_program_interrupt_reasons
|
||||
} program_interrupt_reasons;
|
||||
|
||||
void INLINE_INTERRUPTS program_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia,
|
||||
program_interrupt_reasons reason);
|
||||
|
||||
void INLINE_INTERRUPTS floating_point_unavailable_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
void INLINE_INTERRUPTS system_call_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
void INLINE_INTERRUPTS trace_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
void INLINE_INTERRUPTS floating_point_assist_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
void INLINE_INTERRUPTS machine_check_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
/* Bit of a funny one. One of the trap instructions has been marked
|
||||
as the breakpoint instruction. This special case calls this
|
||||
interrupt routine */
|
||||
|
||||
void INLINE_INTERRUPTS breakpoint_interrupt
|
||||
(cpu *processor,
|
||||
unsigned_word cia);
|
||||
|
||||
/* Hardware generated interrupts
|
||||
|
||||
These hardware generated interrupt routines are called outside of
|
||||
the instruction execution cycle and so return normally.
|
||||
|
||||
More importantly, they assume that the current instruction address
|
||||
held within the processor is correct.
|
||||
|
||||
Return a non zero value if the interrupt was not successfully
|
||||
delivered */
|
||||
|
||||
int INLINE_INTERRUPTS decrementer_interrupt
|
||||
(cpu *processor);
|
||||
|
||||
int INLINE_INTERRUPTS hard_system_reset
|
||||
(cpu *processor);
|
||||
|
||||
int INLINE_INTERRUPTS soft_system_reset
|
||||
(cpu *processor);
|
||||
|
||||
int INLINE_INTERRUPTS external_interrupt
|
||||
(cpu *processor);
|
||||
|
||||
#endif /* _INTERRUPTS_H_ */
|
95
sim/ppc/ppc-opcode-test-1
Normal file
95
sim/ppc/ppc-opcode-test-1
Normal file
@ -0,0 +1,95 @@
|
||||
#
|
||||
# This file is part of the program psim.
|
||||
#
|
||||
# Copyright (C) 1994-1995, 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
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Instruction decode:
|
||||
#
|
||||
# The table that follows is used by gen to construct a decision tree
|
||||
# that can identify each possible instruction. Gen then outputs this
|
||||
# decision tree as (according to config) a table or switch statement
|
||||
# as the function idecode.
|
||||
#
|
||||
# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS
|
||||
# determines of the semantic functions themselves should be expanded
|
||||
# in a similar way.
|
||||
#
|
||||
# The table contains the following entries:
|
||||
#
|
||||
# <valid>
|
||||
#
|
||||
# Must be 1 for the entry to be considered. The last entry must be
|
||||
# zero.
|
||||
#
|
||||
# <first>
|
||||
# <last>
|
||||
#
|
||||
# Range of bits (within the instruction) that should be searched for
|
||||
# an instruction field. Within such ranges, gen looks for opcodes
|
||||
# (constants), registers (strings) and reserved bits (slash) and
|
||||
# according to the rules that follows includes or excludes them from
|
||||
# a possible instruction field.
|
||||
#
|
||||
# <force_first>
|
||||
# <force_last>
|
||||
#
|
||||
# If an instructioin field was found, enlarge the field size so that
|
||||
# it is forced to at least include bits starting from <force_first>
|
||||
# (<force_last>). To stop this occuring, use <force_first> = <last>
|
||||
# + 1 and <force_last> = <first> - 1.
|
||||
#
|
||||
# <force_slash>
|
||||
#
|
||||
# Treat `/' fields as a constant instead of variable when looking for
|
||||
# an instruction field.
|
||||
#
|
||||
# <force_expansion>
|
||||
#
|
||||
# Treat any contained register (string) fields as constant when
|
||||
# determining the instruction field. For the instruction decode (and
|
||||
# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of
|
||||
# what would otherwize be non constant bits of an instruction.
|
||||
#
|
||||
# <use_switch>
|
||||
#
|
||||
# Should this table be expanded using a switch statement (val 1) and
|
||||
# if so, should it be padded with entries so as to force the compiler
|
||||
# to generate a jump table (val 2).
|
||||
#
|
||||
# <special_mask>
|
||||
# <special_value>
|
||||
# <special_rule>
|
||||
#
|
||||
# Special rule to fine tune how specific (or groups) of instructions
|
||||
# are expanded. The applicability of the rule is determined by
|
||||
#
|
||||
# <special_mask> != 0 && (instruction> & <special_mask>) == <special_value>
|
||||
#
|
||||
# Where <instruction> is obtained by looking only at constant fields
|
||||
# with in an instructions spec. When determining an expansion, the
|
||||
# rule is only considered when a node contains a single instruction.
|
||||
# <special_rule> can be any of:
|
||||
#
|
||||
# 0: for this instruction, expand by earlier rules
|
||||
# 1: expand bits <force_low> .. <force_hi> only
|
||||
# 2: boolean expansion of only zero/non-zero cases
|
||||
#
|
||||
0: 5: 0: 5:0:: 2:0x00000000:0x00000000:0
|
||||
21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0
|
||||
6: 9: 6: 9:0:BO: 0:0xfc000000:0x40000000:1
|
||||
11:15:11:15:0:RA: 1:0xfc000000:0x38000000:2
|
||||
11:15:11:15:0:RA: 1:0xfc000000:0x3c000000:2
|
95
sim/ppc/ppc-opcode-test-2
Normal file
95
sim/ppc/ppc-opcode-test-2
Normal file
@ -0,0 +1,95 @@
|
||||
#
|
||||
# This file is part of the program psim.
|
||||
#
|
||||
# Copyright (C) 1994-1995, 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
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Instruction decode:
|
||||
#
|
||||
# The table that follows is used by gen to construct a decision tree
|
||||
# that can identify each possible instruction. Gen then outputs this
|
||||
# decision tree as (according to config) a table or switch statement
|
||||
# as the function idecode.
|
||||
#
|
||||
# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS
|
||||
# determines of the semantic functions themselves should be expanded
|
||||
# in a similar way.
|
||||
#
|
||||
# The table contains the following entries:
|
||||
#
|
||||
# <valid>
|
||||
#
|
||||
# Must be 1 for the entry to be considered. The last entry must be
|
||||
# zero.
|
||||
#
|
||||
# <first>
|
||||
# <last>
|
||||
#
|
||||
# Range of bits (within the instruction) that should be searched for
|
||||
# an instruction field. Within such ranges, gen looks for opcodes
|
||||
# (constants), registers (strings) and reserved bits (slash) and
|
||||
# according to the rules that follows includes or excludes them from
|
||||
# a possible instruction field.
|
||||
#
|
||||
# <force_first>
|
||||
# <force_last>
|
||||
#
|
||||
# If an instructioin field was found, enlarge the field size so that
|
||||
# it is forced to at least include bits starting from <force_first>
|
||||
# (<force_last>). To stop this occuring, use <force_first> = <last>
|
||||
# + 1 and <force_last> = <first> - 1.
|
||||
#
|
||||
# <force_slash>
|
||||
#
|
||||
# Treat `/' fields as a constant instead of variable when looking for
|
||||
# an instruction field.
|
||||
#
|
||||
# <force_expansion>
|
||||
#
|
||||
# Treat any contained register (string) fields as constant when
|
||||
# determining the instruction field. For the instruction decode (and
|
||||
# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of
|
||||
# what would otherwize be non constant bits of an instruction.
|
||||
#
|
||||
# <use_switch>
|
||||
#
|
||||
# Should this table be expanded using a switch statement (val 1) and
|
||||
# if so, should it be padded with entries so as to force the compiler
|
||||
# to generate a jump table (val 2).
|
||||
#
|
||||
# <special_mask>
|
||||
# <special_value>
|
||||
# <special_rule>
|
||||
#
|
||||
# Special rule to fine tune how specific (or groups) of instructions
|
||||
# are expanded. The applicability of the rule is determined by
|
||||
#
|
||||
# <special_mask> != 0 && (instruction> & <special_mask>) == <special_value>
|
||||
#
|
||||
# Where <instruction> is obtained by looking only at constant fields
|
||||
# with in an instructions spec. When determining an expansion, the
|
||||
# rule is only considered when a node contains a single instruction.
|
||||
# <special_rule> can be any of:
|
||||
#
|
||||
# 0: for this instruction, expand by earlier rules
|
||||
# 1: expand bits <force_low> .. <force_hi> only
|
||||
# 2: boolean expansion of only zero/non-zero cases
|
||||
#
|
||||
0: 5: 0: 5:0:: 0:0x00000000:0x00000000:0
|
||||
21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0
|
||||
6: 9: 6: 9:0:BO: 0:0xfc000000:0x40000000:1
|
||||
11:15:11:15:0:RA: 1:0xfc000000:0x38000000:2
|
||||
11:15:11:15:0:RA: 1:0xfc000000:0x3c000000:2
|
@ -1,772 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1991 Gordon Irlam. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sparc trace generator.
|
||||
*
|
||||
* Generate a Sparc address trace.
|
||||
*
|
||||
* Report system calls.
|
||||
*
|
||||
* We want to display the system call and the return value at the same time
|
||||
* (so that other output does not appear between the two) but also want to
|
||||
* identify system calls that block without having to wait for them to
|
||||
* return. Whenever a system call is performed we store the name of the
|
||||
* call and the parameters. If we don't see a return within a certain time
|
||||
* period we display the call regardless, and assume it has blocked.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Imported declarations.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#else
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <machine/trap.h>
|
||||
|
||||
/*
|
||||
* sigcleanup is not defined in a system header file.
|
||||
*/
|
||||
#define SYS_sigcleanup 139
|
||||
|
||||
#include "prototype.h"
|
||||
#include "error.h"
|
||||
#include "spy.h"
|
||||
#include "system_calls.h"
|
||||
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
|
||||
PROTOTYPE(void report_trap,
|
||||
(int pid, void *addr, int trap, int g1, syscall_params *params));
|
||||
PROTOTYPE(void report_trap_result, (int pid, int error, int o0, int o1));
|
||||
PROTOTYPE(void display_trap_msg, (void));
|
||||
PROTOTYPE(void delayed_trap_msg, (void));
|
||||
PROTOTYPE(void discard_trap_msg, (void));
|
||||
PROTOTYPE(int copy_memory, (int pid, void *addr, int size, char *data));
|
||||
PROTOTYPE(char *snarf_string, (int pid, void *addr));
|
||||
PROTOTYPE(char *snarf_data, (int pid, void *addr, int size));
|
||||
PROTOTYPE(char *format_value,
|
||||
(int pid, fmt_type format, unsigned long value, int opt));
|
||||
PROTOTYPE(int printable_data, (char *data, int size));
|
||||
PROTOTYPE(char *print_string, (char *data, int size));
|
||||
|
||||
|
||||
/*
|
||||
* Global definitions.
|
||||
*/
|
||||
|
||||
static char *trap_msg = NULL;
|
||||
static fmt_type result_format;
|
||||
static int no_return;
|
||||
static fmt_type post_fmt;
|
||||
static unsigned long post_value;
|
||||
static int post_size;
|
||||
|
||||
|
||||
/*
|
||||
* Report the occurence of the specified trap.
|
||||
*/
|
||||
|
||||
void report_trap(pid, addr, trap, g1, params_addr)
|
||||
int pid;
|
||||
void *addr;
|
||||
int trap;
|
||||
int g1;
|
||||
syscall_params *params_addr;
|
||||
{
|
||||
syscall_params params;
|
||||
call_desc *call;
|
||||
int i;
|
||||
fmt_type arg_format;
|
||||
char *arg_str;
|
||||
|
||||
/*
|
||||
* Display any previous trap message that is still pending (it might have
|
||||
* been a trap that did not return a value, and so has not yet been
|
||||
* displayed).
|
||||
*/
|
||||
|
||||
display_trap_msg();
|
||||
|
||||
/*
|
||||
* Read the parameters, and construct a string describing the system call.
|
||||
*/
|
||||
|
||||
ensure(ptrace(PTRACE_READDATA, pid,
|
||||
(char *) params_addr, sizeof(syscall_params),
|
||||
(char *) params) != -1);
|
||||
|
||||
no_return = 0;
|
||||
|
||||
if (trap != T_SOFTWARE_TRAP) {
|
||||
|
||||
/*
|
||||
* Not a system call trap.
|
||||
*/
|
||||
|
||||
no_return = 1;
|
||||
|
||||
ensure((trap_msg = malloc(17 + 20 + 1)) != NULL);
|
||||
sprintf(trap_msg, "0x%08lx: trap %d", (unsigned long) addr, trap);
|
||||
|
||||
result_format = fmt_unknown;
|
||||
} if ((g1 < 0) || (g1 >= no_system_calls)) {
|
||||
|
||||
/*
|
||||
* An unknown system call.
|
||||
*/
|
||||
|
||||
ensure((trap_msg = malloc(21 + 20 + 1)) != NULL);
|
||||
sprintf(trap_msg, "0x%08lx: _unknown_%d(",
|
||||
(unsigned long) addr, g1);
|
||||
|
||||
arg_str = format_value(pid, fmt_unknown, params[0], 0);
|
||||
ensure((trap_msg = realloc(trap_msg, strlen(trap_msg)
|
||||
+ strlen(arg_str) + 1 + 1))
|
||||
!= NULL);
|
||||
sprintf(trap_msg + sizeof(trap_msg), "%s)", arg_str);
|
||||
free(arg_str);
|
||||
|
||||
result_format = fmt_unknown;
|
||||
} else {
|
||||
|
||||
/*
|
||||
* A known system call.
|
||||
*/
|
||||
|
||||
call = &system_calls[g1];
|
||||
switch (g1) {
|
||||
case SYS_open :
|
||||
if (!(params[1] & O_CREAT)) {
|
||||
call = &system_call_open_simple;
|
||||
}
|
||||
break;
|
||||
case SYS_exit :
|
||||
case SYS_execve :
|
||||
case SYS_sigcleanup :
|
||||
no_return = 1;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
ensure((trap_msg = malloc(13 + strlen(call->name) + 1 + 1))
|
||||
!= NULL);
|
||||
sprintf(trap_msg, "0x%08lx: %s(",
|
||||
(unsigned long) addr, call->name);
|
||||
|
||||
/*
|
||||
* Display each of the arguments.
|
||||
*/
|
||||
|
||||
for (i = 0; i < NO_PARAMS; i++) {
|
||||
if ((arg_format = call->arg[i]) == fmt_none) {
|
||||
break;
|
||||
}
|
||||
if (i > 0) {
|
||||
strcat(trap_msg, ", ");
|
||||
}
|
||||
if (arg_format == fmt_data) {
|
||||
assert(((i + 1) < NO_PARAMS) &&
|
||||
(call->arg[i + 1] == fmt_data_size));
|
||||
arg_str = format_value(pid, arg_format,
|
||||
params[i], (int) params[i + 1]);
|
||||
} else {
|
||||
arg_str = format_value(pid, arg_format, params[i], 0);
|
||||
}
|
||||
ensure((trap_msg = realloc(trap_msg, strlen(trap_msg) +
|
||||
strlen(arg_str) + 2 + 1))
|
||||
!= NULL);
|
||||
strcat(trap_msg, arg_str);
|
||||
free(arg_str);
|
||||
}
|
||||
|
||||
strcat(trap_msg, ")");
|
||||
|
||||
result_format = call->result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set alarm so that name of call will be displayed even if it blocks.
|
||||
*/
|
||||
|
||||
alarm((unsigned int) 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Report the value returned as a result of the most recent trap.
|
||||
*/
|
||||
|
||||
void report_trap_result(pid, error, o0, o1)
|
||||
int pid;
|
||||
int error;
|
||||
int o0;
|
||||
int o1;
|
||||
{
|
||||
char *result, *eno, *emsg, *addr;
|
||||
|
||||
/*
|
||||
* Turn off alarm used to ensure we print the call promptly - we are about
|
||||
* to print it now.
|
||||
*/
|
||||
|
||||
alarm((unsigned int) 0);
|
||||
|
||||
/*
|
||||
* See if previous call blocked.
|
||||
*/
|
||||
|
||||
if (trap_msg == NULL) {
|
||||
ensure((trap_msg = strdup(" [previous call]")) != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Work out error message (if any) to be printed following return value.
|
||||
*/
|
||||
|
||||
if (error) {
|
||||
eno = format_value(pid, fmt_error, o0, 0);
|
||||
ensure((emsg = malloc(9 + strlen(eno) + 1)) != NULL);
|
||||
sprintf(emsg, " [error %s]", eno);
|
||||
free(eno);
|
||||
o0 = -1;
|
||||
post_fmt = fmt_none;
|
||||
} else {
|
||||
ensure((emsg = strdup("")) != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out all the details of the system call.
|
||||
*/
|
||||
|
||||
if (result_format == fmt_none) {
|
||||
ensure(fprintf(msgfile, "%s: %s%s\n", trace_progname, trap_msg, emsg)
|
||||
!= EOF);
|
||||
} else {
|
||||
result = format_value(pid, result_format, o0, 0);
|
||||
ensure(fprintf(msgfile, "%s: %s -> %s%s\n",
|
||||
trace_progname, trap_msg, result, emsg) != EOF);
|
||||
free(result);
|
||||
}
|
||||
|
||||
free(emsg);
|
||||
|
||||
/*
|
||||
* Display any string or buffer modified by the system call if required.
|
||||
* And providing it can be displayed as a (non-null) string.
|
||||
*/
|
||||
|
||||
if (post_fmt != fmt_none) {
|
||||
result = format_value(pid, post_fmt, post_value, post_size);
|
||||
if ((result[0] == '"') && (strlen(result) > 2)) {
|
||||
addr = format_value(pid, fmt_ptr, post_value, 0);
|
||||
ensure(fprintf(msgfile, "%s: %s: %s\n",
|
||||
trace_progname, addr, result) != EOF);
|
||||
free(addr);
|
||||
}
|
||||
free(result);
|
||||
post_fmt = fmt_none;
|
||||
}
|
||||
|
||||
free(trap_msg);
|
||||
trap_msg = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Report any trap messages that haven't been reported yet.
|
||||
*/
|
||||
|
||||
void display_trap_msg() {
|
||||
|
||||
/*
|
||||
* Clear the alarm - we are about to print the message.
|
||||
*/
|
||||
|
||||
alarm((unsigned int) 0);
|
||||
|
||||
if (trap_msg != NULL) {
|
||||
ensure(fprintf(msgfile, "%s: %s\n", trace_progname, trap_msg) != EOF);
|
||||
free(trap_msg);
|
||||
trap_msg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Report the completion of a trap message as being delayed.
|
||||
*
|
||||
* This routine is invoked when a SIGALRM is received.
|
||||
*/
|
||||
|
||||
void delayed_trap_msg() {
|
||||
|
||||
assert(trap_msg != NULL);
|
||||
|
||||
/*
|
||||
* If the call was not expected to return a value, think nothing of it,
|
||||
* otherwise assume the call has blocked.
|
||||
*/
|
||||
|
||||
ensure(fprintf(msgfile, "%s: %s%s\n",
|
||||
trace_progname, trap_msg, (no_return ? "" : " [pending]"))
|
||||
!= EOF);
|
||||
free(trap_msg);
|
||||
trap_msg = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Discard any pending trap messages.
|
||||
*
|
||||
* This routine is used by the child of a fork to discard the fork system call
|
||||
* record.
|
||||
*/
|
||||
|
||||
void discard_trap_msg() {
|
||||
|
||||
trap_msg = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Attempt to copy size bytes from the target process to data. The number of
|
||||
* bytes successfully copied is returned.
|
||||
*/
|
||||
|
||||
int copy_memory(pid, addr, size, data)
|
||||
int pid;
|
||||
void *addr;
|
||||
int size;
|
||||
char *data;
|
||||
{
|
||||
int lo, hi, try;
|
||||
|
||||
assert(size >= 0);
|
||||
|
||||
/*
|
||||
* Common cases first.
|
||||
*/
|
||||
|
||||
if (ptrace(PTRACE_READDATA, pid, (char *) addr, size, data) != -1) {
|
||||
return size;
|
||||
} else if (ptrace(PTRACE_READDATA, pid, (char *) addr, 1, data) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Binary search.
|
||||
*/
|
||||
|
||||
lo = 1;
|
||||
hi = size - 1;
|
||||
|
||||
while (lo < hi) {
|
||||
try = (lo + hi + 1) / 2;
|
||||
if (ptrace(PTRACE_READDATA, pid, (char *) addr, try, data) != -1) {
|
||||
lo = try;
|
||||
} else {
|
||||
hi = try - 1;
|
||||
}
|
||||
}
|
||||
|
||||
ensure(ptrace(PTRACE_READDATA, pid, (char *) addr, lo, data) != -1);
|
||||
|
||||
return lo;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a string representing the contents of the indicated null termintated
|
||||
* region of memory.
|
||||
*/
|
||||
|
||||
char *snarf_string(pid, addr)
|
||||
int pid;
|
||||
void *addr;
|
||||
{
|
||||
char data[STRING_SIZE_LIMIT + 1];
|
||||
int size, len;
|
||||
char *result = NULL;
|
||||
int too_long = 0;
|
||||
|
||||
size = copy_memory(pid, addr, STRING_SIZE_LIMIT, data);
|
||||
data[size] = '\0';
|
||||
len = strlen(data);
|
||||
too_long = (len == STRING_SIZE_LIMIT);
|
||||
if ((len < size) || too_long) {
|
||||
if (printable_data(data, len)) {
|
||||
result = print_string(data, len);
|
||||
if (too_long) {
|
||||
ensure((result = realloc(result, strlen(result) + 2 + 1))
|
||||
!= NULL);
|
||||
strcat(result, "..");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a string representing the contents of the indicated length delimited
|
||||
* region of memory.
|
||||
*/
|
||||
|
||||
char *snarf_data(pid, addr, size)
|
||||
int pid;
|
||||
void *addr;
|
||||
int size;
|
||||
{
|
||||
char data[DATA_SIZE_LIMIT];
|
||||
char *result = NULL;
|
||||
int too_long = 0;
|
||||
|
||||
if (size > DATA_SIZE_LIMIT) {
|
||||
size = DATA_SIZE_LIMIT;
|
||||
too_long = 1;
|
||||
}
|
||||
if ((size >= 0) && (copy_memory(pid, addr, size, data) == size)) {
|
||||
if (printable_data(data, size)) {
|
||||
result = print_string(data, size);
|
||||
if (too_long) {
|
||||
ensure((result = realloc(result, strlen(result) + 2 + 1))
|
||||
!= NULL);
|
||||
strcat(result, "..");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a string representing the contents of the indicated null termintated
|
||||
* array of pointers to null terminated regions of memory.
|
||||
*/
|
||||
|
||||
char *snarf_string_array(pid, addr)
|
||||
int pid;
|
||||
void *addr;
|
||||
{
|
||||
char *data[ARRAY_SIZE_LIMIT + 1];
|
||||
int size, len, i;
|
||||
char *result = NULL;
|
||||
char *s;
|
||||
int too_long = 0;
|
||||
|
||||
size = copy_memory(pid, addr, ARRAY_SIZE_LIMIT * sizeof(char *),
|
||||
(char *) data) / sizeof(char *);
|
||||
data[size] = NULL;
|
||||
for (len = 0; data[len] != NULL; len++) {
|
||||
}
|
||||
too_long = (len == ARRAY_SIZE_LIMIT);
|
||||
if ((len < size) || too_long) {
|
||||
ensure((result = strdup("{")) != NULL);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i > 0) {
|
||||
strcat(result, ", ");
|
||||
}
|
||||
s = format_value(pid, fmt_string, (unsigned long) data[i], 0);
|
||||
ensure((result = realloc(result,
|
||||
strlen(result) + strlen(s) + 2 + 5 + 1))
|
||||
!= NULL);
|
||||
strcat(result, s);
|
||||
}
|
||||
if (too_long) {
|
||||
strcat(result, ", ..");
|
||||
}
|
||||
strcat(result, "}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a string containing a value printed in a specific format. Opt is a
|
||||
* second optional parameter currently only used to contain the size to be used
|
||||
* with fmt_data.
|
||||
*/
|
||||
|
||||
char *format_value(pid, format, value, opt)
|
||||
int pid;
|
||||
fmt_type format;
|
||||
unsigned long value;
|
||||
int opt;
|
||||
{
|
||||
char *str;
|
||||
int sig, error;
|
||||
|
||||
/*
|
||||
* See if we are meant to hang on to the value for later use.
|
||||
*/
|
||||
|
||||
switch (format) {
|
||||
|
||||
case fmt_post_string :
|
||||
post_fmt = fmt_string ;
|
||||
post_value = value;
|
||||
format = fmt_ptr;
|
||||
break;
|
||||
|
||||
case fmt_post_data :
|
||||
post_fmt = fmt_data;
|
||||
post_value = value;
|
||||
format = fmt_ptr;
|
||||
break;
|
||||
|
||||
case fmt_data_size :
|
||||
format = FMT_SIZE;
|
||||
break;
|
||||
|
||||
case fmt_post_data_size :
|
||||
post_size = (int) value;
|
||||
format = FMT_SIZE;
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display the value.
|
||||
*/
|
||||
|
||||
switch (format) {
|
||||
|
||||
case fmt_dec :
|
||||
|
||||
ensure((str = malloc(20 + 1)) != NULL);
|
||||
sprintf(str, "%d", (int) value);
|
||||
break;
|
||||
|
||||
case fmt_hex :
|
||||
|
||||
ensure((str = malloc(2 + 20 + 1)) != NULL);
|
||||
sprintf(str, "0x%lx", value);
|
||||
break;
|
||||
|
||||
case fmt_ptr :
|
||||
|
||||
if (value == 0) {
|
||||
ensure((str = strdup("NULL")) != NULL);
|
||||
} else {
|
||||
ensure((str = malloc(10 + 1)) != NULL);
|
||||
sprintf(str, "0x%08lx", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case fmt_fd :
|
||||
|
||||
ensure((str = malloc(2 + 20 + 1)) != NULL);
|
||||
sprintf(str, "fd%d", (int) value);
|
||||
break;
|
||||
|
||||
case fmt_signal :
|
||||
|
||||
sig = (int) value;
|
||||
if ((sig < 0) || (sig >= no_signal_names)) {
|
||||
ensure((str = malloc(20 + 1)) != NULL);
|
||||
sprintf(str, "%d", sig);
|
||||
} else {
|
||||
ensure((str = strdup(signal_names[sig])) != NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case fmt_error :
|
||||
|
||||
error = (int) value;
|
||||
if ((error < 0) || (error >= no_error_names)) {
|
||||
ensure((str = malloc(20 + 1)) != NULL);
|
||||
sprintf(str, "%d", error);
|
||||
} else {
|
||||
ensure((str = strdup(error_names[error])) != NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case fmt_open_flags :
|
||||
|
||||
ensure((str = malloc(8 + 3 + 20 + 1)) != NULL);
|
||||
switch (value & 3) {
|
||||
case O_RDONLY :
|
||||
sprintf(str, "O_RDONLY");
|
||||
value -= O_RDONLY;
|
||||
break;
|
||||
case O_WRONLY :
|
||||
sprintf(str, "O_WRONLY");
|
||||
value -= O_WRONLY;
|
||||
break;
|
||||
case O_RDWR :
|
||||
sprintf(str, "O_RDWR");
|
||||
value -= O_RDWR;
|
||||
break;
|
||||
default :
|
||||
sprintf(str, "0x%lx", value);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
if (value != 0) {
|
||||
sprintf(str + strlen(str), "|0x%lx", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case fmt_unknown :
|
||||
|
||||
ensure((str = strdup("..")) != NULL);
|
||||
break;
|
||||
|
||||
case fmt_string :
|
||||
|
||||
if ((str = snarf_string(pid, (void *) value)) == NULL) {
|
||||
str = format_value(pid, fmt_ptr, value, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case fmt_data :
|
||||
|
||||
if ((str = snarf_data(pid, (void *) value, opt)) == NULL) {
|
||||
str = format_value(pid, fmt_ptr, value, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case fmt_string_array :
|
||||
|
||||
if ((str = snarf_string_array(pid, (void *) value)) == NULL) {
|
||||
str = format_value(pid, fmt_ptr, value, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
|
||||
diagnose("Unexpected display format");
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Determine whether size bytes of data are printable.
|
||||
*/
|
||||
|
||||
int printable_data(data, size)
|
||||
char *data;
|
||||
int size;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
|
||||
if (!(isprint(data[i]))) {
|
||||
|
||||
switch (data[i]) {
|
||||
|
||||
case '\0' :
|
||||
case '\t' :
|
||||
case '\n' :
|
||||
case '\f' :
|
||||
case '\r' :
|
||||
break;
|
||||
|
||||
default :
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a string representing size bytes of data.
|
||||
*/
|
||||
|
||||
char *print_string(data, size)
|
||||
char *data;
|
||||
int size;
|
||||
{
|
||||
char *str, *s;
|
||||
int i;
|
||||
|
||||
assert(size >= 0);
|
||||
|
||||
ensure((str = malloc(1 + size * 2 + 1 + 1)) != NULL);
|
||||
s = str;
|
||||
|
||||
*(s++) = '"';
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
|
||||
if ((!(isprint(data[i]))) || (data[i] == '"') || (data[i] == '\\')) {
|
||||
|
||||
*(s++) = '\\';
|
||||
|
||||
switch (data[i]) {
|
||||
case '\0' :
|
||||
*(s++) = '0';
|
||||
break;
|
||||
case '\t' :
|
||||
*(s++) = 't';
|
||||
break;
|
||||
case '\n' :
|
||||
*(s++) = 'n';
|
||||
break;
|
||||
case '\f' :
|
||||
*(s++) = 'f';
|
||||
break;
|
||||
case '\r' :
|
||||
*(s++) = 'r';
|
||||
break;
|
||||
case '"' :
|
||||
case '\\' :
|
||||
*(s++) = data[i];
|
||||
break;
|
||||
default :
|
||||
diagnose("Attempted to display illegal character");
|
||||
}
|
||||
} else {
|
||||
|
||||
*(s++) = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
*(s++) = '"';
|
||||
*s = '\0';
|
||||
|
||||
return str;
|
||||
}
|
@ -1,499 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1991 Gordon Irlam. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Definition of system calls for sparc trace generator.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Imported declarations.
|
||||
*/
|
||||
|
||||
#include "system_calls.h"
|
||||
|
||||
|
||||
/*
|
||||
* Table containing system calls, and their parameter profile.
|
||||
*/
|
||||
|
||||
call_desc system_calls[] = {
|
||||
/* 0 */ {"syscall", {fmt_dec, fmt_unknown}, fmt_dec},
|
||||
/* 1 */ {"_exit", {fmt_dec}, fmt_none},
|
||||
/* 2 */ {"fork", {fmt_none}, fmt_dec},
|
||||
/* 3 */ {"read", {fmt_fd, fmt_post_data, FMT_SIZE}, fmt_post_data_size},
|
||||
/* 4 */ {"write", {fmt_fd, fmt_data, fmt_data_size}, FMT_SIZE},
|
||||
/* 5 */ {"open", {fmt_string, fmt_open_flags, FMT_FLAGS}, fmt_fd},
|
||||
/* 6 */ {"close", {fmt_fd}, FMT_STATUS},
|
||||
/* 7 */ {"wait4", {fmt_dec, fmt_ptr, FMT_FLAGS, fmt_ptr}, fmt_dec},
|
||||
/* 8 */ {"creat", {fmt_string, FMT_FLAGS}, fmt_fd},
|
||||
/* 9 */ {"link", {fmt_string, fmt_string}, FMT_STATUS},
|
||||
/* 10 */ {"unlink", {fmt_string}, FMT_STATUS},
|
||||
/* 11 */ {"_unknown_11[\"old execv\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* execv is now a library routine which calls execve, although
|
||||
* Sun have not officially declared execv obsolete.
|
||||
*/
|
||||
/* 12 */ {"chdir", {fmt_string}, FMT_STATUS},
|
||||
/* 13 */ {"_unknown_13[\"old time\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 14 */ {"mknod", {fmt_string, FMT_FLAGS, FMT_FLAGS}, FMT_STATUS},
|
||||
/* 15 */ {"chmod", {fmt_string, FMT_FLAGS}, FMT_STATUS},
|
||||
/* 16 */ {"chown", {fmt_string, fmt_dec, fmt_dec}, FMT_STATUS},
|
||||
/* 17 */ {"_brk", {fmt_ptr}, FMT_STATUS},
|
||||
/* 18 */ {"_unknown_18[\"old stat\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 19 */ {"lseek", {fmt_fd, FMT_SIZE, fmt_dec}, FMT_SIZE},
|
||||
/* 20 */ {"getpid", {fmt_none}, fmt_dec},
|
||||
/* 21 */ {"_unknown_21", {fmt_unknown}, fmt_unknown},
|
||||
/* 22 */ {"umount[\"System V\"]", {fmt_string}, FMT_STATUS},
|
||||
/* 23 */ {"_unknown_23[\"old setuid\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 24 */ {"getuid", {fmt_none}, fmt_dec},
|
||||
/* 25 */ {"_unknown_25[\"old System V stime\"]",
|
||||
{fmt_unknown},
|
||||
fmt_unknown},
|
||||
/* 26 */ {"ptrace",
|
||||
{fmt_dec, fmt_dec, fmt_ptr, fmt_dec, fmt_ptr},
|
||||
fmt_dec},
|
||||
/* 27 */ {"_unknown_27[\"old alarm\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 28 */ {"_unknown_28[\"old fstat\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 29 */ {"_unknown_29[\"old pause\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 30 */ {"_unknown_30[\"old utime\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 31 */ {"_unknown_31", {fmt_unknown}, fmt_unknown},
|
||||
/* 32 */ {"_unknown_32", {fmt_unknown}, fmt_unknown},
|
||||
/* 33 */ {"access", {fmt_string, FMT_FLAGS}, FMT_STATUS},
|
||||
/* 34 */ {"_unknown_34[\"old nice\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 35 */ {"_unknown_35[\"old ftime\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 36 */ {"sync", {fmt_none}, fmt_none},
|
||||
/* 37 */ {"kill", {fmt_dec, fmt_signal}, FMT_STATUS},
|
||||
/* 38 */ {"stat", {fmt_string, fmt_ptr}, FMT_STATUS},
|
||||
/* 39 */ {"_unknown_39[\"old setpgrp\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 40 */ {"lstat", {fmt_string, fmt_ptr}, FMT_STATUS},
|
||||
/* 41 */ {"dup", {fmt_fd}, fmt_fd},
|
||||
/*
|
||||
* Sun sometimes claim dup has 2 parameters.
|
||||
*/
|
||||
/* 42 */ {"pipe", {fmt_ptr}, FMT_STATUS},
|
||||
/* 43 */ {"_unknown_43[\"old times\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 44 */ {"profil", {fmt_ptr, FMT_SIZE, fmt_ptr, fmt_dec}, FMT_STATUS},
|
||||
/* 45 */ {"_unknown_45", {fmt_unknown}, fmt_unknown},
|
||||
/* 46 */ {"_unknown_46[\"old setgid\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 47 */ {"getgid", {fmt_none}, fmt_dec},
|
||||
/* 48 */ {"_unknown_48[\"old signal\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 49 */ {"_unknown_49", {fmt_unknown}, fmt_unknown},
|
||||
/* 50 */ {"_unknown_50", {fmt_unknown}, fmt_unknown},
|
||||
/* 51 */ {"acct", {fmt_string}, FMT_STATUS},
|
||||
/* 52 */ {"_unknown_52", {fmt_unknown}, fmt_unknown},
|
||||
/* 53 */ {"mctl", {fmt_ptr, FMT_SIZE, fmt_dec, FMT_FLAGS}, FMT_STATUS},
|
||||
/* 54 */ {"ioctl", {fmt_fd, FMT_FLAGS, fmt_ptr}, fmt_dec},
|
||||
/* 55 */ {"reboot", {FMT_FLAGS, fmt_string}, FMT_STATUS},
|
||||
/* 56 */ {"_unknown_56[\"old wait3\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 57 */ {"symlink", {fmt_string, fmt_string}, FMT_STATUS},
|
||||
/* 58 */ {"readlink",
|
||||
{fmt_string, fmt_post_data, FMT_SIZE},
|
||||
fmt_post_data_size},
|
||||
/* 59 */ {"execve",
|
||||
{fmt_string, fmt_string_array, fmt_string_array},
|
||||
FMT_STATUS},
|
||||
/* 60 */ {"umask", {FMT_FLAGS}, FMT_FLAGS},
|
||||
/* 61 */ {"chroot", {fmt_string}, FMT_STATUS},
|
||||
/* 62 */ {"fstat", {fmt_fd, fmt_ptr}, FMT_STATUS},
|
||||
/* 63 */ {"_unknown_63", {fmt_unknown}, fmt_unknown},
|
||||
/* 64 */ {"getpagesize", {fmt_none}, FMT_SIZE},
|
||||
/* 65 */ {"_unknown_65[\"old msync\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* msync is now a library routine which calls mctl, although
|
||||
* Sun have not officially declared msync obsolete.
|
||||
*/
|
||||
/* 66 */ {"vfork", {fmt_none}, fmt_dec},
|
||||
/* 67 */ {"_unknown_67[\"old vread\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* I don't think vread can be generated by the standard
|
||||
* libararies, although Sun have not officially declared it
|
||||
* obsolete.
|
||||
*/
|
||||
/* 68 */ {"_unknown_68[\"old vwrite\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* I don't think vwrite can be generated by the standard
|
||||
* libararies, although Sun have not officially declared it
|
||||
* obsolete.
|
||||
*/
|
||||
/* 69 */ {"_unknown_69[\"old brk\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* Also referred to as sbrk. I don't think it can be generated
|
||||
* by the standard libararies, although Sun have not officially
|
||||
* declared it obsolete.
|
||||
*/
|
||||
/* 70 */ {"_unknown_70[\"old sstk\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* I don't think sstk can be generated by the standard
|
||||
* libararies, although Sun have not officially declared it
|
||||
* obsolete.
|
||||
*/
|
||||
/* 71 */ {"mmap",
|
||||
{fmt_ptr, fmt_post_data_size, FMT_FLAGS, FMT_FLAGS, fmt_fd,
|
||||
FMT_SIZE},
|
||||
fmt_post_data},
|
||||
/* 72 */ {"vadvise", {fmt_dec}, FMT_STATUS},
|
||||
/*
|
||||
* vadvise is currently still a valid system call, although Sun
|
||||
* have said it is likely to disappear in the future.
|
||||
*/
|
||||
/* 73 */ {"munmap", {fmt_ptr, FMT_SIZE}, FMT_STATUS},
|
||||
/* 74 */ {"mprotect", {fmt_ptr, FMT_SIZE, FMT_FLAGS}, FMT_STATUS},
|
||||
/* 75 */ {"_unknown_75[\"old madvise\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* madvise is now a library routine which calls mctl, although
|
||||
* Sun have not officially declared madvise obsolete.
|
||||
*/
|
||||
/* 76 */ {"vhangup", {fmt_none}, FMT_STATUS},
|
||||
/*
|
||||
* Sun sometimes claim vhangup has 1 parameter.
|
||||
*/
|
||||
/* 77 */ {"_unknown_77[\"old vlimit\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 78 */ {"mincore", {fmt_ptr, FMT_SIZE, fmt_ptr}, FMT_STATUS},
|
||||
/* 79 */ {"getgroups", {fmt_dec, fmt_ptr}, fmt_dec},
|
||||
/* 80 */ {"setgroups", {fmt_dec, fmt_ptr}, FMT_STATUS},
|
||||
/* 81 */ {"getpgrp", {fmt_dec}, fmt_dec},
|
||||
/* 82 */ {"setpgrp", {fmt_dec, fmt_dec}, FMT_STATUS},
|
||||
/* 83 */ {"setitimer", {fmt_dec, fmt_ptr, fmt_ptr}, FMT_STATUS},
|
||||
/* 84 */ {"_unknown_84[\"old wait\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* wait is now a library routine which calls wait4, although Sun
|
||||
* have not officially declared wait obsolete.
|
||||
*/
|
||||
/* 85 */ {"swapon", {fmt_string}, FMT_STATUS},
|
||||
/* 86 */ {"getitimer", {fmt_dec, fmt_ptr}, FMT_STATUS},
|
||||
/* 87 */ {"gethostname", {fmt_post_string, FMT_SIZE}, FMT_STATUS},
|
||||
/* 88 */ {"sethostname", {fmt_data, fmt_data_size}, FMT_STATUS},
|
||||
/* 89 */ {"getdtablesize", {fmt_none}, fmt_dec},
|
||||
/* 90 */ {"dup2", {fmt_fd, fmt_dec}, fmt_fd},
|
||||
/* 91 */ {"_unknown_91[\"old getdopt\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* I don't think getdopt can be generated by the standard
|
||||
* libararies, although Sun have not officially declared it
|
||||
* obsolete.
|
||||
*/
|
||||
/* 92 */ {"fcntl", {fmt_fd, fmt_dec, fmt_dec}, fmt_dec},
|
||||
/* 93 */ {"select",
|
||||
{fmt_dec, fmt_ptr, fmt_ptr, fmt_ptr, fmt_ptr},
|
||||
fmt_dec},
|
||||
/* 94 */ {"_unknown_94[\"old setdopt\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* I don't think setdopt can be generated by the standard
|
||||
* libararies, although Sun have not officially declared it
|
||||
* obsolete.
|
||||
*/
|
||||
/* 95 */ {"fsync", {fmt_fd}, FMT_STATUS},
|
||||
/* 96 */ {"setpriority", {fmt_dec, fmt_dec, fmt_dec}, FMT_STATUS},
|
||||
/* 97 */ {"socket", {fmt_dec, fmt_dec, fmt_dec}, fmt_fd},
|
||||
/* 98 */ {"connect", {fmt_fd, fmt_ptr, FMT_SIZE}, FMT_STATUS},
|
||||
/* 99 */ {"accept", {fmt_fd, fmt_ptr, fmt_ptr}, fmt_fd},
|
||||
/* 100 */ {"getpriority", {fmt_dec, fmt_dec}, fmt_dec},
|
||||
/* 101 */ {"send", {fmt_fd, fmt_data, fmt_data_size, FMT_FLAGS}, FMT_SIZE},
|
||||
/* 102 */ {"recv",
|
||||
{fmt_fd, fmt_post_data, FMT_SIZE, FMT_FLAGS},
|
||||
fmt_post_data_size},
|
||||
/* 103 */ {"_unknown_103", {fmt_unknown}, fmt_unknown},
|
||||
/* 104 */ {"bind", {fmt_fd, fmt_ptr, FMT_SIZE}, FMT_STATUS},
|
||||
/* 105 */ {"setsockopt",
|
||||
{fmt_fd, fmt_dec, fmt_dec, fmt_ptr, FMT_SIZE},
|
||||
FMT_STATUS},
|
||||
/* 106 */ {"listen", {fmt_fd, fmt_dec}, FMT_STATUS},
|
||||
/* 107 */ {"_unknown_107[\"old vtimes\"]", {fmt_unknown}, fmt_unknown},
|
||||
/* 108 */ {"_sigvec", {fmt_signal, fmt_ptr, fmt_ptr}, FMT_STATUS},
|
||||
/* 109 */ {"sigblock", {fmt_hex}, fmt_hex},
|
||||
/* 110 */ {"sigsetmask", {fmt_hex}, fmt_hex},
|
||||
/* 111 */ {"sigpause", {fmt_hex}, FMT_STATUS},
|
||||
/* 112 */ {"sigstack", {fmt_ptr, fmt_ptr}, FMT_STATUS},
|
||||
/* 113 */ {"recvmsg", {fmt_fd, fmt_ptr, FMT_FLAGS}, FMT_SIZE},
|
||||
/* 114 */ {"sendmsg", {fmt_fd, fmt_ptr, FMT_FLAGS}, FMT_SIZE},
|
||||
/* 115 */ {"_unknown_115[\"vtrace\"]",
|
||||
{fmt_dec, fmt_hex, fmt_hex},
|
||||
fmt_unknown},
|
||||
/*
|
||||
* I am unsure of the parameters for vtrace.
|
||||
*/
|
||||
/* 116 */ {"gettimeofday", {fmt_ptr, fmt_ptr}, FMT_STATUS},
|
||||
/* 117 */ {"getrusage", {fmt_dec, fmt_ptr}, FMT_STATUS},
|
||||
/* 118 */ {"getsockopt",
|
||||
{fmt_fd, fmt_dec, fmt_dec, fmt_ptr, fmt_ptr},
|
||||
FMT_STATUS},
|
||||
/* 119 */ {"_unknown_119", {fmt_unknown}, fmt_unknown},
|
||||
/* 120 */ {"readv", {fmt_fd, fmt_ptr, fmt_dec}, FMT_SIZE},
|
||||
/* 121 */ {"writev", {fmt_fd, fmt_ptr, fmt_dec}, FMT_SIZE},
|
||||
/* 122 */ {"settimeofday", {fmt_ptr, fmt_ptr}, FMT_STATUS},
|
||||
/* 123 */ {"fchown", {fmt_fd, fmt_dec, fmt_dec}, FMT_STATUS},
|
||||
/* 124 */ {"fchmod", {fmt_fd, FMT_FLAGS}, FMT_STATUS},
|
||||
/* 125 */ {"recvfrom",
|
||||
{fmt_fd, fmt_post_data, FMT_SIZE, FMT_FLAGS, fmt_ptr, fmt_ptr},
|
||||
fmt_post_data_size},
|
||||
/* 126 */ {"setreuid", {fmt_dec, fmt_dec}, FMT_STATUS},
|
||||
/* 127 */ {"setregid", {fmt_dec, fmt_dec}, FMT_STATUS},
|
||||
/* 128 */ {"rename", {fmt_string, fmt_string}, FMT_STATUS},
|
||||
/* 129 */ {"truncate", {fmt_string, FMT_SIZE}, FMT_STATUS},
|
||||
/* 130 */ {"ftruncate", {fmt_fd, FMT_SIZE}, FMT_STATUS},
|
||||
/* 131 */ {"flock", {fmt_fd, FMT_FLAGS}, FMT_STATUS},
|
||||
/* 132 */ {"_unknown_132", {fmt_unknown}, fmt_unknown},
|
||||
/* 133 */ {"sendto",
|
||||
{fmt_fd, fmt_data, fmt_data_size, FMT_FLAGS, fmt_ptr, FMT_SIZE},
|
||||
FMT_SIZE},
|
||||
/* 134 */ {"shutdown", {fmt_fd, fmt_dec}, FMT_STATUS},
|
||||
/* 135 */ {"socketpair", {fmt_dec, fmt_dec, fmt_dec, fmt_ptr}, FMT_STATUS},
|
||||
/*
|
||||
* Sun sometimes claim socketpair has 5 parameters.
|
||||
*/
|
||||
/* 136 */ {"mkdir", {fmt_string, FMT_FLAGS}, FMT_STATUS},
|
||||
/* 137 */ {"rmdir", {fmt_string}, FMT_STATUS},
|
||||
/* 138 */ {"utimes", {fmt_string, fmt_ptr}, FMT_STATUS},
|
||||
/* 139 */ {"_sigcleanup", {fmt_ptr}, FMT_STATUS},
|
||||
/* 140 */ {"adjtime", {fmt_ptr, fmt_ptr}, FMT_STATUS},
|
||||
/* 141 */ {"getpeername", {fmt_fd, fmt_ptr, fmt_ptr}, FMT_STATUS},
|
||||
/* 142 */ {"gethostid", {fmt_none}, fmt_hex},
|
||||
/*
|
||||
* Sun sometimes claim gethostid has 2 parameters.
|
||||
*/
|
||||
/* 143 */ {"_unknown_143", {fmt_unknown}, fmt_unknown},
|
||||
/* 144 */ {"getrlimit", {fmt_dec, fmt_ptr}, FMT_STATUS},
|
||||
/* 145 */ {"setrlimit", {fmt_dec, fmt_ptr}, FMT_STATUS},
|
||||
/* 146 */ {"killpg", {fmt_dec, fmt_signal}, FMT_STATUS},
|
||||
/* 147 */ {"_unknown_147", {fmt_unknown}, fmt_unknown},
|
||||
/* 148 */ {"_unknown_148[\"old quota\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* I don't think quota can be generated by the standard
|
||||
* libararies, although Sun have not officially declared it
|
||||
* obsolete.
|
||||
*/
|
||||
/* 149 */ {"_unknown_149[\"old qquota\"]", {fmt_unknown}, fmt_unknown},
|
||||
/*
|
||||
* I don't think qquota can be generated by the standard
|
||||
* libararies, although Sun have not officially declared it
|
||||
* obsolete.
|
||||
*/
|
||||
/* 150 */ {"getsockname", {fmt_fd, fmt_ptr, fmt_ptr}, FMT_STATUS},
|
||||
/* 151 */ {"getmsg", {fmt_fd, fmt_ptr, fmt_ptr, fmt_ptr}, fmt_dec},
|
||||
/* 152 */ {"putmsg", {fmt_fd, fmt_ptr, fmt_ptr, FMT_FLAGS}, FMT_STATUS},
|
||||
/* 153 */ {"poll", {fmt_ptr, fmt_dec, fmt_dec}, fmt_dec},
|
||||
/* 154 */ {"_unknown_154", {fmt_unknown}, fmt_unknown},
|
||||
/* 155 */ {"nfssvc", {fmt_fd}, FMT_STATUS},
|
||||
/* 156 */ {"_unknown_156[\"old getdirentries\"]",
|
||||
{fmt_unknown},
|
||||
fmt_unknown},
|
||||
/*
|
||||
* I don't think getdirentries can be generated by the standard
|
||||
* libararies, although Sun have not officially declared it
|
||||
* obsolete.
|
||||
*/
|
||||
/* 157 */ {"statfs", {fmt_string, fmt_ptr}, FMT_STATUS},
|
||||
/* 158 */ {"fstatfs", {fmt_fd, fmt_ptr}, FMT_STATUS},
|
||||
/* 159 */ {"unmount", {fmt_string}, FMT_STATUS},
|
||||
/* 160 */ {"async_daemon", {fmt_none}, fmt_none},
|
||||
/* 161 */ {"nfs_getfh", {fmt_hex, fmt_hex}, fmt_unknown},
|
||||
/*
|
||||
* I am unsure of the parameters for nfs_getfh.
|
||||
*/
|
||||
/* 162 */ {"getdomainname", {fmt_post_string, FMT_SIZE}, FMT_STATUS},
|
||||
/* 163 */ {"setdomainname", {fmt_data, fmt_data_size}, FMT_STATUS},
|
||||
/* 164 */ {"rtschedule",
|
||||
{fmt_hex, fmt_hex, fmt_hex, fmt_hex, fmt_hex},
|
||||
fmt_unknown},
|
||||
/*
|
||||
* I am unsure of the parameters for rtschedule.
|
||||
*/
|
||||
/* 165 */ {"quotactl",
|
||||
{fmt_dec, fmt_string, fmt_dec, fmt_ptr},
|
||||
FMT_STATUS},
|
||||
/* 166 */ {"_exportfs", {fmt_string, fmt_ptr}, FMT_STATUS},
|
||||
/* 167 */ {"mount",
|
||||
{fmt_string, fmt_string, FMT_FLAGS, fmt_ptr},
|
||||
FMT_STATUS},
|
||||
/* 168 */ {"ustat", {fmt_hex, fmt_ptr}, FMT_STATUS},
|
||||
/* 169 */ {"_semsys",
|
||||
{fmt_dec, fmt_hex, fmt_hex, fmt_hex, fmt_hex},
|
||||
fmt_dec},
|
||||
/* 170 */ {"_msgsys",
|
||||
{fmt_dec, fmt_hex, fmt_hex, fmt_hex, fmt_hex, fmt_hex},
|
||||
fmt_dec},
|
||||
/* 171 */ {"_shmsys", {fmt_dec, fmt_hex, fmt_hex, fmt_hex}, fmt_dec},
|
||||
/* 172 */ {"_auditsys", {fmt_dec, fmt_hex, fmt_hex, fmt_hex}, fmt_dec},
|
||||
/* 173 */ {"_rfssys",
|
||||
{fmt_dec, fmt_hex, fmt_hex, fmt_hex, fmt_hex},
|
||||
fmt_dec},
|
||||
/* 174 */ {"getdents",
|
||||
{fmt_fd, fmt_post_data, FMT_SIZE},
|
||||
fmt_post_data_size},
|
||||
/* 175 */ {"_setsid", {fmt_dec}, fmt_dec},
|
||||
/* 176 */ {"fchdir", {fmt_fd}, FMT_STATUS},
|
||||
/* 177 */ {"fchroot", {fmt_fd}, FMT_STATUS},
|
||||
/* 178 */ {"vpixsys", {fmt_hex, fmt_hex}, fmt_unknown},
|
||||
/*
|
||||
* I am unsure of the parameters for vpixsys.
|
||||
*/
|
||||
/* 179 */ {"aioread",
|
||||
{fmt_fd, fmt_ptr, FMT_SIZE, FMT_SIZE, fmt_dec, fmt_ptr},
|
||||
FMT_STATUS},
|
||||
/* 180 */ {"aiowrite",
|
||||
{fmt_fd, fmt_data, fmt_data_size, FMT_SIZE, fmt_dec, fmt_ptr},
|
||||
FMT_STATUS},
|
||||
/* 181 */ {"aiowait", {fmt_ptr}, fmt_ptr},
|
||||
/* 182 */ {"aiocancel", {fmt_ptr}, FMT_STATUS},
|
||||
/* 183 */ {"sigpending", {fmt_ptr}, FMT_STATUS},
|
||||
/* 184 */ {"_unknown_184", {fmt_unknown}, fmt_unknown},
|
||||
/* 185 */ {"setpgid", {fmt_dec, fmt_dec}, FMT_STATUS},
|
||||
/* 186 */ {"_pathconf", {fmt_string, fmt_dec}, fmt_dec},
|
||||
/* 187 */ {"fpathconf", {fmt_fd, fmt_dec}, fmt_dec},
|
||||
/* 188 */ {"sysconf", {fmt_dec}, fmt_dec},
|
||||
/* 189 */ {"uname", {fmt_ptr}, FMT_STATUS}
|
||||
/*
|
||||
* Next 8 system calls are for loadable system calls. Not declared since
|
||||
* they are likely to change from one O/S release to the next.
|
||||
*/
|
||||
};
|
||||
|
||||
int no_system_calls = sizeof(system_calls) / sizeof(call_desc);
|
||||
|
||||
call_desc system_call_open_simple =
|
||||
/* 5 */ {"open", {fmt_string, fmt_open_flags}, fmt_fd};
|
||||
|
||||
|
||||
/*
|
||||
* Table containing signal names.
|
||||
*/
|
||||
|
||||
char *signal_names[] = {
|
||||
/* 0 */ "0",
|
||||
/* 1 */ "SIGHUP",
|
||||
/* 2 */ "SIGINT",
|
||||
/* 3 */ "SIGQUIT",
|
||||
/* 4 */ "SIGILL",
|
||||
/* 5 */ "SIGTRAP",
|
||||
/* 6 */ "SIGABRT",
|
||||
/* 7 */ "SIGEMT",
|
||||
/* 8 */ "SIGFPE",
|
||||
/* 9 */ "SIGKILL",
|
||||
/* 10 */ "SIGBUS",
|
||||
/* 11 */ "SIGSEGV",
|
||||
/* 12 */ "SIGSYS",
|
||||
/* 13 */ "SIGPIPE",
|
||||
/* 14 */ "SIGALRM",
|
||||
/* 15 */ "SIGTERM",
|
||||
/* 16 */ "SIGURG",
|
||||
/* 17 */ "SIGSTOP",
|
||||
/* 18 */ "SIGTSTP",
|
||||
/* 19 */ "SIGCONT",
|
||||
/* 20 */ "SIGCHLD",
|
||||
/* 21 */ "SIGTTIN",
|
||||
/* 22 */ "SIGTTOU",
|
||||
/* 23 */ "SIGIO",
|
||||
/* 24 */ "SIGXCPU",
|
||||
/* 25 */ "SIGXFSZ",
|
||||
/* 26 */ "SIGVTALRM",
|
||||
/* 27 */ "SIGPROF",
|
||||
/* 28 */ "SIGWINCH",
|
||||
/* 29 */ "SIGLOST",
|
||||
/* 30 */ "SIGUSR1",
|
||||
/* 31 */ "SIGUSR2"
|
||||
};
|
||||
|
||||
int no_signal_names = sizeof(signal_names) / sizeof(char *);
|
||||
|
||||
|
||||
/*
|
||||
* Table containing error messages.
|
||||
*/
|
||||
|
||||
char *error_names[] = {
|
||||
/* 0 */ "0",
|
||||
/* 1 */ "EPERM",
|
||||
/* 2 */ "ENOENT",
|
||||
/* 3 */ "ESRCH",
|
||||
/* 4 */ "EINTR",
|
||||
/* 5 */ "EIO",
|
||||
/* 6 */ "ENXIO",
|
||||
/* 7 */ "E2BIG",
|
||||
/* 8 */ "ENOEXEC",
|
||||
/* 9 */ "EBADF",
|
||||
/* 10 */ "ECHILD",
|
||||
/* 11 */ "EAGAIN",
|
||||
/* 12 */ "ENOMEM",
|
||||
/* 13 */ "EACCES",
|
||||
/* 14 */ "EFAULT",
|
||||
/* 15 */ "ENOTBLK",
|
||||
/* 16 */ "EBUSY",
|
||||
/* 17 */ "EEXIST",
|
||||
/* 18 */ "EXDEV",
|
||||
/* 19 */ "ENODEV",
|
||||
/* 20 */ "ENOTDIR",
|
||||
/* 21 */ "EISDIR",
|
||||
/* 22 */ "EINVAL",
|
||||
/* 23 */ "ENFILE",
|
||||
/* 24 */ "EMFILE",
|
||||
/* 25 */ "ENOTTY",
|
||||
/* 26 */ "ETXTBSY",
|
||||
/* 27 */ "EFBIG",
|
||||
/* 28 */ "ENOSPC",
|
||||
/* 29 */ "ESPIPE",
|
||||
/* 30 */ "EROFS",
|
||||
/* 31 */ "EMLINK",
|
||||
/* 32 */ "EPIPE",
|
||||
/* 33 */ "EDOM",
|
||||
/* 34 */ "ERANGE",
|
||||
/* 35 */ "EWOULDBLOCK",
|
||||
/* 36 */ "EINPROGRESS",
|
||||
/* 37 */ "EALREADY",
|
||||
/* 38 */ "ENOTSOCK",
|
||||
/* 39 */ "EDESTADDRREQ",
|
||||
/* 40 */ "EMSGSIZE",
|
||||
/* 41 */ "EPROTOTYPE",
|
||||
/* 42 */ "ENOPROTOOPT",
|
||||
/* 43 */ "EPROTONOSUPPORT",
|
||||
/* 44 */ "ESOCKTNOSUPPORT",
|
||||
/* 45 */ "EOPNOTSUPP",
|
||||
/* 46 */ "EPFNOSUPPORT",
|
||||
/* 47 */ "EAFNOSUPPORT",
|
||||
/* 48 */ "EADDRINUSE",
|
||||
/* 49 */ "EADDRNOTAVAIL",
|
||||
/* 50 */ "ENETDOWN",
|
||||
/* 51 */ "ENETUNREACH",
|
||||
/* 52 */ "ENETRESET",
|
||||
/* 53 */ "ECONNABORTED",
|
||||
/* 54 */ "ECONNRESET",
|
||||
/* 55 */ "ENOBUFS",
|
||||
/* 56 */ "EISCONN",
|
||||
/* 57 */ "ENOTCONN",
|
||||
/* 58 */ "ESHUTDOWN",
|
||||
/* 59 */ "ETOOMANYREFS",
|
||||
/* 60 */ "ETIMEDOUT",
|
||||
/* 61 */ "ECONNREFUSED",
|
||||
/* 62 */ "ELOOP",
|
||||
/* 63 */ "ENAMETOOLONG",
|
||||
/* 64 */ "EHOSTDOWN",
|
||||
/* 65 */ "EHOSTUNREACH",
|
||||
/* 66 */ "ENOTEMPTY",
|
||||
/* 67 */ "EPROCLIM",
|
||||
/* 68 */ "EUSERS",
|
||||
/* 69 */ "EDQUOT",
|
||||
/* 70 */ "ESTALE",
|
||||
/* 71 */ "EREMOTE",
|
||||
/* 72 */ "ENOSTR",
|
||||
/* 73 */ "ETIME",
|
||||
/* 74 */ "ENOSR",
|
||||
/* 75 */ "ENOMSG",
|
||||
/* 76 */ "EBADMSG",
|
||||
/* 77 */ "EIDRM",
|
||||
/* 78 */ "EDEADLK",
|
||||
/* 79 */ "ENOLCK",
|
||||
/* 80 */ "ENONET",
|
||||
/* 81 */ "ERREMOTE",
|
||||
/* 82 */ "ENOLINK",
|
||||
/* 83 */ "EADV",
|
||||
/* 84 */ "ESRMNT",
|
||||
/* 85 */ "ECOMM",
|
||||
/* 86 */ "EPROTO",
|
||||
/* 87 */ "EMULTIHOP",
|
||||
/* 88 */ "EDOTDOT",
|
||||
/* 89 */ "EREMCHG",
|
||||
/* 90 */ "ENOSYS"
|
||||
};
|
||||
|
||||
int no_error_names = sizeof(error_names) / sizeof(char *);
|
||||
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1991 Gordon Irlam. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Declaration of system calls for sparc trace generator.
|
||||
*/
|
||||
|
||||
|
||||
#if !defined(SYSCALLS_H)
|
||||
#define SYSCALLS_H 1
|
||||
|
||||
/*
|
||||
* Imported declarations.
|
||||
*/
|
||||
|
||||
#include "agent_msg.h"
|
||||
|
||||
|
||||
/*
|
||||
* Declaration of table containing system calls, and their parameter profile.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Words, such as the parameters and results of system calls, are capable of
|
||||
* being displayed in a number of different formats.
|
||||
*
|
||||
* fmt_none - indicates the absense of further arguments, functions that don't
|
||||
* return a value, etc.
|
||||
*
|
||||
* The function format_value(..) can be used to display a word in one of the
|
||||
* following formats.
|
||||
*
|
||||
* fmt_dec - a signed decimal number : 0, 21, -1
|
||||
* fmt_hex - a unsigned hex number : 0x0, 0x15, 0xffffffff
|
||||
* fmt_ptr - a pointer : NULL, 0x00000015, 0xffffffff
|
||||
* fmt_fd - a file descriptor : fd0, fd15, fd-1
|
||||
* fmt_signal - the name of a signal : 0, SIGTTIN, -1
|
||||
* fmt_error - the name of an error : 0, EISDIR, -1
|
||||
* fmt_open_flags - the flags to open : O_RDONLY, O_WRONLY|0x14, 0xffffffff
|
||||
* fmt_unknown - representation unknown : .., .., ..
|
||||
* fmt_string - if the null termintated string at word is printable displays
|
||||
* the string within quotes, otherwise displays like fmt_ptr
|
||||
* fmt_post_string - displays like fmt_ptr, value of word is also saved,
|
||||
* following the system call a printable string exists at
|
||||
* address word the address and the string will be displayed
|
||||
* fmt_data - only permitted in argument lists, next argument must be
|
||||
* format_data_size, if printable data exists at word having length
|
||||
* specified by the next argument it is printed, otherwise displays
|
||||
* like fmt_ptr
|
||||
* fmt_data_size - displays like FMT_SIZE
|
||||
* fmt_post_data - displays like fmt_ptr, value of word is also saved,
|
||||
* following call if a printable length delimited string exists
|
||||
* it will be displayed
|
||||
* fmt_post_data_size - displays like FMT_SIZE, value is saved for use as
|
||||
* length for fmt_post_data display format
|
||||
* fmt_string_array - word is the address of a null terminted array of strings
|
||||
* to be printed if possible
|
||||
*
|
||||
* Unlike the string formats which typically represent filenames it is not so
|
||||
* important that length delimited data be fully displayed. When printable,
|
||||
* it will be truncate much more harshly than the string formats.
|
||||
*
|
||||
* Only one item can be pending for display at the end of a system call.
|
||||
*
|
||||
* At a later date this program may be extended to display length delimited
|
||||
* data as a hex dump if it is not printable.
|
||||
*
|
||||
* The following macros are employed to make it easy to alter how a whole
|
||||
* class of values is displayed by changing their definition.
|
||||
*
|
||||
* FMT_STATUS - function calls that return 0 on success and -1 on error
|
||||
* FMT_FLAGS - bit field objects
|
||||
* FMT_SIZE - length of an object in bytes
|
||||
*/
|
||||
typedef enum fmt_type {fmt_none = 0, fmt_dec, fmt_hex, fmt_ptr, fmt_fd,
|
||||
fmt_signal, fmt_error, fmt_open_flags, fmt_unknown, fmt_string,
|
||||
fmt_post_string, fmt_data, fmt_post_data, fmt_data_size,
|
||||
fmt_post_data_size, fmt_string_array} fmt_type;
|
||||
|
||||
#define FMT_STATUS fmt_none
|
||||
#define FMT_FLAGS fmt_hex
|
||||
#define FMT_SIZE fmt_dec
|
||||
|
||||
typedef struct _spa_call_desc {
|
||||
char *name;
|
||||
fmt_type arg[NO_PARAMS];
|
||||
fmt_type result;
|
||||
} spa_call_desc;
|
||||
|
||||
extern spa_call_desc spa_system_calls[];
|
||||
|
||||
extern int no_system_calls;
|
||||
|
||||
extern spa_call_desc spa_system_call_open_simple;
|
||||
|
||||
#define SPA_DATA_SIZE_LIMIT 20
|
||||
#define SPA_STRING_SIZE_LIMIT 201
|
||||
#define SPA_ARRAY_SIZE_LIMIT 21
|
||||
|
||||
|
||||
/*
|
||||
* Declaration of table containing signal names.
|
||||
*/
|
||||
|
||||
extern char *spa_signal_names[];
|
||||
|
||||
extern int spa_no_signal_names;
|
||||
|
||||
|
||||
/*
|
||||
* Declaration of table containing error messages.
|
||||
*/
|
||||
|
||||
char *spa_error_names[];
|
||||
|
||||
extern int spa_no_error_names;
|
||||
|
||||
#endif
|
@ -19,8 +19,8 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
#ifndef _PSIM_CONFIG_H_
|
||||
#define _PSIM_CONFIG_H_
|
||||
|
||||
|
||||
/* endianness of the host/target:
|
||||
@ -292,47 +292,141 @@ extern int current_model_issue;
|
||||
GCC -O3 attempts to inline any function or procedure in scope. The
|
||||
options below facilitate fine grained control over what is and what
|
||||
isn't made inline. For instance it can control things down to a
|
||||
specific modules static routines. This control is implemented in
|
||||
two parts. Doing this allows the compiler to both eliminate the
|
||||
overhead of function calls and (as a consequence) also eliminate
|
||||
further dead code.
|
||||
specific modules static routines. Doing this allows the compiler
|
||||
to both eliminate the overhead of function calls and (as a
|
||||
consequence) also eliminate further dead code.
|
||||
|
||||
Experementing with CISC (x86) I've found that I can achieve an
|
||||
order of magintude speed improvement (x3-x5). In the case of RISC
|
||||
(sparc) while the performance gain isn't as great it is still
|
||||
significant.
|
||||
On a CISC (x86) I've found that I can achieve an order of magintude
|
||||
speed improvement (x3-x5). In the case of RISC (sparc) while the
|
||||
performance gain isn't as great it is still significant.
|
||||
|
||||
Part One - Static functions: It is possible to control how static
|
||||
functions within each module are to be compiled. On a per module
|
||||
or global basis, it is possible to specify that a modules static
|
||||
functions should be compiled inline. This is controled by the the
|
||||
macro's STATIC_INLINE and INLINE_STATIC_<module>.
|
||||
Each module is controled by the macro <module>_INLINE which can
|
||||
have the values described below
|
||||
|
||||
Part Two - External functions: Again it is possible to allow the
|
||||
inlining of calls to external functions. This is far more
|
||||
complicated and much heaver on the compiler. In this case, it is
|
||||
controled by the <module>_INLINE macro's. Where each can have a
|
||||
value:
|
||||
0 Do not inline any thing for the given module
|
||||
|
||||
0 Make a normal external call to functions in the module.
|
||||
The following additional values are `bit fields' and can be
|
||||
combined.
|
||||
|
||||
1 Include the module but to not inline functions within it.
|
||||
This allows functions within the module to inline functions
|
||||
from other modules that have been included.
|
||||
1 Include the C file for the module into the file being compiled
|
||||
but do not make the functions within the module inline.
|
||||
|
||||
2 Both include the module and inline functions contained within
|
||||
it.
|
||||
While of no apparent benefit, this makes it possible for the
|
||||
included module, when compiled to inline its calls to what
|
||||
would otherwize be external functions.
|
||||
|
||||
Finally, this is not for the faint harted. I've seen GCC get up to
|
||||
200mb trying to compile what this can create */
|
||||
2 Make external functions within the module `inline'. Thus if
|
||||
the module is included into a file being compiled, calls to
|
||||
its funtions can be eliminated. 2 implies 1.
|
||||
|
||||
4 Make internal (static) functions within the module `inline'.
|
||||
|
||||
In addition to this, modules have been put into two categories.
|
||||
|
||||
Simple modules - eg sim-endian.h bits.h
|
||||
|
||||
Because these modules are small and simple and do not have
|
||||
any complex interpendencies they are configured, if
|
||||
<module>_INLINE is so enabled, to inline themselves in all
|
||||
modules that include those files.
|
||||
|
||||
For the default build, this is a real win as all byte
|
||||
conversion and bit manipulation functions are inlined.
|
||||
|
||||
Complex modules - the rest
|
||||
|
||||
These are all handled using the files inline.h and inline.c.
|
||||
psim.c includes the above which in turn include any remaining
|
||||
code.
|
||||
|
||||
IMPLEMENTATION:
|
||||
|
||||
The inline ability is enabled by prefixing every data / function
|
||||
declaration and definition with one of the following:
|
||||
|
||||
|
||||
INLINE_<module>
|
||||
|
||||
Prefix to any global function that is a candidate for being
|
||||
inline.
|
||||
|
||||
values - `', `static', `static INLINE'
|
||||
|
||||
|
||||
EXTERN_<module>
|
||||
|
||||
Prefix to any global data structures for the module. Global
|
||||
functions that are not to be inlined shall also be prefixed
|
||||
with this.
|
||||
|
||||
values - `', `static', `static'
|
||||
|
||||
|
||||
STATIC_INLINE_<module>
|
||||
|
||||
Prefix to any local (static) function that is a candidate for
|
||||
being made inline.
|
||||
|
||||
values - `static', `static INLINE'
|
||||
|
||||
|
||||
static
|
||||
|
||||
Prefix all local data structures. Local functions that are not
|
||||
to be inlined shall also be prefixed with this.
|
||||
|
||||
values - `static', `static'
|
||||
|
||||
nb: will not work for modules that are being inlined for every
|
||||
use (white lie).
|
||||
|
||||
|
||||
extern
|
||||
#ifndef _INLINE_C_
|
||||
#endif
|
||||
|
||||
Prefix to any declaration of a global object (function or
|
||||
variable) that should not be inlined and should have only one
|
||||
definition. The #ifndef wrapper goes around the definition
|
||||
propper to ensure that only one copy is generated.
|
||||
|
||||
nb: this will not work when a module is being inlined for every
|
||||
use.
|
||||
|
||||
|
||||
STATIC_<module>
|
||||
|
||||
Replaced by either `static' or `EXTERN_MODULE'.
|
||||
|
||||
|
||||
REALITY CHECK:
|
||||
|
||||
This is not for the faint hearted. I've seen GCC get up to 200mb
|
||||
trying to compile what this can create.
|
||||
|
||||
Some of the modules do not yet implement the WITH_INLINE_STATIC
|
||||
option. Instead they use the macro STATIC_INLINE to control their
|
||||
local function.
|
||||
|
||||
Because of the way that GCC parses __attribute__(), the macro's
|
||||
need to be adjacent to the functioin name rather then at the start
|
||||
of the line vis:
|
||||
|
||||
int STATIC_INLINE_MODULE f(void);
|
||||
void INLINE_MODULE *g(void);
|
||||
|
||||
*/
|
||||
|
||||
#define REVEAL_MODULE 1
|
||||
#define INLINE_MODULE 2
|
||||
#define INCLUDE_MODULE (INLINE_MODULE | REVEAL_MODULE)
|
||||
#define INLINE_LOCALS 4
|
||||
#define ALL_INLINE 7
|
||||
|
||||
/* Your compilers inline reserved word */
|
||||
|
||||
#ifndef INLINE
|
||||
#if defined(__GNUC__) && defined(__OPTIMIZE__) && \
|
||||
(DEFAULT_INLINE || SIM_ENDIAN_INLINE || BITS_INLINE || CPU_INLINE || VM_INLINE || CORE_INLINE \
|
||||
|| EVENTS_INLINE || MON_INLINE || INTERRUPTS_INLINE || REGISTERS_INLINE || DEVICE_TREE_INLINE \
|
||||
|| DEVICES_INLINE || SPREG_INLINE || SEMANTICS_INLINE || IDECODE_INLINE || MODEL_INLINE)
|
||||
#if defined(__GNUC__) && defined(__OPTIMIZE__)
|
||||
#define INLINE __inline__
|
||||
#else
|
||||
#define INLINE /*inline*/
|
||||
@ -348,29 +442,30 @@ extern int current_model_issue;
|
||||
/* Default macro to simplify control several of key the inlines */
|
||||
|
||||
#ifndef DEFAULT_INLINE
|
||||
#define DEFAULT_INLINE 0
|
||||
#define DEFAULT_INLINE INLINE_LOCALS
|
||||
#endif
|
||||
|
||||
/* Code that converts between hosts and target byte order. Used on
|
||||
every memory access (instruction and data). (See sim-endian.h for
|
||||
additional byte swapping configuration information) */
|
||||
every memory access (instruction and data). See sim-endian.h for
|
||||
additional byte swapping configuration information. This module
|
||||
can inline for all callers */
|
||||
|
||||
#ifndef SIM_ENDIAN_INLINE
|
||||
#define SIM_ENDIAN_INLINE DEFAULT_INLINE
|
||||
#define SIM_ENDIAN_INLINE (DEFAULT_INLINE ? ALL_INLINE : 0)
|
||||
#endif
|
||||
|
||||
/* Low level bit manipulation routines used to work around a compiler
|
||||
bug in 2.6.3. */
|
||||
/* Low level bit manipulation routines. This module can inline for all
|
||||
callers */
|
||||
|
||||
#ifndef BITS_INLINE
|
||||
#define BITS_INLINE DEFAULT_INLINE
|
||||
#define BITS_INLINE (DEFAULT_INLINE ? ALL_INLINE : 0)
|
||||
#endif
|
||||
|
||||
/* Code that gives access to various CPU internals such as registers.
|
||||
Used every time an instruction is executed */
|
||||
|
||||
#ifndef CPU_INLINE
|
||||
#define CPU_INLINE DEFAULT_INLINE
|
||||
#define CPU_INLINE (DEFAULT_INLINE ? ALL_INLINE : 0)
|
||||
#endif
|
||||
|
||||
/* Code that translates between an effective and real address. Used
|
||||
@ -391,27 +486,27 @@ extern int current_model_issue;
|
||||
Called once per instruction cycle */
|
||||
|
||||
#ifndef EVENTS_INLINE
|
||||
#define EVENTS_INLINE DEFAULT_INLINE
|
||||
#define EVENTS_INLINE (DEFAULT_INLINE ? ALL_INLINE : 0)
|
||||
#endif
|
||||
|
||||
/* Code monotoring the processors performance. It counts events on
|
||||
every instruction cycle */
|
||||
|
||||
#ifndef MON_INLINE
|
||||
#define MON_INLINE DEFAULT_INLINE
|
||||
#define MON_INLINE (DEFAULT_INLINE ? ALL_INLINE : 0)
|
||||
#endif
|
||||
|
||||
/* Code called on the rare occasions that an interrupt occures. */
|
||||
|
||||
#ifndef INTERRUPTS_INLINE
|
||||
#define INTERRUPTS_INLINE 0
|
||||
#define INTERRUPTS_INLINE DEFAULT_INLINE
|
||||
#endif
|
||||
|
||||
/* Code called on the rare occasion that either gdb or the device tree
|
||||
need to manipulate a register within a processor */
|
||||
|
||||
#ifndef REGISTERS_INLINE
|
||||
#define REGISTERS_INLINE 0
|
||||
#define REGISTERS_INLINE DEFAULT_INLINE
|
||||
#endif
|
||||
|
||||
/* Code called on the rare occasion that a processor is manipulating
|
||||
@ -424,12 +519,8 @@ extern int current_model_issue;
|
||||
devices inline. It reports the message: device_tree_find_node()
|
||||
not a leaf */
|
||||
|
||||
#ifndef DEVICE_TREE_INLINE
|
||||
#define DEVICE_TREE_INLINE 0
|
||||
#endif
|
||||
|
||||
#ifndef DEVICES_INLINE
|
||||
#define DEVICES_INLINE 0
|
||||
#ifndef DEVICE_INLINE
|
||||
#define DEVICE_INLINE DEFAULT_INLINE
|
||||
#endif
|
||||
|
||||
/* Code called whenever information on a Special Purpose Register is
|
||||
@ -452,7 +543,7 @@ extern int current_model_issue;
|
||||
inline all of their called functions */
|
||||
|
||||
#ifndef SEMANTICS_INLINE
|
||||
#define SEMANTICS_INLINE (DEFAULT_INLINE ? 1 : 0)
|
||||
#define SEMANTICS_INLINE DEFAULT_INLINE
|
||||
#endif
|
||||
|
||||
/* Code to decode an instruction. Normally called on every instruction
|
||||
@ -468,7 +559,7 @@ extern int current_model_issue;
|
||||
of the code, which is not friendly to the cache. */
|
||||
|
||||
#ifndef MODEL_INLINE
|
||||
#define MODEL_INLINE (DEFAULT_INLINE ? 1 : 0)
|
||||
#define MODEL_INLINE DEFAULT_INLINE
|
||||
#endif
|
||||
|
||||
/* Code to print out what options we were compiled with. Because this
|
||||
@ -477,7 +568,14 @@ extern int current_model_issue;
|
||||
routines will be pulled in twice. */
|
||||
|
||||
#ifndef OPTIONS_INLINE
|
||||
#define OPTIONS_INLINE (DEFAULT_INLINE ? 1 : 0)
|
||||
#define OPTIONS_INLINE DEFAULT_INLINE
|
||||
#endif
|
||||
|
||||
#endif /* _CONFIG_H */
|
||||
/* Code to emulate os or rom compatibility. Called on the rare
|
||||
occasion that the OS or ROM code is being emulated. */
|
||||
|
||||
#ifndef OS_EMUL_INLINE
|
||||
#define OS_EMUL_INLINE 0
|
||||
#endif
|
||||
|
||||
#endif /* _PSIM_CONFIG_H */
|
||||
|
404
sim/ppc/vm.c
404
sim/ppc/vm.c
@ -22,22 +22,12 @@
|
||||
#ifndef _VM_C_
|
||||
#define _VM_C_
|
||||
|
||||
#ifndef STATIC_INLINE_VM
|
||||
#define STATIC_INLINE_VM STATIC_INLINE
|
||||
#endif
|
||||
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
#include "registers.h"
|
||||
|
||||
#include "device_tree.h"
|
||||
#include "device.h"
|
||||
#include "corefile.h"
|
||||
|
||||
#include "vm.h"
|
||||
|
||||
#include "interrupts.h"
|
||||
|
||||
#include "mon.h"
|
||||
|
||||
/* OEA vs VEA
|
||||
@ -64,7 +54,10 @@
|
||||
structures is maintained by updating the structures at
|
||||
`synchronization' points. Of particular note is that (at the time
|
||||
of writing) the memory data types for BAT registers are rebuilt
|
||||
when ever the processor moves between problem and system states */
|
||||
when ever the processor moves between problem and system states.
|
||||
|
||||
Unpacked values are stored in the OEA so that they correctly align
|
||||
to where they will be needed by the PTE address. */
|
||||
|
||||
|
||||
/* Protection table:
|
||||
@ -145,7 +138,7 @@ enum _om_segment_tlb_constants {
|
||||
typedef struct _om_segment_tlb_entry {
|
||||
int key[nr_om_modes];
|
||||
om_access_types invalid_access; /* set to instruction if no_execute bit */
|
||||
unsigned_word masked_virtual_segment_id;
|
||||
unsigned_word masked_virtual_segment_id; /* aligned ready for pte addr */
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 64)
|
||||
int is_valid;
|
||||
unsigned_word masked_effective_segment_id;
|
||||
@ -178,9 +171,14 @@ enum _om_page_tlb_constants {
|
||||
nr_om_page_tlb_constants
|
||||
};
|
||||
|
||||
enum {
|
||||
invalid_tlb_vsid = MASK(0, 63),
|
||||
};
|
||||
|
||||
typedef struct _om_page_tlb_entry {
|
||||
int valid;
|
||||
int protection;
|
||||
int changed;
|
||||
unsigned_word real_address_of_pte_1;
|
||||
unsigned_word masked_virtual_segment_id;
|
||||
unsigned_word masked_page;
|
||||
unsigned_word masked_real_page_number;
|
||||
@ -219,6 +217,9 @@ typedef struct _om_map {
|
||||
/* physical memory for fetching page table entries */
|
||||
core_map *physical;
|
||||
|
||||
/* address xor for PPC endian */
|
||||
unsigned xor[WITH_XOR_ENDIAN];
|
||||
|
||||
} om_map;
|
||||
|
||||
|
||||
@ -274,7 +275,7 @@ struct _vm {
|
||||
/* OEA Support procedures */
|
||||
|
||||
|
||||
STATIC_INLINE_VM unsigned_word
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_segment_tlb_index(unsigned_word ea)
|
||||
{
|
||||
unsigned_word index = EXTRACTED(ea,
|
||||
@ -283,7 +284,7 @@ om_segment_tlb_index(unsigned_word ea)
|
||||
return index;
|
||||
}
|
||||
|
||||
STATIC_INLINE_VM unsigned_word
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_page_tlb_index(unsigned_word ea)
|
||||
{
|
||||
unsigned_word index = EXTRACTED(ea,
|
||||
@ -292,23 +293,131 @@ om_page_tlb_index(unsigned_word ea)
|
||||
return index;
|
||||
}
|
||||
|
||||
STATIC_INLINE_VM unsigned_word
|
||||
om_masked_page(unsigned_word ea)
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_hash_page(unsigned_word masked_vsid,
|
||||
unsigned_word ea)
|
||||
{
|
||||
unsigned_word masked_page = MASKED(ea, 36, 51);
|
||||
return masked_page;
|
||||
unsigned_word extracted_ea = EXTRACTED(ea, 36, 51);
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 32)
|
||||
return masked_vsid ^ INSERTED32(extracted_ea, 7, 31-6);
|
||||
#endif
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 64)
|
||||
return masked_vsid ^ INSERTED64(extracted_ea, 18, 63-7);
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC_INLINE_VM unsigned_word
|
||||
om_masked_byte(unsigned_word ea)
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_pte_0_api(unsigned_word pte_0)
|
||||
{
|
||||
unsigned_word masked_byte = MASKED(ea, 52, 63);
|
||||
return masked_byte;
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 32)
|
||||
return EXTRACTED32(pte_0, 26, 31);
|
||||
#endif
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 64)
|
||||
return EXTRACTED64(pte_0, 52, 56);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_pte_0_hash(unsigned_word pte_0)
|
||||
{
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 32)
|
||||
return EXTRACTED32(pte_0, 25, 25);
|
||||
#endif
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 64)
|
||||
return EXTRACTED64(pte_0, 62, 62);
|
||||
#endif
|
||||
}
|
||||
|
||||
int STATIC_INLINE_VM
|
||||
om_pte_0_valid(unsigned_word pte_0)
|
||||
{
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 32)
|
||||
return MASKED32(pte_0, 0, 0) != 0;
|
||||
#endif
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 64)
|
||||
return MASKED64(pte_0, 63, 63) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_ea_masked_page(unsigned_word ea)
|
||||
{
|
||||
return MASKED(ea, 36, 51);
|
||||
}
|
||||
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_ea_masked_byte(unsigned_word ea)
|
||||
{
|
||||
return MASKED(ea, 52, 63);
|
||||
}
|
||||
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_pte_0_masked_vsid(unsigned_word pte_0)
|
||||
{
|
||||
return INSERTED32(EXTRACTED32(pte_0, 1, 24), 7-5, 31-6);
|
||||
}
|
||||
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_pte_1_pp(unsigned_word pte_1)
|
||||
{
|
||||
return MASKED(pte_1, 62, 63); /*PP*/
|
||||
}
|
||||
|
||||
int STATIC_INLINE_VM
|
||||
om_pte_1_referenced(unsigned_word pte_1)
|
||||
{
|
||||
return EXTRACTED(pte_1, 55, 55);
|
||||
}
|
||||
|
||||
int STATIC_INLINE_VM
|
||||
om_pte_1_changed(unsigned_word pte_1)
|
||||
{
|
||||
return EXTRACTED(pte_1, 56, 56);
|
||||
}
|
||||
|
||||
int STATIC_INLINE_VM
|
||||
om_pte_1_masked_rpn(unsigned_word pte_1)
|
||||
{
|
||||
return MASKED(pte_1, 0, 51); /*RPN*/
|
||||
}
|
||||
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_ea_api(unsigned_word ea)
|
||||
{
|
||||
return EXTRACTED(ea, 36, 41);
|
||||
}
|
||||
|
||||
|
||||
/* Page and Segment table read/write operators, these need to still
|
||||
account for the PPC's XOR operation */
|
||||
|
||||
INLINE_VM vm *
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_read_word(om_map *map,
|
||||
unsigned_word ra,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
if (WITH_XOR_ENDIAN)
|
||||
ra ^= map->xor[sizeof(instruction_word) - 1];
|
||||
return core_map_read_word(map->physical, ra, processor, cia);
|
||||
}
|
||||
|
||||
void STATIC_INLINE_VM
|
||||
om_write_word(om_map *map,
|
||||
unsigned_word ra,
|
||||
unsigned_word val,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
if (WITH_XOR_ENDIAN)
|
||||
ra ^= map->xor[sizeof(instruction_word) - 1];
|
||||
core_map_write_word(map->physical, ra, val, processor, cia);
|
||||
}
|
||||
|
||||
|
||||
/* Bring things into existance */
|
||||
|
||||
vm INLINE_VM *
|
||||
vm_create(core *physical)
|
||||
{
|
||||
vm *virtual;
|
||||
@ -351,7 +460,7 @@ vm_create(core *physical)
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_VM om_bat *
|
||||
om_bat STATIC_INLINE_VM *
|
||||
om_effective_to_bat(om_map *map,
|
||||
unsigned_word ea)
|
||||
{
|
||||
@ -371,7 +480,7 @@ om_effective_to_bat(om_map *map,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_VM om_segment_tlb_entry *
|
||||
om_segment_tlb_entry STATIC_INLINE_VM *
|
||||
om_effective_to_virtual(om_map *map,
|
||||
unsigned_word ea,
|
||||
cpu *processor,
|
||||
@ -407,9 +516,10 @@ om_effective_to_virtual(om_map *map,
|
||||
segment_table_entry += sizeof_segment_table_entry) {
|
||||
/* byte order? */
|
||||
unsigned_word segment_table_entry_dword_0 =
|
||||
core_map_read_8(map->physical, segment_table_entry, processor, cia);
|
||||
om_read_word(map->physical, segment_table_entry, processor, cia);
|
||||
unsigned_word segment_table_entry_dword_1 =
|
||||
core_map_read_8(map->physical, segment_table_entry + 8, processor, cia);
|
||||
om_read_word(map->physical, segment_table_entry + 8,
|
||||
processor, cia);
|
||||
int is_valid = MASKED64(segment_table_entry_dword_0, 56, 56) != 0;
|
||||
unsigned_word masked_effective_segment_id =
|
||||
MASKED64(segment_table_entry_dword_0, 0, 35);
|
||||
@ -430,7 +540,8 @@ om_effective_to_virtual(om_map *map,
|
||||
? om_instruction_read
|
||||
: om_access_any);
|
||||
segment_tlb_entry->masked_virtual_segment_id =
|
||||
MASKED(segment_table_entry_dword_1, 0, 51);
|
||||
INSERTED64(EXTRACTED64(segment_table_entry_dword_1, 0, 51),
|
||||
18-13, 63-7); /* align ready for pte addr */
|
||||
return segment_tlb_entry;
|
||||
}
|
||||
}
|
||||
@ -443,7 +554,7 @@ om_effective_to_virtual(om_map *map,
|
||||
|
||||
|
||||
|
||||
STATIC_INLINE_VM om_page_tlb_entry *
|
||||
om_page_tlb_entry STATIC_INLINE_VM *
|
||||
om_virtual_to_real(om_map *map,
|
||||
unsigned_word ea,
|
||||
om_segment_tlb_entry *segment_tlb_entry,
|
||||
@ -455,46 +566,69 @@ om_virtual_to_real(om_map *map,
|
||||
+ om_page_tlb_index(ea));
|
||||
|
||||
/* is it a tlb hit? */
|
||||
if (page_tlb_entry->valid
|
||||
&& (page_tlb_entry->masked_virtual_segment_id ==
|
||||
segment_tlb_entry->masked_virtual_segment_id)
|
||||
&& (page_tlb_entry->masked_page == om_masked_page(ea))) {
|
||||
error("fixme - it is not a hit if direction/update bits do not match\n");
|
||||
if ((page_tlb_entry->masked_virtual_segment_id
|
||||
== segment_tlb_entry->masked_virtual_segment_id)
|
||||
&& (page_tlb_entry->masked_page
|
||||
== om_ea_masked_page(ea))) {
|
||||
TRACE(trace_vm, ("ea=0x%lx - tlb hit - tlb=0x%lx\n",
|
||||
(long)ea, (long)page_tlb_entry));
|
||||
return page_tlb_entry;
|
||||
}
|
||||
|
||||
/* drats, it is a tlb miss */
|
||||
{
|
||||
unsigned_word page_hash = (segment_tlb_entry->masked_virtual_segment_id
|
||||
^ om_masked_page(ea));
|
||||
unsigned_word page_hash =
|
||||
om_hash_page(segment_tlb_entry->masked_virtual_segment_id, ea);
|
||||
int current_hash;
|
||||
for (current_hash = 0; current_hash < 2; current_hash += 1) {
|
||||
unsigned_word real_address_of_pte_group =
|
||||
(map->real_address_of_page_table
|
||||
| (page_hash & map->page_table_hash_mask));
|
||||
unsigned_word real_address_of_pte;
|
||||
for (real_address_of_pte = real_address_of_pte_group;
|
||||
real_address_of_pte < (real_address_of_pte_group
|
||||
+ sizeof_pte_group);
|
||||
real_address_of_pte += sizeof_pte) {
|
||||
unsigned_word pte_word_0 =
|
||||
core_map_read_word(map->physical,
|
||||
real_address_of_pte,
|
||||
processor, cia);
|
||||
unsigned_word pte_word_1 =
|
||||
core_map_read_word(map->physical,
|
||||
real_address_of_pte + sizeof_pte / 2,
|
||||
processor, cia);
|
||||
error("fixme - check pte hit %ld %ld\n",
|
||||
(long)pte_word_0,
|
||||
(long)pte_word_1);
|
||||
if (1) {
|
||||
error("fixme - update the page_tlb\n");
|
||||
page_tlb_entry->valid = 1;
|
||||
page_tlb_entry->protection = 0;
|
||||
page_tlb_entry->masked_virtual_segment_id = 0;
|
||||
page_tlb_entry->masked_page = 0;
|
||||
page_tlb_entry->masked_real_page_number = 0;
|
||||
unsigned_word real_address_of_pte_0;
|
||||
TRACE(trace_vm,
|
||||
("ea=0x%lx - htab search - pteg=0x%lx htab=0x%lx mask=0x%lx hash=0x%lx\n",
|
||||
(long)ea, (long)real_address_of_pte_group,
|
||||
map->real_address_of_page_table,
|
||||
map->page_table_hash_mask,
|
||||
page_hash));
|
||||
for (real_address_of_pte_0 = real_address_of_pte_group;
|
||||
real_address_of_pte_0 < (real_address_of_pte_group
|
||||
+ sizeof_pte_group);
|
||||
real_address_of_pte_0 += sizeof_pte) {
|
||||
unsigned_word pte_0 = om_read_word(map,
|
||||
real_address_of_pte_0,
|
||||
processor, cia);
|
||||
/* did we hit? */
|
||||
if (om_pte_0_valid(pte_0)
|
||||
&& (current_hash == om_pte_0_hash(pte_0))
|
||||
&& (segment_tlb_entry->masked_virtual_segment_id
|
||||
== om_pte_0_masked_vsid(pte_0))
|
||||
&& (om_ea_api(ea) == om_pte_0_api(pte_0))) {
|
||||
unsigned_word real_address_of_pte_1 = (real_address_of_pte_0
|
||||
+ sizeof_pte / 2);
|
||||
unsigned_word pte_1 = om_read_word(map,
|
||||
real_address_of_pte_1,
|
||||
processor, cia);
|
||||
page_tlb_entry->protection = om_pte_1_pp(pte_1);
|
||||
page_tlb_entry->changed = om_pte_1_changed(pte_1);
|
||||
page_tlb_entry->masked_virtual_segment_id = segment_tlb_entry->masked_virtual_segment_id;
|
||||
page_tlb_entry->masked_page = om_ea_masked_page(ea);
|
||||
page_tlb_entry->masked_real_page_number = om_pte_1_masked_rpn(pte_1);
|
||||
page_tlb_entry->real_address_of_pte_1 = real_address_of_pte_1;
|
||||
if (!om_pte_1_referenced(pte_1)) {
|
||||
om_write_word(map,
|
||||
real_address_of_pte_1,
|
||||
pte_1 | BIT(55),
|
||||
processor, cia);
|
||||
TRACE(trace_vm,
|
||||
("ea=0x%lx - htab hit - set ref - tlb=0x%lx &pte1=0x%lx\n",
|
||||
(long)ea, page_tlb_entry, (long)real_address_of_pte_1));
|
||||
}
|
||||
else {
|
||||
TRACE(trace_vm,
|
||||
("ea=0x%lx - htab hit - tlb=0x%lx &pte1=0x%lx\n",
|
||||
(long)ea, page_tlb_entry, (long)real_address_of_pte_1));
|
||||
}
|
||||
return page_tlb_entry;
|
||||
}
|
||||
}
|
||||
@ -505,7 +639,7 @@ om_virtual_to_real(om_map *map,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
void STATIC_INLINE_VM
|
||||
om_interrupt(cpu *processor,
|
||||
unsigned_word cia,
|
||||
unsigned_word ea,
|
||||
@ -529,7 +663,7 @@ om_interrupt(cpu *processor,
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_VM unsigned_word
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
om_translate_effective_to_real(om_map *map,
|
||||
unsigned_word ea,
|
||||
om_access_types access,
|
||||
@ -544,9 +678,7 @@ om_translate_effective_to_real(om_map *map,
|
||||
|
||||
if (!map->is_relocate) {
|
||||
ra = ea;
|
||||
TRACE(trace_vm, ("%s, direct map, ea=0x%x\n",
|
||||
"om_translate_effective_to_real",
|
||||
ea));
|
||||
TRACE(trace_vm, ("ea=0x%lx - direct map - ra=0x%lx", (long)ea, (long)ra));
|
||||
return ra;
|
||||
}
|
||||
|
||||
@ -554,9 +686,7 @@ om_translate_effective_to_real(om_map *map,
|
||||
bat = om_effective_to_bat(map, ea);
|
||||
if (bat != NULL) {
|
||||
if (!om_valid_access[1][bat->protection_bits][access]) {
|
||||
TRACE(trace_vm, ("%s, bat protection violation, ea=0x%x\n",
|
||||
"om_translate_effective_to_real",
|
||||
ea));
|
||||
TRACE(trace_vm, ("ea=0x%lx - bat access violation\n", (long)ea));
|
||||
if (abort)
|
||||
om_interrupt(processor, cia, ea, access,
|
||||
protection_violation_storage_interrupt);
|
||||
@ -565,9 +695,8 @@ om_translate_effective_to_real(om_map *map,
|
||||
}
|
||||
|
||||
ra = ((ea & bat->block_length_mask) | bat->block_real_page_number);
|
||||
TRACE(trace_vm, ("%s, bat translation, ea=0x%x, ra=0x%x\n",
|
||||
"om_translate_effective_to_real",
|
||||
ea, ra));
|
||||
TRACE(trace_vm, ("ea=0x%lx - bat translation - ra=0x%lx\n",
|
||||
(long)ea, (long)ra));
|
||||
return ra;
|
||||
}
|
||||
|
||||
@ -575,9 +704,7 @@ om_translate_effective_to_real(om_map *map,
|
||||
segment_tlb_entry = om_effective_to_virtual(map, ea, processor, cia);
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 64)
|
||||
if (segment_tlb_entry == NULL) {
|
||||
TRACE(trace_vm, ("%s, segment tlb lookup failed - ea=0x%x\n",
|
||||
"om_translate_effective_to_real",
|
||||
ea));
|
||||
TRACE(trace_vm, ("ea=0x%lx - segment tlb miss\n", (long)ea));
|
||||
if (abort)
|
||||
om_interrupt(processor, cia, ea, access,
|
||||
segment_table_miss_storage_interrupt);
|
||||
@ -587,9 +714,7 @@ om_translate_effective_to_real(om_map *map,
|
||||
#endif
|
||||
/* check for invalid segment access type */
|
||||
if (segment_tlb_entry->invalid_access == access) {
|
||||
TRACE(trace_vm, ("%s, segment tlb access invalid - ea=0x%x\n",
|
||||
"om_translate_effective_to_real",
|
||||
ea));
|
||||
TRACE(trace_vm, ("ea=0x%lx - segment access invalid\n", (long)ea));
|
||||
if (abort)
|
||||
om_interrupt(processor, cia, ea, access,
|
||||
protection_violation_storage_interrupt);
|
||||
@ -602,9 +727,7 @@ om_translate_effective_to_real(om_map *map,
|
||||
access,
|
||||
processor, cia);
|
||||
if (page_tlb_entry == NULL) {
|
||||
TRACE(trace_vm, ("%s, page tlb lookup failed - ea=0x%x\n",
|
||||
"om_translate_effective_to_real",
|
||||
ea));
|
||||
TRACE(trace_vm, ("ea=0x%lx - page tlb miss\n", (long)ea));
|
||||
if (abort)
|
||||
om_interrupt(processor, cia, ea, access,
|
||||
hash_table_miss_storage_interrupt);
|
||||
@ -615,9 +738,7 @@ om_translate_effective_to_real(om_map *map,
|
||||
[segment_tlb_entry->key[map->is_problem_state]]
|
||||
[page_tlb_entry->protection]
|
||||
[access])) {
|
||||
TRACE(trace_vm, ("%s, page tlb access invalid - ea=0x%x\n",
|
||||
"om_translate_effective_to_real",
|
||||
ea));
|
||||
TRACE(trace_vm, ("ea=0x%lx - page tlb access violation\n", (long)ea));
|
||||
if (abort)
|
||||
om_interrupt(processor, cia, ea, access,
|
||||
protection_violation_storage_interrupt);
|
||||
@ -625,11 +746,23 @@ om_translate_effective_to_real(om_map *map,
|
||||
return MASK(0, 63);
|
||||
}
|
||||
|
||||
ra = (page_tlb_entry->masked_real_page_number
|
||||
| om_masked_byte(ea));
|
||||
TRACE(trace_vm, ("%s, page - ea=0x%x, ra=0x%x\n",
|
||||
"om_translate_effective_to_real",
|
||||
ea, ra));
|
||||
/* update change bit as needed */
|
||||
if (access == om_data_write &&!page_tlb_entry->changed) {
|
||||
unsigned_word pte_1 = om_read_word(map,
|
||||
page_tlb_entry->real_address_of_pte_1,
|
||||
processor, cia);
|
||||
om_write_word(map,
|
||||
page_tlb_entry->real_address_of_pte_1,
|
||||
pte_1 | BIT(56),
|
||||
processor, cia);
|
||||
TRACE(trace_vm, ("ea=0x%lx - set change bit - tlb=0x%lx &pte1=0x%lx\n",
|
||||
(long)ea, (long)page_tlb_entry,
|
||||
(long)page_tlb_entry->real_address_of_pte_1));
|
||||
}
|
||||
|
||||
ra = (page_tlb_entry->masked_real_page_number | om_ea_masked_byte(ea));
|
||||
TRACE(trace_vm, ("ea=0x%lx - page translation - ra=0x%lx\n",
|
||||
(long)ea, (long)ra));
|
||||
return ra;
|
||||
}
|
||||
|
||||
@ -640,7 +773,7 @@ om_translate_effective_to_real(om_map *map,
|
||||
|
||||
|
||||
/* rebuild all the relevant bat information */
|
||||
STATIC_INLINE_VM void
|
||||
void STATIC_INLINE_VM
|
||||
om_unpack_bat(om_bat *bat,
|
||||
spreg ubat,
|
||||
spreg lbat)
|
||||
@ -660,7 +793,7 @@ om_unpack_bat(om_bat *bat,
|
||||
|
||||
|
||||
/* rebuild the given bat table */
|
||||
STATIC_INLINE_VM void
|
||||
void STATIC_INLINE_VM
|
||||
om_unpack_bats(om_bats *bats,
|
||||
spreg *raw_bats,
|
||||
msreg msr)
|
||||
@ -682,7 +815,7 @@ om_unpack_bats(om_bats *bats,
|
||||
|
||||
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 32)
|
||||
STATIC_INLINE_VM void
|
||||
void STATIC_INLINE_VM
|
||||
om_unpack_sr(vm *virtual,
|
||||
sreg *srs,
|
||||
int which_sr)
|
||||
@ -709,13 +842,15 @@ om_unpack_sr(vm *virtual,
|
||||
segment_tlb_entry->invalid_access = (MASKED32(new_sr_value, 3, 3)
|
||||
? om_instruction_read
|
||||
: om_access_any);
|
||||
segment_tlb_entry->masked_virtual_segment_id = MASKED32(new_sr_value, 8, 31);
|
||||
segment_tlb_entry->masked_virtual_segment_id =
|
||||
INSERTED32(EXTRACTED32(new_sr_value, 8, 31),
|
||||
7-5, 31-6); /* align ready for pte address */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 32)
|
||||
STATIC_INLINE_VM void
|
||||
void STATIC_INLINE_VM
|
||||
om_unpack_srs(vm *virtual,
|
||||
sreg *srs)
|
||||
{
|
||||
@ -729,7 +864,7 @@ om_unpack_srs(vm *virtual,
|
||||
|
||||
/* Rebuild all the data structures for the new context as specifed by
|
||||
the passed registers */
|
||||
INLINE_VM void
|
||||
void INLINE_VM
|
||||
vm_synchronize_context(vm *virtual,
|
||||
spreg *sprs,
|
||||
sreg *srs,
|
||||
@ -740,33 +875,32 @@ vm_synchronize_context(vm *virtual,
|
||||
int problem_state = (msr & msr_problem_state) != 0;
|
||||
int data_relocate = (msr & msr_data_relocate) != 0;
|
||||
int instruction_relocate = (msr & msr_instruction_relocate) != 0;
|
||||
int little_endian = (msr & msr_little_endian_mode) != 0;
|
||||
|
||||
unsigned_word page_table_hash_mask;
|
||||
unsigned_word real_address_of_page_table;
|
||||
|
||||
|
||||
|
||||
/* update current processor mode */
|
||||
virtual->instruction_map.translation.is_relocate = instruction_relocate;
|
||||
virtual->instruction_map.translation.is_problem_state = problem_state;
|
||||
virtual->data_map.translation.is_relocate = data_relocate;
|
||||
virtual->data_map.translation.is_problem_state = problem_state;
|
||||
|
||||
|
||||
/* update bat registers for the new context */
|
||||
om_unpack_bats(&virtual->ibats, &sprs[spr_ibat0u], msr);
|
||||
om_unpack_bats(&virtual->dbats, &sprs[spr_dbat0u], msr);
|
||||
|
||||
|
||||
/* unpack SDR1 - the storage description register 1 */
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 64)
|
||||
real_address_of_page_table = EXTRACTED64(sprs[spr_sdr1], 0, 45);
|
||||
page_table_hash_mask = MASK64(47-EXTRACTED64(sprs[spr_sdr1], 59, 63),
|
||||
57);
|
||||
real_address_of_page_table = MASKED64(sprs[spr_sdr1], 0, 45);
|
||||
page_table_hash_mask = MASK64(18+28-EXTRACTED64(sprs[spr_sdr1], 59, 63),
|
||||
63-7);
|
||||
#endif
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 32)
|
||||
real_address_of_page_table = EXTRACTED32(sprs[spr_sdr1], 0, 15);
|
||||
page_table_hash_mask = ((EXTRACTED32(sprs[spr_sdr1], 23, 31) << (10+6))
|
||||
| MASK32(16, 25));
|
||||
real_address_of_page_table = MASKED32(sprs[spr_sdr1], 0, 15);
|
||||
page_table_hash_mask = (INSERTED32(EXTRACTED32(sprs[spr_sdr1], 23, 31),
|
||||
7, 7+9-1)
|
||||
| MASK32(7+9, 31-6));
|
||||
#endif
|
||||
virtual->instruction_map.translation.real_address_of_page_table = real_address_of_page_table;
|
||||
virtual->instruction_map.translation.page_table_hash_mask = page_table_hash_mask;
|
||||
@ -774,28 +908,52 @@ vm_synchronize_context(vm *virtual,
|
||||
virtual->data_map.translation.page_table_hash_mask = page_table_hash_mask;
|
||||
|
||||
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 32)
|
||||
/* unpack the segment tlb registers */
|
||||
#if (WITH_TARGET_WORD_BITSIZE == 32)
|
||||
om_unpack_srs(virtual, srs);
|
||||
#endif
|
||||
|
||||
/* set up the XOR registers if the current endian mode conflicts
|
||||
with what is in the MSR */
|
||||
if (WITH_XOR_ENDIAN) {
|
||||
int i = 1;
|
||||
unsigned mask;
|
||||
if ((little_endian && CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
|
||||
|| (!little_endian && CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN))
|
||||
mask = 0;
|
||||
else
|
||||
mask = WITH_XOR_ENDIAN - 1;
|
||||
while (i - 1 < WITH_XOR_ENDIAN) {
|
||||
virtual->instruction_map.translation.xor[i-1] = mask;
|
||||
virtual->data_map.translation.xor[i-1] = mask;
|
||||
mask = (mask << 1) & (WITH_XOR_ENDIAN - 1);
|
||||
i = i * 2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* don't allow the processor to change endian modes */
|
||||
if ((little_endian && CURRENT_TARGET_BYTE_ORDER != LITTLE_ENDIAN)
|
||||
|| (!little_endian && CURRENT_TARGET_BYTE_ORDER != LITTLE_ENDIAN))
|
||||
error("vm_synchronize_context() - unsuported change of byte order\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INLINE_VM vm_data_map *
|
||||
vm_data_map INLINE_VM *
|
||||
vm_create_data_map(vm *memory)
|
||||
{
|
||||
return &memory->data_map;
|
||||
}
|
||||
|
||||
|
||||
INLINE_VM vm_instruction_map *
|
||||
vm_instruction_map INLINE_VM *
|
||||
vm_create_instruction_map(vm *memory)
|
||||
{
|
||||
return &memory->instruction_map;
|
||||
}
|
||||
|
||||
|
||||
STATIC_INLINE_VM unsigned_word
|
||||
unsigned_word STATIC_INLINE_VM
|
||||
vm_translate(om_map *map,
|
||||
unsigned_word ea,
|
||||
om_access_types access,
|
||||
@ -818,7 +976,7 @@ vm_translate(om_map *map,
|
||||
}
|
||||
|
||||
|
||||
INLINE_VM unsigned_word
|
||||
unsigned_word INLINE_VM
|
||||
vm_real_data_addr(vm_data_map *map,
|
||||
unsigned_word ea,
|
||||
int is_read,
|
||||
@ -834,7 +992,7 @@ vm_real_data_addr(vm_data_map *map,
|
||||
}
|
||||
|
||||
|
||||
INLINE_VM unsigned_word
|
||||
unsigned_word INLINE_VM
|
||||
vm_real_instruction_addr(vm_instruction_map *map,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
@ -847,18 +1005,20 @@ vm_real_instruction_addr(vm_instruction_map *map,
|
||||
1); /*abort*/
|
||||
}
|
||||
|
||||
INLINE_VM instruction_word
|
||||
instruction_word INLINE_VM
|
||||
vm_instruction_map_read(vm_instruction_map *map,
|
||||
cpu *processor,
|
||||
unsigned_word cia)
|
||||
{
|
||||
unsigned_word ra = vm_real_instruction_addr(map, processor, cia);
|
||||
ASSERT((cia & 0x3) == 0); /* always aligned */
|
||||
if (WITH_XOR_ENDIAN)
|
||||
ra ^= map->translation.xor[sizeof(instruction_word) - 1];
|
||||
return core_map_read_4(map->code, ra, processor, cia);
|
||||
}
|
||||
|
||||
|
||||
INLINE_VM int
|
||||
int INLINE_VM
|
||||
vm_data_map_read_buffer(vm_data_map *map,
|
||||
void *target,
|
||||
unsigned_word addr,
|
||||
@ -875,7 +1035,9 @@ vm_data_map_read_buffer(vm_data_map *map,
|
||||
0); /*dont-abort*/
|
||||
if (ra == MASK(0, 63))
|
||||
break;
|
||||
if (core_map_read_buffer(map->read, &byte, ea, sizeof(byte))
|
||||
if (WITH_XOR_ENDIAN)
|
||||
ra ^= map->translation.xor[0];
|
||||
if (core_map_read_buffer(map->read, &byte, ra, sizeof(byte))
|
||||
!= sizeof(byte))
|
||||
break;
|
||||
((unsigned_1*)target)[count] = T2H_1(byte);
|
||||
@ -884,7 +1046,7 @@ vm_data_map_read_buffer(vm_data_map *map,
|
||||
}
|
||||
|
||||
|
||||
INLINE_VM int
|
||||
int INLINE_VM
|
||||
vm_data_map_write_buffer(vm_data_map *map,
|
||||
const void *source,
|
||||
unsigned_word addr,
|
||||
@ -902,6 +1064,8 @@ vm_data_map_write_buffer(vm_data_map *map,
|
||||
0); /*dont-abort*/
|
||||
if (ra == MASK(0, 63))
|
||||
break;
|
||||
if (WITH_XOR_ENDIAN)
|
||||
ra ^= map->translation.xor[0];
|
||||
byte = T2H_1(((unsigned_1*)source)[count]);
|
||||
if (core_map_write_buffer((violate_read_only_section
|
||||
? map->read
|
||||
@ -915,25 +1079,25 @@ vm_data_map_write_buffer(vm_data_map *map,
|
||||
|
||||
/* define the read/write 1/2/4/8/word functions */
|
||||
|
||||
#undef N
|
||||
#define N 1
|
||||
#include "vm_n.h"
|
||||
|
||||
#undef N
|
||||
|
||||
#define N 2
|
||||
#include "vm_n.h"
|
||||
|
||||
#undef N
|
||||
|
||||
#define N 4
|
||||
#include "vm_n.h"
|
||||
|
||||
#undef N
|
||||
|
||||
#define N 8
|
||||
#include "vm_n.h"
|
||||
|
||||
#undef N
|
||||
|
||||
#define N word
|
||||
#include "vm_n.h"
|
||||
#undef N
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user