I wanted to migrate my Home Assistant Operating System (HAOS) instance from a Raspberry Pi to an old PC that was apparently older than UEFI. HAOS only supports UEFI boot however. I had read about some community efforts to install Grub for BIOS on top of HAOS. This is not too difficult to do. What seems difficult is making this configuration stable across HAOS updates so that they, first of all work at all with the A/B update mechanism, and secondly, remain working even as HAOS changes across major releases. I took a different path, which is to make the PC quack like UEFI by inserting another bootloader stage before HAOS: Clover EFI Bootloader.
Clover is primarily used to make a PC look sufficiently like a Mac so that macOS can be installed and run. macOS has many dependencies on EFI which need to be emulated by Clover. Linux in contrast is much easier to boot, so most parts of Clover are not necessary for this hack and its configuration will be comparatively simple.
I eventually succeeded in booting a mostly unmodified HAOS Generic x86-64 in UEFI mode. However, I quickly realised that my intended use-case wouldn't work, which was to use the GPU in this old box for hardware accelerated video decoding and analytics in Frigate NVR. This is because HAOS doesn't include drivers for NVIDIA GPUs. (The GPU is much newer than the motherboard.)
So I scrapped that idea for now and thus cannot say whether this method works as intended long-term across updates. The installation succeeded though so I'm putting this out there as a "how I did it", not a "how to-guide".
All the steps are done from a Linux live CD (or USB etc.). I used Debian Live but any distro containing common system utilities should work.
Boot sequence with Clover
From the Clover Manual (PDF):
BIOS→Master Boot Record→Partition/Volume Boot Record→boot
→CLOVERX64.efi
→OSLoader
where the executable code in Master Boot Record and Partition/Volume Boot Record are parts of Clover, boot
is an executable file in the EFI System Partition, also from Clover, and OSLoader is Grub for UEFI as shipped by HAOS.
Specifically, OSLoader will be /efi/boot/bootx64.efi
from the ESP on the HAOS image.
The manual is detailed but somewhat difficult to read. The ArchWiki entry on Clover gives an overview that is easier to read.
Clover requires that the EFI System Partition is FAT32 and won't accept FAT12 or FAT16.
This is allegedly UEFI specification compliant (although I find that the UEFI specification is not very firm on this point), but many UEFI implementations are apparently fine with a FAT16 ESP.
The ESP in HAOS is formatted as FAT16.
I tried it and it didn't work.
I had to reformat it as FAT32.
Unfortunately, the ESP volume is too small to be valid FAT32 according to some sources (like mkfs.fat
).
The HAOS ESP is exactly 32 MiB but the smallest valid FAT32 volume is a tad larger than 32 MiB.
How much larger depends on who you ask, and maybe which parameters are used during formatting (sectors per cluster etc.).
I guess it depends on which historic FAT32 implementations you want to be compliant with.
I haven't bothered to figure out the (most) correct answer.
What this means is that the ESP needs to be enlarged and subsequent partitions shifted over a bit. I made it 100 MiB. I didn't try formatting the ESP in-place as a 32 MiB FAT32 volume and see if Clover would accept it. If it does, then many of these steps are unnecessary. Again, this is how I did it, but if I did this again I would start by just reformatting the existing ESP.
Partitioning
I made a new GUID Partition Table with a 100 MiB ESP first and then eight more partitions corresponding to the layout on the HAOS image.
The partition layout is described in the Home Assistant Developer Docs, section Partitioning.
This was a mistake as HAOS requires at a minimum the partition unique GUID of the system partition to match the expected value from the image, as well as the filesystem label on the ESP to match.
Otherwise the HAOS boot sequence would fail at various stages due to not finding all its volumes.
I later had to fix this up using gdisk
to copy the unique GUID from each partition on the image to the corresponding partition on my target disk, as well as the partition name for good measure.
Use gdisk
command i
to "show detailed information on a partition" such as the unique GUID and partition name on the image.
Use command c
to "change a partition's name" on the target partition.
Use command x
("extra functionality (experts only)"), then command c
to "change partition GUID" on the target partition.
Use mkfs.fat -F 32
to specifically make a FAT32 filesystem on the ESP, overriding the automatic choice between FAT12/16/32 that mkfs.fat
would otherwise make.
fatlabel
can be used to change the filesystem label on the ESP FAT32 filesystem.
Clover installation
Loop mount the Clover ISO at /clover_iso
:
# mkdir /clover_iso
# mount -o loop /media/user/disk/Clover-5162-X64.iso /clover_iso
The commands from ArchWiki should generally apply, but these are the ones that I used.
Replace sdb
with the target disk, the first volume of which will be the EFI System Partition.
Install boot0 and boot1 like this:
# cd /tmp
# cp /clover_iso/usr/standalone/i386/boot0af .
# cp /clover_iso/usr/standalone/i386/boot1f32alt .
# dd if=/dev/sdb count=1 bs=512 of=origMBR
# cp origMBR newMBR
# dd if=boot0af of=newMBR bs=1 count=440 conv=notrunc
# dd if=newMBR of=/dev/sdb count=1 bs=512
# dd if=/dev/sdb1 count=1 bs=512 of=origbs
# cp boot1f32alt newbs
# dd if=origbs of=newbs skip=3 seek=3 bs=1 count=87 conv=notrunc
# dd if=newbs of=/dev/sdb1 count=1 bs=512
Then copy the required files into the ESP filesystem:
# mkdir /esp
# mount /dev/sdb1 /esp
# cp -a /clover_iso/efi/clover/ /esp/EFI/
# cp /clover_iso/usr/standalone/i386/x64/boot6 /esp/boot
Don't worry about warnings from cp
about not being able to copy metadata such as file ownership.
This is caused by using -a
on a filesystem not supporting such attributes (FAT32).
Don't copy bootx64.efi
from Clover.
This executable is only used when booting Clover from UEFI.
Which boot0
to use?
I don't think it matters too much actually.
ArchWiki suggests boot0ss
which according to the Clover manual looks for a HFS+ partition signature.
If not found it falls back to the first FAT32 partition.
I used boot0af
which checks the active partition first (I think this means the partition with the boot flag set).
If none, then it falls back to the EFI System Partition
These two variants should thus in practice both work in this case.
I think my ESP unintentionally does have the boot flag set, so the first check in boot0af
would select it.
However, even if it didn't, then it should still be selected due to being the ESP.
Which boot1
to use?
Either boot1f32
or boot1f32alt
is fine.
Both are for FAT32 volumes.
The difference is that the alt-version has a 2 second pause where it waits for user input to override which next stage to use.
HAOS installation
Loop mount partition 1 from the HAOS image and copy the entire /efi/boot
from it onto the target ESP:
# losetup --show --find /media/user/disk/haos_generic-x86-64-15.2.img
/dev/loop1
# partprobe /dev/loop1
# mkdir /haos_esp
# mount /dev/loop1p1 /haos_esp
# cp -a /haos_esp/efi/boot /esp
/efi/boot
contains the Grub UEFI executable and its configuration.
Copy HAOS partitions 2-9 onto the target disk using dd
or whatever.
Configuring Clover
Clover will be configured to boot Grub without showing a menu. You may wish to pause here, reboot and verify that Clover with its default configuration starts and shows a GUI. If it does, HAOS Grub can be manually started by entering a UEFI shell and typing:
fs0:
cd efi\boot
bootx64.efi
If instead there is a blinking cursor and no more progress, that is a sign that the pre-loader "boot" cannot be found.
This happened to me when the ESP was formatted as FAT16.
The boot
file was there, but the stage 1 bootloader (in the Partition Boot Record) probably couldn't read the filesystem at all.
If successful then reboot into the live CD, mount the target ESP at /haos_esp
and continue.
Or skip the previous part and continue without testing if feeling lucky.
Replace the contents of /haos_esp/efi/clover/config.plist
with the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Boot</key>
<dict>
<key>DefaultVolume</key>
<string>hassos-boot</string>
<key>DefaultLoader</key>
<string>\efi\BOOT\bootx64.efi</string>
<key>Fast</key>
<true/>
</dict>
<key>GUI</key>
<dict>
<key>Custom</key>
<dict>
<key>Entries</key>
<array>
<dict>
<key>Hidden</key>
<false/>
<key>Disabled</key>
<false/>
<key>Volume</key>
<string>hassos-boot</string>
<key>Path</key>
<string>\efi\BOOT\bootx64.efi</string>
<key>Title</key>
<string>HAOS</string>
<key>Type</key>
<string>Linux</string>
</dict>
</array>
</dict>
</dict>
</dict>
</plist>
This is from the ArchWiki entry on Clover, section chainload systemd-boot, lightly edited.
Explanations:
- DefaultVolume and Volume identify the ESP volume, either based on its GUID or name. Not sure if name refers to the partition name or filesystem label. In the HAOS image they are the same, so best keep it that way.
- DefaultLoader and Path are the path to the EFI executable from the root of DefaultVolume/Volume respectively.
- Fast is the option that disables the Clover GUI.
- I don't know what Type (Linux) is used for, or if the false options actually need to be set as such.
Unmounting and rebooting
I always carefully unmount anything I mount on a live CD before rebooting. Generally, do the opposite steps in the opposite order compared to when setting up:
# umount /haos_esp
# umount /esp
# umount /clover_iso
# losetup -d /dev/loop1
After a reboot with the configuration from the previous section Clover should automatically boot HAOS Grub without showing a GUI.
Hardware details
Probably not of interest to anyone, but in case it is the old PC has these specs:
- Asus P7P55 LX
- Intel Core i5-760
- GeForce 960