From 5b8f80992019371e640b9957f3e5d1a2fb570776 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Sun, 20 Sep 2009 19:47:45 -0400 Subject: [PATCH] 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. --- Makefile | 41 ++++++------- src/layout16.lds.S | 21 ------- src/optionroms.c | 19 ++++-- src/rombios.lds.S | 7 ++- src/rombios16.lds.S | 2 - src/rombios32.lds.S | 22 ------- src/shadow.c | 66 ++++++++++----------- tools/checkrom.py | 43 ++++++++++---- tools/layoutrom.py | 137 +++++++++++++++++++++++++++++++------------- 9 files changed, 201 insertions(+), 157 deletions(-) delete mode 100644 src/layout16.lds.S delete mode 100644 src/rombios32.lds.S diff --git a/Makefile b/Makefile index ec30f39..a933f60 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,6 @@ endif OBJCOPY=objcopy OBJDUMP=objdump -NM=nm STRIP=strip .PHONY : all FORCE @@ -112,47 +111,43 @@ $(OUT)asm-offsets.h: $(OUT)asm-offsets.s $(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 @@ $(OUT)vgabios.bin.raw: $(OUT)vgarom.o @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 -// -// 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 @@ get_pci_rom(struct rom_header *rom) 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 @@ lookup_hardcode(u32 vendev) && ((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 @@ run_cbfs_roms(const char *prefix, int isvga) 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 @@ optionrom_setup() 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 -// -// 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 @@ make_bios_writable() 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) + # Get args + objinfo, rawfile, outfile = sys.argv[1:] + + # Read in symbols + objinfofile = open(objinfo, 'rb') + symbols = layoutrom.parseObjDump(objinfofile)[1] syms = {} - for line in sys.stdin.readlines(): - try: - addr, type, sym = line.split() - syms[sym] = int(addr, 16) - except: - pass + 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 # @@ -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 @@ def doLayout16(sections, outname): # , 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 @@ def doLayout16(sections, outname): 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 @@ def doLayout16(sections, outname): 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,)) - -def doLayout32(sections, outname): + 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 + # 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 @@ def keepsection(name, pri, alt): 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 @@ def parseObjDump(file): 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 @@ def main(): sections16, sections32 = gc(info16, info32) - doLayout16(sections16, out16) - doLayout32(sections32, out32) + start16 = doLayout16(sections16, out16) + doLayout32(sections32, out32, start16) if __name__ == '__main__': main() -- 2.25.1