diff options
Diffstat (limited to 'sim/ppc/hw_memory.c')
-rw-r--r-- | sim/ppc/hw_memory.c | 538 |
1 files changed, 0 insertions, 538 deletions
diff --git a/sim/ppc/hw_memory.c b/sim/ppc/hw_memory.c deleted file mode 100644 index 117324b..0000000 --- a/sim/ppc/hw_memory.c +++ /dev/null @@ -1,538 +0,0 @@ -/* This file is part of the program psim. - - Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - */ - - -#ifndef _HW_MEMORY_C_ -#define _HW_MEMORY_C_ - -#ifndef STATIC_INLINE_HW_MEMORY -#define STATIC_INLINE_HW_MEMORY STATIC_INLINE -#endif - -#include "device_table.h" - -/* DEVICE - - - memory - description of system memory - - - DESCRIPTION - - - This device describes the size and location of the banks of - physical memory within the simulation. - - In addition, this device supports the "claim" and "release" methods - that can be used by OpenBoot client programs to manage the - allocation of physical memory. - - - PROPERTIES - - - reg = { <address> <size> } (required) - - Each pair specify one bank of memory. - - available = { <address> <size> } (automatic) - - Each pair specifies a block of memory that is currently unallocated. - - - BUGS - - - OpenFirmware doesn't make it clear if, when releasing memory the - same address + size pair as was used during the claim should be - specified. - - It is assumed that #size-cells and #address-cells for the parent - node of this device are both one i.e. an address or size can be - specified using a single memory cell (word). - - Significant work will be required before the <<memory>> device can - support 64bit addresses (#address-cells equal two). - - */ - -typedef struct _memory_reg_spec { - unsigned_cell base; - unsigned_cell size; -} memory_reg_spec; - -typedef struct _hw_memory_chunk hw_memory_chunk; -struct _hw_memory_chunk { - unsigned_word address; - unsigned_word size; - int available; - hw_memory_chunk *next; -}; - -typedef struct _hw_memory_device { - hw_memory_chunk *heap; -} hw_memory_device; - - -static void * -hw_memory_create(const char *name, - const device_unit *unit_address, - const char *args) -{ - hw_memory_device *hw_memory = ZALLOC(hw_memory_device); - return hw_memory; -} - - -static void -hw_memory_set_available(device *me, - hw_memory_device *hw_memory) -{ - hw_memory_chunk *chunk = NULL; - memory_reg_spec *available = NULL; - int nr_available = 0; - int curr = 0; - int sizeof_available = 0; - /* determine the nr of available chunks */ - chunk = hw_memory->heap; - nr_available = 0; - while (chunk != NULL) { - if (chunk->available) - nr_available += 1; - ASSERT(chunk->next == NULL - || chunk->address < chunk->next->address); - ASSERT(chunk->next == NULL - || chunk->address + chunk->size == chunk->next->address); - chunk = chunk->next; - } - /* now create the available struct */ - ASSERT(nr_available > 0); - sizeof_available = sizeof(memory_reg_spec) * nr_available; - available = zalloc(sizeof_available); - chunk = hw_memory->heap; - curr = 0; - while (chunk != NULL) { - if (chunk->available) { - available[curr].base = H2BE_cell(chunk->address); - available[curr].size = H2BE_cell(chunk->size); - curr += 1; - } - chunk = chunk->next; - } - /* update */ - device_set_array_property(me, "available", available, sizeof_available); - zfree(available); -} - - -static void -hw_memory_init_address(device *me) -{ - hw_memory_device *hw_memory = (hw_memory_device*)device_data(me); - - /* free up any previous structures */ - { - hw_memory_chunk *curr_chunk = hw_memory->heap; - hw_memory->heap = NULL; - while (curr_chunk != NULL) { - hw_memory_chunk *dead_chunk = curr_chunk; - curr_chunk = dead_chunk->next; - dead_chunk->next = NULL; - zfree(dead_chunk); - } - } - - /* attach memory regions according to the "reg" property */ - { - int reg_nr; - reg_property_spec reg; - for (reg_nr = 0; - device_find_reg_array_property(me, "reg", reg_nr, ®); - reg_nr++) { - int i; - /* check that the entry meets restrictions */ - for (i = 0; i < reg.address.nr_cells - 1; i++) - if (reg.address.cells[i] != 0) - device_error(me, "Only single celled addresses supported"); - for (i = 0; i < reg.size.nr_cells - 1; i++) - if (reg.size.cells[i] != 0) - device_error(me, "Only single celled sizes supported"); - /* attach the range */ - device_attach_address(device_parent(me), - attach_raw_memory, - 0 /*address space*/, - reg.address.cells[reg.address.nr_cells - 1], - reg.size.cells[reg.size.nr_cells - 1], - access_read_write_exec, - me); - } - } - - /* create the initial `available memory' data structure */ - if (device_find_property(me, "available") != NULL) { - hw_memory_chunk **curr_chunk = &hw_memory->heap; - int cell_nr; - unsigned_cell dummy; - int nr_cells = device_find_integer_array_property(me, "available", 0, &dummy); - if ((nr_cells % 2) != 0) - device_error(me, "property \"available\" invalid - contains an odd number of cells"); - for (cell_nr = 0; - cell_nr < nr_cells; - cell_nr += 2) { - hw_memory_chunk *new_chunk = ZALLOC(hw_memory_chunk); - device_find_integer_array_property(me, "available", cell_nr, - &new_chunk->address); - device_find_integer_array_property(me, "available", cell_nr + 1, - &new_chunk->size); - new_chunk->available = 1; - *curr_chunk = new_chunk; - curr_chunk = &new_chunk->next; - } - } - else { - hw_memory_chunk **curr_chunk = &hw_memory->heap; - int reg_nr; - reg_property_spec reg; - for (reg_nr = 0; - device_find_reg_array_property(me, "reg", reg_nr, ®); - reg_nr++) { - hw_memory_chunk *new_chunk; - new_chunk = ZALLOC(hw_memory_chunk); - new_chunk->address = reg.address.cells[reg.address.nr_cells - 1]; - new_chunk->size = reg.size.cells[reg.size.nr_cells - 1]; - new_chunk->available = 1; - *curr_chunk = new_chunk; - curr_chunk = &new_chunk->next; - } - } - - /* initialize the alloc property for this device */ - hw_memory_set_available(me, hw_memory); -} - -static void -hw_memory_instance_delete(device_instance *instance) -{ - return; -} - -static int -hw_memory_instance_claim(device_instance *instance, - int n_stack_args, - unsigned_cell stack_args[/*n_stack_args*/], - int n_stack_returns, - unsigned_cell stack_returns[/*n_stack_returns*/]) -{ - hw_memory_device *hw_memory = device_instance_data(instance); - device *me = device_instance_device(instance); - int stackp = 0; - unsigned_word alignment; - unsigned_cell size; - unsigned_cell address; - hw_memory_chunk *chunk = NULL; - - /* get the alignment from the stack */ - if (n_stack_args < stackp + 1) - device_error(me, "claim - incorrect number of arguments (alignment missing)"); - alignment = stack_args[stackp]; - stackp++; - - /* get the size from the stack */ - { - int i; - int nr_cells = device_nr_size_cells(device_parent(me)); - if (n_stack_args < stackp + nr_cells) - device_error(me, "claim - incorrect number of arguments (size missing)"); - for (i = 0; i < nr_cells - 1; i++) { - if (stack_args[stackp] != 0) - device_error(me, "claim - multi-cell sizes not supported"); - stackp++; - } - size = stack_args[stackp]; - stackp++; - } - - /* get the address from the stack */ - { - int nr_cells = device_nr_address_cells(device_parent(me)); - if (alignment != 0) { - if (n_stack_args != stackp) { - if (n_stack_args == stackp + nr_cells) - DTRACE(memory, ("claim - extra address argument ignored\n")); - else - device_error(me, "claim - incorrect number of arguments (optional addr)"); - } - address = 0; - } - else { - int i; - if (n_stack_args != stackp + nr_cells) - device_error(me, "claim - incorrect number of arguments (addr missing)"); - for (i = 0; i < nr_cells - 1; i++) { - if (stack_args[stackp] != 0) - device_error(me, "claim - multi-cell addresses not supported"); - stackp++; - } - address = stack_args[stackp]; - } - } - - /* check that there is space for the result */ - if (n_stack_returns != 0 - && n_stack_returns != device_nr_address_cells(device_parent(me))) - device_error(me, "claim - invalid number of return arguments"); - - /* find a chunk candidate, either according to address or alignment */ - if (alignment == 0) { - chunk = hw_memory->heap; - while (chunk != NULL) { - if ((address + size) <= (chunk->address + chunk->size)) - break; - chunk = chunk->next; - } - if (chunk == NULL || address < chunk->address || !chunk->available) - device_error(me, "failed to allocate %ld bytes at 0x%lx", - (unsigned long)size, (unsigned long)address); - DTRACE(memory, ("claim - address=0x%lx size=0x%lx\n", - (unsigned long)address, - (unsigned long)size)); - } - else { - /* adjust the alignment so that it is a power of two */ - unsigned_word align_mask = 1; - while (align_mask < alignment && align_mask != 0) - align_mask <<= 1; - if (align_mask == 0) - device_error(me, "alignment 0x%lx is to large", (unsigned long)alignment); - align_mask -= 1; - /* now find an aligned chunk that fits */ - chunk = hw_memory->heap; - while (chunk != NULL) { - address = ((chunk->address + align_mask) & ~align_mask); - if ((chunk->available) - && (chunk->address + chunk->size >= address + size)) - break; - chunk = chunk->next; - } - if (chunk == NULL) - device_error(me, "failed to allocate %ld bytes with alignment %ld", - (unsigned long)size, (unsigned long)alignment); - DTRACE(memory, ("claim - size=0x%lx alignment=%ld (0x%lx), address=0x%lx\n", - (unsigned long)size, - (unsigned long)alignment, - (unsigned long)alignment, - (unsigned long)address)); - } - - /* break off a bit before this chunk if needed */ - ASSERT(address >= chunk->address); - if (address > chunk->address) { - hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk); - /* insert a new chunk */ - next_chunk->next = chunk->next; - chunk->next = next_chunk; - /* adjust the address/size */ - next_chunk->address = address; - next_chunk->size = chunk->address + chunk->size - next_chunk->address; - next_chunk->available = 1; - chunk->size = next_chunk->address - chunk->address; - /* make this new chunk the one to allocate */ - chunk = next_chunk; - } - ASSERT(address == chunk->address); - - /* break off a bit after this chunk if needed */ - ASSERT(address + size <= chunk->address + chunk->size); - if (address + size < chunk->address + chunk->size) { - hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk); - /* insert it in to the list */ - next_chunk->next = chunk->next; - chunk->next = next_chunk; - /* adjust the address/size */ - next_chunk->address = address + size; - next_chunk->size = chunk->address + chunk->size - next_chunk->address; - next_chunk->available = 1; - chunk->size = next_chunk->address - chunk->address; - } - ASSERT(address + size == chunk->address + chunk->size); - - /* now allocate/return it */ - chunk->available = 0; - hw_memory_set_available(device_instance_device(instance), hw_memory); - if (n_stack_returns > 0) { - int i; - for (i = 0; i < n_stack_returns - 1; i++) - stack_returns[i] = 0; - stack_returns[n_stack_returns - 1] = address; - } - - return 0; -} - - -static int -hw_memory_instance_release(device_instance *instance, - int n_stack_args, - unsigned_cell stack_args[/*n_stack_args*/], - int n_stack_returns, - unsigned_cell stack_returns[/*n_stack_returns*/]) -{ - hw_memory_device *hw_memory = device_instance_data(instance); - device *me = device_instance_device(instance); - unsigned_word length; - unsigned_word address; - int stackp = 0; - hw_memory_chunk *chunk; - - /* get the length from the stack */ - { - int i; - int nr_cells = device_nr_size_cells(device_parent(me)); - if (n_stack_args < stackp + nr_cells) - device_error(me, "release - incorrect number of arguments (length missing)"); - for (i = 0; i < nr_cells - 1; i++) { - if (stack_args[stackp] != 0) - device_error(me, "release - multi-cell length not supported"); - stackp++; - } - length = stack_args[stackp]; - stackp++; - } - - /* get the address from the stack */ - { - int i; - int nr_cells = device_nr_address_cells(device_parent(me)); - if (n_stack_args != stackp + nr_cells) - device_error(me, "release - incorrect number of arguments (addr missing)"); - for (i = 0; i < nr_cells - 1; i++) { - if (stack_args[stackp] != 0) - device_error(me, "release - multi-cell addresses not supported"); - stackp++; - } - address = stack_args[stackp]; - } - - /* returns ok */ - if (n_stack_returns != 0) - device_error(me, "release - nonzero number of results"); - - /* try to free the corresponding memory chunk */ - chunk = hw_memory->heap; - while (chunk != NULL) { - if (chunk->address == address - && chunk->size == length) { - /* an exact match */ - if (chunk->available) - device_error(me, "memory chunk 0x%lx (size 0x%lx) already available", - (unsigned long)address, - (unsigned long)length); - else { - /* free this chunk */ - DTRACE(memory, ("release - address=0x%lx, length=0x%lx\n", - (unsigned long) address, - (unsigned long) length)); - chunk->available = 1; - break; - } - } - else if (chunk->address >= address - && chunk->address + chunk->size <= address + length) { - /* a sub region */ - if (!chunk->available) { - DTRACE(memory, ("release - address=0x%lx, size=0x%lx within region 0x%lx length 0x%lx\n", - (unsigned long) chunk->address, - (unsigned long) chunk->size, - (unsigned long) address, - (unsigned long) length)); - chunk->available = 1; - } - } - chunk = chunk->next; - } - if (chunk == NULL) { - printf_filtered("warning: released chunks within region 0x%lx..0x%lx\n", - (unsigned long)address, - (unsigned long)(address + length - 1)); - } - - /* check for the chance to merge two adjacent available memory chunks */ - chunk = hw_memory->heap; - while (chunk != NULL) { - if (chunk->available - && chunk->next != NULL && chunk->next->available) { - /* adjacent */ - hw_memory_chunk *delete = chunk->next; - ASSERT(chunk->address + chunk->size == delete->address); - chunk->size += delete->size; - chunk->next = delete->next; - zfree(delete); - } - else { - chunk = chunk->next; - } - } - - /* update the corresponding property */ - hw_memory_set_available(device_instance_device(instance), hw_memory); - - return 0; -} - - -static device_instance_methods hw_memory_instance_methods[] = { - { "claim", hw_memory_instance_claim }, - { "release", hw_memory_instance_release }, - { NULL, }, -}; - -static device_instance_callbacks const hw_memory_instance_callbacks = { - hw_memory_instance_delete, - NULL /*read*/, NULL /*write*/, NULL /*seek*/, - hw_memory_instance_methods -}; - -static device_instance * -hw_memory_create_instance(device *me, - const char *path, - const char *args) -{ - return device_create_instance_from(me, NULL, - device_data(me), /* nothing better */ - path, args, - &hw_memory_instance_callbacks); -} - -static device_callbacks const hw_memory_callbacks = { - { hw_memory_init_address, }, - { NULL, }, /* address */ - { NULL, }, /* IO */ - { NULL, }, /* DMA */ - { NULL, }, /* interrupt */ - { NULL, }, /* unit */ - hw_memory_create_instance, -}; - -const device_descriptor hw_memory_device_descriptor[] = { - { "memory", hw_memory_create, &hw_memory_callbacks }, - { NULL }, -}; - -#endif /* _HW_MEMORY_C_ */ |