mirror of
https://github.com/ipxe/ipxe
synced 2026-02-14 02:31:26 +03:00
[bios] Use generic external heap based on the system memory map
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -29,7 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
#include <ipxe/image.h>
|
#include <ipxe/image.h>
|
||||||
#include <ipxe/uaccess.h>
|
#include <ipxe/uaccess.h>
|
||||||
#include <ipxe/init.h>
|
#include <ipxe/init.h>
|
||||||
#include <ipxe/memblock.h>
|
#include <ipxe/memmap.h>
|
||||||
#include <ipxe/cpio.h>
|
#include <ipxe/cpio.h>
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -287,7 +287,6 @@ int initrd_reshuffle_check ( size_t len, physaddr_t bottom ) {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void initrd_startup ( void ) {
|
static void initrd_startup ( void ) {
|
||||||
void *bottom;
|
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
/* Record largest memory block available. Do this after any
|
/* Record largest memory block available. Do this after any
|
||||||
@@ -297,9 +296,10 @@ static void initrd_startup ( void ) {
|
|||||||
* but before any allocations for downloaded images (which we
|
* but before any allocations for downloaded images (which we
|
||||||
* can safely reuse when rearranging).
|
* can safely reuse when rearranging).
|
||||||
*/
|
*/
|
||||||
len = largest_memblock ( &bottom );
|
len = memmap_largest ( &initrd_bottom );
|
||||||
initrd_bottom = virt_to_phys ( bottom );
|
|
||||||
initrd_top = ( initrd_bottom + len );
|
initrd_top = ( initrd_bottom + len );
|
||||||
|
DBGC ( &images, "INITRD largest memory block is [%#08lx,%#08lx)\n",
|
||||||
|
initrd_bottom, initrd_top );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** initrd startup function */
|
/** initrd startup function */
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ERRFILE_memtop_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 )
|
|
||||||
#define ERRFILE_int15 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 )
|
#define ERRFILE_int15 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 )
|
||||||
#define ERRFILE_pnpbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 )
|
#define ERRFILE_pnpbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 )
|
||||||
#define ERRFILE_bios_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
|
#define ERRFILE_bios_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef _BITS_UMALLOC_H
|
|
||||||
#define _BITS_UMALLOC_H
|
|
||||||
|
|
||||||
/** @file
|
|
||||||
*
|
|
||||||
* x86-specific user memory allocation API implementations
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
||||||
|
|
||||||
#include <ipxe/memtop_umalloc.h>
|
|
||||||
|
|
||||||
#endif /* _BITS_UMALLOC_H */
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
#ifndef _IPXE_MEMTOP_UMALLOC_H
|
|
||||||
#define _IPXE_MEMTOP_UMALLOC_H
|
|
||||||
|
|
||||||
/** @file
|
|
||||||
*
|
|
||||||
* External memory allocation
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
||||||
|
|
||||||
#ifdef UMALLOC_MEMTOP
|
|
||||||
#define UMALLOC_PREFIX_memtop
|
|
||||||
#else
|
|
||||||
#define UMALLOC_PREFIX_memtop __memtop_
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _IPXE_MEMTOP_UMALLOC_H */
|
|
||||||
@@ -139,8 +139,8 @@ static void int15_sync ( void ) {
|
|||||||
* umalloc region), which must be placed before the hidden
|
* umalloc region), which must be placed before the hidden
|
||||||
* textdata region (even if zero-length).
|
* textdata region (even if zero-length).
|
||||||
*/
|
*/
|
||||||
start = umalloc_used.start;
|
start = uheap_used.start;
|
||||||
size = umalloc_used.size;
|
size = uheap_used.size;
|
||||||
if ( ! size )
|
if ( ! size )
|
||||||
start = virt_to_phys ( _textdata );
|
start = virt_to_phys ( _textdata );
|
||||||
hide_region ( &hidemem_umalloc, start, ( start + size ) );
|
hide_region ( &hidemem_umalloc, start, ( start + size ) );
|
||||||
|
|||||||
@@ -1,246 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*
|
|
||||||
* You can also choose to distribute this program under the terms of
|
|
||||||
* the Unmodified Binary Distribution Licence (as given in the file
|
|
||||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
|
||||||
*/
|
|
||||||
|
|
||||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
*
|
|
||||||
* External memory allocation
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <ipxe/uaccess.h>
|
|
||||||
#include <ipxe/memblock.h>
|
|
||||||
#include <ipxe/memmap.h>
|
|
||||||
#include <ipxe/umalloc.h>
|
|
||||||
|
|
||||||
/** Maximum usable address for external allocated memory */
|
|
||||||
#define EM_MAX_ADDRESS 0xffffffffUL
|
|
||||||
|
|
||||||
/** Alignment of external allocated memory */
|
|
||||||
#define EM_ALIGN ( 4 * 1024 )
|
|
||||||
|
|
||||||
/** An external memory block */
|
|
||||||
struct external_memory {
|
|
||||||
/** Size of this memory block (excluding this header) */
|
|
||||||
size_t size;
|
|
||||||
/** Block is currently in use */
|
|
||||||
int used;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Top of heap */
|
|
||||||
static void *top = NULL;
|
|
||||||
|
|
||||||
/** Bottom of heap (current lowest allocated block) */
|
|
||||||
static void *bottom = NULL;
|
|
||||||
|
|
||||||
/** Remaining space on heap */
|
|
||||||
static size_t heap_size;
|
|
||||||
|
|
||||||
/** In-use memory region */
|
|
||||||
struct used_region umalloc_used __used_region = {
|
|
||||||
.name = "umalloc",
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hide umalloc() region
|
|
||||||
*
|
|
||||||
* @v start Start of region
|
|
||||||
* @v end End of region
|
|
||||||
*/
|
|
||||||
static void hide_umalloc ( physaddr_t start, physaddr_t end ) {
|
|
||||||
|
|
||||||
memmap_use ( &umalloc_used, start, ( end - start ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find largest usable memory region
|
|
||||||
*
|
|
||||||
* @ret start Start of region
|
|
||||||
* @ret len Length of region
|
|
||||||
*/
|
|
||||||
size_t largest_memblock ( void **start ) {
|
|
||||||
struct memmap_region region;
|
|
||||||
physaddr_t max = EM_MAX_ADDRESS;
|
|
||||||
physaddr_t region_start;
|
|
||||||
physaddr_t region_end;
|
|
||||||
size_t region_len;
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
/* Avoid returning uninitialised data on error */
|
|
||||||
*start = NULL;
|
|
||||||
|
|
||||||
/* Scan through all memory regions */
|
|
||||||
for_each_memmap ( ®ion, 1 ) {
|
|
||||||
|
|
||||||
/* Truncate block to maximum physical address */
|
|
||||||
memmap_dump ( ®ion );
|
|
||||||
if ( region.addr > max ) {
|
|
||||||
DBGC ( ®ion, "...starts after maximum address "
|
|
||||||
"%lx\n", max );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
region_start = region.addr;
|
|
||||||
if ( ! memmap_is_usable ( ®ion ) )
|
|
||||||
continue;
|
|
||||||
region_end = ( region_start + memmap_size ( ®ion ) );
|
|
||||||
if ( region_end > max ) {
|
|
||||||
DBGC ( ®ion, "...end truncated to maximum address "
|
|
||||||
"%lx\n", max);
|
|
||||||
region_end = 0; /* =max, given the wraparound */
|
|
||||||
}
|
|
||||||
region_len = ( region_end - region_start );
|
|
||||||
|
|
||||||
/* Use largest block */
|
|
||||||
if ( region_len > len ) {
|
|
||||||
DBG ( "...new best block found\n" );
|
|
||||||
*start = phys_to_virt ( region_start );
|
|
||||||
len = region_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise external heap
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void init_eheap ( void ) {
|
|
||||||
void *base;
|
|
||||||
|
|
||||||
heap_size = largest_memblock ( &base );
|
|
||||||
bottom = top = ( base + heap_size );
|
|
||||||
DBG ( "External heap grows downwards from %lx (size %zx)\n",
|
|
||||||
virt_to_phys ( top ), heap_size );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Collect free blocks
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void ecollect_free ( void ) {
|
|
||||||
struct external_memory extmem;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
/* Walk the free list and collect empty blocks */
|
|
||||||
while ( bottom != top ) {
|
|
||||||
memcpy ( &extmem, ( bottom - sizeof ( extmem ) ),
|
|
||||||
sizeof ( extmem ) );
|
|
||||||
if ( extmem.used )
|
|
||||||
break;
|
|
||||||
DBG ( "EXTMEM freeing [%lx,%lx)\n", virt_to_phys ( bottom ),
|
|
||||||
( virt_to_phys ( bottom ) + extmem.size ) );
|
|
||||||
len = ( extmem.size + sizeof ( extmem ) );
|
|
||||||
bottom += len;
|
|
||||||
heap_size += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reallocate external memory
|
|
||||||
*
|
|
||||||
* @v old_ptr Memory previously allocated by umalloc(), or NULL
|
|
||||||
* @v new_size Requested size
|
|
||||||
* @ret new_ptr Allocated memory, or NULL
|
|
||||||
*
|
|
||||||
* Calling realloc() with a new size of zero is a valid way to free a
|
|
||||||
* memory block.
|
|
||||||
*/
|
|
||||||
static void * memtop_urealloc ( void *ptr, size_t new_size ) {
|
|
||||||
struct external_memory extmem;
|
|
||||||
void *new = ptr;
|
|
||||||
size_t align;
|
|
||||||
|
|
||||||
/* (Re)initialise external memory allocator if necessary */
|
|
||||||
if ( bottom == top )
|
|
||||||
init_eheap();
|
|
||||||
|
|
||||||
/* Get block properties into extmem */
|
|
||||||
if ( ptr && ( ptr != NOWHERE ) ) {
|
|
||||||
/* Determine old size */
|
|
||||||
memcpy ( &extmem, ( ptr - sizeof ( extmem ) ),
|
|
||||||
sizeof ( extmem ) );
|
|
||||||
} else {
|
|
||||||
/* Create a zero-length block */
|
|
||||||
if ( heap_size < sizeof ( extmem ) ) {
|
|
||||||
DBG ( "EXTMEM out of space\n" );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ptr = bottom = ( bottom - sizeof ( extmem ) );
|
|
||||||
heap_size -= sizeof ( extmem );
|
|
||||||
DBG ( "EXTMEM allocating [%lx,%lx)\n",
|
|
||||||
virt_to_phys ( ptr ), virt_to_phys ( ptr ) );
|
|
||||||
extmem.size = 0;
|
|
||||||
}
|
|
||||||
extmem.used = ( new_size > 0 );
|
|
||||||
|
|
||||||
/* Expand/shrink block if possible */
|
|
||||||
if ( ptr == bottom ) {
|
|
||||||
/* Update block */
|
|
||||||
new = ( ptr - ( new_size - extmem.size ) );
|
|
||||||
align = ( virt_to_phys ( new ) & ( EM_ALIGN - 1 ) );
|
|
||||||
new_size += align;
|
|
||||||
new -= align;
|
|
||||||
if ( new_size > ( heap_size + extmem.size ) ) {
|
|
||||||
DBG ( "EXTMEM out of space\n" );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n",
|
|
||||||
virt_to_phys ( ptr ),
|
|
||||||
( virt_to_phys ( ptr ) + extmem.size ),
|
|
||||||
virt_to_phys ( new ),
|
|
||||||
( virt_to_phys ( new ) + new_size ) );
|
|
||||||
memmove ( new, ptr, ( ( extmem.size < new_size ) ?
|
|
||||||
extmem.size : new_size ) );
|
|
||||||
bottom = new;
|
|
||||||
heap_size -= ( new_size - extmem.size );
|
|
||||||
extmem.size = new_size;
|
|
||||||
} else {
|
|
||||||
/* Cannot expand; can only pretend to shrink */
|
|
||||||
if ( new_size > extmem.size ) {
|
|
||||||
/* Refuse to expand */
|
|
||||||
DBG ( "EXTMEM cannot expand [%lx,%lx)\n",
|
|
||||||
virt_to_phys ( ptr ),
|
|
||||||
( virt_to_phys ( ptr ) + extmem.size ) );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write back block properties */
|
|
||||||
memcpy ( ( new - sizeof ( extmem ) ), &extmem, sizeof ( extmem ) );
|
|
||||||
|
|
||||||
/* Collect any free blocks and update hidden memory region */
|
|
||||||
ecollect_free();
|
|
||||||
hide_umalloc ( ( virt_to_phys ( bottom ) -
|
|
||||||
( ( bottom == top ) ? 0 : sizeof ( extmem ) ) ),
|
|
||||||
virt_to_phys ( top ) );
|
|
||||||
|
|
||||||
return ( new_size ? new : NOWHERE );
|
|
||||||
}
|
|
||||||
|
|
||||||
PROVIDE_UMALLOC ( memtop, urealloc, memtop_urealloc );
|
|
||||||
@@ -16,7 +16,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
#define TIMER_PCBIOS
|
#define TIMER_PCBIOS
|
||||||
#define CONSOLE_PCBIOS
|
#define CONSOLE_PCBIOS
|
||||||
#define NAP_PCBIOS
|
#define NAP_PCBIOS
|
||||||
#define UMALLOC_MEMTOP
|
#define UMALLOC_UHEAP
|
||||||
#define MEMMAP_INT15
|
#define MEMMAP_INT15
|
||||||
#define SMBIOS_PCBIOS
|
#define SMBIOS_PCBIOS
|
||||||
#define SANBOOT_PCBIOS
|
#define SANBOOT_PCBIOS
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
#ifndef _IPXE_MEMBLOCK_H
|
|
||||||
#define _IPXE_MEMBLOCK_H
|
|
||||||
|
|
||||||
/** @file
|
|
||||||
*
|
|
||||||
* Largest memory block
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
extern size_t largest_memblock ( void **start );
|
|
||||||
|
|
||||||
#endif /* _IPXE_MEMBLOCK_H */
|
|
||||||
@@ -228,7 +228,7 @@ static inline void memmap_dump_all ( int hide ) {
|
|||||||
memmap_dump ( ®ion );
|
memmap_dump ( ®ion );
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct used_region umalloc_used __used_region;
|
extern struct used_region uheap_used __used_region;
|
||||||
|
|
||||||
extern void memmap_update ( struct memmap_region *region, uint64_t start,
|
extern void memmap_update ( struct memmap_region *region, uint64_t start,
|
||||||
uint64_t size, unsigned int flags,
|
uint64_t size, unsigned int flags,
|
||||||
|
|||||||
Reference in New Issue
Block a user