diff options
| -rw-r--r-- | MAINTAINERS | 3 | ||||
| -rw-r--r-- | arch/arm/lib/crt0_aarch64_efi.S | 4 | ||||
| -rw-r--r-- | arch/arm/lib/crt0_arm_efi.S | 4 | ||||
| -rw-r--r-- | cmd/bootefi.c | 2 | ||||
| -rw-r--r-- | doc/README.efi | 275 | ||||
| -rw-r--r-- | doc/README.u-boot_on_efi | 259 | ||||
| -rw-r--r-- | include/asm-generic/pe.h | 21 | ||||
| -rw-r--r-- | include/efi_api.h | 37 | ||||
| -rw-r--r-- | include/efi_loader.h | 4 | ||||
| -rw-r--r-- | include/pe.h | 8 | ||||
| -rw-r--r-- | lib/efi_driver/efi_uclass.c | 6 | ||||
| -rw-r--r-- | lib/efi_loader/efi_boottime.c | 35 | ||||
| -rw-r--r-- | lib/efi_loader/efi_disk.c | 71 | ||||
| -rw-r--r-- | lib/efi_loader/efi_image_loader.c | 2 | ||||
| -rw-r--r-- | lib/efi_loader/efi_runtime.c | 29 | ||||
| -rw-r--r-- | lib/efi_selftest/Makefile | 6 | 
16 files changed, 453 insertions, 313 deletions
| diff --git a/MAINTAINERS b/MAINTAINERS index be941c1e996..d2f8c513e08 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -289,8 +289,11 @@ 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.iscsi  F:	include/efi* +F:	include/pe.h +F:	include/asm-generic/pe.h  F:	lib/efi*/  F:	test/py/tests/test_efi*  F:	cmd/bootefi.c diff --git a/arch/arm/lib/crt0_aarch64_efi.S b/arch/arm/lib/crt0_aarch64_efi.S index 52056469beb..9b0e894f8a2 100644 --- a/arch/arm/lib/crt0_aarch64_efi.S +++ b/arch/arm/lib/crt0_aarch64_efi.S @@ -8,6 +8,8 @@   * This file is taken and modified from the gnu-efi project.   */ +#include <asm-generic/pe.h> +  	.section	.text.head  	/* @@ -62,7 +64,7 @@ extra_header_fields:  	 */  	.long	_start - ImageBase		/* SizeOfHeaders */  	.long	0				/* CheckSum */ -	.short	EFI_SUBSYSTEM			/* Subsystem */ +	.short	IMAGE_SUBSYSTEM_EFI_APPLICATION /* Subsystem */  	.short	0				/* DllCharacteristics */  	.quad	0				/* SizeOfStackReserve */  	.quad	0				/* SizeOfStackCommit */ diff --git a/arch/arm/lib/crt0_arm_efi.S b/arch/arm/lib/crt0_arm_efi.S index 967c8859829..af55bba4baa 100644 --- a/arch/arm/lib/crt0_arm_efi.S +++ b/arch/arm/lib/crt0_arm_efi.S @@ -8,6 +8,8 @@   * This file is taken and modified from the gnu-efi project.   */ +#include <asm-generic/pe.h> +  	.section	.text.head  	/* @@ -64,7 +66,7 @@ extra_header_fields:  	 */  	.long	_start - image_base		/* SizeOfHeaders */  	.long	0				/* CheckSum */ -	.short	EFI_SUBSYSTEM			/* Subsystem */ +	.short	IMAGE_SUBSYSTEM_EFI_APPLICATION	/* Subsystem */  	.short	0				/* DllCharacteristics */  	.long	0				/* SizeOfStackReserve */  	.long	0				/* SizeOfStackCommit */ diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 4233d36b722..2106ed9c8c8 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -411,7 +411,7 @@ static char bootefi_help_text[] =  	"    Use environment variable efi_selftest to select a single test.\n"  	"    Use 'setenv efi_selftest list' to enumerate all tests.\n"  #endif -	"bootmgr [fdt addr]\n" +	"bootefi bootmgr [fdt addr]\n"  	"  - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"  	"\n"  	"    If specified, the device tree located at <fdt address> gets\n" diff --git a/doc/README.efi b/doc/README.efi index 66259f3e260..956f5bfa0c6 100644 --- a/doc/README.efi +++ b/doc/README.efi @@ -4,279 +4,24 @@  # SPDX-License-Identifier:	GPL-2.0+  # -=========== Table of Contents =========== - -  1  U-Boot on EFI -  1.1  In God's Name, Why? -  1.2  Status -  1.3  Build Instructions -  1.4  Trying it out -  1.5  Inner workings -  1.6  EFI Application -  1.7  EFI Payload -  1.8  Tables -  1.9  Interrupts -  1.10 32/64-bit -  1.11 Future work -  1.12 Where is the code? - -  2  EFI on U-Boot -  2.1  In God's Name, Why? -  2.2  How do I get it? -  2.3  Status -  2.4  Future work - -U-Boot on EFI +EFI on U-Boot  ============= -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. - - -In God's Name, Why? -------------------- -This 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 - -- You need to use an EFI implementation (e.g. UEFI) because your vendor -requires it in order to provide support +This document provides information about the implementation of the UEFI API [1] +in U-Boot. -- 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 - -- You use EFI but want to experiment with a simpler alternative like U-Boot +=========== Table of Contents =========== +Motivation +How do I get it?  Status ------- -Only x86 is supported at present. If you are using EFI on another architecture -you may want to reconsider. However, much of the code is generic so could be -ported. - -U-Boot supports running as an EFI application for 32-bit EFI only. This is -not very useful since only a serial port is provided. You can look around at -memory and type 'help' but that is about it. - -More usefully, U-Boot supports building itself as a payload for either 32-bit -or 64-bit EFI. U-Boot is packaged up and loaded in its entirety by EFI. Once -started, U-Boot changes to 32-bit mode (currently) and takes over the -machine. You can use devices, boot a kernel, etc. - - -Build Instructions ------------------- -First choose a board that has EFI support and obtain an EFI implementation -for that board. It will be either 32-bit or 64-bit. Alternatively, you can -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 config (efi-x86_defconfig) is set up for this. -Just build U-Boot as normal, e.g. - -   make efi-x86_defconfig -   make - -To build U-Boot as an EFI payload (32-bit or 64-bit EFI can be used), adjust an -existing config (like qemu-x86_defconfig) to enable CONFIG_EFI, CONFIG_EFI_STUB -and either CONFIG_EFI_STUB_32BIT or CONFIG_EFI_STUB_64BIT. All of these are -boolean Kconfig options. Then build U-Boot as normal, e.g. - -   make qemu-x86_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 - - -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: - -   mkdir /tmp/efi -   cp /path/to/u-boot*.efi /tmp/efi -   qemu-system-x86_64 -bios bios.bin -hda fat:/tmp/efi/ - -Add -nographic if you want to use the terminal for output. Once it starts -type 'fs0:u-boot-payload.efi' to run the payload or 'fs0:u-boot-app.efi' to -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: - -   fs0:u-boot-payload.efi - -(or fs0:u-boot-app.efi for the application) - -This will start the payload, copy U-Boot into RAM and start U-Boot. Note -that EFI does not support booting a 64-bit application from a 32-bit -EFI (or vice versa). Also it will often fail to print an error message if -you get this wrong. - - -Inner workings -============== -Here follow a few implementation notes for those who want to fiddle with -this and perhaps contribute patches. - -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 -U-Boot's malloc(), etc. and enters the normal init sequence (board_init_f() -and board_init_r()). - -Since U-Boot limits its memory access to the allocated regions very little -special code is needed. The CONFIG_EFI_APP option controls a few things -that need to change so 'git grep CONFIG_EFI_APP' may be instructive. -The CONFIG_EFI option controls more general EFI adjustments. - -The only available driver is the serial driver. This calls back into EFI -'boot services' to send and receive characters. Although it is implemented -as a serial driver the console device is not necessarilly serial. If you -boot EFI with video output then the 'serial' device will operate on your -target devices's display instead and the device's USB keyboard will also -work if connected. If you have both serial and video output, then both -consoles will be active. Even though U-Boot does the same thing normally, -These are features of EFI, not U-Boot. - -Very little code is involved in implementing the EFI application feature. -U-Boot is highly portable. Most of the difficulty is in modifying the -Makefile settings to pass the right build flags. In particular there is very -little x86-specific code involved - you can find most of it in -arch/x86/cpu. Porting to ARM (which can also use EFI if you are brave -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 -for booting it. The stub application is built as a normal EFI application -except that it has a lot of data attached to it. - -The stub application is implemented in lib/efi/efi_stub.c. The efi_main() -function is called by EFI. It is responsible for copying U-Boot from its -original location into memory, disabling EFI boot services and starting -U-Boot. U-Boot then starts as normal, relocates, starts all drivers, etc. - -The stub application is architecture-dependent. At present it has some -x86-specific code and a comment at the top of efi_stub.c describes this. - -While the stub application does allocate some memory from EFI this is not -used by U-Boot (the payload). In fact when U-Boot starts it has all of the -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 -display this list. U-Boot uses the list to work out where to relocate -itself. - -Although U-Boot can use any memory it likes, EFI marks some memory as used -by 'run-time services', code that hangs around while U-Boot is running and -is even present when Linux is running. This is common on x86 and provides -a way for Linux to call back into the firmware to control things like CPU -fan speed. U-Boot uses only 'conventional' memory, in EFI terminology. It -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. - -The payload stub can be build as either 32- or 64-bits. Only a small amount -of code is built this way (see the extra- line in lib/efi/Makefile). -Everything else is built as a normal U-Boot, so is always 32-bit on x86 at -present. -  Future work ------------ -This work could be extended in a number of ways: - -- Add a generic x86 EFI payload configuration. At present you need to modify -an existing one, but mostly the low-level x86 code is disabled when booting -on EFI anyway, so a generic 'EFI' board could be created with a suitable set -of drivers enabled. -- Add ARM support -- Add 64-bit application support - -- 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. - -- 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. - -Where is the code? ------------------- -lib/efi -	payload stub, application, support code. Mostly arch-neutral - -arch/x86/lib/efi -	helper functions for the fake DRAM init, etc. These can be used by -	any board that runs as a payload. - -arch/x86/cpu/efi -	x86 support code for running as an EFI application - -board/efi/efi-x86/efi.c -	x86 board code for running as an EFI application - -common/cmd_efi.c -	the 'efi' command - --- -Ben Stoltz, Simon Glass -Google, Inc -July 2015 - -[1] http://www.qemu.org -[2] http://www.tianocore.org/ovmf/ - -------------------------------------------------------------------------------- - -EFI on U-Boot -============= - -In addition to support for running U-Boot as a UEFI application, U-Boot itself -can also expose the UEFI interfaces and thus allow UEFI payloads to run under -it. - -In God's Name, Why? -------------------- +Motivation +---------- -With this support in place, you can run any UEFI payload (such as the Linux +With this API support in place, you can run any UEFI payload (such as the Linux  kernel, grub2 or gummiboot) on U-Boot. This dramatically simplifies boot loader  configuration, as U-Boot based systems now look and feel (almost) the same way  as TianoCore based systems. @@ -337,3 +82,5 @@ have)     - Network device support     - Support for payload exit     - Payload Watchdog support + +[1] http://uefi.org/ diff --git a/doc/README.u-boot_on_efi b/doc/README.u-boot_on_efi new file mode 100644 index 00000000000..298b94e342e --- /dev/null +++ b/doc/README.u-boot_on_efi @@ -0,0 +1,259 @@ +# +# Copyright (C) 2015 Google, Inc +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +U-Boot on EFI +============= +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 + +- You need to use an EFI implementation (e.g. UEFI) because your vendor +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 + +- You use EFI but want to experiment with a simpler alternative like U-Boot + + +Status +------ +Only x86 is supported at present. If you are using EFI on another architecture +you may want to reconsider. However, much of the code is generic so could be +ported. + +U-Boot supports running as an EFI application for 32-bit EFI only. This is +not very useful since only a serial port is provided. You can look around at +memory and type 'help' but that is about it. + +More usefully, U-Boot supports building itself as a payload for either 32-bit +or 64-bit EFI. U-Boot is packaged up and loaded in its entirety by EFI. Once +started, U-Boot changes to 32-bit mode (currently) and takes over the +machine. You can use devices, boot a kernel, etc. + + +Build Instructions +------------------ +First choose a board that has EFI support and obtain an EFI implementation +for that board. It will be either 32-bit or 64-bit. Alternatively, you can +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 config (efi-x86_defconfig) is set up for this. +Just build U-Boot as normal, e.g. + +   make efi-x86_defconfig +   make + +To build U-Boot as an EFI payload (32-bit or 64-bit EFI can be used), adjust an +existing config (like qemu-x86_defconfig) to enable CONFIG_EFI, CONFIG_EFI_STUB +and either CONFIG_EFI_STUB_32BIT or CONFIG_EFI_STUB_64BIT. All of these are +boolean Kconfig options. Then build U-Boot as normal, e.g. + +   make qemu-x86_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 + + +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: + +   mkdir /tmp/efi +   cp /path/to/u-boot*.efi /tmp/efi +   qemu-system-x86_64 -bios bios.bin -hda fat:/tmp/efi/ + +Add -nographic if you want to use the terminal for output. Once it starts +type 'fs0:u-boot-payload.efi' to run the payload or 'fs0:u-boot-app.efi' to +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: + +   fs0:u-boot-payload.efi + +(or fs0:u-boot-app.efi for the application) + +This will start the payload, copy U-Boot into RAM and start U-Boot. Note +that EFI does not support booting a 64-bit application from a 32-bit +EFI (or vice versa). Also it will often fail to print an error message if +you get this wrong. + + +Inner workings +============== +Here follow a few implementation notes for those who want to fiddle with +this and perhaps contribute patches. + +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 +U-Boot's malloc(), etc. and enters the normal init sequence (board_init_f() +and board_init_r()). + +Since U-Boot limits its memory access to the allocated regions very little +special code is needed. The CONFIG_EFI_APP option controls a few things +that need to change so 'git grep CONFIG_EFI_APP' may be instructive. +The CONFIG_EFI option controls more general EFI adjustments. + +The only available driver is the serial driver. This calls back into EFI +'boot services' to send and receive characters. Although it is implemented +as a serial driver the console device is not necessarilly serial. If you +boot EFI with video output then the 'serial' device will operate on your +target devices's display instead and the device's USB keyboard will also +work if connected. If you have both serial and video output, then both +consoles will be active. Even though U-Boot does the same thing normally, +These are features of EFI, not U-Boot. + +Very little code is involved in implementing the EFI application feature. +U-Boot is highly portable. Most of the difficulty is in modifying the +Makefile settings to pass the right build flags. In particular there is very +little x86-specific code involved - you can find most of it in +arch/x86/cpu. Porting to ARM (which can also use EFI if you are brave +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 +for booting it. The stub application is built as a normal EFI application +except that it has a lot of data attached to it. + +The stub application is implemented in lib/efi/efi_stub.c. The efi_main() +function is called by EFI. It is responsible for copying U-Boot from its +original location into memory, disabling EFI boot services and starting +U-Boot. U-Boot then starts as normal, relocates, starts all drivers, etc. + +The stub application is architecture-dependent. At present it has some +x86-specific code and a comment at the top of efi_stub.c describes this. + +While the stub application does allocate some memory from EFI this is not +used by U-Boot (the payload). In fact when U-Boot starts it has all of the +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 +display this list. U-Boot uses the list to work out where to relocate +itself. + +Although U-Boot can use any memory it likes, EFI marks some memory as used +by 'run-time services', code that hangs around while U-Boot is running and +is even present when Linux is running. This is common on x86 and provides +a way for Linux to call back into the firmware to control things like CPU +fan speed. U-Boot uses only 'conventional' memory, in EFI terminology. It +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. + +The payload stub can be build as either 32- or 64-bits. Only a small amount +of code is built this way (see the extra- line in lib/efi/Makefile). +Everything else is built as a normal U-Boot, so is always 32-bit on x86 at +present. + +Future work +----------- +This work could be extended in a number of ways: + +- Add a generic x86 EFI payload configuration. At present you need to modify +an existing one, but mostly the low-level x86 code is disabled when booting +on EFI anyway, so a generic 'EFI' board could be created with a suitable set +of drivers enabled. + +- Add ARM support + +- Add 64-bit application support + +- 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. + +- 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. + +Where is the code? +------------------ +lib/efi +	payload stub, application, support code. Mostly arch-neutral + +arch/x86/lib/efi +	helper functions for the fake DRAM init, etc. These can be used by +	any board that runs as a payload. + +arch/x86/cpu/efi +	x86 support code for running as an EFI application + +board/efi/efi-x86/efi.c +	x86 board code for running as an EFI application + +common/cmd_efi.c +	the 'efi' command + +-- +Ben Stoltz, Simon Glass +Google, Inc +July 2015 + +[1] http://www.qemu.org +[2] http://www.tianocore.org/ovmf/ diff --git a/include/asm-generic/pe.h b/include/asm-generic/pe.h new file mode 100644 index 00000000000..d1683f238af --- /dev/null +++ b/include/asm-generic/pe.h @@ -0,0 +1,21 @@ +/* + *  Portable Executable and Common Object Constants + * + *  Copyright (c) 2018 Heinrich Schuchardt + * + *  based on the "Microsoft Portable Executable and Common Object File Format + *  Specification", revision 11, 2017-01-23 + * + *  SPDX-License-Identifier:     GPL-2.0+ + */ + +#ifndef _ASM_PE_H +#define _ASM_PE_H + +/* Subsystem type */ +#define IMAGE_SUBSYSTEM_EFI_APPLICATION		10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER	11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER	12 +#define IMAGE_SUBSYSTEM_EFI_ROM			13 + +#endif /* _ASM_PE_H */ diff --git a/include/efi_api.h b/include/efi_api.h index 205f8f1f700..3ba650e57e6 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -166,7 +166,14 @@ struct efi_boot_services {  	void (EFIAPI *copy_mem)(void *destination, const void *source,  			size_t length);  	void (EFIAPI *set_mem)(void *buffer, size_t size, uint8_t value); -	void *create_event_ex; +	efi_status_t (EFIAPI *create_event_ex)( +				uint32_t type, efi_uintn_t notify_tpl, +				void (EFIAPI *notify_function) ( +					struct efi_event *event, +					void *context), +				void *notify_context, +				efi_guid_t *event_group, +				struct efi_event **event);  };  /* Types and defines for EFI ResetSystem */ @@ -180,6 +187,17 @@ enum efi_reset_type {  #define EFI_RUNTIME_SERVICES_SIGNATURE	0x5652453544e5552ULL  #define EFI_RUNTIME_SERVICES_REVISION	0x00010000 +#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET	0x00010000 +#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE	0x00020000 +#define CAPSULE_FLAGS_INITIATE_RESET		0x00040000 + +struct efi_capsule_header { +	efi_guid_t *capsule_guid; +	u32 header_size; +	u32 flags; +	u32 capsule_image_size; +}; +  struct efi_runtime_services {  	struct efi_table_hdr hdr;  	efi_status_t (EFIAPI *get_time)(struct efi_time *time, @@ -209,9 +227,20 @@ struct efi_runtime_services {  	void (EFIAPI *reset_system)(enum efi_reset_type reset_type,  				    efi_status_t reset_status,  				    unsigned long data_size, void *reset_data); -	void *update_capsule; -	void *query_capsule_caps; -	void *query_variable_info; +	efi_status_t (EFIAPI *update_capsule)( +			struct efi_capsule_header **capsule_header_array, +			efi_uintn_t capsule_count, +			u64 scatter_gather_list); +	efi_status_t (EFIAPI *query_capsule_caps)( +			struct efi_capsule_header **capsule_header_array, +			efi_uintn_t capsule_count, +			u64 maximum_capsule_size, +			u32 reset_type); +	efi_status_t (EFIAPI *query_variable_info)( +			u32 attributes, +			u64 maximum_variable_storage_size, +			u64 remaining_variable_storage_size, +			u64 maximum_variable_size);  };  /* EFI Configuration Table and GUID definitions */ diff --git a/include/efi_loader.h b/include/efi_loader.h index 21c03c5c28f..07730c3f394 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -173,7 +173,7 @@ extern struct list_head efi_obj_list;  /* Called by bootefi to make console interface available */  int efi_console_register(void);  /* Called by bootefi to make all disk storage accessible as EFI objects */ -int efi_disk_register(void); +efi_status_t efi_disk_register(void);  /* Create handles and protocols for the partitions of a block device */  int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,  			       const char *if_typename, int diskid, @@ -272,7 +272,7 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,  uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,  			    bool overlap_only_ram);  /* Called by board init to initialize the EFI drivers */ -int efi_driver_init(void); +efi_status_t efi_driver_init(void);  /* Called by board init to initialize the EFI memory map */  int efi_memory_init(void);  /* Adds new or overrides configuration table entry to the system table */ diff --git a/include/pe.h b/include/pe.h index 4ef3e92efaf..c3a19cef765 100644 --- a/include/pe.h +++ b/include/pe.h @@ -11,6 +11,8 @@  #ifndef _PE_H  #define _PE_H +#include <asm-generic/pe.h> +  typedef struct _IMAGE_DOS_HEADER {  	uint16_t e_magic;	/* 00: MZ Header signature */  	uint16_t e_cblp;	/* 02: Bytes on last page of file */ @@ -62,12 +64,6 @@ typedef struct _IMAGE_DATA_DIRECTORY {  #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 -/* PE32+ Subsystem type for EFI images */ -#define IMAGE_SUBSYSTEM_EFI_APPLICATION         10 -#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 -#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER      12 -#define IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER      13 -  typedef struct _IMAGE_OPTIONAL_HEADER64 {  	uint16_t Magic; /* 0x20b */  	uint8_t  MajorLinkerVersion; diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c index 90797f96d8d..46b69b479cb 100644 --- a/lib/efi_driver/efi_uclass.c +++ b/lib/efi_driver/efi_uclass.c @@ -287,10 +287,10 @@ out:   *   * @return	0 = success, any other value will stop further execution   */ -int efi_driver_init(void) +efi_status_t efi_driver_init(void)  {  	struct driver *drv; -	int ret = 0; +	efi_status_t ret = EFI_SUCCESS;  	/* Save 'gd' pointer */  	efi_save_gd(); @@ -300,7 +300,7 @@ int efi_driver_init(void)  	     drv < ll_entry_end(struct driver, driver); ++drv) {  		if (drv->id == UCLASS_EFI) {  			ret = efi_add_driver(drv); -			if (ret) { +			if (ret != EFI_SUCCESS) {  				printf("EFI: ERROR: failed to add driver %s\n",  				       drv->name);  				break; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index da93498b36b..6eea2395c7b 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -526,6 +526,38 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,  }  /* + * Create an event in a group. + * + * This function implements the CreateEventEx service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * TODO: Support event groups + * + * @type		type of the event to create + * @notify_tpl		task priority level of the event + * @notify_function	notification function of the event + * @notify_context	pointer passed to the notification function + * @event		created event + * @event_group		event group + * @return		status code + */ +efi_status_t EFIAPI efi_create_event_ex(uint32_t type, efi_uintn_t notify_tpl, +					void (EFIAPI *notify_function) ( +							struct efi_event *event, +							void *context), +					void *notify_context, +					efi_guid_t *event_group, +					struct efi_event **event) +{ +	EFI_ENTRY("%d, 0x%zx, %p, %p, %pUl", type, notify_tpl, notify_function, +		  notify_context, event_group); +	if (event_group) +		return EFI_EXIT(EFI_UNSUPPORTED); +	return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function, +					 notify_context, event)); +} + +/*   * Create an event.   *   * This function implements the CreateEvent service. @@ -2851,6 +2883,7 @@ static const struct efi_boot_services efi_boot_services = {  	.calculate_crc32 = efi_calculate_crc32,  	.copy_mem = efi_copy_mem,  	.set_mem = efi_set_mem, +	.create_event_ex = efi_create_event_ex,  }; @@ -2859,7 +2892,7 @@ static uint16_t __efi_runtime_data firmware_vendor[] = L"Das U-Boot";  struct efi_system_table __efi_runtime_data systab = {  	.hdr = {  		.signature = EFI_SYSTEM_TABLE_SIGNATURE, -		.revision = 0x20005, /* 2.5 */ +		.revision = 2 << 16 | 70, /* 2.7 */  		.headersize = sizeof(struct efi_table_hdr),  	},  	.fw_vendor = (long)firmware_vendor, diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index ac39a65ee89..825a6d86de8 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -226,25 +226,26 @@ efi_fs_from_path(struct efi_device_path *full_path)   * @offset	offset into disk for simple partitions   * @return	disk object   */ -static struct efi_disk_obj *efi_disk_add_dev( +static efi_status_t efi_disk_add_dev(  				efi_handle_t parent,  				struct efi_device_path *dp_parent,  				const char *if_typename,  				struct blk_desc *desc,  				int dev_index,  				lbaint_t offset, -				unsigned int part) +				unsigned int part, +				struct efi_disk_obj **disk)  {  	struct efi_disk_obj *diskobj;  	efi_status_t ret;  	/* Don't add empty devices */  	if (!desc->lba) -		return NULL; +		return EFI_NOT_READY;  	diskobj = calloc(1, sizeof(*diskobj));  	if (!diskobj) -		goto out_of_memory; +		return EFI_OUT_OF_RESOURCES;  	/* Hook up to the device list */  	efi_add_handle(&diskobj->parent); @@ -262,11 +263,11 @@ static struct efi_disk_obj *efi_disk_add_dev(  	ret = efi_add_protocol(diskobj->parent.handle, &efi_block_io_guid,  			       &diskobj->ops);  	if (ret != EFI_SUCCESS) -		goto out_of_memory; +		return ret;  	ret = efi_add_protocol(diskobj->parent.handle, &efi_guid_device_path,  			       diskobj->dp);  	if (ret != EFI_SUCCESS) -		goto out_of_memory; +		return ret;  	if (part >= 1) {  		diskobj->volume = efi_simple_file_system(desc, part,  							 diskobj->dp); @@ -274,7 +275,7 @@ static struct efi_disk_obj *efi_disk_add_dev(  				       &efi_simple_file_system_protocol_guid,  				       diskobj->volume);  		if (ret != EFI_SUCCESS) -			goto out_of_memory; +			return ret;  	}  	diskobj->ops = block_io_disk_template;  	diskobj->ifname = if_typename; @@ -291,10 +292,9 @@ static struct efi_disk_obj *efi_disk_add_dev(  	if (part != 0)  		diskobj->media.logical_partition = 1;  	diskobj->ops.media = &diskobj->media; -	return diskobj; -out_of_memory: -	printf("ERROR: Out of memory\n"); -	return NULL; +	if (disk) +		*disk = diskobj; +	return EFI_SUCCESS;  }  /* @@ -330,8 +330,12 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,  			continue;  		snprintf(devname, sizeof(devname), "%s:%d", pdevname,  			 part); -		efi_disk_add_dev(parent, dp, if_typename, desc, diskid, -				 info.start, part); +		ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid, +				       info.start, part, NULL); +		if (ret != EFI_SUCCESS) { +			printf("Adding partition %s failed\n", pdevname); +			continue; +		}  		disks++;  	} @@ -349,26 +353,32 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,   *   * This gets called from do_bootefi_exec().   */ -int efi_disk_register(void) +efi_status_t efi_disk_register(void)  {  	struct efi_disk_obj *disk;  	int disks = 0; +	efi_status_t ret;  #ifdef CONFIG_BLK  	struct udevice *dev; -	for (uclass_first_device_check(UCLASS_BLK, &dev); -	     dev; +	for (uclass_first_device_check(UCLASS_BLK, &dev); dev;  	     uclass_next_device_check(&dev)) {  		struct blk_desc *desc = dev_get_uclass_platdata(dev);  		const char *if_typename = blk_get_if_type_name(desc->if_type); -		printf("Scanning disk %s...\n", dev->name); -  		/* Add block device for the full device */ -		disk = efi_disk_add_dev(NULL, NULL, if_typename, -					desc, desc->devnum, 0, 0); -		if (!disk) -			return -ENOMEM; +		printf("Scanning disk %s...\n", dev->name); +		ret = efi_disk_add_dev(NULL, NULL, if_typename, +					desc, desc->devnum, 0, 0, &disk); +		if (ret == EFI_NOT_READY) { +			printf("Disk %s not ready\n", dev->name); +			continue; +		} +		if (ret) { +			printf("ERROR: failure to add disk device %s, r = %lu\n", +			       dev->name, ret & ~EFI_ERROR_MASK); +			return ret; +		}  		disks++;  		/* Partitions show up as block devices in EFI */ @@ -404,10 +414,17 @@ int efi_disk_register(void)  				 if_typename, i);  			/* Add block device for the full device */ -			disk = efi_disk_add_dev(NULL, NULL, if_typename, desc, -						i, 0, 0); -			if (!disk) -				return -ENOMEM; +			ret = efi_disk_add_dev(NULL, NULL, if_typename, desc, +					       i, 0, 0, &disk); +			if (ret == EFI_NOT_READY) { +				printf("Disk %s not ready\n", devname); +				continue; +			} +			if (ret) { +				printf("ERROR: failure to add disk device %s, r = %lu\n", +				       devname, ret & ~EFI_ERROR_MASK); +				return ret; +			}  			disks++;  			/* Partitions show up as block devices in EFI */ @@ -419,5 +436,5 @@ int efi_disk_register(void)  #endif  	printf("Found %d disks\n", disks); -	return 0; +	return EFI_SUCCESS;  } diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 9d2214b481c..cac64ba9fec 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -94,7 +94,7 @@ static void efi_set_code_and_data_type(  		loaded_image_info->image_data_type = EFI_BOOT_SERVICES_DATA;  		break;  	case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: -	case IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER: +	case IMAGE_SUBSYSTEM_EFI_ROM:  		loaded_image_info->image_code_type = EFI_RUNTIME_SERVICES_CODE;  		loaded_image_info->image_data_type = EFI_RUNTIME_SERVICES_DATA;  		break; diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 8104e08c466..ccb4fc6141b 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -381,6 +381,32 @@ static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void)  	return EFI_INVALID_PARAMETER;  } +efi_status_t __efi_runtime EFIAPI efi_update_capsule( +			struct efi_capsule_header **capsule_header_array, +			efi_uintn_t capsule_count, +			u64 scatter_gather_list) +{ +	return EFI_UNSUPPORTED; +} + +efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps( +			struct efi_capsule_header **capsule_header_array, +			efi_uintn_t capsule_count, +			u64 maximum_capsule_size, +			u32 reset_type) +{ +	return EFI_UNSUPPORTED; +} + +efi_status_t __efi_runtime EFIAPI efi_query_variable_info( +			u32 attributes, +			u64 maximum_variable_storage_size, +			u64 remaining_variable_storage_size, +			u64 maximum_variable_size) +{ +	return EFI_UNSUPPORTED; +} +  struct efi_runtime_services __efi_runtime_data efi_runtime_services = {  	.hdr = {  		.signature = EFI_RUNTIME_SERVICES_SIGNATURE, @@ -398,4 +424,7 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = {  	.set_variable = efi_set_variable,  	.get_next_high_mono_count = (void *)&efi_device_error,  	.reset_system = &efi_reset_system_boottime, +	.update_capsule = efi_update_capsule, +	.query_capsule_caps = efi_query_capsule_caps, +	.query_variable_info = efi_query_variable_info,  }; diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 90246f78273..c4bdbdf6c05 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -7,8 +7,10 @@  # This file only gets included with CONFIG_EFI_LOADER set, so all  # object inclusion implicitly depends on it -CFLAGS_efi_selftest_miniapp.o := $(CFLAGS_EFI) -Os -ffreestanding -CFLAGS_REMOVE_efi_selftest_miniapp.o := $(CFLAGS_NON_EFI) -Os +CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI) -Os +CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) -Os  obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \  efi_selftest.o \ | 
