diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2013-08-07 23:03:47 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2013-08-10 13:05:39 -0400 |
commit | 2b0fb8c5032fb3590b1325ce6f128ef0af606465 (patch) | |
tree | 8f3bf271b76cc84b35fa1d5ccfd737534ec2fe21 /src | |
parent | fd459e8a3e11c0b84e0f031c249512145c25b2a8 (diff) | |
download | seabios-hppa-2b0fb8c5032fb3590b1325ce6f128ef0af606465.zip seabios-hppa-2b0fb8c5032fb3590b1325ce6f128ef0af606465.tar.gz seabios-hppa-2b0fb8c5032fb3590b1325ce6f128ef0af606465.tar.bz2 |
Add config option to support memory allocations in 9-segment.
Internal "low memory" allocations are currently placed in the UMB
region (0xc0000-0xf0000). However, there have been reports of some
real machines that do not support DMA to this area of memory. So, add
a compile time config option (off by default) to support placing all
internal low-memory allocations at the end of the 640K real-memory
area (0x90000-0xa0000).
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src')
-rw-r--r-- | src/Kconfig | 9 | ||||
-rw-r--r-- | src/pmm.c | 113 | ||||
-rw-r--r-- | src/post.c | 10 | ||||
-rw-r--r-- | src/shadow.c | 4 | ||||
-rw-r--r-- | src/stacks.c | 3 |
5 files changed, 125 insertions, 14 deletions
diff --git a/src/Kconfig b/src/Kconfig index 3a4d580..3a7d6bd 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -113,6 +113,15 @@ endchoice adversely impact any legacy operating systems that call the BIOS in 16bit protected mode. + config MALLOC_UPPERMEMORY + bool "Allocate memory that needs to be in first Meg above 0xc0000" + default y + help + Use the "Upper Memory Block" area (0xc0000-0xf0000) for + internal "low memory" allocations. If this is not + selected, the memory is instead allocated from the + "9-segment" (0x90000-0xa0000). + endmenu menu "Hardware support" @@ -146,6 +146,78 @@ findLast(struct zone_s *zone) /**************************************************************** + * 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 ****************************************************************/ @@ -169,6 +241,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; @@ -255,8 +329,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. @@ -270,6 +348,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; @@ -394,8 +477,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[]; @@ -411,13 +500,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); @@ -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 242f220..966e88d 100644 --- a/src/shadow.c +++ b/src/shadow.c @@ -80,9 +80,11 @@ make_bios_readonly_intel(u16 bdf, u32 pam0) wbinvd(); // Write protect roms from 0xc0000-0xf0000 - u32 romlast = BUILD_BIOS_ADDR, rommax = rom_get_max(); + u32 romlast = BUILD_BIOS_ADDR, rommax = BUILD_BIOS_ADDR; if (CONFIG_WRITABLE_UPPERMEMORY) romlast = rom_get_last(); + if (CONFIG_MALLOC_UPPERMEMORY) + rommax = 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 0640a30..ac75497 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -464,7 +464,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(); |