Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 15 Aug 2017 22:15:18 -0600
From:      Warner Losh <imp@bsdimp.com>
To:        "freebsd-arch@freebsd.org" <arch@freebsd.org>
Subject:   Re: Proposed Enhancements to the EFI booting
Message-ID:  <CANCZdfpanptPoLX1_NFATGcceXL=1jZKcdfLq2xV6b4tLKkPkw@mail.gmail.com>
In-Reply-To: <CANCZdfohX1J-c5E4BHd=YoPXj3=tx7b_fndqfFA8bv2UiWgubw@mail.gmail.com>
References:  <CANCZdfohX1J-c5E4BHd=YoPXj3=tx7b_fndqfFA8bv2UiWgubw@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, Aug 10, 2017 at 10:03 PM, Warner Losh <imp@bsdimp.com> wrote:

> Greetings,
>
> I've been circulating a document (the latest version you can find here
> https://docs.google.com/document/d/1aK9IqF-60JPEbUeSAUAkYjF2W_
> 8EnmczFs6RqCT90Jg/edit?usp=3Dsharing)
>
> I'm opening it up for general comments now. I intend to turn this into a
> full spec, including the bits in the UEFI standard that I reference by
> pointer, and move to implementation soon once any issues are resolved.
>
> Warner
>
> FreeBSD UEFI boot protocol
>
> This document outlines the enhancements to the UEFI Boot Manager Protocol=
,
> as outlined in Version 2.6 of the UEFI spec, chapter 3. It assumes that y=
ou
> are familiar with that chapter and though a comprehensive doc with our
> additions folded into it would be good, it hasn=E2=80=99t been produced.
> Current Algorithm
>
> Boot1.efi currently searches for /boot/loader.efi using a fairly
> complicated algorithm.
>
> First, we look for any ZFS pool that has a /boot/loader.efi on it,
> consistent with its boot environment settings. If we find that, we use it=
.
>
> Second, we search all of the partitions on the device that we booted
> boot1.efi off of for a UFS partition that has a /boot/loader.efi we can
> load. If we find that, we use it.
>
> Third, we search all other devices for a partition that is UFS formatted
> and has a /boot/loader.efi we can load.
>
> There=E2=80=99s some problems with this algorithm. It=E2=80=99s not possi=
ble to specify a
> partition to boot from. We boot from the first /boot/loader.efi that=E2=
=80=99s
> found, even if multiple partitions on a drive have one. Second, it=E2=80=
=99s very
> non-deterministic. The second step was added to add some determinism to t=
he
> process so if you plugged in a FreeBSD 11.0R release USB stick and
> rebooted, you would reboot to the installed system and not the USB
> installer. It doesn=E2=80=99t use the ad-hoc method for identifying which=
 FreeBSD
> partition to boot off of that we use for BIOS boots since in the UEFI
> runtime environment it=E2=80=99s tricky to get the attribute flags of a p=
artition.
> Finally, it doesn=E2=80=99t use the standard UEFI boot manager protocol.
> Proposed Algorithm
>
> First, the FreeBSD UEFI Boot Loader UUID shall be cfee69ad-a0de-47a9-93a8=
-f63106f8ae99
> (below as FreeBSD:). The UEFI defined global variable UUID
> (EFI_GLOBAL_VARIABLE) is 8BE4DF61-93CA-11d2-AA-0D-00-E0-98-03-2B-8C
> (below as UEFI:)
>
> Boot1.efi will find what to use with the following algorithm:
>
>
>    1.
>
>    If the UEFI boot manager passes an optional parameter to boot1.efi,
>    then parse it as if it were a EFI Device Path to find the next stage b=
oot
>    loader to use. If we can use that boot loader, we=E2=80=99re done. Oth=
erwise,
>    ignore it.
>    2.
>
>    Get the value of UEFI:BootCurrent. This will be a 4 digit hex number
>    XXXX. If FreeBSD:BootLoaderXXXX exists, and specifies a file we can lo=
ad,
>    use it. This is in the form of a EFI device path (binary). If it is a =
File
>    path that=E2=80=99s ZFS:yyyy, then boot from the Boot environment for =
ZFS pool
>    yyyy. If :yyyy is omitted, use the first ZFS pool you find.
>
>
It turns out that the path in EFI_LOAD_OPTIONS is really a list of paths. I
believe it would be more robust to use that fact. The list will include
boot1.efi, loader.efi and kernel. However, it could just as easily include
only loader.efi and kernel. The exact interpretation of the extra path
names is OS specific.

If you want to boot ZFS, it can be encoded as File('ZFS') or
File('ZFS:pool'). It's all OS specific.

What to do about /? How do we find it? That's easy. It is the last path in
the list that has a HD specifier (eg, the File part of the path, if
present, is ignored). This also means you could pass in
HD(<mumble1>)/File('/efi/FreeBSD/boot1.efi'),
HD(<mumble2>)/File('/boot/loader.efi'),
HD(<mumble3>)/File('/boot/kernel/kernel'), HD(<mumble4>). In that case
there's 4 partitions involved, we load different bits off each one. Or the
last 3 could be the same (and the final one wouldn't be needed). It would
also allow each phase of the loader to know where it is and find the next
thing to load.

so we don't need FreeBSD:BootLoaderXXX.


>    1.
>
>    If a ZFS pool exists with a bootable environment, boot it.
>    2.
>
>    If a partition with a known filesystem exists on the same device as
>    boot1.efi was loaded from, and it contains /boot/loader.efi, use it.
>    3.
>
>    Set FreeBSD:BootFailedXXXX to the reason for the failure and return
>    Failure to UEFI (so UEFI goes to the next item in the list)
>
>
> If FreeBSD:BootArgumentsXXXX exists, parse it like ASCII text and pass it
> to the boot  loader found in steps 1-4 above. Otherwise pass nothing.
>

It would be more in line with the standard, it seems, to pass this in with
the 'optional data'. If we had the thing being loaded interpret the data as
a list of strings. The current loader uses the first string and passes the
rest to the next loader. This would eliminate the need for
BootArgumentsXXXX.


> If the FreeBSD:Update variable is set, the rc system will update the boot
> order so that UEFI:BootCurrent is at the start of UEFI:BootOrder. This is
> currently done in /etc/rc.d/gptupdate. I propose a /etc/rc.d/efiupdate to
> do this, and to report all the BootFailedXXXX variables ala gptupdate.
>
> Discussion of points raised on IRC:
>
> FreeBSD currently implements a =E2=80=98boot once=E2=80=99 option that=E2=
=80=99s similar to
> =E2=80=98BootNext=E2=80=99 but happens only once. In UEFI, BootNext almos=
t implements this.
> The BIOS loads that option, then deletes the BootNext env variable. Unles=
s
> the OS does something the make it permanent, this is the same as FreeBSD=
=E2=80=99s
> boot once (because the order then reverts to BootOrder). I think that
> BootFailed needs to be implemented with the extra protocol outlined in st=
ep
> 5.
>
> Open Issues:
>
> Allan Jude has raised some issues about ZFS. ZFS has it=E2=80=99s own way=
 to deal
> with all this and he=E2=80=99s curious how this fits into that. EFI doesn=
=E2=80=99t know
> about ZFS, so at most we can only define what happens when boot1.efi take=
s
> over. In that case, I proposed to him that we do what we do now, and
> selection of what ZFS thing can be done either as I proposed, or via the
> zfsbootcfg process if nothing further than ZFS is specified (or
> automatically selected).
>
> How does loader.efi fit for people that load it directly?
>
> Do we want to enable / disable the automatic looking for boot locations
> separately from what to boot being explicitly specified or not? I=E2=80=
=99m leaning
> against.
>
> Can nextboot -k foo be implemented with this? My first notion is that it
> would FreeBSD:KernelXXXX to specify the kernel and FreeBSD:NextKernelXXXX
> which would load that kernel and then unset FreeBSD:NextKernelXXXX. Ditto
> for FreeBSD:KernelFlagsXXXX and FreeBSD:NextKernelFlagsXXXX. nextboot(8)
> would set all these. Maybe FreeBSD:LoaderXXXX and FreeBSD:NextLoaderXXXX
> too...
>

With the above interpretation we wouldn't need any of this. You'd just
create a new BootXXX and point BootNext at it.

I'll update the doc with these, and am open to comments on them.

Warner



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CANCZdfpanptPoLX1_NFATGcceXL=1jZKcdfLq2xV6b4tLKkPkw>