Closed conrad-heimbold closed 1 year ago
I just created an EFI kernel image both with hard-coded/fixed offsets and with flexible/calculated offsets and the difference is quite noticeable:
$ ls -hsl /boot/efi/EFI/Arch/
total 153M
35M -rwxr-xr-x 1 root root 35M Aug 22 17:15 linux-calculated-offsets-signed.efi
40M -rwxr-xr-x 1 root root 40M Aug 22 17:14 linux-hardcoded-offsets-signed.efi
So with calculated offsets, the Linux EFI image is approximately 5 Mebibyte smaller. This means, the Linux EFI image is 5 / 40 = 12,5% smaller!
Now I will try to boot both versions to check how much faster the EFI kernel image with flexible/calculated offsets is in comparison to the EFI kernel image with hardcoded/fixed offsets.
Boot time with fixed/hardcoded offsets:
Startup finished in 6.391s (firmware) + 449ms (loader) + 647ms (kernel) + 8.396s (initrd) + 1.328s (userspace) = 17.214s
graphical.target reached after 1.325s in userspace.
Startup finished in 6.336s (firmware) + 449ms (loader) + 630ms (kernel) + 8.759s (initrd) + 1.967s (userspace) = 18.142s
graphical.target reached after 1.967s in userspace.
Boot time with calculated/flexible offsets:
Startup finished in 6.237s (firmware) + 386ms (loader) + 634ms (kernel) + 7.500s (initrd) + 1.342s (userspace) = 16.101s
graphical.target reached after 1.315s in userspace.
Startup finished in 6.186s (firmware) + 385ms (loader) + 646ms (kernel) + 8.304s (initrd) + 1.248s (userspace) = 16.770s
graphical.target reached after 1.247s in userspace.
So approx. 449ms - 386 ms = 63 milliseconds less for the loader, and (8.396s + 8.759s) / 2 - (7.500s + 8.304s) / 2 = 8.5775s - 7.902s = 0.676 seconds less for the initrd.
So using flexible/calculated offsets would make booting the unified Linux EFI image approximately 0.739 seconds faster!
For a comparison, the offsets:
$ objdump -h /efi/EFI/Arch/linux-hardcoded-offsets-signed.efi > /efi/EFI/Arch/linux-hardcoded-offsets-signed.efi.offsets
$ objdump -h /efi/EFI/Arch/linux-calculated-offsets-signed.efi > /efi/EFI/Arch/linux-calculated-offsets-signed.efi.offsets
$ diff linux-calculated-offsets-signed.efi.offsets linux-hardcoded-offsets-signed.efi.offsets
2c2
< linux-calculated-offsets-signed.efi: file format pei-x86-64
---
> linux-hardcoded-offsets-signed.efi: file format pei-x86-64
22c22
< 8 .osrel 0000011d 0000000000012150 0000000000012150 0000b600 2**2
---
> 8 .osrel 0000011d 0000000000020000 0000000000020000 0000b600 2**2
24c24
< 9 .cmdline 00000071 000000000001226d 000000000001226d 0000b800 2**2
---
> 9 .cmdline 00000070 0000000000030000 0000000000030000 0000b800 2**2
26c26
< 10 .splash 0005c572 00000000000122de 00000000000122de 0000ba00 2**2
---
> 10 .splash 0005c572 0000000000040000 0000000000040000 0000ba00 2**2
28c28
< 11 .linux 00a7e340 000000000006e850 000000000006e850 00068000 2**2
---
> 11 .linux 00a7e340 0000000002000000 0000000002000000 00068000 2**2
30c30
< 12 .initrd 01779682 0000000000aecb90 0000000000aecb90 00ae6400 2**2
---
> 12 .initrd 01c6a282 0000000003000000 0000000003000000 00ae6400 2**2
Oh, i just noticed that this won't make the image smaller, because the vma section positions are concerning the image when loaded into RAM, not the file itself. My assumption was wrong. I did it again with the same initramfs-file and now it doesn't make a difference:
$ ls -alh /efi/EFI/Arch/
total 158M
drwxr-xr-x 3 root root 4.0K Aug 22 18:36 .
drwxr-xr-x 9 root root 4.0K Aug 14 21:20 ..
-rwxr-xr-x 1 root root 40M Aug 22 18:35 linux-calculated-offsets-signed.efi
-rwxr-xr-x 1 root root 40M Aug 22 18:34 linux-hardcoded-offsets-signed.efi
The files have the same size, one is not 5 MB / 12,5% smaller.
$ diff boottime-with-hardcoded-efi-offsets.3.txt boottime-with-calculated-efi-offsets.3.txt
1,2c1,2
< Startup finished in 6.383s (firmware) + 449ms (loader) + 643ms (kernel) + 7.959s (initrd) + 1.078s (userspace) = 16.514s
< graphical.target reached after 1.076s in userspace.
---
> Startup finished in 6.339s (firmware) + 450ms (loader) + 647ms (kernel) + 8.310s (initrd) + 1.240s (userspace) = 16.987s
> graphical.target reached after 1.232s in userspace.
I don't know what went wrong. Now the difference is not that big anymore.
Thanks for the research. I'll look into this further to see if there are any benefits.
After some systemd 254 changes it seems, the signed image produced by sbupdate is broken, issue is similar to dracutdevs/dracut#2431 so it seems like this will be a requirement after systemd 254 release. (254rc3 currently in ArchLinux testing and this results in a non-bootable kernel)
Unfortunately, I don't have the capability to check it now. If someone can provide a succinct fix, this would be nice.
Arch updated to systemd 254 now. If this project won't be adjusted soon then I think it should be retired or big bold warning should be added in readme about its incompatibility with Arch. Thx for all those years.
Just became a victim of this, with a really, REALLY bad timing.
This should either be fixed ASAP or at least deprecated / updated with a script that prints a big warning about not being able to boot...
I think that with systemd 254 rolling to Arch today, this is going to burn a lot of people.
The tool backs up the previous signed image automatically to a .bak
file next to the original image on the EFI partition. You can boot it manually to rescue the system.
Please try the latest version from AUR.
I get:
/e/E/arch [1]$ sudo sbupdate
Generating and signing linux-signed.efi
Host arch 'x86_64', EFI arch 'x64'
Traceback (most recent call last):
File "/usr/lib/systemd/ukify", line 1482, in <module>
main()
File "/usr/lib/systemd/ukify", line 1472, in main
check_inputs(opts)
File "/usr/lib/systemd/ukify", line 359, in check_inputs
check_splash(opts.splash)
File "/usr/lib/systemd/ukify", line 342, in check_splash
img = Image.open(filename, formats=['BMP'])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/PIL/Image.py", line 3280, in open
raise UnidentifiedImageError(msg)
PIL.UnidentifiedImageError: cannot identify image file '/dev/null'
Also if anyone is having trouble using the backup image, once it partially boots and puts you into the root shell you may have to downgrade linux and reboot
pacman -U /var/cache/pacman/pkg/linux-6.4.7.arch1-1-x86_64.pkg.tar.zst
That said, at this point if you set up a uki with mkinitcpio, it's easier to use sbsigntools and boot the uki direcly https://wiki.archlinux.org/title/Unified_kernel_image#Signing_the_UKIs_for_Secure_Boot not sure about keeping fwupdmgr signed though, if anyone has a simple solution for that ~lmk~
Splash should be fixed in 1bd9722cb4017c545c5ded7eb7c6b66921625dd0.
Have the same problem with 0.r131.4926075-1
, kernel is not bootable. Please fix this ASAP.
@bitwave What is the console output when you run sudo sbupdate
manually?
@bitwave The fixed version is r132 or later... Please update your installation.
objcopy
in https://github.com/andreyv/sbupdate/blob/master/sbupdate#L170 uses hard-coded section-vma positions:0x20000
forosrel
,0x30000
forcmdline
,0x40000
forsplash
, and so on.The Arch Wiki in https://wiki.archlinux.org/title/Unified_kernel_image#Manually however recommends more flexible section-vma positions, that depend on the size of the sections / parts before. They first calculate the offsets:
... and then use these offsets instead:
I think this flexible approach is much better, because it can make the resulting UEFI kernel image much smaller; which makes booting a little bit faster.
Analysing the generated UEFI image and getting the sections is still easily possible with tools like
objdump
, so I don't see any added value in using hard-coded offsets:Should I make a pull request for this improvement?