LOADER.EFI(8)           FreeBSD System Manager's Manual          LOADER.EFI(8)

NAME

     loader.efi - UEFI kernel loader

DESCRIPTION

     On UEFI systems, loader.efi loads the kernel.

     loader.efi is invoked directly from the EFI System Partition (ESP) on
     systems installed using bsdinstall(8), when installed as the default EFI
     boot program as described in uefi(8) or when configured as an EFI boot
     entry with efibootmgr(8).

     On systems upgraded from FreeBSD 10 or earlier, the EFI System Partition
     (ESP) can be too small to accommodate loader.efi.  In such cases,
     boot1.efi(8) may be retained as the firmware boot program.  It will
     chain-load the current /boot/loader.efi, which is updated during the
     installworld process.  boot1.efi(8) is deprecated for new installations.

Console Considerations

     The UEFI firmware provides a generic console.  In loader.efi this is
     selected by specifying "efi" using the console variable.  loader.efi
     examines the 8be4df61-93ca-11d2-aa0d-00e098032b8c-ConOut UEFI environment
     variable to guess what the "efi" console points to.  loader.efi will
     output its prompts and menus to all the places specified by ConOut.
     However, the FreeBSD kernel has a limitation when more than one console
     is present.  The kernel outputs to all configured consoles.  Only the
     primary console will get the log messages from the rc(8) system, and
     prompts for things like geli(8) passwords.  If loader.efi finds a video
     device first, then loader.efi tells the kernel to use the video console
     as primary.  Likewise, if a serial device is first in the ConOut list,
     the serial port will be the primary console.

     If there is no ConOut variable, both serial and video are attempted.
     loader.efi uses the "efi" console for the video (which may or may not
     work) and "comconsole" for the serial on COM1 at the default baud rate.
     The kernel will use a dual console, with the video console primary if a
     UEFI graphics device is detected, or the serial console as primary if
     not.

     On x86 platforms, if you wish to redirect the loader's output to a serial
     port when the UEFI firmware doesn't support it, or to a serial port that
     isn't the one the UEFI firmware redirects its output to, set console to
     "comconsole".  The default port is COM1 with an I/O address of 0x3f8.
     comconsole_port is used to set this to a different port address.
     comconsole_speed is used to set the of the serial port (the default is
     9600).  If you have console set to "efi,comconsole" you will get output
     on both the EFI console and the serial port.  If this causes a doubling
     of characters, set console to "efi", since your UEFI firmware is
     redirecting to the serial port already.

     If your UEFI firmware redirects the serial port, you may need to tell the
     kernel which address to use.  EFI uses ACPI's UID to identify the serial
     port, but loader.efi does not have an ACPI parser, so it cannot convert
     that to an I/O port.  The FreeBSD kernel initializes its consoles before
     it can decode ACPI resources.  The FreeBSD kernel will look at the
     hw.uart.console variable to set its serial console.  Its format is
     described in uart(4).  Set it to "io:0x3f8,br:115200" with the proper
     port address.  PCI or memory mapped ports are beyond the scope of this
     man page.

     The serial ports are assigned as follows on IBM PC compatible systems:

           Windows Name    I/O Port Address    Typical FreeBSD device
           COM1            0x3f8               /dev/uart0
           COM2            0x2f8               /dev/uart1
           COM3            0x3e8               /dev/uart2
           COM4            0x2e8               /dev/uart3

     Though COM3 and COM4 can vary.

Primary Console

     The primary console is set using the boot flags.  These command line
     arguments set corresponding flags for the kernel.  These flags can be
     controlled by setting loader environment variables to "yes" or "no".
     Boot flags may be set on the command line to the boot command.  Inside
     the kernel, the RB_ flags are used to control behavior, sometimes in
     architecturally specific ways and are included to aid in discovery of any
     behavior not covered in this document.

           Boot Flag    Loader Variable    Kernel RB_ Flag
           -a           boot_askme         RB_ASKNAME
           -c           boot_cdrom         RB_CDROM
           -d           boot_ddb           RB_KDB
           -r           boot_dfltroot      RB_DFLTROOT
           -D           boot_multiple      RB_MULTIPLE
           -m           boot_mute          RB_MUTE
           -g           boot_gdb           RB_GDB
           -h           boot_serial        RB_SERIAL
           -p           boot_pause         RB_PAUSE
           -P           boot_probe         RB_PROBE
           -s           boot_single        RB_SINGLE
           -v           boot_verbose       RB_VERBOSE

     And the following flags determine the primary console:

           Flags    Kernel Flags               Kernel Consoles    Primary Console
           none     0                          Video              Video
           -h       RB_SERIAL                  Serial             Serial
           -D       RB_MULTIPLE                Serial, Video      Video
           -Dh      RB_SERIAL | RB_MULTIPLE    Serial, Video      Serial

     loader.efi does not implement the probe -P functionality where we use the
     video console if a keyboard is connected and a serial console otherwise.

Additional Environment Variables

     loader.efi can set variables early in startup from a file on the EFI
     partition.  By default, that file is /efi/freebsd/loader.env.  It can be
     changed by setting the FreeBSD EFI variable LoaderEnv, as in:

           echo -n /efi/freebsd/alt.env | efivar -w -t 7 \
               -n cfee69ad-a0de-47a9-93a8-f63106f8ae99-LoaderEnv

     After that is executed, the file /efi/freebsd/alt.env is used instead of
     /efi/freebsd/loader.env.  See efivar(8) for more information on setting
     EFI variables.

     The EFI variable NextLoaderEnv can be set to the pathname of a second
     startup file.  That variable is deleted immediately after its value is
     retrieved, so setting it will affect only the next boot attempt.  For
     either variable, a missing file is silently ignored.

     Only simple variables can be set in the startup file.  It can be useful
     to specify the root filesystem:

           rootdev=disk0s1a

     The startup file contains a series of assignments separated by spaces,
     tabs, or newlines.  Quotes are not given any special treatment.  If no
     =value is given, the value 1 is used.  Invalid syntax and the like are
     silently ignored.

Staging Slop

     The kernel must parse the firmware memory map tables to know what memory
     it can use.  It also needs to allocate memory for the kernel page tables.
     Since it must allocate memory to do this, without overwriting important
     structures, for instance the trampoline page table, loader.efi ensures
     there's extra memory available, called "slop", after everything it loads
     (the kernel, modules and metadata) for the kernel to bootstrap the memory
     allocator.

     By default, amd64 reserves 8MB.  The staging_slop command allows for
     tuning the slop size.  It takes a single argument, the size of the slop
     in bytes.

amd64 Nocopy

     loader.efi will load the kernel into memory that is 2MB aligned below
     4GB.  It cannot load to a fixed address because the UEFI firmware may
     reserve arbitrary memory for its use at runtime.  Prior to FreeBSD 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 copy_staging command is used to enable this
     copying for older kernels.  It takes a single argument which can be one
     of

     disable  Force-disable copying staging area to 2M.

     enable   Force-enable copying staging area to 2M.

     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 kernphys.

     Arm64 loaders have operated in the `nocopy' mode from their inception, so
     there is no copy_staging command on that platform.  Riscv, 32-bit arm and
     arm64 have always loaded at any 2MB aligned location, so do not provide
     copy_staging.

           Note.  BIOS loaders on i386 and amd64 put the staging area starting
           at the physical address 2M, then enable paging with identical
           mapping for the low 1G.  The initial port of loader.efi 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.

           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 loader.efi must only use memory explicitly allocated using
           boot interfaces.  The original way also potentially destroyed UEFI
           runtime interfaces data.

           Eventually, loader.efi and the kernel were improved to avoid this
           problem.

amd64 Faults

     Because it executes in 64-bit long mode, the amd64 version of loader.efi
     is susceptible to CPU faults due to programmer mistakes and memory
     corruption.  To make debugging such faults easier, amd64 loader.efi can
     provide detailed reporting of the CPU state at the time of the fault.

     The grab_faults command installs a handler for faults directly in the
     IDT, avoiding the use of the UEFI debugging interface
     EFI_DEBUG_SUPPORT_PROTOCOL.RegisterExceptionCallback().  That interface
     is left available for advanced debuggers in the UEFI environment.  The
     ungrab_faults command tries to deinstall the fault handler, returning TSS
     and IDT CPU tables to their pre-installation state.  The fault command
     produces a fault in the loader.efi environment for testing purposes, by
     executing the ud2 processor instruction.

i386 firmware on amd64 machines

     Some devices have 64-bit (long mode) capable CPUs, but come with a 32-bit
     (protected mode) UEFI implementation.  /boot/loader_ia32.efi is provided
     for such devices.  It switches to long mode right before executing the
     kernel.  Note that since the firmware expects its runtime EFI functions
     to be executed in 32-bit protected mode, EFI runtime services are not
     available to the kernel.  Which means that programs like efibootmgr(8)
     will not work.

FILES

     /boot/loader.efi  The location of the UEFI kernel loader within the
                       system.

EFI System Partition

     loader.efi is installed on the ESP (EFI System Partition) in one of the
     following locations:

     efi/boot/bootXXX.efi    The default location for any EFI loader (see
                             uefi(8) for values to replace `XXX' with).

     efi/freebsd/loader.efi  The location reserved specifically for the
                             FreeBSD EFI loader.

     The default location for the ESP mount point is documented in hier(7).

EXAMPLES

Updating loader.efi on the ESP

     The following example shows how to install a new loader.efi on the ESP.
     The exact placement is complicated due to the diversity of installations,
     setups and situations.  In this section, paths that are all lower case
     are Unix paths.  Paths that are all upper case are relative to the ESP
     mount point, though they may appear as lower case on your system because
     the FAT filesystem of the ESP is case insensitive.

     Locate the ESP, which has its own partition type of "efi":

           # gpart show nda0
           =>        40  7501476448  nda0  GPT  (3.5T)
                     40      614400     1  efi  (300M)
                 614440  7500862048     2  freebsd-zfs  (3.5T)

     The name of the ESP on this system is nda0p1.  By default, this will be
     mounted on /boot/efi.  To check:

           # mount | grep nda0p1
           /dev/nda0p1 on /boot/efi (msdosfs, local)

     If it's not mounted, you will need to mount it:

           # mount -t msdosfs /dev/nda0p1 /boot/efi

     efibootmgr(8) reports what we booted from.

           # efibootmgr -v
           Boot to FW : false
           BootCurrent: 0001
           Timeout    : 2 seconds
           BootOrder  : 0000, 0001, 0003, 0004, 0005, 0006, 0001, 0008, 000A, 000B, 000C, 000E, 0007
           ...
           +Boot0001* FreeBSD ZPOOL HD(1,GPT,b5d0f86b-265d-1e1b-18aa-0ed55e1e73bd,0x28,0x96000)/File(\EFI\FREEBSD\LOADER.EFI)
                                       nda0p1:/EFI/FREEBSD/LOADER.EFI /boot/efi//EFI/FREEBSD/LOADER.EFI
           ...

     Often there are several options, depending on the BIOS.  The entry that
     we booted with is marked with a `+' at the start of the line, as shown
     above.  So in this case, this firmware is using /EFI/FREEBSD/LOADER.EFI
     from the ESP.  Often times it will be the UEFI "default" loader, which
     varies by architecture.

           Architecture    Default Path
           amd64           /EFI/BOOT/BOOTX64.EFI
           arm             /EFI/BOOT/BOOTARM.EFI
           arm64           /EFI/BOOT/BOOTAA64.EFI
           i386            /EFI/BOOT/BOOTIA32.EFI
           riscv           /EFI/BOOT/BOOTRISCV64.EFI

     However, care must be taken: some multiple-boot environments rely on a
     special bootXXX.efi to function.  Before updating a bootXXX.efi file,
     make sure it is the FreeBSD boot loader before updating it:

           # strings /boot/efi/EFI/BOOT/BOOTX64.EFI | grep FreeBSD | grep EFI
           FreeBSD/amd64 EFI loader, Revision 3.0

     bsdinstall(8) copies loader.efi to the default name if there wasn't one
     there before.  Check to see if they are copies before updating (with X64
     substituted using the above table):

           # cmp /boot/efi/EFI/FREEBSD/LOADER.EFI /boot/efi/EFI/BOOT/BOOTX64.EFI

     Copy the loader:

           # cp /boot/loader.efi /boot/efi/EFI/FREEBSD/LOADER.EFI

     replacing the all caps part of the example with the proper path.

     If ESP path was /FREEBSD/LOADER.EFI and LOADER.EFI and BOOTX64.EFI were
     identical in the cmp step, copy the loader to the default location:

           # cp /boot/loader.efi /boot/efi/EFI/BOOT/BOOTX64.EFI

     Finally, if you mounted the ESP, you may wish to unmount it.

           # umount /boot/efi

SEE ALSO

     loader(8), uefi(8)

BUGS

     Non-x86 serial console handling is even more confusing and less well
     documented.

     Sometimes when the serial port speed isn't set, 9600 is used.  Other
     times the result is typically 115200 since the speed remains unchanged
     from the default.

     U-Boot implements a subset of the UEFI standard.  Some versions do not
     support fetching loader variables, so efibootmgr may not work.  In
     addition, efibootmgr is not supported on armv7 or riscv.  In these
     instances, the user has to understand what was booted to update it
     properly (and in most cases, it will be the FreeBSD path and the UEFI
     default so just copy loader.efi there if there are loaders there).
     Typically in these embedded situations, there is only one .efi file (
     loader.efi or a copy of loader.efi).  The path to this file is typically
     the default removable path above.

     Managing booting multiple OSes on UEFI varies greatly, so extra caution
     is required when updating the UEFI default loader.

FreeBSD 15.1-STABLE-HBSD         June 14, 2026                   LOADER.EFI(8)