Some devices (e.g. Intel Sticks 1st gen, and others) has 32bit EFI, which requires a 32bit efi shell. We build it within the build service. See https://github.com/Sabayon/sbi-tasks/blob/master/static/grub-efi32bit.yaml
235 lines
8.1 KiB
Bash
Executable File
235 lines
8.1 KiB
Bash
Executable File
#!/bin/bash
|
|
# Expected env variables:
|
|
# CHROOT_DIR
|
|
# CDROOT_DIR
|
|
|
|
# This scripts generates an EFI-enabled boot structure
|
|
|
|
# Path to molecules.git dir
|
|
SABAYON_MOLECULE_HOME="${SABAYON_MOLECULE_HOME:-/sabayon}"
|
|
export SABAYON_MOLECULE_HOME
|
|
|
|
MOUNT_DIRS=()
|
|
TEMP_FILES=()
|
|
EFI_BOOT_DIR="${CDROOT_DIR}/efi/boot"
|
|
GRUB_BOOT_DIR_PREFIX="/boot/grub"
|
|
GRUB_LOCALE_DIR_PREFIX="${GRUB_BOOT_DIR_PREFIX}/locale"
|
|
GRUB_BOOT_DIR="${CDROOT_DIR}${GRUB_BOOT_DIR_PREFIX}"
|
|
GRUB_LOCALE_DIR="${CDROOT_DIR}${GRUB_LOCALE_DIR_PREFIX}"
|
|
mkdir -p "${EFI_BOOT_DIR}" || exit 1
|
|
mkdir -p "${GRUB_BOOT_DIR}" || exit 1
|
|
mkdir -p "${GRUB_LOCALE_DIR}" || exit 1
|
|
|
|
x86_64_EFI_DIR_PREFIX="/usr/lib/grub/x86_64-efi"
|
|
i386_EFI_DIR_PREFIX="/usr/lib/grub/i386-efi"
|
|
x86_64_EFI_DIR="${CHROOT_DIR}${x86_64_EFI_DIR_PREFIX}"
|
|
i386_EFI_DIR="${CHROOT_DIR}${i386_EFI_DIR_PREFIX}"
|
|
|
|
# This file is used by grub to determine where's the cdroot
|
|
ts=$(date +%Y%m%d%H%M%S)
|
|
img_id="${ts}${RANDOM}"
|
|
ID_FILE_PREFIX="id."
|
|
ID_FILE="${ID_FILE_PREFIX}${img_id}.uefi"
|
|
|
|
pre_iso_signal_handler() {
|
|
for mount_dir in "${MOUNT_DIRS[@]}"; do
|
|
if [ -d "${mount_dir}" ]; then
|
|
umount -f "${mount_dir}" || \
|
|
umount -l "${mount_dir}" # best effort
|
|
rmdir "${mount_dir}"
|
|
fi
|
|
done
|
|
for temp_dir in "${TEMP_FILES[@]}"; do
|
|
rm -rf "${temp_dir}"
|
|
done
|
|
}
|
|
trap "pre_iso_signal_handler" EXIT SIGINT SIGQUIT SIGILL SIGTERM SIGHUP
|
|
|
|
create_embedded_grub_cfg() {
|
|
local embedded_cfg="${1}"
|
|
|
|
echo "" >| "${embedded_cfg}" || return 1
|
|
echo "echo Booting Sabayon" >> "${embedded_cfg}" || return 1
|
|
echo "search --file --no-floppy --set=root /${ID_FILE}" >> "${embedded_cfg}" || return 1
|
|
echo "set prefix=${GRUB_BOOT_DIR_PREFIX}" >> "${embedded_cfg}" || return 1
|
|
echo "export root" >> "${embedded_cfg}" || return 1
|
|
echo "export prefix" >> "${embedded_cfg}" || return 1
|
|
|
|
# Debug messages, useful for bug reports
|
|
echo "echo grub root = \$root" >> "${embedded_cfg}" || return 1
|
|
echo "echo grub prefix = \$prefix" >> "${embedded_cfg}" || return 1
|
|
echo "sleep 1" >> "${embedded_cfg}" || return 1
|
|
|
|
echo "normal" >> "${embedded_cfg}" || return 1
|
|
echo "" >> "${embedded_cfg}" || return 1
|
|
}
|
|
|
|
create_efi_grub_image() {
|
|
local dir_prefix="${1}"
|
|
local image_name="${2}"
|
|
local image_format="${3}"
|
|
local grub_efi_dir="${4}"
|
|
|
|
local memdisk_dir=$(TMPDIR="${CHROOT_DIR}" mktemp -d --suffix="create_efi_grub_image")
|
|
local memdisk_file=$(TMPDIR="${CHROOT_DIR}" mktemp --suffix="memdisk_image")
|
|
TEMP_FILES+=( "${memdisk_dir}" )
|
|
TEMP_FILES+=( "${memdisk_file}" )
|
|
|
|
local memdisk_boot_dir="${memdisk_dir}/${GRUB_BOOT_DIR_PREFIX}"
|
|
local memdisk_boot_dir_prefix_name="$(basename $(dirname ${GRUB_BOOT_DIR_PREFIX}))"
|
|
local embedded_cfg="${memdisk_boot_dir}/grub.cfg"
|
|
local memdisk_file_chroot_path="${memdisk_file/${CHROOT_DIR}/}"
|
|
|
|
echo "Memdisk relative path: ${memdisk_file_chroot_path}"
|
|
mkdir -p "${memdisk_boot_dir}" || return 1
|
|
|
|
create_embedded_grub_cfg "${embedded_cfg}" || return 1
|
|
|
|
( cd "${memdisk_dir}" && tar -cf - "${memdisk_boot_dir_prefix_name}" ) > "${memdisk_file}" || return 1
|
|
|
|
echo "Attempting to run grub2-mkimage inside chroot ${CHROOT_DIR}..."
|
|
|
|
chroot "${CHROOT_DIR}" grub2-mkimage \
|
|
-m "${memdisk_file_chroot_path}" \
|
|
-p "(memdisk)${GRUB_BOOT_DIR_PREFIX}" \
|
|
-d "${dir_prefix}" \
|
|
-o /"${image_name}" \
|
|
-O "${image_format}" \
|
|
-C xz \
|
|
ext2 fat udf btrfs ntfs reiserfs xfs hfsplus \
|
|
lvm ata part_msdos part_gpt part_apple \
|
|
bsd search_fs_uuid normal chain iso9660 \
|
|
configfile help loadenv reboot cat search \
|
|
memdisk tar boot linux chain echo sleep || return 1
|
|
|
|
echo "grub2-mkimage inside chroot ran successfully. Moving ${image_name} over to ${EFI_BOOT_DIR}"
|
|
mv "${CHROOT_DIR}"/"${image_name}" "${EFI_BOOT_DIR}/" || return 1
|
|
|
|
echo "Copying ${grub_efi_dir} to ${GRUB_BOOT_DIR}..."
|
|
cp -Rp "${grub_efi_dir}" "${GRUB_BOOT_DIR}/" || return 1
|
|
|
|
# cleanup
|
|
rm -rf "${memdisk_dir}" "${memdisk_file}"
|
|
|
|
return 0
|
|
}
|
|
|
|
if [ -d "${x86_64_EFI_DIR}" ]; then
|
|
echo "Creating EFI grub image for x86_64..."
|
|
create_efi_grub_image "${x86_64_EFI_DIR_PREFIX}" \
|
|
"bootx64.efi" \
|
|
"x86_64-efi" \
|
|
"${x86_64_EFI_DIR}" \
|
|
|| exit 1
|
|
elif [ -d "${i386_EFI_DIR}" ]; then
|
|
echo "Creating EFI grub image for i386..."
|
|
create_efi_grub_image "${i386_EFI_DIR_PREFIX}" \
|
|
"bootia32.efi" \
|
|
"i386-efi" \
|
|
"${i386_EFI_DIR}" \
|
|
|| exit 1
|
|
fi
|
|
|
|
# These must exist.
|
|
cp "${CHROOT_DIR}/usr/share/grub/unicode.pf2" "${GRUB_BOOT_DIR}"/ || exit 1
|
|
|
|
# Copy locale files
|
|
localedir="${CHROOT_DIR}/usr/share/locale"
|
|
for dir in "${localedir}"/*; do
|
|
if [ -f "${dir}/LC_MESSAGES/grub.mo" ]; then
|
|
cp -f "${dir}/LC_MESSAGES/grub.mo" "${GRUB_LOCALE_DIR}/${dir##*/}.mo"
|
|
fi
|
|
done
|
|
|
|
# Copy splash, this is in sabayon-artwork-grub, we expect to find it
|
|
cp "${CHROOT_DIR}/usr/share/grub/default-splash.png" "${GRUB_BOOT_DIR}"/ \
|
|
|| exit 1
|
|
|
|
# now setup SecureBoot for x86_64 using shim:
|
|
# See: http://mjg59.dreamwidth.org/20303.html
|
|
efi_x86_64_file="${EFI_BOOT_DIR}"/bootx64.efi
|
|
efi_i386_file="${EFI_BOOT_DIR}"/bootia32.efi
|
|
grub_efi_file="${EFI_BOOT_DIR}"/grubx64.efi
|
|
efi_img="${GRUB_BOOT_DIR}"/efi.img
|
|
shim_dir="${SABAYON_MOLECULE_HOME}"/boot/shim-uefi-secure-boot
|
|
shim_data_dir="${CHROOT_DIR}/usr/share/shim-signed-0.2"
|
|
# This is on the ISO build server, not on the repos
|
|
sbsign_private_key="${shim_dir}"/private.key
|
|
# actually, UEFI SecureBoot needs the cert in DER
|
|
# format (sabayon.cer), while sbsign requires a
|
|
# plain old text-based x509 certificate (sabayon.crt)
|
|
sabayon_der="${shim_dir}"/sabayon.cer
|
|
sabayon_cert="${shim_dir}"/sabayon.crt
|
|
|
|
if [ -f "${efi_x86_64_file}" ] || [ -f "${efi_i386_file}" ]; then
|
|
|
|
if [ -f "${efi_x86_64_file}" ] && [ -f "${sbsign_private_key}" ]; then
|
|
mv "${efi_x86_64_file}" "${grub_efi_file}" || exit 1
|
|
cp "${shim_data_dir}"/shim.efi "${efi_x86_64_file}" || exit 1
|
|
cp "${shim_data_dir}"/MokManager.efi "${EFI_BOOT_DIR}"/ || exit 1
|
|
|
|
# Copy the Sabayon SecureBoot certificate to a nice dir
|
|
mkdir -p "${CDROOT_DIR}"/SecureBoot || exit 1
|
|
cp "${sabayon_der}" "${CDROOT_DIR}"/SecureBoot/ || exit 1
|
|
|
|
# Sign
|
|
sbsign --key "${sbsign_private_key}" --cert "${sabayon_cert}" \
|
|
--output "${grub_efi_file}.signed" \
|
|
"${grub_efi_file}" || exit 1
|
|
mv "${grub_efi_file}.signed" "${grub_efi_file}" || exit 1
|
|
elif [ ! -f "${sbsign_private_key}" ]; then
|
|
echo "No private SecureBoot key file found at ${sbsign_private_key}" >&2
|
|
fi
|
|
|
|
# -- end of SecureBoot --
|
|
# UEFI is currently only supported in x86_64
|
|
|
|
# now the tricky part, create an eltorito alternative image
|
|
# 12 floppies = 2880 x 14, we need more space for SecureBoot and GRUB2
|
|
# stuff to make isohybrid work as expected.
|
|
dd bs=512 count=$((2880 * 24)) if=/dev/zero of="${efi_img}" || exit 1
|
|
mkfs.msdos "${efi_img}" || exit 1
|
|
|
|
tmp_dir=$(TMPDIR="/var/tmp" mktemp -d --suffix="make_grub_efi")
|
|
[[ -z "${tmp_dir}" ]] && exit 1
|
|
MOUNT_DIRS+=( "${tmp_dir}" )
|
|
mount -o loop "${efi_img}" "${tmp_dir}" || exit 1
|
|
mkdir -p "${tmp_dir}/efi/boot" || exit 1
|
|
|
|
# Always add support for 32bit EFI
|
|
echo "Add EFI32bit support"
|
|
wget https://dispatcher.sabayon.org/sbi/namespace/static%3A%3Agrub-efi32bit/bootia32.efi -O ${efi_i386_file}
|
|
|
|
# copy our .efi executables in place
|
|
cp -Rp "${EFI_BOOT_DIR}"/* "${tmp_dir}/efi/boot/" || exit 1
|
|
|
|
# in order to make isohybrid work, we need to copy the grub
|
|
# stuff inside the EFI boot image
|
|
tmp_grub_dir="${tmp_dir}/boot/grub"
|
|
mkdir -p "${tmp_grub_dir}" || exit 1
|
|
|
|
# Remove any previous id file
|
|
rm -f "${CDROOT_DIR}"/"${ID_FILE_PREFIX}"*.uefi
|
|
touch "${CDROOT_DIR}/${ID_FILE}" || exit 1
|
|
|
|
## TODO: is this still needed? We actually embed grub.cfg
|
|
## into the EFI image now. Test by removing the 3 lines below
|
|
## and dding the ISO to a USB storage and try to boot it.
|
|
## copy the chainload grub.cfg version
|
|
create_embedded_grub_cfg "${tmp_grub_dir}/grub.cfg"
|
|
# copy modules, actually, we would just need search
|
|
cp -R "${GRUB_BOOT_DIR}/"*-efi "${tmp_grub_dir}/" || exit 1
|
|
|
|
mkdir -p "${tmp_grub_dir}/SecureBoot" || exit 1
|
|
cp "${sabayon_der}" "${tmp_grub_dir}/SecureBoot/" || exit 1
|
|
|
|
umount "${tmp_dir}" || exit 1
|
|
rmdir "${tmp_dir}" # best effort
|
|
exit 0
|
|
else
|
|
# images not supporting UEFI must get a fake file as efi.img
|
|
# because our mkisofs parameters are static.
|
|
dd bs=512 count=$((2880 * 1)) if=/dev/zero of="${efi_img}" || exit 1
|
|
mkfs.msdos "${efi_img}" || exit 1
|
|
fi
|