diff --git a/dracut-functions.sh b/dracut-functions.sh index ff6749a1..3c475ca7 100755 --- a/dracut-functions.sh +++ b/dracut-functions.sh @@ -995,3 +995,44 @@ get_dev_module() { fi echo "$dev_drivers" } + +# Check if file is in PE format +pe_file_format() { + if [[ $# -eq 1 ]]; then + local magic + magic=$(objdump -p "$1" \ + | gawk '{if ($1 == "Magic"){print strtonum("0x"$2)}}') + magic=$(printf "0x%x" "$magic") + # 0x10b (PE32), 0x20b (PE32+) + [[ $magic == 0x20b || $magic == 0x10b ]] && return 0 + fi + return 1 +} + +# Get specific data from the PE header +pe_get_header_data() { + local data_header + [[ $# -ne "2" ]] && return 1 + [[ $(pe_file_format "$1") -eq 1 ]] && return 1 + data_header=$(objdump -p "$1" \ + | awk -v data="$2" '{if ($1 == data){print $2}}') + echo "$data_header" +} + +# Get the SectionAlignment data from the PE header +pe_get_section_align() { + local align_hex + [[ $# -ne "1" ]] && return 1 + align_hex=$(pe_get_header_data "$1" "SectionAlignment") + [[ $? -eq 1 ]] && return 1 + echo "$((16#$align_hex))" +} + +# Get the ImageBase data from the PE header +pe_get_image_base() { + local base_image + [[ $# -ne "1" ]] && return 1 + base_image=$(pe_get_header_data "$1" "ImageBase") + [[ $? -eq 1 ]] && return 1 + echo "$((16#$base_image))" +} diff --git a/dracut.sh b/dracut.sh index d2f07ac6..1ff51bb1 100755 --- a/dracut.sh +++ b/dracut.sh @@ -1433,7 +1433,6 @@ if [[ ! $print_cmdline ]]; then exit 1 fi unset EFI_MACHINE_TYPE_NAME - EFI_SECTION_VMA_INITRD=0x3000000 case $(uname -m) in x86_64) EFI_MACHINE_TYPE_NAME=x64 @@ -1443,8 +1442,6 @@ if [[ ! $print_cmdline ]]; then ;; aarch64) EFI_MACHINE_TYPE_NAME=aa64 - # aarch64 kernels are uncompressed and thus larger, so we need a bigger gap between vma sections - EFI_SECTION_VMA_INITRD=0x4000000 ;; *) dfatal "Architecture '$(uname -m)' not supported to create a UEFI executable" @@ -2596,29 +2593,64 @@ if [[ $uefi == yes ]]; then done fi + offs=$(objdump -h "$uefi_stub" 2> /dev/null | gawk 'NF==7 {size=strtonum("0x"$3);\ + offset=strtonum("0x"$4)} END {print size + offset}') + if [[ $offs -eq 0 ]]; then + dfatal "Failed to get the size of $uefi_stub to create UEFI image file" + exit 1 + fi + align=$(pe_get_section_align "$uefi_stub") + if [[ $? -eq 1 ]]; then + dfatal "Failed to get the SectionAlignment of the stub PE header to create the UEFI image file" + exit 1 + fi + offs=$((offs + "$align" - offs % "$align")) + [[ -s $dracutsysrootdir/usr/lib/os-release ]] && uefi_osrelease="$dracutsysrootdir/usr/lib/os-release" + [[ -s $dracutsysrootdir/etc/os-release ]] && uefi_osrelease="$dracutsysrootdir/etc/os-release" + [[ -s $uefi_osrelease ]] \ + && uefi_osrelease_offs=${offs} \ + && offs=$((offs + $(stat -Lc%s "$uefi_osrelease"))) \ + && offs=$((offs + "$align" - offs % "$align")) + if [[ $kernel_cmdline ]] || [[ $hostonly_cmdline == yes && -d "$initdir/etc/cmdline.d" ]]; then echo -ne "\x00" >> "$uefi_outdir/cmdline.txt" dinfo "Using UEFI kernel cmdline:" dinfo "$(tr -d '\000' < "$uefi_outdir/cmdline.txt")" uefi_cmdline="${uefi_outdir}/cmdline.txt" + uefi_cmdline_offs=${offs} + offs=$((offs + $(stat -Lc%s "$uefi_cmdline"))) + offs=$((offs + "$align" - offs % "$align")) else unset uefi_cmdline fi - [[ -s $dracutsysrootdir/usr/lib/os-release ]] && uefi_osrelease="$dracutsysrootdir/usr/lib/os-release" - [[ -s $dracutsysrootdir/etc/os-release ]] && uefi_osrelease="$dracutsysrootdir/etc/os-release" if [[ -s ${dracutsysrootdir}${uefi_splash_image} ]]; then uefi_splash_image="${dracutsysrootdir}${uefi_splash_image}" + uefi_splash_offs=${offs} + offs=$((offs + $(stat -Lc%s "$uefi_splash_image"))) + offs=$((offs + "$align" - offs % "$align")) else unset uefi_splash_image fi + uefi_linux_offs="${offs}" + offs=$((offs + $(stat -Lc%s "$kernel_image"))) + offs=$((offs + "$align" - offs % "$align")) + uefi_initrd_offs="${offs}" + + base_image=$(pe_get_image_base "$uefi_stub") + if [[ $? -eq 1 ]]; then + dfatal "Failed to get ImageBase data of $uefi_stub to create UEFI image file" + exit 1 + fi + if objcopy \ - ${uefi_osrelease:+--add-section .osrel="$uefi_osrelease" --change-section-vma .osrel=0x20000} \ - ${uefi_cmdline:+--add-section .cmdline="$uefi_cmdline" --change-section-vma .cmdline=0x30000} \ - ${uefi_splash_image:+--add-section .splash="$uefi_splash_image" --change-section-vma .splash=0x40000} \ - --add-section .linux="$kernel_image" --change-section-vma .linux=0x2000000 \ - --add-section .initrd="${DRACUT_TMPDIR}/initramfs.img" --change-section-vma .initrd="${EFI_SECTION_VMA_INITRD}" \ + ${uefi_osrelease:+--add-section .osrel="$uefi_osrelease" --change-section-vma .osrel=$(printf 0x%x "$uefi_osrelease_offs")} \ + ${uefi_cmdline:+--add-section .cmdline="$uefi_cmdline" --change-section-vma .cmdline=$(printf 0x%x "$uefi_cmdline_offs")} \ + ${uefi_splash_image:+--add-section .splash="$uefi_splash_image" --change-section-vma .splash=$(printf 0x%x "$uefi_splash_offs")} \ + --add-section .linux="$kernel_image" --change-section-vma .linux="$(printf 0x%x "$uefi_linux_offs")" \ + --add-section .initrd="${DRACUT_TMPDIR}/initramfs.img" --change-section-vma .initrd="$(printf 0x%x "$uefi_initrd_offs")" \ + --image-base="$(printf 0x%x "$base_image")" \ "$uefi_stub" "${uefi_outdir}/linux.efi"; then if [[ -n ${uefi_secureboot_key} && -n ${uefi_secureboot_cert} ]]; then if sbsign \