~ubuntu-branches/ubuntu/raring/ipxe/raring

« back to all changes in this revision

Viewing changes to src/util/Option/ROM.pm

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2012-11-14 15:47:31 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20121114154731-jhuy5d1h2jw75qe9
Tags: 1.0.0+git-4.d6b0b76-0ubuntu1
* New upstream snapshot:
  - d/p/iscsi*.patch: Dropped - included in snapshot.
  - Refreshed all other patches.
* d/p/enable-https.patch: Enable HTTPS support (LP: #1025239).

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
#
15
15
# You should have received a copy of the GNU General Public License
16
16
# along with this program; if not, write to the Free Software
17
 
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
18
# 02110-1301, USA.
18
19
 
19
20
=head1 NAME
20
21
 
169
170
 
170
171
use constant ROM_SIGNATURE => 0xaa55;
171
172
use constant PCI_SIGNATURE => 'PCIR';
 
173
use constant PCI_LAST_IMAGE => 0x80;
172
174
use constant PNP_SIGNATURE => '$PnP';
 
175
use constant IPXE_SIGNATURE => 'iPXE';
173
176
 
174
 
our @EXPORT_OK = qw ( ROM_SIGNATURE PCI_SIGNATURE PNP_SIGNATURE );
 
177
our @EXPORT_OK = qw ( ROM_SIGNATURE PCI_SIGNATURE PCI_LAST_IMAGE
 
178
                      PNP_SIGNATURE IPXE_SIGNATURE );
175
179
our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] );
176
180
 
177
181
use constant JMP_SHORT => 0xeb;
178
182
use constant JMP_NEAR => 0xe9;
 
183
use constant CALL_NEAR => 0xe8;
179
184
 
180
185
sub pack_init {
181
186
  my $dest = shift;
199
204
  } elsif ( $jump == JMP_NEAR ) {
200
205
    my $offset = unpack ( "xS", $instr );
201
206
    return ( $offset + 6 );
 
207
  } elsif ( $jump == CALL_NEAR ) {
 
208
    my $offset = unpack ( "xS", $instr );
 
209
    return ( $offset + 6 );
202
210
  } elsif ( $jump == 0 ) {
203
211
    return 0;
204
212
  } else {
229
237
      init =>           { offset => 0x03, length => 0x03,
230
238
                          pack => \&pack_init, unpack => \&unpack_init },
231
239
      checksum =>       { offset => 0x06, length => 0x01, pack => "C" },
 
240
      ipxe_header =>    { offset => 0x10, length => 0x02, pack => "S" },
232
241
      bofm_header =>    { offset => 0x14, length => 0x02, pack => "S" },
233
242
      undi_header =>    { offset => 0x16, length => 0x02, pack => "S" },
234
243
      pci_header =>     { offset => 0x18, length => 0x02, pack => "S" },
241
250
 
242
251
=pod
243
252
 
 
253
=item C<< set ( $data ) >>
 
254
 
 
255
Set option ROM contents.
 
256
 
 
257
=cut
 
258
 
 
259
sub set {
 
260
  my $hash = shift;
 
261
  my $self = tied(%$hash);
 
262
  my $data = shift;
 
263
 
 
264
  # Store data
 
265
  $self->{data} = \$data;
 
266
 
 
267
  # Split out any data belonging to the next image
 
268
  delete $self->{next_image};
 
269
  my $length = ( $hash->{length} * 512 );
 
270
  my $pci_header = $hash->pci_header();
 
271
  if ( ( $length < length $data ) &&
 
272
       ( defined $pci_header ) &&
 
273
       ( ! ( $pci_header->{last_image} & PCI_LAST_IMAGE ) ) ) {
 
274
    my $remainder = substr ( $data, $length );
 
275
    $data = substr ( $data, 0, $length );
 
276
    $self->{next_image} = new Option::ROM;
 
277
    $self->{next_image}->set ( $remainder );
 
278
  }
 
279
}
 
280
 
 
281
=pod
 
282
 
 
283
=item C<< get () >>
 
284
 
 
285
Get option ROM contents.
 
286
 
 
287
=cut
 
288
 
 
289
sub get {
 
290
  my $hash = shift;
 
291
  my $self = tied(%$hash);
 
292
 
 
293
  my $data = ${$self->{data}};
 
294
  $data .= $self->{next_image}->get() if $self->{next_image};
 
295
  return $data;
 
296
}
 
297
 
 
298
=pod
 
299
 
244
300
=item C<< load ( $filename ) >>
245
301
 
246
302
Load option ROM contents from the file C<$filename>.
256
312
 
257
313
  open my $fh, "<$filename"
258
314
      or croak "Cannot open $filename for reading: $!";
259
 
  read $fh, my $data, ( 128 * 1024 ); # 128kB is theoretical max size
260
 
  $self->{data} = \$data;
 
315
  read $fh, my $data, -s $fh;
 
316
  $hash->set ( $data );
261
317
  close $fh;
262
318
}
263
319
 
279
335
 
280
336
  open my $fh, ">$filename"
281
337
      or croak "Cannot open $filename for writing: $!";
282
 
  print $fh ${$self->{data}};
 
338
  my $data = $hash->get();
 
339
  print $fh $data;
283
340
  close $fh;
284
341
}
285
342
 
339
396
 
340
397
=pod
341
398
 
 
399
=item C<< undi_header () >>
 
400
 
 
401
Return a C<Option::ROM::UNDI> object representing the ROM's UNDI header,
 
402
if present.
 
403
 
 
404
=cut
 
405
 
 
406
sub undi_header {
 
407
  my $hash = shift;
 
408
  my $self = tied(%$hash);
 
409
 
 
410
  my $offset = $hash->{undi_header};
 
411
  return undef unless $offset != 0;
 
412
 
 
413
  return Option::ROM::UNDI->new ( $self->{data}, $offset );
 
414
}
 
415
 
 
416
=pod
 
417
 
 
418
=item C<< ipxe_header () >>
 
419
 
 
420
Return a C<Option::ROM::iPXE> object representing the ROM's iPXE
 
421
header, if present.
 
422
 
 
423
=cut
 
424
 
 
425
sub ipxe_header {
 
426
  my $hash = shift;
 
427
  my $self = tied(%$hash);
 
428
 
 
429
  my $offset = $hash->{ipxe_header};
 
430
  return undef unless $offset != 0;
 
431
 
 
432
  return Option::ROM::iPXE->new ( $self->{data}, $offset );
 
433
}
 
434
 
 
435
=pod
 
436
 
 
437
=item C<< next_image () >>
 
438
 
 
439
Return a C<Option::ROM> object representing the next image within the
 
440
ROM, if present.
 
441
 
 
442
=cut
 
443
 
 
444
sub next_image {
 
445
  my $hash = shift;
 
446
  my $self = tied(%$hash);
 
447
 
 
448
  return $self->{next_image};
 
449
}
 
450
 
 
451
=pod
 
452
 
342
453
=item C<< checksum () >>
343
454
 
344
455
Calculate the byte checksum of the ROM.
499
610
  return unpack ( "Z*", $raw );
500
611
}
501
612
 
 
613
##############################################################################
 
614
#
 
615
# Option::ROM::UNDI
 
616
#
 
617
##############################################################################
 
618
 
 
619
package Option::ROM::UNDI;
 
620
 
 
621
use strict;
 
622
use warnings;
 
623
use Carp;
 
624
use bytes;
 
625
 
 
626
sub new {
 
627
  my $class = shift;
 
628
  my $data = shift;
 
629
  my $offset = shift;
 
630
 
 
631
  my $hash = {};
 
632
  tie %$hash, "Option::ROM::Fields", {
 
633
    data => $data,
 
634
    offset => $offset,
 
635
    length => 0x16,
 
636
    fields => {
 
637
      signature =>      { offset => 0x00, length => 0x04, pack => "a4" },
 
638
      struct_length =>  { offset => 0x04, length => 0x01, pack => "C" },
 
639
      checksum =>       { offset => 0x05, length => 0x01, pack => "C" },
 
640
      struct_revision =>{ offset => 0x06, length => 0x01, pack => "C" },
 
641
      version_revision =>{ offset => 0x07, length => 0x01, pack => "C" },
 
642
      version_minor =>  { offset => 0x08, length => 0x01, pack => "C" },
 
643
      version_major =>  { offset => 0x09, length => 0x01, pack => "C" },
 
644
      loader_entry =>   { offset => 0x0a, length => 0x02, pack => "S" },
 
645
      stack_size =>     { offset => 0x0c, length => 0x02, pack => "S" },
 
646
      data_size =>      { offset => 0x0e, length => 0x02, pack => "S" },
 
647
      code_size =>      { offset => 0x10, length => 0x02, pack => "S" },
 
648
      bus_type =>       { offset => 0x12, length => 0x04, pack => "a4" },
 
649
    },
 
650
  };
 
651
  bless $hash, $class;
 
652
 
 
653
  # Retrieve true length of structure
 
654
  my $self = tied ( %$hash );
 
655
  $self->{length} = $hash->{struct_length};
 
656
 
 
657
  return $hash;
 
658
}
 
659
 
 
660
sub checksum {
 
661
  my $hash = shift;
 
662
  my $self = tied(%$hash);
 
663
 
 
664
  return $self->checksum();
 
665
}
 
666
 
 
667
sub fix_checksum {
 
668
  my $hash = shift;
 
669
  my $self = tied(%$hash);
 
670
 
 
671
  $hash->{checksum} = ( ( $hash->{checksum} - $hash->checksum() ) & 0xff );
 
672
}
 
673
 
 
674
##############################################################################
 
675
#
 
676
# Option::ROM::iPXE
 
677
#
 
678
##############################################################################
 
679
 
 
680
package Option::ROM::iPXE;
 
681
 
 
682
use strict;
 
683
use warnings;
 
684
use Carp;
 
685
use bytes;
 
686
 
 
687
sub new {
 
688
  my $class = shift;
 
689
  my $data = shift;
 
690
  my $offset = shift;
 
691
 
 
692
  my $hash = {};
 
693
  tie %$hash, "Option::ROM::Fields", {
 
694
    data => $data,
 
695
    offset => $offset,
 
696
    length => 0x06,
 
697
    fields => {
 
698
      signature =>      { offset => 0x00, length => 0x04, pack => "a4" },
 
699
      struct_length =>  { offset => 0x04, length => 0x01, pack => "C" },
 
700
      checksum =>       { offset => 0x05, length => 0x01, pack => "C" },
 
701
      shrunk_length =>  { offset => 0x06, length => 0x01, pack => "C" },
 
702
      build_id =>       { offset => 0x08, length => 0x04, pack => "L" },
 
703
    },
 
704
  };
 
705
  bless $hash, $class;
 
706
 
 
707
  # Retrieve true length of structure
 
708
  my $self = tied ( %$hash );
 
709
  $self->{length} = $hash->{struct_length};
 
710
 
 
711
  return $hash;
 
712
}
 
713
 
 
714
sub checksum {
 
715
  my $hash = shift;
 
716
  my $self = tied(%$hash);
 
717
 
 
718
  return $self->checksum();
 
719
}
 
720
 
 
721
sub fix_checksum {
 
722
  my $hash = shift;
 
723
  my $self = tied(%$hash);
 
724
 
 
725
  $hash->{checksum} = ( ( $hash->{checksum} - $hash->checksum() ) & 0xff );
 
726
}
 
727
 
502
728
1;