Skip to content

Commit 36a0a66

Browse files
committed
bin/generate-zbm: use mkinitcpio method to calc offsets
Newer versions of the EFI stub provided by systemd-boot are incompatible with the method used by generate-zbm to add sections to the output bundle. mkinitcpio uses a process that evaluates the sizes of each component being combined into the EFI bundle and adjusts their section VMA accordingly. This has been tested with the latest systemd-boot EFI stub and the most recent Gummiboot EFI stub.
1 parent 9222cf9 commit 36a0a66

File tree

1 file changed

+78
-22
lines changed

1 file changed

+78
-22
lines changed

bin/generate-zbm

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ use warnings;
77
our $VERSION = '2.2.1';
88

99
use Getopt::Long qw(:config no_ignore_case auto_version);
10-
use Pod::Usage qw(pod2usage);
10+
use Pod::Usage qw(pod2usage);
1111
use File::Basename;
1212
use File::Temp qw(tempfile tempdir);
1313
use File::Copy;
1414
use File::stat;
1515
use File::Path qw(make_path remove_tree);
1616
use File::Glob qw(:globally :nocase);
1717
use Sort::Versions;
18+
use bigint qw(hex);
1819

1920
use Pod::Usage qw(pod2usage);
2021

@@ -53,7 +54,7 @@ BEGIN {
5354

5455
my ( %runConf, %config );
5556

56-
$runConf{config} = "/etc/zfsbootmenu/config.yaml";
57+
$runConf{config} = "/etc/zfsbootmenu/config.yaml";
5758
$runConf{bootdir} = "/boot";
5859

5960
GetOptions(
@@ -713,8 +714,32 @@ EOF
713714
return $namever;
714715
}
715716

717+
# Given a sections size, calculate where the next section should be placed,
718+
# while respecting the stub alignment value
719+
sub increaseBundleOffset {
720+
my ( $step, $offset, $alignment ) = @_;
721+
$offset += int( ( $step + $alignment - 1 ) / $alignment * $alignment );
722+
Log( "New offset is: " . hex($offset) );
723+
return $offset;
724+
}
725+
726+
# Adds the commands necessary to put another section into the EFI bundle,
727+
# and then calculates where the bundle offset has been moved to
728+
sub addBundleSection {
729+
my ( $cmds, $secname, $filename, $offset, $alignment ) = @_;
730+
731+
my $hex_offset = sprintf( "0x%X", $offset );
732+
push( @$cmds, ( "--add-section", "$secname=\"$filename\"" ), qw(--change-section-vma), ("$secname=\"$hex_offset\""),
733+
);
734+
735+
my $sb = stat($filename);
736+
return increaseBundleOffset( $sb->size, $offset, $alignment );
737+
738+
}
739+
716740
# Creates a UEFI bundle from an initramfs and kernel
717741
# Returns the path to the bundle or dies with an error
742+
718743
sub createUEFIBundle {
719744
my ( $imagedir, $kernel, $initramfs ) = @_;
720745

@@ -734,6 +759,7 @@ sub createUEFIBundle {
734759
exit 1;
735760
}
736761
} else {
762+
737763
# For now, default stub locations are x86_64 only
738764
my @uefi_stub_defaults = qw(
739765
/usr/lib/gummiboot/linuxx64.efi.stub
@@ -756,45 +782,75 @@ sub createUEFIBundle {
756782
}
757783
}
758784

759-
my @cmd = qw(objcopy);
785+
my ( $uki_alignment, $uki_offset );
786+
787+
# Determine stub alignment, most likely 4096
788+
my @cmd = qw(objdump -p);
789+
push( @cmd, $uefi_stub );
790+
791+
my @output = execute(@cmd);
792+
my $status = pop(@output);
793+
if ( $status eq 0 ) {
794+
foreach my $line (@output) {
795+
if ( $line =~ m/SectionAlignment\s+(\d+)/ ) {
796+
Log( "Alignment is: " . hex($1) );
797+
$uki_alignment = hex($1);
798+
}
799+
}
800+
} else {
801+
print "Unable to determine stub alignment!\n";
802+
exit 1;
803+
}
804+
805+
# Determine initial UKI offset value by grabbing the size and VMA of
806+
# the last section of the EFI stub.
807+
@cmd = qw(objdump -w -h);
808+
push( @cmd, $uefi_stub );
809+
810+
@output = execute(@cmd);
811+
$status = pop(@output);
812+
if ( $status eq 0 ) {
813+
my @sizes = split( /\s+/, @output[ scalar @output - 1 ] );
814+
815+
my $size = "0x" . $sizes[3];
816+
my $vma = "0x" . $sizes[4];
817+
my $sum = hex($size) + hex($vma);
818+
819+
$uki_offset = increaseBundleOffset( $sum, 0, $uki_alignment );
820+
Log( "Initial offset is: " . hex($uki_offset) );
821+
} else {
822+
print "Unable to determine initial stub offset!\n";
823+
exit 1;
824+
}
825+
826+
@cmd = qw(objcopy);
827+
828+
my ( $hex_offset, $sb );
760829

761-
# Add os-release, if it exists
762830
if ( -f "/etc/os-release" ) {
763-
push( @cmd,
764-
qw(--add-section .osrel=/etc/os-release),
765-
qw(--change-section-vma .osrel=0x20000)
766-
);
831+
$uki_offset = addBundleSection( \@cmd, ".osrel", "/etc/os-release", $uki_offset, $uki_alignment );
767832
}
768833

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

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

777-
push( @cmd,
778-
( "--add-section", ".cmdline=\"$cmdline\"" ),
779-
qw(--change-section-vma .cmdline=0x30000)
780-
);
841+
$uki_offset = addBundleSection( \@cmd, ".cmdline", $cmdline, $uki_offset, $uki_alignment );
781842
}
782843

783-
# Mandatory kernel and initramfs images
784-
push( @cmd, (
785-
( "--add-section", ".linux=\"$kernel\"" ),
786-
qw(--change-section-vma .linux=0x2000000),
787-
( "--add-section", ".initrd=\"$initramfs\"" ),
788-
qw(--change-section-vma .initrd=0x3000000)
789-
));
844+
$uki_offset = addBundleSection( \@cmd, ".linux", $kernel, $uki_offset, $uki_alignment );
845+
$uki_offset = addBundleSection( \@cmd, ".initrd", $initramfs, $uki_offset, $uki_alignment );
790846

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

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

796-
my @output = execute(@cmd);
797-
my $status = pop(@output);
852+
@output = execute(@cmd);
853+
$status = pop(@output);
798854
if ( $status eq 0 ) {
799855
foreach my $line (@output) {
800856
Log($line);

0 commit comments

Comments
 (0)