Author: mcayland Date: Sat Oct 16 16:02:18 2010 New Revision: 896 URL: http://tracker.coreboot.org/trac/openbios/changeset/896
Log: 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
Modified: trunk/openbios-devel/libopenbios/ofmem_common.c
Modified: trunk/openbios-devel/libopenbios/ofmem_common.c ============================================================================== --- trunk/openbios-devel/libopenbios/ofmem_common.c Wed Oct 13 16:01:51 2010 (r895) +++ trunk/openbios-devel/libopenbios/ofmem_common.c Sat Oct 16 16:02:18 2010 (r896) @@ -1,5 +1,5 @@ /* - * <ofmem_sparc64.c> + * <ofmem_common.c> * * OF Memory manager * @@ -16,6 +16,9 @@ #include "libopenbios/bindings.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 * physical memory in the range for ofmem_map @@ -166,6 +169,28 @@ /* "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_mmu = 0;
@@ -173,8 +198,7 @@ { ofmem_t *ofmem = ofmem_arch_get_private(); translation_t *t; - int ncells; - ucell *props; + int ncells, prop_used, prop_size;
if (s_phandle_mmu == 0) return; @@ -182,31 +206,49 @@ 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 (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 (props == NULL) + if (trans_prop == NULL) { + /* out of memory! */ + printk("Unable to allocate memory for translations property!\n"); return; + }
/* Call architecture-specific routines to generate translation entries */ 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(); }
- set_property(s_phandle_mmu, "translations", - (char*)props, ncells * sizeof(props[0])); + ofmem_set_property(s_phandle_mmu, "translations", + (char*)trans_prop, ncells * sizeof(trans_prop[0]));
- free(props); }
+ 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; - int ncells; - ucell *props; + int ncells, prop_used, prop_size;
- ucell start, size; + ucell start, size, *prop;
if (s_phandle_memory == 0) return; @@ -216,15 +258,32 @@ }
/* 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 (prop_used > *mem_prop_size) {
- if (props == NULL) { + /* 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! */ + printk("Unable to allocate memory for memory range property!\n"); return; }
start = 0; ncells = 0; + prop = *mem_prop;
for (r = range; r; r=r->next) { if (r->start >= top_address) { @@ -233,32 +292,30 @@
size = r->start - start; if (size) { - props[ncells++] = start; - props[ncells++] = size; + prop[ncells++] = start; + prop[ncells++] = size; } start = r->start + r->size; }
/* tail */ if (start < top_address) { - props[ncells++] = start; - props[ncells++] = top_address - start; + prop[ncells++] = start; + prop[ncells++] = top_address - start; }
- set_property(ph, "available", - (char*)props, ncells * sizeof(props[0])); - - free(props); + ofmem_set_property(ph, "available", + (char*)prop, ncells * sizeof(prop[0])); }
static void ofmem_update_translations( void ) { ofmem_t *ofmem = ofmem_arch_get_private();
- ofmem_update_memory_available(s_phandle_memory, - ofmem->phys_range, get_ram_size()); - ofmem_update_memory_available(s_phandle_mmu, - ofmem->virt_range, -1ULL); + ofmem_update_memory_available(s_phandle_memory, ofmem->phys_range, + &phys_range_prop, &phys_range_prop_size, &phys_range_prop_used, get_ram_size()); + ofmem_update_memory_available(s_phandle_mmu, ofmem->virt_range, + &virt_range_prop, &virt_range_prop_size, &virt_range_prop_used, -1ULL); ofmem_update_mmu_translations(); }
@@ -741,5 +798,11 @@ s_phandle_memory = ph_memory; 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(); }