diff --git a/man/mkinitcpio.8.txt b/man/mkinitcpio.8.txt
index 46ff0670..5d987cef 100644
--- a/man/mkinitcpio.8.txt
+++ b/man/mkinitcpio.8.txt
@@ -30,7 +30,7 @@ Options
comma-separated. This option can be specified multiple times.
*-c, \--config* 'config'::
- Use 'config' file to generate the ramdisk. Default: /etc/mkinitcpio.conf
+ Use 'config' file to generate the ramdisk. Default: '/etc/mkinitcpio.conf'.
*-d, \--generatedir* 'directory'::
Set 'directory' as the location where the initramfs is built. This might be
@@ -67,6 +67,14 @@ Options
*-n, \--nocolor*::
Disable color output.
+*-U, \--uefi* 'filename'::
+ Generate a UEFI executable as 'filename'. If a CPIO image is successfully
+ built, it will be used to generate a UEFI executable stub image for UEFI
+ booting. This combines the initramfs, the kernel, any specified microcode
+ and the kernel cmdline into one executable. This is useful for boot chain
+ integrity where the file is signed. Default: no.
+ For a list of relevant options see 'Options for UEFi executable' below.
+
*-P, \--allpresets*::
Process all presets contained in '/etc/mkinitcpio.d'. See the '-p' option for
more detail about presets.
@@ -103,6 +111,34 @@ Options
*-z, \--compress* 'compress'::
Override the compression method with the 'compress' program.
+Options for UEFi executable
+---------------------------
+
+*--cmdline* 'config'::
+ Use kernel cmdline with UEFI executable. If none is specified it will
+ try find one of the files '/etc/kernel/cmdline', '/usr/share/kernel/cmdline'
+ or '/proc/cmdline'.
+
+*--splash* 'filename'::
+ UEFI executables can show a bitmap file on boot.
+
+*--uefistub* 'filename'::
+ UEFI stub image used for UEFI executable generation.
+ Default: Attempts to look for a systemd-boot or gummiboot
+ stub loader.
+
+*--kernelimage* 'filename'::
+ Include a kernel image for the UEFI executable. Default: one of
+ '/lib/modules/$KERNELVERSION/vmlinuz', '/boot/vmlinuz-$KERNELVERSION', or
+ '/boot/vmlinuz-linux'.
+
+*--microcode* 'filename'::
+ Include microcode into the UEFI executable. Default: no.
+
+*--osrelease* 'filename'::
+ Include a os-release file for the UEFI executable.
+ Default: '/etc/os-release' or '/usr/lib/os-release'.
+
About Presets
-------------
A preset is a pre-defined definition on how to create an initial ramdisk.
@@ -349,6 +385,15 @@ Examples
Create an initial ramdisk for the kernel at /boot/vmlinuz-linux. The
resulting image will be written to /boot/initramfs-linux.img.
+*mkinitcpio -U /efi/EFI/Linux/systemd-linux.efi*::
+ Create an initial ramdisk for the kernel along with a UEFI executable.
+ The resuling executable will be written to /efi/EFI/Linux/systemd-linux.efi.
+
+*mkinitcpio -U /efi/EFI/Linux/systemd-linux.efi --microcode /boot/intel-ucode.img --splash /usr/share/systemd/bootctl/splash-arch.bmp*::
+ Create an initial ramdisk for the kernel and an UEFI executable. This
+ also includes the Intel CPU microcode and a splash image which will be
+ used during boot.
+
See also
--------
A more thorough article on configuring mkinitcpio:
diff --git a/mkinitcpio b/mkinitcpio
index 1f6a499b..692c7554 100755
--- a/mkinitcpio
+++ b/mkinitcpio
@@ -22,6 +22,8 @@ _d_presets=mkinitcpio.d
# options and runtime data
_optmoduleroot= _optgenimg=
_optcompress= _opttargetdir=
+_optosrelease=
+_optuefi= _optmicrocode=() _optcmdline= _optsplash= _optkernelimage= _optuefistub=
_optshowautomods=0 _optsavetree=0 _optshowmods=0
_optquiet=1 _optcolor=1
_optskiphooks=() _optaddhooks=() _hooks=() _optpreset=()
@@ -58,11 +60,20 @@ usage: ${0##*/} [options]
-s, --save Save build directory. (default: no)
-d, --generatedir
Write generated image into
-t, --builddir Use DIR as the temporary build directory
- -D, --hookdir Specify where to look for hooks.
+ -D, --hookdir Specify where to look for hooks
+ -U, --uefi Build an UEFI executable
-V, --version Display version information and exit
-v, --verbose Verbose output (default: no)
-z, --compress Use an alternate compressor on the image
+ Options for UEFI executable (-U, --uefi):
+ --cmdline Set kernel line (default content: /etc/kernel/cmdline, /proc/cmdline)
+ --microcode Location of microcode
+ --osrelease Include os-release (default: /etc/os-release)
+ --splash Include bitmap splash
+ --kernelimage Kernel image
+ --uefistub Location of UEFI stub loader
+
EOF
}
@@ -251,6 +262,92 @@ build_image() {
fi
}
+build_uefi(){
+ local out=$1 initramfs=$2 cmdline=$3 osrelease=$4 splash=$5 kernelimg=$6 uefistub=$7 microcode=(${@:7}) errmsg=
+ OBJCOPYARGS=()
+
+ msg "Creating UEFI executable: %s" "$out"
+
+ if [[ -z "$uefistub" ]]; then
+ for stub in {/usr,}/lib/{systemd/boot/efi,gummiboot}/linux{x64,ia32}.efi.stub; do
+ if [[ -f "$stub" ]]; then
+ uefistub="$stub"
+ msg2 "Using UEFI stub: %s" "$uefistub"
+ break
+ fi
+ done
+ elif [[ ! -f "$uefisub" ]]; then
+ error "UEFI stub '%s' not found" "$uefistub"
+ return 1
+ fi
+
+ if [[ -z "$kernelimg" ]]; then
+ for img in "/lib/modules/$KERNELVERSION/vmlinuz" "/boot/vmlinuz-$KERNELVERSION" "/boot/vmlinuz-linux"; do
+ if [[ -f "$img" ]]; then
+ kernelimg="$img"
+ msg2 "Using kernel image: %s" "$kernelimg"
+ break
+ fi
+ done
+ fi
+ if [[ ! -f "$kernelimg" ]]; then
+ error "Kernel image '%s' not found" "$kernelimage"
+ return 1
+ fi
+
+ if [[ -z "$cmdline" ]]; then
+ if [[ -f "/etc/kernel/cmdline" ]]; then
+ cmdline="/etc/kernel/cmdline"
+ elif [[ -f "/usr/lib/kernel/cmdline" ]]; then
+ cmdline="/usr/lib/kernel/cmdline"
+ else
+ warning "Note: /etc/kernel/cmdline does not exist and --cmdline is unset!"
+ cmdline="/proc/cmdline"
+ warning "Reusing current kernel cmdline from $cmdline"
+ fi
+ msg2 "Using cmdline file %s" "$cmdline"
+ fi
+ if [[ ! -f "$cmdline" ]]; then
+ error "Kernel cmdline file '%s' not found" "$cmdline"
+ return 1
+ fi
+
+ if [[ -z "$osrelease" ]]; then
+ if [[ -f "/etc/os-release" ]]; then
+ osrelease="/etc/os-release"
+ elif [[ -f "/usr/lib/os-release" ]]; then
+ osrelease="/usr/lib/os-release"
+ fi
+ msg2 "Using os-release file %s" "$osrelease"
+ fi
+ if [[ ! -f "$osrelease" ]]; then
+ error "os-release file '%s' not found" "$osrelease"
+ return 1
+ fi
+
+ if [[ -z "$initramfs" ]]; then
+ error "Initramfs '%s' not found" "$initramfs"
+ return 1
+ fi
+
+ if [[ -n "$splash" ]]; then
+ OBJCOPYARGS+=(--add-section .splash="$splash" --change-section-vma .splash=0x40000)
+ fi
+ objcopy \
+ --add-section .osrel="$osrelease" --change-section-vma .osrel=0x20000 \
+ --add-section .cmdline=<(grep '^[^#]' "$cmdline" | tr -s '\n' ' ') --change-section-vma .cmdline=0x30000 \
+ --add-section .linux="$kernelimg" --change-section-vma .linux=0x2000000 \
+ --add-section .initrd=<(cat ${microcode[@]} "$initramfs") --change-section-vma .initrd=0x3000000 \
+ ${OBJCOPYARGS[@]} "$uefistub" "$out"
+
+ status=$?
+ if (( $status )) ; then
+ error "UEFI executable generation FAILED"
+ else
+ msg "UEFI executable generation successful"
+ fi
+}
+
process_preset() (
local preset=$1 preset_image= preset_options=
local -a preset_mkopts preset_cmd
@@ -307,6 +404,17 @@ process_preset() (
preset_cmd+=(${!preset_options}) # intentional word splitting
fi
+ preset_efi_image=${p}_efi_image
+ if [[ ${!preset_efi_image:-$ALL_efi_image} ]]; then
+ preset_cmd+=(-U "${!preset_efi_image:-$ALL_efi_image}")
+ fi
+
+ preset_microcode=${p}_microcode[@]
+ if [[ ${!preset_microcode:-$ALL_microcode} ]]; then
+ for mc in "${!preset_microcode:-${ALL_microcode[@]}}"; do
+ preset_cmd+=(-m "$mc")
+ done
+ fi
msg2 "${preset_cmd[*]}"
MKINITCPIO_PROCESS_PRESET=1 "$0" "${preset_cmd[@]}"
(( $? )) && ret=1
@@ -345,10 +453,11 @@ preload_builtin_modules() {
trap 'cleanup 130' INT
trap 'cleanup 143' TERM
-_opt_short='A:c:D:g:H:hk:nLMPp:r:S:sd:t:Vvz:'
+_opt_short='A:c:D:g:H:hk:nLMPp:r:S:sd:t:U:Vvz:'
_opt_long=('add:' 'addhooks:' 'config:' 'generate:' 'hookdir': 'hookhelp:' 'help'
'kernel:' 'listhooks' 'automods' 'moduleroot:' 'nocolor' 'allpresets'
- 'preset:' 'skiphooks:' 'save' 'generatedir:' 'builddir:' 'version' 'verbose' 'compress:')
+ 'preset:' 'skiphooks:' 'save' 'generatedir:' 'builddir:' 'version' 'verbose' 'compress:'
+ 'uefi:' 'microcode:' 'splash:' 'kernelimage:' 'uefistub:')
parseopts "$_opt_short" "${_opt_long[@]}" -- "$@" || exit 1
set -- "${OPTRET[@]}"
@@ -367,6 +476,10 @@ while :; do
shift
_f_config=$1
;;
+ --cmdline)
+ shift
+ _optcmdline=$1
+ ;;
-k|--kernel)
shift
KERNELVERSION=$1
@@ -400,6 +513,13 @@ while :; do
-n|--nocolor)
_optcolor=0
;;
+ -U|--uefi)
+ shift
+ [[ -d $1 ]] && die "Invalid image path -- must not be a directory"
+ if ! _optuefi=$(readlink -f "$1") || [[ ! -e ${_optuefi%/*} ]]; then
+ die "Unable to write to path: \`%s'" "$1"
+ fi
+ ;;
-v|--verbose)
_optquiet=0
;;
@@ -418,13 +538,35 @@ while :; do
hook_list
exit 0
;;
+ --splash)
+ shift
+ [[ -f $1 ]] || die "Invalid file -- must be a file"
+ _optsplash=$1
+ ;;
+ --kernelimage)
+ shift
+ _optkernelimage=$1
+ ;;
+ --uefistub)
+ shift
+ _optkernelimage=$1
+ ;;
-M|--automods)
_optshowautomods=1
;;
+ --microcode)
+ shift
+ _optmicrocode+=($1)
+ ;;
-P|--allpresets)
_optpreset=("$_d_presets"/*.preset)
[[ -e ${_optpreset[0]} ]] || die "No presets found in $_d_presets"
;;
+ --osrelease)
+ shift
+ [[ ! -f $1 ]] && die "Invalid file -- must be a file"
+ _optosrelease=$1
+ ;;
-t|--builddir)
shift
export TMPDIR=$1
@@ -459,6 +601,14 @@ if [[ -n $_d_flag_hooks && -n $_d_flag_install ]]; then
_d_install=${_d_flag_install%:}
fi
+
+# If we specified --uefi but no -g we want to create a temporary initramfs which will be used with the efi executable.
+if [[ $_optuefi && $_optgenimg == "" ]]; then
+ tmpfile=$(mktemp -t mkinitcpio.XXXXXX)
+ trap "rm $tmpfile" EXIT
+ _optgenimg="$tmpfile"
+fi
+
# insist that /proc and /dev be mounted (important for chroots)
# NOTE: avoid using mountpoint for this -- look for the paths that we actually
# use in mkinitcpio. Avoids issues like FS#26344.
@@ -556,6 +706,10 @@ else
msg "Dry run complete, use -g IMAGE to generate a real image"
fi
+if [[ $_optuefi && $_optgenimg ]]; then
+ build_uefi "$_optuefi" "$_optgenimg" "$_optcmdline" "$_optosrelease" "$_optsplash" "$_optkernelimage" "$_optuefistub" "${_optmicrocode[@]}"
+fi
+
cleanup $(( !!_builderrors ))
# vim: set ft=sh ts=4 sw=4 et:
diff --git a/mkinitcpio.d/example.preset b/mkinitcpio.d/example.preset
index a0479d22..d46a074b 100644
--- a/mkinitcpio.d/example.preset
+++ b/mkinitcpio.d/example.preset
@@ -8,6 +8,7 @@ PRESETS=('default' 'fallback')
# as the path to an kernel image.
ALL_kver='/boot/vmlinuz-linux'
ALL_config='/etc/mkinitcpio.conf'
+ALL_microcode=(/boot/*-ucode.img)
# presetname_kver - the kernel version (omit if ALL_kver should be used)
# presetname_config - the configuration file (omit if ALL_config should be used)
@@ -17,9 +18,11 @@ ALL_config='/etc/mkinitcpio.conf'
#default_kver="3.0-ARCH"
#default_config="/etc/mkinitcpio.conf"
default_image="/tmp/initramfs-linux.img"
+default_efi_image="/efi/EFI/Linux/arch-linux.efi"
default_options=""
#fallback_kver="3.0-ARCH"
#fallback_config="/etc/mkinitcpio.conf"
fallback_image="/tmp/initramfs-linux-fallback.img"
+fallback_efi_image="/efi/EFI/Linux/arch-linux-fallback.efi"
fallback_options="-S autodetect"