Page MenuHomeFreeBSD

stand: Parse all arguments passed by UEFI
ClosedPublic

Authored by grembo on Sep 5 2022, 3:58 PM.
Tags
None
Referenced Files
Unknown Object (File)
Wed, Nov 6, 6:09 PM
Unknown Object (File)
Wed, Nov 6, 10:29 AM
Unknown Object (File)
Tue, Nov 5, 10:59 AM
Unknown Object (File)
Tue, Nov 5, 10:58 AM
Unknown Object (File)
Sat, Oct 19, 12:51 PM
Unknown Object (File)
Thu, Oct 17, 2:59 PM
Unknown Object (File)
Thu, Oct 17, 1:00 AM
Unknown Object (File)
Thu, Oct 17, 12:26 AM
Subscribers

Details

Summary

This fixed a problem for me when working with Parallels Desktop 18's UEFI.

To give some background:
Old VM consisting of three HDDs, originally using legacy gptzfsboot. Two disks zpool, one disk swap. For reasons, disks can't be modified in size and the bootloader won't fit the original boot partitions anymore. Since Parallels seems to have issues with FreeBSD 12+ legacy boot (or vice versa) I added an EFI partition on the swap disk.

Unfortunately, EFI boot wouldn't detect my root device automatically, but I could boot when setting it explicitly

set currdev=zfs:tank/root:
load boot/kernel/kernel
load boot/kernel/zfs.ko
boot

Therefore I looked for a way to be able to set this variable somewhere else. Based on the sources and some search results, modifying /efi/freebsd/loader.env sounded promising, so I did this configuration:

loader.env
rootdev=zfs:tank/root:

Unfortunately, this didn't work. After adding some debug code to loader.efi, I learned that the stat call on the file fails (even though the loader seems to look at the correct partition). Also, looking at the partition's content from within the boot loader didn't work (ls said something like / file not found). The EFI partition was formatted using FAT32, not sure if this is related or not (I didn't have time to test other formats yet).

NOTE: When setting up the partition, I used the instructions from https://wiki.freebsd.org/UEFI which recommend newfs_msdos -F 32 -c 1. When simply using newfs_msdos /dev/..., the change in loader.env actually did the trick (and I could also list files on the resulting FAT16 partition).

Next, I discovered that I can create boot loader entries in Parallels Desktop's boot menu, so I did:
Add boot optionSelect PartitionefiBOOTBOOTX64.efi and set the following fields:

Input the description: FreeBSD
Input optional data: rootdev=zfs:tank/root:

Again, this failed, even though the boot loader clearly echoed them back:

Command line arguments: rootdev=zfs:tank/root:

Looking at the code revealed that only arguments [1..argc] are parsed, which lead me to this little patch.

I don't know enough about UEFI to understand if this is correct behavior or if this is actually a bug in Parallels Desktop. In case of the latter, this patch is moot.

NOTE: This comment indicates that The rEFInd Boot Manager might be affected by this as well.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 47247
Build 44134: arc lint + arc unit

Event Timeline

grembo requested review of this revision.Sep 5 2022, 3:58 PM
grembo added a reviewer: imp.
grembo edited the summary of this revision. (Show Details)

There's no harm here. when I added this a million years ago, argv[0] was always the name of the program (eg bootx64.efi), so I assumed it was 'unix convention' and did from argv[1]...
There's really no harm in the 'typical' case.
Since the command line in uefi is weird anyway (its a binary blob in the general case), we need to do the best we can with what we're given.

This revision is now accepted and ready to land.Sep 5 2022, 7:50 PM
NOTE: When setting up the partition, I used the instructions from https://wiki.freebsd.org/UEFI which recommend newfs_msdos -F 32 -c 1. When simply using newfs_msdos /dev/..., the change in loader.env actually did the trick (and I could also list files on the resulting FAT16 partition).

Yea, usually one should only do -F 32 for partitions that are at least 1.25 * minimum size. Any smaller and there's too many buggy UEFI implementations that have heartburn...
These days with 4k sectors, the minimum is 4k x 65527 = 268MB, which means anything smaller than about 300-350MB will be more portable to more UEFI implementations as FAT16. Some guides go so far as to suggest doing FAT16 for < 500MB. However, it's hard to be categorical... We've run into at least one UEFI BIOS that only did FAT32 and the spec seems to suggest that only FAT32 is required. So your milage may vary, though there's a possibility there might be one or more bugs in stand/libsa/dosfs.c (which is what ls would use inside of loader.efi, for example). If you have a reproducible formula, I'll chase that down.

This revision was automatically updated to reflect the committed changes.
In D36457#827888, @imp wrote:
NOTE: When setting up the partition, I used the instructions from https://wiki.freebsd.org/UEFI which recommend newfs_msdos -F 32 -c 1. When simply using newfs_msdos /dev/..., the change in loader.env actually did the trick (and I could also list files on the resulting FAT16 partition).

Yea, usually one should only do -F 32 for partitions that are at least 1.25 * minimum size. Any smaller and there's too many buggy UEFI implementations that have heartburn...
These days with 4k sectors, the minimum is 4k x 65527 = 268MB, which means anything smaller than about 300-350MB will be more portable to more UEFI implementations as FAT16. Some guides go so far as to suggest doing FAT16 for < 500MB. However, it's hard to be categorical... We've run into at least one UEFI BIOS that only did FAT32 and the spec seems to suggest that only FAT32 is required. So your milage may vary, though there's a possibility there might be one or more bugs in stand/libsa/dosfs.c (which is what ls would use inside of loader.efi, for example). If you have a reproducible formula, I'll chase that down.

I tried to reproduce the problem in a fresh VM, but I failed to do so. I reproduced *most* of what the original one looked like (but not all). I wasn't in the mood for messing with the original (as I actually need it at the moment). I played with various settings (partition size, newfs_msdos parameters, use an old gpart label that's not 4k aligned, 4k align it on such a label, modern label, first disk, second disk, third disk, have partitions with gaps etc.) no luck. Maybe the fs was somehow corrupted, even though I could mount/unmount it just fine between attempts.

So definitely nothing that's easy to reproduce it seems.

So definitely nothing that's easy to reproduce it seems.

OK. That's both good and bad. Good that not everybody will hit it, bad that some will and we don't know who / how :(. If you manage to find a way to reproduce it, please let me know.

In D36457#828154, @imp wrote:

So definitely nothing that's easy to reproduce it seems.

OK. That's both good and bad. Good that not everybody will hit it, bad that some will and we don't know who / how :(. If you manage to find a way to reproduce it, please let me know.

I couldn't let this go and managed to reproduce it reliably. The original machine used a FirstUsableLBA of 34, once I copied that on a fresh machine (the virtual SSD would start at 40, so I simply dd'ed over the old gpart label), the problem occurred and I was able to track it down (learning more about FAT than I ever wanted).

In the end, the issue was quite trivial (as it is so many times), see D36482.