summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/util/Option/ROM.pm137
-rwxr-xr-xsrc/util/disrom.pl12
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();