From fd141fb6693520fd01b6f5a5d6b15379fb543254 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Nov 2012 23:19:16 +0000 Subject: [PATCH] [umalloc] Split largest_memblock() function out from init_eheap() Signed-off-by: Michael Brown --- .../i386/interface/pcbios/memtop_umalloc.c | 57 ++----------- src/core/memblock.c | 81 +++++++++++++++++++ src/include/ipxe/memblock.h | 17 ++++ 3 files changed, 106 insertions(+), 49 deletions(-) create mode 100644 src/core/memblock.c create mode 100644 src/include/ipxe/memblock.h diff --git a/src/arch/i386/interface/pcbios/memtop_umalloc.c b/src/arch/i386/interface/pcbios/memtop_umalloc.c index 1821faf2..c382e3c3 100644 --- a/src/arch/i386/interface/pcbios/memtop_umalloc.c +++ b/src/arch/i386/interface/pcbios/memtop_umalloc.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** Alignment of external allocated memory */ @@ -59,53 +60,14 @@ static size_t heap_size; /** * Initialise external heap * - * @ret rc Return status code */ -static int init_eheap ( void ) { - struct memory_map memmap; - unsigned int i; - - DBG ( "Allocating external heap\n" ); - - get_memmap ( &memmap ); - heap_size = 0; - for ( i = 0 ; i < memmap.count ; i++ ) { - struct memory_region *region = &memmap.regions[i]; - unsigned long r_start, r_end; - unsigned long r_size; - - DBG ( "Considering [%llx,%llx)\n", region->start, region->end); - - /* Truncate block to 4GB */ - if ( region->start > UINT_MAX ) { - DBG ( "...starts after 4GB\n" ); - continue; - } - r_start = region->start; - if ( region->end > UINT_MAX ) { - DBG ( "...end truncated to 4GB\n" ); - r_end = 0; /* =4GB, given the wraparound */ - } else { - r_end = region->end; - } - - /* Use largest block */ - r_size = ( r_end - r_start ); - if ( r_size > heap_size ) { - DBG ( "...new best block found\n" ); - top = bottom = phys_to_user ( r_end ); - heap_size = r_size; - } - } - - if ( ! heap_size ) { - DBG ( "No external heap available\n" ); - return -ENOMEM; - } +static void init_eheap ( void ) { + userptr_t base; + heap_size = largest_memblock ( &base ); + bottom = top = userptr_add ( base, heap_size ); DBG ( "External heap grows downwards from %lx (size %zx)\n", user_to_phys ( top, 0 ), heap_size ); - return 0; } /** @@ -144,13 +106,10 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { struct external_memory extmem; userptr_t new = ptr; size_t align; - int rc; - /* Initialise external memory allocator if necessary */ - if ( bottom == top ) { - if ( ( rc = init_eheap() ) != 0 ) - return UNULL; - } + /* (Re)initialise external memory allocator if necessary */ + if ( bottom == top ) + init_eheap(); /* Get block properties into extmem */ if ( ptr && ( ptr != UNOWHERE ) ) { diff --git a/src/core/memblock.c b/src/core/memblock.c new file mode 100644 index 00000000..1fd89b87 --- /dev/null +++ b/src/core/memblock.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Largest memory block + * + */ + +#include +#include +#include +#include + +/** + * Find largest usable memory region + * + * @ret start Start of region + * @ret len Length of region + */ +size_t largest_memblock ( userptr_t *start ) { + struct memory_map memmap; + struct memory_region *region; + physaddr_t max = ~( ( physaddr_t ) 0 ); + physaddr_t region_start; + physaddr_t region_end; + size_t region_len; + unsigned int i; + size_t len = 0; + + /* Avoid returning uninitialised data on error */ + *start = UNULL; + + /* Scan through all memory regions */ + get_memmap ( &memmap ); + for ( i = 0 ; i < memmap.count ; i++ ) { + region = &memmap.regions[i]; + DBG ( "Considering [%llx,%llx)\n", region->start, region->end ); + + /* Truncate block to maximum physical address */ + if ( region->start > max ) { + DBG ( "...starts after maximum address %lx\n", max ); + continue; + } + region_start = region->start; + if ( region->end > max ) { + DBG ( "...end truncated to maximum address %lx\n", max); + region_end = 0; /* =max, given the wraparound */ + } else { + region_end = region->end; + } + region_len = ( region_end - region_start ); + + /* Use largest block */ + if ( region_len > len ) { + DBG ( "...new best block found\n" ); + *start = phys_to_user ( region_start ); + len = region_len; + } + } + + return len; +} diff --git a/src/include/ipxe/memblock.h b/src/include/ipxe/memblock.h new file mode 100644 index 00000000..13af3e43 --- /dev/null +++ b/src/include/ipxe/memblock.h @@ -0,0 +1,17 @@ +#ifndef _IPXE_MEMBLOCK_H +#define _IPXE_MEMBLOCK_H + +/** @file + * + * Largest memory block + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +extern size_t largest_memblock ( userptr_t *start ); + +#endif /* _IPXE_MEMBLOCK_H */