From 329686c0262001054db42f7b5d33677430980fed Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Apr 2010 20:32:25 +0100 Subject: [PATCH] [romprefix] Remove .xrom prefix The .xrom prefix provides an experimental mechanism for loading ROM images greater than 64kB in size by mapping the expansion ROM BAR in at a hopefully-unused address. This is unreliable, and potentially dangerous. In particular, there is no guarantee that any PCI bridges between the CPU and the device will respond to accesses for the "unused" memory region that is chosen, and it is possible that the process of scanning for the "unused" memory region may end up issuing reads to other PCI devices. If this ends up trampling on a register with read side-effects belonging to an unrelated PCI device, this may cause undefined behaviour. Signed-off-by: Michael Brown --- src/Makefile.housekeeping | 2 - src/arch/i386/Makefile.pcbios | 2 - src/arch/i386/prefix/romprefix.S | 383 +----------------------------- src/arch/i386/prefix/xromprefix.S | 9 - src/arch/i386/scripts/i386.lds | 1 - src/util/makerom.pl | 30 +-- 6 files changed, 20 insertions(+), 407 deletions(-) delete mode 100644 src/arch/i386/prefix/xromprefix.S diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index 653542e5..efd85ea3 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -867,8 +867,6 @@ endif # defined(BIN) FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \ -i$(IDENT) -s 0 $@ FINALISE_hrom = $(FINALISE_rom) -FINALISE_xrom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \ - -i$(IDENT) -n -s 0 $@ # Some ROMs require specific flags to be passed to makerom.pl # diff --git a/src/arch/i386/Makefile.pcbios b/src/arch/i386/Makefile.pcbios index e38fbca0..dcabbdf7 100644 --- a/src/arch/i386/Makefile.pcbios +++ b/src/arch/i386/Makefile.pcbios @@ -12,7 +12,6 @@ LDFLAGS += -N --no-check-sections # MEDIA += rom MEDIA += hrom -MEDIA += xrom MEDIA += pxe MEDIA += kpxe MEDIA += kkpxe @@ -26,7 +25,6 @@ MEDIA += raw # PAD_rom = $(PADIMG) --blksize=512 --byte=0xff $@ PAD_hrom = $(PAD_rom) -PAD_xrom = $(PAD_rom) PAD_dsk = $(PADIMG) --blksize=512 $@ PAD_hd = $(PADIMG) --blksize=32768 $@ diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S index 5ea53aac..e7d146eb 100644 --- a/src/arch/i386/prefix/romprefix.S +++ b/src/arch/i386/prefix/romprefix.S @@ -25,19 +25,6 @@ FILE_LICENCE ( GPL2_OR_LATER ) */ #define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 ) -/* We can load a ROM in two ways: have the BIOS load all of it (.rom prefix) - * or have the BIOS load a stub that loads the rest using PCI (.xrom prefix). - * The latter is not as widely supported, but allows the use of large ROMs - * on some systems with crowded option ROM space. - */ - -#ifdef LOAD_ROM_FROM_PCI -#define ROM_SIZE_VALUE _prefix_filesz_sect /* Amount to load in BIOS */ -#else -#define ROM_SIZE_VALUE 0 /* Load amount (before compr. fixup) */ -#endif - - .text .code16 .arch i386 @@ -46,12 +33,10 @@ FILE_LICENCE ( GPL2_OR_LATER ) .org 0x00 romheader: .word 0xAA55 /* BIOS extension signature */ -romheader_size: .byte ROM_SIZE_VALUE /* Size in 512-byte blocks */ +romheader_size: .byte 0 /* Size in 512-byte blocks */ jmp init /* Initialisation vector */ checksum: - .byte 0, 0 -real_size: - .word 0 + .byte 0 .org 0x16 .word undiheader .org 0x18 @@ -61,16 +46,10 @@ real_size: .size romheader, . - romheader .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ -#ifndef LOAD_ROM_FROM_PCI .ascii "ADDB" .long romheader_size .long 512 .long 0 -#endif - .ascii "ADDB" - .long real_size - .long 512 - .long 0 .previous pciheader: @@ -82,18 +61,17 @@ pciheader: .byte 0x03 /* PCI data structure revision */ .byte 0x02, 0x00, 0x00 /* Class code */ pciheader_image_length: - .word ROM_SIZE_VALUE /* Image length */ + .word 0 /* Image length */ .word 0x0001 /* Revision level */ .byte 0x00 /* Code type */ .byte 0x80 /* Last image indicator */ pciheader_runtime_length: - .word ROM_SIZE_VALUE /* Maximum run-time image length */ + .word 0 /* Maximum run-time image length */ .word 0x0000 /* Configuration utility code header */ .word 0x0000 /* DMTF CLP entry point */ .equ pciheader_len, . - pciheader .size pciheader, . - pciheader -#ifndef LOAD_ROM_FROM_PCI .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "ADDW" .long pciheader_image_length @@ -104,7 +82,6 @@ pciheader_runtime_length: .long 512 .long 0 .previous -#endif pnpheader: .ascii "$PnP" /* Signature */ @@ -198,11 +175,6 @@ init: call print_message call print_pci_busdevfn -#ifdef LOAD_ROM_FROM_PCI - /* Save PCI bus:dev.fn for later use */ - movw %ax, pci_busdevfn -#endif - /* Fill in product name string, if possible */ movw $prodstr_pci_id, %di call print_pci_busdevfn @@ -227,9 +199,6 @@ init: jne no_pci3 testb %ah, %ah jnz no_pci3 -#ifdef LOAD_ROM_FROM_PCI - incb pcibios_present -#endif movw $init_message_pci, %si xorw %di, %di call print_message @@ -341,7 +310,7 @@ pmm_scan: /* We have PMM and so a 1kB stack: preserve upper register halves */ pushal /* Calculate required allocation size in %esi */ - movzwl real_size, %eax + movzbl romheader_size, %eax shll $9, %eax addl $_textdata_memsz, %eax orw $0xffff, %ax /* Ensure allocation size is at least 64kB */ @@ -395,7 +364,7 @@ pmm_copy: movl %edi, decompress_to /* Shrink ROM */ movb $_prefix_memsz_sect, romheader_size -#if defined(SHRINK_WITHOUT_PMM) || defined(LOAD_ROM_FROM_PCI) +#ifdef SHRINK_WITHOUT_PMM jmp pmm_done pmm_fail: /* Print marker and copy ourselves to high memory */ @@ -410,28 +379,8 @@ pmm_fail: #endif /* Restore upper register halves */ popal -#if defined(LOAD_ROM_FROM_PCI) - call load_from_pci - jc load_err - jmp load_ok no_pmm: - /* Cannot continue without PMM - print error message */ - xorw %di, %di - movw $init_message_no_pmm, %si - call print_message -load_err: - /* Wait for five seconds to let user see message */ - movw $90, %cx -1: call wait_for_tick - loop 1b - /* Mark environment as invalid and return */ - movl $0, decompress_to - jmp out -load_ok: -#else -no_pmm: -#endif /* Update checksum */ xorw %bx, %bx xorw %si, %si @@ -476,14 +425,14 @@ no_pmm: movw $init_message_done, %si call print_message popf - jnz out + jnz 2f /* Ctrl-B was pressed: invoke iPXE. The keypress will be * picked up by the initial shell prompt, and we will drop * into a shell. */ pushw %cs call exec -out: +2: /* Restore registers */ popw %gs popw %fs @@ -530,11 +479,6 @@ init_message_bbs: init_message_pmm: .asciz " PMM" .size init_message_pmm, . - init_message_pmm -#ifdef LOAD_ROM_FROM_PCI -init_message_no_pmm: - .asciz "\nPMM required but not present!\n" - .size init_message_no_pmm, . - init_message_no_pmm -#endif init_message_int19: .asciz " INT19" .size init_message_int19, . - init_message_int19 @@ -560,32 +504,12 @@ image_source: /* Temporary decompression area * * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block. - * If a PCI ROM load fails, this will be set to zero. */ .globl decompress_to decompress_to: .long HIGHMEM_LOADPOINT .size decompress_to, . - decompress_to -#ifdef LOAD_ROM_FROM_PCI - -/* Set if the PCI BIOS is present, even <3.0 */ -pcibios_present: - .byte 0 - .byte 0 /* for alignment */ - .size pcibios_present, . - pcibios_present - -/* PCI bus:device.function word - * - * Filled in by init in the .xrom case, so the remainder of the ROM - * can be located. - */ -pci_busdevfn: - .word 0 - .size pci_busdevfn, . - pci_busdevfn - -#endif - /* BBS version * * Filled in by BBS BIOS. We ignore the value. @@ -604,289 +528,6 @@ bev_entry: lret .size bev_entry, . - bev_entry - -#ifdef LOAD_ROM_FROM_PCI - -#define PCI_ROM_ADDRESS 0x30 /* Bits 31:11 address, 10:1 reserved */ -#define PCI_ROM_ADDRESS_ENABLE 0x00000001 -#define PCI_ROM_ADDRESS_MASK 0xfffff800 - -#define PCIBIOS_READ_WORD 0xb109 -#define PCIBIOS_READ_DWORD 0xb10a -#define PCIBIOS_WRITE_WORD 0xb10c -#define PCIBIOS_WRITE_DWORD 0xb10d - -/* Determine size of PCI BAR - * - * %bx : PCI bus:dev.fn to probe - * %di : Address of BAR to find size of - * %edx : Mask of address bits within BAR - * - * %ecx : Size for a memory resource, - * 1 for an I/O resource (bit 0 set). - * CF : Set on error or nonexistent device (all-ones read) - * - * All other registers saved. - */ -pci_bar_size: - /* Save registers */ - pushw %ax - pushl %esi - pushl %edx - - /* Read current BAR value */ - movw $PCIBIOS_READ_DWORD, %ax - int $0x1a - - /* Check for device existence and save it */ - testb $1, %cl /* I/O bit? */ - jz 1f - andl $1, %ecx /* If so, exit with %ecx = 1 */ - jmp 99f -1: notl %ecx - testl %ecx, %ecx /* Set ZF iff %ecx was all-ones */ - notl %ecx - jnz 1f - stc /* All ones - exit with CF set */ - jmp 99f -1: movl %ecx, %esi /* Save in %esi */ - - /* Write all ones to BAR */ - movl %edx, %ecx - movw $PCIBIOS_WRITE_DWORD, %ax - int $0x1a - - /* Read back BAR */ - movw $PCIBIOS_READ_DWORD, %ax - int $0x1a - - /* Find decode size from least set bit in mask BAR */ - bsfl %ecx, %ecx /* Find least set bit, log2(decode size) */ - jz 1f /* Mask BAR should not be zero */ - xorl %edx, %edx - incl %edx - shll %cl, %edx /* %edx = decode size */ - jmp 2f -1: xorl %edx, %edx /* Return zero size for mask BAR zero */ - - /* Restore old BAR value */ -2: movl %esi, %ecx - movw $PCIBIOS_WRITE_DWORD, %ax - int $0x1a - - movl %edx, %ecx /* Return size in %ecx */ - - /* Restore registers and return */ -99: popl %edx - popl %esi - popw %ax - ret - - .size pci_bar_size, . - pci_bar_size - -/* PCI ROM loader - * - * Called from init in the .xrom case to load the non-prefix code - * using the PCI ROM BAR. - * - * Returns with carry flag set on error. All registers saved. - */ -load_from_pci: - /* - * Use PCI BIOS access to config space. The calls take - * - * %ah : 0xb1 %al : function - * %bx : bus/dev/fn - * %di : config space address - * %ecx : value to write (for writes) - * - * %ecx : value read (for reads) - * %ah : return code - * CF : error indication - * - * All registers not used for return are preserved. - */ - - /* Save registers and set up %es for big real mode */ - pushal - pushw %es - xorw %ax, %ax - movw %ax, %es - - /* Check PCI BIOS presence */ - cmpb $0, pcibios_present - jz err_pcibios - - /* Load existing PCI ROM BAR */ - movw $PCIBIOS_READ_DWORD, %ax - movw pci_busdevfn, %bx - movw $PCI_ROM_ADDRESS, %di - int $0x1a - - /* Maybe it's already enabled? */ - testb $PCI_ROM_ADDRESS_ENABLE, %cl - jz 1f - movb $1, %dl /* Flag indicating no deinit required */ - movl %ecx, %ebp - jmp check_rom - - /* Determine PCI BAR decode size */ -1: movl $PCI_ROM_ADDRESS_MASK, %edx - call pci_bar_size /* Returns decode size in %ecx */ - jc err_size_insane /* CF => no ROM BAR, %ecx == ffffffff */ - - /* Check sanity of decode size */ - xorl %eax, %eax - movw real_size, %ax - shll $9, %eax /* %eax = ROM size */ - cmpl %ecx, %eax - ja err_size_insane /* Insane if decode size < ROM size */ - cmpl $0x100000, %ecx - jae err_size_insane /* Insane if decode size >= 1MB */ - - /* Find a place to map the BAR - * In theory we should examine e820 and all PCI BARs to find a - * free region. However, we run at POST when e820 may not be - * available, and memory reads of an unmapped location are - * de facto standardized to return all-ones. Thus, we can get - * away with searching high memory (0xf0000000 and up) on - * multiples of the ROM BAR decode size for a sufficiently - * large all-ones region. - */ - movl %ecx, %edx /* Save ROM BAR size in %edx */ - movl $0xf0000000, %ebp - xorl %eax, %eax - notl %eax /* %eax = all ones */ -bar_search: - movl %ebp, %edi - movl %edx, %ecx - shrl $2, %ecx - addr32 repe scasl /* Scan %es:edi for anything not all-ones */ - jz bar_found - addl %edx, %ebp - testl $0x80000000, %ebp - jz err_no_bar - jmp bar_search - -bar_found: - movl %edi, %ebp - /* Save current BAR value on stack to restore later */ - movw $PCIBIOS_READ_DWORD, %ax - movw $PCI_ROM_ADDRESS, %di - int $0x1a - pushl %ecx - - /* Map the ROM */ - movw $PCIBIOS_WRITE_DWORD, %ax - movl %ebp, %ecx - orb $PCI_ROM_ADDRESS_ENABLE, %cl - int $0x1a - - xorb %dl, %dl /* %dl = 0 : ROM was not already mapped */ -check_rom: - /* Check and copy ROM - enter with %dl set to skip unmapping, - * %ebp set to mapped ROM BAR address. - * We check up to prodstr_separator for equality, since anything past - * that may have been modified. Since our check includes the checksum - * byte over the whole ROM stub, that should be sufficient. - */ - xorb %dh, %dh /* %dh = 0 : ROM did not fail integrity check */ - - /* Verify ROM integrity */ - xorl %esi, %esi - movl %ebp, %edi - movl $prodstr_separator, %ecx - addr32 repe cmpsb - jz copy_rom - incb %dh /* ROM failed integrity check */ - movl %ecx, %ebp /* Save number of bytes left */ - jmp skip_load - -copy_rom: - /* Print BAR address and indicate whether we mapped it ourselves */ - movb $( ' ' ), %al - xorw %di, %di - call print_character - movl %ebp, %eax - call print_hex_dword - movb $( '-' ), %al /* '-' for self-mapped */ - subb %dl, %al - subb %dl, %al /* '+' = '-' - 2 for BIOS-mapped */ - call print_character - - /* Copy ROM at %ebp to PMM or highmem block */ - movl %ebp, %esi - movl image_source, %edi - movzwl real_size, %ecx - shll $9, %ecx - addr32 es rep movsb - movl %edi, decompress_to -skip_load: - testb %dl, %dl /* Was ROM already mapped? */ - jnz skip_unmap - - /* Unmap the ROM by restoring old ROM BAR */ - movw $PCIBIOS_WRITE_DWORD, %ax - movw $PCI_ROM_ADDRESS, %di - popl %ecx - int $0x1a - -skip_unmap: - /* Error handling */ - testb %dh, %dh - jnz err_rom_invalid - clc - jmp 99f - -err_pcibios: /* No PCI BIOS available */ - movw $load_message_no_pcibios, %si - xorl %eax, %eax /* "error code" is zero */ - jmp 1f -err_size_insane: /* BAR has size (%ecx) that is insane */ - movw $load_message_size_insane, %si - movl %ecx, %eax - jmp 1f -err_no_bar: /* No space of sufficient size (%edx) found */ - movw $load_message_no_bar, %si - movl %edx, %eax - jmp 1f -err_rom_invalid: /* Loaded ROM does not match (%ebp bytes left) */ - movw $load_message_rom_invalid, %si - movzbl romheader_size, %eax - shll $9, %eax - subl %ebp, %eax - decl %eax /* %eax is now byte index of failure */ - -1: /* Error handler - print message at %si and dword in %eax */ - xorw %di, %di - call print_message - call print_hex_dword - stc -99: popw %es - popal - ret - - .size load_from_pci, . - load_from_pci - -load_message_no_pcibios: - .asciz "\nNo PCI BIOS found! " - .size load_message_no_pcibios, . - load_message_no_pcibios - -load_message_size_insane: - .asciz "\nROM resource has invalid size " - .size load_message_size_insane, . - load_message_size_insane - -load_message_no_bar: - .asciz "\nNo memory hole of sufficient size " - .size load_message_no_bar, . - load_message_no_bar - -load_message_rom_invalid: - .asciz "\nLoaded ROM is invalid at " - .size load_message_rom_invalid, . - load_message_rom_invalid - -#endif /* LOAD_ROM_FROM_PCI */ - - /* INT19 entry point * * Called via the hooked INT 19 if we detected a non-PnP BIOS. We @@ -947,14 +588,6 @@ exec: /* Set %ds = %cs */ pushw %cs popw %ds -#ifdef LOAD_ROM_FROM_PCI - /* Don't execute if load was invalid */ - cmpl $0, decompress_to - jne 1f - lret -1: -#endif - /* Print message as soon as possible */ movw $prodstr, %si xorw %di, %di diff --git a/src/arch/i386/prefix/xromprefix.S b/src/arch/i386/prefix/xromprefix.S deleted file mode 100644 index d7c861f5..00000000 --- a/src/arch/i386/prefix/xromprefix.S +++ /dev/null @@ -1,9 +0,0 @@ -/* - * ROM prefix that loads the bulk of the ROM using direct PCI accesses, - * so as not to take up much option ROM space on PCI <3.0 systems. - */ - -FILE_LICENCE ( GPL2_OR_LATER ) - -#define LOAD_ROM_FROM_PCI -#include "romprefix.S" diff --git a/src/arch/i386/scripts/i386.lds b/src/arch/i386/scripts/i386.lds index 33c75f90..77e8c7e7 100644 --- a/src/arch/i386/scripts/i386.lds +++ b/src/arch/i386/scripts/i386.lds @@ -194,7 +194,6 @@ SECTIONS { * Values calculated to save code from doing it * */ - _prefix_filesz_sect = ( ( _prefix_filesz + 511 ) / 512 ); _prefix_memsz_pgh = ( ( _prefix_memsz + 15 ) / 16 ); _prefix_memsz_sect = ( ( _prefix_memsz + 511 ) / 512 ); _text16_memsz_pgh = ( ( _text16_memsz + 15 ) / 16 ); diff --git a/src/util/makerom.pl b/src/util/makerom.pl index 68c3be98..aed3a569 100755 --- a/src/util/makerom.pl +++ b/src/util/makerom.pl @@ -130,14 +130,14 @@ sub writerom ($$) { close(R); } -sub checksum ($$) { - my ($romref, $romsize) = @_; +sub checksum ($) { + my ($romref) = @_; substr($$romref, 6, 1) = "\x00"; - my $sum = unpack('%8C*', substr($$romref, 0, $romsize)); + my $sum = unpack('%8C*', $$romref); substr($$romref, 6, 1) = chr(256 - $sum); # Double check - $sum = unpack('%8C*', substr($$romref, 0, $romsize)); + $sum = unpack('%8C*', $$romref); if ($sum != 0) { print "Checksum fails\n" } elsif ($opts{'v'}) { @@ -146,10 +146,10 @@ sub checksum ($$) { } sub makerom () { - my ($rom, $romsize, $stubsize); + my ($rom, $romsize); - getopts('3xni:p:s:v', \%opts); - $ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-n] [-x] [-3] rom-file\n"; + getopts('3xi:p:s:v', \%opts); + $ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-x] [-3] rom-file\n"; open(R, $ARGV[0]) or die "$ARGV[0]: $!\n"; # Read in the whole ROM in one gulp my $filesize = read(R, $rom, MAXROMSIZE+1); @@ -183,16 +183,10 @@ sub makerom () { } # Pad with 0xFF to $romsize $rom .= "\xFF" x ($romsize - length($rom)); - # If this is a stub ROM, don't force header size to the full amount - if (!$opts{'n'}) { - if ($romsize >= 128 * 1024) { - print "Warning: ROM size exceeds extension BIOS limit\n"; - } - substr($rom, 2, 1) = chr(($romsize / 512) % 256); - } else { - $stubsize = ord(substr($rom, 2, 1)) * 512; - print "Stub size is $stubsize\n" if $opts{'v'}; + if ($romsize >= 128 * 1024) { + print "Warning: ROM size exceeds extension BIOS limit\n"; } + substr($rom, 2, 1) = chr(($romsize / 512) % 256); print "ROM size is $romsize\n" if $opts{'v'}; # set the product string only if we don't have one yet my $pnp_hdr_offset = unpack('v', substr($rom, PNP_PTR_LOC, 2)); @@ -202,7 +196,7 @@ sub makerom () { # 3c503 requires last two bytes to be 0x80 substr($rom, MINROMSIZE-2, 2) = "\x80\x80" if ($opts{'3'} and $romsize == MINROMSIZE); - checksum(\$rom, $opts{'n'} ? $stubsize : $romsize); + checksum(\$rom); writerom($ARGV[0], \$rom); } @@ -219,7 +213,7 @@ sub modrom () { print "$filesize bytes read\n" if $opts{'v'}; pcipnpheaders(\$rom, undef); undiheaders(\$rom); - checksum(\$rom, ord(substr($rom, 2, 1)) * 512); + checksum(\$rom); writerom($ARGV[0], \$rom); }