@@ -7,14 +7,15 @@ use warnings;
77our $VERSION = ' 2.2.1' ;
88
99use Getopt::Long qw( :config no_ignore_case auto_version) ;
10- use Pod::Usage qw( pod2usage) ;
10+ use Pod::Usage qw( pod2usage) ;
1111use File::Basename;
1212use File::Temp qw( tempfile tempdir) ;
1313use File::Copy;
1414use File::stat ;
1515use File::Path qw( make_path remove_tree) ;
1616use File::Glob qw( :globally :nocase) ;
1717use Sort::Versions;
18+ use bigint qw( hex) ;
1819
1920use Pod::Usage qw( pod2usage) ;
2021
@@ -53,7 +54,7 @@ BEGIN {
5354
5455my ( %runConf , %config );
5556
56- $runConf {config } = " /etc/zfsbootmenu/config.yaml" ;
57+ $runConf {config } = " /etc/zfsbootmenu/config.yaml" ;
5758$runConf {bootdir } = " /boot" ;
5859
5960GetOptions(
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+
718743sub 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