linuxboot/bin/nvram-compact
2018-03-16 10:35:44 -04:00

105 lines
2.1 KiB
Perl
Executable File

#!/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;