aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2009-09-24 20:51:55 -0400
committerKevin O'Connor <kevin@koconnor.net>2009-09-24 20:51:55 -0400
commitf416fe97ae885e97a4c9678813a6005aa83fb4b6 (patch)
tree1f2ff3388802e8329cf30e9ba0f9c05e3ec94972 /src
parent34ec7b0a5ab55399653cfef4e50570bda2b9ffb2 (diff)
downloadseabios-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.h4
-rw-r--r--src/config.h2
-rw-r--r--src/pmm.c100
-rw-r--r--src/post.c4
-rw-r--r--src/util.h4
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
diff --git a/src/pmm.c b/src/pmm.c
index 1732c69b..6ce6c6fd 100644
--- a/src/pmm.c
+++ b/src/pmm.c
@@ -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;
diff --git a/src/post.c b/src/post.c
index e2569b0c..c21b46e6 100644
--- a/src/post.c
+++ b/src/post.c
@@ -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();
diff --git a/src/util.h b/src/util.h
index 7601b482..a74bdec1 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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);
}