]> git.ipfire.org Git - thirdparty/dracut.git/commitdiff
dracut.sh: add support for creating a UEFI boot executable
authorHarald Hoyer <harald@redhat.com>
Thu, 19 Mar 2015 11:55:17 +0000 (12:55 +0100)
committerHarald Hoyer <harald@redhat.com>
Fri, 20 Mar 2015 13:31:23 +0000 (14:31 +0100)
With an EFI stub, the kernel, the initramfs and a kernel cmdline can be
glued together to a single UEFI executable, which can be booted by a
UEFI BIOS.

dracut-bash-completion.sh
dracut.8.asc
dracut.conf.5.asc
dracut.sh

index 35ddc4d0724fc6be76412e56ea3765bf499fb731..09330a67323082214718f1f95fbf2791018e075d 100644 (file)
@@ -32,6 +32,7 @@ _dracut() {
                               --xz --no-compress --gzip --list-modules --show-modules --keep
                               --printsize --regenerate-all --noimageifnotneeded --early-microcode
                               --no-early-microcode --print-cmdline --prelink --noprelink --reproducible
+                              --uefi
                               '
 
                        [ARG]='-a -m -o -d -I -k -c -L --kver --add --force-add --add-drivers
@@ -39,7 +40,7 @@ _dracut() {
                               --fwdir --libdirs --fscks --add-fstab --mount --device --nofscks
                               --kmoddir --conf --confdir --tmpdir --stdlog --compress --prefix
                               --kernel-cmdline --sshkey --persistent-policy --install-optional
-                              --loginstall
+                              --loginstall --uefi-stub --kernel-image
                               '
         )
 
index 9aecbfbddb6d139aad8ae1975ba3479bfb5ac2f2..f5459b4560566db8397d0131ba159ae4b19df83f 100644 (file)
@@ -465,6 +465,20 @@ will not be able to boot.
 **--loginstall _<DIR>_::
     Log all files installed from the host to _<DIR>_.
 
+**--uefi::
+    Instead of creating an initramfs image, dracut will create an UEFI executable,
+    which can be executed by an UEFI BIOS.
+
+**--uefi-stub _<FILE>_::
+    Specifies the UEFI stub loader, which will load the attached kernel, initramfs and
+    kernel command line and boots the kernel. The default is
+    _/lib/systemd/boot/efi/linux<EFI-MACHINE-TYPE-NAME>.efi.stub_
+    or _/usr/lib/gummiboot/linux<EFI-MACHINE-TYPE-NAME>.efi.stub_
+
+**--kernel-image _<FILE>_::
+    Specifies the kernel image, which to include in the UEFI executable. The default is
+    _/lib/modules/<KERNEL-VERSION>/vmlinuz_ or _/boot/vmlinuz-<KERNEL-VERSION>_
+
 FILES
 -----
 _/var/log/dracut.log_::
index 0531a495d5910565069f8a01718abb53b54dd343..430d5dd46e9586dde64a5b0e6d8322b10bf06137 100644 (file)
@@ -189,6 +189,16 @@ provide a valid _/etc/fstab_.
 *loginstall=*"__<DIR>__"::
     Log all files installed from the host to _<DIR>_.
 
+*uefi_stub=*"_<FILE>_"::
+    Specifies the UEFI stub loader, which will load the attached kernel, initramfs and
+    kernel command line and boots the kernel. The default is
+    _/lib/systemd/boot/efi/linux<EFI-MACHINE-TYPE-NAME>.efi.stub_
+    or _/usr/lib/gummiboot/linux<EFI-MACHINE-TYPE-NAME>.efi.stub_
+
+*kernel_image=*"_<FILE>_"::
+    Specifies the kernel image, which to include in the UEFI executable. The default is
+    _/lib/modules/<KERNEL-VERSION>/vmlinuz_ or _/boot/vmlinuz-<KERNEL-VERSION>_
+
 Files
 -----
 _/etc/dracut.conf_::
index 149557bd6e456363ed70751bbcebee50fd824ea5..92362867db95208f88fc1677d88ecee4eded4bcc 100755 (executable)
--- a/dracut.sh
+++ b/dracut.sh
@@ -195,6 +195,10 @@ Creates initial ramdisk images for preloading modules
   --logfile [FILE]      Logfile to use (overrides configuration setting)
   --reproducible        Create reproducible images
   --loginstall [DIR]    Log all files installed from the host to [DIR]
+  --uefi                Create an UEFI executable with the kernel cmdline and
+                        kernel combined
+  --uefi-stub [FILE]    Use the UEFI stub [FILE] to create an UEFI executable
+  --kernel-image [FILE] location of the kernel image
 
 If [LIST] has multiple arguments, then you have to put these in quotes.
 
@@ -389,6 +393,9 @@ rearrange_params()
         --long no-early-microcode \
         --long reproducible \
         --long loginstall: \
+        --long uefi \
+        --long uefi-stub: \
+        --long kernel-image: \
         -- "$@")
 
     if (( $? != 0 )); then
@@ -577,6 +584,11 @@ while :; do
         --regenerate-all) regenerate_all="yes";;
         --noimageifnotneeded) noimageifnotneeded="yes";;
         --reproducible) reproducible_l="yes";;
+        --uefi)        uefi="yes";;
+        --uefi-stub)
+                       uefi_stub_l="$2";               PARMS_TO_STORE+=" '$2'"; shift;;
+        --kernel-image)
+                       kernel_image_l="$2";            PARMS_TO_STORE+=" '$2'"; shift;;
         --) shift; break;;
 
         *)  # should not even reach this point
@@ -822,6 +834,8 @@ stdloglvl=$((stdloglvl + verbosity_mod_l))
 [[ $logfile_l ]] && logfile="$logfile_l"
 [[ $reproducible_l ]] && reproducible="$reproducible_l"
 [[ $loginstall_l ]] && loginstall="$loginstall_l"
+[[ $uefi_stub_l ]] && uefi_stub="$uefi_stub_l"
+[[ $kernel_image_l ]] && kernel_image="$kernel_image_l"
 
 # eliminate IFS hackery when messing with fw_dir
 fw_dir=${fw_dir//:/ }
@@ -880,6 +894,7 @@ trap '
     ret=$?;
     [[ $keep ]] && echo "Not removing $initdir." >&2 || { [[ $initdir ]] && rm -rf -- "$initdir"; };
     [[ $keep ]] && echo "Not removing $early_cpio_dir." >&2 || { [[ $early_cpio_dir ]] && rm -Rf -- "$early_cpio_dir"; };
+    [[ $keep ]] && echo "Not removing $uefi_outdir." >&2 || { [[ $uefi_outdir ]] && rm -Rf -- "$uefi_outdir"; };
     [[ $_dlogdir ]] && rm -Rf -- "$_dlogdir";
     exit $ret;
     ' EXIT
@@ -1031,6 +1046,48 @@ if [[ ! $print_cmdline ]]; then
         fi
         loginstall=$(readlink -f "$loginstall")
     fi
+
+    if [[ $uefi = yes ]]; then
+        if ! command -v objcopy &>/dev/null; then
+            dfatal "Need 'objcopy' to create a UEFI executable"
+            exit 1
+        fi
+        unset EFI_MACHINE_TYPE_NAME
+        case $(arch) in
+            x86_64)
+                EFI_MACHINE_TYPE_NAME=x64;;
+            ia32)
+                EFI_MACHINE_TYPE_NAME=ia32;;
+            *)
+                dfatal "Architecture '$(arch)' not supported to create a UEFI executable"
+                exit 1
+                ;;
+        esac
+
+        if ! [[ -s $uefi_stub ]]; then
+            for uefi_stub in \
+                "/lib/systemd/boot/efi/linux${EFI_MACHINE_TYPE_NAME}.efi.stub" \
+                    "/usr/lib/gummiboot/linux${EFI_MACHINE_TYPE_NAME}.efi.stub"; do
+                [[ -s $uefi_stub ]] || continue
+                break
+            done
+        fi
+        if ! [[ -s $uefi_stub ]]; then
+            dfatal "Can't find a uefi stub '$uefi_stub' to create a UEFI executable"
+            exit 1
+        fi
+
+        if ! [[ $kernel_image ]]; then
+            for kernel_image in "/lib/modules/$kernel/vmlinuz" "/boot/vmlinuz-$kernel"; do
+                [[ -s "$kernel_image" ]] || continue
+                break
+            done
+        fi
+        if ! [[ -s $kernel_image ]]; then
+            dfatal "Can't find a kernel image '$kernel_image' to create a UEFI executable"
+            exit 1
+        fi
+    fi
 fi
 
 if [[ $acpi_override = yes ]] && ! check_kernel_config CONFIG_ACPI_INITRD_TABLE_OVERRIDE; then
@@ -1643,7 +1700,14 @@ if [[ $hostonly_cmdline ]] ; then
     fi
 fi
 rm -f -- "$outfile"
-dinfo "*** Creating image file ***"
+dinfo "*** Creating image file '$outfile' ***"
+
+if [[ $uefi = yes ]]; then
+    uefi_outfile="$outfile"
+    readonly uefi_outdir="$(mktemp --tmpdir="$TMPDIR/" -d -t initrd.XXXXXX)"
+    # redirect initrd output
+    outfile="$uefi_outdir/initrd"
+fi
 
 if [[ $DRACUT_REPRODUCIBLE ]]; then
     find "$initdir" -newer "$dracutbasedir/dracut-functions.sh" -print0 \
@@ -1679,7 +1743,7 @@ if ! (
     dfatal "dracut: creation of $outfile failed"
     exit 1
 fi
-dinfo "*** Creating image file done ***"
+dinfo "*** Creating initrd image file '$outfile' done ***"
 
 if (( maxloglvl >= 5 )); then
     if [[ $allowlocal ]]; then
@@ -1689,4 +1753,31 @@ if (( maxloglvl >= 5 )); then
     fi
 fi
 
+if [[ $uefi = yes ]]; then
+    if [[ $kernel_cmdline ]]; then
+        echo -n "$kernel_cmdline" > "$uefi_outdir/cmdline.txt"
+    elif [[ $hostonly_cmdline = yes ]] && [ -d $initdir/etc/cmdline.d ];then
+        for conf in $initdir/etc/cmdline.d/*.conf ; do
+            [ -e "$conf" ] || continue
+            printf "%s " "$(< $conf)" >> "$uefi_outdir/cmdline.txt"
+        done
+    else
+        do_print_cmdline > "$uefi_outdir/cmdline.txt"
+    fi
+    echo -ne "\x00" >> "$uefi_outdir/cmdline.txt"
+
+    dinfo "Using UEFI kernel cmdline:"
+    dinfo $(< "$uefi_outdir/cmdline.txt")
+
+    [[ -s /etc/os-release ]] && uefi_osrelease="/etc/os-release"
+
+    objcopy \
+        ${uefi_osrelease:+--add-section .osrel=$uefi_osrelease --change-section-vma .osrel=0x20000} \
+        --add-section .cmdline="$uefi_outdir/cmdline.txt" --change-section-vma .cmdline=0x30000 \
+        --add-section .linux="$kernel_image" --change-section-vma .linux=0x40000 \
+        --add-section .initrd="$outfile" --change-section-vma .initrd=0x3000000 \
+        "$uefi_stub" "$uefi_outfile"
+    dinfo "*** Creating UEFI image file '$uefi_outfile' done ***"
+fi
+
 exit 0