Change OFMEM so that the generated available, physical and virtual properties are passed by reference into Forth.

The previous code used the standard set_property() function which copies the new property into the dictionary each time the 
property is set. During OpenSolaris boot, this would cause OpenBIOS to run out of memory due to large number of changes to the 
memory regions.

Now for each property we have a static buffer allocated within OpenBIOS which starts from 2K and doubles in size everytime the 
memory region is exhausted, and set the address directly to the relevant buffer. This saves a great deal of memory and prevents 
the dictionary and internal memory regions from being exhausted during OpenSolaris boot.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk> 


git-svn-id: svn://coreboot.org/openbios/trunk/openbios-devel@896 f158a5a8-5612-0410-a976-696ce0be7e32
This commit is contained in:
Mark Cave-Ayland
2010-10-16 14:02:18 +00:00
committed by Mark Cave-Ayland
parent 05ec5dd149
commit a32ba29f8b

View File

@@ -1,5 +1,5 @@
/* /*
* <ofmem_sparc64.c> * <ofmem_common.c>
* *
* OF Memory manager * OF Memory manager
* *
@@ -16,6 +16,9 @@
#include "libopenbios/bindings.h" #include "libopenbios/bindings.h"
#include "libopenbios/ofmem.h" #include "libopenbios/ofmem.h"
/* Default size of memory allocated for each of the MMU properties (in bytes) */
#define OFMEM_DEFAULT_PROP_SIZE 2048
/* /*
* define OFMEM_FILL_RANGE to claim any unclaimed virtual and * define OFMEM_FILL_RANGE to claim any unclaimed virtual and
* physical memory in the range for ofmem_map * physical memory in the range for ofmem_map
@@ -166,6 +169,28 @@ void* ofmem_realloc( void *ptr, size_t size )
/* "translations" and "available" property tracking */ /* "translations" and "available" property tracking */
/************************************************************************/ /************************************************************************/
static int trans_prop_size = 0, phys_range_prop_size = 0, virt_range_prop_size = 0;
static int trans_prop_used = 0, phys_range_prop_used = 0, virt_range_prop_used = 0;
static ucell *trans_prop, *phys_range_prop, *virt_range_prop;
static void
ofmem_set_property( phandle_t ph, const char *name, const char *buf, int len )
{
/* This is very similar to set_property() in libopenbios/bindings.c but allows
us to set the property pointer directly, rather than having to copy it
into the Forth dictonary every time we update the memory properties */
if( !ph ) {
printk("ofmem_set_property: NULL phandle\n");
return;
}
PUSH((ucell)buf);
PUSH(len);
PUSH((ucell)name);
PUSH(strlen(name));
PUSH_ph(ph);
fword("encode-property");
}
static phandle_t s_phandle_memory = 0; static phandle_t s_phandle_memory = 0;
static phandle_t s_phandle_mmu = 0; static phandle_t s_phandle_mmu = 0;
@@ -173,8 +198,7 @@ static void ofmem_update_mmu_translations( void )
{ {
ofmem_t *ofmem = ofmem_arch_get_private(); ofmem_t *ofmem = ofmem_arch_get_private();
translation_t *t; translation_t *t;
int ncells; int ncells, prop_used, prop_size;
ucell *props;
if (s_phandle_mmu == 0) if (s_phandle_mmu == 0)
return; return;
@@ -182,31 +206,49 @@ static void ofmem_update_mmu_translations( void )
for( t = ofmem->trans, ncells = 0; t ; t=t->next, ncells++ ) { for( t = ofmem->trans, ncells = 0; t ; t=t->next, ncells++ ) {
} }
props = malloc(ncells * sizeof(ucell) * ofmem_arch_get_translation_entry_size()); /* Get the current number of bytes required for the MMU translation property */
prop_used = ncells * sizeof(ucell) * ofmem_arch_get_translation_entry_size();
if (props == NULL) if (prop_used > trans_prop_size) {
/* The property doesn't fix within the existing space, so keep doubling it
until it does */
prop_size = trans_prop_size;
while (prop_size < prop_used) {
prop_size *= 2;
}
/* Allocate the new memory and copy all of the existing information across */
trans_prop = realloc(trans_prop, prop_size);
trans_prop_size = prop_size;
trans_prop_used = prop_used;
}
if (trans_prop == NULL) {
/* out of memory! */
printk("Unable to allocate memory for translations property!\n");
return; return;
}
/* Call architecture-specific routines to generate translation entries */ /* Call architecture-specific routines to generate translation entries */
for( t = ofmem->trans, ncells = 0 ; t ; t=t->next ) { for( t = ofmem->trans, ncells = 0 ; t ; t=t->next ) {
ofmem_arch_create_translation_entry(&props[ncells], t); ofmem_arch_create_translation_entry(&trans_prop[ncells], t);
ncells += ofmem_arch_get_translation_entry_size(); ncells += ofmem_arch_get_translation_entry_size();
} }
set_property(s_phandle_mmu, "translations", ofmem_set_property(s_phandle_mmu, "translations",
(char*)props, ncells * sizeof(props[0])); (char*)trans_prop, ncells * sizeof(trans_prop[0]));
free(props);
} }
static void ofmem_update_memory_available( phandle_t ph, range_t *range, static void ofmem_update_memory_available( phandle_t ph, range_t *range,
u64 top_address ) ucell **mem_prop, int *mem_prop_size, int *mem_prop_used, u64 top_address )
{ {
range_t *r; range_t *r;
int ncells; int ncells, prop_used, prop_size;
ucell *props;
ucell start, size; ucell start, size, *prop;
if (s_phandle_memory == 0) if (s_phandle_memory == 0)
return; return;
@@ -216,15 +258,32 @@ static void ofmem_update_memory_available( phandle_t ph, range_t *range,
} }
/* inverse of phys_range list could take 2 more cells for the tail */ /* inverse of phys_range list could take 2 more cells for the tail */
props = malloc((ncells+1) * sizeof(ucell) * 2); prop_used = (ncells+1) * sizeof(ucell) * 2;
if (props == NULL) { if (prop_used > *mem_prop_size) {
/* The property doesn't fix within the existing space, so keep doubling it
until it does */
prop_size = *mem_prop_size;
while (prop_size < prop_used) {
prop_size *= 2;
}
/* Allocate the new memory and copy all of the existing information across */
*mem_prop = realloc(*mem_prop, prop_size);
*mem_prop_size = prop_size;
*mem_prop_used = prop_used;
}
if (*mem_prop == NULL) {
/* out of memory! */ /* out of memory! */
printk("Unable to allocate memory for memory range property!\n");
return; return;
} }
start = 0; start = 0;
ncells = 0; ncells = 0;
prop = *mem_prop;
for (r = range; r; r=r->next) { for (r = range; r; r=r->next) {
if (r->start >= top_address) { if (r->start >= top_address) {
@@ -233,32 +292,30 @@ static void ofmem_update_memory_available( phandle_t ph, range_t *range,
size = r->start - start; size = r->start - start;
if (size) { if (size) {
props[ncells++] = start; prop[ncells++] = start;
props[ncells++] = size; prop[ncells++] = size;
} }
start = r->start + r->size; start = r->start + r->size;
} }
/* tail */ /* tail */
if (start < top_address) { if (start < top_address) {
props[ncells++] = start; prop[ncells++] = start;
props[ncells++] = top_address - start; prop[ncells++] = top_address - start;
} }
set_property(ph, "available", ofmem_set_property(ph, "available",
(char*)props, ncells * sizeof(props[0])); (char*)prop, ncells * sizeof(prop[0]));
free(props);
} }
static void ofmem_update_translations( void ) static void ofmem_update_translations( void )
{ {
ofmem_t *ofmem = ofmem_arch_get_private(); ofmem_t *ofmem = ofmem_arch_get_private();
ofmem_update_memory_available(s_phandle_memory, ofmem_update_memory_available(s_phandle_memory, ofmem->phys_range,
ofmem->phys_range, get_ram_size()); &phys_range_prop, &phys_range_prop_size, &phys_range_prop_used, get_ram_size());
ofmem_update_memory_available(s_phandle_mmu, ofmem_update_memory_available(s_phandle_mmu, ofmem->virt_range,
ofmem->virt_range, -1ULL); &virt_range_prop, &virt_range_prop_size, &virt_range_prop_used, -1ULL);
ofmem_update_mmu_translations(); ofmem_update_mmu_translations();
} }
@@ -741,5 +798,11 @@ void ofmem_register( phandle_t ph_memory, phandle_t ph_mmu )
s_phandle_memory = ph_memory; s_phandle_memory = ph_memory;
s_phandle_mmu = ph_mmu; s_phandle_mmu = ph_mmu;
/* Initialise some default property sizes */
trans_prop_size = phys_range_prop_size = virt_range_prop_size = OFMEM_DEFAULT_PROP_SIZE;
trans_prop = malloc(trans_prop_size);
phys_range_prop = malloc(phys_range_prop_size);
virt_range_prop = malloc(virt_range_prop_size);
ofmem_update_translations(); ofmem_update_translations();
} }