Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mkinitcpio] Create UEFI executables #53

Merged
merged 12 commits into from
Jul 7, 2021
45 changes: 44 additions & 1 deletion man/mkinitcpio.8.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,13 @@ Options
after all other hooks from the config file. Multiple hooks should be
comma-separated. This option can be specified multiple times.

*-C, \--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'. Only used along with '--uefi'.

*-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
Expand Down Expand Up @@ -59,14 +64,39 @@ Options
*-L, \--listhooks*::
List all available hooks.

*-l, \--splash* 'filename'::
UEFI executables can show a bitmap file on boot.

*-I, \--uefistub* 'filename'::
UEFI stub image used for UEFI executable generation. Only used if '--uefi'
is specified. Default: Attempts to look for a systemd-boot or gummiboot
stub loader.

*-i, \--kernelimage* 'filename'::
Include a kernel image for the UEFI executable. This is only used if
'--uefi' is specified. Default: one of
'/lib/modules/$KERNELVERSION/vmlinuz', '/boot/vmlinuz-$KERNELVERSION', or
Foxboron marked this conversation as resolved.
Show resolved Hide resolved
'/boot/vmlinuz-linux'.

*-M, \--automods*::
Display modules found via autodetection. mkinitcpio will automatically try to
determine which kernel modules are needed to start your computer. This option
lists which modules were detected.

*-m, \--microcode* 'filename'::
Include microcode into the UEFI executable. This option is only used if
'--uefi' is specified. Default: no.

*-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.

*-P, \--allpresets*::
Process all presets contained in '/etc/mkinitcpio.d'. See the '-p' option for
more detail about presets.
Expand All @@ -79,6 +109,10 @@ Options
*-r, \--moduleroot* 'root'::
Specifies the root directory to find modules in, defaulting to '/'.

*-R, \--osrelease* 'filename'::
Include a os-release file for the UEFI executable. Only used if '--uefi' is
specified. Default: '/etc/os-release' or '/usr/lib/os-release'.

*-S, \--skiphooks* 'hooks'::
Skip 'hooks' when generating the image. Multiple hooks should be comma-separated.
This option can be specified multiple times.
Expand Down Expand Up @@ -349,6 +383,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 -g /boot/initramfs-linux.img -k /boot/vmlinuz-linux --uefi /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 -g /boot/initramfs-linux.img -k /boot/vmlinuz-linux -U /efi/EFI/Linux/systemd-linux.efi -M /boot/intel-ucode.img -l /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:
Expand Down
150 changes: 147 additions & 3 deletions mkinitcpio
Original file line number Diff line number Diff line change
Expand Up @@ -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=()
Expand All @@ -44,6 +46,7 @@ usage: ${0##*/} [options]
Options:
-A, --addhooks <hooks> Add specified hooks, comma separated, to image
-c, --config <config> Use alternate config file. (default: /etc/mkinitcpio.conf)
-C, --cmdline <cmdline> Set kernel line. (default content: /etc/kernel/cmdline, /proc/cmdline)
-g, --generate <path> Generate cpio image and write to specified path
-H, --hookhelp <hookname> Display help for given hook and exit
-h, --help Display this message and exit
Expand All @@ -58,7 +61,13 @@ usage: ${0##*/} [options]
-s, --save Save build directory. (default: no)
-d, --generatedir <dir> Write generated image into <dir>
-t, --builddir <dir> Use DIR as the temporary build directory
-D, --hookdir <dir> Specify where to look for hooks.
-D, --hookdir <dir> Specify where to look for hooks
-U, --uefi <path> Build an UEFI executable
-m, --microcode <path> Location of microcode for UEFI executable
-R, --osrelease <path> Include os-release (default: /etc/os-release)
-l, --splash <path> Include bitmap splash for UEFI executable
-i, --kernelimage <path> Kernel image for UEFI executable
-I, --uefistub <path> Location of UEFI stub loader
-V, --version Display version information and exit
-v, --verbose Verbose output (default: no)
-z, --compress <program> Use an alternate compressor on the image
Expand Down Expand Up @@ -251,6 +260,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
Foxboron marked this conversation as resolved.
Show resolved Hide resolved
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"
Foxboron marked this conversation as resolved.
Show resolved Hide resolved
warning "Reusing current kernel cmdline from $cmdline"
fi
msg2 "Using cmdline file %s" "$cmdline"
fi
if [[ ! -f "$cmdline" ]]; then
Foxboron marked this conversation as resolved.
Show resolved Hide resolved
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"
Foxboron marked this conversation as resolved.
Show resolved Hide resolved

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
Expand Down Expand Up @@ -307,6 +402,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
Expand Down Expand Up @@ -345,10 +451,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:c:D:g:H:hk:I:i:nLl:Mm:Pp:R: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:')
Foxboron marked this conversation as resolved.
Show resolved Hide resolved

parseopts "$_opt_short" "${_opt_long[@]}" -- "$@" || exit 1
set -- "${OPTRET[@]}"
Expand All @@ -367,6 +474,10 @@ while :; do
shift
_f_config=$1
;;
-C|--cmdline)
shift
_optcmdline=$1
;;
-k|--kernel)
shift
KERNELVERSION=$1
Expand Down Expand Up @@ -400,6 +511,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"
Foxboron marked this conversation as resolved.
Show resolved Hide resolved
fi
;;
-v|--verbose)
_optquiet=0
;;
Expand All @@ -418,13 +536,35 @@ while :; do
hook_list
exit 0
;;
-l|--splash)
shift
[[ -f $1 ]] || die "Invalid file -- must be a file"
_optsplash=$1
;;
-i|--kernelimage)
shift
_optkernelimage=$1
;;
-I|--uefistub)
shift
_optkernelimage=$1
;;
-M|--automods)
_optshowautomods=1
;;
-m|--microcode)
shift
_optmicrocode+=($1)
;;
-P|--allpresets)
_optpreset=("$_d_presets"/*.preset)
[[ -e ${_optpreset[0]} ]] || die "No presets found in $_d_presets"
;;
-R|--osrelease)
shift
[[ ! -f $1 ]] && die "Invalid file -- must be a file"
_optosrelease=$1
;;
-t|--builddir)
shift
export TMPDIR=$1
Expand Down Expand Up @@ -556,6 +696,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:
3 changes: 3 additions & 0 deletions mkinitcpio.d/example.preset
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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"