efi_loader: provide new doc/README.uefi
Provides information about - usage of the bootefi command - overview of UEFI - interaction between U-Boot and EFI drivers Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org> Acked-by: Leif Lindholm <leif.lindholm@linaro.org> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
e1214151e8
commit
1914e5b5d8
@ -330,7 +330,7 @@ EFI PAYLOAD
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Maintained
|
||||
T: git git://github.com/agraf/u-boot.git
|
||||
F: doc/README.efi
|
||||
F: doc/README.uefi
|
||||
F: doc/README.iscsi
|
||||
F: include/efi*
|
||||
F: include/pe.h
|
||||
|
332
doc/README.uefi
Normal file
332
doc/README.uefi
Normal file
@ -0,0 +1,332 @@
|
||||
<!--
|
||||
Copyright (c) 2018 Heinrich Schuchardt
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0+
|
||||
-->
|
||||
|
||||
# UEFI on U-Boot
|
||||
|
||||
The Unified Extensible Firmware Interface Specification (UEFI) [1] has become
|
||||
the default for booting on AArch64 and x86 systems. It provides a stable API for
|
||||
the interaction of drivers and applications with the firmware. The API comprises
|
||||
access to block storage, network, and console to name a few. The Linux kernel
|
||||
and boot loaders like GRUB or the FreeBSD loader can be executed.
|
||||
|
||||
## Building for UEFI
|
||||
|
||||
The UEFI standard supports only little endian systems. The UEFI support can be
|
||||
activated for ARM and x86 by specifying
|
||||
|
||||
CONFIG_CMD_BOOTEFI=y
|
||||
CONFIG_EFI_LOADER=y
|
||||
|
||||
in the .config file.
|
||||
|
||||
Support for attaching virtual block devices, e.g. iSCSI drives connected by the
|
||||
loaded UEFI application [3], requires
|
||||
|
||||
CONFIG_BLK=y
|
||||
CONFIG_PARTITIONS=y
|
||||
|
||||
### Executing a UEFI binary
|
||||
|
||||
The bootefi command is used to start UEFI applications or to install UEFI
|
||||
drivers. It takes two parameters
|
||||
|
||||
bootefi <image address> [fdt address]
|
||||
|
||||
* image address - the memory address of the UEFI binary
|
||||
* fdt address - the memory address of the flattened device tree
|
||||
|
||||
Below you find the output of an example session starting GRUB.
|
||||
|
||||
=> load mmc 0:2 ${fdt_addr_r} boot/dtb
|
||||
29830 bytes read in 14 ms (2 MiB/s)
|
||||
=> load mmc 0:1 ${kernel_addr_r} efi/debian/grubaa64.efi
|
||||
reading efi/debian/grubaa64.efi
|
||||
120832 bytes read in 7 ms (16.5 MiB/s)
|
||||
=> bootefi ${kernel_addr_r} ${fdt_addr_r}
|
||||
|
||||
The environment variable 'bootargs' is passed as load options in the UEFI system
|
||||
table. The Linux kernel EFI stub uses the load options as command line
|
||||
arguments.
|
||||
|
||||
### Executing the boot manager
|
||||
|
||||
The UEFI specfication foresees to define boot entries and boot sequence via UEFI
|
||||
variables. Booting according to these variables is possible via
|
||||
|
||||
bootefi bootmgr [fdt address]
|
||||
|
||||
As of U-Boot v2018.03 UEFI variables are not persisted and cannot be set at
|
||||
runtime.
|
||||
|
||||
### Executing the built in hello world application
|
||||
|
||||
A hello world UEFI application can be built with
|
||||
|
||||
CONFIG_CMD_BOOTEFI_HELLO_COMPILE=y
|
||||
|
||||
It can be embedded into the U-Boot binary with
|
||||
|
||||
CONFIG_CMD_BOOTEFI_HELLO=y
|
||||
|
||||
The bootefi command is used to start the embedded hello world application.
|
||||
|
||||
bootefi hello [fdt address]
|
||||
|
||||
Below you find the output of an example session.
|
||||
|
||||
=> bootefi hello ${fdtcontroladdr}
|
||||
## Starting EFI application at 01000000 ...
|
||||
WARNING: using memory device/image path, this may confuse some payloads!
|
||||
Hello, world!
|
||||
Running on UEFI 2.7
|
||||
Have SMBIOS table
|
||||
Have device tree
|
||||
Load options: root=/dev/sdb3 init=/sbin/init rootwait ro
|
||||
## Application terminated, r = 0
|
||||
|
||||
The environment variable fdtcontroladdr points to U-Boot's internal device tree
|
||||
(if available).
|
||||
|
||||
### Executing the built-in selftest
|
||||
|
||||
An UEFI selftest suite can be embedded in U-Boot by building with
|
||||
|
||||
CONFIG_CMD_BOOTEFI_SELFTEST=y
|
||||
|
||||
For testing the UEFI implementation the bootefi command can be used to start the
|
||||
selftest.
|
||||
|
||||
bootefi selftest [fdt address]
|
||||
|
||||
The environment variable 'efi_selftest' can be used to select a single test. If
|
||||
it is not provided all tests are executed except those marked as 'on request'.
|
||||
If the environment variable is set to 'list' a list of all tests is shown.
|
||||
|
||||
Below you can find the output of an example session.
|
||||
|
||||
=> setenv efi_selftest simple network protocol
|
||||
=> bootefi selftest
|
||||
Testing EFI API implementation
|
||||
Selected test: 'simple network protocol'
|
||||
Setting up 'simple network protocol'
|
||||
Setting up 'simple network protocol' succeeded
|
||||
Executing 'simple network protocol'
|
||||
DHCP Discover
|
||||
DHCP reply received from 192.168.76.2 (52:55:c0:a8:4c:02)
|
||||
as broadcast message.
|
||||
Executing 'simple network protocol' succeeded
|
||||
Tearing down 'simple network protocol'
|
||||
Tearing down 'simple network protocol' succeeded
|
||||
Boot services terminated
|
||||
Summary: 0 failures
|
||||
Preparing for reset. Press any key.
|
||||
|
||||
## The UEFI life cycle
|
||||
|
||||
After the U-Boot platform has been initialized the UEFI API provides two kinds
|
||||
of services
|
||||
|
||||
* boot services and
|
||||
* runtime services.
|
||||
|
||||
The API can be extended by loading UEFI drivers which come in two variants
|
||||
|
||||
* boot drivers and
|
||||
* runtime drivers.
|
||||
|
||||
UEFI drivers are installed with U-Boot's bootefi command. With the same command
|
||||
UEFI applications can be executed.
|
||||
|
||||
Loaded images of UEFI drivers stay in memory after returning to U-Boot while
|
||||
loaded images of applications are removed from memory.
|
||||
|
||||
An UEFI application (e.g. an operating system) that wants to take full control
|
||||
of the system calls ExitBootServices. After a UEFI application calls
|
||||
ExitBootServices
|
||||
|
||||
* boot services are not available anymore
|
||||
* timer events are stopped
|
||||
* the memory used by U-Boot except for runtime services is released
|
||||
* the memory used by boot time drivers is released
|
||||
|
||||
So this is a point of no return. Afterwards the UEFI application can only return
|
||||
to U-Boot by rebooting.
|
||||
|
||||
## The UEFI object model
|
||||
|
||||
UEFI offers a flexible and expandable object model. The objects in the UEFI API
|
||||
are devices, drivers, and loaded images. These objects are referenced by
|
||||
handles.
|
||||
|
||||
The interfaces implemented by the objects are referred to as protocols. These
|
||||
are identified by GUIDs. They can be installed and uninstalled by calling the
|
||||
appropriate boot services.
|
||||
|
||||
Handles are created by the InstallProtocolInterface or the
|
||||
InstallMultipleProtocolinterfaces service if NULL is passed as handle.
|
||||
|
||||
Handles are deleted when the last protocol has been removed with the
|
||||
UninstallProtocolInterface or the UninstallMultipleProtocolInterfaces service.
|
||||
|
||||
Devices offer the EFI_DEVICE_PATH_PROTOCOL. A device path is the concatenation
|
||||
of device nodes. By their device paths all devices of a system are arranged in a
|
||||
tree.
|
||||
|
||||
Drivers offer the EFI_DRIVER_BINDING_PROTOCOL. This protocol is used to connect
|
||||
a driver to devices (which are referenced as controllers in this context).
|
||||
|
||||
Loaded images offer the EFI_LOADED_IMAGE_PROTOCOL. This protocol provides meta
|
||||
information about the image and a pointer to the unload callback function.
|
||||
|
||||
## The UEFI events
|
||||
|
||||
In the UEFI terminology an event is a data object referencing a notification
|
||||
function which is queued for calling when the event is signaled. The following
|
||||
types of events exist:
|
||||
|
||||
* periodic and single shot timer events
|
||||
* exit boot services events, triggered by calling the ExitBootServices() service
|
||||
* virtual address change events
|
||||
* memory map change events
|
||||
* read to boot events
|
||||
* reset system events
|
||||
* system table events
|
||||
* events that are only triggered programmatically
|
||||
|
||||
Events can be created with the CreateEvent service and deleted with CloseEvent
|
||||
service.
|
||||
|
||||
Events can be assigned to an event group. If any of the events in a group is
|
||||
signaled, all other events in the group are also set to the signaled state.
|
||||
|
||||
## The UEFI driver model
|
||||
|
||||
A driver is specific for a single protocol installed on a device. To install a
|
||||
driver on a device the ConnectController service is called. In this context
|
||||
controller refers to the device for which the driver is installed.
|
||||
|
||||
The relevant drivers are identified using the EFI_DRIVER_BINDING_PROTOCOL. This
|
||||
protocol has has three functions:
|
||||
|
||||
* supported - determines if the driver is compatible with the device
|
||||
* start - installs the driver by opening the relevant protocol with
|
||||
attribute EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
* stop - uninstalls the driver
|
||||
|
||||
The driver may create child controllers (child devices). E.g. a driver for block
|
||||
IO devices will create the device handles for the partitions. The child
|
||||
controllers will open the supported protocol with the attribute
|
||||
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
|
||||
|
||||
A driver can be detached from a device using the DisconnectController service.
|
||||
|
||||
## U-Boot devices mapped as UEFI devices
|
||||
|
||||
Some of the U-Boot devices are mapped as UEFI devices
|
||||
|
||||
* block IO devices
|
||||
* console
|
||||
* graphical output
|
||||
* network adapter
|
||||
|
||||
As of U-Boot 2018.03 the logic for doing this is hard coded.
|
||||
|
||||
The development target is to integrate the setup of these UEFI devices with the
|
||||
U-Boot driver model. So when a U-Boot device is discovered a handle should be
|
||||
created and the device path protocol and the relevant IO protocol should be
|
||||
installed. The UEFI driver then would be attached by calling ConnectController.
|
||||
When a U-Boot device is removed DisconnectController should be called.
|
||||
|
||||
## UEFI devices mapped as U-Boot devices
|
||||
|
||||
UEFI drivers binaries and applications may create new (virtual) devices, install
|
||||
a protocol and call the ConnectController service. Now the matching UEFI driver
|
||||
is determined by iterating over the implementations of the
|
||||
EFI_DRIVER_BINDING_PROTOCOL.
|
||||
|
||||
It is the task of the UEFI driver to create a corresponding U-Boot device and to
|
||||
proxy calls for this U-Boot device to the controller.
|
||||
|
||||
In U-Boot 2018.03 this has only been implemented for block IO devices.
|
||||
|
||||
### UEFI uclass
|
||||
|
||||
An UEFI uclass driver (lib/efi_driver/efi_uclass.c) has been created that
|
||||
takes care of initializing the UEFI drivers and providing the
|
||||
EFI_DRIVER_BINDING_PROTOCOL implementation for the UEFI drivers.
|
||||
|
||||
A linker created list is used to keep track of the UEFI drivers. To create an
|
||||
entry in the list the UEFI driver uses the U_BOOT_DRIVER macro specifying
|
||||
UCLASS_EFI as the ID of its uclass, e.g.
|
||||
|
||||
/* Identify as UEFI driver */
|
||||
U_BOOT_DRIVER(efi_block) = {
|
||||
.name = "EFI block driver",
|
||||
.id = UCLASS_EFI,
|
||||
.ops = &driver_ops,
|
||||
};
|
||||
|
||||
The available operations are defined via the structure struct efi_driver_ops.
|
||||
|
||||
struct efi_driver_ops {
|
||||
const efi_guid_t *protocol;
|
||||
const efi_guid_t *child_protocol;
|
||||
int (*bind)(efi_handle_t handle, void *interface);
|
||||
};
|
||||
|
||||
When the supported() function of the EFI_DRIVER_BINDING_PROTOCOL is called the
|
||||
uclass checks if the protocol GUID matches the protocol GUID of the UEFI driver.
|
||||
In the start() function the bind() function of the UEFI driver is called after
|
||||
checking the GUID.
|
||||
The stop() function of the EFI_DRIVER_BINDING_PROTOCOL disconnects the child
|
||||
controllers created by the UEFI driver and the UEFI driver. (In U-Boot v2013.03
|
||||
this is not yet completely implemented.)
|
||||
|
||||
### UEFI block IO driver
|
||||
|
||||
The UEFI block IO driver supports devices exposing the EFI_BLOCK_IO_PROTOCOL.
|
||||
|
||||
When connected it creates a new U-Boot block IO device with interface type
|
||||
IF_TYPE_EFI, adds child controllers mapping the partitions, and installs the
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on these. This can be used together with the
|
||||
software iPXE to boot from iSCSI network drives [3].
|
||||
|
||||
This driver is only available if U-Boot is configured with
|
||||
|
||||
CONFIG_BLK=y
|
||||
CONFIG_PARTITIONS=y
|
||||
|
||||
## TODOs as of U-Boot 2018.03
|
||||
|
||||
* unimplemented or incompletely implemented boot services
|
||||
* Exit - call unload function, unload applications only
|
||||
* ReinstallProtocolInterface
|
||||
* UnloadImage
|
||||
|
||||
* unimplemented events
|
||||
* EVT_RUNTIME
|
||||
* EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
|
||||
* event groups
|
||||
|
||||
* data model
|
||||
* manage events in a linked list
|
||||
* manage configuration tables in a linked list
|
||||
|
||||
* UEFI drivers
|
||||
* support DisconnectController for UEFI block devices.
|
||||
|
||||
* support for CONFIG_EFI_LOADER in the sandbox (CONFIG_SANDBOX=y)
|
||||
|
||||
* UEFI variables
|
||||
* persistence
|
||||
* runtime support
|
||||
|
||||
## Links
|
||||
|
||||
* [1](http://uefi.org/specifications)
|
||||
http://uefi.org/specifications - UEFI specifications
|
||||
* [2](./driver-model/README.txt) doc/driver-model/README.txt - Driver model
|
||||
* [3](./README.iscsi) doc/README.iscsi - iSCSI booting with U-Boot and iPXE
|
Loading…
Reference in New Issue
Block a user