dracut.sh: add support for creating a UEFI boot executable

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.
master
Harald Hoyer 2015-03-19 12:55:17 +01:00
parent 21a209735a
commit 636d2d46a5
4 changed files with 119 additions and 3 deletions

View 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
'
)


View 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_::

View 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_::

View File

@ -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