#!/usr/bin/env bash
function extension_prepare_config__prepare_grub_standard() {
declare -g DISTRO_GENERIC_KERNEL=${DISTRO_GENERIC_KERNEL:-no}
declare -g UEFI_GRUB_TERMINAL="${UEFI_GRUB_TERMINAL:-"serial console"}"
declare -g UEFI_GRUB_DISABLE_OS_PROBER="${UEFI_GRUB_DISABLE_OS_PROBER:-}"
declare -g UEFI_GRUB_DISTRO_NAME="${UEFI_GRUB_DISTRO_NAME:-Armbian}"
declare -g UEFI_GRUB_TIMEOUT=${UEFI_GRUB_TIMEOUT:-0}
declare -g GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_DEFAULT:-}"
declare -g UEFI_ENABLE_BIOS_AMD64="${UEFI_ENABLE_BIOS_AMD64:-yes}"
declare -g UEFI_EXPORT_KERNEL_INITRD="${UEFI_EXPORT_KERNEL_INITRD:-no}"
declare -a packages=()
if [[ "${UEFI_GRUB}" != "skip" ]]; then
declare -g BOOTCONFIG="none"
unset BOOTSOURCE
declare -g IMAGE_PARTITION_TABLE="gpt"
declare -g UEFISIZE=260
declare -g BOOTSIZE=0
if [[ $BOOTPART_REQUIRED == "yes" ]]; then
declare -g UEFI_MOUNT_POINT=/boot
fi
declare -g EXTRA_BSP_NAME="${EXTRA_BSP_NAME}-grub"
declare -g UEFI_GRUB_TARGET_BIOS=""
packages+=(efibootmgr efivar cloud-initramfs-growroot busybox)
packages+=(os-prober "grub-efi-${ARCH}-bin")
if [[ "${ARCH}" == "amd64" ]]; then
declare -g UEFI_GRUB_TARGET="x86_64-efi"
if [[ "${UEFI_ENABLE_BIOS_AMD64}" == "yes" ]]; then
packages+=(grub-pc-bin grub-pc)
declare -g UEFI_GRUB_TARGET_BIOS="i386-pc"
declare -g BIOSSIZE=4
else
packages+=("grub-efi-${ARCH}")
fi
else
packages+=("grub-efi-${ARCH}")
fi
if [[ "${ARCH}" == "arm64" ]]; then
declare -g UEFI_GRUB_TARGET="arm64-efi"
elif [[ "${ARCH}" == "loong64" ]]; then
declare -g UEFI_GRUB_TARGET="loongarch64-efi"
fi
fi
if [[ "${DISTRIBUTION}" == "Ubuntu" ]]; then
DISTRO_KERNEL_VER="generic"
DISTRO_KERNEL_PACKAGES="linux-image-generic"
DISTRO_FIRMWARE_PACKAGES="linux-firmware"
elif [[ "${DISTRIBUTION}" == "Debian" ]]; then
DISTRO_KERNEL_VER="${ARCH}"
DISTRO_KERNEL_PACKAGES="linux-image-${ARCH}"
DISTRO_FIRMWARE_PACKAGES="firmware-linux-free"
fi
if [[ "${DISTRO_GENERIC_KERNEL}" == "yes" ]]; then
declare -g IMAGE_INSTALLED_KERNEL_VERSION="${DISTRO_KERNEL_VER}"
declare -g KERNELSOURCE='none'
declare -g INSTALL_ARMBIAN_FIRMWARE=no
else
declare -g KERNELDIR="linux-uefi-${LINUXFAMILY}"
DISTRO_KERNEL_PACKAGES=""
DISTRO_FIRMWARE_PACKAGES=""
fi
add_packages_to_image ${DISTRO_FIRMWARE_PACKAGES} ${DISTRO_KERNEL_PACKAGES} "${packages[@]}"
display_alert "Extension: ${EXTENSION}: ${UEFI_GRUB} activating" "GRUB with SERIALCON=${SERIALCON}; timeout ${UEFI_GRUB_TIMEOUT}; BIOS=${UEFI_GRUB_TARGET_BIOS}" ""
}
function post_family_tweaks_bsp__remove_uboot_grub() {
if [[ "${UEFI_GRUB}" == "skip" ]]; then
display_alert "Extension: ${EXTENSION}: Skipping remove uboot from BSP" "due to UEFI_GRUB:${UEFI_GRUB}" "debug"
return 0
fi
display_alert "Removing uboot from BSP" "${EXTENSION}" "info"
pushd "${destination}" || exit_with_error "cray-cray about destination: ${destination}"
run_host_command_logged find "." -type f "|" grep -e "uboot" -e "u-boot" "|" xargs rm -v
popd
}
function pre_umount_final_image__remove_uboot_initramfs_hook_grub() {
if [[ "${UEFI_GRUB}" == "skip" ]]; then
display_alert "Extension: ${EXTENSION}: Skipping GRUB install" "due to UEFI_GRUB:${UEFI_GRUB}" "debug"
return 0
fi
[[ -f "$MOUNT"/etc/initramfs/post-update.d/99-uboot ]] && rm -v "$MOUNT"/etc/initramfs/post-update.d/99-uboot
return 0
}
pre_umount_final_image__install_grub() {
if [[ "${UEFI_GRUB}" == "skip" ]]; then
display_alert "Extension: ${EXTENSION}: Skipping GRUB install" "due to UEFI_GRUB:${UEFI_GRUB}" "debug"
if [[ "${DISTRO_GENERIC_KERNEL}" == "yes" ]]; then
display_alert "Extension: ${EXTENSION}: Skipping GRUB install" "due to UEFI_GRUB:${UEFI_GRUB} - calling update_initramfs directly with IMAGE_INSTALLED_KERNEL_VERSION=${DISTRO_KERNEL_VER}" "debug"
IMAGE_INSTALLED_KERNEL_VERSION="${DISTRO_KERNEL_VER}" update_initramfs "${MOUNT}"
fi
return 0
fi
configure_grub
local chroot_target="${MOUNT}"
display_alert "Extension: ${EXTENSION}: Installing bootloader" "GRUB" "info"
rm -rf "${MOUNT}"/boot/dtb* || true
call_extension_method "grub_early_config" <<- 'GRUB_EARLY_CONFIG'
Allow for early GRUB configuration.
This is called after `configure_grub`, and zapping /boot/dtb*.
chroot ($MOUNT) is *not* mounted yet.
GRUB_EARLY_CONFIG
cat <<- grubCfgFragHostSide >> "${MOUNT}"/etc/default/grub.d/99-armbian-host-side.cfg
GRUB_DISABLE_OS_PROBER=true
grubCfgFragHostSide
mkdir -p "${MOUNT}"/usr/share/images/grub/
cp "${SRC}"/packages/blobs/splash/grub.png "${MOUNT}"/usr/share/images/grub/wallpaper.png
if [[ "${DISTRO_GENERIC_KERNEL}" == "yes" ]]; then
display_alert "Extension: ${EXTENSION}: Using Distro Generic Kernel" "${EXTENSION}: update_initramfs with IMAGE_INSTALLED_KERNEL_VERSION: ${DISTRO_KERNEL_VER}" "debug"
IMAGE_INSTALLED_KERNEL_VERSION="${DISTRO_KERNEL_VER}" update_initramfs "${MOUNT}"
fi
mount_chroot "$chroot_target/"
call_extension_method "grub_pre_install" <<- 'GRUB_PRE_INSTALL'
Last-minute hook for GRUB tweaks before actually installing GRUB and running update-grub.
The chroot ($MOUNT) is mounted.
GRUB_PRE_INSTALL
deploy_qemu_binary_to_chroot "$chroot_target" "grub"
if [[ "${UEFI_GRUB_TARGET_BIOS}" != "" ]]; then
display_alert "Extension: ${EXTENSION}: Installing GRUB BIOS..." "${UEFI_GRUB_TARGET_BIOS} device ${LOOP}" ""
chroot_custom "$chroot_target" grub-install --target=${UEFI_GRUB_TARGET_BIOS} "${LOOP}" || {
exit_with_error "${install_grub_cmdline} failed!"
}
fi
local install_grub_cmdline="grub-install --target=${UEFI_GRUB_TARGET} --efi-directory=${UEFI_MOUNT_POINT} --no-nvram --removable"
display_alert "Extension: ${EXTENSION}: Installing GRUB EFI..." "${UEFI_GRUB_TARGET}" ""
chroot_custom "$chroot_target" "$install_grub_cmdline" || {
exit_with_error "${install_grub_cmdline} failed!"
}
chroot_custom "$chroot_target" mkdir -pv '/dev/disk/by-uuid/"$(grub-probe --target=fs_uuid /)"' "||" true
chroot_custom "$chroot_target" mkdir -pv '/dev/disk/by-uuid/"$(grub-probe --target=fs_uuid /boot)"' "||" true
display_alert "Extension: ${EXTENSION}: Creating GRUB config..." "grub-mkconfig" ""
chroot_custom "$chroot_target" update-grub || {
display_alert "GRUB grub-mkconfig failed" "update-grub failed; dumping full config" "err"
declare -a mkconfig_input_files=()
mkconfig_input_files+=("${MOUNT}/etc/default/grub")
mkconfig_input_files+=("${MOUNT}/etc/default/grub.d/"*)
mkconfig_input_files+=("${MOUNT}/etc/grub.d/"*)
run_tool_batcat "${mkconfig_input_files[@]}"
exit_with_error "update-grub failed!"
}
call_extension_method "grub_late_config" <<- 'GRUB_LATE_CONFIG'
Allow for late GRUB configuration.
This is called after grub-install and update-grub.
chroot ($MOUNT) is mounted. sanity checks are going to be performed.
GRUB_LATE_CONFIG
declare -i has_failed_sanity_check=0
if grep -q '/dev' "${chroot_target}/boot/grub/grub.cfg"; then
display_alert "GRUB sanity check failed" "grub.cfg contains /dev" "err"
SHOW_LOG=yes run_host_command_logged grep '/dev' "${chroot_target}/boot/grub/grub.cfg" "||" true
has_failed_sanity_check=1
else
display_alert "Extension: ${EXTENSION}: GRUB config sanity check passed" "no '/dev' found in grub.cfg" "info"
fi
if ! grep -q 'initrd.img' "${chroot_target}/boot/grub/grub.cfg"; then
display_alert "GRUB config sanity check failed" "no initrd.img references found in /boot/grub/grub.cfg" "err"
has_failed_sanity_check=1
else
display_alert "Extension: ${EXTENSION}: GRUB config sanity check passed" "initrd.img references found OK in /boot/grub/grub.cfg" "debug"
fi
if [[ ${has_failed_sanity_check} -gt 0 ]]; then
exit_with_error "Extension: ${EXTENSION}: GRUB config sanity check failed, image will be unbootable; see above errors"
fi
if [[ "${UEFI_GRUB_TERMINAL}" =~ "gfxterm" ]]; then
if ! grep -q "background_image" "${chroot_target}/boot/grub/grub.cfg"; then
display_alert "Extension: ${EXTENSION}: GRUB mkconfig problem" "no wallpaper detected in generated grub.cfg" "warn"
else
display_alert "Extension: ${EXTENSION}: GRUB config sanity check passed" "wallpaper setup" "debug"
fi
else
display_alert "Extension: ${EXTENSION}: GRUB config sanity check passed" "UEFI_GRUB_TERMINAL!=gfxterm, skipping wallpaper check" "debug"
fi
rm -f "${MOUNT}"/etc/default/grub.d/99-armbian-host-side.cfg
undeploy_qemu_binary_from_chroot "$chroot_target" "grub"
umount_chroot "$chroot_target/"
}
pre_umount_final_image__900_export_kernel_and_initramfs() {
if [[ "${UEFI_EXPORT_KERNEL_INITRD}" == "yes" ]]; then
display_alert "Extension: ${EXTENSION}: Exporting Kernel and Initrd for" "kexec" "info"
run_host_command_logged ls -la "${MOUNT}"/boot/vmlinuz-* "${MOUNT}"/boot/initrd.img-* || true
run_host_command_logged cp -pv "${MOUNT}"/boot/vmlinuz-* "${DESTIMG}/${version}.kernel"
run_host_command_logged cp -pv "${MOUNT}"/boot/initrd.img-* "${DESTIMG}/${version}.initrd"
fi
}
configure_grub() {
display_alert "Extension: ${EXTENSION}: Configuring GRUB" "UEFI GRUB; SERIALCON=${SERIALCON}" "info"
if [[ "${SERIALCON}" != "tty1" && "${SERIALCON}" != "tty0" ]]; then
GRUB_CMDLINE_LINUX_DEFAULT+=" console=tty0"
fi
[[ -n "$SERIALCON" ]] &&
GRUB_CMDLINE_LINUX_DEFAULT+=" console=${SERIALCON}"
GRUB_CMDLINE_LINUX_DEFAULT+=" splash plymouth.ignore-serial-consoles i915.force_probe=*"
if [[ "${VENDOR}" == Armbian ]]; then
display_alert "Extension: ${EXTENSION}: Enabling" "Armbian Wallpaper on GRUB" "info"
mkdir -p "${MOUNT}"/usr/share/desktop-base/
cat <<- grubWallpaper >> "${MOUNT}"/usr/share/desktop-base/grub_background.sh
WALLPAPER=/usr/share/images/grub/wallpaper.png
COLOR_NORMAL=white/black
COLOR_HIGHLIGHT=black/white
grubWallpaper
run_host_command_logged chmod -v +x "${MOUNT}"/usr/share/desktop-base/grub_background.sh
fi
display_alert "Extension: ${EXTENSION}: GRUB EFI kernel cmdline" "cmdline '${GRUB_CMDLINE_LINUX_DEFAULT}' distro=${UEFI_GRUB_DISTRO_NAME} timeout=${UEFI_GRUB_TIMEOUT}" ""
cat <<- grubCfgFrag >> "${MOUNT}"/etc/default/grub.d/98-armbian.cfg
GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_DEFAULT}"
GRUB_TIMEOUT_STYLE=menu # Show the menu with Kernel options (Armbian or -generic)...
GRUB_TIMEOUT=${UEFI_GRUB_TIMEOUT} # ... for ${UEFI_GRUB_TIMEOUT} seconds, then boot the Armbian default.
GRUB_DISTRIBUTOR="${UEFI_GRUB_DISTRO_NAME}" # On GRUB menu will show up as "Armbian GNU/Linux" (will show up in some UEFI BIOS boot menu (F8?) as "armbian", not on others)
GRUB_BACKGROUND="/usr/share/images/grub/wallpaper.png" # Armbian GRUB wallpaper. 05_debian_theme gives GRUB_BACKGROUND precedence over the WALLPAPER sourced from /usr/share/desktop-base/grub_background.sh, so the Armbian image wins even on Debian desktop images where desktop-base ships (and overwrites) that file to point at its own theme wallpaper (Trixie: ceratopsian). Ubuntu already showed the Armbian image; this makes it deterministic on both.
GRUB_DISABLE_SUBMENU=y # Do not put all kernel options into a submenu, instead, list them all on the main menu.
GRUB_DISABLE_OS_PROBER=false # Have to be explicit about enabling os-prober
GRUB_FONT="/usr/share/grub/unicode.pf2" # Be explicit about the font to use so Ubuntu does not freak out and mess gfxterm
GRUB_GFXPAYLOAD_LINUX=text # Note the correct var name is GRUB_GFXPAYLOAD_LINUX, not GRUB_GFXPAYLOAD (the latter is silently ignored). The 'text' value disables Ubuntu's vt.handoff=7 injection: Ubuntu's grub2 10_linux only expands 'vt.handoff=7' inside grub.cfg's gfxmode function when the gfxpayload arg is exactly 'keep'. Setting it to 'text' makes the runtime check fail and the framebuffer console stays bound to fbcon for the entire userspace lifetime — which is what we want, otherwise after Plymouth quits on a CLI install (or after the user uninstalls the desktop), the kernel hands the framebuffer to VT7 waiting for an X server, nothing ever claims it, and the local console goes black even though getty@tty1 is running.
GRUB_DISABLE_UUID=false # Be explicit about wanting UUID
GRUB_DISABLE_LINUX_UUID=false # Be explicit about wanting UUID
grubCfgFrag
if [[ "a${UEFI_GRUB_DISABLE_OS_PROBER}" != "a" ]]; then
cat <<- grubCfgFragHostSide >> "${MOUNT}"/etc/default/grub.d/98-armbian.cfg
GRUB_DISABLE_OS_PROBER=${UEFI_GRUB_DISABLE_OS_PROBER}
grubCfgFragHostSide
fi
if [[ "a${UEFI_GRUB_TERMINAL}" != "a" ]]; then
cat <<- grubCfgFragTerminal >> "${MOUNT}"/etc/default/grub.d/98-armbian.cfg
GRUB_TERMINAL="${UEFI_GRUB_TERMINAL}"
grubCfgFragTerminal
fi
}