In a past post about UEFI, I talked about the boot process: The UEFI firmware looks for a FAT32 disk volume that contains a specific file, e.g. EFI\BOOT\bootx64.efi, and it loads that file; that boot loader takes care of loading the rest of the operating system. And if you want to boot a UEFI device from a USB key, the same thing applies: Format it as FAT32, put the needed file at EFI\BOOT\bootx64.efi, and you’re set to go, nothing special is required beyond that.
But booting from a CD (or the more common case of booting a VM from an ISO, since most VMs can’t easily use a USB key) is a little more interesting. I always assumed that the UEFI firmware was smart enough to read the needed files from an ISO9660 or UDF structure on the CD/ISO itself, but working with Linux OSes over the past few days made me realize that’s not the case at all.
So let’s start off with Windows. When you want to create a bootable ISO, you do so using OSCDIMG.EXE, a tool included in the Windows ADK. The command line typically looks something like this:
oscdimg -m -o -u2 -udfver102 -bootdata:2#p0,e,bc:\winpe_x64\etfsboot.com#pEF,e,bc:\winpe_x64\efisys.bin c:\winpe_x64\ISO c:\winpe_x64\winpeuefi.iso
Let’s decipher that a bit. This says to create a UDF 1.02 format ISO image, and to include two different boot sectors. The first one (type 0) is used for non-UEFI (legacy BIOS booting); the content is in the etfsboot.com file. The second one (type EF) is used for UEFI; the content is in the efisys.bin file. OK, that etfsboot.com file is a throwback to MS-DOS days (legacy BIOS is that old), so having a little 4KB bootstrap, the equivalent of the boot sector on a hard disk, makes sense. But that efisys.bin file, or the equivalent efisys_noprompt.bin that eliminates the “press any key to boot from CD” message, is a little more mysterious.
Notice that the size of both of these files is exactly the same, 1440KB, exactly the size of a “high density” floppy disk. That’s not a coincidence, as it turns out these are actually floppy disk images. Fortunately, 7-Zip knows how to explore these disk images, so we can see inside:
Now it makes perfect sense, the UEFI firmware reads the FAT32 “floppy” from the ISO boot sector, and as with a hard disk or USB, it looks for that EFI\BOOT\BOOTX64.EFI file and executes it. If you extract the file from the image and rename it to have a “.exe” extension, you can look at the file properties:
OK, so this file was originally named “cdboot.efi” (and oddly enough, the file in the “noprompt” image has the same “cdboot.efi” original name, but a different file size — so they are close to the same, but just different enough that only one will prompt). What does this file do exactly? Well, it’s not documented, so we have to do some guessing. Looking at the output from the Sysinternals STRINGS.EXE utility shows a lot of interesting stuff, but I suspect the main task is to (eventually) load bootmgr.efi, the main Windows boot loader. That then loads the BCD, kernel, etc. Since we’re talking about installing an OS, it would be booting into Windows PE.
So that’s what happens with Windows. What about Linux? The instructions for creating a bootable ISO for a Linux installation involves similar command line options to what you use with Windows, but instead of specifying the efisys.bin image, you specify an efiboot.img file. That file is bigger than a floppy (so obviously the Windows one could be bigger too, but it doesn’t need to be), but it does have the same key EFI\BOOT\BOOTX64.EFI file:
In this case, the BOOTX64.EFI file was originally SHIM.EFI, the Linux shim bootloader (signed by Microsoft, so it can load even with Secure Boot enabled) that then loads Grub, which reads the grub.cfg (similar to a BCD) to decide what OS kernel to load.
It certainly would have been easier (and less hack-ish) to have the UEFI firmware understand how to load an operating system from an ISO9660 or UDF file system, but it certainly appears that UEFI can’t do that, hence this extra level of FAT32-ness is required.
Categories: Geeking Out