mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-04 05:50:17 +00:00 
			
		
		
		
	We do not support bootefi booting ARMv7 in non-secure mode. Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> Signed-off-by: Alexander Graf <agraf@suse.de>
		
			
				
	
	
		
			335 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			335 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
<!--
 | 
						|
    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
 | 
						|
 | 
						|
* support bootefi booting ARMv7 in non-secure mode (CONFIG_ARMV7_NONSEC=y)
 | 
						|
 | 
						|
## 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
 |