Page MenuHomeFreeBSD

loader.efi(8): document slop control, amd64 nocopy, and amd64 fault commands
ClosedPublic

Authored by kib on Sep 4 2022, 7:48 AM.
Tags
None
Referenced Files
Unknown Object (File)
Wed, Oct 2, 10:24 AM
Unknown Object (File)
Wed, Oct 2, 10:24 AM
Unknown Object (File)
Wed, Oct 2, 10:24 AM
Unknown Object (File)
Wed, Oct 2, 10:23 AM
Unknown Object (File)
Wed, Oct 2, 10:23 AM
Unknown Object (File)
Wed, Oct 2, 10:10 AM
Unknown Object (File)
Thu, Sep 19, 1:15 PM
Unknown Object (File)
Fri, Sep 13, 7:53 AM
Subscribers

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

kib requested review of this revision.Sep 4 2022, 7:48 AM

Just one small nit, otherwise LGTM.

stand/man/loader.efi.8
224

large the slop

kib marked an inline comment as done.Sep 4 2022, 4:20 PM

I have reworded the proposed diff for better readability in English; please consider adopting any or all of these changes:

.Ss Staging Slop
The kernel needs to allocate memory during very early bootstrap,
when creating kernel page tables and other data structures needed for initial operations.
Because the kernel cannot even parse the firmware tables describing available memory without allocating,
this makes bootstrapping problematic.
To solve this issue,
the kernel assumes that some memory after the staging area
.Po
where the kernel itself, together with modules and metadata, as loaded by
.Nm ,
resides
.Pc
is available for use,
without causing corruption of any firmware data.
.Pp
It is up to the loader to ensure that the staging area is larger than just the loaded kernel, modules, and metadata, by an extra
.Dq slop
amount.
By default, amd64 reserves 8MB.
The
.Ic staging_slop
command allows for tuning the slop size.
It takes a single argument, the size of the slop in bytes.
.Ss amd64 Nocopy
BIOS loaders on i386 and amd64 put the staging area starting at the physical address
.Ad 2M ,
then enables paging with identical mapping for the low
.Ad 1G .
The initial port of
.Nm
followed the same scheme for handing control to the kernel,
since it avoided modifications for the loader/kernel hand-off protocol,
and for the kernel page table bootstrap.
.Pp
This approach is incompatible with the UEFI specification,
and as a practical matter,
caused troubles on many boards,
because UEFI firmware is free to use any memory for its own needs.
Applications like
.Nm
must only use memory explicitly allocated using boot interfaces.
The original way also potentially destroyed UEFI runtime interfaces data.
.Pp
Eventually,
.Nm
and the kernel were improved to avoid this problem.
For backward bug-compatibility,
and to allow booting older kernels with newer
.Nm ,
this
.Sq nocopy
behaviour can be controlled by the loader
.Ic copy_staging
command.
It takes a single argument,
which can be one of
.Bl -tag -width disable
.It Ar disable
Force-disable copying staging area to
.Ad 2M .
.It Ar enable
Force-enable copying staging area to
.Ad 2M .
.It Ar auto
Selects the behaviour based on the kernel's capability of boostraping
from non-2M physical base.
The kernel reports this capability by exporting the symbol
.Va kernphys .
.El
.Pp
Arm64 loaders have operated in the
.Sq nocopy
mode from their inception,
so there is no
.Ic copy_staging
command on that platform.
.Ss amd64 Faults
Because it executes in x86 protected mode,
the amd64 version of
.Nm
is susceptible to CPU faults due to programmer mistakes and memory corruption.
To make debugging such faults easier, amd64
.Nm
can provide detailed reporting of the CPU state at the time of the fault.
.Pp
The
.Ic grab_faults
command installs a handler for faults directly in the IDT,
avoiding the use of the UEFI debugging interface
.Fn EFI_DEBUG_SUPPORT_PROTOCOL.RegisterExceptionCallback .
That interface is left available for advanced debuggers in the UEFI environment.
The
.Ic ungrab_faults
command tries to deinstall the fault handler, returning TSS and IDT
CPU tables to their pre-installation state.
The
.Ic fault
command produces a fault in the
.Nm
environment for testing purposes,
by executing the
.Ic ud2
processor instruction.

I love this information. Despite my extensive edits, I'm glad this is here.

stand/man/loader.efi.8
226

The kernel must parse the firmware memory map tables to know what memory it can use.
Since it must allocate memory to do this,
.Nm
ensures there's extra memory available, called
.Dq slop ,
after everything it loads
.Po
the kernel, modules and metadata
.Pc
for the kernel to bootstrap the memory allocator.

259

"originally" "eventually" "newer" and "older" are great terms to describe this problem generally.
However, let's say I have a random kernel. How do I know if it is an 'older' one that needs to be copied down to 2MB, or if it's a newer one that can tolerate being loaded anywhere? Having some rough release versions here would be quite helpful. I work on this stuff all the time, and I don't know the cutoff line.

Also, the information is all good, but I think something like the following would be better:

.Nm
will load the kernel into memory that is 2MB aligned below 1GB.
It cannot load to a fixed address because the UEFI firmware may reserve arbitrary memory for its use at runtime.
Prior to
.Fx 13.1 ,
kernels retained the old BIOS-boot protocol of loading at exactly 2MB.
Such kernels must be copied from their loaded location to 2MB prior starting them up.
The
.Ic copy_staging
command is used to enable this copying for older kernels.
It takes a single argument
.... (rest as before)

This removes some of the history, to be true, but retains the relevant bits for users to decide if they
might need this as a workaround for older kernels. I debated adding that this workaround is only for
older machines whose kernel fits between 2MB and the first memory above that that the firmware
reserves, etc, but couldn't find a good way to say that which wasn't confusing. It's more for the 'upgrade'
scenario where you've upgraded the boot loader, but want to boot the old kernel to resolve some issue
with the new.

287

Arm64 loaders have operated in the
.Sq nocopy
mode from their inception, so there is no
.Ic copy_staging
command on that platform.

Riscv, 32-bit arm and arm64 have always loaded at any 2MB aligned location, so do not provide
.Ic copy_staging .

kib marked 3 inline comments as done.Sep 5 2022, 3:00 PM
kib added inline comments.
stand/man/loader.efi.8
259

"originally" "eventually" "newer" and "older" are great terms to describe this problem generally.
However, let's say I have a random kernel. How do I know if it is an 'older' one that needs to be copied down to 2MB, or if it's a newer one that can tolerate being loaded anywhere? Having some rough release versions here would be quite helpful. I work on this stuff all the time, and I don't know the cutoff line.

There is exact information below, how to determine if the kernel supports loading at any 2MB physical, the "kernphys" symbol presence.

It's more for the 'upgrade' scenario where you've upgraded the boot loader, but want to boot the old kernel to resolve some issue with the new.

For upgrade scenario, the automation should work. My intent in providing this information was more for the cases where kernel regressed by e.g. stopping exporting the symbol for whatever reason, e.g. if stripped to aggressively. Then user at least has some clue where to start looking.

I took your text. and moved the background into a note. I still want the motivation to be present in the man page.

kib marked an inline comment as done.

imp' notes

Thanks for the updates based on my suggestions.

stand/man/loader.efi.8
259

Most people won't know to look at for kernphys symbol, even after reading this man page. They will have a system that isn't booting. While the automation should work, it is still a good idea to document when the symbol appeared in our release timeline to help less technical users that might need this workaround decide whether or not to try it, so I like that you've included it. I think the current text strikes a good balance between motivation and practical effect.

This revision is now accepted and ready to land.Sep 6 2022, 3:44 PM