]> xenbits.xensource.com Git - people/andrewcoop/seabios.git/commitdiff
Add mechanism to declare variables as "low mem" and use for extra stack.
authorKevin O'Connor <kevin@koconnor.net>
Sun, 13 May 2012 16:10:30 +0000 (12:10 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Sun, 20 May 2012 22:10:38 +0000 (18:10 -0400)
Add a mechanism (VARLOW declaration) to make a variable reside in the
low memory (e-segment) area.  This is useful for runtime variables
that need to be accessed from 16bit code and need to be modifiable
during runtime.

Move the 16bit "extra stack" from the EBDA to the low memory area
using this declaration mechanism.  Also increase the size of this
stack from 512 bytes to 2048 bytes.

This also reworks tools/layoutrom.py a bit.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
src/asm-offsets.c
src/ata.c
src/biosvar.h
src/block.c
src/config.h
src/post.c
src/romlayout.S
src/stacks.c
src/types.h
src/util.h
tools/layoutrom.py

index 5035cef8f7fe1be9d2c007e6182c4ca5b2bde0e4..b98f3b5a87c510ac46f16fdd2bdd13e731ad5ac9 100644 (file)
@@ -2,7 +2,6 @@
 
 #include "gen-defs.h" // OFFSET
 #include "bregs.h" // struct bregs
-#include "biosvar.h" // struct bios_data_area_s
 
 /* workaround for a warning with -Wmissing-prototypes */
 void foo(void) VISIBLE16;
@@ -21,11 +20,4 @@ void foo(void)
     OFFSET(BREGS_edi, bregs, edi);
     OFFSET(BREGS_flags, bregs, flags);
     OFFSET(BREGS_code, bregs, code);
-
-    COMMENT("BDA");
-    OFFSET(BDA_ebda_seg, bios_data_area_s, ebda_seg);
-
-    COMMENT("EBDA");
-    DEFINE(EBDA_OFFSET_TOP_STACK, EBDA_OFFSET_TOP_STACK);
-    DEFINE(EBDA_SEGMENT_START, EBDA_SEGMENT_START);
 }
index c37691a04a52a706d339b0454a43f52e853089bf..b261bfe964c474c22dadd943a0f1e5c009e8317f 100644 (file)
--- a/src/ata.c
+++ b/src/ata.c
@@ -10,7 +10,7 @@
 #include "util.h" // dprintf
 #include "cmos.h" // inb_cmos
 #include "pic.h" // enable_hwirq
-#include "biosvar.h" // GET_EBDA
+#include "biosvar.h" // GET_GLOBAL
 #include "pci.h" // foreachpci
 #include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
 #include "pci_regs.h" // PCI_INTERRUPT_LINE
@@ -379,6 +379,7 @@ struct sff_dma_prd {
 static int
 ata_try_dma(struct disk_op_s *op, int iswrite, int blocksize)
 {
+    ASSERT16();
     if (! CONFIG_ATA_DMA)
         return -1;
     u32 dest = (u32)op->buf_fl;
@@ -396,9 +397,7 @@ ata_try_dma(struct disk_op_s *op, int iswrite, int blocksize)
         return -1;
 
     // Build PRD dma structure.
-    struct sff_dma_prd *dma = MAKE_FLATPTR(
-        get_ebda_seg()
-        , (void*)offsetof(struct extended_bios_data_area_s, extra_stack));
+    struct sff_dma_prd *dma = MAKE_FLATPTR(SEG_LOW, ExtraStack);
     struct sff_dma_prd *origdma = dma;
     while (bytes) {
         if (dma >= &origdma[16])
index b6f7174c59dd7b3ffd739c1ff85f45cd172ce91c..99c2565bc1bd0a14578da5d25ff4876b5f0885b7 100644 (file)
@@ -242,9 +242,6 @@ struct extended_bios_data_area_s {
     /* TSC emulation timekeepers */
     u64 tsc_8254;
     int last_tsc_8254;
-
-    // Stack space available for code that needs it.
-    u8 extra_stack[512] __aligned(8);
 } PACKED;
 
 // The initial size and location of EBDA
@@ -272,11 +269,6 @@ get_ebda_ptr(void)
 #define SET_EBDA(var, val)                      \
     SET_EBDA2(get_ebda_seg(), var, (val))
 
-#define EBDA_OFFSET_TOP_STACK                                   \
-    offsetof(struct extended_bios_data_area_s, extra_stack[     \
-                 FIELD_SIZEOF(struct extended_bios_data_area_s  \
-                              , extra_stack)])
-
 
 /****************************************************************
  * Global variables
@@ -320,6 +312,22 @@ static inline u16 get_global_seg(void) {
 #define GET_GLOBALFLAT(var) GET_GLOBAL(*GLOBALFLAT2GLOBAL(&(var)))
 
 
+/****************************************************************
+ * "Low" memory variables
+ ****************************************************************/
+
+extern u8 _datalow_seg, _datalow_base[];
+#define SEG_LOW ((u32)&_datalow_seg)
+
+#if MODESEGMENT
+#define GET_LOW(var)            GET_FARVAR(SEG_LOW, (var))
+#define SET_LOW(var, val)       SET_FARVAR(SEG_LOW, (var), (val))
+#else
+#define GET_LOW(var)            (var)
+#define SET_LOW(var, val)       do { (var) = (val); } while (0)
+#endif
+
+
 /****************************************************************
  * Bios Config Table
  ****************************************************************/
index a80199c6d9a5170a92e33435853dcaa43064338e..194d6f26422d539c9fa0aa8396f00065816dd099 100644 (file)
@@ -328,7 +328,7 @@ process_op(struct disk_op_s *op)
     }
 }
 
-// Execute a "disk_op_s" request - this runs on a stack in the ebda.
+// Execute a "disk_op_s" request - this runs on the extra stack.
 static int
 __send_disk_op(struct disk_op_s *op_far, u16 op_seg)
 {
@@ -349,7 +349,7 @@ __send_disk_op(struct disk_op_s *op_far, u16 op_seg)
     return status;
 }
 
-// Execute a "disk_op_s" request by jumping to a stack in the ebda.
+// Execute a "disk_op_s" request by jumping to the extra 16bit stack.
 int
 send_disk_op(struct disk_op_s *op)
 {
index 521469b2cf256d3ba17ebd5fdb5c3ca8b1faa4e8..23591b979c7734521f8a0104cfe68eac0ea04a0c 100644 (file)
@@ -39,6 +39,7 @@
 #define BUILD_BIOS_ADDR           0xf0000
 #define BUILD_BIOS_SIZE           0x10000
 #define BUILD_LOWMEM_SIZE         0x8000
+#define BUILD_EXTRA_STACK_SIZE    0x800
 // 32KB for shadow ram copying (works around emulator deficiencies)
 #define BUILD_BIOS_TMP_ADDR       0x30000
 #define BUILD_SMM_INIT_ADDR       0x38000
index 8383b7917eaf1e6cf7a31da1d114e6276f02476c..71e69fdc5f75f9232c5dfe8af1bcb965a2b00cef 100644 (file)
@@ -211,9 +211,6 @@ startBoot(void)
 static void
 maininit(void)
 {
-    // Running at new code address - do code relocation fixups
-    malloc_fixupreloc();
-
     // Setup ivt/bda/ebda
     init_ivt();
     init_bda();
@@ -287,6 +284,21 @@ maininit(void)
  * POST entry and code relocation
  ****************************************************************/
 
+// Relocation fixup code that runs at new address after relocation complete.
+static void
+afterReloc(void *datalow)
+{
+    // Running at new code address - do code relocation fixups
+    malloc_fixupreloc();
+
+    // Move low-memory initial variable content to new location.
+    extern u8 datalow_start[], datalow_end[];
+    memmove(datalow, datalow_start, datalow_end - datalow_start);
+
+    // Run main code
+    maininit();
+}
+
 // Update given relocs for the code at 'dest' with a given 'delta'
 static void
 updateRelocs(void *dest, u32 *rstart, u32 *rend, u32 delta)
@@ -306,32 +318,42 @@ reloc_init(void)
     }
     // Symbols populated by the build.
     extern u8 code32flat_start[];
-    extern u8 _reloc_min_align[];
+    extern u8 _reloc_min_align;
     extern u32 _reloc_abs_start[], _reloc_abs_end[];
     extern u32 _reloc_rel_start[], _reloc_rel_end[];
     extern u32 _reloc_init_start[], _reloc_init_end[];
     extern u8 code32init_start[], code32init_end[];
+    extern u32 _reloc_datalow_start[], _reloc_datalow_end[];
+    extern u8 _datalow_min_align;
+    extern u8 datalow_start[], datalow_end[];
 
     // Allocate space for init code.
     u32 initsize = code32init_end - code32init_start;
-    u32 align = (u32)&_reloc_min_align;
-    void *dest = memalign_tmp(align, initsize);
-    if (!dest)
+    u32 codealign = (u32)&_reloc_min_align;
+    void *codedest = memalign_tmp(codealign, initsize);
+    u32 datalowsize = datalow_end - datalow_start;
+    u32 datalowalign = (u32)&_datalow_min_align;
+    void *datalow = memalign_low(datalowalign, datalowsize);
+    if (!codedest || !datalow)
         panic("No space for init relocation.\n");
 
     // Copy code and update relocs (init absolute, init relative, and runtime)
+    dprintf(1, "Relocating low data from %p to %p (size %d)\n"
+            , datalow_start, datalow, datalowsize);
+    updateRelocs(code32flat_start, _reloc_datalow_start, _reloc_datalow_end
+                 , datalow - (void*)datalow_start);
     dprintf(1, "Relocating init from %p to %p (size %d)\n"
-            , code32init_start, dest, initsize);
-    s32 delta = dest - (void*)code32init_start;
-    memcpy(dest, code32init_start, initsize);
-    updateRelocs(dest, _reloc_abs_start, _reloc_abs_end, delta);
-    updateRelocs(dest, _reloc_rel_start, _reloc_rel_end, -delta);
+            , code32init_start, codedest, initsize);
+    s32 delta = codedest - (void*)code32init_start;
+    memcpy(codedest, code32init_start, initsize);
+    updateRelocs(codedest, _reloc_abs_start, _reloc_abs_end, delta);
+    updateRelocs(codedest, _reloc_rel_start, _reloc_rel_end, -delta);
     updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta);
 
     // Call maininit() in relocated code.
-    void (*func)(void) = (void*)maininit + delta;
+    void (*func)(void*) = (void*)afterReloc + delta;
     barrier();
-    func();
+    func(datalow);
 }
 
 // Setup for code relocation and then call reloc_init
index c4b2ef11db44be1ab3803004274e7025c9fea9af..399f596b910d8dd410b51987a065951b41827c5b 100644 (file)
@@ -232,13 +232,11 @@ entry_resume:
         // Disable interrupts
         cli
         cld
-        // Use a stack in EBDA
-        movw $SEG_BDA, %ax
-        movw %ax, %ds
-        movw BDA_ebda_seg, %ax
+        // Use the ExtraStack in low mem.
+        movl $_datalow_seg, %eax
         movw %ax, %ds
         movw %ax, %ss
-        movl $EBDA_OFFSET_TOP_STACK, %esp
+        movl $ExtraStack + BUILD_EXTRA_STACK_SIZE, %esp
         // Call handler.
         jmp handle_resume
 
index 17f1a4a81915b51fedee507aacc7ba0c8c9a60ad..0371330adc8443ec2c80d0df233051c9b339299a 100644 (file)
@@ -4,7 +4,7 @@
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
-#include "biosvar.h" // get_ebda_seg
+#include "biosvar.h" // GET_GLOBAL
 #include "util.h" // dprintf
 #include "bregs.h" // CR0_PE
 
@@ -149,21 +149,24 @@ wait_irq(void)
 
 
 /****************************************************************
- * Stack in EBDA
+ * Extra 16bit stack
  ****************************************************************/
 
-// Switch to the extra stack in ebda and call a function.
+// Space for a stack for 16bit code.
+u8 ExtraStack[BUILD_EXTRA_STACK_SIZE+1] VARLOW __aligned(8);
+
+// Switch to the extra stack and call a function.
 inline u32
 stack_hop(u32 eax, u32 edx, void *func)
 {
     ASSERT16();
-    u16 ebda_seg = get_ebda_seg(), bkup_ss;
+    u16 stack_seg = SEG_LOW, bkup_ss;
     u32 bkup_esp;
     asm volatile(
         // Backup current %ss/%esp values.
         "movw %%ss, %w3\n"
         "movl %%esp, %4\n"
-        // Copy ebda seg to %ds/%ss and set %esp
+        // Copy stack seg to %ds/%ss and set %esp
         "movw %w6, %%ds\n"
         "movw %w6, %%ss\n"
         "movl %5, %%esp\n"
@@ -174,7 +177,7 @@ stack_hop(u32 eax, u32 edx, void *func)
         "movw %w3, %%ss\n"
         "movl %4, %%esp"
         : "+a" (eax), "+d" (edx), "+c" (func), "=&r" (bkup_ss), "=&r" (bkup_esp)
-        : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg)
+        : "i" (&ExtraStack[BUILD_EXTRA_STACK_SIZE]), "r" (stack_seg)
         : "cc", "memory");
     return eax;
 }
index c0c6d26ca24358d3405fb97050ce24c09b2a9f20..0f83697ef1033205881da9b3e9e27c0038c860b0 100644 (file)
@@ -61,6 +61,8 @@ extern void __force_link_error__only_in_16bit(void) __noreturn;
 # define VAR32SEG __section(".discard.var32seg." UNIQSEC)
 // Designate a 32bit variable also available in 16bit "big real" mode.
 # define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak
+// Designate a variable as visible and located in the e-segment.
+# define VARLOW __section(".discard.varlow." UNIQSEC) __VISIBLE __weak
 // Designate top-level assembler as 16bit only.
 # define ASM16(code) __ASM(code)
 // Designate top-level assembler as 32bit flat only.
@@ -80,6 +82,7 @@ extern void __force_link_error__only_in_16bit(void) __noreturn;
 # define VAR16FIXED(addr) VAR16VISIBLE
 # define VAR32SEG __section(".data32seg." UNIQSEC)
 # define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak
+# define VARLOW __section(".discard.varlow." UNIQSEC) __VISIBLE __weak
 # define ASM16(code)
 # define ASM32FLAT(code)
 # define ASSERT16() __force_link_error__only_in_16bit()
@@ -96,6 +99,7 @@ extern void __force_link_error__only_in_16bit(void) __noreturn;
 # define VAR16FIXED(addr) VAR16VISIBLE
 # define VAR32SEG __section(".discard.var32seg." UNIQSEC)
 # define VAR32FLATVISIBLE __section(".data.runtime." UNIQSEC) __VISIBLE
+# define VARLOW __section(".datalow." UNIQSEC) __VISIBLE
 # define ASM16(code)
 # define ASM32FLAT(code) __ASM(code)
 # define ASSERT16() __force_link_error__only_in_16bit()
index 04de66b2d01407bdf694356806bfc437bcb6def9..e0e98f05dfc4103170a48479be600a1a9022b46b 100644 (file)
@@ -230,6 +230,7 @@ int get_keystroke(int msec);
 
 // stacks.c
 u32 call32(void *func, u32 eax, u32 errret);
+extern u8 ExtraStack[];
 inline u32 stack_hop(u32 eax, u32 edx, void *func);
 extern struct thread_info MainThread;
 extern int CanPreempt;
index 86e1f3351f47019490debd620980feec158c9bec..1ae7c83d34a21a2eef89ade7a67d4ddb753c403a 100755 (executable)
@@ -40,7 +40,7 @@ def alignpos(pos, alignbytes):
 
 # Determine the final addresses for a list of sections that end at an
 # address.
-def setSectionsStart(sections, endaddr, minalign=1):
+def setSectionsStart(sections, endaddr, minalign=1, segoffset=0):
     totspace = 0
     for section in sections:
         if section.align > minalign:
@@ -53,12 +53,14 @@ def setSectionsStart(sections, endaddr, minalign=1):
     for section in sections:
         curaddr = alignpos(curaddr, section.align)
         section.finalloc = curaddr
+        section.finalsegloc = curaddr - segoffset
         curaddr += section.size
-    return startaddr
+    return startaddr, minalign
 
 # The 16bit code can't exceed 64K of space.
 BUILD_BIOS_ADDR = 0xf0000
 BUILD_BIOS_SIZE = 0x10000
+BUILD_ROM_START = 0xc0000
 
 # Layout the 16bit code.  This ensures sections with fixed offset
 # requirements are placed in the correct location.  It also places the
@@ -69,7 +71,8 @@ def fitSections(sections, fillsections):
     for section in sections:
         if section.name.startswith('.fixedaddr.'):
             addr = int(section.name[11:], 16)
-            section.finalloc = addr
+            section.finalloc = addr + BUILD_BIOS_ADDR
+            section.finalsegloc = addr
             fixedsections.append((addr, section))
             if section.align != 1:
                 print "Error: Fixed section %s has non-zero alignment (%d)" % (
@@ -99,7 +102,7 @@ def fitSections(sections, fillsections):
     canrelocate = [section for size, align, name, section in canrelocate]
     totalused = 0
     for freespace, fixedsection in fixedAddr:
-        addpos = fixedsection.finalloc + fixedsection.size
+        addpos = fixedsection.finalsegloc + fixedsection.size
         totalused += fixedsection.size
         nextfixedaddr = addpos + freespace
 #        print "Filling section %x uses %d, next=%x, available=%d" % (
@@ -122,7 +125,8 @@ def fitSections(sections, fillsections):
             # Found a section that can fit.
             fitnextaddr, fitsection = canfit
             canrelocate.remove(fitsection)
-            fitsection.finalloc = addpos
+            fitsection.finalloc = addpos + BUILD_BIOS_ADDR
+            fitsection.finalsegloc = addpos
             addpos = fitnextaddr
             totalused += fitsection.size
 #            print "    Adding %s (size %d align %d) pos=%x avail=%d" % (
@@ -137,68 +141,104 @@ def fitSections(sections, fillsections):
             firstfixed, BUILD_BIOS_SIZE, total, slack,
             (float(slack) / total) * 100.0))
 
-    return firstfixed
+    return firstfixed + BUILD_BIOS_ADDR
+
+# Return the subset of sections with a given category
+def getSectionsCategory(sections, category):
+    return [section for section in sections if section.category == category]
 
 # Return the subset of sections with a given name prefix
-def getSectionsPrefix(sections, category, prefix):
+def getSectionsPrefix(sections, prefix):
     return [section for section in sections
-            if section.category == category and section.name.startswith(prefix)]
-
-def doLayout(sections):
+            if section.name.startswith(prefix)]
+
+# The sections (and associated information) to be placed in output rom
+class LayoutInfo:
+    sections16 = sec16_start = sec16_align = None
+    sections32seg = sec32seg_start = sec32seg_align = None
+    sections32flat = sec32flat_start = sec32flat_align = None
+    sections32init = sec32init_start = sec32init_align = None
+    sections32low = sec32low_start = sec32low_align = None
+    datalow_base = None
+
+# Determine final memory addresses for sections
+def doLayout(sections, genreloc):
+    li = LayoutInfo()
     # Determine 16bit positions
-    textsections = getSectionsPrefix(sections, '16', '.text.')
+    li.sections16 = getSectionsCategory(sections, '16')
+    textsections = getSectionsPrefix(li.sections16, '.text.')
     rodatasections = (
-        getSectionsPrefix(sections, '16', '.rodata.str1.1')
-        + getSectionsPrefix(sections, '16', '.rodata.__func__.')
-        + getSectionsPrefix(sections, '16', '.rodata.__PRETTY_FUNCTION__.'))
-    datasections = getSectionsPrefix(sections, '16', '.data16.')
-    fixedsections = getSectionsPrefix(sections, '16', '.fixedaddr.')
+        getSectionsPrefix(li.sections16, '.rodata.str1.1')
+        + getSectionsPrefix(li.sections16, '.rodata.__func__.')
+        + getSectionsPrefix(li.sections16, '.rodata.__PRETTY_FUNCTION__.'))
+    datasections = getSectionsPrefix(li.sections16, '.data16.')
+    fixedsections = getSectionsPrefix(li.sections16, '.fixedaddr.')
 
     firstfixed = fitSections(fixedsections, textsections)
     remsections = [s for s in textsections+rodatasections+datasections
                    if s.finalloc is None]
-    code16_start = setSectionsStart(remsections, firstfixed)
+    li.sec16_start, li.sec16_align = setSectionsStart(
+        remsections, firstfixed, segoffset=BUILD_BIOS_ADDR)
 
     # Determine 32seg positions
-    textsections = getSectionsPrefix(sections, '32seg', '.text.')
+    li.sections32seg = getSectionsCategory(sections, '32seg')
+    textsections = getSectionsPrefix(li.sections32seg, '.text.')
     rodatasections = (
-        getSectionsPrefix(sections, '32seg', '.rodata.str1.1')
-        + getSectionsPrefix(sections, '32seg', '.rodata.__func__.')
-        + getSectionsPrefix(sections, '32seg', '.rodata.__PRETTY_FUNCTION__.'))
-    datasections = getSectionsPrefix(sections, '32seg', '.data32seg.')
+        getSectionsPrefix(li.sections32seg, '.rodata.str1.1')
+        + getSectionsPrefix(li.sections32seg, '.rodata.__func__.')
+        + getSectionsPrefix(li.sections32seg, '.rodata.__PRETTY_FUNCTION__.'))
+    datasections = getSectionsPrefix(li.sections32seg, '.data32seg.')
 
-    code32seg_start = setSectionsStart(
-        textsections + rodatasections + datasections, code16_start)
+    li.sec32seg_start, li.sec32seg_align = setSectionsStart(
+        textsections + rodatasections + datasections, li.sec16_start
+        , segoffset=BUILD_BIOS_ADDR)
 
     # Determine 32flat runtime positions
-    textsections = getSectionsPrefix(sections, '32flat', '.text.')
-    rodatasections = getSectionsPrefix(sections, '32flat', '.rodata')
-    datasections = getSectionsPrefix(sections, '32flat', '.data.')
-    bsssections = getSectionsPrefix(sections, '32flat', '.bss.')
+    li.sections32flat = getSectionsCategory(sections, '32flat')
+    textsections = getSectionsPrefix(li.sections32flat, '.text.')
+    rodatasections = getSectionsPrefix(li.sections32flat, '.rodata')
+    datasections = getSectionsPrefix(li.sections32flat, '.data.')
+    bsssections = getSectionsPrefix(li.sections32flat, '.bss.')
 
-    code32flat_start = setSectionsStart(
+    li.sec32flat_start, li.sec32flat_align = setSectionsStart(
         textsections + rodatasections + datasections + bsssections
-        , code32seg_start + BUILD_BIOS_ADDR, 16)
+        , li.sec32seg_start, 16)
 
     # Determine 32flat init positions
-    textsections = getSectionsPrefix(sections, '32init', '.text.')
-    rodatasections = getSectionsPrefix(sections, '32init', '.rodata')
-    datasections = getSectionsPrefix(sections, '32init', '.data.')
-    bsssections = getSectionsPrefix(sections, '32init', '.bss.')
+    li.sections32init = getSectionsCategory(sections, '32init')
+    textsections = getSectionsPrefix(li.sections32init, '.text.')
+    rodatasections = getSectionsPrefix(li.sections32init, '.rodata')
+    datasections = getSectionsPrefix(li.sections32init, '.data.')
+    bsssections = getSectionsPrefix(li.sections32init, '.bss.')
 
-    code32init_start = setSectionsStart(
+    li.sec32init_start, li.sec32init_align = setSectionsStart(
         textsections + rodatasections + datasections + bsssections
-        , code32flat_start, 16)
+        , li.sec32flat_start, 16)
+
+    # Determine "low memory" data positions
+    li.sections32low = getSectionsCategory(sections, '32low')
+    if genreloc:
+        sec32low_top = li.sec32init_start
+        datalow_base = min(BUILD_BIOS_ADDR, li.sec32flat_start) - 64*1024
+    else:
+        sec32low_top = min(BUILD_BIOS_ADDR, li.sec32init_start)
+        datalow_base = sec32low_top - 64*1024
+    li.datalow_base = max(BUILD_ROM_START, alignpos(datalow_base, 2*1024))
+    li.sec32low_start, li.sec32low_align = setSectionsStart(
+        li.sections32low, sec32low_top, 16, segoffset=li.datalow_base)
 
     # Print statistics
-    size16 = BUILD_BIOS_SIZE - code16_start
-    size32seg = code16_start - code32seg_start
-    size32flat = code32seg_start + BUILD_BIOS_ADDR - code32flat_start
-    size32init = code32flat_start - code32init_start
+    size16 = BUILD_BIOS_ADDR + BUILD_BIOS_SIZE - li.sec16_start
+    size32seg = li.sec16_start - li.sec32seg_start
+    size32flat = li.sec32seg_start - li.sec32flat_start
+    size32init = li.sec32flat_start - li.sec32init_start
+    sizelow = sec32low_top - li.sec32low_start
     print "16bit size:           %d" % size16
     print "32bit segmented size: %d" % size32seg
     print "32bit flat size:      %d" % size32flat
     print "32bit flat init size: %d" % size32init
+    print "Lowmem size:          %d" % sizelow
+    return li
 
 
 ######################################################################
@@ -206,7 +246,7 @@ def doLayout(sections):
 ######################################################################
 
 # Write LD script includes for the given cross references
-def outXRefs(sections):
+def outXRefs(sections, useseg=0):
     xrefs = {}
     out = ""
     for section in sections:
@@ -218,162 +258,155 @@ def outXRefs(sections):
                 or reloc.symbolname in xrefs):
                 continue
             xrefs[reloc.symbolname] = 1
-            addr = symbol.section.finalloc + symbol.offset
-            if (section.fileid == '32flat'
-                and symbol.section.fileid in ('16', '32seg')):
-                addr += BUILD_BIOS_ADDR
-            out += "%s = 0x%x ;\n" % (reloc.symbolname, addr)
+            loc = symbol.section.finalloc
+            if useseg:
+                loc = symbol.section.finalsegloc
+            out += "%s = 0x%x ;\n" % (reloc.symbolname, loc + symbol.offset)
     return out
 
 # Write LD script includes for the given sections using relative offsets
-def outRelSections(sections, startsym):
+def outRelSections(sections, startsym, useseg=0):
+    sections = [(section.finalloc, section) for section in sections
+                if section.finalloc is not None]
+    sections.sort()
     out = ""
-    for section in sections:
-        out += ". = ( 0x%x - %s ) ;\n" % (section.finalloc, startsym)
+    for addr, section in sections:
+        loc = section.finalloc
+        if useseg:
+            loc = section.finalsegloc
+        out += ". = ( 0x%x - %s ) ;\n" % (loc, startsym)
         if section.name == '.rodata.str1.1':
             out += "_rodata = . ;\n"
         out += "*(%s)\n" % (section.name,)
     return out
 
-def getSectionsFile(sections, fileid, defaddr=0):
-    sections = [(section.finalloc, section)
-                for section in sections if section.fileid == fileid]
-    sections.sort()
-    sections = [section for addr, section in sections]
-    pos = defaddr
-    if sections:
-        pos = sections[0].finalloc
-    return sections, pos
-
-# Layout the 32bit segmented code.  This places the code as high as possible.
-def writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat):
+# Build linker script output for a list of relocations.
+def strRelocs(outname, outrel, relocs):
+    relocs.sort()
+    return ("        %s_start = ABSOLUTE(.) ;\n" % (outname,)
+            + "".join(["LONG(0x%x - %s)\n" % (pos, outrel)
+                       for pos in relocs])
+            + "        %s_end = ABSOLUTE(.) ;\n" % (outname,))
+
+# Find all relocations in the given sections with the given attributes
+def getRelocs(sections, type=None, category=None, notcategory=None):
+    out = []
+    for section in sections:
+        for reloc in section.relocs:
+            if reloc.symbol.section is None:
+                continue
+            destcategory = reloc.symbol.section.category
+            if ((type is None or reloc.type == type)
+                and (category is None or destcategory == category)
+                and (notcategory is None or destcategory != notcategory)):
+                out.append(section.finalloc + reloc.offset)
+    return out
+
+# Return the start address and minimum alignment for a set of sections
+def getSectionsStart(sections, defaddr=0):
+    return min([section.finalloc for section in sections
+                if section.finalloc is not None] or [defaddr])
+
+# Output the linker scripts for all required sections.
+def writeLinkerScripts(li, entrysym, genreloc, out16, out32seg, out32flat):
     # Write 16bit linker script
-    sections16, code16_start = getSectionsFile(sections, '16')
-    output = open(out16, 'wb')
-    output.write(COMMONHEADER + outXRefs(sections16) + """
+    out = outXRefs(li.sections16, useseg=1) + """
+    _datalow_base = 0x%x ;
+    _datalow_seg = 0x%x ;
+
     code16_start = 0x%x ;
     .text16 code16_start : {
-""" % (code16_start)
-                 + outRelSections(sections16, 'code16_start')
-                 + """
+%s
     }
-"""
-                 + COMMONTRAILER)
-    output.close()
+""" % (li.datalow_base,
+       li.datalow_base / 16,
+       li.sec16_start - BUILD_BIOS_ADDR,
+       outRelSections(li.sections16, 'code16_start', useseg=1))
+    outfile = open(out16, 'wb')
+    outfile.write(COMMONHEADER + out + COMMONTRAILER)
+    outfile.close()
 
     # Write 32seg linker script
-    sections32seg, code32seg_start = getSectionsFile(
-        sections, '32seg', code16_start)
-    output = open(out32seg, 'wb')
-    output.write(COMMONHEADER + outXRefs(sections32seg) + """
+    out = outXRefs(li.sections32seg, useseg=1) + """
     code32seg_start = 0x%x ;
     .text32seg code32seg_start : {
-""" % (code32seg_start)
-                 + outRelSections(sections32seg, 'code32seg_start')
-                 + """
+%s
     }
-"""
-                 + COMMONTRAILER)
-    output.close()
+""" % (li.sec32seg_start - BUILD_BIOS_ADDR,
+       outRelSections(li.sections32seg, 'code32seg_start', useseg=1))
+    outfile = open(out32seg, 'wb')
+    outfile.write(COMMONHEADER + out + COMMONTRAILER)
+    outfile.close()
 
     # Write 32flat linker script
-    sections32flat, code32flat_start = getSectionsFile(
-        sections, '32flat', code32seg_start)
+    sections32all = li.sections32flat + li.sections32init + li.sections32low
+    sec32all_start = li.sec32low_start
+    entrysympos = entrysym.section.finalloc + entrysym.offset
     relocstr = ""
-    relocminalign = 0
     if genreloc:
         # Generate relocations
-        relocstr, size, relocminalign = genRelocs(sections)
-        code32flat_start -= size
-    output = open(out32flat, 'wb')
-    output.write(COMMONHEADER
-                 + outXRefs(sections32flat) + """
+        absrelocs = getRelocs(
+            li.sections32init, type='R_386_32', category='32init')
+        relrelocs = getRelocs(
+            li.sections32init, type='R_386_PC32', notcategory='32init')
+        initrelocs = getRelocs(
+            li.sections32flat + li.sections32low + li.sections16
+            + li.sections32seg, category='32init')
+        lowrelocs = getRelocs(
+            li.sections16 + li.sections32seg + sections32all, category='32low')
+        relocstr = (strRelocs("_reloc_abs", "code32init_start", absrelocs)
+                    + strRelocs("_reloc_rel", "code32init_start", relrelocs)
+                    + strRelocs("_reloc_init", "code32flat_start", initrelocs)
+                    + strRelocs("_reloc_datalow", "code32flat_start", lowrelocs))
+        numrelocs = len(absrelocs + relrelocs + initrelocs + lowrelocs)
+        sec32all_start -= numrelocs * 4
+    out = outXRefs(sections32all) + """
     %s = 0x%x ;
     _reloc_min_align = 0x%x ;
+    _datalow_min_align = 0x%x ;
+
     code32flat_start = 0x%x ;
     .text code32flat_start : {
-""" % (entrysym.name,
-       entrysym.section.finalloc + entrysym.offset + BUILD_BIOS_ADDR,
-       relocminalign, code32flat_start)
-                 + relocstr
-                 + """
+%s
+        datalow_start = ABSOLUTE(.) ;
+%s
+        datalow_end = ABSOLUTE(.) ;
         code32init_start = ABSOLUTE(.) ;
-"""
-                 + outRelSections(getSectionsPrefix(sections32flat, '32init', '')
-                                  , 'code32flat_start')
-                 + """
+%s
         code32init_end = ABSOLUTE(.) ;
-"""
-                 + outRelSections(getSectionsPrefix(sections32flat, '32flat', '')
-                                  , 'code32flat_start')
-                 + """
+%s
         . = ( 0x%x - code32flat_start ) ;
         *(.text32seg)
         . = ( 0x%x - code32flat_start ) ;
         *(.text16)
         code32flat_end = ABSOLUTE(.) ;
     } :text
-""" % (code32seg_start + BUILD_BIOS_ADDR, code16_start + BUILD_BIOS_ADDR)
-                 + COMMONTRAILER
-                 + """
+""" % (entrysym.name, entrysympos,
+       li.sec32init_align,
+       li.sec32low_align,
+       sec32all_start,
+       relocstr,
+       outRelSections(li.sections32low, 'code32flat_start'),
+       outRelSections(li.sections32init, 'code32flat_start'),
+       outRelSections(li.sections32flat, 'code32flat_start'),
+       li.sec32seg_start,
+       li.sec16_start)
+    out = COMMONHEADER + out + COMMONTRAILER + """
 ENTRY(%s)
 PHDRS
 {
         text PT_LOAD AT ( code32flat_start ) ;
 }
-""" % (entrysym.name,))
-    output.close()
+""" % (entrysym.name,)
+    outfile = open(out32flat, 'wb')
+    outfile.write(out)
+    outfile.close()
 
 
 ######################################################################
 # Detection of init code
 ######################################################################
 
-# Determine init section relocations
-def genRelocs(sections):
-    absrelocs = []
-    relrelocs = []
-    initrelocs = []
-    minalign = 16
-    for section in sections:
-        if section.category == '32init' and section.align > minalign:
-            minalign = section.align
-        for reloc in section.relocs:
-            symbol = reloc.symbol
-            if symbol.section is None:
-                continue
-            relocpos = section.finalloc + reloc.offset
-            if (reloc.type == 'R_386_32' and section.category == '32init'
-                and symbol.section.category == '32init'):
-                # Absolute relocation
-                absrelocs.append(relocpos)
-            elif (reloc.type == 'R_386_PC32' and section.category == '32init'
-                  and symbol.section.category != '32init'):
-                # Relative relocation
-                relrelocs.append(relocpos)
-            elif (section.category != '32init'
-                  and symbol.section.category == '32init'):
-                # Relocation to the init section
-                if section.fileid in ('16', '32seg'):
-                    relocpos += BUILD_BIOS_ADDR
-                initrelocs.append(relocpos)
-    absrelocs.sort()
-    relrelocs.sort()
-    initrelocs.sort()
-    out = ("        _reloc_abs_start = ABSOLUTE(.) ;\n"
-           + "".join(["LONG(0x%x - code32init_start)\n" % (pos,)
-                      for pos in absrelocs])
-           + "        _reloc_abs_end = ABSOLUTE(.) ;\n"
-           + "        _reloc_rel_start = ABSOLUTE(.) ;\n"
-           + "".join(["LONG(0x%x - code32init_start)\n" % (pos,)
-                      for pos in relrelocs])
-           + "        _reloc_rel_end = ABSOLUTE(.) ;\n"
-           + "        _reloc_init_start = ABSOLUTE(.) ;\n"
-           + "".join(["LONG(0x%x - code32flat_start)\n" % (pos,)
-                      for pos in initrelocs])
-           + "        _reloc_init_end = ABSOLUTE(.) ;\n")
-    return out, len(absrelocs + relrelocs + initrelocs) * 4, minalign
-
 def markRuntime(section, sections):
     if (section is None or not section.keep or section.category is not None
         or '.init.' in section.name or section.fileid != '32flat'):
@@ -386,7 +419,8 @@ def markRuntime(section, sections):
 def findInit(sections):
     # Recursively find and mark all "runtime" sections.
     for section in sections:
-        if '.runtime.' in section.name or '.export.' in section.name:
+        if ('.datalow.' in section.name or '.runtime.' in section.name
+            or '.export.' in section.name):
             markRuntime(section, sections)
     for section in sections:
         if section.category is not None:
@@ -468,7 +502,7 @@ def gc(info16, info32seg, info32flat):
 
 class Section:
     name = size = alignment = fileid = relocs = None
-    finalloc = category = keep = None
+    finalloc = finalsegloc = category = keep = None
 class Reloc:
     offset = type = symbolname = symbol = None
 class Symbol:
@@ -571,13 +605,17 @@ def main():
     # Separate 32bit flat into runtime and init parts
     findInit(sections)
 
+    # Note "low memory" parts
+    for section in getSectionsPrefix(sections, '.datalow.'):
+        section.category = '32low'
+
     # Determine the final memory locations of each kept section.
-    doLayout(sections)
+    genreloc = '_reloc_abs_start' in info32flat[1]
+    li = doLayout(sections, genreloc)
 
     # Write out linker script files.
     entrysym = info16[1]['entry_elf']
-    genreloc = '_reloc_abs_start' in info32flat[1]
-    writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat)
+    writeLinkerScripts(li, entrysym, genreloc, out16, out32seg, out32flat)
 
 if __name__ == '__main__':
     main()