mirror of
https://github.com/hamishcoleman/thinkpad-ec
synced 2024-11-16 06:12:48 +00:00
Add support for extracting firmware images from FL1 files with PFH headers embedded in the file
This commit is contained in:
parent
844a6d1ad6
commit
c1f42903d9
@ -10,6 +10,9 @@ use strict;
|
|||||||
# any actions needed to extract or insert into the container - It does
|
# any actions needed to extract or insert into the container - It does
|
||||||
# not check any checksums within the IMG - that should be left to
|
# not check any checksums within the IMG - that should be left to
|
||||||
# the img manipulating tools (like mec tools).
|
# the img manipulating tools (like mec tools).
|
||||||
|
#
|
||||||
|
# This script now supports extracting a couple of FL1 files, so its name
|
||||||
|
# is starting to be wrong.
|
||||||
|
|
||||||
package FL2::base;
|
package FL2::base;
|
||||||
use warnings;
|
use warnings;
|
||||||
@ -350,6 +353,126 @@ sub extract {
|
|||||||
#}
|
#}
|
||||||
|
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
package FL1::PFH_header;
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
#
|
||||||
|
# Look for FL1 files that have a "$PFH" prefix header near their end
|
||||||
|
#
|
||||||
|
# Seen in at least the l530 firmware updates
|
||||||
|
|
||||||
|
use base qw(FL2::base);
|
||||||
|
|
||||||
|
sub _find_capsule_header {
|
||||||
|
my $self = shift;
|
||||||
|
my $buf = $self->get_block(0,16);
|
||||||
|
return undef if (!defined($buf));
|
||||||
|
$buf = $$buf;
|
||||||
|
|
||||||
|
my $capsule_uuid = "\xbd\x86\x66\x3b\x76\x0d\x30\x40\xb7\x0e\xb5\x51\x9e\x2f\xc5\xa0";
|
||||||
|
|
||||||
|
if ($buf eq $capsule_uuid) {
|
||||||
|
# TODO
|
||||||
|
# - while I am reading the capsule signature, I dont understand
|
||||||
|
# why the magic offset doesnt match anything in the capsule header
|
||||||
|
return 0x1d0;
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _find_pfh {
|
||||||
|
my $self = shift;
|
||||||
|
my $offset = 0;
|
||||||
|
|
||||||
|
while ($offset < $self->{filesize}) {
|
||||||
|
my $buf = $self->get_block($offset, 4);
|
||||||
|
return undef if (!defined($buf));
|
||||||
|
$buf = $$buf;
|
||||||
|
|
||||||
|
if ($buf eq '$PFH') {
|
||||||
|
return $offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
$offset+=0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef; # not found
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _check {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
# List of known file sizes (basically a doublecheck on the signature)
|
||||||
|
my $known = {
|
||||||
|
9437264 => 1,
|
||||||
|
12587008 => 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
my $capsule_offset_hack = $self->_find_capsule_header() ||0;
|
||||||
|
|
||||||
|
my $header_offset = $self->_find_pfh();
|
||||||
|
return undef if (!defined($header_offset));
|
||||||
|
|
||||||
|
my $header_size = 4+4+4+2+4+2+4+4;
|
||||||
|
|
||||||
|
my $buf = $self->get_block($header_offset, $header_size);
|
||||||
|
|
||||||
|
return undef if (!defined($buf));
|
||||||
|
return undef if (!defined($known->{$self->{filesize}}));
|
||||||
|
|
||||||
|
my @fields = qw(
|
||||||
|
signature version headersize headerchecksum
|
||||||
|
totalimagesize totalimagechecksum
|
||||||
|
numberofimages imagetableoffset
|
||||||
|
);
|
||||||
|
my @values = unpack("a4VVvVvVV",$$buf);
|
||||||
|
map { $self->{header}{$fields[$_]} = $values[$_] } (0..scalar(@fields)-1);
|
||||||
|
|
||||||
|
return undef if ($self->{header}{signature} ne '$PFH');
|
||||||
|
|
||||||
|
# now load the partition table
|
||||||
|
$buf = $self->get_block(
|
||||||
|
$self->{header}{imagetableoffset}+$capsule_offset_hack,
|
||||||
|
(4+4+8+4)*$self->{header}{numberofimages}
|
||||||
|
);
|
||||||
|
return undef if (!defined($buf));
|
||||||
|
|
||||||
|
$buf = $$buf;
|
||||||
|
|
||||||
|
while ($buf) {
|
||||||
|
my ($FileOffset, $Size, $FlashAddress, $NameOffset, $rest) =
|
||||||
|
unpack("VVQVa*",$buf);
|
||||||
|
$buf = $rest;
|
||||||
|
|
||||||
|
my $buf2 = $self->get_block(
|
||||||
|
$NameOffset+$capsule_offset_hack,
|
||||||
|
32 # TODO - just a guess at the max name size
|
||||||
|
);
|
||||||
|
return undef if (!defined($buf2));
|
||||||
|
|
||||||
|
my $name = unpack("Z*",$$buf2);
|
||||||
|
|
||||||
|
if ($name eq 'Ec') {
|
||||||
|
$self->set_offset_size(
|
||||||
|
$FileOffset+$capsule_offset_hack,
|
||||||
|
$Size,
|
||||||
|
);
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub extract {
|
||||||
|
return shift->_extract(shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
# no insert() will work until we know how to generate the checksums
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
@ -395,6 +518,9 @@ sub detect_img {
|
|||||||
if (!defined($object)) {
|
if (!defined($object)) {
|
||||||
$object = FL2::prefix_head->new($fh);
|
$object = FL2::prefix_head->new($fh);
|
||||||
}
|
}
|
||||||
|
if (!defined($object)) {
|
||||||
|
$object = FL1::PFH_header->new($fh);
|
||||||
|
}
|
||||||
|
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user