123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- /* 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 3 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, see <http://www.gnu.org/licenses/>.
-
- */
- #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),
- 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,
- attach_type attach,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- device *client) /*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),
- 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),
- 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(device *me,
- cpu *processor,
- unsigned_word cia,
- device_ioctl_request request,
- 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);
- switch (request) {
- case device_ioctl_break:
- {
- 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);
- break;
- }
- default:
- device_error(me, "Unsupported ioctl request");
- 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,
- };
- static void *
- hw_vm_create(const char *name,
- const device_unit *address,
- const char *args)
- {
- 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_ */
|