Add malloc_high/fseg() and rework bios table creation to use them.

Add malloc like functions for memory management instead of open-coding
    memory reservation in all callers.
Add ability for unused high ram to be returned for general purpose use.
Break up acpi table creation into multiple functions.
Also, move smbios tables into high ram (instead of f-segment).
diff --git a/src/acpi.c b/src/acpi.c
index 72977b1..bafdd6b 100644
--- a/src/acpi.c
+++ b/src/acpi.c
@@ -1,13 +1,13 @@
 // Support for generating ACPI tables (on emulators)
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
 // Copyright (C) 2006 Fabrice Bellard
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
 #include "acpi.h" // struct rsdp_descriptor
 #include "util.h" // memcpy
-#include "memmap.h" // bios_table_cur_addr
+#include "memmap.h" // malloc_fseg
 #include "pci.h" // pci_find_device
 #include "biosvar.h" // GET_EBDA
 #include "pci_ids.h" // PCI_VENDOR_ID_INTEL
@@ -44,7 +44,7 @@
 struct rsdt_descriptor_rev1
 {
     ACPI_TABLE_HEADER_DEF       /* ACPI common table header */
-    u32 table_offset_entry [3]; /* Array of pointers to other */
+    u32 table_offset_entry[3];  /* Array of pointers to other */
     /* ACPI tables */
 } PACKED;
 
@@ -224,8 +224,9 @@
     return x;
 }
 
-static void acpi_build_table_header(struct acpi_table_header *h,
-                                    u32 sig, int len, u8 rev)
+static void
+build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev
+             , struct rsdt_descriptor_rev1 *rsdt)
 {
     h->signature = sig;
     h->length = cpu_to_le32(len);
@@ -237,153 +238,44 @@
     h->oem_revision = cpu_to_le32(1);
     h->asl_compiler_revision = cpu_to_le32(1);
     h->checksum -= checksum(h, len);
+
+    // Add to rsdt table
+    if (!rsdt)
+        return;
+    if (rsdt->length >= sizeof(*rsdt)) {
+        dprintf(1, "No more room for rsdt entry!\n");
+        return;
+    }
+    u32 *p = (void*)rsdt + rsdt->length;
+    *p = (u32)h;
+    rsdt->length += sizeof(*p);
 }
 
-#define SSDT_SIGNATURE 0x54445353// SSDT
-static int
-acpi_build_processor_ssdt(u8 *ssdt)
+static void
+build_fadt(struct rsdt_descriptor_rev1 *rsdt, int bdf)
 {
-    u8 *ssdt_ptr = ssdt;
-    int i, length;
-    int smp_cpus = CountCPUs;
-    int acpi_cpus = smp_cpus > 0xff ? 0xff : smp_cpus;
+    struct fadt_descriptor_rev1 *fadt = malloc_high(sizeof(*fadt));
+    struct facs_descriptor_rev1 *facs = malloc_high(sizeof(*facs) + 63);
+    void *dsdt = malloc_high(sizeof(AmlCode));
 
-    ssdt_ptr[9] = 0; // checksum;
-    ssdt_ptr += sizeof(struct acpi_table_header);
-
-    // caluculate the length of processor block and scope block excluding PkgLength
-    length = 0x0d * acpi_cpus + 4;
-
-    // build processor scope header
-    *(ssdt_ptr++) = 0x10; // ScopeOp
-    if (length <= 0x3e) {
-        *(ssdt_ptr++) = length + 1;
-    } else {
-        *(ssdt_ptr++) = 0x7F;
-        *(ssdt_ptr++) = (length + 2) >> 6;
-    }
-    *(ssdt_ptr++) = '_'; // Name
-    *(ssdt_ptr++) = 'P';
-    *(ssdt_ptr++) = 'R';
-    *(ssdt_ptr++) = '_';
-
-    // build object for each processor
-    for(i=0;i<acpi_cpus;i++) {
-        *(ssdt_ptr++) = 0x5B; // ProcessorOp
-        *(ssdt_ptr++) = 0x83;
-        *(ssdt_ptr++) = 0x0B; // Length
-        *(ssdt_ptr++) = 'C';  // Name (CPUxx)
-        *(ssdt_ptr++) = 'P';
-        if ((i & 0xf0) != 0)
-            *(ssdt_ptr++) = (i >> 4) < 0xa ? (i >> 4) + '0' : (i >> 4) + 'A' - 0xa;
-        else
-            *(ssdt_ptr++) = 'U';
-        *(ssdt_ptr++) = (i & 0xf) < 0xa ? (i & 0xf) + '0' : (i & 0xf) + 'A' - 0xa;
-        *(ssdt_ptr++) = i;
-        *(ssdt_ptr++) = 0x10; // Processor block address
-        *(ssdt_ptr++) = 0xb0;
-        *(ssdt_ptr++) = 0;
-        *(ssdt_ptr++) = 0;
-        *(ssdt_ptr++) = 6;    // Processor block length
+    if (!fadt || !facs || !dsdt) {
+        dprintf(1, "Not enough memory for fadt!\n");
+        return;
     }
 
-    acpi_build_table_header((struct acpi_table_header *)ssdt,
-                            SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
+    /* FACS */
+    facs = (void*)ALIGN((u32)facs, 64);
+    memset(facs, 0, sizeof(*facs));
+    facs->signature = FACS_SIGNATURE;
+    facs->length = cpu_to_le32(sizeof(*facs));
 
-    return ssdt_ptr - ssdt;
-}
-
-struct rsdp_descriptor *RsdpAddr;
-
-/* base_addr must be a multiple of 4KB */
-void acpi_bios_init(void)
-{
-    if (! CONFIG_ACPI)
-        return;
-
-    dprintf(3, "init ACPI tables\n");
-
-    // This code is hardcoded for PIIX4 Power Management device.
-    int bdf = pci_find_device(PCI_VENDOR_ID_INTEL
-                              , PCI_DEVICE_ID_INTEL_82371AB_3);
-    if (bdf < 0)
-        // Device not found
-        return;
-
-    struct rsdp_descriptor *rsdp;
-    struct rsdt_descriptor_rev1 *rsdt;
-    struct fadt_descriptor_rev1 *fadt;
-    struct facs_descriptor_rev1 *facs;
-    struct multiple_apic_table *madt;
-    u8 *dsdt, *ssdt;
-    u32 base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr, ssdt_addr;
-    u32 acpi_tables_size, madt_addr, madt_size;
-    int i;
-
-    /* reserve memory space for tables */
-    bios_table_cur_addr = ALIGN(bios_table_cur_addr, 16);
-    rsdp = (void *)bios_table_cur_addr;
-    bios_table_cur_addr += sizeof(*rsdp);
-
-    addr = base_addr = RamSize - CONFIG_ACPI_DATA_SIZE;
-    add_e820(addr, CONFIG_ACPI_DATA_SIZE, E820_ACPI);
-    rsdt_addr = addr;
-    rsdt = (void *)(addr);
-    addr += sizeof(*rsdt);
-
-    fadt_addr = addr;
-    fadt = (void *)(addr);
-    addr += sizeof(*fadt);
-
-    addr = ALIGN(addr, 64);
-    facs_addr = addr;
-    facs = (void *)(addr);
-    addr += sizeof(*facs);
-
-    dsdt_addr = addr;
-    dsdt = (void *)(addr);
-    addr += sizeof(AmlCode);
-
-    ssdt_addr = addr;
-    ssdt = (void *)(addr);
-    addr += acpi_build_processor_ssdt(ssdt);
-
-    int smp_cpus = CountCPUs;
-    addr = ALIGN(addr, 8);
-    madt_addr = addr;
-    madt_size = sizeof(*madt) +
-        sizeof(struct madt_processor_apic) * smp_cpus +
-        sizeof(struct madt_io_apic);
-    madt = (void *)(addr);
-    addr += madt_size;
-
-    acpi_tables_size = addr - base_addr;
-
-    dprintf(1, "ACPI tables: RSDP addr=0x%08lx"
-            " ACPI DATA addr=0x%08lx size=0x%x\n",
-            (unsigned long)rsdp,
-            (unsigned long)rsdt, acpi_tables_size);
-
-    /* RSDP */
-    memset(rsdp, 0, sizeof(*rsdp));
-    rsdp->signature = RSDP_SIGNATURE;
-    memcpy(rsdp->oem_id, CONFIG_APPNAME6, 6);
-    rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
-    rsdp->checksum -= checksum(rsdp, 20);
-    RsdpAddr = rsdp;
-
-    /* RSDT */
-    memset(rsdt, 0, sizeof(*rsdt));
-    rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
-    rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
-    rsdt->table_offset_entry[2] = cpu_to_le32(ssdt_addr);
-    acpi_build_table_header((struct acpi_table_header *)rsdt,
-                            RSDT_SIGNATURE, sizeof(*rsdt), 1);
+    /* DSDT */
+    memcpy(dsdt, AmlCode, sizeof(AmlCode));
 
     /* FADT */
     memset(fadt, 0, sizeof(*fadt));
-    fadt->firmware_ctrl = cpu_to_le32(facs_addr);
-    fadt->dsdt = cpu_to_le32(dsdt_addr);
+    fadt->firmware_ctrl = cpu_to_le32((u32)facs);
+    fadt->dsdt = cpu_to_le32((u32)dsdt);
     fadt->model = 1;
     fadt->reserved1 = 0;
     int pm_sci_int = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
@@ -401,23 +293,29 @@
     fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
     /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */
     fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6));
-    acpi_build_table_header((struct acpi_table_header *)fadt, FACP_SIGNATURE,
-                            sizeof(*fadt), 1);
 
-    /* FACS */
-    memset(facs, 0, sizeof(*facs));
-    facs->signature = FACS_SIGNATURE;
-    facs->length = cpu_to_le32(sizeof(*facs));
+    build_header((void*)fadt, FACP_SIGNATURE, sizeof(*fadt), 1, rsdt);
+}
 
-    /* DSDT */
-    memcpy(dsdt, AmlCode, sizeof(AmlCode));
-
-    /* MADT */
+static void
+build_madt(struct rsdt_descriptor_rev1 *rsdt)
+{
+    int smp_cpus = CountCPUs;
+    int madt_size = (sizeof(struct multiple_apic_table)
+                     + sizeof(struct madt_processor_apic) * smp_cpus
+                     + sizeof(struct madt_io_apic)
+                     + sizeof(struct madt_intsrcovr) * 16);
+    struct multiple_apic_table *madt = malloc_high(madt_size);
+    if (!madt) {
+        dprintf(1, "Not enough memory for madt!\n");
+        return;
+    }
     memset(madt, 0, madt_size);
     madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
     madt->flags = cpu_to_le32(1);
-    struct madt_processor_apic *apic = (void *)&madt[1];
-    for(i=0;i<smp_cpus;i++) {
+    struct madt_processor_apic *apic = (void*)&madt[1];
+    int i;
+    for (i=0; i<smp_cpus; i++) {
         apic->type = APIC_PROCESSOR;
         apic->length = sizeof(*apic);
         apic->processor_id = i;
@@ -425,7 +323,7 @@
         apic->flags = cpu_to_le32(1);
         apic++;
     }
-    struct madt_io_apic *io_apic = (void *)apic;
+    struct madt_io_apic *io_apic = (void*)apic;
     io_apic->type = APIC_IO;
     io_apic->length = sizeof(*io_apic);
     io_apic->io_apic_id = smp_cpus;
@@ -444,11 +342,116 @@
         intsrcovr->gsi    = i;
         intsrcovr->flags  = 0xd; /* active high, level triggered */
         intsrcovr++;
-        madt_size += sizeof(struct madt_intsrcovr);
     }
 
-    acpi_build_table_header((struct acpi_table_header *)madt,
-                            APIC_SIGNATURE, madt_size, 1);
+    build_header((void*)madt, APIC_SIGNATURE, (void*)intsrcovr - (void*)madt
+                 , 1, rsdt);
+}
+
+#define SSDT_SIGNATURE 0x54445353 // SSDT
+static void
+build_ssdt(struct rsdt_descriptor_rev1 *rsdt)
+{
+    int smp_cpus = CountCPUs;
+    int acpi_cpus = smp_cpus > 0xff ? 0xff : smp_cpus;
+    // calculate the length of processor block and scope block
+    // excluding PkgLength
+    int cpu_length = 13 * acpi_cpus + 4;
+
+    int length = sizeof(struct acpi_table_header) + 3 + cpu_length;
+    u8 *ssdt = malloc_high(length);
+    if (! ssdt) {
+        dprintf(1, "No space for ssdt!\n");
+        return;
+    }
+
+    u8 *ssdt_ptr = ssdt;
+    ssdt_ptr[9] = 0; // checksum;
+    ssdt_ptr += sizeof(struct acpi_table_header);
+
+    // build processor scope header
+    *(ssdt_ptr++) = 0x10; // ScopeOp
+    if (cpu_length <= 0x3e) {
+        *(ssdt_ptr++) = cpu_length + 1;
+    } else {
+        *(ssdt_ptr++) = 0x7F;
+        *(ssdt_ptr++) = (cpu_length + 2) >> 6;
+    }
+    *(ssdt_ptr++) = '_'; // Name
+    *(ssdt_ptr++) = 'P';
+    *(ssdt_ptr++) = 'R';
+    *(ssdt_ptr++) = '_';
+
+    // build object for each processor
+    int i;
+    for (i=0; i<acpi_cpus; i++) {
+        *(ssdt_ptr++) = 0x5B; // ProcessorOp
+        *(ssdt_ptr++) = 0x83;
+        *(ssdt_ptr++) = 0x0B; // Length
+        *(ssdt_ptr++) = 'C';  // Name (CPUxx)
+        *(ssdt_ptr++) = 'P';
+        if ((i & 0xf0) != 0)
+            *(ssdt_ptr++) = (i >> 4) < 0xa ? (i >> 4) + '0' : (i >> 4) + 'A' - 0xa;
+        else
+            *(ssdt_ptr++) = 'U';
+        *(ssdt_ptr++) = (i & 0xf) < 0xa ? (i & 0xf) + '0' : (i & 0xf) + 'A' - 0xa;
+        *(ssdt_ptr++) = i;
+        *(ssdt_ptr++) = 0x10; // Processor block address
+        *(ssdt_ptr++) = 0xb0;
+        *(ssdt_ptr++) = 0;
+        *(ssdt_ptr++) = 0;
+        *(ssdt_ptr++) = 6;    // Processor block length
+    }
+
+    build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1, rsdt);
+}
+
+struct rsdp_descriptor *RsdpAddr;
+
+void
+acpi_bios_init(void)
+{
+    if (! CONFIG_ACPI)
+        return;
+
+    dprintf(3, "init ACPI tables\n");
+
+    // This code is hardcoded for PIIX4 Power Management device.
+    int bdf = pci_find_device(PCI_VENDOR_ID_INTEL
+                              , PCI_DEVICE_ID_INTEL_82371AB_3);
+    if (bdf < 0)
+        // Device not found
+        return;
+
+    // Create initial rsdt table
+    struct rsdt_descriptor_rev1 *rsdt = malloc_high(sizeof(*rsdt));
+    if (!rsdt) {
+        dprintf(1, "Not enough memory for acpi rsdt table!\n");
+        return;
+    }
+    memset(rsdt, 0, sizeof(*rsdt));
+    rsdt->length = offsetof(struct rsdt_descriptor_rev1, table_offset_entry[0]);
+
+    // Add tables
+    build_fadt(rsdt, bdf);
+    build_ssdt(rsdt);
+    build_madt(rsdt);
+
+    build_header((void*)rsdt, RSDT_SIGNATURE, rsdt->length, 1, NULL);
+
+    // Build rsdp pointer table
+    struct rsdp_descriptor *rsdp = malloc_fseg(sizeof(*rsdp));
+    if (!rsdp) {
+        dprintf(1, "Not enough memory for acpi rsdp!\n");
+        return;
+    }
+    memset(rsdp, 0, sizeof(*rsdp));
+    rsdp->signature = RSDP_SIGNATURE;
+    memcpy(rsdp->oem_id, CONFIG_APPNAME6, 6);
+    rsdp->rsdt_physical_address = cpu_to_le32((u32)rsdt);
+    rsdp->checksum -= checksum(rsdp, 20);
+    RsdpAddr = rsdp;
+    dprintf(1, "ACPI tables: RSDP=%p RSDT=%p\n", rsdp, rsdt);
 }
 
 u32
diff --git a/src/config.h b/src/config.h
index cba7ac4..3b4b5fe 100644
--- a/src/config.h
+++ b/src/config.h
@@ -98,12 +98,12 @@
 #define CONFIG_MAX_E820 32
 // Space to reserve in f-segment for run-time built bios tables.
 #define CONFIG_MAX_BIOSTABLE 2048
+// Space to reserve in high-memory for tables
+#define CONFIG_MAX_HIGHTABLE (64*1024)
 
 #define CONFIG_MAX_ATA_INTERFACES 4
 #define CONFIG_MAX_ATA_DEVICES  (CONFIG_MAX_ATA_INTERFACES*2)
 
-#define CONFIG_ACPI_DATA_SIZE 0x00010000L
-
 #define CONFIG_MODEL_ID      0xFC
 #define CONFIG_SUBMODEL_ID   0x00
 #define CONFIG_BIOS_REVISION 0x01
diff --git a/src/coreboot.c b/src/coreboot.c
index a760414..f99146e 100644
--- a/src/coreboot.c
+++ b/src/coreboot.c
@@ -1,6 +1,6 @@
 // Coreboot interface support.
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
@@ -11,6 +11,7 @@
 #include "mptable.h" // MPTABLE_SIGNATURE
 #include "biosvar.h" // GET_EBDA
 #include "lzmadecode.h" // LzmaDecode
+#include "memmap.h" // malloc_fseg
 
 
 /****************************************************************
@@ -29,15 +30,14 @@
         return;
     if (checksum(pos, p->size) != 0)
         return;
-    bios_table_cur_addr = ALIGN(bios_table_cur_addr, 16);
-    if (bios_table_cur_addr + p->size > bios_table_end_addr) {
+    void *newpos = malloc_fseg(p->size);
+    if (!newpos) {
         dprintf(1, "No room to copy PIR table!\n");
         return;
     }
-    dprintf(1, "Copying PIR from %p to %x\n", pos, bios_table_cur_addr);
-    memcpy((void*)bios_table_cur_addr, pos, p->size);
-    PirOffset = bios_table_cur_addr - BUILD_BIOS_ADDR;
-    bios_table_cur_addr += p->size;
+    dprintf(1, "Copying PIR from %p to %p\n", pos, newpos);
+    memcpy(newpos, pos, p->size);
+    PirOffset = (u32)newpos - BUILD_BIOS_ADDR;
 }
 
 static void
@@ -51,20 +51,17 @@
     if (checksum(pos, sizeof(*p)) != 0)
         return;
     u32 length = p->length * 16;
-    bios_table_cur_addr = ALIGN(bios_table_cur_addr, 16);
     u16 mpclength = ((struct mptable_config_s *)p->physaddr)->length;
-    if (bios_table_cur_addr + length + mpclength > bios_table_end_addr) {
+    struct mptable_floating_s *newpos = malloc_fseg(length + mpclength);
+    if (!newpos) {
         dprintf(1, "No room to copy MPTABLE!\n");
         return;
     }
-    dprintf(1, "Copying MPTABLE from %p/%x to %x\n"
-            , pos, p->physaddr, bios_table_cur_addr);
-    memcpy((void*)bios_table_cur_addr, pos, length);
-    struct mptable_floating_s *newp = (void*)bios_table_cur_addr;
-    newp->physaddr = bios_table_cur_addr + length;
-    newp->checksum -= checksum(newp, sizeof(*newp));
-    memcpy((void*)bios_table_cur_addr + length, (void*)p->physaddr, mpclength);
-    bios_table_cur_addr += length + mpclength;
+    dprintf(1, "Copying MPTABLE from %p/%x to %p\n", pos, p->physaddr, newpos);
+    memcpy(newpos, pos, length);
+    newpos->physaddr = (u32)newpos + length;
+    newpos->checksum -= checksum(newpos, sizeof(*newpos));
+    memcpy((void*)newpos + length, (void*)p->physaddr, mpclength);
 }
 
 static void
@@ -83,15 +80,14 @@
         if (checksum(pos, length) != 0)
             return;
     }
-    bios_table_cur_addr = ALIGN(bios_table_cur_addr, 16);
-    if (bios_table_cur_addr + length > bios_table_end_addr) {
+    void *newpos = malloc_fseg(length);
+    if (!newpos) {
         dprintf(1, "No room to copy ACPI RSDP table!\n");
         return;
     }
-    dprintf(1, "Copying ACPI RSDP from %p to %x\n", pos, bios_table_cur_addr);
-    RsdpAddr = (void*)bios_table_cur_addr;
-    memcpy(RsdpAddr, pos, length);
-    bios_table_cur_addr += length;
+    dprintf(1, "Copying ACPI RSDP from %p to %p\n", pos, newpos);
+    memcpy(newpos, pos, length);
+    RsdpAddr = newpos;
 }
 
 // Attempt to find (and relocate) any standard bios tables found in a
diff --git a/src/memmap.c b/src/memmap.c
index 65c9cd7..b8072ac 100644
--- a/src/memmap.c
+++ b/src/memmap.c
@@ -1,6 +1,6 @@
 // Support for building memory maps suitable for int 15 e820 calls.
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
@@ -8,6 +8,11 @@
 #include "util.h" // dprintf.h
 #include "biosvar.h" // SET_EBDA
 
+
+/****************************************************************
+ * e820 memory map
+ ****************************************************************/
+
 // Remove an entry from the e820_list.
 static void
 remove_e820(int i)
@@ -118,12 +123,6 @@
 void
 memmap_setup()
 {
-    memset(BiosTableSpace, 0, CONFIG_MAX_BIOSTABLE);
-    bios_table_cur_addr = (u32)BiosTableSpace;
-    bios_table_end_addr = bios_table_cur_addr + CONFIG_MAX_BIOSTABLE;
-    dprintf(1, "bios_table_addr: 0x%08x end=0x%08x\n",
-            bios_table_cur_addr, bios_table_end_addr);
-
     e820_count = 0;
 }
 
@@ -132,11 +131,89 @@
 memmap_finalize()
 {
     dump_map();
+}
 
-    dprintf(1, "final bios_table_addr: 0x%08x (used %d%%)\n"
-            , bios_table_cur_addr
-            , (100 * (bios_table_cur_addr - (u32)&BiosTableSpace)
-               / CONFIG_MAX_BIOSTABLE));
-    if (bios_table_cur_addr > bios_table_end_addr)
-        panic("bios_table_end_addr overflow!\n");
+
+/****************************************************************
+ * malloc
+ ****************************************************************/
+
+#define MINALIGN 16
+
+struct zone_s {
+    u32 top, bottom, cur;
+};
+
+static struct zone_s ZoneHigh, ZoneFSeg;
+
+static void *
+__malloc(struct zone_s *zone, u32 size)
+{
+    u32 newpos = (zone->cur - size) / MINALIGN * MINALIGN;
+    if (newpos < zone->bottom)
+        // No space
+        return NULL;
+    zone->cur = newpos;
+    return (void*)newpos;
+}
+
+// Allocate memory at the top of ram.
+void *
+malloc_high(u32 size)
+{
+    return __malloc(&ZoneHigh, size);
+}
+
+// Allocate memory in the 0xf0000-0x100000 area of ram.
+void *
+malloc_fseg(u32 size)
+{
+    return __malloc(&ZoneFSeg, size);
+}
+
+void
+malloc_setup()
+{
+    // Memory in 0xf0000 area.
+    memset(BiosTableSpace, 0, CONFIG_MAX_BIOSTABLE);
+    ZoneFSeg.bottom = (u32)BiosTableSpace;
+    ZoneFSeg.top = ZoneFSeg.cur = ZoneFSeg.bottom + CONFIG_MAX_BIOSTABLE;
+
+    // Find memory at the top of ram.
+    u32 top = 0;
+    int i;
+    for (i=e820_count-1; i>=0; i--) {
+        struct e820entry *e = &e820_list[i];
+        u64 end = e->start + e->size;
+        if (e->type != E820_RAM || end > 0xffffffff)
+            continue;
+        top = end;
+        break;
+    }
+    if (top < 1024*1024 + CONFIG_MAX_HIGHTABLE) {
+        // No memory above 1Meg
+        memset(&ZoneHigh, 0, sizeof(ZoneHigh));
+        return;
+    }
+    ZoneHigh.bottom = top - CONFIG_MAX_HIGHTABLE;
+    ZoneHigh.top = ZoneHigh.cur = ZoneHigh.bottom + CONFIG_MAX_HIGHTABLE;
+    add_e820(ZoneHigh.bottom, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
+}
+
+void
+malloc_finalize()
+{
+    // Give back unused high ram.
+    u32 giveback = (ZoneHigh.cur - ZoneHigh.bottom) / 4096 * 4096;
+    add_e820(ZoneHigh.bottom, giveback, E820_RAM);
+
+    // Report statistics
+    u32 used = ZoneFSeg.top - ZoneFSeg.cur;
+    u32 avail = ZoneFSeg.top - ZoneFSeg.bottom;
+    dprintf(1, "malloc_fseg used=%d (%d%%)\n"
+            , used, (100 * used) / avail);
+    used = ZoneHigh.top - ZoneHigh.cur;
+    avail = ZoneHigh.top - ZoneHigh.bottom;
+    dprintf(1, "malloc_high used=%d (%d%%) (returned %d)\n"
+            , used, (100 * used) / avail, giveback);
 }
diff --git a/src/memmap.h b/src/memmap.h
index 8338c43..8df9ed0 100644
--- a/src/memmap.h
+++ b/src/memmap.h
@@ -20,12 +20,16 @@
 void memmap_setup();
 void memmap_finalize();
 
+void *malloc_high(u32 size);
+void *malloc_fseg(u32 size);
+void malloc_setup();
+void malloc_finalize();
+
 // e820 map storage (defined in system.c)
 extern struct e820entry e820_list[];
 extern int e820_count;
 
 // Space for exported bios tables (defined in misc.c)
-extern u32 bios_table_cur_addr, bios_table_end_addr;
 extern char BiosTableSpace[];
 
 #endif // e820map.h
diff --git a/src/misc.c b/src/misc.c
index bece61e..956e545 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1,6 +1,6 @@
 // Code for misc 16bit handlers and variables.
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
 // Copyright (C) 2002  MandrakeSoft S.A.
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -15,7 +15,6 @@
 // Amount of continuous ram >4Gig
 u64 RamSizeOver4G;
 // Space for bios tables built an run-time.
-u32 bios_table_cur_addr, bios_table_end_addr;
 char BiosTableSpace[CONFIG_MAX_BIOSTABLE] VAR16_32;
 
 
diff --git a/src/mptable.c b/src/mptable.c
index e81bd62..5758b28 100644
--- a/src/mptable.c
+++ b/src/mptable.c
@@ -1,12 +1,12 @@
 // MPTable generation (on emulators)
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
 // Copyright (C) 2006 Fabrice Bellard
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
 #include "util.h" // dprintf
-#include "memmap.h" // bios_table_cur_addr
+#include "memmap.h" // malloc_fseg
 #include "config.h" // CONFIG_*
 #include "mptable.h" // MPTABLE_SIGNATURE
 
@@ -23,21 +23,20 @@
         // Building an mptable on uniprocessor machines confuses some OSes.
         return;
 
-    u32 start = ALIGN(bios_table_cur_addr, 16);
     int length = (sizeof(struct mptable_floating_s)
                   + sizeof(struct mptable_config_s)
                   + sizeof(struct mpt_cpu) * smp_cpus
                   + sizeof(struct mpt_bus)
                   + sizeof(struct mpt_ioapic)
                   + sizeof(struct mpt_intsrc) * 16);
-    if (start + length > bios_table_end_addr) {
+    void *start = malloc_fseg(length);
+    if (!start) {
         dprintf(1, "No room for MPTABLE!\n");
         return;
     }
-    bios_table_cur_addr = start + length;
 
     /* floating pointer structure */
-    struct mptable_floating_s *floating = (void*)start;
+    struct mptable_floating_s *floating = start;
     memset(floating, 0, sizeof(*floating));
     struct mptable_config_s *config = (void*)&floating[1];
     floating->signature = MPTABLE_SIGNATURE;
@@ -108,6 +107,6 @@
     // Set checksum.
     config->checksum -= checksum(config, config->length);
 
-    dprintf(1, "MP table addr=0x%x MPC table addr=0x%x size=0x%x\n",
-            (u32)floating, (u32)config, length);
+    dprintf(1, "MP table addr=%p MPC table addr=%p size=%d\n",
+            floating, config, length);
 }
diff --git a/src/post.c b/src/post.c
index aa7b83f..052edb5 100644
--- a/src/post.c
+++ b/src/post.c
@@ -1,6 +1,6 @@
 // 32bit code to Power On Self Test (POST) a machine.
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
 // Copyright (C) 2002  MandrakeSoft S.A.
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -166,6 +166,7 @@
     ram_probe();
     mtrr_setup();
     smp_probe();
+    malloc_setup();
 
     pnp_setup();
     vga_setup();
@@ -179,6 +180,7 @@
     smm_init();
 
     init_bios_tables();
+    malloc_finalize();
     memmap_finalize();
 
     boot_setup();
diff --git a/src/smbios.c b/src/smbios.c
index e9a4b31..fb03671 100644
--- a/src/smbios.c
+++ b/src/smbios.c
@@ -1,12 +1,12 @@
 // smbios table generation (on emulators)
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
 // Copyright (C) 2006 Fabrice Bellard
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
 #include "util.h" // dprintf
-#include "memmap.h" // bios_table_cur_addr
+#include "memmap.h" // malloc_fseg
 #include "biosvar.h" // GET_EBDA
 
 
@@ -222,13 +222,16 @@
  ****************************************************************/
 
 static void
-smbios_entry_point_init(void *start,
-                        u16 max_structure_size,
+smbios_entry_point_init(u16 max_structure_size,
                         u16 structure_table_length,
-                        u32 structure_table_address,
+                        void *structure_table_address,
                         u16 number_of_structures)
 {
-    struct smbios_entry_point *ep = (struct smbios_entry_point *)start;
+    struct smbios_entry_point *ep = malloc_fseg(sizeof(*ep));
+    if (! ep) {
+        dprintf(1, "No space for smbios entry table!\n");
+        return;
+    }
 
     memcpy(ep->anchor_string, "_SM_", 4);
     ep->length = 0x1f;
@@ -240,13 +243,15 @@
     memcpy(ep->intermediate_anchor_string, "_DMI_", 5);
 
     ep->structure_table_length = structure_table_length;
-    ep->structure_table_address = structure_table_address;
+    ep->structure_table_address = (u32)structure_table_address;
     ep->number_of_structures = number_of_structures;
     ep->smbios_bcd_revision = 0x24;
 
-    ep->checksum -= checksum(start, 0x10);
+    ep->checksum -= checksum(ep, 0x10);
 
-    ep->intermediate_checksum -= checksum(start + 0x10, ep->length - 0x10);
+    ep->intermediate_checksum -= checksum((void*)ep + 0x10, ep->length - 0x10);
+
+    dprintf(1, "SMBIOS ptr=%p table=%p\n", ep, structure_table_address);
 }
 
 /* Type 0 -- BIOS Information */
@@ -537,13 +542,14 @@
 
     dprintf(3, "init SMBIOS tables\n");
 
-    unsigned cpu_num, nr_structs = 0, max_struct_size = 0;
-    char *start, *p, *q;
+    char *start = malloc_high(2048); // XXX - determine real size
+    if (! start) {
+        dprintf(1, "No memory for smbios tables\n");
+        return;
+    }
 
-    bios_table_cur_addr = ALIGN(bios_table_cur_addr, 16);
-    start = (void *)(bios_table_cur_addr);
-
-    p = (char *)start + sizeof(struct smbios_entry_point);
+    u32 nr_structs = 0, max_struct_size = 0;
+    char *q, *p = start;
 
 #define add_struct(fn) { \
     q = (fn); \
@@ -556,7 +562,7 @@
     add_struct(smbios_type_0_init(p));
     add_struct(smbios_type_1_init(p));
     add_struct(smbios_type_3_init(p));
-    int smp_cpus = CountCPUs;
+    int cpu_num, smp_cpus = CountCPUs;
     for (cpu_num = 1; cpu_num <= smp_cpus; cpu_num++)
         add_struct(smbios_type_4_init(p, cpu_num));
     add_struct(smbios_type_16_init(p));
@@ -568,13 +574,5 @@
 
 #undef add_struct
 
-    smbios_entry_point_init(
-        start, max_struct_size,
-        (p - (char *)start) - sizeof(struct smbios_entry_point),
-        (u32)(start + sizeof(struct smbios_entry_point)),
-        nr_structs);
-
-    bios_table_cur_addr += (p - (char *)start);
-
-    dprintf(1, "SMBIOS table addr=0x%08lx\n", (unsigned long)start);
+    smbios_entry_point_init(max_struct_size, p - start, start, nr_structs);
 }