From 5de45cd3da2308a6db37fb7c0822c9fdadf00d96 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 23 Jul 2012 17:41:38 +0100 Subject: [PATCH] [romprefix] Report a pessimistic runtime size estimate PCI3.0 allows us to report a "runtime size" which can be smaller than the actual ROM size. On systems that support PMM our runtime size will be small (~2.5kB), which helps to conserve the limited option ROM space. However, there is no guarantee that the PMM allocation will succeed, and so we need to report the worst-case runtime size in the PCI header. Move the "shrunk ROM size" field from the PCI header to a new "iPXE ROM header", allowing it to be accessed by ROM-manipulation utilities such as disrom.pl. Reported-by: Anton D. Kachalov Signed-off-by: Michael Brown --- src/arch/i386/prefix/romprefix.S | 28 +++++++++--- src/util/Option/ROM.pm | 77 +++++++++++++++++++++++++++++++- src/util/disrom.pl | 11 +++++ src/util/fixrom.pl | 1 + 4 files changed, 111 insertions(+), 6 deletions(-) diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S index 2719a70a..2b4c20b8 100644 --- a/src/arch/i386/prefix/romprefix.S +++ b/src/arch/i386/prefix/romprefix.S @@ -63,6 +63,8 @@ romheader_size: .byte 0 /* Size in 512-byte blocks */ jmp init /* Initialisation vector */ checksum: .byte 0 + .org 0x10 + .word ipxeheader .org 0x16 .word undiheader .org 0x18 @@ -78,9 +80,6 @@ checksum: .long 0 .previous -build_id: - .long _build_id /* Randomly-generated build ID */ - pciheader: .ascii "PCIR" /* Signature */ .word pci_vendor_id /* Vendor identification */ @@ -106,7 +105,7 @@ pciheader_runtime_length: .long pciheader_image_length .long 512 .long 0 - .ascii "ADHW" + .ascii ZINFO_TYPE_ADxW .long pciheader_runtime_length .long 512 .long 0 @@ -175,6 +174,25 @@ undiheader: .equ undiheader_len, . - undiheader .size undiheader, . - undiheader +ipxeheader: + .ascii "iPXE" /* Signature */ + .byte ipxeheader_len /* Length of structure */ + .byte 0 /* Checksum */ +shrunk_rom_size: + .byte 0 /* Shrunk size (in 512-byte blocks) */ + .byte 0 /* Reserved */ +build_id: + .long _build_id /* Randomly-generated build ID */ + .equ ipxeheader_len, . - ipxeheader + .size ipxeheader, . - ipxeheader + + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ + .ascii "ADHB" + .long shrunk_rom_size + .long 512 + .long 0 + .previous + /* Initialisation (called once during POST) * * Determine whether or not this is a PnP system via a signature @@ -354,7 +372,7 @@ pmm_scan: addr32 rep movsl /* PMM presence implies flat real mode */ popw %es /* Shrink ROM */ - movw pciheader_runtime_length, %ax + movb shrunk_rom_size, %al movb %al, romheader_size 1: /* Allocate decompression PMM block. Round up the size to the * nearest 128kB and use the size within the PMM handle; this diff --git a/src/util/Option/ROM.pm b/src/util/Option/ROM.pm index fdc5e4ae..82d65426 100644 --- a/src/util/Option/ROM.pm +++ b/src/util/Option/ROM.pm @@ -172,9 +172,10 @@ use constant ROM_SIGNATURE => 0xaa55; use constant PCI_SIGNATURE => 'PCIR'; use constant PCI_LAST_IMAGE => 0x80; use constant PNP_SIGNATURE => '$PnP'; +use constant IPXE_SIGNATURE => 'iPXE'; our @EXPORT_OK = qw ( ROM_SIGNATURE PCI_SIGNATURE PCI_LAST_IMAGE - PNP_SIGNATURE ); + PNP_SIGNATURE IPXE_SIGNATURE ); our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] ); use constant JMP_SHORT => 0xeb; @@ -232,6 +233,7 @@ sub new { init => { offset => 0x03, length => 0x03, pack => \&pack_init, unpack => \&unpack_init }, checksum => { offset => 0x06, length => 0x01, pack => "C" }, + ipxe_header => { offset => 0x10, length => 0x02, pack => "S" }, bofm_header => { offset => 0x14, length => 0x02, pack => "S" }, undi_header => { offset => 0x16, length => 0x02, pack => "S" }, pci_header => { offset => 0x18, length => 0x02, pack => "S" }, @@ -390,6 +392,25 @@ sub pnp_header { =pod +=item C<< ipxe_header () >> + +Return a C object representing the ROM's iPXE +header, if present. + +=cut + +sub ipxe_header { + my $hash = shift; + my $self = tied(%$hash); + + my $offset = $hash->{ipxe_header}; + return undef unless $offset != 0; + + return Option::ROM::iPXE->new ( $self->{data}, $offset ); +} + +=pod + =item C<< next_image () >> Return a C object representing the next image within the @@ -566,4 +587,58 @@ sub product { return unpack ( "Z*", $raw ); } +############################################################################## +# +# Option::ROM::iPXE +# +############################################################################## + +package Option::ROM::iPXE; + +use strict; +use warnings; +use Carp; +use bytes; + +sub new { + my $class = shift; + my $data = shift; + my $offset = shift; + + my $hash = {}; + tie %$hash, "Option::ROM::Fields", { + data => $data, + offset => $offset, + length => 0x06, + fields => { + signature => { offset => 0x00, length => 0x04, pack => "a4" }, + struct_length => { offset => 0x04, length => 0x01, pack => "C" }, + checksum => { offset => 0x05, length => 0x01, pack => "C" }, + shrunk_length => { offset => 0x06, length => 0x01, pack => "C" }, + build_id => { offset => 0x08, length => 0x04, pack => "L" }, + }, + }; + bless $hash, $class; + + # Retrieve true length of structure + my $self = tied ( %$hash ); + $self->{length} = $hash->{struct_length}; + + return $hash; +} + +sub checksum { + my $hash = shift; + my $self = tied(%$hash); + + return $self->checksum(); +} + +sub fix_checksum { + my $hash = shift; + my $self = tied(%$hash); + + $hash->{checksum} = ( ( $hash->{checksum} - $hash->checksum() ) & 0xff ); +} + 1; diff --git a/src/util/disrom.pl b/src/util/disrom.pl index c133c26a..87138686 100755 --- a/src/util/disrom.pl +++ b/src/util/disrom.pl @@ -85,4 +85,15 @@ do { printf "\n"; } + my $ipxe = $rom->ipxe_header(); + if ( $ipxe ) { + printf "iPXE header:\n\n"; + printf " %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $ipxe->{checksum}, + ( ( $ipxe->checksum == 0 ) ? "" : "INCORRECT: " ), $ipxe->checksum; + printf " %-16s 0x%02x (%d)\n", "Shrunk length:", + $ipxe->{shrunk_length}, ( $ipxe->{shrunk_length} * 512 ); + printf " %-16s 0x%08x\n", "Build ID:", $ipxe->{build_id}; + printf "\n"; + } + } while ( $rom = $rom->next_image ); diff --git a/src/util/fixrom.pl b/src/util/fixrom.pl index c84e2cf2..8987b512 100755 --- a/src/util/fixrom.pl +++ b/src/util/fixrom.pl @@ -32,6 +32,7 @@ foreach my $romfile ( @romfiles ) { my $image = $rom; while ( $image ) { $image->pnp_header->fix_checksum() if $image->pnp_header; + $image->ipxe_header->fix_checksum() if $image->ipxe_header; $image->fix_checksum(); $image = $image->next_image(); }