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 --- Makefile | 2 +- src/Kconfig | 9 +++++ src/pmm.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/post.c | 10 +++-- src/shadow.c | 4 +- src/stacks.c | 3 +- tools/layoutrom.py | 36 ++++++++++++++--- 7 files changed, 156 insertions(+), 21 deletions(-)
diff --git a/Makefile b/Makefile index 00ef346..2116407 100644 --- a/Makefile +++ b/Makefile @@ -148,7 +148,7 @@ $(OUT)romlayout16.lds: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)ccode16.o $(O $(Q)$(OBJDUMP) -thr $(OUT)code32flat.o > $(OUT)code32flat.o.objdump $(Q)$(OBJDUMP) -thr $(OUT)code32seg.o > $(OUT)code32seg.o.objdump $(Q)$(OBJDUMP) -thr $(OUT)code16.o > $(OUT)code16.o.objdump - $(Q)$(PYTHON) ./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32seg.o.objdump $(OUT)code32flat.o.objdump $(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds + $(Q)$(PYTHON) ./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32seg.o.objdump $(OUT)code32flat.o.objdump $(OUT)$(KCONFIG_AUTOHEADER) $(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds
# These are actually built by tools/layoutrom.py above, but by pulling them # into an extra rule we prevent make -j from spawning layoutrom.py 4 times. 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" diff --git a/src/pmm.c b/src/pmm.c index 8f993fd..1c8da1e 100644 --- a/src/pmm.c +++ b/src/pmm.c @@ -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); diff --git a/src/post.c b/src/post.c index d706d4f..27f5709 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 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(); diff --git a/tools/layoutrom.py b/tools/layoutrom.py index 20b9716..17330ae 100755 --- a/tools/layoutrom.py +++ b/tools/layoutrom.py @@ -59,6 +59,7 @@ def setSectionsStart(sections, endaddr, minalign=1, segoffset=0): BUILD_BIOS_ADDR = 0xf0000 BUILD_BIOS_SIZE = 0x10000 BUILD_ROM_START = 0xc0000 +BUILD_LOWRAM_END = 0xa0000 # Space to reserve in f-segment for dynamic allocations BUILD_MIN_BIOSTABLE = 2048
@@ -166,7 +167,7 @@ class LayoutInfo: exportsyms = varlowsyms = None
# Determine final memory addresses for sections -def doLayout(sections): +def doLayout(sections, config): li = LayoutInfo() # Determine 16bit positions li.sections16 = getSectionsCategory(sections, '16') @@ -238,10 +239,14 @@ def doLayout(sections): # Determine "low memory" data positions li.sections32low = getSectionsCategory(sections, '32low') sec32low_end = li.sec32init_start - final_sec32low_end = min(BUILD_BIOS_ADDR, li.sec32flat_start) + if config.get('CONFIG_MALLOC_UPPERMEMORY'): + final_sec32low_end = min(BUILD_BIOS_ADDR, li.sec32flat_start) + zonelow_base = final_sec32low_end - 64*1024 + li.zonelow_base = max(BUILD_ROM_START, alignpos(zonelow_base, 2*1024)) + else: + final_sec32low_end = BUILD_LOWRAM_END + li.zonelow_base = final_sec32low_end - 64*1024 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)) li.sec32low_start, li.sec32low_align = setSectionsStart( li.sections32low, sec32low_end, 16 , segoffset=li.zonelow_base - relocdelta) @@ -620,9 +625,25 @@ def parseObjDump(file, fileid): pass return sections, symbols
+# Parser for constants in simple C header files. +def scanconfig(file): + f = open(file, 'rb') + opts = {} + for l in f.readlines(): + parts = l.split() + if len(parts) != 3: + continue + if parts[0] != '#define': + continue + value = parts[2] + if value.isdigit() or (value.startswith('0x') and value[2:].isdigit()): + value = int(value, 0) + opts[parts[1]] = value + return opts + def main(): # Get output name - in16, in32seg, in32flat, out16, out32seg, out32flat = sys.argv[1:] + in16, in32seg, in32flat, cfgfile, out16, out32seg, out32flat = sys.argv[1:]
# Read in the objdump information infile16 = open(in16, 'rb') @@ -634,6 +655,9 @@ def main(): info32seg = parseObjDump(infile32seg, '32seg') info32flat = parseObjDump(infile32flat, '32flat')
+ # Read kconfig config file + config = scanconfig(cfgfile) + # Figure out which sections to keep. sections = gc(info16, info32seg, info32flat)
@@ -648,7 +672,7 @@ def main(): section.category = '32fseg'
# Determine the final memory locations of each kept section. - li = doLayout(sections) + li = doLayout(sections, config) li.genreloc = genreloc
# Exported symbols