UEFI and MBR bootable
I took the external drive, where I had installed opensuse 13.1 in UEFI mode, and decided to try to make it also bootable in MBR mode. In principle, that would allow the drive to be bootable on both newer UEFI boxes and older MBR based boxes.
This post describes what I did and how it turned out.
I’ll note that this is mostly an exercise to see what is possible. I don’t have any actual need for it.
My basic plan was to use Yast bootloader settings to switch from “grub2-efi” (used on UEFI systems), to plain “grub2” (used with legacy MBR based booting). There is not a lot of overlap in the files used by these boot loaders, so this plan should work provided that switching to “grub2” does not delete the files needed for “grub2-efi” to work. Most of the files for “grub2-efi” are stored in either the EFI partition (mounted as “/boot/efi”), or are in the directory “/boot/grub2/x86_64-efi”. The files for plain “grub2” are in the directory “/boot/grub2/i386-pc”, with some additional code in either the MBR of the disk or in the partition boot record. Additionally, “grub2” might install some code in the space between the MBR and the first partition.
For those not familiar with the term, the MBR (or main boot record) is the first physical sector on the hard drive, and contains the traditional partition table. For use on UEFI, it is normal to instead use GPT partitioning, which leaves a dummy MBR available, and known as the protective MBR.
Booting the external drive
I chose to boot the external drive on an older MBR box. I already had opensuse installed on the internal drive, so I modified the boot menu of that to boot the external drive. I could not directly boot, since at this stage the external drive was set for UEFI booting only.
There are two alternatives to this. I could have just booted it on my UEFI box. If I had told Yast to switch to grub2, it probably would have complained that grub2 was not appropriate. But it would have gone ahead and made the switch anyway. Alternatively, I could have gone to rescue mode, booting a live CD and mounting the partitions from the external drive on “/mnt”. And then I could have installed grub2 in rescue mode (see my post on rescuing).
Where to install grub2?
Before attempting to install, I had to decide where to install. I could either install on the MBR or on one of the partitions. However, both of those have problems. Traditional MBR booting assumes a traditional MBR partitioned disk. But this disk had GPT partitioning. To install in a partition, I would need a hybrid partitioning scheme where one of the partitions is listed in both the GPT partition table and the protective MBR. The “gdisk” command can setup such hybrid partitioning. You need only identify which partition is to be listed in both partition tables.
Installing grub2 in the MBR raises a different issue. In a typical MBR partitioning scheme, there is unassigned and unusable space between the MBR and the first partition. And grub2 puts some code there. On a GPT partitioned disk, that space is usable. The grub2 software can cope with that, by using a special boot partition, called a BIOS boot partition. The special partition can fit in the space before the first standard partition, usually starting at sector 34.
I chose to go with installing in the MBR. So I created that BIOS boot partition, using the “gdisk” command. Here’s the resulting partition table:
# gdisk -l /dev/sdb GPT fdisk (gdisk) version 0.8.7 Partition table scan: MBR: protective BSD: not present APM: not present GPT: present Found valid GPT with protective MBR; using GPT. Disk /dev/sdb: 156301488 sectors, 74.5 GiB Logical sector size: 512 bytes Disk identifier (GUID): 50D37558-962E-42F6-A846-9414ECC0F510 Partition table holds up to 128 entries First usable sector is 34, last usable sector is 156301454 Partitions will be aligned on 2-sector boundaries Total free space is 143 sectors (71.5 KiB) Number Start (sector) End (sector) Size Code Name 1 2048 321535 156.0 MiB EF00 primary 2 321536 4530175 2.0 GiB 8200 primary 3 4530176 46475263 20.0 GiB 8300 primary 4 46475264 156301311 52.4 GiB 8300 primary 5 34 2047 1007.0 KiB EF02 BIOS boot partition
With that in place, I was ready to proceed with the grub2 install.
Next, I started Yast –> System –> Boot Loader
On the first screen, I made sure that “Boot from Master Boot Record” was the only box checked.
Next, I clicked on “Boot Loader Installation Details” toward the bottom of the screen. That listed two disks. I made sure that the external drive came first in that list. That is necessary, since that’s the MBR on which I wanted grub2 to be installed.
Finally, I clicked the OK button, and grub2 was installed. A quick check showed that the important files for grub2-efi were still there.
The next step was to attempt to boot the external drive in MBR mode, and then in UEFI mode. I first tested MBR mode on my older non-UEFI box. And that worked fine.
At this stage, I did not test on my UEFI box. I expect that it would have worked, but only if I had disabled secure-boot.
Configuring for secure-boot
To be used with secure-boot, the “grub.cfg” needs to use a “linuxefi” command instead of a “linux” command, and it needs to append an “initrdefi” command rather than an “initrd” command. However, that would be incompatible with MBR booting requirements.
This is fairly easy to fix. I simply created an alternative “grub.cfg” file, which I named “grub.altcfg”. I edited that to use “linuxefi” and “initrdefi” on the appropriate lines.
Next, I moved to the directory “/boot/efi/EFI/Boot” which is where the UEFI booting starts out. There’s a small “grub.cfg” file there. It contained the line:
which I promptly changed to read
I was now set for testing a UEFI boot. And that worked as expected.
Whenever “grub.cfg” (in the directory “/boot/grub2”) is updated, I will now need to regenerate “grub2.altcfg”. I wrote a small “sed” script for that purpose.
/^[ ]*linux[ ]/s/linux/linuxefi/ /^[ ]*initrd[ ]/s/initrd/initrdefi/
Note that those brackets contain a space followed by a tab character (the tab does not show on the blog).
So now, I just run
# cd /boot/grub2 # sed -f /usr/local/lib/grubefi.sed grub.cfg > grub.altcfg
whenever “grub.cfg” needs updating. And it will need updating after any kernel update.