Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[util] Allow Option::ROM to understand and modify initialisation entr…
…y point

Add support for manipulating the jump instruction that forms the
option ROM initialisation entry point, so that mergerom.pl can treat
it just like other entry points.

Add support for merging the initialisation entry point (and IBM BOFM
table) to mergerom.pl; this is another slightly icky but unfortunately
necessary GPL vs. NDA workaround.  When mergerom.pl replaces an entry
point in the original ROM, it now fills in the corresponding entry
point in the merged ROM with the original value; this allows (for
example) a merged initialisation entry point to do some processing and
then jump back to the original entry point.
  • Loading branch information
Michael Brown committed Aug 15, 2008
1 parent 8f8f5ac commit 23bca8f
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 7 deletions.
44 changes: 42 additions & 2 deletions src/util/Option/ROM.pm
Expand Up @@ -73,7 +73,10 @@ sub FETCH {
my $raw = substr ( ${$self->{data}},
( $self->{offset} + $self->{fields}->{$key}->{offset} ),
$self->{fields}->{$key}->{length} );
return unpack ( $self->{fields}->{$key}->{pack}, $raw );
my $unpack = ( ref $self->{fields}->{$key}->{unpack} ?
$self->{fields}->{$key}->{unpack} :
sub { unpack ( $self->{fields}->{$key}->{pack}, shift ); } );
return &$unpack ( $raw );
}

sub STORE {
Expand All @@ -82,7 +85,10 @@ sub STORE {
my $value = shift;

croak "Nonexistent field \"$key\"" unless $self->EXISTS ( $key );
my $raw = pack ( $self->{fields}->{$key}->{pack}, $value );
my $pack = ( ref $self->{fields}->{$key}->{pack} ?
$self->{fields}->{$key}->{pack} :
sub { pack ( $self->{fields}->{$key}->{pack}, shift ); } );
my $raw = &$pack ( $value );
substr ( ${$self->{data}},
( $self->{offset} + $self->{fields}->{$key}->{offset} ),
$self->{fields}->{$key}->{length} ) = $raw;
Expand Down Expand Up @@ -168,6 +174,36 @@ use constant PNP_SIGNATURE => '$PnP';
our @EXPORT_OK = qw ( ROM_SIGNATURE PCI_SIGNATURE PNP_SIGNATURE );
our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] );

use constant JMP_SHORT => 0xeb;
use constant JMP_NEAR => 0xe9;

sub pack_init {
my $dest = shift;

# Always create a near jump; it's simpler
if ( $dest ) {
return pack ( "CS", JMP_NEAR, ( $dest - 6 ) );
} else {
return pack ( "CS", 0, 0 );
}
}

sub unpack_init {
my $instr = shift;

# Accept both short and near jumps
( my $jump, my $offset ) = unpack ( "CS", $instr );
if ( $jump == JMP_SHORT ) {
return ( $offset + 5 );
} elsif ( $jump == JMP_NEAR ) {
return ( $offset + 6 );
} elsif ( $jump == 0 ) {
return 0;
} else {
croak "Unrecognised jump instruction in init vector\n";
}
}

=pod
=item C<< new () >>
Expand All @@ -187,7 +223,11 @@ sub new {
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" },
bofm_header => { offset => 0x14, length => 0x02, pack => "S" },
undi_header => { offset => 0x16, length => 0x02, pack => "S" },
pci_header => { offset => 0x18, length => 0x02, pack => "S" },
pnp_header => { offset => 0x1a, length => 0x02, pack => "S" },
Expand Down
1 change: 1 addition & 0 deletions src/util/disrom.pl
Expand Up @@ -38,6 +38,7 @@
printf "ROM header:\n\n";
printf " Length:\t0x%02x (%d)\n", $rom->{length}, ( $rom->{length} * 512 );
printf " Checksum:\t0x%02x (0x%02x)\n", $rom->{checksum}, $rom->checksum;
printf " Init:\t\t0x%04x\n", $rom->{init};
printf " UNDI header:\t0x%04x\n", $rom->{undi_header};
printf " PCI header:\t0x%04x\n", $rom->{pci_header};
printf " PnP header:\t0x%04x\n", $rom->{pnp_header};
Expand Down
28 changes: 23 additions & 5 deletions src/util/mergerom.pl
Expand Up @@ -23,6 +23,18 @@
use lib "$FindBin::Bin";
use Option::ROM qw ( :all );

sub merge_entry_points {
my $baserom_entry = \shift;
my $rom_entry = \shift;
my $offset = shift;

if ( $$rom_entry ) {
my $old_entry = $$baserom_entry;
$$baserom_entry = ( $offset + $$rom_entry );
$$rom_entry = $old_entry;
}
}

my @romfiles = @ARGV;
my @roms = map { my $rom = new Option::ROM; $rom->load($_); $rom } @romfiles;

Expand All @@ -34,6 +46,12 @@
# Update base length
$baserom->{length} += $rom->{length};

# Merge initialisation entry point
merge_entry_points ( $baserom->{init}, $rom->{init}, $offset );

# Merge BOFM header
merge_entry_points ( $baserom->{bofm_header}, $rom->{bofm_header}, $offset );

# Update PCI header, if present in both
my $baserom_pci = $baserom->pci_header;
my $rom_pci = $rom->pci_header;
Expand All @@ -52,18 +70,18 @@
# Merge CLP entry point
if ( exists ( $baserom_pci->{clp_entry} ) &&
exists ( $rom_pci->{clp_entry} ) ) {
$baserom_pci->{clp_entry} = ( $offset + $rom_pci->{clp_entry} )
if $rom_pci->{clp_entry};
merge_entry_points ( $baserom_pci->{clp_entry}, $rom_pci->{clp_entry},
$offset );
}
}

# Update PnP header, if present in both
my $baserom_pnp = $baserom->pnp_header;
my $rom_pnp = $rom->pnp_header;
if ( $baserom_pnp && $rom_pnp ) {
$baserom_pnp->{bcv} = ( $offset + $rom_pnp->{bcv} ) if $rom_pnp->{bcv};
$baserom_pnp->{bdv} = ( $offset + $rom_pnp->{bdv} ) if $rom_pnp->{bdv};
$baserom_pnp->{bev} = ( $offset + $rom_pnp->{bev} ) if $rom_pnp->{bev};
merge_entry_points ( $baserom_pnp->{bcv}, $rom_pnp->{bcv}, $offset );
merge_entry_points ( $baserom_pnp->{bdv}, $rom_pnp->{bdv}, $offset );
merge_entry_points ( $baserom_pnp->{bev}, $rom_pnp->{bev}, $offset );
}

# Fix checksum for this ROM segment
Expand Down

0 comments on commit 23bca8f

Please sign in to comment.