From 8477437c171d313390015b0aee80938f4dcc32c7 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Wed, 5 Jun 1996 16:02:54 +0000 Subject: [PATCH] Latest changes from Andrew --- sim/ppc/.Sanitize | 7 + sim/ppc/ChangeLog | 484 +++++++++++++++++++++++++++++++++++++++++- sim/ppc/hw_disk.c | 255 ++++++++++++++++++++++ sim/ppc/hw_init.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++++++ sim/ppc/hw_register.c | 125 +++++++++++ sim/ppc/hw_vm.c | 269 ++++++++++++++++++++++++ 6 files changed, 1708 insertions(+), 1 deletion(-) create mode 100644 sim/ppc/hw_disk.c create mode 100644 sim/ppc/hw_init.c create mode 100644 sim/ppc/hw_register.c create mode 100644 sim/ppc/hw_vm.c diff --git a/sim/ppc/.Sanitize b/sim/ppc/.Sanitize index 0e10881..47ca881 100644 --- a/sim/ppc/.Sanitize +++ b/sim/ppc/.Sanitize @@ -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 diff --git a/sim/ppc/ChangeLog b/sim/ppc/ChangeLog index c562fb3..a3738b1 100644 --- a/sim/ppc/ChangeLog +++ b/sim/ppc/ChangeLog @@ -1,9 +1,25 @@ +Wed Jun 5 01:39:07 1996 Andrew Cagney + + * 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 + + * 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 - * 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 + * 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 (AC_TYPE_{MODE,OFF,PID,SIZE,UID}_T): Define. * config{.in,ure}: Regenerate. +Mon Jun 3 23:19:57 1996 Andrew Cagney + + * 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 * 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 * psim.c (psim_usage): Add message about solaris, linux emulations. +Thu May 30 00:00:10 1996 Andrew Cagney + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 * configure.in (AC_STRUCT_ST_{BLKSIZE,BLOCKS,RDEV}): Use these @@ -162,6 +337,42 @@ Sun Apr 14 21:32:41 1996 Andrew Cagney * device_table.c (stack_ioctl_callback): Return 0 status. (vm_ioctl_callback): Ditto +Sat Apr 13 00:00:24 1996 Andrew Cagney + + * 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 + + * 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 + + * emul_bugapi.c (emul_bugapi_create): More strict check of OEA + address. + Thu Apr 4 20:58:05 1996 Andrew Cagney * interrupts.h (interrupts): New structure contains state of @@ -199,6 +410,25 @@ Fri Mar 29 20:17:17 1996 Andrew Cagney * Makefile.in (hw_iobus.o): New dependency. +Fri Mar 29 12:17:58 1996 Andrew Cagney + + * 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 + + * 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 * configure: Regenerate with autoconf 2.9. @@ -207,6 +437,11 @@ Thu Mar 21 00:14:26 1996 Andrew Cagney * device_table.h: Always include string headers. +Thu Mar 21 00:06:09 1996 Andrew Cagney + + * 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 * 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 * 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 + + * Makefile.in (corefile.o): missing dependency on device_table.h + etc. + Tue Feb 27 23:59:35 1996 Andrew Cagney - aka Noid * 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 * (address nee config_address): ditto. * (interrupt): ditto. +Mon Feb 26 21:11:20 1996 Andrew Cagney - aka Noid + + * 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 * 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 * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Makefile.in (maintainer-clean): Remove .log, core and *.core + (From NetBSD) files. + +Wed May 29 22:57:40 1996 Andrew Cagney + + * ChangeLog.00, ChangeLog: ChangeLog from gdb-4.16 becomes + ChangeLog.00 + diff --git a/sim/ppc/hw_disk.c b/sim/ppc/hw_disk.c new file mode 100644 index 0000000..eb4d236 --- /dev/null +++ b/sim/ppc/hw_disk.c @@ -0,0 +1,255 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + 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 + + +/* 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 =
(required) + +
is parent bus dependant. + + device_type = "block" + + name = "disk" | "cdrom" | "fd" + + file = (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_ */ diff --git a/sim/ppc/hw_init.c b/sim/ppc/hw_init.c new file mode 100644 index 0000000..6d51c7e --- /dev/null +++ b/sim/ppc/hw_init.c @@ -0,0 +1,569 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + 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 into memory at starting at + . Assumes that memory exists for the load. + + PROPERTIES + + file-name = + + Name of the file to be loaded into memory + + real-address = + + 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 = + + Integer value to be loaded into memory + + real-address = + + 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 \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 = + + 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 = + + 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 = + + 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_ diff --git a/sim/ppc/hw_register.c b/sim/ppc/hw_register.c new file mode 100644 index 0000000..4c812b1 --- /dev/null +++ b/sim/ppc/hw_register.c @@ -0,0 +1,125 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + 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 +#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 . 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, ®ister_callbacks }, + { NULL }, +}; + +#endif _HW_REGISTER_C_ diff --git a/sim/ppc/hw_vm.c b/sim/ppc/hw_vm.c new file mode 100644 index 0000000..df861d4 --- /dev/null +++ b/sim/ppc/hw_vm.c @@ -0,0 +1,269 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + 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 + +/* 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 = + + 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 = + + 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_ -- 2.7.4