Allow rom to grow beyond 64K.
If rom is over 64K then use part of e-segment for 32bit code.
Push 32bit code as high as it can go in the f-segment.
Do version building before layoutrom.py - this way layoutrom knows
full size of rom.
Make layoutrom.py build the full ld script - remove now unused ld
scripts that just imported the output of layoutrom.py.
Also, use "objdump" instead of "nm" - reduce toolchain requirements.
Enhance tools/checkrom.py so that it can pad bios.bin to size qemu is
happy with.
Also, add dependencies to build rules for local tools - if tool
changes automatically rerun it.
Make sure option roms don't overwrite the 32bit code (should the 32bit
code be in the e-segment).
Make sure shadow code works even if part of the code is in the
e-segment.
diff --git a/Makefile b/Makefile
index ec30f39..a933f60 100644
--- a/Makefile
+++ b/Makefile
@@ -51,7 +51,6 @@
OBJCOPY=objcopy
OBJDUMP=objdump
-NM=nm
STRIP=strip
.PHONY : all FORCE
@@ -112,47 +111,43 @@
$(OUT)ccode.16.s: ; $(call whole-compile, $(CFLAGS16) -S, $(addprefix src/, $(SRC16)),$@)
+$(OUT)ccode32.o: ; $(call whole-compile, $(CFLAGS), $(addprefix src/, $(SRC32)),$@)
+
$(OUT)code16.o: romlayout.S $(OUT)ccode.16.s $(OUT)asm-offsets.h
@echo " Compiling (16bit) $@"
$(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ $< -o $@
-$(OUT)code32.o: ; $(call whole-compile, $(CFLAGS), $(addprefix src/, $(SRC32)),$@)
-
-$(OUT)romlayout16.lds $(OUT)romlayout32.lds: $(OUT)code32.o $(OUT)code16.o
- @echo " Building layout information $@"
+$(OUT)romlayout16.lds $(OUT)romlayout32.lds $(OUT)code32.o: $(OUT)ccode32.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)$(LD) -melf_i386 -r $(OUT)ccode32.o $(OUT)version.o -o $(OUT)code32.o
$(Q)$(OBJDUMP) -thr $(OUT)code32.o > $(OUT)code32.o.objdump
$(Q)$(OBJDUMP) -thr $(OUT)code16.o > $(OUT)code16.o.objdump
$(Q)./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32.o.objdump $(OUT)romlayout16.lds $(OUT)romlayout32.lds
-$(OUT)layout16.lds: $(OUT)romlayout16.lds
-$(OUT)rombios32.lds: $(OUT)romlayout32.lds
-
-$(OUT)rom16.o: $(OUT)code16.o $(OUT)rom32.o $(OUT)layout16.lds
+$(OUT)rom16.o: $(OUT)code16.o $(OUT)rom32.o $(OUT)romlayout16.lds
@echo " Linking (no relocs) $@"
- $(Q)$(LD) -r -T $(OUT)layout16.lds $< -o $@
+ $(Q)$(LD) -r -T $(OUT)romlayout16.lds $< -o $@
-$(OUT)rom32.o: $(OUT)code32.o $(OUT)rombios32.lds
+$(OUT)rom32.o: $(OUT)code32.o $(OUT)romlayout32.lds
@echo " Linking (no relocs) $@"
- $(Q)$(LD) -r -T $(OUT)rombios32.lds $< -o $@
+ $(Q)$(LD) -r -T $(OUT)romlayout32.lds $< -o $@
$(OUT)rom.o: $(OUT)rom16.o $(OUT)rom32.o $(OUT)rombios16.lds $(OUT)rombios.lds
@echo " Linking $@ (version \"$(VERSION)\")"
- $(Q)echo 'const char VERSION[] __attribute__((section(".data32.version"))) = "$(VERSION)";' > $(OUT)version.c
- $(Q)$(CC) $(CFLAGS) -c $(OUT)version.c -o $(OUT)version.o
$(Q)$(LD) -T $(OUT)rombios16.lds $(OUT)rom16.o -R $(OUT)rom32.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)rom32.o $(OUT)version.o -R $(OUT)rom16.moved.o -o $@
+ $(Q)$(LD) -T $(OUT)rombios.lds $(OUT)rom16.final.o $(OUT)rom32.o -R $(OUT)rom16.moved.o -o $@
-$(OUT)bios.bin.elf: $(OUT)rom.o
+$(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py
@echo " Prepping $@"
- $(Q)$(NM) $< | ./tools/checkrom.py
- $(Q)$(STRIP) $< -o $@
-
-$(OUT)bios.bin: $(OUT)bios.bin.elf
- @echo " Extracting binary $@"
- $(Q)$(OBJCOPY) -O binary $< $@
+ $(Q)$(OBJDUMP) -thr $< > $<.objdump
+ $(Q)$(OBJCOPY) -O binary $< $(OUT)bios.bin.raw
+ $(Q)./tools/checkrom.py $<.objdump $(OUT)bios.bin.raw $(OUT)bios.bin
+ $(Q)$(STRIP) $< -o $(OUT)bios.bin.elf
################ VGA build rules
@@ -175,7 +170,7 @@
@echo " Extracting binary $@"
$(Q)$(OBJCOPY) -O binary $< $@
-$(OUT)vgabios.bin: $(OUT)vgabios.bin.raw
+$(OUT)vgabios.bin: $(OUT)vgabios.bin.raw tools/buildrom.py
@echo " Finalizing rom $@"
$(Q)./tools/buildrom.py $< $@
diff --git a/src/layout16.lds.S b/src/layout16.lds.S
deleted file mode 100644
index 40f3664..0000000
--- a/src/layout16.lds.S
+++ /dev/null
@@ -1,21 +0,0 @@
-// Placement of the 16bit code.
-//
-// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU LGPLv3 license.
-
-#include "config.h" // BUILD_BIOS_ADDR
-
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH("i386")
-SECTIONS
-{
-
-// The actual placement of the 16bit sections is determined by the
-// script tools/layoutrom.py
-#include "../out/romlayout16.lds"
-
- // Discard regular data sections to force a link error if
- // 16bit code attempts to access data not marked with VAR16.
- /DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) }
-}
diff --git a/src/optionroms.c b/src/optionroms.c
index 7d93a87..18526f4 100644
--- a/src/optionroms.c
+++ b/src/optionroms.c
@@ -164,12 +164,22 @@
return pci;
}
+// Return the memory position up to which roms may be located.
+static inline u32
+max_rom()
+{
+ extern u8 code32_start[];
+ if ((u32)code32_start > BUILD_BIOS_ADDR)
+ return BUILD_BIOS_ADDR;
+ return (u32)code32_start;
+}
+
// Copy a rom to its permanent location below 1MiB
static struct rom_header *
copy_rom(struct rom_header *rom)
{
u32 romsize = rom->size * 512;
- if (RomEnd + romsize > BUILD_BIOS_ADDR) {
+ if (RomEnd + romsize > max_rom()) {
// Option rom doesn't fit.
dprintf(1, "Option rom %p doesn't fit.\n", rom);
return NULL;
@@ -213,8 +223,7 @@
&& ((OPTIONROM_VENDEV_2 >> 16)
| ((OPTIONROM_VENDEV_2 & 0xffff)) << 16) == vendev)
return copy_rom((void*)OPTIONROM_MEM_2);
- int ret = cbfs_copy_optionrom((void*)RomEnd, BUILD_BIOS_ADDR - RomEnd
- , vendev);
+ int ret = cbfs_copy_optionrom((void*)RomEnd, max_rom() - RomEnd, vendev);
if (ret < 0)
return NULL;
return (void*)RomEnd;
@@ -229,7 +238,7 @@
file = cbfs_findprefix(prefix, file);
if (!file)
break;
- int ret = cbfs_copyfile(file, (void*)RomEnd, BUILD_BIOS_ADDR - RomEnd);
+ int ret = cbfs_copyfile(file, (void*)RomEnd, max_rom() - RomEnd);
if (ret > 0)
init_optionrom((void*)RomEnd, 0, isvga);
}
@@ -343,7 +352,7 @@
if (CONFIG_OPTIONROMS_DEPLOYED) {
// Option roms are already deployed on the system.
u32 pos = RomEnd;
- while (pos < BUILD_BIOS_ADDR) {
+ while (pos < max_rom()) {
int ret = init_optionrom((void*)pos, 0, 0);
if (ret)
pos += OPTION_ROM_ALIGN;
diff --git a/src/rombios.lds.S b/src/rombios.lds.S
index 3d59fad..8400732 100644
--- a/src/rombios.lds.S
+++ b/src/rombios.lds.S
@@ -4,16 +4,17 @@
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+#include "config.h" // BUILD_BIOS_ADDR
+
+OUTPUT_FORMAT("elf32-i386")
OUTPUT_ARCH("i386")
ENTRY(post32)
SECTIONS
{
.text code32_start : {
*(.text32)
- *(.data32.version)
- . = code16_start ;
+ . = code16_start + BUILD_BIOS_ADDR - code32_start ;
*(.text16)
final_code16_end = . ;
}
diff --git a/src/rombios16.lds.S b/src/rombios16.lds.S
index 6e6a2f1..f9046ad 100644
--- a/src/rombios16.lds.S
+++ b/src/rombios16.lds.S
@@ -4,8 +4,6 @@
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
-#include "config.h" // BUILD_BIOS_ADDR
-
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH("i386")
SECTIONS
diff --git a/src/rombios32.lds.S b/src/rombios32.lds.S
deleted file mode 100644
index 62e92d1..0000000
--- a/src/rombios32.lds.S
+++ /dev/null
@@ -1,22 +0,0 @@
-// Linker definitions for 32 bit code
-//
-// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU LGPLv3 license.
-
-#include "config.h" // BUILD_BIOS_ADDR
-
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH("i386")
-SECTIONS
-{
- .text32 BUILD_BIOS_ADDR : {
- code32_start = ABSOLUTE(.) ;
-
-// The actual sections kept is determined by the script tools/layoutrom.py
-#include "../out/romlayout32.lds"
-
- freespace_start = . ;
- code32_end = ABSOLUTE(.) ;
- }
-}
diff --git a/src/shadow.c b/src/shadow.c
index daa2e21..f0f97c5 100644
--- a/src/shadow.c
+++ b/src/shadow.c
@@ -23,28 +23,8 @@
// Enable shadowing and copy bios.
static void
-copy_bios(u16 bdf)
+__make_bios_writable(u16 bdf)
{
- pci_config_writeb(bdf, 0x59, 0x30);
- memcpy((void*)BUILD_BIOS_ADDR, (void*)BIOS_SRC_ADDR, BUILD_BIOS_SIZE);
-}
-
-// Make the 0xc0000-0x100000 area read/writable.
-void
-make_bios_writable()
-{
- if (CONFIG_COREBOOT)
- return;
-
- dprintf(3, "enabling shadow ram\n");
-
- // Locate chip controlling ram shadowing.
- int bdf = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441);
- if (bdf < 0) {
- dprintf(1, "Unable to unlock ram - bridge not found\n");
- return;
- }
-
// Make ram from 0xc0000-0xf0000 writable
int clear = 0;
int i;
@@ -68,24 +48,46 @@
if (clear)
memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
+ // Make ram from 0xf0000-0x100000 writable
int reg = pci_config_readb(bdf, 0x59);
- if (reg & 0x10) {
- // Ram already present - just enable writes
- pci_config_writeb(bdf, 0x59, 0x30);
+ pci_config_writeb(bdf, 0x59, 0x30);
+ if (reg & 0x10)
+ // Ram already present.
+ return;
+
+ // Copy bios.
+ memcpy((void*)BUILD_BIOS_ADDR, (void*)BIOS_SRC_ADDR, BUILD_BIOS_SIZE);
+}
+
+// Make the 0xc0000-0x100000 area read/writable.
+void
+make_bios_writable()
+{
+ if (CONFIG_COREBOOT)
+ return;
+
+ dprintf(3, "enabling shadow ram\n");
+
+ // Locate chip controlling ram shadowing.
+ int bdf = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441);
+ if (bdf < 0) {
+ dprintf(1, "Unable to unlock ram - bridge not found\n");
return;
}
- // Enable shadowing and copy bios.
- if (IN_RANGE((u32)copy_bios, BUILD_BIOS_ADDR, BUILD_BIOS_SIZE)) {
- // Jump to shadow enable function - use the copy in the
- // temporary storage area so that memory does not change under
- // the executing code.
- u32 pos = (u32)copy_bios - BUILD_BIOS_ADDR + BIOS_SRC_ADDR;
+ int reg = pci_config_readb(bdf, 0x59);
+ if (!(reg & 0x10)) {
+ // QEMU doesn't fully implement the piix shadow capabilities -
+ // if ram isn't backing the bios segment when shadowing is
+ // disabled, the code itself wont be in memory. So, run the
+ // code from the high-memory flash location.
+ u32 pos = (u32)__make_bios_writable - BUILD_BIOS_ADDR + BIOS_SRC_ADDR;
void (*func)(u16 bdf) = (void*)pos;
func(bdf);
- } else {
- copy_bios(bdf);
+ return;
}
+ // Ram already present - just enable writes
+ __make_bios_writable(bdf);
}
// Make the BIOS code segment area (0xf0000) read-only.
diff --git a/tools/checkrom.py b/tools/checkrom.py
index 7dc5afc..b1d732a 100755
--- a/tools/checkrom.py
+++ b/tools/checkrom.py
@@ -6,33 +6,56 @@
# This file may be distributed under the terms of the GNU GPLv3 license.
import sys
+import layoutrom
def main():
- # Read in symbols (that are valid)
- syms = {}
- for line in sys.stdin.readlines():
- try:
- addr, type, sym = line.split()
- syms[sym] = int(addr, 16)
- except:
- pass
+ # Get args
+ objinfo, rawfile, outfile = sys.argv[1:]
+ # Read in symbols
+ objinfofile = open(objinfo, 'rb')
+ symbols = layoutrom.parseObjDump(objinfofile)[1]
+ syms = {}
+ for name, (addr, section) in symbols.items():
+ syms[name] = addr
+
+ # Read in raw file
+ f = open(rawfile, 'rb')
+ rawdata = f.read()
+ f.close()
+ datasize = len(rawdata)
+ finalsize = 64*1024
+ if datasize > 64*1024:
+ finalsize = 128*1024
+
+ # Sanity checks
c16e = syms['code16_end'] + 0xf0000
f16e = syms['final_code16_end']
if c16e != f16e:
print "Error! 16bit code moved during linking (0x%x vs 0x%x)" % (
c16e, f16e)
sys.exit(1)
+ if datasize > finalsize:
+ print "Error! Code is too big (0x%x vs 0x%x)" % (
+ datasize, finalsize)
+ sys.exit(1)
+ # Print statistics
sizefree = syms['freespace_end'] - syms['freespace_start']
size16 = syms['code16_end'] - syms['code16_start']
size32 = syms['code32_end'] - syms['code32_start']
totalc = size16+size32
print "16bit size: %d" % size16
print "32bit size: %d" % size32
- print "Total size: %d Free space: %d Percent used: %.1f%%" % (
- totalc, sizefree
- , (totalc / float(size16+size32+sizefree)) * 100.0)
+ print "Total size: %d Free space: %d Percent used: %.1f%% (%dKiB rom)" % (
+ totalc, sizefree + finalsize - datasize
+ , (totalc / float(finalsize)) * 100.0
+ , finalsize / 1024)
+
+ # Write final file
+ f = open(outfile, 'wb')
+ f.write(("\0" * (finalsize - datasize)) + rawdata)
+ f.close()
if __name__ == '__main__':
main()
diff --git a/tools/layoutrom.py b/tools/layoutrom.py
index 8d557bc..da2940f 100755
--- a/tools/layoutrom.py
+++ b/tools/layoutrom.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Script to arrange sections to ensure fixed offsets.
+# Script to analyze code and arrange ld sections.
#
# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
#
@@ -7,18 +7,49 @@
import sys
-
+# Align 'pos' to 'alignbytes' offset
def alignpos(pos, alignbytes):
mask = alignbytes - 1
return (pos + mask) & ~mask
+# LD script headers/trailers
+COMMONHEADER = """
+/* DO NOT EDIT! This is an autogenerated file. See tools/layoutrom.py. */
+OUTPUT_FORMAT("elf32-i386")
+OUTPUT_ARCH("i386")
+SECTIONS
+{
+"""
+COMMONTRAILER = """
+}
+"""
+
######################################################################
# 16bit fixed address section fitting
######################################################################
-MAXPOS = 0x10000
+# Get the maximum start position for a list of sections that end at an
+# address.
+def getSectionsStart(sections, endaddr, minalign=1):
+ totspace = 0
+ for size, align, name in sections:
+ if align > minalign:
+ minalign = align
+ totspace = alignpos(totspace, align) + size
+ return (endaddr - totspace) / minalign * minalign
+# Write LD script includes for the given sections
+def outSections(file, sections):
+ for size, align, name in sections:
+ file.write("*(%s)\n" % (name,))
+
+# The 16bit code can't exceed 64K of space.
+MAXPOS = 64*1024
+
+# Layout the 16bit code. This ensures sections with fixed offset
+# requirements are placed in the correct location. It also places the
+# 16bit code as high as possible in the f-segment.
def doLayout16(sections, outname):
textsections = []
rodatasections = []
@@ -103,18 +134,6 @@
# , fitnextaddr, nextfixedaddr - fitnextaddr)
firstfixed = fixedsections[0][0]
- # Find overall start position
- restalign = 0
- restspace = 0
- restsections = []
- for section in textsections + rodatasections + datasections:
- size, align, name = section
- if align > restalign:
- restalign = align
- restspace = alignpos(restspace, align) + size
- restsections.append(section)
- startrest = (firstfixed - restspace) / restalign * restalign
-
# Report stats
total = MAXPOS-firstfixed
slack = total - totalused
@@ -123,20 +142,23 @@
firstfixed, MAXPOS, total, slack,
(float(slack) / total) * 100.0))
+ # Find overall start position
+ start16 = getSectionsStart(
+ textsections + rodatasections + datasections, firstfixed)
+
# Write header
output = open(outname, 'wb')
- output.write("""
+ output.write(COMMONHEADER + """
.text16 0x%x : {
code16_start = ABSOLUTE(.) ;
freespace_end = . ;
-""" % startrest)
+""" % start16)
# Write regular sections
- for section in restsections:
- name = section[2]
- if rodatasections and name == rodatasections[0][2]:
- output.write("code16_rodata = . ;\n")
- output.write("*(%s)\n" % (name,))
+ outSections(output, textsections)
+ output.write("code16_rodata = . ;\n")
+ outSections(output, rodatasections)
+ outSections(output, datasections)
# Write fixed sections
for addr, section, extrasections in fixedsections:
@@ -150,32 +172,66 @@
output.write("""
code16_end = ABSOLUTE(.) ;
}
-""")
+
+ /* Discard regular data sections to force a link error if
+ * 16bit code attempts to access data not marked with VAR16
+ */
+ /DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) }
+""" + COMMONTRAILER)
+
+ return start16
######################################################################
# 32bit section outputting
######################################################################
-def outsections(file, sections, prefix):
+# Return the subset of sections with a given name prefix
+def getSectionsPrefix(sections, prefix):
lp = len(prefix)
+ out = []
for size, align, name in sections:
if name[:lp] == prefix:
- file.write("*(%s)\n" % (name,))
+ out.append((size, align, name))
+ return out
-def doLayout32(sections, outname):
+# Layout the 32bit code. This places the code as high as possible.
+def doLayout32(sections, outname, start16):
+ start16 += 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)
+
+ # Write sections
output = open(outname, 'wb')
- outsections(output, sections, '.text.')
+ output.write(COMMONHEADER + """
+ .text32 0x%x : {
+ code32_start = ABSOLUTE(.) ;
+""" % start32)
+
+ outSections(output, textsections)
output.write("code32_rodata = . ;\n")
- outsections(output, sections, '.rodata')
- outsections(output, sections, '.data.')
- outsections(output, sections, '.bss.')
+ outSections(output, rodatasections)
+ outSections(output, datasections)
+ outSections(output, bsssections)
+
+ output.write("""
+ freespace_start = . ;
+ code32_end = ABSOLUTE(.) ;
+ }
+""" + COMMONTRAILER)
######################################################################
# Section garbage collection
######################################################################
+# Note required section, and recursively set all referenced sections
+# as required.
def keepsection(name, pri, alt):
if name in pri[3]:
# Already kept - nothing to do.
@@ -186,15 +242,18 @@
return
# Keep all sections that this section points to
for symbol in relocs:
- section = pri[1].get(symbol)
- if section is not None and section[:9] != '.discard.':
+ addr, section = pri[1].get(symbol, (None, None))
+ if (section is not None and '*' not in section
+ and section[:9] != '.discard.'):
keepsection(section, pri, alt)
continue
# Not in primary sections - it may be a cross 16/32 reference
- section = alt[1].get(symbol)
- if section is not None:
+ addr, section = alt[1].get(symbol, (None, None))
+ if section is not None and '*' not in section:
keepsection(section, alt, pri)
+# 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], [])
@@ -261,8 +320,8 @@
try:
section, off, symbol = line[17:].split()
off = int(off, 16)
- if '*' not in section:
- symbols[symbol] = section
+ addr = int(line[:8], 16)
+ symbols[symbol] = addr, section
except:
pass
continue
@@ -287,8 +346,8 @@
sections16, sections32 = gc(info16, info32)
- doLayout16(sections16, out16)
- doLayout32(sections32, out32)
+ start16 = doLayout16(sections16, out16)
+ doLayout32(sections32, out32, start16)
if __name__ == '__main__':
main()