]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[util] Allow Option::ROM to understand and modify initialisation entry point
authorMichael Brown <mcb30@etherboot.org>
Fri, 15 Aug 2008 03:10:35 +0000 (04:10 +0100)
committerMichael Brown <mcb30@etherboot.org>
Fri, 15 Aug 2008 03:10:35 +0000 (04:10 +0100)
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.

src/util/Option/ROM.pm
src/util/disrom.pl
src/util/mergerom.pl

index f5c33f8a29453084da2872b5d308ce0e2debba83..7a1bb88389d8d1320960173c0ba52d096cb223c7 100644 (file)
@@ -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" },
index c472037afa817cf4980ddf1ea2b559c50b71d7a8..80ac4af8f14f162abfaf943a0920da365ca444d5 100755 (executable)
@@ -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};
index ce1befb7f4375e339bb17b27b370d1e56b157a50..f9c52502d13de827ca6ee848e4744d7ad00e55e2 100755 (executable)
@@ -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