Fix some PMM corner-cases.
Make sure not to divide by zero when calculating usage percent in
debug messages.
Make sure high memory zones are aligned; make sure zone is big enough
even after loss due to alignment.
Be sure to reset ZoneTmpHigh and PMMAllocs on failure paths.
Fix corner case in pmm_free() where an allocation might not get freed
due to ordering of pmmalloc_s structs.
diff --git a/src/pmm.c b/src/pmm.c
index 3e08da1..b3eef4b 100644
--- a/src/pmm.c
+++ b/src/pmm.c
@@ -81,8 +81,9 @@
struct zone_s *zone = Zones[i];
u32 used = zone->top - zone->cur;
u32 avail = zone->top - zone->bottom;
+ u32 pct = avail ? ((100 * used) / avail) : 0;
dprintf(2, "zone %d: %08x-%08x used=%d (%d%%)\n"
- , i, zone->bottom, zone->top, used, (100 * used) / avail);
+ , i, zone->bottom, zone->top, used, pct);
}
}
@@ -122,7 +123,7 @@
struct e820entry *e = &e820_list[i];
u64 end = e->start + e->size;
if (e->type != E820_RAM || end > 0xffffffff
- || e->size < CONFIG_MAX_HIGHTABLE)
+ || e->size < CONFIG_MAX_HIGHTABLE + MALLOC_MIN_ALIGN)
continue;
top = end;
bottom = e->start;
@@ -131,16 +132,17 @@
if (top < 1024*1024 + CONFIG_MAX_HIGHTABLE) {
// No memory above 1Meg
memset(&ZoneHigh, 0, sizeof(ZoneHigh));
+ memset(&ZoneTmpHigh, 0, sizeof(ZoneHigh));
return;
}
// Memory at top of ram.
- ZoneHigh.bottom = top - CONFIG_MAX_HIGHTABLE;
+ ZoneHigh.bottom = ALIGN(top - CONFIG_MAX_HIGHTABLE, MALLOC_MIN_ALIGN);
ZoneHigh.top = ZoneHigh.cur = ZoneHigh.bottom + CONFIG_MAX_HIGHTABLE;
add_e820(ZoneHigh.bottom, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
// Memory above 1Meg
- ZoneTmpHigh.bottom = bottom;
+ ZoneTmpHigh.bottom = ALIGN(bottom, MALLOC_MIN_ALIGN);
ZoneTmpHigh.top = ZoneTmpHigh.cur = ZoneHigh.bottom;
}
@@ -170,25 +172,28 @@
void *data;
u32 olddata;
u32 handle;
+ u32 oldallocdata;
struct pmmalloc_s *next;
};
struct pmmalloc_s *PMMAllocs VAR32VISIBLE;
-#define PMMALLOCSIZE ALIGN(sizeof(struct pmmalloc_s), MALLOC_MIN_ALIGN)
+// Memory zone that pmm allocation tracking info is stored in
+#define ZONEALLOC (&ZoneTmpHigh)
// Allocate memory from the given zone and track it as a PMM allocation
static void *
pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align)
{
- struct pmmalloc_s *info = zone_malloc(&ZoneTmpHigh, sizeof(*info)
+ u32 oldallocdata = GET_PMMVAR(ZONEALLOC->cur);
+ struct pmmalloc_s *info = zone_malloc(ZONEALLOC, sizeof(*info)
, MALLOC_MIN_ALIGN);
if (!info)
return NULL;
u32 olddata = GET_PMMVAR(zone->cur);
void *data = zone_malloc(zone, size, align);
if (! data) {
- zone_free(&ZoneTmpHigh, info, (u32)info + PMMALLOCSIZE);
+ zone_free(ZONEALLOC, info, oldallocdata);
return NULL;
}
dprintf(8, "pmm_malloc zone=%p handle=%x size=%d align=%x"
@@ -198,6 +203,7 @@
SET_PMMVAR(info->data, data);
SET_PMMVAR(info->olddata, olddata);
SET_PMMVAR(info->handle, handle);
+ SET_PMMVAR(info->oldallocdata, oldallocdata);
SET_PMMVAR(info->next, GET_PMMVAR(PMMAllocs));
SET_PMMVAR(PMMAllocs, info);
return data;
@@ -216,6 +222,9 @@
if (GET_PMMVAR(info->olddata) == (u32)data) {
SET_PMMVAR(info->olddata, olddata);
return;
+ } else if (GET_PMMVAR(info->oldallocdata) == (u32)data) {
+ SET_PMMVAR(info->oldallocdata, olddata);
+ return;
}
}
@@ -233,16 +242,18 @@
return -1;
if (GET_PMMVAR(info->data) == data) {
SET_PMMVAR(*pinfo, GET_PMMVAR(info->next));
+ u32 oldallocdata = GET_PMMVAR(info->oldallocdata);
u32 olddata = GET_PMMVAR(info->olddata);
pmm_free_data(zone, data, olddata);
- pmm_free_data(&ZoneTmpHigh, info, (u32)info + PMMALLOCSIZE);
- dprintf(8, "pmm_free data=%p zone=%p olddata=%p info=%p\n"
- , data, zone, (void*)olddata, info);
+ pmm_free_data(ZONEALLOC, info, oldallocdata);
+ dprintf(8, "pmm_free data=%p zone=%p olddata=%p oldallocdata=%p"
+ " info=%p\n"
+ , data, zone, (void*)olddata, (void*)oldallocdata
+ , info);
return 0;
}
pinfo = &info->next;
}
- return -1;
}
// Find the amount of free space in a given zone.
@@ -250,9 +261,12 @@
pmm_getspace(struct zone_s *zone)
{
u32 space = GET_PMMVAR(zone->cur) - GET_PMMVAR(zone->bottom);
- if (space <= PMMALLOCSIZE)
+ if (zone != ZONEALLOC)
+ return space;
+ u32 reserve = ALIGN(sizeof(struct pmmalloc_s), MALLOC_MIN_ALIGN);
+ if (space <= reserve)
return 0;
- return space - PMMALLOCSIZE;
+ return space - reserve;
}
// Find the data block allocated with pmm_malloc with a given handle.
@@ -406,6 +420,8 @@
dprintf(3, "init PMM\n");
+ PMMAllocs = NULL;
+
PMMHEADER.signature = PMM_SIGNATURE;
PMMHEADER.entry_offset = (u32)entry_pmm - BUILD_BIOS_ADDR;
PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER));