Latest changes from Andrew

This commit is contained in:
Michael Meissner 1996-06-05 16:02:54 +00:00
parent 911026aa8b
commit 8477437c17
6 changed files with 1708 additions and 1 deletions

View file

@ -73,7 +73,10 @@ filter_filename.h
hw_com.c
hw_cpu.c
hw_cpu.h
hw_disk.c
hw_eeprom.c
hw_htab.c
hw_init.c
hw_iobus.c
hw_memory.c
hw_nvram.c
@ -82,6 +85,9 @@ hw_pci_ide.c
hw_phb.c
hw_phb.h
hw_pic.c
hw_register.c
hw_trace.c
hw_vm.c
idecode_branch.h
idecode_expression.h
idecode_fields.h
@ -101,6 +107,7 @@ options.c
options.h
os_emul.c
os_emul.h
pk_disklabel.c
ppc-cache-rules
ppc-instructions
ppc-opcode-complex

View file

@ -1,9 +1,25 @@
Wed Jun 5 01:39:07 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* psim.c (psim_options): Correct type of dummy arguments being
passed to a device_ioctl call.
* hw_init.c (hw_data_init_data_callback): Adjust printf arguments.
(write_stack_arguments): Ditto.
* hw_trace.c: Instance callback entry no longer a table.
Wed Jun 5 01:39:07 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* emul_unix.c (do_unix_umask): Cast printf argument.
(convert_to_linux_termios): Use LINUX_VSWTC not LINUX_VSWCH
Mon Jun 3 15:02:04 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* device_table.c (update_for_binary_section): Abort if we find an
* hw_init.c (update_for_binary_section): Abort if we find an
.interp section, which indicates the need for shared libraries to
be loaded.
Mon Jun 3 15:02:04 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* emul_unix.c (do_unix_{time,gettimeofday,getrusage}): Add support
for time, gettimeofday, and getrusage system calls.
({solaris,linux}_descriptors): Add new system calls.
@ -14,6 +30,17 @@ Mon Jun 3 15:02:04 1996 Michael Meissner <meissner@tiktok.cygnus.com>
(AC_TYPE_{MODE,OFF,PID,SIZE,UID}_T): Define.
* config{.in,ure}: Regenerate.
Mon Jun 3 23:19:57 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* emul_netbsd.c (emul_netbsd_create): Use the more specific names
`ppc-elf' and `ppc-xcoff' for the stack-type.
* emul_unix.c (emul_unix_create): Ditto.
* emul_bugapi.c (emul_bugapi_create): Ditto.
* hw_init.c: Reconize the new names.
* emul_unix.c (do_unix_break): Adjust so that the updated ioctl
call is used (no system parameter).
Sun Jun 2 11:21:17 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* emul_unix.{h,c}: New files to provide Solaris and Linux system
@ -46,6 +73,154 @@ Sun Jun 2 11:21:17 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* psim.c (psim_usage): Add message about solaris, linux
emulations.
Thu May 30 00:00:10 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* hw_iobus.c: Tidy up notes so that they can be auto-extracted.
* README: Correct PSIM's title
Wed May 29 23:50:26 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* basics.h: New global type object_disposition, used to indicate
the status of objects when things are restarted.
Fri May 17 17:28:52 1996 Andrew Cagney <cagney@benjimen.highland.com.au>
* device_table.h: Change the interrupt descriptor structure so
that it includes an additional member - an upper bound on the
interrupts by that name.
* device.c (device_interrupt_decode): Allow a range of interrupt
ports (eg rst0 .. rst6) if the port descriptors bound is non zero.
* device.c (device_tree_print_device): Include a list of valid
interrupt ports when listing supported devices.
* device.h, device.c (device_child_interrupt_*): Delete. Not used.
* emul_generic.c (emul_add_tree_hardware): Modify the creation of
the interrupt net so that it uses int0 .. intN.
Tue May 14 23:03:53 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* device.h, device.c (device_ioctl): Drop the system argument.
Devices can not obtain this using the device_system() call.
* device_table.h: Adjust accordingly.
* hw_*.c: Adjust accordingly.
* emul_netbsd.c (do_break): Adjust call to vm device accordingly.
* psim.c (psim_options): Use a device_ioctl call to force the
hw_trace device to update the trace options.
* hw_trace.c: Replace the init function with an ioctl call. Adjust
doc accordingly.
* psim.c (psim_init): Re-order initialization so that the
os-emulation is initialized after the device tree. Without this,
os-emul's are not able to create instances or access properties
that contain an instance handle.
* device.h, device.c (device_add_*_property): Make these functions
internal to device.c. The user has access to the more generic
device_tree_add_parsed function. Differentiate between the initial
and current value for each property.
* (clean_device_properties): New function that deletes any
properties created after the start of a simulation and restores
the initial value of any others (ignoring ihandles).
* (init_device_properties): (Re)Initialize any properties that
contain ihandles. create
* (device_tree_init): Include calls to clean the device tree's
properties and then initialize them. Document this in the device.h
file.
Mon May 6 17:36:15 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* interrupts.c (decrementer_interrupt): Always pend a decrementer
interrupt even if it is not yet possible to deliver it.
Wed May 1 12:26:51 1996 Andrew Cagney <cagney@benjimen>
* mon.h, mon.c (mon_get_number_of_insns): Make this externally
visable adjusting the arguments so that the interface is correct.
(mon_print_info): Adjust calls.
* registers.h, registers.c (register_description): Add phony
cycle, insn and stall registers.
* psim.c (psim_read_register): Return nr of instructions for given
processor.
Tue Apr 30 22:09:09 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* hw_htab.c: New file. Extract contents from disk_table.c.
Contains a device that, during initialization will create a
PowerPC htab in memory.
* hw_register.c: New file. Extract contents from disk_table.c.
Contains a device that, during initialization, will parse its
property list and use that to initialize various processor
registers (not target specific).
* hw_vm.c: New file. Extract contents from disk_table.c. Contains
a device that handles accesses to invalid virtual memory addresses
(in user mode).
* hw_init.c: New file. Extract contents from disk_table.c. Misc
devices that can initialize memory from a file.
* hw_trace.c: New file. Extract contents from disk_table.c.
Configure trace options from property values.
* Makefile.in (hw_htab.o, hw_register.o, hw_vm.o, hw_init.o,
hw_trace.c): Add new device files.
* device_table.c: Remove above code, now in separate independant
files.
Fri Apr 26 00:00:07 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* hw_disk.c: New file. Disk and CDROM device.
* Makefile.in (hw_disk.o): Add device hw_disk.c.
* pk_disklabel.c: New file. Implement the miss-named disk-label
package.
* Makefile.in (pk.h): Create the file pk.h that contains a list of all
the packages.
* Makefile.in (hw.h, hw.c): Add dependancy on Makefile so that
they are re-created when the makefile is updated.
* emul_generic.c (emul_add_tree_hardware): Add a disk device
(below the iobus) to the device tree. Include an ihandle of
the disk as /chosen/disk.
* emul_bugapi.c (emul_bugapi_create): Don't initialize the input,
output and (new) disk handles yet.
* (emul_bugapi_init): Initialize the input, output (and just added)
disk ihandles here.
* (emul_bugapi_do_diskio): New. Performs disk i/o (well at least
what I think the behavour is).
* emul_bugapi.c (emul_bugapi_instruction_call): Add hook to disk
i/o bug call. For RETURN call, exit using gpr[3]'s status even
though this isn't part of the spec - makes it possible for machine
code to signal the aporting of a simulation run.
* emul_chirp.c (chirp_emul_call_method): Add support for the
claim/release methods.
* (chirp_emul_exit): Add an optional exit status argument to
the exit method. Makes it possible for chirp emul simulations
to abort upon an error.
* device.h, device.c (device_instance_claim,
device_instance_release): New methods for claiming and releasing
memory.
* hw_memory.c: add claim and release memory methods.
* hw_*: Use the claim memory method when allocating physical
memory.
Thu Apr 18 23:38:10 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* hw_nvram.c (hw_nvram_update_clock): Use the current not previous
time when updating the clock.
* hw_nvram.c: Tidy up documentation
Fri May 24 10:08:10 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* configure.in (AC_STRUCT_ST_{BLKSIZE,BLOCKS,RDEV}): Use these
@ -162,6 +337,42 @@ Sun Apr 14 21:32:41 1996 Andrew Cagney <cagney@highland.com.au>
* device_table.c (stack_ioctl_callback): Return 0 status.
(vm_ioctl_callback): Ditto
Sat Apr 13 00:00:24 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* emul_netbsd.c (do_read): Correctly set the return value.
(do_getpid): Ditto.
(do_getuid): Ditto.
(do_geteuid): Ditto.
(do_dup): Ditto.
(do_getegid): Ditto.
(do_getgid): Ditto.
(do_sigprocmask): Ditto.
(do_umask): Ditto.
(do_dup2): Ditto.
(do_gettimeofday): Ditto.
(do_getrusage): Ditto.
(do_fstat): Ditto.
(do_stat): Ditto.
(do_lseek): Ditto.
(do___sysctl): Ditto.
Fri Apr 12 20:56:47 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* device_table.c (vm_ioctl_callback): Don't access the processor
registers directly, instead leave it to the caller to handle this.
* emul_netbsd.c (do_break): Which calls vm_ioctl_callback to
perform a break. Pass in the new break value and set the
registers according to the result.
* emul_generic.c (emul_write_status): Change so that r3 contains
either status or errno and failure is indicated by SO.
Thu Apr 4 23:03:38 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* emul_bugapi.c (emul_bugapi_create): More strict check of OEA
address.
Thu Apr 4 20:58:05 1996 Andrew Cagney <cagney@highland.com.au>
* interrupts.h (interrupts): New structure contains state of
@ -199,6 +410,25 @@ Fri Mar 29 20:17:17 1996 Andrew Cagney <cagney@highland.com.au>
* Makefile.in (hw_iobus.o): New dependency.
Fri Mar 29 12:17:58 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* emul_bugapi.c (_os_emul_data): Add fields for output, input.
(emul_bugapi_create): Create input, output from /chosen/stdin and
/chosen/stdout.
(emul_bugapi_do_{read,write}): Switch to use device_instance
interface.
(emul_bugapi_instruction_call): Change calls to
emul_bugapi_do_{read,write} to pass device instance argument.
Tue Mar 26 14:57:58 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* igen.c (idecode_switch_end): Fix 2/26 change so that an extra
default is not written out if a default was already written.
* psim.c (psim_{read,write}_register): Use sizeof unsigned_8 to
size cooked_buf, not sizeof natural_word, since floating point
registers are 8 bytes.
Mon Mar 25 22:07:13 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* configure: Regenerate with autoconf 2.9.
@ -207,6 +437,11 @@ Thu Mar 21 00:14:26 1996 Andrew Cagney <cagney@highland.com.au>
* device_table.h: Always include string headers.
Thu Mar 21 00:06:09 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* main.c (error): Be careful to not try to print out statistics
when the simulation was never created.
Sun Mar 17 22:40:57 1996 Andrew Cagney <cagney@highland.com.au>
* basics.h: Move the event queue's definition to here so that it
@ -322,6 +557,11 @@ Sun Mar 3 03:10:22 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* device.c (device_tree_print_device, device_tree_add_parsed):
Remove references to phandle properties.
Wed Feb 28 00:43:07 1996 Andrew Cagney - aka Noid <cagney@highland.com.au>
* Makefile.in (corefile.o): missing dependency on device_table.h
etc.
Tue Feb 27 23:59:35 1996 Andrew Cagney - aka Noid <cagney@highland.com.au>
* device_table.h: Revamp device init callbacks so that they are a
@ -339,6 +579,13 @@ Tue Feb 27 23:59:35 1996 Andrew Cagney - aka Noid <cagney@highland.com.au>
* (address nee config_address): ditto.
* (interrupt): ditto.
Mon Feb 26 21:11:20 1996 Andrew Cagney - aka Noid <cagney@highland.com.au>
* igen.c (idecode_switch_end): Output a default entry when the
switch statement is perfect. Firstly stops GCC complaining about
an incomplete switch and secondly it will be eliminated by a good
compiler any way.
Mon Feb 26 22:47:15 1996 Andrew Cagney - aka Noid <cagney@highland.com.au>
* Makefile.in (hw.h, hw.c): New targets. Create from the list of
@ -362,3 +609,238 @@ Mon Feb 26 22:24:00 1996 Andrew Cagney - aka Noid <cagney@highland.com.au>
* device_table.c: Delete the memory device (moved to hw_memory.c).
* hw_memory.c: New file. Just an OpenBoot memory device.
Wed Jan 17 21:47:34 1996 Andrew Cagney <cagney@highland.com.au>
* device.c (device_init_address): New. Split initialization into
two stages, address and address spaces
* device.c (device_init_data): New. ... and data or other work.
With out this, devices try to modify memory before it as been
attached.
* device.c (device_tree_init): Update to perform staged
initialization.
* device.c (device_init): Delete.
Wed Jan 17 21:43:09 1996 Andrew Cagney <cagney@highland.com.au>
* device_table.c (data_*): Rewrite to make heaver use of property
nodes. Allow initialization by different data types.
* device_table.c (htab_* pte_*): Rewrite to use properties.
* emul_chirp.c (emul_chirp_create): Use
* emul_bugapi.c (emul_bugapi_create): Ditto
* emul_netbsd.c (emul_netbsd_create): Ditto
Wed Jan 17 21:24:50 1996 Andrew Cagney <cagney@highland.com.au>
* emul_generic.c (emul_add_tree_options): Annotate existing tree
with options that haven't yet been specified.
* emul_generic.c (emul_add_tree_hardware): Annotate existing tree
with demo devices and properties.
* emul_chirp.c (emul_chirp_create): Update to use new
device_tree_add_parsed call and additional information now
included in the device tree. Use emul_add_tree* functions to add
any missing details.
* emul_bugapi.c (emul_bugapi_create): Ditto
* emul_netbsd.c (emul_netbsd_create): Ditto
Wed Jan 17 21:18:27 1996 Andrew Cagney <cagney@highland.com.au>
* device.c (device_instance_create): New. Create/delete and
operate on instances of a device.
* device.c (device_instance_delete): Ditto
* device.c (device_instance_read): Ditto
* device.c (device_instance_write): Ditto
* device.c (device_instance_seek): Ditto
* device.c (device_instance_data): Ditto
* device.c (device_instance_name): Ditto
* device.c (device_instance_path): Ditto
* emul_chirp.c (chirp_emul_open): Implement using device_instance.
* emul_chirp.c (chirp_emul_close): Ditto
* emul_chirp.c (chirp_emul_read): Ditto
* emul_chirp.c (chirp_emul_write): Ditto
* emul_chirp.c (chirp_emul_seek): Ditto
* emul_chirp.c (chirp_read_t2h_args): Read arguments from device.
Being careful to convert all from target to host byte order.
* emul_chirp.c (chirp_write_h2t_args): Converse.
Wed Jan 17 20:07:15 1996 Andrew Cagney <cagney@highland.com.au>
* device.c (device_tree_add_parsed): New. Rewrite code to add
devices to the device tree so that a single printf style function
is used.
* device.c (device_tree_add_*): Delete. Replaced by above.
* device.c (split_device_specifier): Functions to manipulate a
device specifier (path) breaking it into its components
* device.c (split_property_specifier): Ditto
* device.c (split_device_name): Ditto
* device.c (split_find_device): Ditto
* device.c (scan_*): Delete
* device.c (device_tree_find_device): Rewrite to use above.
* device.c (device_add_property): Ditto
Wed Jan 17 19:51:56 1996 Andrew Cagney <cagney@highland.com.au>
* psim.c(psim_options): Parse the psim options, installing their
value in the device tree. Options are now first entered into a
device tree and then extracted out again when needed. This allows
greater flexability in configuration.
* psim.c (psim_tree): Returns a basic device tree ready for
parsing by psim_options.
* psim.c (psim_usage): New. Give usage to varing levels of detail
according to the verbosity. In turn output device and trace
usage.
* main.c (main): Update to use new system
* sim_calls.c (sim_open, sim_do_command): Ditto
* psim.c (psim_options): Add `r' option - ram size.
* psim.c (psim_options): Add `o' option - openboot tree entry.
* psim.c (psim_options): Add `h'/`H' options - more help.
* debug.c (trace_usage): Add more detailed help.
* device.c (device_usage): New. Output help including a list of
the devices currently available in the device table.
* device_table.c: Add usage operator to each device.
* corefile.c (core_create, core_device_create): Adjust so that the
core device is created earlier for psim_tree(). Core can later be
created from it.
* psim.c (psim_create): Update to handle above way of creating
things. Extract all information from the device tree.
* device_tree.c (trace_*): New device node, its properties are
used to set the value of the trace options. Init this device (in
psim_options) when ever the options are updated.
Wed Jan 17 19:46:07 1996 Andrew Cagney <cagney@highland.com.au>
* debug.h: Add trace_print_info, trace_print_device_tree and
trace_dump_device_tree. The first is a replacement for the
variable `print_info' found in main.c and sim_calls.c. The latter
two enable the dumping of the entire device tree.
* debug.c: Add to trace_description table.
* main.c (main): Use above trace instead of local variable
* sim_calls.c (sim_close): Ditto
* device.c (device_tree_print_device): New. Prints the device
tree in a format that is consistent with what can be parsed by the
device tree load from file code.
* psim.c (psim_create): Dump device tree if enabled. If nump
selected, exit psim immediatly.
Wed Jan 17 19:36:52 1996 Andrew Cagney <cagney@highland.com.au>
* corefile-n.h (core_map_read_N): When mapping from an address to
a device, do not subtract the devices base. The device its self
can do this. Brings the behavour into line with OpenBoot.
* corefile-n.h (core_map_write_N): Ditto
* corefile.c (core_map_read_buffer): Ditto
* corefile.c (core_map_write_buffer): Ditto
* device_table.c (console_io_read_buffer_callback): Adjust to
handle biased address.
* device_table.c (console_io_write_buffer_callback): Ditto
Wed Jan 17 18:36:09 1996 Andrew Cagney <cagney@highland.com.au>
* device.c (attach_device_interrupt_edge): New. Interrupt model
did not allow interrupts to be wired up as a general net (edges).
Re-implement so that interrupt events can be passed to multiple
controllers and interrupt controllers can further propogate
interrupt events.
* device.c (attach_device_interrupt_edge) : New, Ditto
* device.c (detach_device_interrupt_edge) : New, Ditto
* device.c (clean_device_interrupt_edges) : New, Ditto
* device.c (device_interrupt_event) : New, Ditto
* device.c (device_interrupt_attach) : New, Ditto
* device.c (device_interrupt_detach) : New, Ditto
* device.c (device_child_interrupt_attach) : New, Ditto
* device.c (device_child_interrupt_detach) : New, Ditto
* device.c (device_attach_interrupt) : Delete old
* device.c (device_detach_interrupt) : Delete old
* device.c (device_interrupt) : Delete old
* device.c (device_interrupt_ack) : Delete old
* device_table.c (unimp_*) : Update to match
* device_table.c (icu_io_write_buffer_callback) : Update to use
interface.
* device_table.c (icu_interrupt_event_callback) : Ditto
Wed Jan 17 18:18:40 1996 Andrew Cagney <cagney@highland.com.au>
* device.c (external_to_device) : New function that provides a
standard mapping between a devices internal representation (a
pointer) and its external (or what is passed to a client)
representation (a phandle). Implement using the cap object
attached to the root node.
* device.c (device_to_external) : Ditto
* device.c (external_to_device_instance) : Ditto but for ihandle
and device instance.
* device.c (device_instance_to_external) : Ditto
* Makefile (device.o): Add dependency on cap.
* emul_chirp.c (struct _emul_chirp_data) : Elimate use of cap. Code
needing to translate between internal and external representations
changed to use the external_to_device et.al. device operations.
* emul_chirp.c (chirp_emul_*) : Ditto
* Makefile (emul_chirp.o): Remove dependency on cap
Sat Jan 6 10:13:26 1996 Andrew Cagney - aka Noid <cagney@highland.com.au>
* emul_chirp.c (map_over_chirp_note): Tighten up (and fix) checks
on OpenBoot note section.
Fri Jan 5 20:28:53 1996 Andrew Cagney <cagney@hignland.com.au>
* emul_generic.c (emul_write_buffer): Use vm faulting byte
read/write calls for buffer transfers. This will cause a fault to
occure if the transfer fails. CHRP catches the fault while the
others suffer the consequences.
(emul_read_buffer): Ditto.
(emul_write_word): Ditto.
(emul_read_word): Ditto.
(emul_read_string): Ditto.
Fri Jan 5 18:55:34 1996 Andrew Cagney <cagney@highland.com.au>
* emul_chirp.c (emul_chirp_create, emul_chirp_instruction_call),
emul_generic (emul_blr_instruction): Use a real blr instruction to
return from a client service call.
* emul_chirp.c (services): Add all OpenBoot services to table.
* emul_generic.h, emul_bugapi.c (emul_bugapi_create), emul_chirp.c
(emul_chirp_create) : Use names instead of numbers for
instructions being stored in memory.
Fri Jan 5 18:52:28 1996 Andrew Cagney <cagney@highland.com.au>
* Makefile.in (maintainer-clean): Remove .log, core and *.core
(From NetBSD) files.
Wed May 29 22:57:40 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* ChangeLog.00, ChangeLog: ChangeLog from gdb-4.16 becomes
ChangeLog.00

255
sim/ppc/hw_disk.c Normal file
View file

@ -0,0 +1,255 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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 _HW_DISK_C_
#define _HW_DISK_C_
#include "device_table.h"
#include "pk.h"
#include <stdio.h>
/* DEVICE
cdrom - readable block device
disk - readable block device that should be writeable
floppy - readable block device that should be writeable
DESCRIPTION
Block I/O devices that model the behavour of a fixed or removable
disk device.
Creating an instance of this device with no arguments will provide
access to primative read/write operators. If arguments are
specified then the disk-label package is used to perform abstract
disk I/O. The disk-label package will then use this devices
primatives.
For hardware I/O, this device would normally be attached to a
parent `bus' and that bus would use the I/O methods to read and
write raw data. The bus might actually be a SCSI or IDE device.
It is assumed that the parent bus can take care of DMA.
PROPERTIES
reg = <address> (required)
<address> is parent bus dependant.
device_type = "block"
name = "disk" | "cdrom" | "fd"
file = <file-name> (required)
The name of the file that contains the disk image.
*/
typedef struct _hw_disk_device {
const char *name;
int read_only;
unsigned_word size;
FILE *image;
} hw_disk_device;
typedef struct _hw_disk_instance {
long pos;
hw_disk_device *disk;
} hw_disk_instance;
static void
hw_disk_init_address(device *me)
{
hw_disk_device *disk = device_data(me);
generic_device_init_address(me);
if (disk->image != NULL)
fclose(disk->image);
disk->name = device_find_string_property(me, "file");
if (strcmp(device_name(me), "disk") == 0) {
disk->read_only = 0;
disk->image = fopen(disk->name, "r+");
}
else {
disk->read_only = 1;
disk->image = fopen(disk->name, "r");
}
if (disk->image == NULL) {
perror(device_name(me));
device_error(me, "open %s failed\n", disk->name);
}
}
static unsigned
hw_disk_io_read_buffer(device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia)
{
hw_disk_device *disk = device_data(me);
if (nr_bytes == 0)
return 0;
if (addr + nr_bytes > disk->size)
return 0;
if (fseek(disk->image, addr, SEEK_SET) < 0)
return 0;
if (fread(dest, nr_bytes, 1, disk->image) != 1)
return 0;
return nr_bytes;
}
static unsigned
hw_disk_io_write_buffer(device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia)
{
hw_disk_device *disk = device_data(me);
if (disk->read_only)
return 0;
if (nr_bytes == 0)
return 0;
if (addr + nr_bytes > disk->size)
return 0;
if (fseek(disk->image, addr, SEEK_SET) < 0)
return 0;
if (fwrite(source, nr_bytes, 1, disk->image) != 1)
return 0;
return nr_bytes;
}
/* instances of the hw_disk device */
static void
hw_disk_instance_delete(device_instance *instance)
{
hw_disk_instance *data = device_instance_data(instance);
zfree(data);
}
static int
hw_disk_instance_read(device_instance *instance,
void *buf,
unsigned_word len)
{
hw_disk_instance *data = device_instance_data(instance);
if (fseek(data->disk->image, data->pos, SEEK_SET) < 0)
return -1;
if (fread(buf, len, 1, data->disk->image) != 1)
return -1;
data->pos = ftell(data->disk->image);
return len;
}
static int
hw_disk_instance_write(device_instance *instance,
const void *buf,
unsigned_word len)
{
hw_disk_instance *data = device_instance_data(instance);
if (data->disk->read_only)
return -1;
if (fseek(data->disk->image, data->pos, SEEK_SET) < 0)
return -1;
if (fwrite(buf, len, 1, data->disk->image) != 1)
return -1;
data->pos = ftell(data->disk->image);
return len;
}
static int
hw_disk_instance_seek(device_instance *instance,
unsigned_word pos_hi,
unsigned_word pos_lo)
{
hw_disk_instance *data = device_instance_data(instance);
data->pos = pos_lo;
return 0;
}
static const device_instance_callbacks hw_disk_instance_callbacks = {
hw_disk_instance_delete,
hw_disk_instance_read,
hw_disk_instance_write,
hw_disk_instance_seek,
};
static device_instance *
hw_disk_create_instance(device *me,
const char *path,
const char *args)
{
device_instance *disk_instance;
hw_disk_device *disk = device_data(me);
hw_disk_instance *data = ZALLOC(hw_disk_instance);
data->disk = disk;
data->pos = 0;
disk_instance = device_create_instance_from(me, NULL,
data,
path, args,
&hw_disk_instance_callbacks);
return pk_disklabel_create_instance(disk_instance, args);
}
static device_callbacks const hw_disk_callbacks = {
{ hw_disk_init_address, NULL },
{ NULL, }, /* address */
{ hw_disk_io_read_buffer,
hw_disk_io_write_buffer, },
{ NULL, }, /* DMA */
{ NULL, }, /* interrupt */
{ NULL, }, /* unit */
hw_disk_create_instance,
};
static void *
hw_disk_create(const char *name,
const device_unit *unit_address,
const char *args,
device *parent)
{
/* create the descriptor */
hw_disk_device *hw_disk = ZALLOC(hw_disk_device);
return hw_disk;
}
const device_descriptor hw_disk_device_descriptor[] = {
{ "disk", hw_disk_create, &hw_disk_callbacks },
{ NULL },
};
#endif /* _HW_DISK_C_ */

569
sim/ppc/hw_init.c Normal file
View file

@ -0,0 +1,569 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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 _HW_INIT_C_
#define _HW_INIT_C_
#include "device_table.h"
#include "bfd.h"
#include "psim.h"
/* DMA a file into memory */
static int
dma_file(device *me,
const char *file_name,
unsigned_word addr)
{
int count;
int inc;
FILE *image;
char buf[1024];
/* get it open */
image = fopen(file_name, "r");
if (image == NULL)
return -1;
/* read it in slowly */
count = 0;
while (1) {
inc = fread(buf, 1, sizeof(buf), image);
if (feof(image) || ferror(image))
break;
if (device_dma_write_buffer(device_parent(me),
buf,
0 /*address-space*/,
addr+count,
inc /*nr-bytes*/,
1 /*violate ro*/) != inc) {
fclose(image);
return -1;
}
count += inc;
}
/* close down again */
fclose(image);
return count;
}
/* DEVICE
file - load a file into memory
DESCRIPTION
Loads the entire contents of <file-name> into memory at starting at
<real-address>. Assumes that memory exists for the load.
PROPERTIES
file-name = <string>
Name of the file to be loaded into memory
real-address = <integer>
Real address at which the file is to be loaded */
static void
hw_file_init_data_callback(device *me)
{
int count;
const char *file_name = device_find_string_property(me, "file-name");
unsigned_word addr = device_find_integer_property(me, "real-address");
/* load the file */
count = dma_file(me, file_name, addr);
if (count < 0)
device_error(me, "Problem loading file %s\n", file_name);
}
static device_callbacks const hw_file_callbacks = {
{ NULL, hw_file_init_data_callback, },
{ NULL, }, /* address */
{ NULL, }, /* IO */
{ NULL, }, /* DMA */
{ NULL, }, /* interrupt */
{ NULL, }, /* unit */
};
/* DEVICE
data - initialize a memory location
DESCRIPTION
A word sized quantity of data is written into memory, using the
targets byte ordering, at the specified memory location.
In the future this device will be extended so that it supports
initialization using other data types (eg array, ...)
PROPERTIES
data = <int>
Integer value to be loaded into memory
real-address = <integer>
Start address for the data. */
static void
hw_data_init_data_callback(device *me)
{
unsigned_word addr = device_find_integer_property(me, "real-address");
const device_property *data = device_find_property(me, "data");
if (data == NULL)
device_error(me, "missing property <data>\n");
switch (data->type) {
case integer_property:
{
unsigned32 buf = device_find_integer_property(me, "data");
H2T(buf);
if (device_dma_write_buffer(device_parent(me),
&buf,
0 /*address-space*/,
addr,
sizeof(buf), /*nr-bytes*/
1 /*violate ro*/) != sizeof(buf))
device_error(me, "Problem storing integer 0x%x at 0x%lx\n",
(unsigned)buf, (unsigned long)addr);
}
break;
default:
device_error(me, "Write of this data is not yet implemented\n");
break;
}
}
static device_callbacks const hw_data_callbacks = {
{ NULL, hw_data_init_data_callback, },
{ NULL, }, /* address */
{ NULL, }, /* IO */
{ NULL, }, /* DMA */
{ NULL, }, /* interrupt */
{ NULL, }, /* unit */
};
/* DEVICE
load-binary - load binary segments into memory
DESCRIPTION
Each loadable segment of the specified binary is loaded into memory
at its required address. It is assumed that the memory at those
addresses already exists.
This device is normally used to load an executable into memory as
part of real mode simulation.
PROPERTIES
file-name = <string>
Name of the binary to be loaded.
DEVICE
map-binary - map the binary into the users address space
DESCRIPTION
Similar to load-binary except that memory for each segment is
created before the corresponding data for the segment is loaded.
This device is normally used to load an executable into a user mode
simulation.
PROPERTIES
file-name = <string>
Name of the binary to be loaded.
*/
static void
update_for_binary_section(bfd *abfd,
asection *the_section,
PTR obj)
{
unsigned_word section_vma;
unsigned_word section_size;
access_type access;
device *me = (device*)obj;
/* skip the section if no memory to allocate */
if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
return;
/* check/ignore any sections of size zero */
section_size = bfd_get_section_size_before_reloc(the_section);
if (section_size == 0)
return;
/* find where it is to go */
section_vma = bfd_get_section_vma(abfd, the_section);
DTRACE(binary,
("name=%-7s, vma=0x%.8lx, size=%6ld, flags=%3lx(%s%s%s%s%s )\n",
bfd_get_section_name(abfd, the_section),
(long)section_vma,
(long)section_size,
(long)bfd_get_section_flags(abfd, the_section),
bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
));
/* If there is an .interp section, it means it needs a shared library interpreter. */
if (strcmp(".interp", bfd_get_section_name(abfd, the_section)) == 0)
error("Shared libraries are not yet supported.\n");
/* determine the devices access */
access = access_read;
if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
access |= access_exec;
if (!(bfd_get_section_flags(abfd, the_section) & SEC_READONLY))
access |= access_write;
/* if a map, pass up a request to create the memory in core */
if (strncmp(device_name(me), "map-binary", strlen("map-binary")) == 0)
device_attach_address(device_parent(me),
device_name(me),
attach_raw_memory,
0 /*address space*/,
section_vma,
section_size,
access,
me);
/* if a load dma in the required data */
if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
void *section_init = zalloc(section_size);
if (!bfd_get_section_contents(abfd,
the_section,
section_init, 0,
section_size)) {
bfd_perror("binary");
device_error(me, "load of data failed");
return;
}
if (device_dma_write_buffer(device_parent(me),
section_init,
0 /*space*/,
section_vma,
section_size,
1 /*violate_read_only*/)
!= section_size)
device_error(me, "broken transfer\n");
zfree(section_init); /* only free if load */
}
}
static void
hw_binary_init_data_callback(device *me)
{
/* get the file name */
const char *file_name = device_find_string_property(me, "file-name");
bfd *image;
/* open the file */
image = bfd_openr(file_name, NULL);
if (image == NULL) {
bfd_perror("binary");
device_error(me, "Failed to open file %s\n", file_name);
}
/* check it is valid */
if (!bfd_check_format(image, bfd_object)) {
bfd_close(image);
device_error(me, "The file %s has an invalid binary format\n", file_name);
}
/* and the data sections */
bfd_map_over_sections(image,
update_for_binary_section,
(PTR)me);
bfd_close(image);
}
static device_callbacks const hw_binary_callbacks = {
{ NULL, hw_binary_init_data_callback, },
{ NULL, }, /* address */
{ NULL, }, /* IO */
{ NULL, }, /* DMA */
{ NULL, }, /* interrupt */
{ NULL, }, /* unit */
};
/* DEVICE
stack - create an initial stack frame in memory
DESCRIPTION
Creates a stack frame of the specified type in memory.
Due to the startup sequence gdb uses when commencing a simulation,
it is not possible for the data to be placed on the stack to be
specified as part of the device tree. Instead the arguments to be
pushed onto the stack are specified using an IOCTL call.
The IOCTL takes the additional arguments:
| unsigned_word stack_end -- where the stack should come down from
| char **argv -- ...
| char **envp -- ...
PROPERTIES
stack-type = <string>
The form of the stack frame that is to be created.
*/
static int
sizeof_argument_strings(char **arg)
{
int sizeof_strings = 0;
/* robust */
if (arg == NULL)
return 0;
/* add up all the string sizes (padding as we go) */
for (; *arg != NULL; arg++) {
int len = strlen(*arg) + 1;
sizeof_strings += ALIGN_8(len);
}
return sizeof_strings;
}
static int
number_of_arguments(char **arg)
{
int nr;
if (arg == NULL)
return 0;
for (nr = 0; *arg != NULL; arg++, nr++);
return nr;
}
static int
sizeof_arguments(char **arg)
{
return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
}
static void
write_stack_arguments(device *me,
char **arg,
unsigned_word start_block,
unsigned_word end_block,
unsigned_word start_arg,
unsigned_word end_arg)
{
DTRACE(stack,
("write_stack_arguments(device=%s, arg=0x%lx, start_block=0x%lx, end_block=0x%lx, start_arg=0x%lx, end_arg=0x%lx)\n",
device_name(me), (long)arg, (long)start_block, (long)end_block, (long)start_arg, (long)end_arg));
if (arg == NULL)
device_error(me, "Attempt to write a null array onto the stack\n");
/* only copy in arguments, memory is already zero */
for (; *arg != NULL; arg++) {
int len = strlen(*arg)+1;
unsigned_word target_start_block;
DTRACE(stack,
("write_stack_arguments() write %s=%s at %s=0x%lx %s=0x%lx %s=0x%lx\n",
"**arg", *arg, "start_block", (long)start_block,
"len", (long)len, "start_arg", (long)start_arg));
if (psim_write_memory(device_system(me), 0, *arg,
start_block, len,
0/*violate_readonly*/) != len)
device_error(me, "Write of **arg (%s) at 0x%lx of stack failed\n",
*arg, (unsigned long)start_block);
target_start_block = H2T_word(start_block);
if (psim_write_memory(device_system(me), 0, &target_start_block,
start_arg, sizeof(target_start_block),
0) != sizeof(target_start_block))
device_error(me, "Write of *arg onto stack failed\n");
start_block += ALIGN_8(len);
start_arg += sizeof(start_block);
}
start_arg += sizeof(start_block); /*the null at the end*/
if (start_block != end_block
|| ALIGN_8(start_arg) != end_arg)
device_error(me, "Probable corrpution of stack arguments\n");
DTRACE(stack, ("write_stack_arguments() = void\n"));
}
static void
create_ppc_elf_stack_frame(device *me,
unsigned_word bottom_of_stack,
char **argv,
char **envp)
{
/* fixme - this is over aligned */
/* information block */
const unsigned sizeof_envp_block = sizeof_argument_strings(envp);
const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block;
const unsigned sizeof_argv_block = sizeof_argument_strings(argv);
const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block;
/* auxiliary vector - contains only one entry */
const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word); /* magic */
const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry);
/* environment points (including null sentinal) */
const unsigned sizeof_envp = sizeof_arguments(envp);
const unsigned_word start_envp = start_aux - sizeof_envp;
/* argument pointers (including null sentinal) */
const int argc = number_of_arguments(argv);
const unsigned sizeof_argv = sizeof_arguments(argv);
const unsigned_word start_argv = start_envp - sizeof_argv;
/* link register save address - alligned to a 16byte boundary */
const unsigned_word top_of_stack = ((start_argv
- 2 * sizeof(unsigned_word))
& ~0xf);
/* install arguments on stack */
write_stack_arguments(me, envp,
start_envp_block, bottom_of_stack,
start_envp, start_aux);
write_stack_arguments(me, argv,
start_argv_block, start_envp_block,
start_argv, start_envp);
/* set up the registers */
psim_write_register(device_system(me), -1,
&top_of_stack, "sp", cooked_transfer);
psim_write_register(device_system(me), -1,
&argc, "r3", cooked_transfer);
psim_write_register(device_system(me), -1,
&start_argv, "r4", cooked_transfer);
psim_write_register(device_system(me), -1,
&start_envp, "r5", cooked_transfer);
psim_write_register(device_system(me), -1,
&start_aux, "r6", cooked_transfer);
}
static void
create_ppc_aix_stack_frame(device *me,
unsigned_word bottom_of_stack,
char **argv,
char **envp)
{
unsigned_word core_envp;
unsigned_word core_argv;
unsigned_word core_argc;
unsigned_word core_aux;
unsigned_word top_of_stack;
/* cheat - create an elf stack frame */
create_ppc_elf_stack_frame(me, bottom_of_stack, argv, envp);
/* extract argument addresses from registers */
psim_read_register(device_system(me), 0,
&top_of_stack, "r1", cooked_transfer);
psim_read_register(device_system(me), 0,
&core_argc, "r3", cooked_transfer);
psim_read_register(device_system(me), 0,
&core_argv, "r4", cooked_transfer);
psim_read_register(device_system(me), 0,
&core_envp, "r5", cooked_transfer);
psim_read_register(device_system(me), 0,
&core_aux, "r6", cooked_transfer);
/* extract arguments from registers */
device_error(me, "Unfinished procedure create_ppc_aix_stack_frame\n");
}
static int
hw_stack_ioctl_callback(device *me,
cpu *processor,
unsigned_word cia,
va_list ap)
{
unsigned_word stack_pointer;
const char *stack_type;
char **argv;
char **envp;
stack_pointer = va_arg(ap, unsigned_word);
argv = va_arg(ap, char **);
envp = va_arg(ap, char **);
DTRACE(stack,
("stack_ioctl_callback(me=0x%lx:%s processor=0x%lx cia=0x%lx argv=0x%lx envp=0x%lx)\n",
(long)me, device_name(me), (long)processor, (long)cia, (long)argv, (long)envp));
stack_type = device_find_string_property(me, "stack-type");
if (strcmp(stack_type, "ppc-elf") == 0)
create_ppc_elf_stack_frame(me, stack_pointer, argv, envp);
else if (strcmp(stack_type, "ppc-xcoff") == 0)
create_ppc_aix_stack_frame(me, stack_pointer, argv, envp);
else if (strcmp(stack_type, "none") != 0)
device_error(me, "Unknown initial stack frame type %s\n", stack_type);
DTRACE(stack,
("stack_ioctl_callback() = void\n"));
return 0;
}
static device_callbacks const hw_stack_callbacks = {
{ NULL, },
{ NULL, }, /* address */
{ NULL, }, /* IO */
{ NULL, }, /* DMA */
{ NULL, }, /* interrupt */
{ NULL, }, /* unit */
NULL, /* instance */
hw_stack_ioctl_callback,
};
const device_descriptor hw_init_device_descriptor[] = {
{ "file", NULL, &hw_file_callbacks },
{ "data", NULL, &hw_data_callbacks },
{ "load-binary", NULL, &hw_binary_callbacks },
{ "map-binary", NULL, &hw_binary_callbacks },
{ "stack", NULL, &hw_stack_callbacks },
{ NULL },
};
#endif _HW_INIT_C_

125
sim/ppc/hw_register.c Normal file
View file

@ -0,0 +1,125 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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 _HW_REGISTER_C_
#define _HW_REGISTER_C_
#include "device_table.h"
#include <stdlib.h>
#include "psim.h"
/* DEVICE
register - dummy device to initialize processor registers
DESCRIPTION
The properties of this device are used, during initialization, to
specify the initial value of various processor registers. The
property name specifying the register to be initialized with the
special form <cpu-nr>.<register> being used to initialize a
specific processor's register (eg 0.pc).
Because, when the device tree is created, overriding properties are
entered into the tree before any default values, this device must
initialize registers in newest (default) to oldest (overriding)
property order.
The actual registers (for a given target) are defined in the file
registers.c.
This device is normally a child of the /openprom/init node.
EXAMPLE
Given a device tree containing the entry:
| /openprom/init/register/pc 0xfff00cf0
then specifying the command line option:
| -o '/openprom/init/register/pc 0x0'
would override the initial value of processor zero's program
counter. The resultant device tree tree containing:
| /openprom/init/register/0.pc 0x0
| /openprom/init/register/pc 0xfff00cf0
and would be processed last to first resulting in the sequence: set
all program counters to 0xfff00cf0; set processor zero's program
counter to zero. */
static void
do_register_init(device *me,
const device_property *prop)
{
psim *system = device_system(me);
if (prop != NULL) {
const char *name = prop->name;
unsigned32 value = device_find_integer_property(me, name);
int processor;
do_register_init(me, device_next_property(prop));
if (strchr(name, '.') == NULL) {
processor = -1;
DTRACE(register, ("%s=0x%lx\n", name, (unsigned long)value));
}
else {
char *end;
processor = strtoul(name, &end, 0);
ASSERT(end[0] == '.');
name = end+1;
DTRACE(register, ("%d.%s=0x%lx\n", processor, name,
(unsigned long)value));
}
psim_write_register(system, processor, /* all processors */
&value,
name,
cooked_transfer);
}
}
static void
register_init_data_callback(device *me)
{
const device_property *prop = device_find_property(me, NULL);
do_register_init(me, prop);
}
static device_callbacks const register_callbacks = {
{ NULL, register_init_data_callback, },
{ NULL, }, /* address */
{ NULL, }, /* IO */
{ NULL, }, /* DMA */
{ NULL, }, /* interrupt */
{ NULL, }, /* unit */
};
const device_descriptor hw_register_device_descriptor[] = {
{ "register", NULL, &register_callbacks },
{ NULL },
};
#endif _HW_REGISTER_C_

269
sim/ppc/hw_vm.c Normal file
View file

@ -0,0 +1,269 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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 _HW_VM_C_
#define _HW_VM_C_
#include "device_table.h"
#include "cpu.h"
#include <signal.h>
/* DEVICE
vm - virtual memory device for user simulation modes
DESCRIPTION
In user mode, mapped text, data and stack addresses are managed by
the core. Unmapped addresses are passed onto this device (because
it establishes its self as the fallback device) for processing.
During initialization, children of this device will request the
mapping of the initial text and data segments. Those requests are
passed onto the core device so that that may establish the initial
memory regions.
Once the simulation has started (as noted above) any access to an
unmapped address range will be passed down to this device as an IO
access. This device will then either attach additional memory to
the core device or signal the access as being invalid.
The IOCTL function is used to notify this device of any changes to
the users `brk' point.
PROPERTIES
stack-base = <number>
Specifies the lower address of the stack segment in the users
virtual address space. The initial stack page is defined by
stack-base + nr-bytes.
nr-bytes = <number>
Specifies the maximum size of the stack segment in the users
address space.
*/
typedef struct _hw_vm_device {
/* area of memory valid for stack addresses */
unsigned_word stack_base; /* min possible stack value */
unsigned_word stack_bound;
unsigned_word stack_lower_limit;
/* area of memory valid for heap addresses */
unsigned_word heap_base;
unsigned_word heap_bound;
unsigned_word heap_upper_limit;
} hw_vm_device;
static void
hw_vm_init_address_callback(device *me)
{
hw_vm_device *vm = (hw_vm_device*)device_data(me);
/* revert the stack/heap variables to their defaults */
vm->stack_base = device_find_integer_property(me, "stack-base");
vm->stack_bound = (vm->stack_base
+ device_find_integer_property(me, "nr-bytes"));
vm->stack_lower_limit = vm->stack_bound;
vm->heap_base = 0;
vm->heap_bound = 0;
vm->heap_upper_limit = 0;
/* establish this device as the default memory handler */
device_attach_address(device_parent(me),
device_name(me),
attach_callback + 1,
0 /*address space - ignore*/,
0 /*addr - ignore*/,
(((unsigned)0)-1) /*nr_bytes - ignore*/,
access_read_write /*access*/,
me);
}
static void
hw_vm_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*/
{
hw_vm_device *vm = (hw_vm_device*)device_data(me);
/* update end of bss if necessary */
if (vm->heap_base < addr + nr_bytes) {
vm->heap_base = addr + nr_bytes;
vm->heap_bound = addr + nr_bytes;
vm->heap_upper_limit = addr + nr_bytes;
}
device_attach_address(device_parent(me),
device_name(me),
attach_raw_memory,
0 /*address space*/,
addr,
nr_bytes,
access,
me);
}
static unsigned
hw_vm_add_space(device *me,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia)
{
hw_vm_device *vm = (hw_vm_device*)device_data(me);
unsigned_word block_addr;
unsigned block_nr_bytes;
/* an address in the stack area, allocate just down to the addressed
page */
if (addr >= vm->stack_base && addr < vm->stack_lower_limit) {
block_addr = FLOOR_PAGE(addr);
block_nr_bytes = vm->stack_lower_limit - block_addr;
vm->stack_lower_limit = block_addr;
}
/* an address in the heap area, allocate all of the required heap */
else if (addr >= vm->heap_upper_limit && addr < vm->heap_bound) {
block_addr = vm->heap_upper_limit;
block_nr_bytes = vm->heap_bound - vm->heap_upper_limit;
vm->heap_upper_limit = vm->heap_bound;
}
/* oops - an invalid address - abort the cpu */
else if (processor != NULL) {
cpu_halt(processor, cia, was_signalled, SIGSEGV);
return 0;
}
/* 2*oops - an invalid address and no processor */
else {
return 0;
}
/* got the parameters, allocate the space */
device_attach_address(device_parent(me),
"vm@0x0,0", /* stop remap */
attach_raw_memory,
0 /*address space*/,
block_addr,
block_nr_bytes,
access_read_write,
me);
return block_nr_bytes;
}
static unsigned
hw_vm_io_read_buffer_callback(device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia)
{
if (hw_vm_add_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
memset(dest, 0, nr_bytes); /* always initialized to zero */
return nr_bytes;
}
else
return 0;
}
static unsigned
hw_vm_io_write_buffer_callback(device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia)
{
if (hw_vm_add_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
return device_dma_write_buffer(device_parent(me), source,
space, addr,
nr_bytes,
0/*violate_read_only*/);
}
else
return 0;
}
static int
hw_vm_ioctl_callback(device *me,
cpu *processor,
unsigned_word cia,
va_list ap)
{
/* While the caller is notified that the heap has grown by the
requested amount, the heap is actually extended out to a page
boundary. */
hw_vm_device *vm = (hw_vm_device*)device_data(me);
unsigned_word requested_break = va_arg(ap, unsigned_word);
unsigned_word new_break = ALIGN_8(requested_break);
unsigned_word old_break = vm->heap_bound;
signed_word delta = new_break - old_break;
if (delta > 0)
vm->heap_bound = ALIGN_PAGE(new_break);
return 0;
}
static device_callbacks const hw_vm_callbacks = {
{ hw_vm_init_address_callback, },
{ hw_vm_attach_address,
passthrough_device_address_detach, },
{ hw_vm_io_read_buffer_callback,
hw_vm_io_write_buffer_callback, },
{ NULL, passthrough_device_dma_write_buffer, },
{ NULL, }, /* interrupt */
{ generic_device_unit_decode,
generic_device_unit_encode, },
NULL, /* instance */
hw_vm_ioctl_callback,
};
static void *
hw_vm_create(const char *name,
const device_unit *address,
const char *args,
device *parent)
{
hw_vm_device *vm = ZALLOC(hw_vm_device);
return vm;
}
const device_descriptor hw_vm_device_descriptor[] = {
{ "vm", hw_vm_create, &hw_vm_callbacks },
{ NULL },
};
#endif _HW_VM_C_