Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bin/generate-zbm: use objcopy procedure from mkinitcpio #509

Merged
merged 1 commit into from
Oct 24, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 78 additions & 22 deletions bin/generate-zbm
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ use warnings;
our $VERSION = '2.2.1';

use Getopt::Long qw(:config no_ignore_case auto_version);
use Pod::Usage qw(pod2usage);
use Pod::Usage qw(pod2usage);
use File::Basename;
use File::Temp qw(tempfile tempdir);
use File::Copy;
use File::stat;
use File::Path qw(make_path remove_tree);
use File::Glob qw(:globally :nocase);
use Sort::Versions;
use bigint qw(hex);

use Pod::Usage qw(pod2usage);

Expand Down Expand Up @@ -53,7 +54,7 @@ BEGIN {

my ( %runConf, %config );

$runConf{config} = "/etc/zfsbootmenu/config.yaml";
$runConf{config} = "/etc/zfsbootmenu/config.yaml";
$runConf{bootdir} = "/boot";

GetOptions(
Expand Down Expand Up @@ -713,8 +714,32 @@ EOF
return $namever;
}

# Given a sections size, calculate where the next section should be placed,
# while respecting the stub alignment value
sub increaseBundleOffset {
my ( $step, $offset, $alignment ) = @_;
$offset += int( ( $step + $alignment - 1 ) / $alignment * $alignment );
Log( "New offset is: " . hex($offset) );
return $offset;
}

# Adds the commands necessary to put another section into the EFI bundle,
# and then calculates where the bundle offset has been moved to
sub addBundleSection {
my ( $cmds, $secname, $filename, $offset, $alignment ) = @_;

my $hex_offset = sprintf( "0x%X", $offset );
push( @$cmds, ( "--add-section", "$secname=\"$filename\"" ), qw(--change-section-vma), ("$secname=\"$hex_offset\""),
);

my $sb = stat($filename);
return increaseBundleOffset( $sb->size, $offset, $alignment );

}

# Creates a UEFI bundle from an initramfs and kernel
# Returns the path to the bundle or dies with an error

sub createUEFIBundle {
my ( $imagedir, $kernel, $initramfs ) = @_;

Expand All @@ -734,6 +759,7 @@ sub createUEFIBundle {
exit 1;
}
} else {

# For now, default stub locations are x86_64 only
my @uefi_stub_defaults = qw(
/usr/lib/gummiboot/linuxx64.efi.stub
Expand All @@ -756,45 +782,75 @@ sub createUEFIBundle {
}
}

my @cmd = qw(objcopy);
my ( $uki_alignment, $uki_offset );

# Determine stub alignment, most likely 4096
my @cmd = qw(objdump -p);
push( @cmd, $uefi_stub );

my @output = execute(@cmd);
my $status = pop(@output);
if ( $status eq 0 ) {
foreach my $line (@output) {
if ( $line =~ m/SectionAlignment\s+(\d+)/ ) {
Log( "Alignment is: " . hex($1) );
$uki_alignment = hex($1);
}
}
} else {
print "Unable to determine stub alignment!\n";
exit 1;
}

# Determine initial UKI offset value by grabbing the size and VMA of
# the last section of the EFI stub.
@cmd = qw(objdump -w -h);
push( @cmd, $uefi_stub );

@output = execute(@cmd);
$status = pop(@output);
if ( $status eq 0 ) {
my @sizes = split( /\s+/, @output[ scalar @output - 1 ] );

my $size = "0x" . $sizes[3];
my $vma = "0x" . $sizes[4];
my $sum = hex($size) + hex($vma);

$uki_offset = increaseBundleOffset( $sum, 0, $uki_alignment );
Log( "Initial offset is: " . hex($uki_offset) );
} else {
print "Unable to determine initial stub offset!\n";
exit 1;
}

@cmd = qw(objcopy);

my ( $hex_offset, $sb );

# Add os-release, if it exists
if ( -f "/etc/os-release" ) {
push( @cmd,
qw(--add-section .osrel=/etc/os-release),
qw(--change-section-vma .osrel=0x20000)
);
$uki_offset = addBundleSection( \@cmd, ".osrel", "/etc/os-release", $uki_offset, $uki_alignment );
}

# Add cmdline, if it exists
if ( nonempty $runConf{cmdline} ) {
my $cmdline = join( '/', $imagedir, "cmdline.txt" );

open( my $fh, '>', $cmdline );
print $fh $runConf{cmdline};
close($fh);

push( @cmd,
( "--add-section", ".cmdline=\"$cmdline\"" ),
qw(--change-section-vma .cmdline=0x30000)
);
$uki_offset = addBundleSection( \@cmd, ".cmdline", $cmdline, $uki_offset, $uki_alignment );
}

# Mandatory kernel and initramfs images
push( @cmd, (
( "--add-section", ".linux=\"$kernel\"" ),
qw(--change-section-vma .linux=0x2000000),
( "--add-section", ".initrd=\"$initramfs\"" ),
qw(--change-section-vma .initrd=0x3000000)
));
$uki_offset = addBundleSection( \@cmd, ".linux", $kernel, $uki_offset, $uki_alignment );
$uki_offset = addBundleSection( \@cmd, ".initrd", $initramfs, $uki_offset, $uki_alignment );

push( @cmd, ( $uefi_stub, $output_file ) );

my $command = join( ' ', @cmd );
Log("Executing: $command");

my @output = execute(@cmd);
my $status = pop(@output);
@output = execute(@cmd);
$status = pop(@output);
if ( $status eq 0 ) {
foreach my $line (@output) {
Log($line);
Expand Down