heads/initrd/bin/kexec-boot
Jonathon Hall af5eb2edf9
Blob jail: Make device firmware available during initrd
Some device firmware, such as the graphics microcontroller, is needed
during the initrd - i915 is often loaded in the initrd, and this is the
only chance to load GuC firmware.

Device firmware must still be available after the real root is mounted
too, so update the custom firmware path in the kernel when the firmware
is moved to /run.

Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2023-09-29 15:36:31 -04:00

180 lines
4.2 KiB
Bash
Executable File

#!/bin/bash
# Launches kexec from saved configuration entries
set -e -o pipefail
. /tmp/config
. /etc/functions
TRACE "Under /bin/kexec-boot"
dryrun="n"
printfiles="n"
printinitrd="n"
while getopts "b:e:r:a:o:fi" arg; do
case $arg in
b) bootdir="$OPTARG" ;;
e) entry="$OPTARG" ;;
r) cmdremove="$OPTARG" ;;
a) cmdadd="$OPTARG" ;;
o) override_initrd="$OPTARG" ;;
f) dryrun="y"; printfiles="y" ;;
i) dryrun="y"; printinitrd="y" ;;
esac
done
if [ -z "$bootdir" -o -z "$entry" ]; then
die "Usage: $0 -b /boot -e 'kexec params|...|...'"
fi
bootdir="${bootdir%%/}"
kexectype=`echo $entry | cut -d\| -f2`
kexecparams=`echo $entry | cut -d\| -f3- | tr '|' '\n'`
kexeccmd="kexec"
cmdadd="$CONFIG_BOOT_KERNEL_ADD $cmdadd"
cmdremove="$CONFIG_BOOT_KERNEL_REMOVE $cmdremove"
if [ "$(load_config_value CONFIG_USE_BLOB_JAIL)" = "y" ]; then
cmdadd="$cmdadd firmware_class.path=/firmware/"
fi
fix_file_path() {
if [ "$printfiles" = "y" ]; then
# output file relative to local boot directory
echo ".$firstval"
fi
filepath="$bootdir$firstval"
if ! [ -r $filepath ]; then
die "Failed to find file $firstval"
fi
}
adjusted_cmd_line="n"
adjust_cmd_line() {
if [ -n "$cmdremove" ]; then
for i in $cmdremove; do
cmdline=$(echo $cmdline | sed "s/\b$i\b//g")
done
fi
if [ -n "$cmdadd" ]; then
cmdline="$cmdline $cmdadd"
fi
adjusted_cmd_line="y"
}
if [ "$CONFIG_DEBUG_OUTPUT" = "y" ];then
#If expecting debug output, have kexec load (-l) output debug info
kexeccmd="$kexeccmd -d"
fi
module_number="1"
while read line
do
key=`echo $line | cut -d\ -f1`
firstval=`echo $line | cut -d\ -f2`
restval=`echo $line | cut -d\ -f3-`
if [ "$key" = "kernel" ]; then
fix_file_path
if [ "$kexectype" = "xen" ]; then
# always use xen with custom arguments
kexeccmd="$kexeccmd -l $filepath"
kexeccmd="$kexeccmd --command-line \"$restval no-real-mode reboot=no vga=current\""
elif [ "$kexectype" = "multiboot" ]; then
kexeccmd="$kexeccmd -l $filepath"
kexeccmd="$kexeccmd --command-line \"$restval\""
elif [ "$kexectype" = "elf" ]; then
DEBUG "kexectype= $kexectype"
DEBUG "restval= $restval"
DEBUG "filepath= $filepath"
kexeccmd="$kexeccmd -l $filepath"
DEBUG "kexeccmd= $kexeccmd"
else
DEBUG "unknown kexectype!!!!"
kexeccmd="$kexeccmd -l $filepath"
fi
fi
if [ "$key" = "module" ]; then
fix_file_path
cmdline="$restval"
if [ "$kexectype" = "xen" ]; then
if [ "$module_number" -eq 1 ]; then
adjust_cmd_line
elif [ "$module_number" -eq 2 ]; then
if [ "$printinitrd" = "y" ]; then
# output the current path to initrd
echo $filepath
fi
if [ -n "$override_initrd" ]; then
filepath="$override_initrd"
fi
fi
fi
module_number=`expr $module_number + 1`
kexeccmd="$kexeccmd --module \"$filepath $cmdline\""
fi
if [ "$key" = "initrd" ]; then
fix_file_path
if [ "$printinitrd" = "y" ]; then
# output the current path to initrd
echo $filepath
fi
if [ -n "$override_initrd" ]; then
filepath="$override_initrd"
fi
firmware_initrd="$(inject_firmware.sh "$filepath" || true)"
if [ -n "$firmware_initrd" ]; then
filepath="$firmware_initrd"
fi
kexeccmd="$kexeccmd --initrd=$filepath"
fi
if [ "$key" = "append" ]; then
cmdline="$firstval $restval"
adjust_cmd_line
kexeccmd="$kexeccmd --append=\"$cmdline\""
fi
done << EOF
$kexecparams
EOF
if [ "$adjusted_cmd_line" = "n" ]; then
if [ "$kexectype" = "elf" ]; then
kexeccmd="$kexeccmd --append=\"$cmdadd\""
else
die "Failed to add required kernel commands: $cmdadd"
fi
fi
if [ "$dryrun" = "y" ]; then exit 0; fi
echo "Loading the new kernel:"
echo "$kexeccmd"
eval "$kexeccmd" \
|| die "Failed to load the new kernel"
if [ "$CONFIG_DEBUG_OUTPUT" = "y" ];then
#Repeat kexec command that will be executed since in debug
DEBUG "kexeccmd= $kexeccmd"
#Ask user if they want to continue booting without echoing back the input (-s)
read -s -n 1 -p "[DEBUG] Continue booting? [Y/n]: " debug_boot_confirm
echo
if [ "${debug_boot_confirm^^}" = N ]; then
# abort
die "Boot aborted"
fi
fi
if [ "$CONFIG_TPM" = "y" ]; then
tpmr kexec_finalize
fi
if [ -x /bin/io386 -a "$CONFIG_FINALIZE_PLATFORM_LOCKING_PRESKYLAKE" = "y" ]; then
lock_chip
fi
echo "Starting the new kernel"
exec kexec -e