Add support for 32bit PCI BIOS entry.
[seabios.git] / src / pmm.c
index e90a7a8869bca16876f623449f7ccbbcc77f01e2..dab8fb36b13c48cf09813720e2680bd5af48b077 100644 (file)
--- a/src/pmm.c
+++ b/src/pmm.c
 #include "biosvar.h" // GET_BDA
 
 
-#if MODE16
+#if MODESEGMENT
 // The 16bit pmm entry points runs in "big real" mode, and can
 // therefore read/write to the 32bit malloc variables.
-#define GET_PMMVAR(var) GET_FARVAR(0, (var))
-#define SET_PMMVAR(var, val) SET_FARVAR(0, (var), (val))
+#define GET_PMMVAR(var) ({                      \
+            SET_SEG(ES, 0);                     \
+            __GET_VAR("addr32 ", ES, (var)); })
+#define SET_PMMVAR(var, val) do {               \
+        SET_SEG(ES, 0);                         \
+        __SET_VAR("addr32 ", ES, (var), (val)); \
+    } while (0)
 #else
 #define GET_PMMVAR(var) (var)
 #define SET_PMMVAR(var, val) do { (var) = (val); } while (0)
@@ -26,11 +31,11 @@ struct zone_s {
     u32 top, bottom, cur;
 };
 
-struct zone_s ZoneLow VAR32VISIBLE, ZoneHigh VAR32VISIBLE;
-struct zone_s ZoneFSeg VAR32VISIBLE;
-struct zone_s ZoneTmpLow VAR32VISIBLE, ZoneTmpHigh VAR32VISIBLE;
+struct zone_s ZoneLow VAR32FLATVISIBLE, ZoneHigh VAR32FLATVISIBLE;
+struct zone_s ZoneFSeg VAR32FLATVISIBLE;
+struct zone_s ZoneTmpLow VAR32FLATVISIBLE, ZoneTmpHigh VAR32FLATVISIBLE;
 
-struct zone_s *Zones[] VAR32VISIBLE = {
+struct zone_s *Zones[] VAR32FLATVISIBLE = {
     &ZoneTmpLow, &ZoneLow, &ZoneFSeg, &ZoneTmpHigh, &ZoneHigh
 };
 
@@ -49,7 +54,7 @@ relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size)
         return -1;
 
     // Do copy
-    if (MODE16)
+    if (MODESEGMENT)
         memcpy_far(FLATPTR_TO_SEG(newebda)
                    , (void*)FLATPTR_TO_OFFSET(newebda)
                    , FLATPTR_TO_SEG(oldebda)
@@ -66,33 +71,38 @@ relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size)
 }
 
 // Support expanding the ZoneLow dynamically.
-static int
+static void
 zonelow_expand(u32 size, u32 align)
 {
+    u32 oldpos = GET_PMMVAR(ZoneLow.cur);
+    u32 newpos = ALIGN_DOWN(oldpos - size, align);
+    u32 bottom = GET_PMMVAR(ZoneLow.bottom);
+    if (newpos >= bottom && newpos <= oldpos)
+        // Space already present.
+        return;
     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)
+    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);
+        oldpos = ebda_end;
+        newpos = ALIGN_DOWN(oldpos - 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 -1;
+        return;
 
     // Move ebda
     int ret = relocate_ebda(newebda, ebda_pos, ebda_size);
     if (ret)
-        return ret;
+        return;
 
     // Update zone
+    SET_PMMVAR(ZoneLow.cur, oldpos);
     SET_PMMVAR(ZoneLow.bottom, newbottom);
-    return 0;
 }
 
 
@@ -101,7 +111,7 @@ zonelow_expand(u32 size, u32 align)
  ****************************************************************/
 
 // Obtain memory from a given zone.
-void *
+static void *
 zone_malloc(struct zone_s *zone, u32 size, u32 align)
 {
     u32 oldpos = GET_PMMVAR(zone->cur);
@@ -113,15 +123,6 @@ zone_malloc(struct zone_s *zone, u32 size, u32 align)
     return (void*)newpos;
 }
 
-// Return memory to a zone (if it was the last to be allocated).
-static void
-zone_free(struct zone_s *zone, void *data, u32 olddata)
-{
-    if (! data || GET_PMMVAR(zone->cur) != (u32)data)
-        return;
-    SET_PMMVAR(zone->cur, olddata);
-}
-
 // Find the zone that contains the given data block.
 static struct zone_s *
 zone_find(void *data)
@@ -136,6 +137,17 @@ zone_find(void *data)
     return NULL;
 }
 
+// Return memory to a zone (if it was the last to be allocated).
+static int
+zone_free(void *data, u32 olddata)
+{
+    struct zone_s *zone = zone_find(data);
+    if (!zone || !data || GET_PMMVAR(zone->cur) != (u32)data)
+        return -1;
+    SET_PMMVAR(zone->cur, olddata);
+    return 0;
+}
+
 // Report the status of all the zones.
 static void
 dumpZones()
@@ -151,78 +163,9 @@ dumpZones()
     }
 }
 
-void
-malloc_setup()
-{
-    ASSERT32();
-    dprintf(3, "malloc setup\n");
-
-    // Memory in 0xf0000 area.
-    memset(BiosTableSpace, 0, CONFIG_MAX_BIOSTABLE);
-    ZoneFSeg.bottom = (u32)BiosTableSpace;
-    ZoneFSeg.top = ZoneFSeg.cur = ZoneFSeg.bottom + CONFIG_MAX_BIOSTABLE;
-
-    // Memory under 1Meg.
-    ZoneTmpLow.bottom = BUILD_STACK_ADDR;
-    ZoneTmpLow.top = ZoneTmpLow.cur = BUILD_EBDA_MINIMUM;
-
-    // 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);
-    if (!e) {
-        // No memory above 1Meg
-        memset(&ZoneHigh, 0, sizeof(ZoneHigh));
-        memset(&ZoneTmpHigh, 0, sizeof(ZoneTmpHigh));
-        return;
-    }
-    u32 top = e->start + e->size, bottom = e->start;
-
-    // Memory at top of ram.
-    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 = ALIGN(bottom, MALLOC_MIN_ALIGN);
-    ZoneTmpHigh.top = ZoneTmpHigh.cur = ZoneHigh.bottom;
-}
-
-void
-malloc_finalize()
-{
-    dprintf(3, "malloc finalize\n");
-
-    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);
-    dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback);
-
-    // Clear low-memory allocations.
-    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
+ * tracked memory allocations
  ****************************************************************/
 
 // Information on PMM tracked allocations
@@ -234,32 +177,27 @@ struct pmmalloc_s {
     struct pmmalloc_s *next;
 };
 
-struct pmmalloc_s *PMMAllocs VAR32VISIBLE;
-
-// Memory zone that pmm allocation tracking info is stored in
-#define ZONEALLOC (&ZoneTmpHigh)
+struct pmmalloc_s *PMMAllocs VAR32FLATVISIBLE;
 
 // Allocate memory from the given zone and track it as a PMM allocation
-static void *
+void *
 pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align)
 {
-    u32 oldallocdata = GET_PMMVAR(ZONEALLOC->cur);
-    struct pmmalloc_s *info = zone_malloc(ZONEALLOC, sizeof(*info)
+    u32 oldallocdata = GET_PMMVAR(ZoneTmpHigh.cur);
+    struct pmmalloc_s *info = zone_malloc(&ZoneTmpHigh, sizeof(*info)
                                           , MALLOC_MIN_ALIGN);
-    if (!info)
-        return NULL;
+    if (!info) {
+        oldallocdata = GET_PMMVAR(ZoneTmpLow.cur);
+        info = zone_malloc(&ZoneTmpLow, sizeof(*info), MALLOC_MIN_ALIGN);
+        if (!info)
+            return NULL;
+    }
+    if (zone == &ZoneLow)
+        zonelow_expand(size, align);
     u32 olddata = GET_PMMVAR(zone->cur);
     void *data = zone_malloc(zone, size, align);
-#if 0  // XXX - gcc4.3 internal compiler error - disable for now
-    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);
-    }
-#endif
     if (! data) {
-        zone_free(ZONEALLOC, info, oldallocdata);
+        zone_free(info, oldallocdata);
         return NULL;
     }
     dprintf(8, "pmm_malloc zone=%p handle=%x size=%d align=%x"
@@ -277,12 +215,12 @@ pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align)
 
 // Free a raw data block (either from a zone or from pmm alloc list).
 static void
-pmm_free_data(struct zone_s *zone, void *data, u32 olddata)
+pmm_free_data(void *data, u32 olddata)
 {
-    if (GET_PMMVAR(zone->cur) == (u32)data) {
-        zone_free(zone, data, olddata);
+    int ret = zone_free(data, olddata);
+    if (!ret)
+        // Success - done.
         return;
-    }
     struct pmmalloc_s *info;
     for (info=GET_PMMVAR(PMMAllocs); info; info = GET_PMMVAR(info->next))
         if (GET_PMMVAR(info->olddata) == (u32)data) {
@@ -295,12 +233,9 @@ pmm_free_data(struct zone_s *zone, void *data, u32 olddata)
 }
 
 // Free a data block allocated with pmm_malloc
-static int
+int
 pmm_free(void *data)
 {
-    struct zone_s *zone = zone_find(GET_PMMVAR(data));
-    if (!zone)
-        return -1;
     struct pmmalloc_s **pinfo = &PMMAllocs;
     for (;;) {
         struct pmmalloc_s *info = GET_PMMVAR(*pinfo);
@@ -310,12 +245,10 @@ pmm_free(void *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(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);
+            pmm_free_data(data, olddata);
+            pmm_free_data(info, oldallocdata);
+            dprintf(8, "pmm_free data=%p olddata=%p oldallocdata=%p info=%p\n"
+                    , data, (void*)olddata, (void*)oldallocdata, info);
             return 0;
         }
         pinfo = &info->next;
@@ -328,8 +261,9 @@ 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)
+    if (zone != &ZoneTmpHigh && zone != &ZoneTmpLow)
         return space;
+    // Account for space needed for PMM tracking.
     u32 reserve = ALIGN(sizeof(struct pmmalloc_s), MALLOC_MIN_ALIGN);
     if (space <= reserve)
         return 0;
@@ -347,6 +281,71 @@ pmm_find(u32 handle)
     return NULL;
 }
 
+void
+malloc_setup()
+{
+    ASSERT32FLAT();
+    dprintf(3, "malloc setup\n");
+
+    PMMAllocs = NULL;
+
+    // Memory in 0xf0000 area.
+    extern u8 code32flat_start[];
+    if ((u32)code32flat_start > BUILD_BIOS_ADDR)
+        // Clear unused parts of f-segment
+        memset((void*)BUILD_BIOS_ADDR, 0
+               , (u32)code32flat_start - BUILD_BIOS_ADDR);
+    memset(BiosTableSpace, 0, CONFIG_MAX_BIOSTABLE);
+    ZoneFSeg.bottom = (u32)BiosTableSpace;
+    ZoneFSeg.top = ZoneFSeg.cur = ZoneFSeg.bottom + CONFIG_MAX_BIOSTABLE;
+
+    // Memory under 1Meg.
+    ZoneTmpLow.bottom = BUILD_STACK_ADDR;
+    ZoneTmpLow.top = ZoneTmpLow.cur = BUILD_EBDA_MINIMUM;
+
+    // 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);
+    if (!e) {
+        // No memory above 1Meg
+        memset(&ZoneHigh, 0, sizeof(ZoneHigh));
+        memset(&ZoneTmpHigh, 0, sizeof(ZoneTmpHigh));
+        return;
+    }
+    u32 top = e->start + e->size, bottom = e->start;
+
+    // Memory at top of ram.
+    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 = ALIGN(bottom, MALLOC_MIN_ALIGN);
+    ZoneTmpHigh.top = ZoneTmpHigh.cur = ZoneHigh.bottom;
+}
+
+void
+malloc_finalize()
+{
+    dprintf(3, "malloc finalize\n");
+
+    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);
+    dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback);
+
+    // Clear low-memory allocations.
+    memset((void*)ZoneTmpLow.bottom, 0, ZoneTmpLow.top - ZoneTmpLow.bottom);
+}
+
 
 /****************************************************************
  * pmm interface
@@ -441,7 +440,7 @@ handle_pmm01(u16 *args)
 {
     u32 handle = *(u32*)&args[1];
     dprintf(3, "pmm01: handle=%x\n", handle);
-    if (handle == 0xFFFFFFFF)
+    if (handle == PMM_DEFAULT_HANDLE)
         return 0;
     return (u32)pmm_find(handle);
 }
@@ -493,8 +492,6 @@ pmm_setup()
 
     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));