diff options
-rw-r--r-- | src/util/Option/ROM.pm | 137 | ||||
-rwxr-xr-x | src/util/disrom.pl | 12 |
2 files changed, 110 insertions, 39 deletions
diff --git a/src/util/Option/ROM.pm b/src/util/Option/ROM.pm index 48d92dda..7bbd6986 100644 --- a/src/util/Option/ROM.pm +++ b/src/util/Option/ROM.pm @@ -116,7 +116,9 @@ sub EXISTS { return ( exists $self->{fields}->{$key} && ( ( $self->{fields}->{$key}->{offset} + - $self->{fields}->{$key}->{length} ) <= $self->{length} ) ); + $self->{fields}->{$key}->{length} ) <= $self->{length} ) && + ( ! defined $self->{fields}->{$key}->{check} || + &{$self->{fields}->{$key}->{check}} ( $self, $key ) ) ); } sub FIRSTKEY { @@ -172,10 +174,11 @@ use constant ROM_SIGNATURE => 0xaa55; use constant PCI_SIGNATURE => 'PCIR'; use constant PCI_LAST_IMAGE => 0x80; use constant PNP_SIGNATURE => '$PnP'; +use constant UNDI_SIGNATURE => 'UNDI'; use constant IPXE_SIGNATURE => 'iPXE'; our @EXPORT_OK = qw ( ROM_SIGNATURE PCI_SIGNATURE PCI_LAST_IMAGE - PNP_SIGNATURE IPXE_SIGNATURE ); + PNP_SIGNATURE UNDI_SIGNATURE IPXE_SIGNATURE ); our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] ); use constant JMP_SHORT => 0xeb; @@ -210,10 +213,20 @@ sub unpack_init { } elsif ( $jump == 0 ) { return 0; } else { - croak "Unrecognised jump instruction in init vector\n"; + carp "Unrecognised jump instruction in init vector\n"; + return 0; } } +sub check_pcat_rom { + my $self = shift; + my $key = shift; + + my $pci = $self->{rom}->pci_header (); + + return ! defined $pci || $pci->{code_type} == 0x00; +} + =pod =item C<< new () >> @@ -227,21 +240,29 @@ sub new { my $hash = {}; tie %$hash, "Option::ROM::Fields", { + rom => $hash, # ROM object itself data => undef, offset => 0x00, length => 0x20, + file_offset => 0x0, fields => { signature => { offset => 0x00, length => 0x02, pack => "S" }, length => { offset => 0x02, length => 0x01, pack => "C" }, # "init" is part of a jump instruction 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" }, + pack => \&pack_init, unpack => \&unpack_init, + check => \&check_pcat_rom }, + checksum => { offset => 0x06, length => 0x01, pack => "C", + check => \&check_pcat_rom }, + ipxe_header => { offset => 0x10, length => 0x02, pack => "S", + check => \&check_pcat_rom }, + bofm_header => { offset => 0x14, length => 0x02, pack => "S", + check => \&check_pcat_rom }, + undi_header => { offset => 0x16, length => 0x02, pack => "S", + check => \&check_pcat_rom }, pci_header => { offset => 0x18, length => 0x02, pack => "S" }, - pnp_header => { offset => 0x1a, length => 0x02, pack => "S" }, + pnp_header => { offset => 0x1a, length => 0x02, pack => "S", + check => \&check_pcat_rom }, }, }; bless $hash, $class; @@ -250,9 +271,9 @@ sub new { =pod -=item C<< set ( $data ) >> +=item C<< set ( $data [, $file_offset ] ) >> -Set option ROM contents. +Set option ROM contents, optionally sets original file offset. =cut @@ -260,9 +281,11 @@ sub set { my $hash = shift; my $self = tied(%$hash); my $data = shift; + my $file_offset = shift // 0x0; # Store data $self->{data} = \$data; + $self->{file_offset} = $file_offset; # Split out any data belonging to the next image delete $self->{next_image}; @@ -273,7 +296,7 @@ sub set { my $remainder = substr ( $data, $length ); $data = substr ( $data, 0, $length ); $self->{next_image} = new Option::ROM; - $self->{next_image}->set ( $remainder ); + $self->{next_image}->set ( $remainder, $self->{file_offset} + $length ); } } @@ -311,6 +334,7 @@ sub load { open my $fh, "<$filename" or croak "Cannot open $filename for reading: $!"; + binmode $fh; read $fh, my $data, -s $fh; $hash->set ( $data ); close $fh; @@ -335,6 +359,7 @@ sub save { open my $fh, ">$filename" or croak "Cannot open $filename for writing: $!"; my $data = $hash->get(); + binmode $fh; print $fh $data; close $fh; } @@ -369,9 +394,9 @@ sub pci_header { my $self = tied(%$hash); my $offset = $hash->{pci_header}; - return undef unless $offset != 0; + return undef unless $offset; - return Option::ROM::PCI->new ( $self->{data}, $offset ); + return Option::ROM::PCI->new ( $self, $offset ); } =pod @@ -388,9 +413,9 @@ sub pnp_header { my $self = tied(%$hash); my $offset = $hash->{pnp_header}; - return undef unless $offset != 0; + return undef unless $offset; - return Option::ROM::PnP->new ( $self->{data}, $offset ); + return Option::ROM::PnP->new ( $self, $offset ); } =pod @@ -407,9 +432,9 @@ sub undi_header { my $self = tied(%$hash); my $offset = $hash->{undi_header}; - return undef unless $offset != 0; + return undef unless $offset; - return Option::ROM::UNDI->new ( $self->{data}, $offset ); + return Option::ROM::UNDI->new ( $self, $offset ); } =pod @@ -426,9 +451,9 @@ sub ipxe_header { my $self = tied(%$hash); my $offset = $hash->{ipxe_header}; - return undef unless $offset != 0; + return undef unless $offset; - return Option::ROM::iPXE->new ( $self->{data}, $offset ); + return Option::ROM::iPXE->new ( $self, $offset ); } =pod @@ -475,9 +500,25 @@ sub fix_checksum { my $hash = shift; my $self = tied(%$hash); + return unless ( exists $hash->{checksum} ); $hash->{checksum} = ( ( $hash->{checksum} - $hash->checksum() ) & 0xff ); } +=pod + +=item C<< file_offset () >> + +Get file offset of image. + +=cut + +sub file_offset { + my $hash = shift; + my $self = tied(%$hash); + + return $self->{file_offset}; +} + ############################################################################## # # Option::ROM::PCI @@ -493,12 +534,13 @@ use bytes; sub new { my $class = shift; - my $data = shift; + my $rom = shift; my $offset = shift; my $hash = {}; tie %$hash, "Option::ROM::Fields", { - data => $data, + rom => $rom, + data => $rom->{data}, offset => $offset, length => 0x0c, fields => { @@ -522,11 +564,17 @@ sub new { }; bless $hash, $class; - # Retrieve true length of structure my $self = tied ( %$hash ); + my $length = $rom->{rom}->length (); + + return undef unless ( $offset + $self->{length} <= $length && + $hash->{signature} eq Option::ROM::PCI_SIGNATURE && + $offset + $hash->{struct_length} <= $length ); + + # Retrieve true length of structure $self->{length} = $hash->{struct_length}; - return $hash; + return $hash; } sub device_list { @@ -564,12 +612,13 @@ use bytes; sub new { my $class = shift; - my $data = shift; + my $rom = shift; my $offset = shift; my $hash = {}; tie %$hash, "Option::ROM::Fields", { - data => $data, + rom => $rom, + data => $rom->{data}, offset => $offset, length => 0x06, fields => { @@ -586,11 +635,17 @@ sub new { }; bless $hash, $class; - # Retrieve true length of structure my $self = tied ( %$hash ); + my $length = $rom->{rom}->length (); + + return undef unless ( $offset + $self->{length} <= $length && + $hash->{signature} eq Option::ROM::PNP_SIGNATURE && + $offset + $hash->{struct_length} * 16 <= $length ); + + # Retrieve true length of structure $self->{length} = ( $hash->{struct_length} * 16 ); - return $hash; + return $hash; } sub checksum { @@ -644,12 +699,13 @@ use bytes; sub new { my $class = shift; - my $data = shift; + my $rom = shift; my $offset = shift; my $hash = {}; tie %$hash, "Option::ROM::Fields", { - data => $data, + rom => $rom, + data => $rom->{data}, offset => $offset, length => 0x16, fields => { @@ -669,8 +725,14 @@ sub new { }; bless $hash, $class; - # Retrieve true length of structure my $self = tied ( %$hash ); + my $length = $rom->{rom}->length (); + + return undef unless ( $offset + $self->{length} <= $length && + $hash->{signature} eq Option::ROM::UNDI_SIGNATURE && + $offset + $hash->{struct_length} <= $length ); + + # Retrieve true length of structure $self->{length} = $hash->{struct_length}; return $hash; @@ -705,12 +767,13 @@ use bytes; sub new { my $class = shift; - my $data = shift; + my $rom = shift; my $offset = shift; my $hash = {}; tie %$hash, "Option::ROM::Fields", { - data => $data, + rom => $rom, + data => $rom->{data}, offset => $offset, length => 0x06, fields => { @@ -723,8 +786,14 @@ sub new { }; bless $hash, $class; - # Retrieve true length of structure my $self = tied ( %$hash ); + my $length = $rom->{rom}->length (); + + return undef unless ( $offset + $self->{length} <= $length && + $hash->{signature} eq Option::ROM::IPXE_SIGNATURE && + $offset + $hash->{struct_length} <= $length ); + + # Retrieve true length of structure $self->{length} = $hash->{struct_length}; return $hash; diff --git a/src/util/disrom.pl b/src/util/disrom.pl index 920a86b2..71eee590 100755 --- a/src/util/disrom.pl +++ b/src/util/disrom.pl @@ -28,8 +28,9 @@ my $romfile = shift || "-"; my $rom = new Option::ROM; $rom->load ( $romfile ); -do { +my $index = 0; +do { die "Not an option ROM image\n" unless $rom->{signature} == ROM_SIGNATURE; @@ -38,15 +39,16 @@ do { die "ROM image truncated (is $filelength, should be $romlength)\n" if $filelength < $romlength; + printf "Index: %d, offset: 0x%08x\n\n", $index++, $rom->file_offset; printf "ROM header:\n\n"; printf " %-16s 0x%02x (%d)\n", "Length:", $rom->{length}, ( $rom->{length} * 512 ); printf " %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $rom->{checksum}, - ( ( $rom->checksum == 0 ) ? "" : "INCORRECT: " ), $rom->checksum; - printf " %-16s 0x%04x\n", "Init:", $rom->{init}; - printf " %-16s 0x%04x\n", "UNDI header:", $rom->{undi_header}; + ( ( $rom->checksum () == 0 ) ? "" : "INCORRECT: " ), $rom->checksum () if ( exists $rom->{checksum} ); + printf " %-16s 0x%04x\n", "Init:", $rom->{init} if ( defined $rom->{init} ); + printf " %-16s 0x%04x\n", "UNDI header:", $rom->{undi_header} if ( exists $rom->{undi_header} ); printf " %-16s 0x%04x\n", "PCI header:", $rom->{pci_header}; - printf " %-16s 0x%04x\n", "PnP header:", $rom->{pnp_header}; + printf " %-16s 0x%04x\n", "PnP header:", $rom->{pnp_header} if ( exists $rom->{pnp_header} ); printf "\n"; my $pci = $rom->pci_header(); |