SeaBIOS v1.7.0 and earlier had an allocator that would reserve memory in the "9-segment" - memory at the end of the first 640K. (Subsequent versions of SeaBIOS allocate ram for "low memory" in the e-segment.) I recently revived the 9-segment code for testing purposes. I don't plan to commit this to the SeaBIOS repo - I'm posting it here in case there is interest. It is also available at:
https://github.com/KevinOConnor/seabios/tree/test-9segment-20130223
-Kevin
From 3608cf00a12c33f03c8dcb3f3ba272effdf3dfb7 Mon Sep 17 00:00:00 2001
From: Kevin O'Connor kevin@koconnor.net Date: Mon, 18 Feb 2013 10:45:39 -0500 Subject: [PATCH] Revive 9-segment allocator. To: seabios@seabios.org
May be useful for testing.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/Kconfig | 9 +++++ src/pmm.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/post.c | 10 +++-- src/shadow.c | 4 +- src/stacks.c | 3 +- tools/layoutrom.py | 9 +++-- 6 files changed, 131 insertions(+), 17 deletions(-)
diff --git a/src/Kconfig b/src/Kconfig index 98a6642..c88aaec 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -104,6 +104,15 @@ endchoice help Support floppy images in coreboot flash.
+ config MALLOC_UPPERMEMORY + bool "Allocate memory that needs to be in first Meg above 0xc0000" + default y + help + Use the "Upper Memory Block" area for internal "low + memory" allocations. If this is not selected, the memory + is instead allocated between 0x90000-0xa0000 (the + "9-segment"). + endmenu
menu "Hardware support" diff --git a/src/pmm.c b/src/pmm.c index f02cf62..829547f 100644 --- a/src/pmm.c +++ b/src/pmm.c @@ -174,8 +174,12 @@ static struct allocinfo_s *RomBase; u32 rom_get_max(void) { - return ALIGN_DOWN((u32)RomBase->allocend - OPROM_HEADER_RESERVE - , OPTION_ROM_ALIGN); + if (CONFIG_MALLOC_UPPERMEMORY) + return ALIGN_DOWN((u32)RomBase->allocend - OPROM_HEADER_RESERVE + , OPTION_ROM_ALIGN); + extern u8 code32init_end[]; + u32 end = (u32)code32init_end; + return end > BUILD_BIOS_ADDR ? BUILD_BIOS_ADDR : end; }
// Return the end of the last deployed option rom. @@ -189,6 +193,11 @@ rom_get_last(void) struct rom_header * rom_reserve(u32 size) { + if (!CONFIG_MALLOC_UPPERMEMORY) { + if (RomEnd + size > rom_get_max()) + return NULL; + return (void*)RomEnd; + } u32 newend = ALIGN(RomEnd + size, OPTION_ROM_ALIGN) + OPROM_HEADER_RESERVE; if (newend > (u32)RomBase->allocend) return NULL; @@ -313,8 +322,14 @@ malloc_init(void) // Initialize low-memory region extern u8 varlow_start[], varlow_end[], final_varlow_start[]; memmove(final_varlow_start, varlow_start, varlow_end - varlow_start); - addSpace(&ZoneLow, zonelow_base + OPROM_HEADER_RESERVE, final_varlow_start); - RomBase = findLast(&ZoneLow); + if (CONFIG_MALLOC_UPPERMEMORY) { + addSpace(&ZoneLow, zonelow_base + OPROM_HEADER_RESERVE + , final_varlow_start); + RomBase = findLast(&ZoneLow); + } else { + addSpace(&ZoneLow, (void*)ALIGN_DOWN((u32)final_varlow_start, 1024) + , final_varlow_start); + }
// Add space available in f-segment to ZoneFSeg extern u8 zonefseg_start[], zonefseg_end[]; @@ -330,13 +345,19 @@ malloc_prepboot(void) ASSERT32FLAT(); dprintf(3, "malloc finalize\n");
- // Place an optionrom signature around used low mem area. u32 base = rom_get_max(); - struct rom_header *dummyrom = (void*)base; - dummyrom->signature = OPTION_ROM_SIGNATURE; - int size = (BUILD_BIOS_ADDR - base) / 512; - dummyrom->size = (size > 255) ? 255 : size; memset((void*)RomEnd, 0, base-RomEnd); + if (CONFIG_MALLOC_UPPERMEMORY) { + // Place an optionrom signature around used low mem area. + struct rom_header *dummyrom = (void*)base; + dummyrom->signature = OPTION_ROM_SIGNATURE; + int size = (BUILD_BIOS_ADDR - base) / 512; + dummyrom->size = (size > 255) ? 255 : size; + } + + // Reserve more low-mem if needed. + u32 endlow = GET_BDA(mem_size_kb)*1024; + add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
// Clear unused f-seg ram. struct allocinfo_s *info = findLast(&ZoneFSeg); @@ -357,6 +378,78 @@ malloc_prepboot(void)
/**************************************************************** + * ebda movement + ****************************************************************/ + +// Move ebda +static int +relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size) +{ + u32 lowram = GET_BDA(mem_size_kb) * 1024; + if (oldebda != lowram) + // EBDA isn't at end of ram - give up. + return -1; + + // Do copy + memmove((void*)newebda, (void*)oldebda, ebda_size * 1024); + + // Update indexes + dprintf(1, "ebda moved from %x to %x\n", oldebda, newebda); + SET_BDA(mem_size_kb, newebda / 1024); + SET_BDA(ebda_seg, FLATPTR_TO_SEG(newebda)); + return 0; +} + +// Support expanding the ZoneLow dynamically. +static void * +zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill) +{ + // Make sure to not move ebda while an optionrom is running. + if (unlikely(wait_preempt())) { + void *data = allocSpace(&ZoneLow, size, align, fill); + if (data) + return data; + } + + struct allocinfo_s *info = findLast(&ZoneLow); + if (!info) + return NULL; + u32 oldpos = (u32)info->allocend; + u32 newpos = ALIGN_DOWN(oldpos - size, align); + u32 bottom = (u32)info->dataend; + if (newpos >= bottom && newpos <= oldpos) + // Space already present. + return allocSpace(&ZoneLow, size, align, fill); + u16 ebda_seg = get_ebda_seg(); + u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0); + u8 ebda_size = GET_EBDA(ebda_seg, size); + u32 ebda_end = ebda_pos + ebda_size * 1024; + if (ebda_end != bottom) + // Something else is after ebda - can't use any existing space. + newpos = ALIGN_DOWN(ebda_end - size, align); + u32 newbottom = ALIGN_DOWN(newpos, 1024); + u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024); + if (newebda < BUILD_EBDA_MINIMUM) + // Not enough space. + return NULL; + + // Move ebda + int ret = relocate_ebda(newebda, ebda_pos, ebda_size); + if (ret) + return NULL; + + // Update zone + if (ebda_end == bottom) { + info->data = (void*)newbottom; + info->dataend = (void*)newbottom; + } else + addSpace(&ZoneLow, (void*)newbottom, (void*)ebda_end); + + return allocSpace(&ZoneLow, size, align, fill); +} + + +/**************************************************************** * tracked memory allocations ****************************************************************/
@@ -380,6 +473,8 @@ pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align)
// Find and reserve space for main allocation void *data = allocSpace(zone, size, align, &detail->datainfo); + if (!CONFIG_MALLOC_UPPERMEMORY && !data && zone == &ZoneLow) + data = zonelow_expand(size, align, &detail->datainfo); if (!data) { freeSpace(&detail->detailinfo); return NULL; diff --git a/src/post.c b/src/post.c index 44bb0b0..70a3be6 100644 --- a/src/post.c +++ b/src/post.c @@ -85,17 +85,21 @@ bda_init(void) memset(bda, 0, sizeof(*bda));
int esize = EBDA_SIZE_START; - SET_BDA(mem_size_kb, BUILD_LOWRAM_END/1024 - esize); u16 ebda_seg = EBDA_SEGMENT_START; + extern u8 final_varlow_start[]; + if (!CONFIG_MALLOC_UPPERMEMORY) + ebda_seg = FLATPTR_TO_SEG(ALIGN_DOWN((u32)final_varlow_start, 1024) + - EBDA_SIZE_START*1024); SET_BDA(ebda_seg, ebda_seg);
+ SET_BDA(mem_size_kb, ebda_seg / (1024/16)); + // Init ebda struct extended_bios_data_area_s *ebda = get_ebda_ptr(); memset(ebda, 0, sizeof(*ebda)); ebda->size = esize;
- add_e820((u32)MAKE_FLATPTR(ebda_seg, 0), GET_EBDA(ebda_seg, size) * 1024 - , E820_RESERVED); + add_e820((u32)ebda, BUILD_LOWRAM_END-(u32)ebda, E820_RESERVED);
// Init extra stack StackPos = (void*)(&ExtraStack[BUILD_EXTRA_STACK_SIZE] - zonelow_base); diff --git a/src/shadow.c b/src/shadow.c index e971fe9..5bb1bd7 100644 --- a/src/shadow.c +++ b/src/shadow.c @@ -80,7 +80,9 @@ make_bios_readonly_intel(u16 bdf, u32 pam0) wbinvd();
// Write protect roms from 0xc0000-0xf0000 - u32 romend = rom_get_last(), romtop = rom_get_max(); + u32 romend = rom_get_last(), romtop = BUILD_BIOS_ADDR; + if (CONFIG_MALLOC_UPPERMEMORY) + romtop = rom_get_max(); int i; for (i=0; i<6; i++) { u32 mem = BUILD_ROM_START + i * 32*1024; diff --git a/src/stacks.c b/src/stacks.c index 7423939..3d49d35 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -456,7 +456,8 @@ finish_preempt(void) int wait_preempt(void) { - if (MODESEGMENT || !CONFIG_THREAD_OPTIONROMS || !CanPreempt) + if (MODESEGMENT || !CONFIG_THREAD_OPTIONROMS || !CanPreempt + || getesp() < 1024*1024) return 0; while (CanPreempt) yield(); diff --git a/tools/layoutrom.py b/tools/layoutrom.py index 6e1c588..d45a37e 100755 --- a/tools/layoutrom.py +++ b/tools/layoutrom.py @@ -238,10 +238,13 @@ def doLayout(sections): # Determine "low memory" data positions li.sections32low = getSectionsCategory(sections, '32low') sec32low_end = li.sec32init_start - final_sec32low_start = min(BUILD_BIOS_ADDR, li.sec32flat_start) - relocdelta = final_sec32low_start - sec32low_end - zonelow_base = final_sec32low_start - 64*1024 + final_sec32low_end = min(BUILD_BIOS_ADDR, li.sec32flat_start) + relocdelta = final_sec32low_end - sec32low_end + zonelow_base = final_sec32low_end - 64*1024 li.zonelow_base = max(BUILD_ROM_START, alignpos(zonelow_base, 2*1024)) + if '.bss.RomBase' not in dict([(s.name, '') for s in sections]): #XXX + relocdelta = 0xa0000 - sec32low_end + li.zonelow_base = 0x90000 li.sec32low_start, li.sec32low_align = setSectionsStart( li.sections32low, sec32low_end, 16 , segoffset=li.zonelow_base - relocdelta)