aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86/cpu/efi/payload.c9
-rw-r--r--arch/x86/dts/Makefile2
-rw-r--r--arch/x86/lib/bootm.c11
-rw-r--r--arch/x86/lib/zimage.c13
-rw-r--r--common/board_r.c5
-rw-r--r--doc/board/allwinner/index.rst9
-rw-r--r--doc/board/allwinner/sunxi.rst319
-rw-r--r--doc/board/index.rst1
-rw-r--r--doc/develop/uefi/u-boot_on_efi.rst6
-rw-r--r--drivers/serial/serial_efi.c11
-rw-r--r--include/configs/efi-x86_app.h25
-rw-r--r--include/efi.h57
-rw-r--r--include/efi_api.h15
-rw-r--r--include/init.h7
-rw-r--r--include/tee.h1
-rw-r--r--lib/Kconfig2
-rw-r--r--lib/efi/efi.c29
-rw-r--r--lib/efi/efi_app.c223
-rw-r--r--lib/efi/efi_stub.c36
-rw-r--r--lib/efi_loader/efi_variable_tee.c16
-rw-r--r--lib/vsprintf.c9
21 files changed, 741 insertions, 65 deletions
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c
index 3a9f7d7..04ce188 100644
--- a/arch/x86/cpu/efi/payload.c
+++ b/arch/x86/cpu/efi/payload.c
@@ -7,6 +7,7 @@
#include <common.h>
#include <cpu_func.h>
#include <efi.h>
+#include <efi_api.h>
#include <errno.h>
#include <init.h>
#include <log.h>
@@ -296,8 +297,14 @@ void setup_efi_info(struct efi_info *efi_info)
void efi_show_bdinfo(void)
{
struct efi_entry_systable *table = NULL;
+ struct efi_system_table *sys_table;
int size, ret;
ret = efi_info_get(EFIET_SYS_TABLE, (void **)&table, &size);
- bdinfo_print_num_l("efi_table", (ulong)table);
+ if (!ret) {
+ bdinfo_print_num_l("efi_table", table->sys_table);
+ sys_table = (struct efi_system_table *)(uintptr_t)
+ table->sys_table;
+ bdinfo_print_num_l(" revision", sys_table->fw_revision);
+ }
}
diff --git a/arch/x86/dts/Makefile b/arch/x86/dts/Makefile
index be209aa..5c8c05e 100644
--- a/arch/x86/dts/Makefile
+++ b/arch/x86/dts/Makefile
@@ -24,7 +24,7 @@ dtb-y += bayleybay.dtb \
targets += $(dtb-y)
-DTC_FLAGS += -R 4 -p 0x1000
+DTC_FLAGS += -R 4 -p $(if $(CONFIG_EFI_APP),0x8000,0x1000)
PHONY += dtbs
dtbs: $(addprefix $(obj)/, $(dtb-y))
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c
index 667e5e6..57cba5c 100644
--- a/arch/x86/lib/bootm.c
+++ b/arch/x86/lib/bootm.c
@@ -179,10 +179,14 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit)
* U-Boot is setting them up that way for itself in
* arch/i386/cpu/cpu.c.
*
- * Note that we cannot currently boot a kernel while running as
- * an EFI application. Please use the payload option for that.
+ * Note: this is incomplete for EFI kernels!
+ *
+ * This can boot a kernel while running as an EFI application,
+ * but if the kernel requires EFI support then that support needs
+ * to be enabled first (see EFI_LOADER). Also the EFI information
+ * must enabled with setup_efi_info(). See setup_zimage() for
+ * how this is done with the stub.
*/
-#ifndef CONFIG_EFI_APP
__asm__ __volatile__ (
"movl $0, %%ebp\n"
"cli\n"
@@ -191,7 +195,6 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit)
[boot_params] "S"(setup_base),
"b"(0), "D"(0)
);
-#endif
}
/* We can't get to here */
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
index 7ce0222..9cc0449 100644
--- a/arch/x86/lib/zimage.c
+++ b/arch/x86/lib/zimage.c
@@ -365,11 +365,14 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
strcpy(cmd_line, (char *)cmdline_force);
else
build_command_line(cmd_line, auto_boot);
- ret = bootm_process_cmdline(cmd_line, max_size, BOOTM_CL_ALL);
- if (ret) {
- printf("Cmdline setup failed (max_size=%x, bootproto=%x, err=%d)\n",
- max_size, bootproto, ret);
- return ret;
+ if (IS_ENABLED(CONFIG_CMD_BOOTM)) {
+ ret = bootm_process_cmdline(cmd_line, max_size,
+ BOOTM_CL_ALL);
+ if (ret) {
+ printf("Cmdline setup failed (max_size=%x, bootproto=%x, err=%d)\n",
+ max_size, bootproto, ret);
+ return ret;
+ }
}
printf("Kernel command line: \"");
puts(cmd_line);
diff --git a/common/board_r.c b/common/board_r.c
index 6d52066..760c2d0 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -841,9 +841,8 @@ void board_init_r(gd_t *new_gd, ulong dest_addr)
* TODO(sjg@chromium.org): Consider doing this for all archs, or
* dropping the new_gd parameter.
*/
-#if CONFIG_IS_ENABLED(X86_64)
- arch_setup_gd(new_gd);
-#endif
+ if (CONFIG_IS_ENABLED(X86_64) && !IS_ENABLED(CONFIG_EFI_APP))
+ arch_setup_gd(new_gd);
#ifdef CONFIG_NEEDS_MANUAL_RELOC
int i;
diff --git a/doc/board/allwinner/index.rst b/doc/board/allwinner/index.rst
new file mode 100644
index 0000000..7352ccd
--- /dev/null
+++ b/doc/board/allwinner/index.rst
@@ -0,0 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Allwinner (sunxi) boards
+========================
+
+.. toctree::
+ :maxdepth: 2
+
+ sunxi
diff --git a/doc/board/allwinner/sunxi.rst b/doc/board/allwinner/sunxi.rst
new file mode 100644
index 0000000..797222d
--- /dev/null
+++ b/doc/board/allwinner/sunxi.rst
@@ -0,0 +1,319 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (C) 2021 Arm Ltd.
+
+Allwinner SoC based boards
+==========================
+For boards using an Allwinner ARM based SoC ("sunxi"), the U-Boot build
+system generates a single integrated image file: ``u-boot-sunxi-with-spl.bin.``
+This file can be used on SD cards, eMMC devices, SPI flash and for the
+USB-OTG based boot method (FEL). To build this file:
+
+* For 64-bit SoCs, build Trusted Firmware (TF-A, formerly known as ATF) first,
+ you will need its ``bl31.bin``. See below for more details.
+* Optionally on 64-bit SoCs, build the `crust`_ management processor firmware,
+ you will need its ``scp.bin``. See below for more details.
+* Build U-Boot::
+
+ $ export BL31=/path/to/bl31.bin # required for 64-bit SoCs
+ $ export SCP=/path/to/scp.bin # optional for some 64-bit SoCs
+ $ make <yourboardname>_defconfig
+ $ make
+* Transfer to an (micro)SD card (see below for more details)::
+
+ $ sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=8k seek=1
+* Boot and enjoy!
+
+.. note::
+ The traditional SD card location the Allwinner BootROM loads from is 8KB
+ (sector 16). This works fine with the old MBR partitioning scheme, which most
+ SD cards come formatted with. However this is in the middle of a potential
+ GPT partition table, which will become invalid in this step. Newer SoCs
+ (starting with the H3 from late 2014) also support booting from 128KB, which
+ is beyond even a GPT and thus a safer location.
+
+For more details, and alternative boot locations or installations, see below.
+
+Building Arm Trusted Firmware (TF-A)
+------------------------------------
+Boards using a 64-bit Soc (A64, H5, H6, H616, R329) require the BL31 stage of
+the `Arm Trusted Firmware-A`_ firmware. This provides the reference
+implementation of secure software for Armv8-A, offering PSCI and SMCCC
+services. Allwinner support is fully mainlined. To build bl31.bin::
+
+ $ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+ $ cd trusted-firmware-a
+ $ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sun50i_a64 DEBUG=1
+ $ export BL31=$(pwd)/build/sun50i_a64/debug/bl31.bin
+
+The target platform (``PLAT=``) for A64 and H5 SoCs is sun50i_a64, for the H6
+sun50i_h6, for the H616 sun50i_h616, and for the R329 sun50i_r329. Use::
+
+ $ find plat/allwinner -name platform.mk
+
+to find all supported platforms. TF-A's `docs/plat/allwinner.rst`_ contains
+more information and lists some build options.
+
+Building the Crust management processor firmware
+------------------------------------------------
+For some SoCs and boards, the integrated OpenRISC management controller can
+be used to provide power management services, foremost suspend to RAM.
+There is a community supported Open Source implementation called `crust`_,
+which runs on most SoCs featuring a management controller.
+
+This firmware part is optional, setting the SCP environment variable to
+/dev/null avoids the warning message when building without one.
+
+To build crust's scp.bin, you need an OpenRISC (or1k) cross compiler, then::
+
+ $ git clone https://github.com/crust-firmware/crust.git
+ $ cd crust
+ $ make <yourboard>_defconfig
+ $ make CROSS_COMPILE=or1k-none-elf- scp
+ $ export SCP=$(pwd)/build/scp/scp.bin
+
+Find a list of supported board configurations in the `configs/`_ directory.
+The `crust README`_ has more information about the building process, including
+information about where to get OpenRISC cross compilers.
+
+Building the U-Boot image
+-------------------------
+Find the U-Boot defconfig file for your board first. Those files live in
+the ``configs/`` directory; you can grep for the stub name of the devicetree
+file, if you know that, or for the SoC name to find the right version::
+
+ $ git grep -l MACH_SUN8I_H3 configs
+ $ git grep -l sun50i-h6-orangepi-3 configs
+
+The `linux-sunxi`_ wiki also lists the name of the defconfig file in the
+respective board page. Then use this defconfig file to create the .config
+file, and build the image::
+
+ $ make <yourboard>_defconfig
+ $ make
+
+For 64-bit boards, this requires either the BL31 environment variable to be
+set (as shown above in the TF-A build example), or it to be supplied on the
+build command line::
+
+ $ make BL31=/src/tf-a.git/build/sun50i_h616/debug/bl31.bin
+
+The same applies to the (optional) SCP firmware.
+
+The file containing everything you need is called ``u-boot-sunxi-with-spl.bin``,
+you will find it in the root folder of your U-Boot (build) tree. Except for
+raw NAND flash devices this very same file can be used for any boot source.
+It will contain the SPL image, fitted with the proper signature recognised by
+the BROM, and the required checksum. Also it will contain at least U-Boot
+proper, either wrapped in the legacy U-Boot image format, or in a FIT image.
+The board's devicetree is also included, either appended to the U-Boot proper
+image, or contained in the FIT image. If required by the SoC, this FIT file will
+also include the other firmware images.
+
+Installing U-Boot
+-----------------
+
+Installing on a (micro-) SD card
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+All Allwinner SoCs will try to find a boot image at sector 16 (8KB) of
+an SD card, connected to the first MMC controller. To transfer the generated
+image to an SD card, from any Linux device (including the board itself) with
+an (micro-)SD card reader, type::
+
+ $ sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1k seek=8
+
+``/dev/sdx`` needs to be replaced with the block device name of the SD card
+reader. On some machines this could be ``/dev/mmcblkX``.
+Newer SoCs (starting from the H3 from 2014, and including all ARM64 SoCs),
+also look at sector 256 (128KB) for the signature (after having checked the
+8KB location). Installing the firmware there has the advantage of not
+overlapping with a GPT partition table. Simply replace the "``seek=8``" above
+with "``seek=128``".
+
+You can also use an existing (mainline) U-Boot to write to the SD card. Load
+the generated U-Boot image somewhere into DRAM (via ``ext4load``, ``fatload``,
+or ``tftpboot``), then write to MMC device 0::
+
+ => fatload mmc 0:1 $kernel_addr_r u-boot-sunxi-with-spl.bin
+ => mmc dev 0
+ => mmc write $kernel_addr_r 0x10 0x7f0
+
+To use the alternative boot location on newer SoCs::
+
+ => mmc write $kernel_addr_r 0x100 0x700
+
+Installing on eMMC (on-board flash memory)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Some boards have a soldered eMMC chip, some other boards have an eMMC socket
+to receive an optional eMMC module. U-Boot can be installed to those chips,
+to boot without an SD card inserted. The Boot-ROM can boot either from the
+regular user data partition, or from one of the separate eMMC boot partitions.
+U-Boot can be installed either from a running Linux instance on the device,
+from a running (mainline) U-Boot, or via an adapter for the (removable)
+eMMC module.
+
+Installing on an eMMC user data partition from Linux
+````````````````````````````````````````````````````
+If you have a running Linux instance on the device, and have somehow copied
+over the image file to that device, you can write the image directly into the
+eMMC device from there.
+Find the name of the block device file first, it is one of the
+``/dev/mmcblk<X>`` devices. eMMC devices typically also list a
+``/dev/mmcblk<X>boot0`` partition (see below), this helps you to tell it apart
+from the SD card device.
+To install onto the user data partition::
+
+ $ sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/dev/mmcblkX bs=1k seek=8
+
+Similar to SD cards, the BROM in newer SoCs (H3 and above) also checks
+sector 256 of an eMMC, so you can use "``seek=128``" as well. Having a GPT
+on an eMMC device is much more likely than on an SD card, so you should
+probably stick to the alternative location, or use one of the boot partitions.
+
+Installing on an eMMC boot partition from Linux
+```````````````````````````````````````````````
+In the following examples, ``/dev/mmcblkX`` needs to be replaced with the block
+device name of the eMMC device. The eMMC device can be recognised by also
+listing the boot partitions (``/dev/mmcblkXboot0``) in ``/proc/partitions``.
+
+To allow booting from one of the eMMC boot partitions, this one needs to be
+enabled first. This only needs to be done once, as this setting is
+persistent, even though the boot partition can be disabled or changed again
+any time later::
+
+ # apt-get install mmc-utils
+ # mmc bootbus set single_hs x1 x4 /dev/mmcblkX
+ # mmc bootpart enable 1 1 /dev/mmcblkX
+
+The first "1" in the last command points to the boot partition number to be
+used, typically devices offer two boot partitions.
+
+By default Linux disables write access to the boot partitions, to prevent
+accidental overwrites. You need to disable the write protection (until the
+next reboot), then can write the U-Boot image to the *first* sector of the
+selected boot partition::
+
+ # echo 0 > /sys/block/mmcblkXboot0/force_ro
+ # dd if=u-boot-sunxi-with-spl.bin of=/dev/mmcblkXboot0 bs=1k
+
+Installing on an eMMC user data partition from U-Boot
+`````````````````````````````````````````````````````
+You can also write the generated image file to an SD card, boot the device
+from there, and burn the very same image to the eMMC device from U-Boot.
+The following commands copy the image from the SD card to the eMMC device::
+
+ => mmc dev 0
+ => mmc read $kernel_addr_r 0x10 0x7f0
+ => mmc dev 1
+ => mmc write $kernel_addr_r 0x10 0x7f0
+
+You can also copy an image from the 8K offset of an SD card to the 128K
+offset of the eMMC (or any combination), just change the "``0x10 0x7f0``" above
+to "``0x100 0x700``", respectively. Of course the image file can be loaded via
+any other loading method, including ``fatload``, ``ext4load``, ``tftpboot``.
+
+Installing on an eMMC boot partition from U-Boot
+````````````````````````````````````````````````
+The selected eMMC boot partition needs to be initially enabled first (same
+as in Linux above), you can do this from U-Boot with::
+
+ => mmc dev 1
+ => mmc bootbus 1 1 0 0
+ => mmc partconf 1 1 1 1
+
+The first "1" in both commands denotes the MMC device number. The second "1"
+in the partconf command sets the required ``BOOT_ACK`` option, the last two "1"s
+selects the active boot partition and the target for the next data access,
+respectively. So for the next "``mmc write``" command to address one of the boot
+partitions, the last number must either be "1" or "2", "0" would switch (back)
+to the normal user data partition.
+
+Then load the ``u-boot-sunxi-with-spl.bin`` image file into DRAM, either by
+reading directly from an SD card or eMMC user data partition, or from a
+file system or TFTP (see above), and transfer it to the boot partition::
+
+ => tftpboot $kernel_addr_r u-boot-sunxi-with-spl.bin
+ => mmc write $kernel_addr_r 0 0x7f0
+
+After that the device should boot from the selected boot partition, which takes
+precedence over booting from the user data partition.
+
+Installing on SPI flash
+^^^^^^^^^^^^^^^^^^^^^^^
+Some devices have a SPI NOR flash chip soldered on the board. If it is
+connected to the SPI0 pins on PortC, the BROM can also boot from there.
+Typically the SPI flash has the lowest boot priority, so SD card and eMMC
+devices will be considered first.
+
+Installing on SPI flash from Linux
+``````````````````````````````````
+If the devicetree enables and describes the SPI flash device, you can access
+the SPI flash content from Linux, using the `MTD utils`_::
+
+ # apt-get install mtd-utils
+ # mtdinfo
+ # mtd_debug erase /dev/mtdX 0 0xf0000
+ # mtd_debug write /dev/mtdX 0 0xf0000 u-boot-sunxi-with-spl.bin
+
+``/dev/mtdX`` needs to be replaced with the respective device name, as listed
+in the output of ``mtdinfo``.
+
+Installing on SPI flash from U-Boot
+```````````````````````````````````
+If SPI flash driver and command support (``CONFIG_CMD_SF``) is enabled in the
+U-Boot configuration, the image file can be installed via U-Boot as well::
+
+ => tftpboot $kernel_addr_r u-boot-sunxi-with-spl.bin
+ => sf probe
+ => sf erase 0 +0xf0000
+ => sf write $kernel_addr_r 0 $filesize
+
+Installing on SPI flash via USB in FEL mode
+```````````````````````````````````````````
+If the device is in FEL mode (see below), the SPI flash can also be written to
+with the sunxi-fel utility, via an USB(-OTG) cable from any USB host machine::
+
+ $ sunxi-fel spiflash-write 0 u-boot-sunxi-with-spl.bin
+
+Booting via the USB(-OTG) FEL mode
+----------------------------------
+If none of the boot locations checked by the BROM contains a medium or valid
+signature, the BROM will enter the so-called FEL mode, in which it will
+listen to commands from a host on the SoC's USB-OTG interface. Those commands
+allow to read from and write to arbitrary memory locations, also to start
+execution at any address, which allows to bootstrap a board solely via an
+USB cable. Some boards feature a "FEL" or "U-Boot" button, which forces
+FEL mode despite a valid boot location being present. The same can be achieved
+via a `magic binary`_ on an SD card, which allows to enter FEL mode on any
+board.
+
+To use FEL booting, let the board enter FEL mode, via any of the mentioned
+methods (no boot media, FEL button, SD card with FEL binary), then connect
+a USB cable to the board's USB OTG port. Some boards (Pine64, TV boxes) don't
+have a separate OTG port. In this case mostly one of the USB-A ports is
+connected to USB0, and can be used via a non-standard USB-A to USB-A cable.
+
+Typically there is no on-board indication of FEL mode, other than a new USB
+device appearing on the connected host computer. The USB vendor/device ID
+is 1f3a:efe8. Mostly this will identify as "sunxi SoC OTG connector in
+FEL/flashing mode", but older distributions might still report "Onda
+(unverified) V972 tablet in flashing mode".
+
+The `sunxi_fel`_ tool implements the proprietary BROM protocol, and allows to
+bootstrap U-Boot by just providing our venerable u-boot-sunxi-with-spl.bin::
+
+ $ sudo apt-get install sunxi-tools
+ $ sunxi-fel uboot u-boot-sunxi-with-spl.bin
+
+Additional binaries like a kernel, an initial ramdisk or a boot script, can
+also be uploaded via FEL, check the Wiki's `FEL page`_ for more details.
+
+.. _`Arm Trusted Firmware-A`: https://www.trustedfirmware.org/projects/tf-a/
+.. _`docs/plat/allwinner.rst`: https://trustedfirmware-a.readthedocs.io/en/latest/plat/allwinner.html
+.. _`crust`: https://github.com/crust-firmware/crust
+.. _`configs/`: https://github.com/crust-firmware/crust/tree/master/configs
+.. _`crust README`: https://github.com/crust-firmware/crust/blob/master/README.md#building-the-firmware
+.. _`linux-sunxi`: https://linux-sunxi.org
+.. _`MTD utils`: http://www.linux-mtd.infradead.org/
+.. _`magic binary`: https://github.com/linux-sunxi/sunxi-tools/raw/master/bin/fel-sdboot.sunxi
+.. _`sunxi_fel`: https://github.com/linux-sunxi/sunxi-tools
+.. _`FEL page`: https://linux-sunxi.org/FEL/USBBoot
diff --git a/doc/board/index.rst b/doc/board/index.rst
index 13f4db8..0a02fec 100644
--- a/doc/board/index.rst
+++ b/doc/board/index.rst
@@ -9,6 +9,7 @@ Board-specific doc
actions/index
advantech/index
AndesTech/index
+ allwinner/index
amlogic/index
apple/index
atmel/index
diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst
index 5f2f850..acad639 100644
--- a/doc/develop/uefi/u-boot_on_efi.rst
+++ b/doc/develop/uefi/u-boot_on_efi.rst
@@ -265,13 +265,11 @@ 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. 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.
+- Add more drivers to the application side (e.g.USB, environment access).
- 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.
+ though. It is better to use the app.
Where is the code?
------------------
diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c
index 33ddbd6..0067576 100644
--- a/drivers/serial/serial_efi.c
+++ b/drivers/serial/serial_efi.c
@@ -24,6 +24,9 @@ struct serial_efi_priv {
bool have_key;
};
+/* Convert a lower-case character to its ctrl-char equivalent */
+#define CTL_CH(c) ((c) - 'a' + 1)
+
int serial_efi_setbrg(struct udevice *dev, int baudrate)
{
return 0;
@@ -49,6 +52,7 @@ static int serial_efi_get_key(struct serial_efi_priv *priv)
static int serial_efi_getc(struct udevice *dev)
{
struct serial_efi_priv *priv = dev_get_priv(dev);
+ char conv_scan[10] = {0, 'p', 'n', 'f', 'b', 'a', 'e', 0, 8};
int ret, ch;
ret = serial_efi_get_key(priv);
@@ -63,8 +67,11 @@ static int serial_efi_getc(struct udevice *dev)
* key scan code of 8. Handle this so that backspace works correctly
* in the U-Boot command line.
*/
- if (!ch && priv->key.scan_code == 8)
- ch = 8;
+ if (!ch && priv->key.scan_code < sizeof(conv_scan)) {
+ ch = conv_scan[priv->key.scan_code];
+ if (ch >= 'a')
+ ch -= 'a' - 1;
+ }
debug(" [%x %x %x] ", ch, priv->key.unicode_char, priv->key.scan_code);
return ch;
diff --git a/include/configs/efi-x86_app.h b/include/configs/efi-x86_app.h
index 6061a6d..33afb7c 100644
--- a/include/configs/efi-x86_app.h
+++ b/include/configs/efi-x86_app.h
@@ -10,8 +10,33 @@
#undef CONFIG_TPM_TIS_BASE_ADDRESS
+/*
+ * Select the output device: Put an 'x' prefix before one of these to disable it
+ */
+
+/*
+ * Video output - can normally continue after exit_boot_services has been
+ * called, since output to the display does not require EFI services at that
+ * point. U-Boot sets up the console memory and does its own drawing.
+ */
#define CONFIG_STD_DEVICES_SETTINGS "stdin=serial\0" \
"stdout=vidconsole\0" \
"stderr=vidconsole\0"
+/*
+ * Serial output with no console. Run qemu with:
+ *
+ * -display none -serial mon:stdio
+ *
+ * This will hang or fail to output on the console after exit_boot_services is
+ * called.
+ */
+#define xCONFIG_STD_DEVICES_SETTINGS "stdin=serial\0" \
+ "stdout=serial\0" \
+ "stderr=serial\0"
+
+#undef CONFIG_BOOTCOMMAND
+
+#define CONFIG_BOOTCOMMAND "part list efi 0; fatls efi 0:1"
+
#endif
diff --git a/include/efi.h b/include/efi.h
index 0ec5913..877a2e5 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -321,7 +321,7 @@ struct efi_info_hdr {
* struct efi_entry_hdr - Header for a table entry
*
* @type: enum eft_entry_t
- * @size size of entry bytes excluding header and padding
+ * @size: size of entry bytes excluding header and padding
* @addr: address of this entry (0 if it follows the header )
* @link: size of entry including header and padding
* @spare1: Spare space for expansion
@@ -400,15 +400,37 @@ static inline struct efi_mem_desc *efi_get_next_mem_desc(
return (struct efi_mem_desc *)((ulong)desc + map->desc_size);
}
+/**
+ * struct efi_priv - Information about the environment provided by EFI
+ *
+ * @parent_image: image passed into the EFI app or stub
+ * @sys_table: Pointer to system table
+ * @boot: Pointer to boot-services table
+ * @run: Pointer to runtime-services table
+ *
+ * @use_pool_for_malloc: true if all allocation should go through the EFI 'pool'
+ * methods allocate_pool() and free_pool(); false to use 'pages' methods
+ * allocate_pages() and free_pages()
+ * @ram_base: Base address of RAM (size CONFIG_EFI_RAM_SIZE)
+ * @image_data_type: Type of the loaded image (e.g. EFI_LOADER_CODE)
+ *
+ * @info: Header of the info list, holding info collected by the stub and passed
+ * to U-Boot
+ * @info_size: Size of the info list @info in bytes
+ * @next_hdr: Pointer to where to put the next header when adding to the list
+ */
struct efi_priv {
efi_handle_t parent_image;
- struct efi_device_path *device_path;
struct efi_system_table *sys_table;
struct efi_boot_services *boot;
struct efi_runtime_services *run;
+
+ /* app: */
bool use_pool_for_malloc;
unsigned long ram_base;
unsigned int image_data_type;
+
+ /* stub: */
struct efi_info_hdr *info;
unsigned int info_size;
void *next_hdr;
@@ -419,10 +441,12 @@ struct efi_priv {
*
* @handle: handle of the controller on which this driver is installed
* @blkio: block io protocol proxied by this driver
+ * @device_path: EFI path to the device
*/
struct efi_media_plat {
- efi_handle_t handle;
- struct efi_block_io *blkio;
+ efi_handle_t handle;
+ struct efi_block_io *blkio;
+ struct efi_device_path *device_path;
};
/* Base address of the EFI image */
@@ -451,6 +475,27 @@ extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[];
EFI_VARIABLE_APPEND_WRITE)
/**
+ * efi_get_priv() - Get access to the EFI-private information
+ *
+ * This struct it used by both the stub and the app to record things about the
+ * EFI environment. It is not available in U-Boot proper after the stub has
+ * jumped there. Use efi_info_get() to obtain info in that case.
+ *
+ * Return: pointer to private info
+ */
+struct efi_priv *efi_get_priv(void);
+
+/**
+ * efi_set_priv() - Set up a pointer to the EFI-private information
+ *
+ * This is called in the stub and app to record the location of this
+ * information.
+ *
+ * @priv: New location of private data
+ */
+void efi_set_priv(struct efi_priv *priv);
+
+/**
* efi_get_sys_table() - Get access to the main EFI system table
*
* @return pointer to EFI system table
@@ -521,6 +566,10 @@ void efi_putc(struct efi_priv *priv, const char ch);
/**
* efi_info_get() - get an entry from an EFI table
*
+ * This function is called from U-Boot proper to read information set up by the
+ * EFI stub. It can only be used when running from the EFI stub, not when U-Boot
+ * is running as an app.
+ *
* @type: Entry type to search for
* @datap: Returns pointer to entry data
* @sizep: Returns pointer to entry size
diff --git a/include/efi_api.h b/include/efi_api.h
index 80109f0..ec9fa89 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -2035,4 +2035,19 @@ struct efi_firmware_management_protocol {
const u16 *package_version_name);
};
+#define EFI_DISK_IO_PROTOCOL_GUID \
+ EFI_GUID(0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, \
+ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+
+struct efi_disk {
+ u64 revision;
+ efi_status_t (EFIAPI *read_disk)(struct efi_disk *this, u32 media_id,
+ u64 offset, efi_uintn_t buffer_size,
+ void *buffer);
+
+ efi_status_t (EFIAPI *write_disk)(struct efi_disk *this, u32 media_id,
+ u64 offset, efi_uintn_t buffer_size,
+ void *buffer);
+};
+
#endif
diff --git a/include/init.h b/include/init.h
index f2cd46d..dcd682c 100644
--- a/include/init.h
+++ b/include/init.h
@@ -14,8 +14,11 @@
#include <linux/types.h>
-/* Avoid using CONFIG_EFI_STUB directly as we may boot from other loaders */
-#ifdef CONFIG_EFI_STUB
+/*
+ * In case of the EFI app the UEFI firmware provides the low-level
+ * initialisation.
+ */
+#ifdef CONFIG_EFI
#define ll_boot_init() false
#else
#include <asm/global_data.h>
diff --git a/include/tee.h b/include/tee.h
index 5005149..13f6096 100644
--- a/include/tee.h
+++ b/include/tee.h
@@ -58,6 +58,7 @@
#define TEE_SUCCESS 0x00000000
#define TEE_ERROR_STORAGE_NOT_AVAILABLE 0xf0100003
#define TEE_ERROR_GENERIC 0xffff0000
+#define TEE_ERROR_EXCESS_DATA 0xffff0004
#define TEE_ERROR_BAD_PARAMETERS 0xffff0006
#define TEE_ERROR_ITEM_NOT_FOUND 0xffff0008
#define TEE_ERROR_NOT_IMPLEMENTED 0xffff0009
diff --git a/lib/Kconfig b/lib/Kconfig
index 10ba086..1883ac7 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -52,7 +52,7 @@ config CC_OPTIMIZE_LIBS_FOR_SPEED
config CHARSET
bool
- default y if UT_UNICODE || EFI_LOADER || UFS
+ default y if UT_UNICODE || EFI_LOADER || UFS || EFI_APP
help
Enables support for various conversions between different
character sets, such as between unicode representations and
diff --git a/lib/efi/efi.c b/lib/efi/efi.c
index 69e52e4..cd6bf47 100644
--- a/lib/efi/efi.c
+++ b/lib/efi/efi.c
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
+ * Functions shared by the app and stub
+ *
* Copyright (c) 2015 Google, Inc
*
* EFI information obtained here:
@@ -17,6 +19,33 @@
#include <efi.h>
#include <efi_api.h>
+static struct efi_priv *global_priv;
+
+struct efi_priv *efi_get_priv(void)
+{
+ return global_priv;
+}
+
+void efi_set_priv(struct efi_priv *priv)
+{
+ global_priv = priv;
+}
+
+struct efi_system_table *efi_get_sys_table(void)
+{
+ return global_priv->sys_table;
+}
+
+struct efi_boot_services *efi_get_boot(void)
+{
+ return global_priv->boot;
+}
+
+unsigned long efi_get_ram_base(void)
+{
+ return global_priv->ram_base;
+}
+
/*
* Global declaration of gd.
*
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c
index f616656..d60f2f6 100644
--- a/lib/efi/efi_app.c
+++ b/lib/efi/efi_app.c
@@ -21,29 +21,58 @@
#include <efi.h>
#include <efi_api.h>
#include <sysreset.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
-static struct efi_priv *global_priv;
-
-struct efi_system_table *efi_get_sys_table(void)
+int efi_info_get(enum efi_entry_t type, void **datap, int *sizep)
{
- return global_priv->sys_table;
+ return -ENOSYS;
}
-struct efi_boot_services *efi_get_boot(void)
+/**
+ * efi_bind_block() - bind a new block device to an EFI device
+ *
+ * Binds a new top-level EFI_MEDIA device as well as a child block device so
+ * that the block device can be accessed in U-Boot.
+ *
+ * The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
+ * for example, just like any other interface type.
+ *
+ * @handle: handle of the controller on which this driver is installed
+ * @blkio: block io protocol proxied by this driver
+ * @device_path: EFI device path structure for this
+ * @len: Length of @device_path in bytes
+ * @devp: Returns the bound device
+ * @return 0 if OK, -ve on error
+ */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio,
+ struct efi_device_path *device_path, int len,
+ struct udevice **devp)
{
- return global_priv->boot;
-}
+ struct efi_media_plat plat;
+ struct udevice *dev;
+ char name[18];
+ int ret;
-unsigned long efi_get_ram_base(void)
-{
- return global_priv->ram_base;
-}
+ plat.handle = handle;
+ plat.blkio = blkio;
+ plat.device_path = malloc(device_path->length);
+ if (!plat.device_path)
+ return log_msg_ret("path", -ENOMEM);
+ memcpy(plat.device_path, device_path, device_path->length);
+ ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
+ &plat, ofnode_null(), &dev);
+ if (ret)
+ return log_msg_ret("bind", ret);
-int efi_info_get(enum efi_entry_t type, void **datap, int *sizep)
-{
- return -ENOSYS;
+ snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
+ device_set_name(dev, name);
+ *devp = dev;
+
+ return 0;
}
static efi_status_t setup_memory(struct efi_priv *priv)
@@ -77,13 +106,14 @@ static efi_status_t setup_memory(struct efi_priv *priv)
ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
priv->image_data_type, pages, &addr);
if (ret) {
- printf("(using pool %lx) ", ret);
+ log_info("(using pool %lx) ", ret);
priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE,
&ret);
if (!priv->ram_base)
return ret;
priv->use_pool_for_malloc = true;
} else {
+ log_info("(using allocated RAM address %lx) ", (ulong)addr);
priv->ram_base = addr;
}
gd->ram_size = pages << 12;
@@ -91,6 +121,14 @@ static efi_status_t setup_memory(struct efi_priv *priv)
return 0;
}
+/**
+ * free_memory() - Free memory used by the U-Boot app
+ *
+ * This frees memory allocated in setup_memory(), in preparation for returning
+ * to UEFI. It also zeroes the global_data pointer.
+ *
+ * @priv: Private EFI data
+ */
static void free_memory(struct efi_priv *priv)
{
struct efi_boot_services *boot = priv->boot;
@@ -106,6 +144,150 @@ static void free_memory(struct efi_priv *priv)
}
/**
+ * devpath_is_partition() - Figure out if a device path is a partition
+ *
+ * Checks if a device path refers to a partition on some media device. This
+ * works by checking for a valid partition number in a hard-driver media device
+ * as the final component of the device path.
+ *
+ * @path: device path
+ * Return: true if a partition, false if not
+ * (e.g. it might be media which contains partitions)
+ */
+static bool devpath_is_partition(const struct efi_device_path *path)
+{
+ const struct efi_device_path *p;
+ bool was_part;
+
+ for (p = path; p->type != DEVICE_PATH_TYPE_END;
+ p = (void *)p + p->length) {
+ was_part = false;
+ if (p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
+ p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
+ struct efi_device_path_hard_drive_path *hd =
+ (void *)path;
+
+ if (hd->partition_number)
+ was_part = true;
+ }
+ }
+
+ return was_part;
+}
+
+/**
+ * setup_block() - Find all block devices and setup EFI devices for them
+ *
+ * Partitions are ignored, since U-Boot has partition handling. Errors with
+ * particular devices produce a warning but execution continues to try to
+ * find others.
+ *
+ * Return: 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP
+ * if a required protocol is not supported
+ */
+static int setup_block(void)
+{
+ efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
+ efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
+ efi_guid_t efi_pathutil_guid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
+ efi_guid_t efi_pathtext_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
+ struct efi_boot_services *boot = efi_get_boot();
+ struct efi_device_path_utilities_protocol *util;
+ struct efi_device_path_to_text_protocol *text;
+ struct efi_device_path *path;
+ struct efi_block_io *blkio;
+ efi_uintn_t num_handles;
+ efi_handle_t *handle;
+ int ret, i;
+
+ if (!boot)
+ return log_msg_ret("sys", -ENOSYS);
+
+ /* Find all devices which support the block I/O protocol */
+ ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_blkio_guid, NULL,
+ &num_handles, &handle);
+ if (ret)
+ return log_msg_ret("loc", -ENOTSUPP);
+ log_debug("Found %d handles:\n", (int)num_handles);
+
+ /* We need to look up the path size and convert it to text */
+ ret = boot->locate_protocol(&efi_pathutil_guid, NULL, (void **)&util);
+ if (ret)
+ return log_msg_ret("util", -ENOTSUPP);
+ ret = boot->locate_protocol(&efi_pathtext_guid, NULL, (void **)&text);
+ if (ret)
+ return log_msg_ret("text", -ENOTSUPP);
+
+ for (i = 0; i < num_handles; i++) {
+ struct udevice *dev;
+ const u16 *name;
+ bool is_part;
+ int len;
+
+ ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
+ (void **)&path);
+ if (ret) {
+ log_warning("- devpath %d failed (ret=%d)\n", i, ret);
+ continue;
+ }
+
+ ret = boot->handle_protocol(handle[i], &efi_blkio_guid,
+ (void **)&blkio);
+ if (ret) {
+ log_warning("- blkio %d failed (ret=%d)\n", i, ret);
+ continue;
+ }
+
+ name = text->convert_device_path_to_text(path, true, false);
+ is_part = devpath_is_partition(path);
+
+ if (!is_part) {
+ len = util->get_device_path_size(path);
+ ret = efi_bind_block(handle[i], blkio, path, len, &dev);
+ if (ret) {
+ log_warning("- blkio bind %d failed (ret=%d)\n",
+ i, ret);
+ continue;
+ }
+ } else {
+ dev = NULL;
+ }
+
+ /*
+ * Show the device name if we created one. Otherwise indicate
+ * that it is a partition.
+ */
+ printf("%2d: %-12s %ls\n", i, dev ? dev->name : "<partition>",
+ name);
+ }
+ boot->free_pool(handle);
+
+ return 0;
+}
+
+/**
+ * dm_scan_other() - Scan for UEFI devices that should be available to U-Boot
+ *
+ * This sets up block devices within U-Boot for those found in UEFI. With this,
+ * U-Boot can access those devices
+ *
+ * @pre_reloc_only: true to only bind pre-relocation devices (ignored)
+ * Returns: 0 on success, -ve on error
+ */
+int dm_scan_other(bool pre_reloc_only)
+{
+ if (gd->flags & GD_FLG_RELOC) {
+ int ret;
+
+ ret = setup_block();
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
* efi_main() - Start an EFI image
*
* This function is called by our EFI start-up code. It handles running
@@ -119,9 +301,12 @@ efi_status_t EFIAPI efi_main(efi_handle_t image,
efi_status_t ret;
/* Set up access to EFI data structures */
- efi_init(priv, "App", image, sys_table);
-
- global_priv = priv;
+ ret = efi_init(priv, "App", image, sys_table);
+ if (ret) {
+ printf("Failed to set up U-Boot: err=%lx\n", ret);
+ return ret;
+ }
+ efi_set_priv(priv);
/*
* Set up the EFI debug UART so that printf() works. This is
@@ -147,7 +332,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image,
static void efi_exit(void)
{
- struct efi_priv *priv = global_priv;
+ struct efi_priv *priv = efi_get_priv();
free_memory(priv);
printf("U-Boot EFI exiting\n");
diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c
index b3393e4..c89ae7c 100644
--- a/lib/efi/efi_stub.c
+++ b/lib/efi/efi_stub.c
@@ -31,7 +31,6 @@
#error "This file needs to be ported for use on architectures"
#endif
-static struct efi_priv *global_priv;
static bool use_uart;
struct __packed desctab_info {
@@ -63,6 +62,8 @@ void _debug_uart_init(void)
void putc(const char ch)
{
+ struct efi_priv *priv = efi_get_priv();
+
if (ch == '\n')
putc('\r');
@@ -73,7 +74,7 @@ void putc(const char ch)
;
outb(ch, (ulong)&com_port->thr);
} else {
- efi_putc(global_priv, ch);
+ efi_putc(priv, ch);
}
}
@@ -225,6 +226,22 @@ static int get_codeseg32(void)
return cs32;
}
+/**
+ * setup_info_table() - sets up a table containing information from EFI
+ *
+ * We must call exit_boot_services() before jumping out of the stub into U-Boot
+ * proper, so that U-Boot has full control of peripherals, memory, etc.
+ *
+ * Once we do this, we cannot call any boot-services functions so we must find
+ * out everything we need to before doing that.
+ *
+ * Set up a struct efi_info_hdr table which can hold various records (e.g.
+ * struct efi_entry_memmap) with information obtained from EFI.
+ *
+ * @priv: Pointer to our private information which contains the list
+ * @size: Size of the table to allocate
+ * Return: 0 if OK, non-zero on error
+ */
static int setup_info_table(struct efi_priv *priv, int size)
{
struct efi_info_hdr *info;
@@ -248,6 +265,19 @@ static int setup_info_table(struct efi_priv *priv, int size)
return 0;
}
+/**
+ * add_entry_addr() - Add a new entry to the efi_info list
+ *
+ * This adds an entry, consisting of a tag and two lots of data. This avoids the
+ * caller having to coalesce the data first
+ *
+ * @priv: Pointer to our private information which contains the list
+ * @type: Type of the entry to add
+ * @ptr1: Pointer to first data block to add
+ * @size1: Size of first data block in bytes (can be 0)
+ * @ptr2: Pointer to second data block to add
+ * @size2: Size of second data block in bytes (can be 0)
+ */
static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type,
void *ptr1, int size1, void *ptr2, int size2)
{
@@ -291,7 +321,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image,
puts(" efi_init() failed\n");
return ret;
}
- global_priv = priv;
+ efi_set_priv(priv);
cs32 = get_codeseg32();
if (cs32 < 0)
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 281f886..a2c65e3 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -15,7 +15,6 @@
#include <malloc.h>
#include <mm_communication.h>
-#define OPTEE_PAGE_SIZE BIT(12)
extern struct efi_var_file __efi_runtime_data *efi_var_buf;
static efi_uintn_t max_buffer_size; /* comm + var + func + data */
static efi_uintn_t max_payload_size; /* func + data */
@@ -114,7 +113,11 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
rc = tee_invoke_func(conn.tee, &arg, 2, param);
tee_shm_free(shm);
tee_close_session(conn.tee, conn.session);
- if (rc || arg.ret != TEE_SUCCESS)
+ if (rc)
+ return EFI_DEVICE_ERROR;
+ if (arg.ret == TEE_ERROR_EXCESS_DATA)
+ log_err("Variable payload too large\n");
+ if (arg.ret != TEE_SUCCESS)
return EFI_DEVICE_ERROR;
switch (param[1].u.value.a) {
@@ -256,15 +259,6 @@ efi_status_t EFIAPI get_max_payload(efi_uintn_t *size)
}
*size = var_payload->size;
/*
- * Although the max payload is configurable on StMM, we only share a
- * single page from OP-TEE for the non-secure buffer used to communicate
- * with StMM. Since OP-TEE will reject to map anything bigger than that,
- * make sure we are in bounds.
- */
- if (*size > OPTEE_PAGE_SIZE)
- *size = OPTEE_PAGE_SIZE - MM_COMMUNICATE_HEADER_SIZE -
- MM_VARIABLE_COMMUNICATE_SIZE;
- /*
* There seems to be a bug in EDK2 miscalculating the boundaries and
* size checks, so deduct 2 more bytes to fulfill this requirement. Fix
* it up here to ensure backwards compatibility with older versions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index e634bd7..de9f236 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -276,9 +276,8 @@ static char *string(char *buf, char *end, char *s, int field_width,
}
/* U-Boot uses UTF-16 strings in the EFI context only. */
-#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
-static char *string16(char *buf, char *end, u16 *s, int field_width,
- int precision, int flags)
+static __maybe_unused char *string16(char *buf, char *end, u16 *s,
+ int field_width, int precision, int flags)
{
const u16 *str = s ? s : L"<NULL>";
ssize_t i, len = utf16_strnlen(str, precision);
@@ -317,7 +316,6 @@ static char *device_path_string(char *buf, char *end, void *dp, int field_width,
return buf;
}
#endif
-#endif
static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
int precision, int flags)
@@ -616,7 +614,8 @@ repeat:
case 's':
/* U-Boot uses UTF-16 strings in the EFI context only. */
-#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
+#if (CONFIG_IS_ENABLED(EFI_LOADER) || CONFIG_IS_ENABLED(EFI_APP)) && \
+ !defined(API_BUILD)
if (qualifier == 'l') {
str = string16(str, end, va_arg(args, u16 *),
field_width, precision, flags);