From Mageia wiki
Jump to: navigation, search

Creating a Master Grub2 boot loader in UEFI

It is not a good idea to rely on one operating system's boot loader to control booting of multiple systems. The disadvantages are many - the major one being that failure of the controlling system can break booting of all systems. Also the grub2 menu entry created in one system may not offer particular kernel parameters that the system's own boot loader does.

The following approach uses an independent small (20MB) partition with it's own installation of grub2. This boots first and then chain-loads into the boot loader of whichever system is to be launched.

This small partition is never automatically mounted by any of the systems on the machine, and as such is very unlikely to be damaged during system updates etc.

Each system only modifies it's own boot loader during kernel updates etc. and there is no interaction at all between different systems on the machine.

If new systems are added to the machine this script may be run again and will probably find them. Note that any hand edited additions should be made in a separate master-grub/grub2/custom.cfg which will not be overwritten when the script is re-run. One backup of the master-grub/boot/grub2/grub.cfg is kept as grub.cfg~.

When installing a new system make sure it does not write to the ESP (In Mageia 6 and onwards there is an advanced option for this in the installer summary bootloader section) then reboot into an existing Mageia install and re-run the script. On reboot the newly installed system should be available to boot from the master menu.

To simplify initial setup the following script will do all that is needed except create the required small partition. It assumes that it is being run on a default Mageia >= 5 UEFI installation with os-prober installed.

OK, so you decided it sounds like a good idea? Then read all of the following before doing anything.

Instructions

  • In a UEFI Mageia >= 5 system go to: MCC -> Local Disks -> Manage Disk Partitions (Click Continue in the warning dialog to accept that you could do damage in here!) Find some free space and create a small ext2 partition of around 20MB (the initial install will use about 7MB). Format the partition and label it (using the Expert mode) as "master-grub".
  • In your home folder create a text file named mkmastergrub2.
  • Copy/Paste the complete script below into the file using a text editor and save the file.
  • In a terminal in the same folder do:
chmod +x mkmastergrub2
  • Assuming everything above has been done correctly then do:
su
./mkmastergrub2

That's it!

If it fails or you have any comments then I would love to hear from you to improve/debug this tool. Please note any error messages. It should auto-create entries for most linux distributions and Windows. Other systems are probably best added later by hand into custom.cfg rather than grub.cfg. Enjoy!

One final note. At present (Sept 2015) when the grub2 package is updated in Mageia 5, the boot order will be changed to put that system first rather than your 'master'. https://bugs.mageia.org/show_bug.cgi?id=15583 To work around this issue you can edit /boot/grub2/install.sh in Mageia5 to read:

grub2-install --bootloader-id=tmp --no-nvram
 

This bug is fixed in Mageia >= 6.

The script:

#!/bin/bash
# mkmastergrub2

################################################################
# Note: Currently only for UEFI mode.
#
# This script creates a basic Master grub2 install to chainload  
# into any systems on a machine.
# Further menu entries may be added manually to master-grub's 
# custom.cfg at any time.
# A small (20MB) ext2 (native linux) partition labelled 
# "master-grub" must be prepared and formatted before running
#  this script.
# Run as root:
# ./mkmastergrub2
################################################################
# Changelog
# 23/06/2016 Added ability to put manually written entries in 
#            custom.cfg that will not be overwritten on re-runs
#            of script
# 05/08/2015 Added startup.nsh to work around VBox nvram bug.
#            Use correct path for *buntu installations.
# 01/12/2022 Fix name change to Master Menu in theme.txt.
################################################################

prep() {
# Check we are root
(((UID))) && { echo "You must be root to run $0"; exit 0; }
# Check it's a UEFI system
[[ -d /sys/firmware/efi ]] || { echo "Not a UEFI booted system"; exit 1; }
# Get ESP device
if ! mountpoint -q /boot/EFI; then
echo "ESP not mounted - please reboot and run again"
exit 1
else
esp=$(df -h /boot/EFI |(read; awk '{print $1; exit}'))
umount $esp || { echo "Failed to unmount ESP in prep"; exit 1; }
fi
umounts
}

umounts() {
# Unmount any existing temporary mount points
if mountpoint -q /master-grub/EFI; then
  umount /master-grub/EFI || { echo "Failed to unmount old EFI mount please reboot and run again"; exit 1; }
fi
if mountpoint -q /master-grub; then
  umount /master-grub || { echo "Failed to unmount old mount please reboot and run again"; exit 1; }
fi
}

probed() {
os-prober > probe.tmp
corepath="/boot/grub2/x86_64-efi/core.efi"
while read line; do
ostyp=$(echo $line | cut -d: -f4)
if [[ "$ostyp" = "linux" ]]; then
dev=$(echo $line | cut -d: -f1)
name=$(echo $line | cut -d: -f2 |cut -d'(' -f1)" on "$dev
uuid=$(blkid $dev -s UUID | cut -d= -f2)
if echo $name|grep -q buntu; then
corepath="/boot/grub/x86_64-efi/core.efi"
fi
echo "menuentry '$name' {"
echo "search --no-floppy --fs-uuid --set=root $uuid"
echo "chainloader $corepath"
echo "}"
echo
elif [[ "$ostyp" = "Windows" ]]; then
dev=$(echo $line | cut -d@ -f1)
name="Windows on $dev"
uuid=$(blkid $dev -s UUID | cut -d= -f2)
echo "menuentry '$name' {"
echo "search --no-floppy --fs-uuid --set=root $uuid"
echo "chainloader /EFI/Microsoft/Boot/bootmgfw.efi"
echo "}"
echo
fi
done < probe.tmp
rm -f probe.tmp
}

thisone() {
dev=$(df -h /boot |(read; awk '{print $1; exit}'))
name=$(cat /etc/os-release | grep PRETTY_NAME |cut -d= -f2|cut -d'"' -f2)
uuid=$(blkid $dev -s UUID | cut -d= -f2)
echo "menuentry '$name on $dev' {"
echo "search --no-floppy --fs-uuid --set=root $uuid"
echo "chainloader /boot/grub2/x86_64-efi/core.efi"
echo "}"
echo
}

startupnsh() {
if dmidecode|grep -q vboxVer; then
cat > /master-grub/EFI/startup.nsh <<EOF
fs0:
if not exist EFI then
fs1:
endif
cd EFI/master
grubx64.efi
EOF
fi
}

cfg_header() {
cat> /master-grub/grub2/grub.cfg<<EOF
set default="0"
set timeout=10

if loadfont unicode ; then
  set gfxmode=1024x768x32
  insmod all_video
  insmod gfxterm
  set locale_dir=$prefix/locale
  set lang=en_GB
  insmod gettext
fi
terminal_output gfxterm
insmod part_gpt
insmod ext2

# Theme
insmod gfxmenu
loadfont /grub2/themes/maggy/MageiaLogo-Bold-16.pf2
loadfont /grub2/themes/maggy/MageiaLogo-Bold-20.pf2
loadfont /grub2/themes/maggy/MageiaLogo-Bold-28.pf2
loadfont /grub2/themes/maggy/MageiaLogo-Regular-20.pf2
insmod png
set theme=/grub2/themes/maggy/theme.txt
export theme

EOF
}

cfg_footer() {
cat>> /master-grub/grub2/grub.cfg<<EOF

if [ -f  /grub2/custom.cfg ]; then
  source /grub2/custom.cfg
fi

EOF
}

cleanup() {
# Unmount ESP and master-grub
umounts
# Re-mount ESP
mount -t vfat $esp /boot/EFI || { echo "Failed to re-mount ESP in cleanup"; exit 1; }
# Delete master-grub mount point
rm -r /master-grub || { echo "Failed to delete /master-grub mount point in cleanup"; exit 1; }
}

# OK let's get started ------------------------
prep
# Create temporary mount point for master-grub partition
mkdir -p /master-grub || { echo "Failed to create master-grub mount point"; exit 1; }
# Mount master-grub partition on /master-grub
mount -L master-grub /master-grub || { echo "Failed to mount master-grub"; exit 1; }
# Create mount point for ESP on master-grub
mkdir -p /master-grub/EFI || { echo "Failed to create master-grub/EFI mount point"; exit 1; }
# Mount ESP on master-grub
mount -t vfat $esp /master-grub/EFI || { echo "Failed to mount ESP in master-grub"; exit 1; }
# Install grub2 to master-grub
grub2-install --boot-directory=/master-grub --bootloader-id=master || { echo "Failed to install grub"; exit 1; }
# Copy some files
cp -r /boot/grub2/fonts /master-grub/grub2/ || { echo "Failed to copy over fonts"; exit 1; }
cp -r /boot/grub2/themes /master-grub/grub2/ || { echo "Failed to copy over theme"; exit 1; }
# Change menu title
sed -i 's/"Mageia Boot Menu"/"Master Boot Menu"/' $(find /master-grub/grub2 -name theme.txt)
# Add startup.nsh if this is a VBox install to workaround bug that loses nvram
startupnsh
# Back up any existing grub.cfg
[[ -f /master-grub/grub2/grub.cfg ]] && mv /master-grub/grub2/grub.cfg /master-grub/grub2/grub.cfg~
# Write initial grub.cfg template to master-grub
cfg_header
# Create new top entry for current system in grub.cfg
thisone >> /master-grub/grub2/grub.cfg
# Create new probed entries for grub.cfg
probed >> /master-grub/grub2/grub.cfg
# Add custom.cfg capability
cfg_footer
# Tidy up and re-mount ESP
cleanup
echo "Install complete :)"