[SeaBIOS] [PATCH 2/8] Add mechanism to declare variables as "low mem" and use for extra stack.

Kevin O'Connor kevin at koconnor.net
Mon May 14 05:34:42 CEST 2012


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.

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 src/asm-offsets.c  |    8 -----
 src/ata.c          |    4 +--
 src/biosvar.h      |    8 -----
 src/block.c        |    2 +-
 src/config.h       |    1 +
 src/post.c         |   48 ++++++++++++++++++++++--------
 src/romlayout.S    |    9 ++---
 src/stacks.c       |    7 +++-
 src/types.h        |    4 ++
 src/util.h         |    1 +
 tools/layoutrom.py |   81 ++++++++++++++++++++++++++++++++++-----------------
 11 files changed, 106 insertions(+), 67 deletions(-)

diff --git a/src/asm-offsets.c b/src/asm-offsets.c
index 5035cef..b98f3b5 100644
--- a/src/asm-offsets.c
+++ b/src/asm-offsets.c
@@ -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);
 }
diff --git a/src/ata.c b/src/ata.c
index c37691a..b8b0cb3 100644
--- a/src/ata.c
+++ b/src/ata.c
@@ -396,9 +396,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 = (void*)ExtraStack;
     struct sff_dma_prd *origdma = dma;
     while (bytes) {
         if (dma >= &origdma[16])
diff --git a/src/biosvar.h b/src/biosvar.h
index b6f7174..0674df6 100644
--- a/src/biosvar.h
+++ b/src/biosvar.h
@@ -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
diff --git a/src/block.c b/src/block.c
index a80199c..263fa30 100644
--- a/src/block.c
+++ b/src/block.c
@@ -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)
 {
diff --git a/src/config.h b/src/config.h
index 521469b..23591b9 100644
--- a/src/config.h
+++ b/src/config.h
@@ -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
diff --git a/src/post.c b/src/post.c
index 8383b79..3561c0d 100644
--- a/src/post.c
+++ b/src/post.c
@@ -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)
@@ -311,27 +323,37 @@ reloc_init(void)
     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
diff --git a/src/romlayout.S b/src/romlayout.S
index c4b2ef1..917a6fe 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -232,13 +232,12 @@ 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 $ExtraStack, %eax
+        shrl $4, %eax
         movw %ax, %ds
         movw %ax, %ss
-        movl $EBDA_OFFSET_TOP_STACK, %esp
+        movl $BUILD_EXTRA_STACK_SIZE, %esp
         // Call handler.
         jmp handle_resume
 
diff --git a/src/stacks.c b/src/stacks.c
index 17f1a4a..659e5bf 100644
--- a/src/stacks.c
+++ b/src/stacks.c
@@ -152,12 +152,15 @@ wait_irq(void)
  * Stack in EBDA
  ****************************************************************/
 
+// Space for a stack for 16bit code.
+char ExtraStack[BUILD_EXTRA_STACK_SIZE] VARLOW __aligned(16);
+
 // Switch to the extra stack in ebda 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 = FLATPTR_TO_SEG(ExtraStack), bkup_ss;
     u32 bkup_esp;
     asm volatile(
         // Backup current %ss/%esp values.
@@ -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" (BUILD_EXTRA_STACK_SIZE), "r" (stack_seg)
         : "cc", "memory");
     return eax;
 }
diff --git a/src/types.h b/src/types.h
index c0c6d26..0f83697 100644
--- a/src/types.h
+++ b/src/types.h
@@ -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()
diff --git a/src/util.h b/src/util.h
index 04de66b..0c731fe 100644
--- a/src/util.h
+++ b/src/util.h
@@ -230,6 +230,7 @@ int get_keystroke(int msec);
 
 // stacks.c
 u32 call32(void *func, u32 eax, u32 errret);
+extern char ExtraStack[];
 inline u32 stack_hop(u32 eax, u32 edx, void *func);
 extern struct thread_info MainThread;
 extern int CanPreempt;
diff --git a/tools/layoutrom.py b/tools/layoutrom.py
index 86e1f33..bf4a9c4 100755
--- a/tools/layoutrom.py
+++ b/tools/layoutrom.py
@@ -144,7 +144,7 @@ def getSectionsPrefix(sections, category, prefix):
     return [section for section in sections
             if section.category == category and section.name.startswith(prefix)]
 
-def doLayout(sections):
+def doLayout(sections, genreloc):
     # Determine 16bit positions
     textsections = getSectionsPrefix(sections, '16', '.text.')
     rodatasections = (
@@ -190,15 +190,25 @@ def doLayout(sections):
         textsections + rodatasections + datasections + bsssections
         , code32flat_start, 16)
 
+    datalowsections = getSectionsPrefix(sections, '32flat', '.datalow.')
+    for section in datalowsections:
+        section.category = '32low'
+    datalowtop = code32init_start
+    if genreloc:
+        datalowtop = min(datalowtop, BUILD_BIOS_ADDR)
+    datalow_start = setSectionsStart(datalowsections, datalowtop, 16)
+
     # 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
+    sizelow = code32init_start - datalow_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
 
 
 ######################################################################
@@ -235,6 +245,7 @@ def outRelSections(sections, startsym):
         out += "*(%s)\n" % (section.name,)
     return out
 
+# Return the sections with the given fileid (ie, one input object file).
 def getSectionsFile(sections, fileid, defaddr=0):
     sections = [(section.finalloc, section)
                 for section in sections if section.fileid == fileid]
@@ -279,24 +290,31 @@ def writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat)
     # Write 32flat linker script
     sections32flat, code32flat_start = getSectionsFile(
         sections, '32flat', code32seg_start)
-    relocstr = ""
-    relocminalign = 0
+    relocstr = relocdefstr = ""
     if genreloc:
         # Generate relocations
-        relocstr, size, relocminalign = genRelocs(sections)
+        relocstr, size, relocdefstr = genRelocs(sections)
         code32flat_start -= size
     output = open(out32flat, 'wb')
     output.write(COMMONHEADER
                  + outXRefs(sections32flat) + """
     %s = 0x%x ;
-    _reloc_min_align = 0x%x ;
+%s
     code32flat_start = 0x%x ;
     .text code32flat_start : {
 """ % (entrysym.name,
        entrysym.section.finalloc + entrysym.offset + BUILD_BIOS_ADDR,
-       relocminalign, code32flat_start)
+       relocdefstr, code32flat_start)
                  + relocstr
                  + """
+        datalow_start = ABSOLUTE(.) ;
+"""
+                 + outRelSections(getSectionsPrefix(sections32flat, '32low', '')
+                                  , 'code32flat_start')
+                 + """
+        datalow_end = ABSOLUTE(.) ;
+"""
+                 + """
         code32init_start = ABSOLUTE(.) ;
 """
                  + outRelSections(getSectionsPrefix(sections32flat, '32init', '')
@@ -329,20 +347,31 @@ PHDRS
 # Detection of init code
 ######################################################################
 
+def strRelocs(outname, outrel, relocs):
+    return ("        %s_start = ABSOLUTE(.) ;\n" % (outname,)
+            + "".join(["LONG(0x%x - %s)\n" % (pos, outrel)
+                       for pos in relocs])
+            + "        %s_end = ABSOLUTE(.) ;\n" % (outname,))
+
 # Determine init section relocations
 def genRelocs(sections):
     absrelocs = []
     relrelocs = []
     initrelocs = []
-    minalign = 16
+    datalowrelocs = []
+    mincodealign = mindatalowalign = 16
     for section in sections:
-        if section.category == '32init' and section.align > minalign:
-            minalign = section.align
+        if section.category == '32init' and section.align > mincodealign:
+            mincodealign = section.align
+        elif section.category == '32low' and section.align > mindatalowalign:
+            mindatalowalign = section.align
         for reloc in section.relocs:
             symbol = reloc.symbol
             if symbol.section is None:
                 continue
             relocpos = section.finalloc + reloc.offset
+            if section.fileid in ('16', '32seg'):
+                relocpos += BUILD_BIOS_ADDR
             if (reloc.type == 'R_386_32' and section.category == '32init'
                 and symbol.section.category == '32init'):
                 # Absolute relocation
@@ -354,25 +383,22 @@ def genRelocs(sections):
             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)
+            if symbol.section.category == '32low':
+                # Relocation to the low memory section
+                datalowrelocs.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
+    datalowrelocs.sort()
+    relocstr = (strRelocs("_reloc_abs", "code32init_start", absrelocs)
+                + strRelocs("_reloc_rel", "code32init_start", relrelocs)
+                + strRelocs("_reloc_init", "code32flat_start", initrelocs)
+                + strRelocs("_reloc_datalow", "code32flat_start", datalowrelocs))
+    relocdefstr = ("    _reloc_min_align = 0x%x ;\n" % (mincodealign,)
+                   + "    _datalow_min_align = 0x%x ;\n" % (mindatalowalign,))
+    numrelocs = len(absrelocs + relrelocs + initrelocs + datalowrelocs)
+    return relocstr, numrelocs * 4, relocdefstr
 
 def markRuntime(section, sections):
     if (section is None or not section.keep or section.category is not None
@@ -386,7 +412,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:
@@ -572,11 +599,11 @@ def main():
     findInit(sections)
 
     # Determine the final memory locations of each kept section.
-    doLayout(sections)
+    genreloc = '_reloc_abs_start' in info32flat[1]
+    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)
 
 if __name__ == '__main__':
-- 
1.7.6.5




More information about the SeaBIOS mailing list