Avoid runtime relocation of 16bit "low" mem - calculate at build instead.

Some 16bit accesses to "low" mem variables use 16bit relocations
instead of the normal 32bit relocations.  This causes build problems
if the "low" mem sections move more than 64K during relocation.

The final location of the "low" memory can be determined during the
build, so link the 16bit code with the final post-reloc location of
the "low" mem variables instead.  This eliminates the need to do these
runtime relocations on the 16bit code.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
diff --git a/src/biosvar.h b/src/biosvar.h
index fd2f1bf..eceee54 100644
--- a/src/biosvar.h
+++ b/src/biosvar.h
@@ -250,13 +250,13 @@
  * "Low" memory variables
  ****************************************************************/
 
-extern u8 _datalow_seg, _datalow_base[];
+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))
-#define LOWFLAT2LOW(var) ((typeof(var))((void*)(var) - (u32)_datalow_base))
+#define LOWFLAT2LOW(var) ((typeof(var))((void*)(var) - (u32)datalow_base))
 #else
 #define GET_LOW(var)            (var)
 #define SET_LOW(var, val)       do { (var) = (val); } while (0)
diff --git a/src/pmm.c b/src/pmm.c
index 5d43645..1addb41 100644
--- a/src/pmm.c
+++ b/src/pmm.c
@@ -170,13 +170,6 @@
 
 #define OPROM_HEADER_RESERVE 16
 
-// Return maximum address of read/writable "low mem" space.
-static inline u32 lowmemend(void) {
-    extern u8 code32flat_start[], code32init_end[];
-    u32 end = CONFIG_RELOCATE_INIT ? (u32)code32init_end : (u32)code32flat_start;
-    return end > BUILD_BIOS_ADDR ? BUILD_BIOS_ADDR : end;
-}
-
 // Return the memory position up to which roms may be located.
 u32
 rom_get_top(void)
@@ -199,8 +192,8 @@
     u32 newend = ALIGN(RomEnd + size, OPTION_ROM_ALIGN) + OPROM_HEADER_RESERVE;
     if (newend > (u32)RomBase->allocend)
         return NULL;
-    if (newend < (u32)_datalow_base + OPROM_HEADER_RESERVE)
-        newend = (u32)_datalow_base + OPROM_HEADER_RESERVE;
+    if (newend < (u32)datalow_base + OPROM_HEADER_RESERVE)
+        newend = (u32)datalow_base + OPROM_HEADER_RESERVE;
     RomBase->data = RomBase->dataend = (void*)newend;
     return (void*)RomEnd;
 }
@@ -253,7 +246,8 @@
     // Populate other regions
     addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM);
     addSpace(&ZoneFSeg, BiosTableSpace, &BiosTableSpace[CONFIG_MAX_BIOSTABLE]);
-    addSpace(&ZoneLow, _datalow_base + OPROM_HEADER_RESERVE, (void*)lowmemend());
+    extern u8 final_datalow_start[];
+    addSpace(&ZoneLow, datalow_base + OPROM_HEADER_RESERVE, final_datalow_start);
     RomBase = findLast(&ZoneLow);
     if (highram) {
         addSpace(&ZoneHigh, (void*)highram
diff --git a/src/post.c b/src/post.c
index 1d0d35a..3101505 100644
--- a/src/post.c
+++ b/src/post.c
@@ -97,7 +97,7 @@
              , E820_RESERVED);
 
     // Init extra stack
-    StackPos = (void*)(&ExtraStack[BUILD_EXTRA_STACK_SIZE] - _datalow_base);
+    StackPos = (void*)(&ExtraStack[BUILD_EXTRA_STACK_SIZE] - datalow_base);
 }
 
 static void
@@ -293,14 +293,14 @@
 
 // Relocation fixup code that runs at new address after relocation complete.
 static void
-afterReloc(void *datalow)
+afterReloc(void)
 {
     // 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);
+    extern u8 datalow_start[], datalow_end[], final_datalow_start[];
+    memmove(final_datalow_start, datalow_start, datalow_end - datalow_start);
 
     // Run main code
     maininit();
@@ -331,24 +331,20 @@
     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[];
+    extern u8 datalow_start[], datalow_end[], final_datalow_start[];
 
     // Allocate space for init code.
     u32 initsize = code32init_end - code32init_start;
     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)
+    if (!codedest)
         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);
+            , datalow_start, final_datalow_start, datalow_end - datalow_start);
     updateRelocs(code32flat_start, _reloc_datalow_start, _reloc_datalow_end
-                 , datalow - (void*)datalow_start);
+                 , final_datalow_start - datalow_start);
     dprintf(1, "Relocating init from %p to %p (size %d)\n"
             , code32init_start, codedest, initsize);
     s32 delta = codedest - (void*)code32init_start;
@@ -358,9 +354,9 @@
     updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta);
 
     // Call maininit() in relocated code.
-    void (*func)(void*) = (void*)afterReloc + delta;
+    void (*func)(void) = (void*)afterReloc + delta;
     barrier();
-    func(datalow);
+    func();
 }
 
 // Setup for code relocation and then call reloc_init
diff --git a/tools/layoutrom.py b/tools/layoutrom.py
index 74b410f..7a7d08c 100755
--- a/tools/layoutrom.py
+++ b/tools/layoutrom.py
@@ -48,8 +48,6 @@
         totspace = alignpos(totspace, section.align) + section.size
     startaddr = (endaddr - totspace) / minalign * minalign
     curaddr = startaddr
-    # out = [(addr, sectioninfo), ...]
-    out = []
     for section in sections:
         curaddr = alignpos(curaddr, section.align)
         section.finalloc = curaddr
@@ -159,7 +157,7 @@
     sections32flat = sec32flat_start = sec32flat_align = None
     sections32init = sec32init_start = sec32init_align = None
     sections32low = sec32low_start = sec32low_align = None
-    datalow_base = None
+    datalow_base = final_sec32low_start = None
 
 # Determine final memory addresses for sections
 def doLayout(sections, genreloc):
@@ -219,13 +217,17 @@
     li.sections32low = getSectionsCategory(sections, '32low')
     if genreloc:
         sec32low_top = li.sec32init_start
-        datalow_base = min(BUILD_BIOS_ADDR, li.sec32flat_start) - 64*1024
+        final_sec32low_top = min(BUILD_BIOS_ADDR, li.sec32flat_start)
     else:
         sec32low_top = min(BUILD_BIOS_ADDR, li.sec32init_start)
-        datalow_base = sec32low_top - 64*1024
+        final_sec32low_top = sec32low_top
+    relocdelta = final_sec32low_top - sec32low_top
+    datalow_base = final_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)
+        li.sections32low, sec32low_top, 16
+        , segoffset=li.datalow_base - relocdelta)
+    li.final_sec32low_start = li.sec32low_start + relocdelta
 
     # Print statistics
     size16 = BUILD_BIOS_ADDR + BUILD_BIOS_SIZE - li.sec16_start
@@ -311,7 +313,7 @@
 def writeLinkerScripts(li, entrysym, genreloc, out16, out32seg, out32flat):
     # Write 16bit linker script
     out = outXRefs(li.sections16, useseg=1) + """
-    _datalow_base = 0x%x ;
+    datalow_base = 0x%x ;
     _datalow_seg = 0x%x ;
 
     code16_start = 0x%x ;
@@ -352,8 +354,7 @@
         initrelocs = getRelocs(
             li.sections32flat + li.sections32low + li.sections16
             + li.sections32seg, category='32init')
-        lowrelocs = getRelocs(
-            li.sections16 + li.sections32seg + sections32all, category='32low')
+        lowrelocs = getRelocs(sections32all, category='32low')
         relocstr = (strRelocs("_reloc_abs", "code32init_start", absrelocs)
                     + strRelocs("_reloc_rel", "code32init_start", relrelocs)
                     + strRelocs("_reloc_init", "code32flat_start", initrelocs)
@@ -363,8 +364,8 @@
     out = outXRefs(sections32all) + """
     %s = 0x%x ;
     _reloc_min_align = 0x%x ;
-    _datalow_base = 0x%x ;
-    _datalow_min_align = 0x%x ;
+    datalow_base = 0x%x ;
+    final_datalow_start = 0x%x ;
 
     code32flat_start = 0x%x ;
     .text code32flat_start : {
@@ -385,7 +386,7 @@
 """ % (entrysym.name, entrysympos,
        li.sec32init_align,
        li.datalow_base,
-       li.sec32low_align,
+       li.final_sec32low_start,
        sec32all_start,
        relocstr,
        outRelSections(li.sections32low, 'code32flat_start'),