diff options
-rw-r--r-- | MAINTAINERS | 4 | ||||
-rw-r--r-- | cmd/efidebug.c | 5 | ||||
-rw-r--r-- | doc/index.rst | 13 | ||||
-rw-r--r-- | doc/uefi/index.rst | 11 | ||||
-rw-r--r-- | doc/uefi/iscsi.rst (renamed from doc/README.iscsi) | 48 | ||||
-rw-r--r-- | doc/uefi/u-boot_on_efi.rst (renamed from doc/README.u-boot_on_efi) | 67 | ||||
-rw-r--r-- | doc/uefi/uefi.rst (renamed from doc/README.uefi) | 152 | ||||
-rw-r--r-- | include/efi_api.h | 4 | ||||
-rw-r--r-- | lib/efi_loader/Kconfig | 8 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 28 | ||||
-rw-r--r-- | lib/efi_loader/efi_runtime.c | 89 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_set_virtual_address_map.c | 31 | ||||
-rw-r--r-- | scripts/Makefile.lib | 2 |
13 files changed, 275 insertions, 187 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index c28251e698..182c9c7fc2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -485,9 +485,7 @@ M: Heinrich Schuchardt <xypron.glpk@gmx.de> R: Alexander Graf <agraf@csgraf.de> S: Maintained T: git https://gitlab.denx.de/u-boot/custodians/u-boot-efi.git -F: doc/README.uefi -F: doc/README.iscsi -F: doc/efi.rst +F: doc/uefi/* F: include/capitalization.h F: include/charset.h F: include/cp1250.h diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 02dc491a68..961e8fad22 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -729,7 +729,8 @@ static int u16_tohex(u16 c) * * Implement efidebug "boot dump" sub-command. * Dump information of all UEFI load options defined. - * - boot dump + * + * efidebug boot dump */ static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) @@ -1013,7 +1014,6 @@ static cmd_tbl_t cmd_efidebug_boot_sub[] = { * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure * * Implement efidebug "boot" sub-command. - * See above for details of sub-commands. */ static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) @@ -1059,7 +1059,6 @@ static cmd_tbl_t cmd_efidebug_sub[] = { * * Implement efidebug command which allows us to display and * configure UEFI environment. - * See above for details of sub-commands. */ static int do_efidebug(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) diff --git a/doc/index.rst b/doc/index.rst index 9ae2e167bc..458f0d2d0e 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -15,8 +15,21 @@ if you want to help out. .. toctree:: :maxdepth: 2 +Unified Extensible Firmware (UEFI) +---------------------------------- + +U-Boot provides an implementation of the UEFI API allowing to run UEFI +compliant software like Linux, GRUB, and iPXE. Furthermore U-Boot itself +can be run an UEFI payload. + +.. toctree:: + :maxdepth: 2 + + uefi/index + Driver-Model documentation -------------------------- + The following holds information on the U-Boot device driver framework: driver-model, including the design details of itself and several driver subsystems. diff --git a/doc/uefi/index.rst b/doc/uefi/index.rst new file mode 100644 index 0000000000..b790a91f17 --- /dev/null +++ b/doc/uefi/index.rst @@ -0,0 +1,11 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +Unified Extensible Firmware (UEFI) +================================== + +.. toctree:: + :maxdepth: 2 + + uefi.rst + u-boot_on_efi.rst + iscsi.rst diff --git a/doc/README.iscsi b/doc/uefi/iscsi.rst index 3a12438f90..51d38cde24 100644 --- a/doc/README.iscsi +++ b/doc/uefi/iscsi.rst @@ -1,6 +1,11 @@ -# iSCSI booting with U-Boot and iPXE +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (c) 2018 Heinrich Schuchardt -## Motivation +iSCSI booting with U-Boot and iPXE +================================== + +Motivation +---------- U-Boot has only a reduced set of supported network protocols. The focus for network booting has been on UDP based protocols. A TCP stack and HTTP support @@ -39,7 +44,8 @@ fine grained control of the boot process and can provide a command shell. iPXE can be built as an EFI application (named snp.efi) which can be loaded and run by U-Boot. -## Boot sequence +Boot sequence +------------- U-Boot loads the EFI application iPXE snp.efi using the bootefi command. This application has network access via the simple network protocol offered by @@ -103,16 +109,19 @@ the EFI stub Linux is called as an EFI application:: | | | ~ ~ ~ ~| -## Security +Security +-------- The iSCSI protocol is not encrypted. The traffic could be secured using IPsec but neither U-Boot nor iPXE does support this. So we should at least separate the iSCSI traffic from all other network traffic. This can be achieved using a virtual local area network (VLAN). -## Configuration +Configuration +------------- -### iPXE +iPXE +~~~~ For running iPXE on arm64 the bin-arm64-efi/snp.efi build target is needed:: @@ -130,7 +139,9 @@ http://ipxe.org/cfg iPXE by default will put the CPU to rest when waiting for input. U-Boot does not wake it up due to missing interrupt support. To avoid this behavior create -file src/config/local/nap.h:: +file src/config/local/nap.h: + +.. code-block:: c /* nap.h */ #undef NAP_EFIX86 @@ -138,7 +149,9 @@ file src/config/local/nap.h:: #define NAP_NULL The supported commands in iPXE are controlled by an include, too. Putting the -following into src/config/local/general.h is sufficient for most use cases:: +following into src/config/local/general.h is sufficient for most use cases: + +.. code-block:: c /* general.h */ #define NSLOOKUP_CMD /* Name resolution command */ @@ -151,20 +164,21 @@ following into src/config/local/general.h is sufficient for most use cases:: #define DOWNLOAD_PROTO_NFS /* Network File System Protocol */ #define DOWNLOAD_PROTO_FILE /* Local file system access */ -### Open-iSCSI +Open-iSCSI +~~~~~~~~~~ When the root file system is on an iSCSI drive you should disable pings and set -the replacement timer to a high value [3]: +the replacement timer to a high value in the configuration file [3]:: node.conn[0].timeo.noop_out_interval = 0 node.conn[0].timeo.noop_out_timeout = 0 node.session.timeo.replacement_timeout = 86400 -## Links +Links +----- -* [1](https://ipxe.org) https://ipxe.org - iPXE open source boot firmware -* [2](https://www.gnu.org/software/grub/) https://www.gnu.org/software/grub/ - - GNU GRUB (Grand Unified Bootloader) -* [3](https://github.com/open-iscsi/open-iscsi/blob/master/README) - https://github.com/open-iscsi/open-iscsi/blob/master/README - - Open-iSCSI README +* [1] https://ipxe.org - iPXE open source boot firmware +* [2] https://www.gnu.org/software/grub/ - + GNU GRUB (Grand Unified Bootloader) +* [3] https://github.com/open-iscsi/open-iscsi/blob/master/README - + Open-iSCSI README diff --git a/doc/README.u-boot_on_efi b/doc/uefi/u-boot_on_efi.rst index e12dd4e3e6..c9a41bc919 100644 --- a/doc/README.u-boot_on_efi +++ b/doc/uefi/u-boot_on_efi.rst @@ -1,6 +1,5 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# Copyright (C) 2015 Google, Inc +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (C) 2015 Google, Inc U-Boot on EFI ============= @@ -8,36 +7,20 @@ This document provides information about U-Boot running on top of EFI, either as an application or just as a means of getting U-Boot onto a new platform. -=========== Table of Contents =========== - -Motivation -Status -Build Instructions -Trying it out -Inner workings -EFI Application -EFI Payload -Tables -Interrupts -32/64-bit -Future work -Where is the code? - - Motivation ---------- Running U-Boot on EFI is useful in several situations: - You have EFI running on a board but U-Boot does not natively support it -fully yet. You can boot into U-Boot from EFI and use that until U-Boot is -fully ported + fully yet. You can boot into U-Boot from EFI and use that until U-Boot is + fully ported - You need to use an EFI implementation (e.g. UEFI) because your vendor -requires it in order to provide support + requires it in order to provide support - You plan to use coreboot to boot into U-Boot but coreboot support does -not currently exist for your platform. In the meantime you can use U-Boot -on EFI and then move to U-Boot on coreboot when ready + not currently exist for your platform. In the meantime you can use U-Boot + on EFI and then move to U-Boot on coreboot when ready - You use EFI but want to experiment with a simpler alternative like U-Boot @@ -66,7 +49,7 @@ opt for using QEMU [1] and the OVMF [2], as detailed below. To build U-Boot as an EFI application (32-bit EFI required), enable CONFIG_EFI and CONFIG_EFI_APP. The efi-x86_app config (efi-x86_app_defconfig) is set up -for this. Just build U-Boot as normal, e.g. +for this. Just build U-Boot as normal, e.g.:: make efi-x86_app_defconfig make @@ -75,22 +58,22 @@ To build U-Boot as an EFI payload (32-bit or 64-bit EFI can be used), enable CONFIG_EFI, CONFIG_EFI_STUB, and select either CONFIG_EFI_STUB_32BIT or CONFIG_EFI_STUB_64BIT. The efi-x86_payload configs (efi-x86_payload32_defconfig and efi-x86_payload32_defconfig) are set up for this. Then build U-Boot as -normal, e.g. +normal, e.g.:: make efi-x86_payload32_defconfig (or efi-x86_payload64_defconfig) make You will end up with one of these files depending on what you build for: - u-boot-app.efi - U-Boot EFI application - u-boot-payload.efi - U-Boot EFI payload application +* u-boot-app.efi - U-Boot EFI application +* u-boot-payload.efi - U-Boot EFI payload application Trying it out ------------- QEMU is an emulator and it can emulate an x86 machine. Please make sure your QEMU version is 2.3.0 or above to test this. You can run the payload with -something like this: +something like this:: mkdir /tmp/efi cp /path/to/u-boot*.efi /tmp/efi @@ -102,7 +85,7 @@ run the application. 'bios.bin' is the EFI 'BIOS'. Check [2] to obtain a prebuilt EFI BIOS for QEMU or you can build one from source as well. To try it on real hardware, put u-boot-app.efi on a suitable boot medium, -such as a USB stick. Then you can type something like this to start it: +such as a USB stick. Then you can type something like this to start it:: fs0:u-boot-payload.efi @@ -115,7 +98,7 @@ you get this wrong. Inner workings -============== +-------------- Here follow a few implementation notes for those who want to fiddle with this and perhaps contribute patches. @@ -123,7 +106,7 @@ The application and payload approaches sound similar but are in fact implemented completely differently. EFI Application ---------------- +~~~~~~~~~~~~~~~ For the application the whole of U-Boot is built as a shared library. The efi_main() function is in lib/efi/efi_app.c. It sets up some basic EFI functions with efi_init(), sets up U-Boot global_data, allocates memory for @@ -154,7 +137,7 @@ enough) should be straightforward. Use the 'reset' command to get back to EFI. EFI Payload ------------ +~~~~~~~~~~~ The payload approach is a different kettle of fish. It works by building U-Boot exactly as normal for your target board, then adding the entire image (including device tree) into a small EFI stub application responsible @@ -175,7 +158,7 @@ memory available to it and can operate as it pleases (but see the next section). Tables ------- +~~~~~~ The payload can pass information to U-Boot in the form of EFI tables. At present this feature is used to pass the EFI memory map, an inordinately large list of memory regions. You can use the 'efi mem all' command to @@ -191,14 +174,14 @@ will relocate itself to the top of the largest block of memory it can find below 4GB. Interrupts ----------- +~~~~~~~~~~ U-Boot drivers typically don't use interrupts. Since EFI enables interrupts it is possible that an interrupt will fire that U-Boot cannot handle. This seems to cause problems. For this reason the U-Boot payload runs with interrupts disabled at present. 32/64-bit ---------- +~~~~~~~~~ While the EFI application can in principle be built as either 32- or 64-bit, only 32-bit is currently supported. This means that the application can only be used with 32-bit EFI. @@ -219,12 +202,12 @@ This work could be extended in a number of ways: - Figure out how to solve the interrupt problem - Add more drivers to the application side (e.g. video, block devices, USB, -environment access). This would mostly be an academic exercise as a strong -use case is not readily apparent, but it might be fun. + environment access). This would mostly be an academic exercise as a strong + use case is not readily apparent, but it might be fun. - Avoid turning off boot services in the stub. Instead allow U-Boot to make -use of boot services in case it wants to. It is unclear what it might want -though. + use of boot services in case it wants to. It is unclear what it might want + though. Where is the code? ------------------ @@ -248,5 +231,5 @@ Ben Stoltz, Simon Glass Google, Inc July 2015 -[1] http://www.qemu.org -[2] http://www.tianocore.org/ovmf/ +* [1] http://www.qemu.org +* [2] http://www.tianocore.org/ovmf/ diff --git a/doc/README.uefi b/doc/uefi/uefi.rst index 1d1039a6ae..db942df694 100644 --- a/doc/README.uefi +++ b/doc/uefi/uefi.rst @@ -1,10 +1,8 @@ -<!-- -SPDX-License-Identifier: GPL-2.0+ +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (c) 2018 Heinrich Schuchardt -Copyright (c) 2018 Heinrich Schuchardt ---> - -# UEFI on U-Boot +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 @@ -12,21 +10,23 @@ 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. -## Development target +Development target +------------------ The implementation of UEFI in U-Boot strives to reach the requirements described in the "Embedded Base Boot Requirements (EBBR) Specification - Release v1.0" -[4]. The "Server Base Boot Requirements System Software on ARM Platforms" [5] +[2]. The "Server Base Boot Requirements System Software on ARM Platforms" [3] describes a superset of the EBBR specification and may be used as further reference. A full blown UEFI implementation would contradict the U-Boot design principle "keep it small". -## Building for UEFI +Building U-Boot for UEFI +------------------------ The UEFI standard supports only little-endian systems. The UEFI support can be -activated for ARM and x86 by specifying +activated for ARM and x86 by specifying:: CONFIG_CMD_BOOTEFI=y CONFIG_EFI_LOADER=y @@ -34,22 +34,23 @@ activated for ARM and x86 by specifying in the .config file. Support for attaching virtual block devices, e.g. iSCSI drives connected by the -loaded UEFI application [3], requires +loaded UEFI application [4], requires:: CONFIG_BLK=y CONFIG_PARTITIONS=y -### Executing a UEFI binary +Executing a UEFI binary +~~~~~~~~~~~~~~~~~~~~~~~ The bootefi command is used to start UEFI applications or to install UEFI -drivers. It takes two parameters +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. +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) @@ -62,31 +63,33 @@ 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 +Executing the boot manager +~~~~~~~~~~~~~~~~~~~~~~~~~~ The UEFI specification foresees to define boot entries and boot sequence via UEFI -variables. Booting according to these variables is possible via +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 +Executing the built in hello world application +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A hello world UEFI application can be built with +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 +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. +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. +Below you find the output of an example session:: => bootefi hello ${fdtcontroladdr} ## Starting EFI application at 01000000 ... @@ -101,14 +104,15 @@ Below you find the output of an example session. The environment variable fdtcontroladdr points to U-Boot's internal device tree (if available). -### Executing the built-in self-test +Executing the built-in self-test +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -An UEFI self-test suite can be embedded in U-Boot by building with +An UEFI self-test 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 -self-test. +self-test:: bootefi selftest [fdt address] @@ -116,7 +120,7 @@ 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. +Below you can find the output of an example session:: => setenv efi_selftest simple network protocol => bootefi selftest @@ -135,18 +139,19 @@ Below you can find the output of an example session. Summary: 0 failures Preparing for reset. Press any key. -## The UEFI life cycle +The UEFI life cycle +------------------- After the U-Boot platform has been initialized the UEFI API provides two kinds -of services +of services: -* boot services and -* runtime services. +* boot services +* runtime services -The API can be extended by loading UEFI drivers which come in two variants +The API can be extended by loading UEFI drivers which come in two variants: -* boot drivers and -* runtime drivers. +* boot drivers +* runtime drivers UEFI drivers are installed with U-Boot's bootefi command. With the same command UEFI applications can be executed. @@ -166,7 +171,8 @@ ExitBootServices So this is a point of no return. Afterwards the UEFI application can only return to U-Boot by rebooting. -## The UEFI object model +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 @@ -192,7 +198,8 @@ 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 +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 @@ -213,7 +220,8 @@ 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 +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 @@ -234,7 +242,8 @@ 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 +U-Boot devices mapped as UEFI devices +------------------------------------- Some of the U-Boot devices are mapped as UEFI devices @@ -246,12 +255,13 @@ Some of the U-Boot devices are mapped as UEFI devices 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 +U-Boot driver model [5]. 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 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 @@ -263,7 +273,8 @@ 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 +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 @@ -271,16 +282,16 @@ 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. +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, + .name = "EFI block driver", + .id = UCLASS_EFI, + .ops = &driver_ops, }; -The available operations are defined via the structure struct efi_driver_ops. +The available operations are defined via the structure struct efi_driver_ops:: struct efi_driver_ops { const efi_guid_t *protocol; @@ -296,57 +307,28 @@ 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 +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]. +software iPXE to boot from iSCSI network drives [4]. -This driver is only available if U-Boot is configured with +This driver is only available if U-Boot is configured with:: CONFIG_BLK=y CONFIG_PARTITIONS=y -## TODOs as of U-Boot 2019.04 - -* unimplemented or incompletely implemented boot services - * Exit - call unload function, unload applications only - * ProtocolRegisterNotify - * UnloadImage - -* unimplemented or incompletely implemented runtime services - * SetVariable() ignores attribute EFI_VARIABLE_APPEND_WRITE - * QueryVariableInfo is not implemented - -* unimplemented events - * EVT_RUNTIME - * EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE - -* data model - * 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 - -* incompletely implemented protocols - * support version 0x00020000 of the EFI file protocol - -## Links +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 -* [4](https://github.com/ARM-software/ebbr/releases/download/v1.0/ebbr-v1.0.pdf) +* [1] http://uefi.org/specifications - UEFI specifications +* [2] https://github.com/ARM-software/ebbr/releases/download/v1.0/ebbr-v1.0.pdf - Embedded Base Boot Requirements (EBBR) Specification - Release v1.0 -* [5](https://developer.arm.com/docs/den0044/latest/server-base-boot-requirements-system-software-on-arm-platforms-version-11) +* [3] https://developer.arm.com/docs/den0044/latest/server-base-boot-requirements-system-software-on-arm-platforms-version-11 - Server Base Boot Requirements System Software on ARM Platforms - Version 1.1 +* [4] :doc:`iscsi` +* [5] :doc:`../driver-model/index` diff --git a/include/efi_api.h b/include/efi_api.h index d4f32dbdc8..e5634dc6a0 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -238,8 +238,8 @@ struct efi_runtime_services { efi_status_t (EFIAPI *set_wakeup_time)(char enabled, struct efi_time *time); efi_status_t (EFIAPI *set_virtual_address_map)( - unsigned long memory_map_size, - unsigned long descriptor_size, + efi_uintn_t memory_map_size, + efi_uintn_t descriptor_size, uint32_t descriptor_version, struct efi_mem_desc *virtmap); efi_status_t (EFIAPI *convert_pointer)( diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index a7f2c68fa9..c7027a9676 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -107,4 +107,12 @@ config EFI_HAVE_RUNTIME_RESET default y depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || SYSRESET_X86 +config EFI_GRUB_ARM32_WORKAROUND + bool "Workaround for GRUB on 32bit ARM" + default y + depends on ARM && !ARM64 + help + GRUB prior to version 2.04 requires U-Boot to disable caches. This + workaround currently is also needed on systems with caches that + cannot be managed via CP15. endif diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4f6e8d1679..f75ca1a67c 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -39,14 +39,6 @@ LIST_HEAD(efi_register_notify_events); /* Handle of the currently executing image */ static efi_handle_t current_image; -/* - * If we're running on nasty systems (32bit ARM booting into non-EFI Linux) - * we need to do trickery with caches. Since we don't want to break the EFI - * aware boot path, only apply hacks when loading exiting directly (breaking - * direct Linux EFI booting along the way - oh well). - */ -static bool efi_is_direct_boot = true; - #ifdef CONFIG_ARM /* * The "gd" pointer lives in a register on ARM and AArch64 that we declare @@ -1911,13 +1903,21 @@ error: */ static void efi_exit_caches(void) { -#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64) +#if defined(CONFIG_EFI_GRUB_ARM32_WORKAROUND) /* - * Grub on 32bit ARM needs to have caches disabled before jumping into - * a zImage, but does not know of all cache layers. Give it a hand. + * Boooting Linux via GRUB prior to version 2.04 fails on 32bit ARM if + * caches are enabled. + * + * TODO: + * According to the UEFI spec caches that can be managed via CP15 + * operations should be enabled. Caches requiring platform information + * to manage should be disabled. This should not happen in + * ExitBootServices() but before invoking any UEFI binary is invoked. + * + * We want to keep the current workaround while GRUB prior to version + * 2.04 is still in use. */ - if (efi_is_direct_boot) - cleanup_before_linux(); + cleanup_before_linux(); #endif } @@ -2893,8 +2893,6 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, if (ret != EFI_SUCCESS) return EFI_EXIT(EFI_INVALID_PARAMETER); - efi_is_direct_boot = false; - image_obj->exit_data_size = exit_data_size; image_obj->exit_data = exit_data; diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 8b56ab0207..fb24131462 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -81,6 +81,10 @@ struct elf_rela { long addend; }; +static __efi_runtime_data struct efi_mem_desc *efi_virtmap; +static __efi_runtime_data efi_uintn_t efi_descriptor_count; +static __efi_runtime_data efi_uintn_t efi_descriptor_size; + /* * EFI runtime code lives in two stages. In the first stage, U-Boot and an EFI * payload are running concurrently at the same time. In this mode, we can @@ -89,7 +93,9 @@ struct elf_rela { efi_status_t efi_init_runtime_supported(void) { - u16 efi_runtime_services_supported = 0; + u16 efi_runtime_services_supported = + EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP | + EFI_RT_SUPPORTED_CONVERT_POINTER; /* * This value must be synced with efi_runtime_detach_list @@ -98,8 +104,7 @@ efi_status_t efi_init_runtime_supported(void) #ifdef CONFIG_EFI_HAVE_RUNTIME_RESET efi_runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM; #endif - efi_runtime_services_supported |= - EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP; + return EFI_CALL(efi_set_variable(L"RuntimeServicesSupported", &efi_global_variable_guid, EFI_VARIABLE_BOOTSERVICE_ACCESS | @@ -427,8 +432,8 @@ void efi_runtime_detach(void) * Return: status code EFI_UNSUPPORTED */ static __efi_runtime efi_status_t EFIAPI efi_set_virtual_address_map_runtime( - unsigned long memory_map_size, - unsigned long descriptor_size, + efi_uintn_t memory_map_size, + efi_uintn_t descriptor_size, uint32_t descriptor_version, struct efi_mem_desc *virtmap) { @@ -454,6 +459,58 @@ static __efi_runtime efi_status_t EFIAPI efi_convert_pointer_runtime( return EFI_UNSUPPORTED; } +/** + * efi_convert_pointer_runtime() - convert from physical to virtual pointer + * + * This function implements the ConvertPointer() runtime service until + * the first call to SetVirtualAddressMap(). + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @debug_disposition: indicates if pointer may be converted to NULL + * @address: pointer to be converted + * Return: status code EFI_UNSUPPORTED + */ +static __efi_runtime efi_status_t EFIAPI efi_convert_pointer( + efi_uintn_t debug_disposition, void **address) +{ + efi_physical_addr_t addr = (uintptr_t)*address; + efi_uintn_t i; + efi_status_t ret = EFI_NOT_FOUND; + + EFI_ENTRY("%zu %p", debug_disposition, address); + + if (!efi_virtmap) { + ret = EFI_UNSUPPORTED; + goto out; + } + + if (!address) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + for (i = 0; i < efi_descriptor_count; i++) { + struct efi_mem_desc *map = (void *)efi_virtmap + + (efi_descriptor_size * i); + + if (addr >= map->physical_start && + (addr < map->physical_start + + (map->num_pages << EFI_PAGE_SHIFT))) { + *address = (void *)(uintptr_t) + (addr + map->virtual_start - + map->physical_start); + + ret = EFI_SUCCESS; + break; + } + } + +out: + return EFI_EXIT(ret); +} + static __efi_runtime void efi_relocate_runtime_table(ulong offset) { ulong patchoff; @@ -480,6 +537,12 @@ static __efi_runtime void efi_relocate_runtime_table(ulong offset) */ efi_runtime_services.convert_pointer = &efi_convert_pointer_runtime; + /* + * TODO: Update UEFI variable RuntimeServicesSupported removing flags + * EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP and + * EFI_RT_SUPPORTED_CONVERT_POINTER as required by the UEFI spec 2.8. + */ + /* Update CRC32 */ efi_update_table_header_crc32(&efi_runtime_services.hdr); } @@ -571,19 +634,23 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) * Return: status code */ static efi_status_t EFIAPI efi_set_virtual_address_map( - unsigned long memory_map_size, - unsigned long descriptor_size, + efi_uintn_t memory_map_size, + efi_uintn_t descriptor_size, uint32_t descriptor_version, struct efi_mem_desc *virtmap) { - int n = memory_map_size / descriptor_size; - int i; + efi_uintn_t n = memory_map_size / descriptor_size; + efi_uintn_t i; int rt_code_sections = 0; struct efi_event *event; - EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size, + EFI_ENTRY("%zx %zx %x %p", memory_map_size, descriptor_size, descriptor_version, virtmap); + efi_virtmap = virtmap; + efi_descriptor_size = descriptor_size; + efi_descriptor_count = n; + /* * TODO: * Further down we are cheating. While really we should implement @@ -800,7 +867,7 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .get_wakeup_time = (void *)&efi_unimplemented, .set_wakeup_time = (void *)&efi_unimplemented, .set_virtual_address_map = &efi_set_virtual_address_map, - .convert_pointer = (void *)&efi_unimplemented, + .convert_pointer = efi_convert_pointer, .get_variable = efi_get_variable, .get_next_variable_name = efi_get_next_variable_name, .set_variable = efi_set_variable, diff --git a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c index 6ee7bbeb01..a4e5a50f63 100644 --- a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c +++ b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c @@ -20,6 +20,7 @@ static u32 desc_version; static u64 page1; static u64 page2; static u32 notify_call_count; +static bool convert_pointer_failed; /** * notify () - notification function @@ -39,17 +40,28 @@ static void EFIAPI notify(struct efi_event *event, void *context) addr = (void *)(uintptr_t)page1; ret = runtime->convert_pointer(0, &addr); - if (ret != EFI_SUCCESS) - efi_st_todo("ConvertPointer failed\n"); - if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE) - efi_st_todo("ConvertPointer wrong address\n"); + if (ret != EFI_SUCCESS) { + efi_st_error("ConvertPointer failed\n"); + convert_pointer_failed = true; + return; + } + if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE) { + efi_st_error("ConvertPointer wrong address\n"); + convert_pointer_failed = true; + return; + } addr = (void *)(uintptr_t)page2; ret = runtime->convert_pointer(0, &addr); - if (ret != EFI_SUCCESS) - efi_st_todo("ConvertPointer failed\n"); - if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE) - efi_st_todo("ConvertPointer wrong address\n"); + if (ret != EFI_SUCCESS) { + efi_st_error("ConvertPointer failed\n"); + convert_pointer_failed = true; + return; + } + if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE) { + efi_st_error("ConvertPointer wrong address\n"); + convert_pointer_failed = true; + } } /** @@ -123,6 +135,7 @@ static int setup(const efi_handle_t handle, case EFI_LOADER_DATA: case EFI_BOOT_SERVICES_CODE: case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: continue; } memcpy(pos1, pos2, desc_size); @@ -180,6 +193,8 @@ static int execute(void) notify_call_count); return EFI_ST_FAILURE; } + if (convert_pointer_failed) + return EFI_ST_FAILURE; return EFI_ST_SUCCESS; } diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index de67677f61..2f5e28cac3 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -383,7 +383,7 @@ cmd_efi_ld = $(LD) -nostdlib -znocombreloc -T $(EFI_LDS_PATH) -shared \ EFI_LDS_PATH = $(srctree)/arch/$(ARCH)/lib/$(EFI_LDS) -$(obj)/efi_crt0.o: $(srctree)/arch/$(ARCH)/lib/$(EFI_CRT0:.o=.S) +$(obj)/efi_crt0.o: $(srctree)/arch/$(ARCH)/lib/$(EFI_CRT0:.o=.S) FORCE $(call if_changed_dep,as_o_S) $(obj)/efi_reloc.o: $(srctree)/arch/$(ARCH)/lib/$(EFI_RELOC:.o=.c) $(recordmcount_source) FORCE |