/* This file is part of the program psim.
- Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+ 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
#ifndef _DEVICE_TABLE_C_
#define _DEVICE_TABLE_C_
-#ifndef STATIC_INLINE_DEVICE_TABLE
-#define STATIC_INLINE_DEVICE_TABLE STATIC_INLINE
-#endif
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <ctype.h>
-
#include "device_table.h"
-#include "events.h"
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_STDLIB_H
+#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
-
-#include "cpu.h"
+#include <ctype.h>
-#include "bfd.h"
/* Helper functions */
-/* Generic device init: Attaches the device of size <nr_bytes> (taken
- from <name>@<int>,<nr_bytes>) to its parent at address zero and
- with read/write access. */
-
-STATIC_INLINE_DEVICE_TABLE void
-generic_init_callback(device *me,
- psim *system)
-{
- unsigned_word addr;
- unsigned nr_bytes;
- if (scand_uw_u(device_name(me), &addr, &nr_bytes) != 2)
- error("generic_init_callback() invalid nr_bytes in %s\n", device_name(me));
- device_attach_address(device_parent(me),
- device_name(me),
- attach_callback,
- 0 /*space*/,
- addr,
- nr_bytes,
- access_read_write,
- me);
-}
-
-/* DMA a file into memory */
-STATIC_INLINE_DEVICE_TABLE int
-dma_file(device *me,
- const char *file_name,
- unsigned_word addr)
-{
- int count;
- int inc;
- FILE *image;
- char buf[1024];
+/* Go through the devices various reg properties for those that
+ specify attach addresses */
- /* 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;
+void
+generic_device_init_address(device *me)
+{
+ static const char *(reg_property_names[]) = {
+ "attach-addresses",
+ "assigned-addresses",
+ "reg",
+ "alternate-reg" ,
+ NULL
+ };
+ const char **reg_property_name;
+ int nr_valid_reg_properties = 0;
+ for (reg_property_name = reg_property_names;
+ *reg_property_name != NULL;
+ reg_property_name++) {
+ if (device_find_property(me, *reg_property_name) != NULL) {
+ reg_property_spec reg;
+ int reg_entry;
+ for (reg_entry = 0;
+ device_find_reg_array_property(me, *reg_property_name, reg_entry,
+ ®);
+ reg_entry++) {
+ unsigned_word attach_address;
+ int attach_space;
+ unsigned attach_size;
+ if (!device_address_to_attach_address(device_parent(me),
+ ®.address,
+ &attach_space, &attach_address,
+ me))
+ continue;
+ if (!device_size_to_attach_size(device_parent(me),
+ ®.size,
+ &attach_size, me))
+ continue;
+ device_attach_address(device_parent(me),
+ attach_callback,
+ attach_space, attach_address, attach_size,
+ access_read_write_exec,
+ me);
+ nr_valid_reg_properties++;
+ }
+ /* if first option matches don't try for any others */
+ if (reg_property_name == reg_property_names)
+ break;
}
- count += inc;
}
-
- /* close down again */
- fclose(image);
-
- return count;
-}
-
-
-\f
-/* inimplemented versions of each function */
-
-void
-unimp_device_init(device *me,
- psim *system)
-{
- error("device_init_callback for %s not implemented\n", device_name(me));
-}
-
-void
-unimp_device_attach_address(device *me,
- const char *name,
- attach_type type,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- device *who) /*callback/default*/
-{
- error("device_attach_address_callback for %s not implemented\n", device_name(me));
-}
-
-void
-unimp_device_detach_address(device *me,
- const char *name,
- attach_type type,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- device *who) /*callback/default*/
-{
- error("device_detach_address_callback for %s not implemented\n", device_name(me));
-}
-
-unsigned
-unimp_device_io_read_buffer(device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- error("device_io_read_buffer_callback for %s not implemented\n", device_name(me));
- return 0;
-}
-
-unsigned
-unimp_device_io_write_buffer(device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- error("device_io_write_buffer_callback for %s not implemented\n", device_name(me));
- return 0;
-}
-
-unsigned
-unimp_device_dma_read_buffer(device *me,
- void *target,
- int space,
- unsigned_word addr,
- unsigned nr_bytes)
-{
- error("device_dma_read_buffer_callback for %s not implemented\n", device_name(me));
- return 0;
-}
-
-unsigned
-unimp_device_dma_write_buffer(device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- int violate_read_only_section)
-{
- error("device_dma_write_buffer_callback for %s not implemented\n", device_name(me));
- return 0;
-}
-
-void
-unimp_device_attach_interrupt(device *me,
- device *who,
- int interrupt_line,
- const char *name)
-{
- error("device_attach_interrupt_callback for %s not implemented\n", device_name(me));
}
-void
-unimp_device_detach_interrupt(device *me,
- device *who,
- int interrupt_line,
- const char *name)
+int
+generic_device_unit_decode(device *bus,
+ const char *unit,
+ device_unit *phys)
{
- error("device_detach_interrupt_callback for %s not implemented\n", device_name(me));
-}
-
-void
-unimp_device_interrupt(device *me,
- device *who,
- int interrupt_line,
- int interrupt_status,
- cpu *processor,
- unsigned_word cia)
-{
- error("device_interrupt_callback for %s not implemented\n", device_name(me));
+ memset(phys, 0, sizeof(device_unit));
+ if (unit == NULL)
+ return 0;
+ else {
+ int nr_cells = 0;
+ const int max_nr_cells = device_nr_address_cells(bus);
+ while (1) {
+ char *end = NULL;
+ unsigned long val;
+ val = strtoul(unit, &end, 0);
+ /* parse error? */
+ if (unit == end)
+ return -1;
+ /* two many cells? */
+ if (nr_cells >= max_nr_cells)
+ return -1;
+ /* save it */
+ phys->cells[nr_cells] = val;
+ nr_cells++;
+ unit = end;
+ /* more to follow? */
+ if (isspace(*unit) || *unit == '\0')
+ break;
+ if (*unit != ',')
+ return -1;
+ unit++;
+ }
+ if (nr_cells < max_nr_cells) {
+ /* shift everything to correct position */
+ int i;
+ for (i = 1; i <= nr_cells; i++)
+ phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
+ for (i = 0; i < (max_nr_cells - nr_cells); i++)
+ phys->cells[i] = 0;
+ }
+ phys->nr_cells = max_nr_cells;
+ return max_nr_cells;
+ }
}
-void
-unimp_device_interrupt_ack(device *me,
- int interrupt_line,
- int interrupt_status)
+int
+generic_device_unit_encode(device *bus,
+ const device_unit *phys,
+ char *buf,
+ int sizeof_buf)
{
- error("device_interrupt_ack_callback for %s not implemented\n", device_name(me));
+ int i;
+ int len;
+ char *pos = buf;
+ /* skip leading zero's */
+ for (i = 0; i < phys->nr_cells; i++) {
+ if (phys->cells[i] != 0)
+ break;
+ }
+ /* don't output anything if empty */
+ if (phys->nr_cells == 0) {
+ strcpy(pos, "");
+ len = 0;
+ }
+ else if (i == phys->nr_cells) {
+ /* all zero */
+ strcpy(pos, "0");
+ len = 1;
+ }
+ else {
+ for (; i < phys->nr_cells; i++) {
+ if (pos != buf) {
+ strcat(pos, ",");
+ pos = strchr(pos, '\0');
+ }
+ if (phys->cells[i] < 10)
+ sprintf(pos, "%ld", (unsigned long)phys->cells[i]);
+ else
+ sprintf(pos, "0x%lx", (unsigned long)phys->cells[i]);
+ pos = strchr(pos, '\0');
+ }
+ len = pos - buf;
+ }
+ if (len >= sizeof_buf)
+ error("generic_unit_encode - buffer overflow\n");
+ return len;
+}
+
+int
+generic_device_address_to_attach_address(device *me,
+ const device_unit *address,
+ int *attach_space,
+ unsigned_word *attach_address,
+ device *client)
+{
+ int i;
+ for (i = 0; i < address->nr_cells - 2; i++) {
+ if (address->cells[i] != 0)
+ device_error(me, "Only 32bit addresses supported");
+ }
+ if (address->nr_cells >= 2)
+ *attach_space = address->cells[address->nr_cells - 2];
+ else
+ *attach_space = 0;
+ *attach_address = address->cells[address->nr_cells - 1];
+ return 1;
}
-void
-unimp_device_ioctl(device *me,
- psim *system,
- cpu *processor,
- unsigned_word cia,
- va_list ap)
+int
+generic_device_size_to_attach_size(device *me,
+ const device_unit *size,
+ unsigned *nr_bytes,
+ device *client)
{
- error("device_ioctl_callback for %s not implemented\n", device_name(me));
+ int i;
+ for (i = 0; i < size->nr_cells - 1; i++) {
+ if (size->cells[i] != 0)
+ device_error(me, "Only 32bit sizes supported");
+ }
+ *nr_bytes = size->cells[0];
+ return *nr_bytes;
}
-\f
/* ignore/passthrough versions of each function */
void
-ignore_device_init(device *me,
- psim *system)
-{
- /*null*/
-}
-
-void
-passthrough_device_attach_address(device *me,
- const char *name,
+passthrough_device_address_attach(device *me,
attach_type attach,
int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
- device *who) /*callback/default*/
+ device *client) /*callback/default*/
{
- device_attach_address(device_parent(me), name, attach,
+ device_attach_address(device_parent(me), attach,
space, addr, nr_bytes,
access,
- who);
+ client);
}
void
-passthrough_device_detach_address(device *me,
- const char *name,
+passthrough_device_address_detach(device *me,
attach_type attach,
int space,
unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- device *who) /*callback/default*/
+ unsigned nr_bytes,
+ access_type access,
+ device *client) /*callback/default*/
{
- device_detach_address(device_parent(me), name, attach,
+ device_detach_address(device_parent(me), attach,
space, addr, nr_bytes, access,
- who);
+ client);
}
unsigned
passthrough_device_dma_read_buffer(device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes)
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes)
{
return device_dma_read_buffer(device_parent(me), dest,
space, addr, nr_bytes);
violate_read_only_section);
}
-void
-passthrough_device_attach_interrupt(device *me,
- device *who,
- int interrupt_line,
- const char *name)
-{
- device_attach_interrupt(device_parent(me), who,
- interrupt_line, name);
-}
-
-void
-passthrough_device_detach_interrupt(device *me,
- device *who,
- int interrupt_line,
- const char *name)
-{
- device_detach_interrupt(device_parent(me), who,
- interrupt_line, name);
-}
-
-
-void
-passthrough_device_interrupt(device *me,
- device *who,
- int interrupt_line,
- int interrupt_status,
- cpu *processor,
- unsigned_word cia)
-{
- device_interrupt(device_parent(me), who,
- interrupt_line, interrupt_status,
- processor, cia);
-}
-
-
-static const device_callbacks passthrough_callbacks = {
- ignore_device_init,
- passthrough_device_attach_address,
- passthrough_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- passthrough_device_dma_read_buffer,
- passthrough_device_dma_write_buffer,
- passthrough_device_attach_interrupt,
- passthrough_device_detach_interrupt,
- passthrough_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* Simple console device: console@<address>,16
-
- Input characters are taken from the keyboard, output characters
- sent to the terminal. Echoing of characters is not disabled.
-
- The device has four registers:
-
- 0x0: read
- 0x4: read-status
- 0x8: write
- 0xC: write-status
-
- Where a nonzero status register indicates that the device is ready
- (input fifo contains a character or output fifo has space). */
-
-typedef struct _console_buffer {
- char buffer;
- int status;
- event_entry_tag event_tag;
-} console_buffer;
-
-typedef struct _console_device {
- console_buffer input;
- console_buffer output;
-} console_device;
-
-typedef enum {
- console_read_buffer = 0,
- console_read_status = 4,
- console_write_buffer = 8,
- console_write_status = 12,
- console_offset_mask = 0xc,
- console_size = 16,
-} console_offsets;
-
-
-static unsigned
-console_io_read_buffer_callback(device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- console_device *console = (console_device*)device_data(me);
- unsigned_1 val;
-
- /* determine what was read */
-
- switch ((int)addr) {
-
- case console_read_buffer:
- val = console->input.buffer;
- break;
-
- case console_read_status:
- { /* check for input */
- int flags;
- int status;
- /* get the old status */
- flags = fcntl(0, F_GETFL, 0);
- if (flags == -1) {
- perror("console");
- val = 0;
- break;
- }
- /* temp, disable blocking IO */
- status = fcntl(0, F_SETFL, flags | O_NDELAY);
- if (status == -1) {
- perror("console");
- val = 0;
- break;
- }
- /* try for input */
- status = read(0, &console->input.buffer, 1);
- if (status == 1) {
- console->input.status = 1;
- }
- else {
- console->input.status = 0;
- }
- /* return to regular vewing */
- fcntl(0, F_SETFL, flags);
- }
- val = console->input.status;
- break;
-
- case console_write_buffer:
- val = console->output.buffer;
- break;
-
- case console_write_status:
- val = console->output.status;
- break;
-
- default:
- error("console_read_callback() internal error\n");
- val = 0;
- break;
-
- }
-
- memset(dest, 0, nr_bytes);
- *(unsigned_1*)dest = val;
- return nr_bytes;
-}
-
-static unsigned
-console_io_write_buffer_callback(device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- console_device *console = (console_device*)device_data(me);
- unsigned_1 val = *(unsigned_1*)source;
-
- switch ((int)addr) {
- case console_read_buffer:
- console->input.buffer = val;
- break;
- case console_read_status:
- console->input.status = val;
- break;
- case console_write_buffer:
- DTRACE(console, ("<%c:%d>", val, val));
- printf_filtered("%c",val) ;
- console->output.buffer = val;
- console->output.status = 1;
- break;
- case console_write_status:
- console->output.status = val;
- break;
- default:
- error("console_write_callback() internal error\n");
- }
-
- return nr_bytes;
-}
-
-
-static device_callbacks const console_callbacks = {
- generic_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- console_io_read_buffer_callback,
- console_io_write_buffer_callback,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-static void *
-console_create(const char *name,
- device *parent)
-{
- /* create the descriptor */
- console_device *console = ZALLOC(console_device);
- console->output.status = 1;
- console->output.buffer = '\0';
- console->input.status = 0;
- console->input.buffer = '\0';
- return console;
-}
-
-
-\f
-/* ICU device: icu@0x<address>,4
-
- Single 4 byte register. Read returns processor number. Write
- interrupts specified processor.
-
- Illustrates passing of events to parent device. Passing of
- interrupts to parent bus.
-
- NB: For the sake of illustrating the passing of interrupts. This
- device doesn't pass interrupt events to its parent. Instead it
- passes them back to its self. */
-
-static unsigned
-icu_io_read_buffer_callback(device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- unsigned_1 val;
- val = cpu_nr(processor);
- memset(dest, 0, nr_bytes);
- *(unsigned_1*)dest = val;
- return nr_bytes;
-}
-
-
-static unsigned
-icu_io_write_buffer_callback(device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- unsigned_1 val = H2T_1(*(unsigned_1*)source);
- /* tell the parent device that the interrupt lines have changed.
- For this fake ICU. The interrupt lines just indicate the cpu to
- interrupt next */
- device_interrupt(device_parent(me), me,
- val, val,
- processor, cia);
- return nr_bytes;
-}
-
-
-static device_callbacks const icu_callbacks = {
- generic_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- icu_io_read_buffer_callback,
- icu_io_write_buffer_callback,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* HALT device: halt@0x<address>,4
-
- With real hardware, the processor operation is normally terminated
- through a reset. This device illustrates how a reset device could
- be attached to an address */
-
-
-static unsigned
-halt_io_read_buffer_callback(device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- cpu_halt(processor, cia, was_exited, 0);
- return 0;
-}
-
-
-static unsigned
-halt_io_write_buffer_callback(device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
+int
+ignore_device_unit_decode(device *me,
+ const char *unit,
+ device_unit *phys)
{
- cpu_halt(processor, cia, was_exited, *(unsigned_1*)source);
+ memset(phys, 0, sizeof(device_unit));
return 0;
}
-static device_callbacks const halt_callbacks = {
- generic_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- halt_io_read_buffer_callback,
- halt_io_write_buffer_callback,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* Register init device: register
-
- Properties attached to the register device specify the name/value
- initialization pair for cpu registers.
-
- FIXME: A specific processor can be initialized by creating a
- property with a name like `0.pc'. */
-
-static void
-register_init(device *me,
- const char *name,
- void *data)
-{
- psim *system = (psim*)data;
- unsigned32 value = device_find_integer_property(me, name);
- int processor;
- if (isdigit(name[0]) && name[1] == '.') {
- processor = atol(name);
- name += 2;
- DTRACE(register, ("%d.%s=0x%lx\n", processor, name, (unsigned long)value));
- }
- else {
- processor = -1;
- DTRACE(register, ("%s=0x%lx\n", name, (unsigned long)value));
- }
- psim_write_register(system, processor, /* all processors */
- &value,
- name,
- cooked_transfer);
-}
-
-
-static void
-register_init_callback(device *me,
- psim *system)
-{
- device_traverse_properties(me, register_init, system);
-}
-
-
-static device_callbacks const register_callbacks = {
- register_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* VEA VM device: vm@0x<stack-base>,<nr_bytes>
-
- A VEA mode device. This sets its self up as the default memory
- device capturing all accesses (reads/writes) to currently unmapped
- addresses. If the unmaped access falls within unallocated stack or
- heap address ranges then memory is allocated and the access is
- allowed to continue.
-
- During init phase, this device expects to receive `attach' requests
- from its children for the text/data/bss memory areas. Typically,
- this would be done by the binary device.
-
- STACK: The location of the stack in memory is specified as part of
- the devices name. Unmaped accesses that fall within the stack
- space result in the allocated stack being grown downwards so that
- it includes the page of the culprit access.
-
- HEAP: During initialization, the vm device monitors all `attach'
- operations from its children using this to determine the initial
- location of the heap. The heap is then extended by system calls
- that frob the heap upper bound variable (see system.c). */
-
-
-typedef struct _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;
-} vm_device;
-
-
-static void
-vm_init_callback(device *me,
- psim *system)
-{
- vm_device *vm = (vm_device*)device_data(me);
-
- /* revert the stack/heap variables to their defaults */
- 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_default,
- 0 /*address space - ignore*/,
- 0 /*addr - ignore*/,
- 0 /*nr_bytes - ignore*/,
- access_read_write /*access*/,
- me);
-}
-
-
-static void
-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*/
-{
- vm_device *vm = (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),
- "vm@0x0,0", /* stop remap */
- attach_raw_memory,
- 0 /*address space*/,
- addr,
- nr_bytes,
- access,
- me);
-}
-
-
-STATIC_INLINE_DEVICE_TABLE unsigned
-add_vm_space(device *me,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- vm_device *vm = (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
-vm_io_read_buffer_callback(device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- if (add_vm_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
-vm_io_write_buffer_callback(device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- if (add_vm_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 void
-vm_ioctl_callback(device *me,
- psim *system,
- 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 infact extended out to a page
- boundary. */
- vm_device *vm = (vm_device*)device_data(me);
- unsigned_word new_break = ALIGN_8(cpu_registers(processor)->gpr[3]);
- unsigned_word old_break = vm->heap_bound;
- signed_word delta = new_break - old_break;
- if (delta > 0)
- vm->heap_bound = ALIGN_PAGE(new_break);
- cpu_registers(processor)->gpr[0] = 0;
- cpu_registers(processor)->gpr[3] = new_break;
-}
-
-
-static device_callbacks const vm_callbacks = {
- vm_init_callback,
- vm_attach_address,
- passthrough_device_detach_address,
- vm_io_read_buffer_callback,
- vm_io_write_buffer_callback,
- unimp_device_dma_read_buffer,
- passthrough_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- vm_ioctl_callback,
-};
-
-
-static void *
-vea_vm_create(const char *name,
- device *parent)
-{
- vm_device *vm = ZALLOC(vm_device);
- unsigned_word addr;
- unsigned nr_bytes;
-
- /* extract out the stack parameters */
- if (scand_uw_u(name, &addr, &nr_bytes) != 2)
- error("vm_device_create() invalid vm device %s\n", name);
- vm->stack_base = addr;
- vm->stack_bound = addr + nr_bytes;
- return vm;
-}
-
-
-\f
-/* Memory init device: memory@0x<addr>,<size>,<access>
-
- This strange device is used create sections of memory */
-
-static void
-memory_init_callback(device *me,
- psim *system)
-{
- unsigned_word addr;
- unsigned nr_bytes;
- unsigned access;
- int nr_args;
-
- nr_args = scand_uw_u_u(device_name(me), &addr, &nr_bytes, &access);
- switch (nr_args) {
- case 2:
- access = access_read_write_exec;
- break;
- case 3:
- break;
- default:
- error("memory_init_callback() invalid memory device %s\n", device_name(me));
- break;
- }
-
- device_attach_address(device_parent(me),
- device_name(me),
- attach_raw_memory,
- 0 /*address space*/,
- addr,
- nr_bytes,
- (access_type)access,
- me);
-}
-
-
-static device_callbacks const memory_callbacks = {
- memory_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* IOBUS device: iobus@<address>
-
- Simple bus on which some IO devices live */
-
-static void
-iobus_attach_address_callback(device *me,
- const char *name,
- attach_type type,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- device *who) /*callback/default*/
-{
- unsigned_word iobus_addr;
- /* sanity check */
- if (type == attach_default)
- error("iobus_attach_address_callback() no default for %s/%s\n",
- device_name(me), name);
- if (space != 0)
- error("iobus_attach_address_callback() no space for %s/%s\n",
- device_name(me), name);
- /* get the bus address */
- if (scand_uw(device_name(me), &iobus_addr) != 1)
- error("iobus_attach_address_callback() invalid address for %s\n",
- device_name(me));
- device_attach_address(device_parent(me),
- device_name(me),
- type,
- 0 /*space*/,
- iobus_addr + addr,
- nr_bytes,
- access,
- who);
-}
-
-
-STATIC_INLINE_DEVICE_TABLE void
-iobus_do_interrupt(event_queue *queue,
- void *data)
-{
- cpu *target = (cpu*)data;
- /* try to interrupt the processor. If the attempt fails, try again
- on the next tick */
- if (!external_interrupt(target))
- event_queue_schedule(queue, 1, iobus_do_interrupt, target);
-}
-
-
-static void
-iobus_interrupt_callback(device *me,
- device *who,
- int interrupt_line,
- int interrupt_status,
- cpu *processor,
- unsigned_word cia)
-{
- /* the interrupt controler can't interrupt a cpu at any time.
- Rather it must synchronize with the system clock before
- performing an interrupt on the given processor */
- psim *system = cpu_system(processor);
- cpu *target = psim_cpu(system, interrupt_status);
- if (target != NULL) {
- event_queue *events = cpu_event_queue(target);
- event_queue_schedule(events, 1, iobus_do_interrupt, target);
- }
-}
-
-
-static device_callbacks const iobus_callbacks = {
- ignore_device_init,
- iobus_attach_address_callback,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- iobus_interrupt_callback,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* FILE device: file@0x<address>,<file-name>
- (later - file@0x<address>,<size>,<file-offset>,<file-name>)
-
- Specifies a file to read directly into memory starting at <address> */
-
-
-static void
-file_init_callback(device *me,
- psim *system)
-{
- unsigned_word addr;
- int count;
- char file_name[1024];
-
- if (scand_uw_c(device_name(me), &addr, file_name, sizeof(file_name)) != 2)
- error("devices/file - Usage: file@<address>,<file-name>\n");
-
- /* load the file */
- count = dma_file(me, file_name, addr);
- if (count < 0)
- error("device_table/%s - Problem loading file %s\n", device_name(me), file_name);
-}
-
-
-static device_callbacks const file_callbacks = {
- file_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* DATA device: data@<address>,<count>,<value>
-
- Store <value> at <address> using <count> size transfer */
-
-static void
-data_init_callback(device *me,
- psim *system)
-{
- unsigned_word addr;
- unsigned count;
- unsigned value;
- union {
- unsigned_1 v1;
- unsigned_2 v2;
- unsigned_4 v4;
- unsigned_8 v8;
- } buf;
-
- if (scand_uw_u_u(device_name(me), &addr, &count, &value) != 3)
- error("devices/data - Usage: data@<address>,<count>,<value>\n");
-
- /* store the data value */
- switch (count) {
- case 1:
- buf.v1 = H2T_1(value);
- break;
- case 2:
- buf.v2 = H2T_2(value);
- break;
- case 4:
- buf.v4 = H2T_4(value);
- break;
- case 8:
- buf.v8 = H2T_8(value);
- break;
- }
- if (device_dma_write_buffer(device_parent(me),
- &buf,
- 0 /*address-space*/,
- addr,
- count, /*nr-bytes*/
- 1 /*violate ro*/) != count) {
- error("devices/%s - Problem storing 0x%x at 0x%lx\n",
- device_name(me), value, (long)addr);
- }
-}
-
-
-static device_callbacks const data_callbacks = {
- data_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* HTAB: htab@<address>,<nr_bytes>
- PTE: pte@<real-address>,<virtual-address>,<nr_bytes>,<wimg>,<pp>
- PTE: pte@<real-address>,<wimg>,<pp>,<binary>
-
- HTAB defines the location (in physical memory) of a HASH table.
- PTE (as a child of HTAB) defines a mapping that is to be entered
- into that table.
-
- NB: All the work in this device is done during init by the PTE.
- The pte, looks up its parent to determine the address of the HTAB
- and then uses DMA calls to establish the required mapping. */
-
-
-STATIC_INLINE_DEVICE_TABLE void
-htab_decode_hash_table(device *parent,
- unsigned32 *htaborg,
- unsigned32 *htabmask)
-{
- unsigned_word htab_ra;
- unsigned htab_nr_bytes;
- unsigned n;
- /* determine the location/size of the hash table */
- if (parent == NULL
- || strncmp(device_name(parent), "htab@", strlen("htab@")) != 0)
- error("devices/htab - missing htab device\n");
- if (scand_uw_u(device_name(parent), &htab_ra, &htab_nr_bytes) != 2)
- error("devices/%s - Usage: htab@<real-addr>,<nr_bytes>\n",
- device_name(parent));
- for (n = htab_nr_bytes; n > 1; n = n / 2) {
- if (n % 2 != 0)
- error("devices/%s - htab size 0x%x not a power of two\n",
- device_name(parent), htab_nr_bytes);
- }
- *htaborg = htab_ra;
- *htabmask = MASKED32(htab_nr_bytes - 1, 7, 31-6);
- if ((htab_ra & INSERTED32(*htabmask, 7, 15)) != 0) {
- error("devices/%s - htaborg 0x%x not aligned to htabmask 0x%x\n",
- device_name(parent), *htaborg, *htabmask);
- }
- DTRACE(htab, ("htab - htaborg=0x%lx htabmask=0x%lx\n",
- (unsigned long)*htaborg, (unsigned long)*htabmask));
-}
-
-
-STATIC_INLINE void
-htab_map_page(device *me,
- unsigned_word ra,
- unsigned64 va,
- unsigned wimg,
- unsigned pp,
- unsigned32 htaborg,
- unsigned32 htabmask)
-{
- unsigned64 vpn = va << 12;
- unsigned32 vsid = INSERTED32(EXTRACTED64(vpn, 0, 23), 0, 23);
- unsigned32 page = INSERTED32(EXTRACTED64(vpn, 24, 39), 0, 15);
- unsigned32 hash = INSERTED32(EXTRACTED32(vsid, 5, 23)
- ^ EXTRACTED32(page, 0, 15),
- 7, 31-6);
- int h;
- for (h = 0; h < 2; h++) {
- unsigned32 pteg = (htaborg | (hash & htabmask));
- int pti;
- for (pti = 0; pti < 8; pti++, pteg += 8) {
- unsigned32 current_target_pte0;
- unsigned32 current_pte0;
- if (device_dma_read_buffer(device_parent(me),
- ¤t_target_pte0,
- 0, /*space*/
- pteg,
- sizeof(current_target_pte0)) != 4)
- error("htab_init_callback() failed to read a pte at 0x%x\n",
- pteg);
- current_pte0 = T2H_4(current_target_pte0);
- if (!MASKED32(current_pte0, 0, 0)) {
- /* empty pte fill it */
- unsigned32 pte0 = (MASK32(0, 0)
- | INSERTED32(EXTRACTED32(vsid, 0, 23), 1, 24)
- | INSERTED32(h, 25, 25)
- | INSERTED32(EXTRACTED32(page, 0, 5), 26, 31));
- unsigned32 target_pte0 = H2T_4(pte0);
- unsigned32 pte1 = (INSERTED32(EXTRACTED32(ra, 0, 19), 0, 19)
- | INSERTED32(wimg, 25, 28)
- | INSERTED32(pp, 30, 31));
- unsigned32 target_pte1 = H2T_4(pte1);
- if (device_dma_write_buffer(device_parent(me),
- &target_pte0,
- 0, /*space*/
- pteg,
- sizeof(target_pte0),
- 1/*ro?*/) != 4
- || device_dma_write_buffer(device_parent(me),
- &target_pte1,
- 0, /*space*/
- pteg + 4,
- sizeof(target_pte1),
- 1/*ro?*/) != 4)
- error("htab_init_callback() failed to write a pte a 0x%x\n",
- pteg);
- DTRACE(htab, ("map - va=0x%lx ra=0x%lx &pte0=0x%lx pte0=0x%lx pte1=0x%lx\n",
- (unsigned long)va, (unsigned long)ra,
- (unsigned long)pteg,
- (unsigned long)pte0, (unsigned long)pte1));
- return;
- }
- }
- /* re-hash */
- hash = MASKED32(~hash, 0, 18);
- }
-}
-
-STATIC_INLINE_DEVICE_TABLE void
-htab_map_region(device *me,
- unsigned_word pte_ra,
- unsigned_word pte_va,
- unsigned nr_bytes,
- unsigned wimg,
- unsigned pp,
- unsigned32 htaborg,
- unsigned32 htabmask)
-{
- unsigned_word ra;
- unsigned64 va;
- /* go through all pages and create a pte for each */
- for (ra = pte_ra, va = (signed_word)pte_va;
- ra < pte_ra + nr_bytes;
- ra += 0x1000, va += 0x1000) {
- htab_map_page(me, ra, va, wimg, pp, htaborg, htabmask);
- }
-}
-
-typedef struct _htab_binary_sizes {
- unsigned_word text_ra;
- unsigned_word text_base;
- unsigned_word text_bound;
- unsigned_word data_ra;
- unsigned_word data_base;
- unsigned data_bound;
- device *me;
-} htab_binary_sizes;
-
-STATIC_INLINE_DEVICE_TABLE void
-htab_sum_binary(bfd *abfd,
- sec_ptr sec,
- PTR data)
-{
- htab_binary_sizes *sizes = (htab_binary_sizes*)data;
- unsigned_word size = bfd_get_section_size_before_reloc (sec);
- unsigned_word vma = bfd_get_section_vma (abfd, sec);
-
- /* skip the section if no memory to allocate */
- if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
- return;
-
- if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
- || (bfd_get_section_flags (abfd, sec) & SEC_READONLY)) {
- if (sizes->text_bound < vma + size)
- sizes->text_bound = ALIGN_PAGE(vma + size);
- if (sizes->text_base > vma)
- sizes->text_base = FLOOR_PAGE(vma);
- }
- else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA)
- || (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)) {
- if (sizes->data_bound < vma + size)
- sizes->data_bound = ALIGN_PAGE(vma + size);
- if (sizes->data_base > vma)
- sizes->data_base = FLOOR_PAGE(vma);
- }
-}
-
-STATIC_INLINE_DEVICE_TABLE void
-htab_dma_binary(bfd *abfd,
- sec_ptr sec,
- PTR data)
-{
- htab_binary_sizes *sizes = (htab_binary_sizes*)data;
- void *section_init;
- unsigned_word section_vma;
- unsigned_word section_size;
- unsigned_word section_ra;
- device *me = sizes->me;
-
- /* skip the section if no memory to allocate */
- if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
- return;
-
- /* check/ignore any sections of size zero */
- section_size = bfd_get_section_size_before_reloc(sec);
- if (section_size == 0)
- return;
-
- /* if nothing to load, ignore this one */
- if (! (bfd_get_section_flags(abfd, sec) & SEC_LOAD))
- return;
-
- /* find where it is to go */
- section_vma = bfd_get_section_vma(abfd, sec);
- section_ra = 0;
- if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
- || (bfd_get_section_flags (abfd, sec) & SEC_READONLY))
- section_ra = (section_vma - sizes->text_base + sizes->text_ra);
- else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA))
- section_ra = (section_vma - sizes->data_base + sizes->data_ra);
- else
- return; /* just ignore it */
-
- DTRACE(htab,
- ("load - name=%-7s vma=0x%.8lx size=%6ld ra=0x%.8lx flags=%3lx(%s%s%s%s%s )\n",
- bfd_get_section_name(abfd, sec),
- (long)section_vma,
- (long)section_size,
- (long)section_ra,
- (long)bfd_get_section_flags(abfd, sec),
- bfd_get_section_flags(abfd, sec) & SEC_LOAD ? " LOAD" : "",
- bfd_get_section_flags(abfd, sec) & SEC_CODE ? " CODE" : "",
- bfd_get_section_flags(abfd, sec) & SEC_DATA ? " DATA" : "",
- bfd_get_section_flags(abfd, sec) & SEC_ALLOC ? " ALLOC" : "",
- bfd_get_section_flags(abfd, sec) & SEC_READONLY ? " READONLY" : ""
- ));
-
- /* dma in the sections data */
- section_init = zalloc(section_size);
- if (!bfd_get_section_contents(abfd,
- sec,
- section_init, 0,
- section_size)) {
- bfd_perror("devices/pte");
- error("devices/%s - no data loaded\n", device_name(me));
- }
- if (device_dma_write_buffer(device_parent(me),
- section_init,
- 0 /*space*/,
- section_ra,
- section_size,
- 1 /*violate_read_only*/)
- != section_size)
- error("devices/%s - broken dma transfer\n", device_name(me));
- zfree(section_init); /* only free if load */
-}
-
-
-STATIC_INLINE_DEVICE_TABLE void
-htab_map_binary(device *me,
- unsigned_word ra,
- unsigned wimg,
- unsigned pp,
- char *file_name,
- unsigned32 htaborg,
- unsigned32 htabmask)
-{
- htab_binary_sizes sizes;
- bfd *image;
- sizes.text_base = -1;
- sizes.data_base = -1;
- sizes.text_bound = 0;
- sizes.data_bound = 0;
- sizes.me = me;
-
- /* open the file */
- image = bfd_openr(file_name, NULL);
- if (image == NULL) {
- bfd_perror("devices/pte");
- error("devices/%s - the file %s not loaded\n", device_name(me), file_name);
- }
-
- /* check it is valid */
- if (!bfd_check_format(image, bfd_object)) {
- bfd_close(image);
- error("devices/%s - the file %s has an invalid binary format\n",
- device_name(me), file_name);
- }
-
- /* determine the size of each of the files regions */
- bfd_map_over_sections (image, htab_sum_binary, (PTR) &sizes);
-
- /* determine the real addresses of the sections */
- sizes.text_ra = ra;
- sizes.data_ra = ALIGN_PAGE(sizes.text_ra +
- (sizes.text_bound - sizes.text_base));
-
- DTRACE(htab, ("text map - base=0x%lx bound=0x%lx ra=0x%lx\n",
- (unsigned long)sizes.text_base,
- (unsigned long)sizes.text_bound,
- (unsigned long)sizes.text_ra));
- DTRACE(htab, ("data map - base=0x%lx bound=0x%lx ra=0x%lx\n",
- (unsigned long)sizes.data_base,
- (unsigned long)sizes.data_bound,
- (unsigned long)sizes.data_ra));
-
- /* set up virtual memory maps for each of the regions */
- htab_map_region(me, sizes.text_ra, sizes.text_base,
- sizes.text_bound - sizes.text_base,
- wimg, pp,
- htaborg, htabmask);
- htab_map_region(me, sizes.data_ra, sizes.data_base,
- sizes.data_bound - sizes.data_base,
- wimg, pp,
- htaborg, htabmask);
-
- /* dma the sections into physical memory */
- bfd_map_over_sections (image, htab_dma_binary, (PTR) &sizes);
-}
-
-static void
-htab_init_callback(device *me,
- psim *system)
-{
- if (WITH_TARGET_WORD_BITSIZE != 32)
- error("devices/htab: only 32bit targets currently suported\n");
-
- /* only the pte does work */
- if (strncmp(device_name(me), "pte@", strlen("pte@")) == 0) {
- unsigned32 htaborg;
- unsigned32 htabmask;
- signed32 pte_va; /* so that 0xff...0 is make 0xffffff00 */
- unsigned32 pte_ra;
- unsigned pte_nr_bytes;
- unsigned pte_wimg;
- unsigned pte_pp;
- char file_name[1024];
-
- htab_decode_hash_table(device_parent(me), &htaborg, &htabmask);
-
- /* handle a normal mapping definition */
- if (scand_uw_uw_u_u_u(device_name(me), &pte_ra, &pte_va, &pte_nr_bytes,
- &pte_wimg, &pte_pp) == 5) {
- DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, va=0x%lx, nr_bytes=%ld\n",
- (unsigned long)pte_ra,
- (long)pte_wimg,
- (long)pte_pp,
- (unsigned long)pte_va,
- (long)pte_nr_bytes));
- htab_map_region(me, pte_ra, pte_va, pte_nr_bytes, pte_wimg, pte_pp,
- htaborg, htabmask);
- }
- else if (scand_uw_u_u_c(device_name(me), &pte_ra, &pte_wimg, &pte_pp,
- file_name, sizeof(file_name)) == 4) {
- DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, binary=%s\n",
- (unsigned long)pte_ra,
- (unsigned long)pte_wimg,
- (long)pte_pp,
- file_name));
- htab_map_binary(me, pte_ra, pte_wimg, pte_pp, file_name,
- htaborg, htabmask);
- }
- else {
- error("devices/%s - Usage: %s\nor\t%s\n",
- device_name(me),
- "pte@,<real-addr>,<virtual-addr>,<nr-bytes>,<wimg>,<pp>",
- "pte@<real-addr>,<wimg>,<pp>,<binary>");
- }
- }
-}
-
-
-static device_callbacks const htab_callbacks = {
- htab_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- passthrough_device_dma_read_buffer,
- passthrough_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* Simulator device: sim@0x<address>,<nr_bytes>
-
- Eventually gives access to the hardware configuration. For
- instance, it could allow the setting (on the fly) of variables such
- as hardware floating-point or strict-alignment.
-
- It's intended use is as part of testing the simulators
- functionality */
-
-static device_callbacks const sim_callbacks = {
- ignore_device_init,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* Load device: binary
-
- Single property the name of which specifies the file (understood by
- BFD) that is to be DMAed into memory as part of init */
-
-STATIC_INLINE_DEVICE_TABLE 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" : ""
- ));
-
- /* 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("core:load_section()");
- error("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)
- error("data_init_callback() broken transfer for %s\n", device_name(me));
- zfree(section_init); /* only free if load */
- }
-}
-
-
-static void
-binary_init_callback(device *me,
- psim *system)
-{
- const char *file_name;
- bfd *image;
-
-
- /* get the property specifying the file name */
- file_name = device_find_next_property(me, NULL);
-
- /* open the file */
- image = bfd_openr(file_name, NULL);
- if (image == NULL) {
- bfd_perror("devices/binary");
- error("devices/%s - the file %s not loaded\n", device_name(me), file_name);
- }
-
- /* check it is valid */
- if (!bfd_check_format(image, bfd_object)) {
- bfd_close(image);
- error("devices/%s - the file %s has an invalid binary format\n",
- device_name(me), file_name);
- }
-
- /* and the data sections */
- bfd_map_over_sections(image,
- update_for_binary_section,
- (PTR)me);
-
- bfd_close(image);
-}
-
-
-static device_callbacks const binary_callbacks = {
- binary_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* Stack device: stack@<type>
-
- Has a single IOCTL to create a stack frame of the specified type.
- If <type> is elf or xcoff then a corresponding stack is created.
- Any other value of type is ignored.
-
- The IOCTL takes the additional arguments:
-
- unsigned_word stack_end -- where the stack should come down from
- char **argv -- ...
- char **envp -- ...
-
- */
-
-STATIC_INLINE_DEVICE_TABLE 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_INLINE_DEVICE_TABLE int
-number_of_arguments(char **arg)
-{
- int nr;
- if (arg == NULL)
- return 0;
- for (nr = 0; *arg != NULL; arg++, nr++);
- return nr;
-}
-
-STATIC_INLINE_DEVICE_TABLE int
-sizeof_arguments(char **arg)
-{
- return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
-}
-
-STATIC_INLINE_DEVICE_TABLE void
-write_stack_arguments(psim *system,
- char **arg,
- unsigned_word start_block,
- unsigned_word end_block,
- unsigned_word start_arg,
- unsigned_word end_arg)
-{
- DTRACE(stack,
- ("write_stack_arguments(system=0x%lx, arg=0x%lx, start_block=0x%lx, end_block=0x%lx, start_arg=0x%lx, end_arg=0x%lx)\n",
- (long)system, (long)arg, (long)start_block, (long)end_block, (long)start_arg, (long)end_arg));
- if (arg == NULL)
- error("write_arguments: character array NULL\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(system, 0, *arg,
- start_block, len,
- 0/*violate_readonly*/) != len)
- error("write_stack_arguments() - write of **arg (%s) at 0x%x failed\n",
- *arg, start_block);
- target_start_block = H2T_word(start_block);
- if (psim_write_memory(system, 0, &target_start_block,
- start_arg, sizeof(target_start_block),
- 0) != sizeof(target_start_block))
- error("write_stack_arguments() - write of *arg 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)
- error("write_stack_arguments - possible corruption\n");
- DTRACE(stack,
- ("write_stack_arguments() = void\n"));
-}
-
-STATIC_INLINE_DEVICE_TABLE void
-create_elf_stack_frame(psim *system,
- 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(system, envp,
- start_envp_block, bottom_of_stack,
- start_envp, start_aux);
- write_stack_arguments(system, argv,
- start_argv_block, start_envp_block,
- start_argv, start_envp);
-
- /* set up the registers */
- psim_write_register(system, -1,
- &top_of_stack, "sp", cooked_transfer);
- psim_write_register(system, -1,
- &argc, "r3", cooked_transfer);
- psim_write_register(system, -1,
- &start_argv, "r4", cooked_transfer);
- psim_write_register(system, -1,
- &start_envp, "r5", cooked_transfer);
- psim_write_register(system, -1,
- &start_aux, "r6", cooked_transfer);
-}
-
-STATIC_INLINE_DEVICE_TABLE void
-create_aix_stack_frame(psim *system,
- 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_elf_stack_frame(system, bottom_of_stack, argv, envp);
-
- /* extract argument addresses from registers */
- psim_read_register(system, 0, &top_of_stack, "r1", cooked_transfer);
- psim_read_register(system, 0, &core_argc, "r3", cooked_transfer);
- psim_read_register(system, 0, &core_argv, "r4", cooked_transfer);
- psim_read_register(system, 0, &core_envp, "r5", cooked_transfer);
- psim_read_register(system, 0, &core_aux, "r6", cooked_transfer);
-
- /* extract arguments from registers */
- error("create_aix_stack_frame() - what happens next?\n");
-}
-
-
-
-static void
-stack_ioctl_callback(device *me,
- psim *system,
- 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, system=0x%lx, processor=0x%lx, cia=0x%lx, argv=0x%lx, envp=0x%lx)\n",
- (long)me, device_name(me), (long)system, (long)processor, (long)cia, (long)argv, (long)envp));
- stack_type = device_find_next_property(me, NULL);
- if (stack_type != NULL) {
- if (strcmp(stack_type, "elf") == 0)
- create_elf_stack_frame(system, stack_pointer, argv, envp);
- else if (strcmp(stack_type, "xcoff") == 0)
- create_aix_stack_frame(system, stack_pointer, argv, envp);
- }
- DTRACE(stack,
- ("stack_ioctl_callback() = void\n"));
-}
-
-\f
-
-
-static device_callbacks const stack_callbacks = {
- ignore_device_init,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- stack_ioctl_callback,
+static const device_callbacks passthrough_callbacks = {
+ { NULL, }, /* init */
+ { passthrough_device_address_attach,
+ passthrough_device_address_detach, },
+ { NULL, }, /* IO */
+ { passthrough_device_dma_read_buffer, passthrough_device_dma_write_buffer, },
+ { NULL, }, /* interrupt */
+ { generic_device_unit_decode,
+ generic_device_unit_encode, },
};
-\f
-device_descriptor device_table[] = {
- { "console", console_create, &console_callbacks },
- { "memory", NULL, &memory_callbacks },
- { "vm", vea_vm_create, &vm_callbacks },
- { "halt", NULL, &halt_callbacks },
- { "icu", NULL, &icu_callbacks },
- { "register", NULL, ®ister_callbacks },
- { "iobus", NULL, &iobus_callbacks },
- { "file", NULL, &file_callbacks },
- { "data", NULL, &data_callbacks },
- { "htab", NULL, &htab_callbacks },
- { "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */
- { "stack", NULL, &stack_callbacks },
- { "sim", NULL, &sim_callbacks },
- { "load-binary", NULL, &binary_callbacks },
- { "map-binary", NULL, &binary_callbacks },
+static const device_descriptor ob_device_table[] = {
+ /* standard OpenBoot devices */
+ { "aliases", NULL, &passthrough_callbacks },
{ "options", NULL, &passthrough_callbacks },
- { "init", NULL, &passthrough_callbacks },
{ "chosen", NULL, &passthrough_callbacks },
+ { "packages", NULL, &passthrough_callbacks },
+ { "cpus", NULL, &passthrough_callbacks },
+ { "openprom", NULL, &passthrough_callbacks },
+ { "init", NULL, &passthrough_callbacks },
{ NULL },
};
+const device_descriptor *const device_table[] = {
+ ob_device_table,
+#include "hw.c"
+ NULL,
+};
+
+
#endif /* _DEVICE_TABLE_C_ */