diskimage-builder/diskimage_builder/elements/bootloader/finalise.d/50-bootloader
Pierre Crégut 6e71bd4239 Makes EFI images bootable by bios
For Bios and EFI compatibility, grub must be installed twice.
This patch adds the bios version when EFI is selected. The GPT EFI  block partitioning
already adds the bios partition, but the bootloader only called grub once.

Change-Id: Iee6c8b3b97b3cfff4562bcb30a50800f5ade894a
Closes-Bug: #1889089
2020-08-18 14:41:21 +10:00

247 lines
8.9 KiB
Bash
Executable File

#!/bin/bash
# Configure grub. Note that the various conditionals here are to handle
# different distributions gracefully.
if [ ${DIB_DEBUG_TRACE:-1} -gt 0 ]; then
set -x
fi
set -eu
set -o pipefail
BOOT_DEV=$IMAGE_BLOCK_DEVICE
# All available devices, handy for some bootloaders...
declare -A DEVICES
eval DEVICES=( $IMAGE_BLOCK_DEVICES )
function install_extlinux {
install-packages -m bootloader extlinux
echo "Installing Extlinux..."
# Find and install mbr.bin
for MBR in /usr/share/syslinux/mbr.bin /usr/lib/syslinux/mbr.bin \
/usr/lib/extlinux/mbr.bin /usr/lib/EXTLINUX/mbr.bin ; do
if [ -f $MBR ]; then
break
fi
done
if [ ! -f $MBR ]; then
echo "mbr.bin (from EXT/SYSLINUX) not found."
exit 1
fi
dd if=$MBR of=$BOOT_DEV
# Find any pre-created extlinux install directory
for EXTDIR in /boot/extlinux /boot/syslinux ; do
if [ -d $EXTDIR ] ; then
break
fi
done
if [ ! -d $EXTDIR ] ; then
# No install directory found so default to /boot/syslinux
EXTDIR=/boot/syslinux
mkdir -p $EXTDIR
fi
# Finally install extlinux
extlinux --install $EXTDIR
}
function install_grub2 {
# Check for offline installation of grub
if [ -f "/tmp/grub/install" ] ; then
source /tmp/grub/install
# Right now we can't use pkg-map to branch by arch, so tag an
# architecture specific virtual package so we can install the
# rigth thing based on distribution.
elif [[ "$ARCH" =~ "ppc" ]]; then
install-packages -m bootloader grub-ppc64
elif [[ "${DIB_BLOCK_DEVICE}" == "mbr" ||
"${DIB_BLOCK_DEVICE}" == "gpt" ]]; then
install-packages -m bootloader grub-pc
elif [[ "${DIB_BLOCK_DEVICE}" == "efi" ]]; then
install-packages -m bootloader grub-efi-$ARCH
else
echo "Failure: I'm not sure what bootloader to install"
echo "Ensure you have included a block-device-* element"
exit 1
fi
# XXX: grub-probe on the nbd0/loop0 device returns nothing - workaround, manually
# specify modules. https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1073731
GRUBNAME=$(type -p grub-install) || echo "trying grub2-install"
if [ -z "$GRUBNAME" ]; then
GRUBNAME=$(type -p grub2-install)
fi
# If no GRUB2 is found, fallback to extlinux
if [ -z "$GRUBNAME" ] || [ $($GRUBNAME --version | grep "0.97" | wc -l) -ne 0 ]; then
echo "No GRUB2 found. Fallback to Extlinux..."
install_extlinux
exit 0
fi
echo "Installing GRUB2..."
# We need --force so grub does not fail due to being installed on the
# root partition of a block device.
GRUB_OPTS=${GRUB_OPTS:-"--force"}
# XXX: This is buggy:
# - --target=i386-pc is invalid for non-i386/amd64 architectures
# - and for UEFI too.
# GRUB_OPTS="$GRUB_OPTS --target=i386-pc"
if [[ ! $GRUB_OPTS == *--target* ]] && [[ $($GRUBNAME --version) =~ ' 2.' ]]; then
# /sys/ comes from the host machine. If the host machine is using EFI
# but the image being built doesn't have EFI boot-images installed we
# should set the --target to use a BIOS-based boot-image.
#
# * --target tells grub what's the target platform
# * the boot images are placed in /usr/lib/grub/<cpu>-<platform>
# * i386-pc is used for BIOS-based machines
# http://www.gnu.org/software/grub/manual/grub.html#Installation
#
if [ -d /sys/firmware/efi ]; then
if [ ! -d /usr/lib/grub/*-efi ]; then
case $ARCH in
"x86_64"|"amd64")
GRUB_OPTS="$GRUB_OPTS --target=i386-pc"
;;
"i386")
target=i386-pc
if [ -e /proc/device-tree ]; then
for x in /proc/device-tree/*; do
if [ -e "$x" ]; then
target="i386-ieee1275"
fi
done
fi
GRUB_OPTS="$GRUB_OPTS --target=$target"
;;
esac
fi
fi
fi
if [[ "$ARCH" =~ "ppc" ]] ; then
# For PPC (64-Bit regardless of Endian-ness), we use the "boot"
# partition as the one to point grub-install to, not the loopback
# device. ppc has a dedicated PReP boot partition.
# For grub2 < 2.02~beta3 this needs to be a /dev/mapper/... node after
# that a dev/loopXpN node will work fine.
$GRUBNAME --modules="part_msdos" $GRUB_OPTS ${DEVICES[boot]} --no-nvram
else
# This set of modules is sufficient for all installs (mbr/gpt/efi)
modules="part_msdos part_gpt lvm"
extra_options=""
if [[ ${DIB_BLOCK_DEVICE} == "mbr" || ${DIB_BLOCK_DEVICE} == "gpt" ]]; then
modules="$modules biosdisk"
elif [[ ${DIB_BLOCK_DEVICE} == "efi" ]]; then
# This tells the EFI install to put the EFI binaries into
# the generic /BOOT directory and avoids trying to update
# nvram settings.
extra_options="--removable"
# We need to manually set the target if it's different to
# the host. Setup for EFI
case $ARCH in
"x86_64"|"amd64")
GRUB_OPTS="--target=x86_64-efi"
# This call installs grub for BIOS compatability
# which makes portable EFI/BIOS images.
$GRUBNAME --modules="$modules" --target=i386-pc $BOOT_DEV
;;
# At this point, we don't need to override the target
# for any other architectures.
esac
fi
$GRUBNAME --modules="$modules" $extra_options $GRUB_OPTS $BOOT_DEV
fi
# This might be better factored out into a per-distro 'install-bootblock'
# helper.
if [ -d /boot/grub2 ]; then
GRUB_CFG=/boot/grub2/grub.cfg
elif [ -d /boot/grub ]; then
GRUB_CFG=/boot/grub/grub.cfg
fi
# Override the root device to the default label, and disable uuid
# lookup.
echo "GRUB_DEVICE=LABEL=${DIB_ROOT_LABEL}" >> /etc/default/grub
echo 'GRUB_DISABLE_LINUX_UUID=true' >> /etc/default/grub
echo "GRUB_TIMEOUT=${DIB_GRUB_TIMEOUT:-5}" >>/etc/default/grub
echo 'GRUB_TERMINAL="serial console"' >>/etc/default/grub
echo 'GRUB_GFXPAYLOAD_LINUX=auto' >>/etc/default/grub
if [[ -n "${DIB_BOOTLOADER_SERIAL_CONSOLE}" ]]; then
SERIAL_CONSOLE="${DIB_BOOTLOADER_SERIAL_CONSOLE}"
elif [[ "powerpc ppc64 ppc64le" =~ "$ARCH" ]]; then
# Serial console on Power is hvc0
SERIAL_CONSOLE="hvc0"
elif [[ "arm64" =~ "$ARCH" ]]; then
SERIAL_CONSOLE="ttyAMA0,115200"
else
SERIAL_CONSOLE="ttyS0,115200"
fi
GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=${SERIAL_CONSOLE} no_timer_check"
echo "GRUB_CMDLINE_LINUX_DEFAULT=\"${GRUB_CMDLINE_LINUX_DEFAULT} ${DIB_BOOTLOADER_DEFAULT_CMDLINE}\"" >>/etc/default/grub
echo 'GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"' >>/etc/default/grub
if type grub2-mkconfig >/dev/null; then
GRUB_MKCONFIG="grub2-mkconfig -o $GRUB_CFG"
else
GRUB_MKCONFIG="grub-mkconfig -o $GRUB_CFG"
fi
# os-prober leaks /dev/sda into config file in dual-boot host
# Disable grub-os-prober to avoid the issue while running
# grub-mkconfig
# Setting a flag to track whether the entry is already there in grub config
PROBER_DISABLED=
if ! grep -qe "^\s*GRUB_DISABLE_OS_PROBER=true" /etc/default/grub; then
PROBER_DISABLED=true
echo 'GRUB_DISABLE_OS_PROBER=true' >> /etc/default/grub
fi
$GRUB_MKCONFIG
# Remove the fix to disable os_prober
if [ -n "$PROBER_DISABLED" ]; then
sed -i '$d' /etc/default/grub
fi
# grub-mkconfig generates a config with the device in it,
# This shouldn't be needed, but old code has bugs
DIB_RELEASE=${DIB_RELEASE:-}
if [ "$DIB_RELEASE" = 'wheezy' ]; then
sed -i "s%search --no.*%%" $GRUB_CFG
sed -i "s%set root=.*%set root=(hd0,1)%" $GRUB_CFG
fi
# Fix efi specific instructions in grub config file
if [ -d /sys/firmware/efi ]; then
sed -i 's%\(initrd\|linux\)efi /boot%\1 /boot%g' $GRUB_CFG
fi
# when using efi, and having linux16/initrd16, it needs to be replaced
# by linuxefi/initrdefi. When building images on a non-efi system,
# the 16 suffix is added to linux/initrd entries, but we need it to be
# linuxefi/initrdefi for the image to boot under efi
if [[ ${DIB_BLOCK_DEVICE} == "efi" ]]; then
sed -i 's%\(linux\|initrd\)16 /boot%\1efi /boot%g' $GRUB_CFG
fi
}
DIB_EXTLINUX=${DIB_EXTLINUX:-0}
if [ "$DIB_EXTLINUX" != "0" ]; then
install_extlinux
else
install_grub2
fi