[SeaBIOS] [PATCH 3/3] Add support for 32bit PCI BIOS entry

Kevin O'Connor kevin at koconnor.net
Tue Dec 29 04:13:08 CET 2009


Add support for 32bit PCI BIOS entry.

Create a new code blob (code32seg) with support for 32bit functions
   that need to utilize explicit segment accesses.
This code blob uses global variables relative to %gs:%ebx.
Add BIOS32 structure and code.
Add code for 32bit PCI BIOS code.


diff --git a/Makefile b/Makefile
index 26c9461..a5fd63d 100644
--- a/Makefile
+++ b/Makefile
@@ -13,12 +13,13 @@ OUT=out/
 # Source files
 SRCBOTH=misc.c pmm.c stacks.c output.c util.c block.c floppy.c ata.c mouse.c \
         kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
-        pnpbios.c pirtable.c vgahooks.c ramdisk.c \
+        pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c \
         usb.c usb-uhci.c usb-ohci.c usb-hid.c paravirt.c
-SRC16=$(SRCBOTH) system.c disk.c apm.c pcibios.c font.c
+SRC16=$(SRCBOTH) system.c disk.c apm.c font.c
 SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
       acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
       lzmadecode.c
+SRC32SEG=util.c output.c pci.c pcibios.c
 
 cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
               /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;)
@@ -34,10 +35,12 @@ COMMONCFLAGS += $(call cc-option,$(CC),-nopie,)
 COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
 COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
 
-override CFLAGS = $(COMMONCFLAGS) -g -DMODE16=0 -DMODESEGMENT=0
-CFLAGS16INC = $(COMMONCFLAGS) -DMODE16=1 -DMODESEGMENT=1 -fno-defer-pop \
-              $(call cc-option,$(CC),-fno-jump-tables,-DMANUAL_NO_JUMP_TABLE) \
-              $(call cc-option,$(CC),-fno-tree-switch-conversion,) \
+CFLAGS32FLAT = $(COMMONCFLAGS) -g -DMODE16=0 -DMODESEGMENT=0
+CFLAGSSEG = $(COMMONCFLAGS) -DMODESEGMENT=1 -fno-defer-pop \
+            $(call cc-option,$(CC),-fno-jump-tables,-DMANUAL_NO_JUMP_TABLE) \
+            $(call cc-option,$(CC),-fno-tree-switch-conversion,)
+CFLAGS32SEG = $(CFLAGSSEG) -DMODE16=0
+CFLAGS16INC = $(CFLAGSSEG) -DMODE16=1 \
               $(call cc-option,$(CC),--param large-stack-frame=4,)
 CFLAGS16 = $(CFLAGS16INC) -g
 
@@ -112,36 +115,46 @@ $(OUT)asm-offsets.h: $(OUT)asm-offsets.s
 
 $(OUT)ccode.16.s: ; $(call whole-compile, $(CFLAGS16) -S, $(addprefix src/, $(SRC16)),$@)
 
-$(OUT)ccode32flat.o: ; $(call whole-compile, $(CFLAGS), $(addprefix src/, $(SRC32FLAT)),$@)
+$(OUT)code32seg.o: ; $(call whole-compile, $(CFLAGS32SEG), $(addprefix src/, $(SRC32SEG)),$@)
+
+$(OUT)ccode32flat.o: ; $(call whole-compile, $(CFLAGS32FLAT), $(addprefix src/, $(SRC32FLAT)),$@)
 
 $(OUT)code16.o: romlayout.S $(OUT)ccode.16.s $(OUT)asm-offsets.h
 	@echo "  Compiling (16bit) $@"
 	$(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ $< -o $@
 
-$(OUT)romlayout16.lds $(OUT)romlayout32flat.lds $(OUT)code32flat.o: $(OUT)ccode32flat.o $(OUT)code16.o tools/layoutrom.py
+$(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds $(OUT)code32flat.o: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)code16.o tools/layoutrom.py
 	@echo "  Building ld scripts (version \"$(VERSION)\")"
 	$(Q)echo 'const char VERSION[] = "$(VERSION)";' > $(OUT)version.c
-	$(Q)$(CC) $(CFLAGS) -c $(OUT)version.c -o $(OUT)version.o
+	$(Q)$(CC) $(CFLAGS32FLAT) -c $(OUT)version.c -o $(OUT)version.o
 	$(Q)$(LD) -melf_i386 -r $(OUT)ccode32flat.o $(OUT)version.o -o $(OUT)code32flat.o
 	$(Q)$(OBJDUMP) -thr $(OUT)code32flat.o > $(OUT)code32flat.o.objdump
+	$(Q)$(OBJDUMP) -thr $(OUT)code32seg.o > $(OUT)code32seg.o.objdump
 	$(Q)$(OBJDUMP) -thr $(OUT)code16.o > $(OUT)code16.o.objdump
-	$(Q)./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32flat.o.objdump $(OUT)romlayout16.lds $(OUT)romlayout32flat.lds
+	$(Q)./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32seg.o.objdump $(OUT)code32flat.o.objdump $(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds
 
 
 $(OUT)rom16.o: $(OUT)code16.o $(OUT)rom32flat.o $(OUT)romlayout16.lds
 	@echo "  Linking (no relocs) $@"
 	$(Q)$(LD) -r -T $(OUT)romlayout16.lds $< -o $@
 
+$(OUT)rom32seg.o: $(OUT)code32seg.o $(OUT)romlayout32seg.lds
+	@echo "  Linking (no relocs) $@"
+	$(Q)$(LD) -r -T $(OUT)romlayout32seg.lds $< -o $@
+
 $(OUT)rom32flat.o: $(OUT)code32flat.o $(OUT)romlayout32flat.lds
 	@echo "  Linking (no relocs) $@"
 	$(Q)$(LD) -r -T $(OUT)romlayout32flat.lds $< -o $@
 
-$(OUT)rom.o: $(OUT)rom16.o $(OUT)rom32flat.o $(OUT)rombios16.lds $(OUT)rombios.lds
+$(OUT)rom.o: $(OUT)rom16.o $(OUT)rom32seg.o $(OUT)rom32flat.o $(OUT)rombios16.lds  $(OUT)rombios32seg.lds $(OUT)rombios.lds
 	@echo "  Linking $@"
-	$(Q)$(LD) -T $(OUT)rombios16.lds $(OUT)rom16.o -R $(OUT)rom32flat.o -o $(OUT)rom16.reloc.o
+	$(Q)$(LD) -T $(OUT)rombios16.lds $(OUT)rom16.o -R $(OUT)rom32seg.o -R $(OUT)rom32flat.o -o $(OUT)rom16.reloc.o
 	$(Q)$(STRIP) $(OUT)rom16.reloc.o -o $(OUT)rom16.final.o
 	$(Q)$(OBJCOPY) --adjust-vma 0xf0000 $(OUT)rom16.o $(OUT)rom16.moved.o
-	$(Q)$(LD) -T $(OUT)rombios.lds $(OUT)rom16.final.o $(OUT)rom32flat.o -R $(OUT)rom16.moved.o -o $@
+	$(Q)$(LD) -T $(OUT)rombios32seg.lds $(OUT)rom32seg.o -R $(OUT)rom16.o -R $(OUT)rom32flat.o -o $(OUT)rom32seg.reloc.o
+	$(Q)$(STRIP) $(OUT)rom32seg.reloc.o -o $(OUT)rom32seg.final.o
+	$(Q)$(OBJCOPY) --adjust-vma 0xf0000 $(OUT)rom32seg.o $(OUT)rom32seg.moved.o
+	$(Q)$(LD) -T $(OUT)rombios.lds $(OUT)rom16.final.o $(OUT)rom32seg.final.o $(OUT)rom32flat.o -R $(OUT)rom16.moved.o -R $(OUT)rom32seg.moved.o -o $@
 
 $(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py
 	@echo "  Prepping $@"
diff --git a/src/biosvar.h b/src/biosvar.h
index 6a789e4..eb34286 100644
--- a/src/biosvar.h
+++ b/src/biosvar.h
@@ -260,12 +260,21 @@ get_ebda_ptr()
  * Global variables
  ****************************************************************/
 
+#if MODE16 == 0 && MODESEGMENT == 1
+// In 32bit segmented mode %cs may not be readable and the code may be
+// relocated.  The entry code sets up %gs with a readable segment and
+// %ebx with the base code offset.
+#define GLOBAL_SEGREG GS
+#define GLOBAL_OFFSET __CodeOffset
+#else
 #define GLOBAL_SEGREG CS
+#define GLOBAL_OFFSET 0
+#endif
 static inline u16 get_global_seg() {
     return GET_SEG(GLOBAL_SEGREG);
 }
 #define GET_GLOBAL(var)                         \
-    GET_VAR(GLOBAL_SEGREG, (var))
+    GET_VAR(GLOBAL_SEGREG, *(typeof(&(var)))((void*)&(var) + GLOBAL_OFFSET))
 #define SET_GLOBAL(var, val) do {               \
         ASSERT32FLAT();                         \
         (var) = (val);                          \
diff --git a/src/config.h b/src/config.h
index cf5678d..1450bf7 100644
--- a/src/config.h
+++ b/src/config.h
@@ -192,6 +192,7 @@
 #define DEBUG_ISR_hwpic2 5
 #define DEBUG_HDL_pnp 1
 #define DEBUG_HDL_pmm 1
+#define DEBUG_HDL_pcibios32 9
 
 #define DEBUG_unimplemented 2
 #define DEBUG_invalid 3
diff --git a/src/optionroms.c b/src/optionroms.c
index 0be6852..31bb98b 100644
--- a/src/optionroms.c
+++ b/src/optionroms.c
@@ -172,10 +172,10 @@ get_pci_rom(struct rom_header *rom)
 static inline u32
 max_rom()
 {
-    extern u8 code32_start[];
-    if ((u32)code32_start > BUILD_BIOS_ADDR)
+    extern u8 code32flat_start[];
+    if ((u32)code32flat_start > BUILD_BIOS_ADDR)
         return BUILD_BIOS_ADDR;
-    return (u32)code32_start;
+    return (u32)code32flat_start;
 }
 
 // Copy a rom to its permanent location below 1MiB
diff --git a/src/output.c b/src/output.c
index 3b0e0e7..2e7175e 100644
--- a/src/output.c
+++ b/src/output.c
@@ -87,8 +87,10 @@ putc_debug(struct putcinfo *action, char c)
 // In segmented mode just need a dummy variable (putc_debug is always
 // used anyway), and in 32bit flat mode need a pointer to the 32bit
 // instance of putc_debug().
-#if MODESEGMENT
+#if MODE16
 static struct putcinfo debuginfo VAR16;
+#elif MODESEGMENT
+static struct putcinfo debuginfo VAR32SEG;
 #else
 static struct putcinfo debuginfo = { putc_debug };
 #endif
diff --git a/src/pcibios.c b/src/pcibios.c
index 6fb7d9e..91b7655 100644
--- a/src/pcibios.c
+++ b/src/pcibios.c
@@ -12,6 +12,10 @@
 #include "biosvar.h" // GET_EBDA
 #include "pci_regs.h" // PCI_VENDOR_ID
 
+// romlayout.S
+extern void bios32_entry();
+extern void pcibios32_entry();
+
 #define RET_FUNC_NOT_SUPPORTED 0x81
 #define RET_BAD_VENDOR_ID      0x83
 #define RET_DEVICE_NOT_FOUND   0x86
@@ -30,8 +34,7 @@ handle_1ab101(struct bregs *regs)
     regs->bx = 0x0210; // PCI version 2.10
     regs->cl = pci_bdf_to_bus(max - 1);
     regs->edx = 0x20494350; // "PCI "
-    // XXX - bochs bios code sets edi to point to 32bit code - but no
-    // reference to this in spec.
+    regs->edi = (u32)pcibios32_entry + BUILD_BIOS_ADDR;
     set_code_success(regs);
 }
 
@@ -154,7 +157,7 @@ handle_1ab10e(struct bregs *regs)
 
     // Memcpy pir table slots to dest buffer.
     memcpy_far(buf_seg, buf_far
-               , get_global_seg(), pirtable_g->slots
+               , get_global_seg(), (void*)(pirtable_g->slots) + GLOBAL_OFFSET
                , pirsize);
 
     // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
@@ -192,3 +195,41 @@ handle_1ab1(struct bregs *regs)
     default:   handle_1ab1XX(regs); break;
     }
 }
+
+
+/****************************************************************
+ * 32bit interface
+ ****************************************************************/
+
+#if MODE16 == 0 && MODESEGMENT == 1
+// Entry point for 32bit pci bios functions.
+void VISIBLE32SEG
+handle_pcibios32(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_pcibios32);
+    handle_1ab1(regs);
+}
+#endif
+
+struct bios32_s {
+    u32 signature;
+    u32 entry;
+    u8 version;
+    u8 length;
+    u8 checksum;
+    u8 reserved[5];
+} PACKED;
+
+struct bios32_s BIOS32HEADER __aligned(16) VAR16EXPORT = {
+    .signature = 0x5f32335f, // _32_
+    .length = sizeof(BIOS32HEADER) / 16,
+};
+
+void
+bios32_setup(void)
+{
+    dprintf(3, "init bios32\n");
+
+    BIOS32HEADER.entry = (u32)bios32_entry;
+    BIOS32HEADER.checksum -= checksum(&BIOS32HEADER, sizeof(BIOS32HEADER));
+}
diff --git a/src/pmm.c b/src/pmm.c
index d05cc6f..dab8fb3 100644
--- a/src/pmm.c
+++ b/src/pmm.c
@@ -290,10 +290,11 @@ malloc_setup()
     PMMAllocs = NULL;
 
     // Memory in 0xf0000 area.
-    extern u8 code32_start[];
-    if ((u32)code32_start > BUILD_BIOS_ADDR)
+    extern u8 code32flat_start[];
+    if ((u32)code32flat_start > BUILD_BIOS_ADDR)
         // Clear unused parts of f-segment
-        memset((void*)BUILD_BIOS_ADDR, 0, (u32)code32_start - BUILD_BIOS_ADDR);
+        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;
diff --git a/src/post.c b/src/post.c
index 2f14aa7..db9d8f7 100644
--- a/src/post.c
+++ b/src/post.c
@@ -189,6 +189,7 @@ post()
     smm_init();
 
     // Setup interfaces that option roms may need
+    bios32_setup();
     pmm_setup();
     pnp_setup();
     kbd_setup();
diff --git a/src/rombios.lds.S b/src/rombios.lds.S
index 6f6040b..20cbebe 100644
--- a/src/rombios.lds.S
+++ b/src/rombios.lds.S
@@ -11,12 +11,15 @@ OUTPUT_ARCH("i386")
 ENTRY(post32)
 SECTIONS
 {
-        .text code32_start : {
-                *(.text32)
+        .text code32flat_start : {
+                *(.text32flat)
 
-                . = data16_start + BUILD_BIOS_ADDR - code32_start ;
+                . = code32seg_start + BUILD_BIOS_ADDR - code32flat_start ;
+                *(.text32seg)
+
+                . = data16_start + BUILD_BIOS_ADDR - code32flat_start ;
                 *(.data16)
-                . = text16_start + BUILD_BIOS_ADDR - code32_start ;
+                . = text16_start + BUILD_BIOS_ADDR - code32flat_start ;
                 *(.text16)
                 final_text16_end = . ;
                 }
diff --git a/src/romlayout.S b/src/romlayout.S
index b651a2b..afdefed 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -374,6 +374,64 @@ apm32protected_entry:
         popfw
         lretl
 
+// PCI-BIOS 32bit entry point
+        DECLFUNC pcibios32_entry
+pcibios32_entry:
+        pushfl
+        pushl %gs               // Backup %gs
+        cli
+        cld
+        pushl %eax              // Save registers (matches struct bregs)
+        pushl %ecx
+        pushl %edx
+        pushl %ebx
+        pushl %ebp
+        pushl %esi
+        pushl %edi
+        pushw %es
+        pushw %ds
+        calll 1f                // Setup %ebx to be code base
+1:      popl %ebx
+        subl $1b, %ebx
+        movl %ds, %eax          // Move %ds to %gs
+        movl %eax, %gs
+        movl %ss, %eax          // Move %ss to %ds
+        movl %eax, %ds
+        movl %esp, %eax         // First arg is pointer to struct bregs
+        calll handle_pcibios32
+        popw %ds                // Restore registers (from struct bregs)
+        popw %es
+        popl %edi
+        popl %esi
+        popl %ebp
+        popl %ebx
+        popl %edx
+        popl %ecx
+        popl %eax
+        popl %gs
+        popfl
+        lretl
+
+// BIOS32 support
+        EXPORTFUNC bios32_entry
+bios32_entry:
+        pushfl
+#if CONFIG_PCIBIOS
+        // Check for PCI-BIOS request
+        cmpl $0x49435024, %eax // $PCI
+        jne 1f
+        movl $BUILD_BIOS_ADDR, %ebx
+        movl $BUILD_BIOS_SIZE, %ecx
+        movl $pcibios32_entry, %edx
+        xorb %al, %al
+        jmp 2f
+#endif
+        // Unknown request
+1:      movb $0x80, %al
+        // Return to caller
+2:      popfl
+        lretl
+
 // 32bit elf entry point
         EXPORTFUNC post32
 post32:
diff --git a/src/types.h b/src/types.h
index b9786e2..cc64cba 100644
--- a/src/types.h
+++ b/src/types.h
@@ -33,6 +33,9 @@ union u64_u32_u {
 
 #define UNIQSEC __FILE__ "." __stringify(__LINE__)
 
+extern void __force_link_error__only_in_32bit_flat() __attribute__ ((noreturn));
+extern void __force_link_error__only_in_16bit() __attribute__ ((noreturn));
+
 #define __ASM(code) asm(".section .text.asm." UNIQSEC "\n\t" code)
 
 #if MODE16 == 1
@@ -40,6 +43,8 @@ union u64_u32_u {
 # define VISIBLE16 __VISIBLE
 // Notes a function as externally visible in the 32bit flat code chunk.
 # define VISIBLE32FLAT
+// Notes a function as externally visible in the 32bit segmented code chunk.
+# define VISIBLE32SEG
 // Designate a variable as (only) visible to 16bit code.
 # define VAR16 __section(".data16." UNIQSEC)
 // Designate a variable as visible to 16bit, 32bit, and assembler code.
@@ -48,6 +53,8 @@ union u64_u32_u {
 # define VAR16EXPORT __section(".data16.export." UNIQSEC) __VISIBLE
 // Designate a variable at a specific 16bit address
 # define VAR16FIXED(addr) __aligned(1) __VISIBLE __section(".fixedaddr." __stringify(addr))
+// Designate a variable as (only) visible to 32bit segmented code.
+# 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 top-level assembler as 16bit only.
@@ -55,20 +62,35 @@ union u64_u32_u {
 // Designate top-level assembler as 32bit flat only.
 # define ASM32FLAT(code)
 // Compile time check for a given mode.
-extern void __force_link_error__only_in_32bit_flat() __attribute__ ((noreturn));
 #define ASSERT16() do { } while (0)
 #define ASSERT32FLAT() __force_link_error__only_in_32bit_flat()
+#elif MODESEGMENT == 1
+register u32 __CodeOffset asm ("ebx") __VISIBLE;
+# define VISIBLE16
+# define VISIBLE32FLAT
+# define VISIBLE32SEG __VISIBLE
+# define VAR16 __section(".discard.var16." UNIQSEC)
+# define VAR16VISIBLE VAR16 __VISIBLE __weak
+# define VAR16EXPORT VAR16VISIBLE
+# define VAR16FIXED(addr) VAR16VISIBLE
+# define VAR32SEG __section(".data32seg." UNIQSEC)
+# define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak
+# define ASM16(code)
+# define ASM32FLAT(code)
+#define ASSERT16() __force_link_error__only_in_16bit()
+#define ASSERT32FLAT() __force_link_error__only_in_32bit_flat()
 #else
 # define VISIBLE16
 # define VISIBLE32FLAT __VISIBLE
+# define VISIBLE32SEG
 # define VAR16 __section(".discard.var16." UNIQSEC)
 # define VAR16VISIBLE VAR16 __VISIBLE __weak
 # define VAR16EXPORT VAR16VISIBLE
 # define VAR16FIXED(addr) VAR16VISIBLE
+# define VAR32SEG __section(".discard.var32seg." UNIQSEC)
 # define VAR32FLATVISIBLE __VISIBLE
 # define ASM16(code)
 # define ASM32FLAT(code) __ASM(code)
-extern void __force_link_error__only_in_16bit() __attribute__ ((noreturn));
 #define ASSERT16() __force_link_error__only_in_16bit()
 #define ASSERT32FLAT() do { } while (0)
 #endif
diff --git a/src/util.h b/src/util.h
index 7d95cbe..7117fa5 100644
--- a/src/util.h
+++ b/src/util.h
@@ -268,6 +268,7 @@ void VISIBLE16 handle_1553(struct bregs *regs);
 
 // pcibios.c
 void handle_1ab1(struct bregs *regs);
+void bios32_setup(void);
 
 // shadow.c
 void make_bios_writable();
diff --git a/tools/checkrom.py b/tools/checkrom.py
index 6f7b3ba..5c9600f 100755
--- a/tools/checkrom.py
+++ b/tools/checkrom.py
@@ -39,14 +39,21 @@ def main():
         print "Error!  Code is too big (0x%x vs 0x%x)" % (
             datasize, finalsize)
         sys.exit(1)
+    actualdatasize = f16e - syms['code32flat_start']
+    if datasize != actualdatasize:
+        print "Error!  Unknown extra data (0x%x vs 0x%x)" % (
+            datasize, actualdatasize)
+        sys.exit(1)
 
     # Print statistics
     sizefree = syms['freespace_end'] - syms['freespace_start']
     size16 = syms['text16_end'] - syms['data16_start']
-    size32 = syms['code32_end'] - syms['code32_start']
-    totalc = size16+size32
-    print "16bit size: %d" % size16
-    print "32bit size: %d" % size32
+    size32seg = syms['code32seg_end'] - syms['code32seg_start']
+    size32flat = syms['code32flat_end'] - syms['code32flat_start']
+    totalc = size16+size32seg+size32flat
+    print "16bit size:           %d" % size16
+    print "32bit segmented size: %d" % size32seg
+    print "32bit flat size:      %d" % size32flat
     print "Total size: %d  Free space: %d  Percent used: %.1f%% (%dKiB rom)" % (
         totalc, sizefree + finalsize - datasize
         , (totalc / float(finalsize)) * 100.0
diff --git a/tools/layoutrom.py b/tools/layoutrom.py
index 85bdc7d..3113407 100755
--- a/tools/layoutrom.py
+++ b/tools/layoutrom.py
@@ -151,7 +151,6 @@ def doLayout16(sections, outname):
     output.write(COMMONHEADER + """
         data16_start = 0x%x ;
         .data16 data16_start : {
-                freespace_end = . ;
 """ % data16_start)
     outSections(output, datasections)
     output.write("code16_rodata = . ;\n")
@@ -199,23 +198,53 @@ def getSectionsPrefix(sections, prefix):
             out.append((size, align, name))
     return out
 
-# Layout the 32bit code.  This places the code as high as possible.
-def doLayout32(sections, outname, start16):
-    start16 += 0xf0000
+# Layout the 32bit segmented code.  This places the code as high as possible.
+def doLayout32seg(sections, outname, endat):
+    # Find sections to output
+    textsections = getSectionsPrefix(sections, '.text.')
+    rodatasections = (getSectionsPrefix(sections, '.rodata.str1.1')
+                      + getSectionsPrefix(sections, '.rodata.__func__.'))
+    datasections = getSectionsPrefix(sections, '.data32seg.')
+    startat = getSectionsStart(
+        textsections + rodatasections + datasections, endat)
+
+    # Write sections
+    output = open(outname, 'wb')
+    output.write(COMMONHEADER + """
+        code32seg_start = 0x%x ;
+        .text32seg code32seg_start : {
+                freespace_end = . ;
+""" % startat)
+
+    outSections(output, textsections)
+    output.write("code32seg_rodata = . ;\n")
+    outSections(output, rodatasections)
+    outSections(output, datasections)
+
+    output.write("""
+                code32seg_end = ABSOLUTE(.) ;
+        }
+        /DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) }
+""" + COMMONTRAILER)
+    return startat
+
+# Layout the 32bit flat code.  This places the code as high as possible.
+def doLayout32flat(sections, outname, endat):
+    endat += 0xf0000
     # Find sections to output
     textsections = getSectionsPrefix(sections, '.text.')
     rodatasections = getSectionsPrefix(sections, '.rodata')
     datasections = getSectionsPrefix(sections, '.data.')
     bsssections = getSectionsPrefix(sections, '.bss.')
-    start32 = getSectionsStart(
-        textsections + rodatasections + datasections + bsssections, start16, 512)
+    startat = getSectionsStart(
+        textsections + rodatasections + datasections + bsssections, endat, 512)
 
     # Write sections
     output = open(outname, 'wb')
     output.write(COMMONHEADER + """
-        .text32 0x%x : {
-                code32_start = ABSOLUTE(.) ;
-""" % start32)
+        code32flat_start = 0x%x ;
+        .text32flat code32flat_start : {
+""" % startat)
 
     outSections(output, textsections)
     output.write("code32_rodata = . ;\n")
@@ -225,63 +254,70 @@ def doLayout32(sections, outname, start16):
 
     output.write("""
                 freespace_start = . ;
-                code32_end = ABSOLUTE(.) ;
+                code32flat_end = ABSOLUTE(.) ;
         }
 """ + COMMONTRAILER)
+    return startat
 
 
 ######################################################################
 # Section garbage collection
 ######################################################################
 
+def getSectionsList(info, names):
+    out = []
+    for i in info[0]:
+        size, align, section = i
+        if section not in names:
+#            print "gc", section
+            continue
+        out.append(i)
+    return out
+
 # Note required section, and recursively set all referenced sections
 # as required.
-def keepsection(name, pri, alt):
-    if name in pri[3]:
+def keepsection(name, infos, pos=0):
+    if name in infos[pos][3]:
         # Already kept - nothing to do.
         return
-    pri[3].append(name)
-    relocs = pri[2].get(name)
+    infos[pos][3].append(name)
+    relocs = infos[pos][2].get(name)
     if relocs is None:
         return
     # Keep all sections that this section points to
     for symbol in relocs:
-        addr, section = pri[1].get(symbol, (None, None))
+        addr, section = infos[pos][1].get(symbol, (None, None))
         if (section is not None and '*' not in section
             and section[:9] != '.discard.'):
-            keepsection(section, pri, alt)
+            keepsection(section, infos, pos)
             continue
         # Not in primary sections - it may be a cross 16/32 reference
-        addr, section = alt[1].get(symbol, (None, None))
+        newpos = (pos+1)%3
+        addr, section = infos[newpos][1].get(symbol, (None, None))
+        if section is not None and '*' not in section:
+            keepsection(section, infos, newpos)
+            continue
+        newpos = (pos+2)%3
+        addr, section = infos[(pos+2)%3][1].get(symbol, (None, None))
         if section is not None and '*' not in section:
-            keepsection(section, alt, pri)
+            keepsection(section, infos, newpos)
 
 # Determine which sections are actually referenced and need to be
 # placed into the output file.
-def gc(info16, info32):
-    # pri = (sections, symbols, relocs, keep sections)
-    pri = (info16[0], info16[1], info16[2], [])
-    alt = (info32[0], info32[1], info32[2], [])
+def gc(info16, info32seg, info32flat):
+    # infos = ((sections, symbols, relocs, keep sections), ...)
+    infos = ((info16[0], info16[1], info16[2], []),
+             (info32seg[0], info32seg[1], info32seg[2], []),
+             (info32flat[0], info32flat[1], info32flat[2], []))
     # Start by keeping sections that are globally visible.
     for size, align, section in info16[0]:
         if section[:11] == '.fixedaddr.' or '.export.' in section:
-            keepsection(section, pri, alt)
+            keepsection(section, infos)
     # Return sections found.
-    sections16 = []
-    for info in info16[0]:
-        size, align, section = info
-        if section not in pri[3]:
-#            print "gc16", section
-            continue
-        sections16.append(info)
-    sections32 = []
-    for info in info32[0]:
-        size, align, section = info
-        if section not in alt[3]:
-#            print "gc32", section
-            continue
-        sections32.append(info)
-    return sections16, sections32
+    sections16 = getSectionsList(info16, infos[0][3])
+    sections32seg = getSectionsList(info32seg, infos[1][3])
+    sections32flat = getSectionsList(info32flat, infos[2][3])
+    return sections16, sections32seg, sections32flat
 
 
 ######################################################################
@@ -340,18 +376,21 @@ def parseObjDump(file):
 
 def main():
     # Get output name
-    in16, in32, out16, out32 = sys.argv[1:]
+    in16, in32seg, in32flat, out16, out32seg, out32flat = sys.argv[1:]
 
     infile16 = open(in16, 'rb')
-    infile32 = open(in32, 'rb')
+    infile32seg = open(in32seg, 'rb')
+    infile32flat = open(in32flat, 'rb')
 
     info16 = parseObjDump(infile16)
-    info32 = parseObjDump(infile32)
+    info32seg = parseObjDump(infile32seg)
+    info32flat = parseObjDump(infile32flat)
 
-    sections16, sections32 = gc(info16, info32)
+    sections16, sections32seg, sections32flat = gc(info16, info32seg, info32flat)
 
     start16 = doLayout16(sections16, out16)
-    doLayout32(sections32, out32, start16)
+    start32seg = doLayout32seg(sections32seg, out32seg, start16)
+    doLayout32flat(sections32flat, out32flat, start32seg)
 
 if __name__ == '__main__':
     main()



More information about the SeaBIOS mailing list