diff options
author | Joshua Oreman | 2009-10-18 22:12:51 +0200 |
---|---|---|
committer | Marty Connor | 2010-01-20 23:46:48 +0100 |
commit | 06a8398422efb613b7ee4f9d8f1abcc813bb3f3b (patch) | |
tree | 81dc06685687ee84b6b168e1218852e3f6c175bf /src/util | |
parent | [config] Make PXE stack a compile-time option (diff) | |
download | ipxe-06a8398422efb613b7ee4f9d8f1abcc813bb3f3b.tar.gz ipxe-06a8398422efb613b7ee4f9d8f1abcc813bb3f3b.tar.xz ipxe-06a8398422efb613b7ee4f9d8f1abcc813bb3f3b.zip |
[prefix] Add .xrom prefix for a ROM that loads itself by PCI accesses
The standard option ROM format provides a header indicating the size
of the entire ROM, which the BIOS will reserve space for, load, and
call as necessary. However, this space is strictly limited to 128k for
all ROMs. gPXE ameliorates this somewhat by reserving space for itself
in high memory and relocating the majority of its code there, but on
systems prior to PCI3 enough space must still be present to load the
ROM in the first place. Even on PCI3 systems, the BIOS often limits the
size of ROM it will load to a bit over 64kB.
These space problems can be solved by providing an artificially small
size in the ROM header: just enough to let the prefix code (at the
beginning of the ROM image) be loaded by the BIOS. To the BIOS, the
gPXE ROM will appear to be only a few kilobytes; it can then load
the rest of itself by accessing the ROM directly using the PCI
interface reserved for that task.
There are a few problems with this approach. First, gPXE needs to find
an unmapped region in memory to map the ROM so it can read from it;
this is done using the crude but effective approach of scanning high
memory (over 0xF0000000) for a sufficiently large region of all-ones
(0xFF) reads. (In x86 architecture, all-ones is returned for accesses
to memory regions that no mapped device can satisfy.) This is not
provably valid in all situations, but has worked well in practice.
More importantly, this type of ROM access can only work if the PCI ROM
BAR exists at all. NICs on physical add-in PCI cards generally must
have the BAR in order for the BIOS to be able to load their ROM, but
ISA cards and LAN-on-Motherboard cards will both fail to load gPXE
using this scheme.
Due to these uncertainties, it is recommended that .xrom only be used
when a regular .rom image is infeasible due to crowded option ROM
space. However, when it works it could allow loading gPXE images
as large as a flash chip one could find - 128kB or even higher.
Signed-off-by: Marty Connor <mdc@etherboot.org>
Diffstat (limited to 'src/util')
-rwxr-xr-x | src/util/makerom.pl | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/src/util/makerom.pl b/src/util/makerom.pl index aed3a569..68c3be98 100755 --- a/src/util/makerom.pl +++ b/src/util/makerom.pl @@ -130,14 +130,14 @@ sub writerom ($$) { close(R); } -sub checksum ($) { - my ($romref) = @_; +sub checksum ($$) { + my ($romref, $romsize) = @_; substr($$romref, 6, 1) = "\x00"; - my $sum = unpack('%8C*', $$romref); + my $sum = unpack('%8C*', substr($$romref, 0, $romsize)); substr($$romref, 6, 1) = chr(256 - $sum); # Double check - $sum = unpack('%8C*', $$romref); + $sum = unpack('%8C*', substr($$romref, 0, $romsize)); if ($sum != 0) { print "Checksum fails\n" } elsif ($opts{'v'}) { @@ -146,10 +146,10 @@ sub checksum ($) { } sub makerom () { - my ($rom, $romsize); + my ($rom, $romsize, $stubsize); - getopts('3xi:p:s:v', \%opts); - $ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-x] [-3] rom-file\n"; + 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"; 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,10 +183,16 @@ sub makerom () { } # Pad with 0xFF to $romsize $rom .= "\xFF" x ($romsize - length($rom)); - if ($romsize >= 128 * 1024) { - print "Warning: ROM size exceeds extension BIOS limit\n"; + # 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'}; } - 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)); @@ -196,7 +202,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); + checksum(\$rom, $opts{'n'} ? $stubsize : $romsize); writerom($ARGV[0], \$rom); } @@ -213,7 +219,7 @@ sub modrom () { print "$filesize bytes read\n" if $opts{'v'}; pcipnpheaders(\$rom, undef); undiheaders(\$rom); - checksum(\$rom); + checksum(\$rom, ord(substr($rom, 2, 1)) * 512); writerom($ARGV[0], \$rom); } |