mirror of
https://github.com/linuxboot/linuxboot
synced 2024-11-21 23:59:59 +00:00
Merge ssh://github.com/linuxboot/linuxboot into HEAD
This commit is contained in:
commit
c20d46ccb4
104
bin/nvram-compact
Executable file
104
bin/nvram-compact
Executable file
@ -0,0 +1,104 @@
|
||||
#!/usr/bin/perl
|
||||
# Remove invalid and non-data entries from an NVRAM section
|
||||
# This only handles the common cases
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use EFI;
|
||||
use Getopt::Long;
|
||||
use File::Basename;
|
||||
use File::Temp 'tempfile';
|
||||
use Data::Dumper;
|
||||
|
||||
my $nvram_guid = "cef5b9a3-476d-497f-9fdc-e98143e0422c";
|
||||
my $verbose = 0;
|
||||
|
||||
local $/;
|
||||
my $ffs = <>;
|
||||
|
||||
my $file_guid = EFI::read_guid($ffs, 0x00);
|
||||
die "$file_guid != nvram guid $nvram_guid\n"
|
||||
unless $file_guid eq $nvram_guid;
|
||||
|
||||
# should check for FFS header 2, as well as confirm length
|
||||
my $offset = 0x18;
|
||||
my $ffs_hdr = substr($ffs, 0x00, $offset);
|
||||
my $ffs_len = length($ffs);
|
||||
my $data = '';
|
||||
|
||||
|
||||
|
||||
while($offset < $ffs_len - 0x08)
|
||||
{
|
||||
my $nvar = EFI::NVRAM::NVAR->parse($ffs, $offset)
|
||||
or last;
|
||||
|
||||
$offset += $nvar->length();
|
||||
|
||||
# Decide if we keep it:
|
||||
# No valid bit? do not keep
|
||||
next unless $nvar->valid();
|
||||
|
||||
# if this is not an ASCII name variable
|
||||
# we probably have already copied its data by
|
||||
# following the linked list
|
||||
my $name = $nvar->name()
|
||||
or next;
|
||||
my $guid = $nvar->guid();
|
||||
my $attr = $nvar->{attr};
|
||||
|
||||
# Linked? Superceded. We don't want to keep it
|
||||
# but we need to follow the linked list to
|
||||
# find the latest version of the data
|
||||
|
||||
while(1)
|
||||
{
|
||||
my $next = $nvar->next()
|
||||
or last;
|
||||
|
||||
$nvar = EFI::NVRAM::NVAR->parse($ffs, $next);
|
||||
|
||||
die sprintf "offset 0x%x: next failed?\n", $next
|
||||
unless $nvar;
|
||||
|
||||
die sprintf "offset 0x%x: nvar is not valid?\n", $next
|
||||
unless $nvar->valid();
|
||||
}
|
||||
|
||||
# Replace the name and guid with that of our first one
|
||||
# in the linked list of nvars
|
||||
$nvar->{name} = $name;
|
||||
$nvar->{guid} = $guid;
|
||||
$nvar->{attr} = $attr;
|
||||
|
||||
warn "$name\n"
|
||||
if $verbose;
|
||||
|
||||
$data .= $nvar->output();
|
||||
}
|
||||
|
||||
# Create the new FFS and pad it to the end
|
||||
my $new_ffs = $ffs_hdr . $data;
|
||||
$new_ffs .= chr(0xFF) x ($ffs_len - length($new_ffs));
|
||||
|
||||
# Look to see if there is a GUID store?
|
||||
while($offset < $ffs_len)
|
||||
{
|
||||
if (substr($ffs, $offset, 1) eq chr(0xFF))
|
||||
{
|
||||
$offset++;
|
||||
next;
|
||||
}
|
||||
|
||||
# Non-empty space. copy it to the end
|
||||
warn sprintf "offset 0x%x: GUID store found\n", $offset;
|
||||
my $guid_store = substr($ffs, $offset);
|
||||
substr($new_ffs, $offset) = $guid_store;
|
||||
last;
|
||||
}
|
||||
|
||||
|
||||
print $new_ffs;
|
||||
|
@ -29,8 +29,8 @@ $(dixe-files): extract.intermediate
|
||||
FVS := \
|
||||
$(BUILD)/rom/0x00000000.ifd \
|
||||
$(BUILD)/rom/0x00010000.bin \
|
||||
$(BUILD)/rom/0x00800000.fv \
|
||||
$(BUILD)/rom/0x00820000.fv \
|
||||
$(BUILD)/nvram1.vol \
|
||||
$(BUILD)/nvram2.vol \
|
||||
$(BUILD)/rom/0x00840000.bin \
|
||||
$(BUILD)/dxe.vol \
|
||||
$(BUILD)/rom/0x00f00000.fv \
|
||||
@ -43,6 +43,16 @@ $(BUILD)/dxe.vol: \
|
||||
$(BUILD)/Linux.ffs \
|
||||
$(BUILD)/Initrd.ffs \
|
||||
|
||||
nvram1-size := 0x20000
|
||||
nvram2-size := 0x20000
|
||||
$(BUILD)/nvram1.vol: $(BUILD)/nvram1.ffs
|
||||
$(BUILD)/nvram2.vol: $(BUILD)/nvram2.ffs
|
||||
|
||||
$(BUILD)/nvram1.ffs: $(BUILD)/rom/0x00800000/cef5b9a3-476d-497f-9fdc-e98143e0422c.ffs
|
||||
./bin/nvram-compact < $< > $@
|
||||
$(BUILD)/nvram2.ffs: $(BUILD)/rom/0x00820000/cef5b9a3-476d-497f-9fdc-e98143e0422c.ffs
|
||||
./bin/nvram-compact < $< > $@
|
||||
|
||||
# I wish we could use our own builds of these, but
|
||||
# the AMI firmware modules do not play nice with us.
|
||||
NO = \
|
||||
|
176
lib/EFI.pm
176
lib/EFI.pm
@ -467,8 +467,20 @@ sub fv_append
|
||||
|
||||
# if the current offset does not align with the block size,
|
||||
# we should add a pad section until the next block
|
||||
my $block_unaligned = $fv_block_size - (length($$fv_ref) % $fv_block_size);
|
||||
$block_unaligned += $fv_block_size if $block_unaligned < $ffs_hdr_len;
|
||||
# The firmware files can specify their desired alignment
|
||||
# we just force 4KB is they want anything
|
||||
my $attr = ord(substr($ffs, 0x13, 1));
|
||||
my $alignment = ($attr & 0x38) >> 3;
|
||||
if ($alignment == 0)
|
||||
{
|
||||
$alignment = 0x10;
|
||||
} else {
|
||||
warn sprintf "alignment attribute %02x\n", $alignment;
|
||||
$alignment = 0x1000;
|
||||
}
|
||||
|
||||
my $block_unaligned = $alignment - (length($$fv_ref) % $alignment);
|
||||
$block_unaligned += $alignment if $block_unaligned < $ffs_hdr_len;
|
||||
|
||||
$$fv_ref .= EFI::ffs_pad($block_unaligned - $ffs_hdr_len);
|
||||
my $ffs_offset = length($$fv_ref);
|
||||
@ -508,6 +520,13 @@ sub fv_pad
|
||||
|
||||
|
||||
# Helpers for reading values from the ROM images
|
||||
sub read8
|
||||
{
|
||||
my $data = shift;
|
||||
my $offset = shift;
|
||||
return unpack("C", substr($data, $offset, 1));
|
||||
}
|
||||
|
||||
sub read16
|
||||
{
|
||||
my $data = shift;
|
||||
@ -515,6 +534,15 @@ sub read16
|
||||
return unpack("v", substr($data, $offset, 2));
|
||||
}
|
||||
|
||||
sub write16
|
||||
{
|
||||
my $len = shift;
|
||||
return ''
|
||||
. chr(($len >> 0) & 0xFF)
|
||||
. chr(($len >> 8) & 0xFF)
|
||||
;
|
||||
}
|
||||
|
||||
sub read24
|
||||
{
|
||||
my $data = shift;
|
||||
@ -526,7 +554,6 @@ sub read24
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
sub write24
|
||||
{
|
||||
my $len = shift;
|
||||
@ -545,6 +572,17 @@ sub read32
|
||||
return unpack("V", substr($data, $offset, 4));
|
||||
}
|
||||
|
||||
sub write32
|
||||
{
|
||||
my $len = shift;
|
||||
return ''
|
||||
. chr(($len >> 0) & 0xFF)
|
||||
. chr(($len >> 8) & 0xFF)
|
||||
. chr(($len >> 16) & 0xFF)
|
||||
. chr(($len >> 24) & 0xFF)
|
||||
;
|
||||
}
|
||||
|
||||
sub read64
|
||||
{
|
||||
my $data = shift;
|
||||
@ -580,5 +618,137 @@ sub read_guid
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Parse the older NVAR (non-volatile variable) structures
|
||||
#
|
||||
package EFI::NVRAM::NVAR;
|
||||
|
||||
my $nvar_sig = 0x5241564e; # 'NVAR'
|
||||
my $nvar_entry_ascii_name = 0x02;
|
||||
my $nvar_entry_data_only = 0x08;
|
||||
my $nvar_entry_valid = 0x80;
|
||||
|
||||
|
||||
#
|
||||
# Create a NVAR object from an in-memory representation
|
||||
# of the structure.
|
||||
#
|
||||
sub parse
|
||||
{
|
||||
my $class = shift;
|
||||
my $ffs = shift;
|
||||
my $offset = shift || 0;
|
||||
|
||||
my $ffs_len = length($ffs);
|
||||
|
||||
my $sig = EFI::read32($ffs, $offset + 0x00);
|
||||
|
||||
# we've reached the end of the data;
|
||||
return if $sig == 0xFFFFFFFF;
|
||||
|
||||
die sprintf "0x%x: sig %08x != nvram %08x\n",
|
||||
$offset, $sig, $nvar_sig
|
||||
unless $sig eq $nvar_sig;
|
||||
|
||||
my $len = EFI::read16($ffs, $offset + 0x04);
|
||||
|
||||
die sprintf "0x%x: len %x > length %x\n",
|
||||
$offset, $len, $ffs_len
|
||||
unless $offset + $len <= $ffs_len;
|
||||
|
||||
my $nvar = substr($ffs, $offset, $len);
|
||||
my $next = EFI::read24($nvar, 0x06);
|
||||
my $attr = EFI::read8($nvar, 0x09);
|
||||
my $data = substr($nvar, 0x0a);
|
||||
my $name;
|
||||
my $guid_id;
|
||||
|
||||
# depending on the attribute we might have a
|
||||
# nul terminated string and a guid index in the guidstore
|
||||
if ($attr & $nvar_entry_ascii_name)
|
||||
{
|
||||
$guid_id = EFI::read8($data, 0);
|
||||
my $name_end = index($data, chr(0), 1);
|
||||
die sprintf "offset 0x%x: ascii name, but no nul\n", $offset
|
||||
if $name_end == -1;
|
||||
|
||||
$name = substr($data, 1, $name_end-1);
|
||||
|
||||
# remove the guid and name from the data
|
||||
$data = substr($data, $name_end+1);
|
||||
}
|
||||
|
||||
my $self = bless {
|
||||
nvar => $nvar,
|
||||
offset => $offset,
|
||||
attr => $attr,
|
||||
name => $name,
|
||||
guid => $guid_id,
|
||||
next => $next,
|
||||
data => $data,
|
||||
}, $class;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Serialize an NVRAM NVAR structure
|
||||
#
|
||||
sub output
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
my $data = $self->{data};
|
||||
my $attr = $self->{attr};
|
||||
my $name = $self->{name};
|
||||
if ($name)
|
||||
{
|
||||
# update the attribute that we have name
|
||||
$attr |= $nvar_entry_ascii_name;
|
||||
$attr &= ~$nvar_entry_data_only;
|
||||
$data = chr($self->{guid}) . $self->{name} . chr(0x00) . $data;
|
||||
}
|
||||
|
||||
return ''
|
||||
. EFI::write32($nvar_sig) # 0x00
|
||||
. EFI::write16(length($data) + 0x0A) # 0x04
|
||||
. EFI::write24(0xFFFFFF) # no next # 0x06
|
||||
. chr($attr) # 0x09
|
||||
. $data; # 0x0A
|
||||
}
|
||||
|
||||
|
||||
sub length
|
||||
{
|
||||
my $self = shift;
|
||||
return length $self->{nvar};
|
||||
}
|
||||
|
||||
|
||||
sub valid
|
||||
{
|
||||
my $self = shift;
|
||||
return $self->{attr} & $nvar_entry_valid;
|
||||
}
|
||||
|
||||
|
||||
sub next
|
||||
{
|
||||
my $self = shift;
|
||||
# all F is no next, since that can be inverted in the flash
|
||||
return if $self->{next} eq 0xFFFFFF;
|
||||
|
||||
# the next pointer is relative to the offset of this one,
|
||||
# so shift it by the amount that we've advanced
|
||||
return $self->{next} + $self->{offset};
|
||||
}
|
||||
|
||||
sub name { my $self = shift; return $self->{name}; }
|
||||
sub guid { my $self = shift; return $self->{guid}; }
|
||||
sub data { my $self = shift; return $self->{data}; }
|
||||
|
||||
|
||||
"0, but true";
|
||||
__END__
|
||||
|
Loading…
Reference in New Issue
Block a user