(UEFI) Chainloading GRUB from GRUB

There's another way: you can create a menu entry that tells GRUB to load another secondary grub.cfg, such as one from another Linux distro.

For example, I started with Gentoo Linux from which I installed GRUB2 into the MBR (the machine is too old for EFI).

I then installed NixOS, which I configured to generate grub.cfg in it's own /boot (separate from Gentoo's /boot) but without installing GRUB.

To clarify, grub-install was executed from Gentoo but not from NixOS.

Next, to be able to boot NixOS, I added this to /etc/grub.d/40_custom in Gentoo:

exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.

menuentry 'NixOS' --class gnu-linux --class gnu --class os $menuentry_id_option 'nixos-0aca58bc-8fdb-4a07-aa2f-56406bcf19b7' {
        set root='hd0,msdos4'
        configfile /nixos/root/boot/grub/grub.cfg

The key is the configfile /nixos/root/boot/grub/grub.cfg line. It tells GRUB to load another grub.cfg. I then ran grub-mkconfig from Gentoo to apply the changes.

Now, when I boot and select NixOS the entire GRUB interface refreshes to reflect the NixOS grub.cfg, from which I can boot the OS. Unlike chainloading, this configuration utilizes a single installation of GRUB; it simply uses a second configuration.

I've found out how to manually install the .efi on each of my /'s. Referring to the secondary GRUB chainloader from the primary config is simple:

menuentry "GRUB chainloader" {
 #Load grub on partition 7 of a gpt formatted drive. 
 #It will reference its own modules and config.
 chainloader (hd0,gpt7)/path/to/bootloader/on/myOS/core.efi

To create this secondary .efi I used grub-mkimage because grub-install didn't let me write to a non-FAT filesystem. The syntax is very picky and it doesn't give errors if you use a wrong path, so check the arguments carefully:

grub-mkimage -o /path/to/mounted/targetOS/efidir/core.efi --format=x86_64-efi '--prefix=(hd0,gpt7)/boot/grub' ext2 part_gpt

I tried leaving out the GPT or ext2 filesystem modules but that didn't work, those two modules were the absolute minimum requirement for my system (ext2 works for ext2/3/4).

The prefix directory is where the secondary bootloader will look for its modules folder and config file. So I have manually created a /boot/grub/ for each OS that includes a x86_64-efi/ folder (copied from /usr/lib/grub) and a grub.cfg I can modify using grub-mkconfig with OS-probing disabled (or just manually edit it).

I originally installed each OS without GRUB. This method allowed me to install secondary GRUB bootloaders on all operating systems using a first OS or LiveCD with GRUB. I can change the boot configuration of each OS independently, no risks for contamination because the ESP is never mounted.

I am trying to do a similar thing for i386-pc grub, and chainloader of the the core.img file would not work, giving "error: invalid signature"

But I had learned that the grub core.img file is multiboot compliant, so I was able to boot core.img like:

multiboot (hd0,7)/core.img

and successfully get the new grub, it's modules and initial configuration.

I suppose your chainloader command fails on an efi for a non-efi grub, so this failrue can be detected and fall-back to multiboot on core.img before the boot command.