mirror of
https://github.com/xcat2/xNBA.git
synced 2024-11-25 19:08:35 +00:00
[util] Allow Option::ROM to understand and modify initialisation entry 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.
This commit is contained in:
parent
8f8f5acf09
commit
23bca8f9d8
@ -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 {
|
||||
@ -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;
|
||||
@ -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 () >>
|
||||
@ -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" },
|
||||
|
@ -38,6 +38,7 @@ die "ROM image truncated (is $filelength, should be $romlength)\n"
|
||||
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};
|
||||
|
@ -23,6 +23,18 @@ use FindBin;
|
||||
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;
|
||||
|
||||
@ -34,6 +46,12 @@ foreach my $rom ( @roms ) {
|
||||
# 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;
|
||||
@ -52,8 +70,8 @@ foreach my $rom ( @roms ) {
|
||||
# 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 );
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,9 +79,9 @@ foreach my $rom ( @roms ) {
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user