diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2009-09-24 20:51:55 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2009-09-24 20:51:55 -0400 |
commit | f416fe97ae885e97a4c9678813a6005aa83fb4b6 (patch) | |
tree | 1f2ff3388802e8329cf30e9ba0f9c05e3ec94972 /src | |
parent | 34ec7b0a5ab55399653cfef4e50570bda2b9ffb2 (diff) | |
download | seabios-f416fe97ae885e97a4c9678813a6005aa83fb4b6.tar.gz |
Add support for permanent low memory allocations.
Support pmm style permanent low-memory allocations.
When used, relocate ebda and store permanent memory at top of 640K.
Diffstat (limited to 'src')
-rw-r--r-- | src/biosvar.h | 4 | ||||
-rw-r--r-- | src/config.h | 2 | ||||
-rw-r--r-- | src/pmm.c | 100 | ||||
-rw-r--r-- | src/post.c | 4 | ||||
-rw-r--r-- | src/util.h | 4 |
5 files changed, 101 insertions, 13 deletions
diff --git a/src/biosvar.h b/src/biosvar.h index 9ed02a33..983d28fb 100644 --- a/src/biosvar.h +++ b/src/biosvar.h @@ -228,9 +228,7 @@ struct extended_bios_data_area_s { #define EBDA_SIZE_START \ DIV_ROUND_UP(sizeof(struct extended_bios_data_area_s), 1024) #define EBDA_SEGMENT_START \ - FLATPTR_TO_SEG((640 - EBDA_SIZE_START) * 1024) -#define EBDA_SEGMENT_MINIMUM \ - FLATPTR_TO_SEG((640 - 256) * 1024) + FLATPTR_TO_SEG(BUILD_LOWRAM_END - EBDA_SIZE_START*1024) // Accessor functions static inline u16 get_ebda_seg() { diff --git a/src/config.h b/src/config.h index 494fe8d5..df10bbe4 100644 --- a/src/config.h +++ b/src/config.h @@ -123,6 +123,8 @@ #define BUILD_STACK_ADDR 0x7c00 #define BUILD_S3RESUME_STACK_ADDR 0x1000 #define BUILD_AP_BOOT_ADDR 0x10000 +#define BUILD_EBDA_MINIMUM 0x90000 +#define BUILD_LOWRAM_END 0xa0000 #define BUILD_ROM_START 0xc0000 #define BUILD_BIOS_ADDR 0xf0000 #define BUILD_BIOS_SIZE 0x10000 @@ -8,13 +8,9 @@ #include "config.h" // BUILD_BIOS_ADDR #include "memmap.h" // find_high_area #include "farptr.h" // GET_FARVAR -#include "biosvar.h" // EBDA_SEGMENT_MINIMUM +#include "biosvar.h" // GET_BDA -/**************************************************************** - * malloc - ****************************************************************/ - #if MODE16 // The 16bit pmm entry points runs in "big real" mode, and can // therefore read/write to the 32bit malloc variables. @@ -38,6 +34,72 @@ struct zone_s *Zones[] VAR32VISIBLE = { &ZoneTmpLow, &ZoneLow, &ZoneFSeg, &ZoneTmpHigh, &ZoneHigh }; + +/**************************************************************** + * 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 + if (MODE16) + memcpy_far(FLATPTR_TO_SEG(newebda) + , (void*)FLATPTR_TO_OFFSET(newebda) + , FLATPTR_TO_SEG(oldebda) + , (void*)FLATPTR_TO_OFFSET(oldebda) + , ebda_size * 1024); + else + 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 int +zonelow_expand(u32 size, u32 align) +{ + u16 ebda_seg = get_ebda_seg(); + u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0); + u32 bottom = GET_PMMVAR(ZoneLow.bottom); + u32 cur = GET_PMMVAR(ZoneLow.cur); + u8 ebda_size = GET_EBDA2(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. + cur = ebda_end; + u32 newcur = ALIGN_DOWN(cur - size, align); + u32 newbottom = ALIGN_DOWN(newcur, 1024); + u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024); + if (newebda < BUILD_EBDA_MINIMUM) + // Not enough space. + return -1; + + // Move ebda + int ret = relocate_ebda(newebda, ebda_pos, ebda_size); + if (ret) + return ret; + + // Update zone + SET_PMMVAR(ZoneLow.bottom, newbottom); + return 0; +} + + +/**************************************************************** + * zone allocations + ****************************************************************/ + // Obtain memory from a given zone. void * zone_malloc(struct zone_s *zone, u32 size, u32 align) @@ -102,10 +164,10 @@ malloc_setup() // Memory under 1Meg. ZoneTmpLow.bottom = BUILD_STACK_ADDR; - ZoneTmpLow.top = ZoneTmpLow.cur = (u32)MAKE_FLATPTR(EBDA_SEGMENT_MINIMUM, 0); + ZoneTmpLow.top = ZoneTmpLow.cur = BUILD_EBDA_MINIMUM; - // Permanent memory under 1Meg. XXX - not implemented yet. - ZoneLow.bottom = ZoneLow.top = ZoneLow.cur = 0xa0000; + // Permanent memory under 1Meg. + ZoneLow.bottom = ZoneLow.top = ZoneLow.cur = BUILD_LOWRAM_END; // Find memory at the top of ram. struct e820entry *e = find_high_area(CONFIG_MAX_HIGHTABLE+MALLOC_MIN_ALIGN); @@ -134,6 +196,10 @@ malloc_finalize() dumpZones(); + // Reserve more low-mem if needed. + u32 endlow = GET_BDA(mem_size_kb)*1024; + add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED); + // Give back unused high ram. u32 giveback = ALIGN_DOWN(ZoneHigh.cur - ZoneHigh.bottom, PAGE_SIZE); add_e820(ZoneHigh.bottom, giveback, E820_RAM); @@ -143,6 +209,17 @@ malloc_finalize() memset((void*)ZoneTmpLow.bottom, 0, ZoneTmpLow.top - ZoneTmpLow.bottom); } +// Allocate memory from ZoneLow - growing the zone if needed. +void * +zone_malloc_low(u32 size, u32 align) +{ + void *ret = zone_malloc(&ZoneLow, size, align); + if (ret) + return ret; + zonelow_expand(size, align); + return zone_malloc(&ZoneLow, size, align); +} + /**************************************************************** * pmm allocation @@ -173,6 +250,12 @@ pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align) return NULL; u32 olddata = GET_PMMVAR(zone->cur); void *data = zone_malloc(zone, size, align); + if (!data && zone == &ZoneLow) { + // Try to expand permanent low zone. + zonelow_expand(size, align); + olddata = GET_PMMVAR(zone->cur); + data = zone_malloc(zone, size, align); + } if (! data) { zone_free(ZONEALLOC, info, oldallocdata); return NULL; @@ -241,6 +324,7 @@ pmm_free(void *data) static u32 pmm_getspace(struct zone_s *zone) { + // XXX - doesn't account for ZoneLow being able to grow. u32 space = GET_PMMVAR(zone->cur) - GET_PMMVAR(zone->bottom); if (zone != ZONEALLOC) return space; @@ -78,7 +78,7 @@ init_bda() memset(bda, 0, sizeof(*bda)); int esize = EBDA_SIZE_START; - SET_BDA(mem_size_kb, 640 - esize); + SET_BDA(mem_size_kb, BUILD_LOWRAM_END/1024 - esize); u16 eseg = EBDA_SEGMENT_START; SET_BDA(ebda_seg, eseg); @@ -119,7 +119,7 @@ ram_probe(void) } // Don't declare any memory between 0xa0000 and 0x100000 - add_e820(0xa0000, 0x50000, E820_HOLE); + add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE); // Mark known areas as reserved. u16 ebda_seg = get_ebda_seg(); @@ -260,6 +260,7 @@ void pnp_setup(); // pmm.c extern struct zone_s ZoneLow, ZoneHigh, ZoneFSeg, ZoneTmpLow, ZoneTmpHigh; void *zone_malloc(struct zone_s *zone, u32 size, u32 align); +void *zone_malloc_low(u32 size, u32 align); void malloc_setup(); void malloc_finalize(); void pmm_setup(); @@ -267,6 +268,9 @@ void pmm_finalize(); // Minimum alignment of malloc'd memory #define MALLOC_MIN_ALIGN 16 // Helper functions for memory allocation. +static inline void *malloc_low(u32 size) { + return zone_malloc_low(size, MALLOC_MIN_ALIGN); +} static inline void *malloc_high(u32 size) { return zone_malloc(&ZoneHigh, size, MALLOC_MIN_ALIGN); } |