[PATCH v4 00/34] efi: Improvements to U-Boot running on top of UEFI

At present U-Boot can be built as an EFI app, but it is really just for testing, with very few features. Instead, the payload build is used for booting on top of UEFI, where U-Boot takes over the machine immediately and supplies its own drivers.
But the app could be made more useful.
This series provides access to EFI block devices and the video console within U-Boot. It also restructures the app to make it possible to boot a kernel, although further work is needed to implement this.
This can be thought of as making U-Boot perform a little like 'grub', in that it runs purely based on UEFI-provided services.
Of course a lot more work is required, but this is a start.
Note: It would be very useful to include qemu tests of the app and stub in CI.
This is available at u-boot-dm/efi-working
Changes in v4: - Change the patch subject to make it clear this does not build U-Boot - Make EFI_LOADER depend on !EFI_APP - Update commit message to mention that you have to build U-Boot
Changes in v3: - Add new patch to show the system-table revision - Default to 256MB of RAM for U-Boot instead of 32MB - Drop comments that confuse sphinx - Fix 'complicating' typo - Move device_path path change to its own patch - Update minimum RAM to 256MB! - s/qemu/QEMU/
Changes in v2: - Add MAINTAINERS entry - Add a better boot command too - Add a note that EFI_GRAPHICS_OUTPUT_PROTOCOL is used - Add a sentence about what the patch does - Add a work-around to avoid a toolchain crash - Add new patch to drop the OF_EMBED warning for EFI - Add new patch to enable DM_ETH for the app - Add new patch to support the efi command in the app - Add support for creating a partition table with a filesystem inside - Add support for running qemu with just a serial console (no display) - Drop mention of partitions from the commit message - Expand the commit message to make things clearer - Fix 'as' typo - Show the correct interface type with 'part list' - Update documentation - Update the commit message to explain things better - Use log_info() instead of printf()
Simon Glass (34): efi: Add a script to build an image for testing on UEFI efi: Enable DM_ETH for the app efi: Drop the OF_EMBED warning for EFI x86: Create a 32/64-bit selection for the app efi: Create a 64-bit app x86: Don't duplicate global_ptr in 64-bit EFI app efi: Add a way to obtain boot services in the app efi: Add video support to the app efi: Add EFI uclass for media efi: Add a media/block driver for EFI block devices efi: Locate all block devices in the app patman: Use a ValueError exception if tools.Run() fails binman: Report an error if test files fail to compile binman: Support reading the offset of an ELF-file symbol binman: Tidy up comments on _DoTestFile() binman: Support updating the dtb in an ELF file efi: serial: Support arrow keys bloblist: Support allocating the bloblist x86: Allow booting a kernel from the EFI app x86: Don't process the kernel command line unless enabled x86: efi: Add room for the binman definition in the dtb efi: Drop device_path from struct efi_priv efi: Add comments to struct efi_priv efi: Fix ll_boot_init() operation with the app efi: Add a few comments to the stub efi: Share struct efi_priv between the app and stub code efi: Move exit_boot_services into a function efi: Check for failure when initing the app efi: Mention that efi_info_get() is only used in the stub efi: Show when allocated pages are used efi: Allow easy selection of serial-only operation efi: Update efi_get_next_mem_desc() to avoid needing a map efi: Support the efi command in the app efi: Show the system-table revision
MAINTAINERS | 7 + Makefile | 10 +- arch/sandbox/dts/test.dts | 4 + arch/x86/cpu/efi/payload.c | 17 +- arch/x86/cpu/intel_common/Makefile | 2 +- arch/x86/cpu/u-boot-64.lds | 2 + arch/x86/cpu/x86_64/Makefile | 4 + arch/x86/cpu/x86_64/cpu.c | 32 +- arch/x86/cpu/x86_64/misc.c | 41 +++ arch/x86/dts/Makefile | 2 +- arch/x86/dts/efi-x86_app.dts | 4 + arch/x86/lib/bootm.c | 11 +- arch/x86/lib/zimage.c | 13 +- board/efi/Kconfig | 15 +- board/efi/efi-x86_app/Kconfig | 6 +- board/efi/efi-x86_app/MAINTAINERS | 11 +- cmd/Makefile | 2 +- cmd/efi.c | 78 +++-- common/Kconfig | 15 +- common/bloblist.c | 16 +- common/board_f.c | 8 +- ..._app_defconfig => efi-x86_app32_defconfig} | 3 +- configs/efi-x86_app64_defconfig | 38 +++ disk/part.c | 5 +- doc/develop/bloblist.rst | 16 + doc/develop/uefi/u-boot_on_efi.rst | 74 ++++- drivers/block/Kconfig | 33 +++ drivers/block/Makefile | 4 + drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 + drivers/block/efi_blk.c | 115 ++++++++ drivers/block/sb_efi_media.c | 20 ++ drivers/serial/serial_efi.c | 11 +- drivers/video/Kconfig | 2 +- drivers/video/efi.c | 45 ++- include/configs/efi-x86_app.h | 31 +- include/dm/uclass-id.h | 1 + include/efi.h | 121 +++++++- include/efi_api.h | 15 + include/init.h | 2 +- lib/efi/Kconfig | 34 ++- lib/efi/efi.c | 106 +++++++ lib/efi/efi_app.c | 276 +++++++++++++++++- lib/efi/efi_stub.c | 95 +++--- lib/efi_loader/Kconfig | 1 + scripts/build-efi.sh | 193 ++++++++++++ test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++ tools/binman/binman.rst | 36 +++ tools/binman/cmdline.py | 2 + tools/binman/control.py | 11 + tools/binman/elf.py | 74 ++++- tools/binman/elf_test.py | 45 ++- tools/binman/ftest.py | 88 +++++- tools/binman/test/Makefile | 13 +- tools/binman/test/bss_data.c | 2 +- tools/binman/test/embed_data.c | 16 + tools/binman/test/embed_data.lds | 23 ++ tools/binman/test/u_boot_binman_embed.c | 13 + tools/binman/test/u_boot_binman_embed.lds | 29 ++ tools/binman/test/u_boot_binman_embed_sm.c | 13 + tools/patman/tools.py | 2 +- 62 files changed, 1745 insertions(+), 205 deletions(-) create mode 100644 arch/x86/cpu/x86_64/misc.c rename configs/{efi-x86_app_defconfig => efi-x86_app32_defconfig} (94%) create mode 100644 configs/efi-x86_app64_defconfig create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/efi_blk.c create mode 100644 drivers/block/sb_efi_media.c create mode 100755 scripts/build-efi.sh create mode 100644 test/dm/efi_media.c create mode 100644 tools/binman/test/embed_data.c create mode 100644 tools/binman/test/embed_data.lds create mode 100644 tools/binman/test/u_boot_binman_embed.c create mode 100644 tools/binman/test/u_boot_binman_embed.lds create mode 100644 tools/binman/test/u_boot_binman_embed_sm.c

It is quite complicated to run U-Boot on QEMU since we have four different builds and they must use different versions of qemu and the UEFI binaries.
Add a script to help. It requires U-Boot itself to be built. Once that is done you can use this script to build an image for use with qemu and optionally run it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v4: - Change the patch subject to make it clear this does not build U-Boot - Update commit message to mention that you have to build U-Boot
Changes in v3: - Fix 'complicating' typo - s/qemu/QEMU/
Changes in v2: - Add MAINTAINERS entry - Add support for creating a partition table with a filesystem inside - Add support for running qemu with just a serial console (no display)
MAINTAINERS | 1 + doc/develop/uefi/u-boot_on_efi.rst | 62 +++++++++ scripts/build-efi.sh | 193 +++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100755 scripts/build-efi.sh
diff --git a/MAINTAINERS b/MAINTAINERS index 9d8cba90280..fa7fe900705 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -710,6 +710,7 @@ M: Heinrich Schuchardt xypron.glpk@gmx.de S: Maintained W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: lib/efi/efi_app.c +F: scripts/build-efi.sh
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 43afb11de56..8856af3db56 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -98,6 +98,11 @@ 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.
+You may find the script `scripts/build-efi.sh` helpful for building and testing +U-Boot on UEFI on QEMU. It also includes links to UEFI binaries dating from +2021. + +See `Example run`_ for an example run.
Inner workings -------------- @@ -193,6 +198,63 @@ 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.
+Example run +----------- + +This shows running with serial enabled (see `include/configs/efi-x86_app.h`):: + + $ scripts/build-efi.sh -wsPr + Packaging efi-x86_app32 + Running qemu-system-i386 + + BdsDxe: failed to load Boot0001 "UEFI QEMU HARDDISK QM00005 " from PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0): Not Found + BdsDxe: loading Boot0002 "EFI Internal Shell" from Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1) + BdsDxe: starting Boot0002 "EFI Internal Shell" from Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1) + + UEFI Interactive Shell v2.2 + EDK II + UEFI v2.70 (EDK II, 0x00010000) + Mapping table + FS0: Alias(s):HD0a65535a1:;BLK1: + PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0)/HD(1,GPT,0FFD5E61-3B0C-4326-8049-BDCDC910AF72,0x800,0xB000) + BLK0: Alias(s): + PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0) + + Press ESC in 5 seconds to skip startup.nsh or any other key to continue. + Shell> fs0:u-boot-app.efi + U-Boot EFI App (using allocated RAM address 47d4000) key=8d4, image=06a6f610 + starting + + + U-Boot 2022.01-rc4 (Sep 19 2021 - 14:03:20 -0600) + + CPU: x86, vendor Intel, device 663h + DRAM: 32 MiB + 0: efi_media_0 PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0) + 1: <partition> PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0)/HD(1,GPT,0FFD5E61-3B0C-4326-8049-BDCDC910AF72,0x800,0xB000) + Loading Environment from nowhere... OK + Model: EFI x86 Application + Hit any key to stop autoboot: 0 + + Partition Map for EFI device 0 -- Partition Type: EFI + + Part Start LBA End LBA Name + Attributes + Type GUID + Partition GUID + 1 0x00000800 0x0000b7ff "boot" + attrs: 0x0000000000000000 + type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 + guid: 0ffd5e61-3b0c-4326-8049-bdcdc910af72 + 19 startup.nsh + 528384 u-boot-app.efi + 10181 NvVars + + 3 file(s), 0 dir(s) + + => QEMU: Terminated + + Future work ----------- This work could be extended in a number of ways: diff --git a/scripts/build-efi.sh b/scripts/build-efi.sh new file mode 100755 index 00000000000..ce761840097 --- /dev/null +++ b/scripts/build-efi.sh @@ -0,0 +1,193 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0+ +# +# Script to build an EFI thing suitable for booting with QEMU, possibly running +# it also. + +# This just an example. It assumes that + +# - you build U-Boot in ${ubdir}/<name> where <name> is the U-Boot board config +# - /mnt/x is a directory used for mounting +# - you have access to the 'pure UEFI' builds for QEMU +# +# UEFI binaries for QEMU used for testing this script: +# +# OVMF-pure-efi.i386.fd at +# https://drive.google.com/file/d/1jWzOAZfQqMmS2_dAK2G518GhIgj9r2RY/view?usp=s... + +# OVMF-pure-efi.x64.fd at +# https://drive.google.com/file/d/1c39YI9QtpByGQ4V0UNNQtGqttEzS-eFV/view?usp=s... + +set -e + +usage() { + echo "Usage: $0 [-a | -p] [other opts]" 1>&2 + echo 1>&2 + echo " -a - Package up the app" 1>&2 + echo " -o - Use old EFI app build (before 32/64 split)" 1>&2 + echo " -p - Package up the payload" 1>&2 + echo " -P - Create a partition table" 1>&2 + echo " -r - Run QEMU with the image" 1>&2 + echo " -s - Run QEMU with serial only (no display)" 1>&2 + echo " -w - Use word version (32-bit)" 1>&2 + exit 1 +} + +# 32- or 64-bit EFI +bitness=64 + +# app or payload ? +type=app + +# create a partition table and put the filesystem in that (otherwise put the +# filesystem in the raw device) +part= + +# run the image with QEMU +run= + +# run QEMU without a display (U-Boot must be set to stdout=serial) +serial= + +# before the 32/64 split of the app +old= + +# Set ubdir to the build directory where you build U-Boot out-of-tree +# We avoid in-tree build because it gets confusing trying different builds +ubdir=/tmp/b/ + +while getopts "aopPrsw" opt; do + case "${opt}" in + a) + type=app + ;; + p) + type=payload + ;; + r) + run=1 + ;; + s) + serial=1 + ;; + w) + bitness=32 + ;; + o) + old=1 + ;; + P) + part=1 + ;; + *) + usage + ;; + esac +done + +run_qemu() { + extra= + if [[ "${bitness}" = "64" ]]; then + qemu=qemu-system-x86_64 + bios=OVMF-pure-efi.x64.fd + else + qemu=qemu-system-i386 + bios=OVMF-pure-efi.i386.fd + fi + if [[ -n "${serial}" ]]; then + extra="-display none -serial mon:stdio" + fi + echo "Running ${qemu}" + # Use 512MB since U-Boot EFI likes to have 256MB to play with + "${qemu}" -bios "${bios}" \ + -m 512 \ + -drive id=disk,file="${IMG}",if=none,format=raw \ + -nic none -device ahci,id=ahci \ + -device ide-hd,drive=disk,bus=ahci.0 ${extra} +} + +setup_files() { + echo "Packaging ${BUILD}" + mkdir -p $TMP + cat >$TMP/startup.nsh <<EOF +fs0:u-boot-${type}.efi +EOF + sudo cp ${ubdir}/${BUILD}/u-boot-${type}.efi $TMP + + # Can copy in other files here: + #sudo cp ${ubdir}/$BUILD/image.bin $TMP/chromeos.rom + #sudo cp /boot/vmlinuz-5.4.0-77-generic $TMP/vmlinuz +} + +# Copy files into the filesystem +copy_files() { + sudo cp $TMP/* $MNT +} + +# Create a filesystem on a raw device and copy in the files +setup_raw() { + mkfs.vfat "${IMG}" >/dev/null + sudo mount -o loop "${IMG}" $MNT + copy_files + sudo umount $MNT +} + +# Create a partition table and put the filesystem in the first partition +# then copy in the files +setup_part() { + # Create a gpt partition table with one parittion + parted "${IMG}" mklabel gpt 2>/dev/null + + # This doesn't work correctly. It creates: + # Number Start End Size File system Name Flags + # 1 1049kB 24.1MB 23.1MB boot msftdata + # Odd if the same is entered interactively it does set the FS type + parted -s -a optimal -- "${IMG}" mkpart boot fat32 1MiB 23MiB + + # Map this partition to a loop device + kp="$(sudo kpartx -av ${IMG})" + read boot_dev<<<$(grep -o 'loop.*p.' <<< "${kp}") + test "${boot_dev}" + dev="/dev/mapper/${boot_dev}" + + mkfs.vfat "${dev}" >/dev/null + + sudo mount -o loop "${dev}" $MNT + + copy_files + + # Sync here since this makes kpartx more likely to work the first time + sync + sudo umount $MNT + + # For some reason this needs a sleep or it sometimes fails, if it was + # run recently (in the last few seconds) + if ! sudo kpartx -d "${IMG}" > /dev/null; then + sleep .5 + sudo kpartx -d "${IMG}" > /dev/null || \ + echo "Failed to remove ${boot_dev}, use: sudo kpartx -d ${IMG}" + fi +} + +TMP="/tmp/efi${bitness}${type}" +MNT=/mnt/x +BUILD="efi-x86_${type}${bitness}" +IMG=try.img + +if [[ -n "${old}" && "${bitness}" = "32" ]]; then + BUILD="efi-x86_${type}" +fi + +setup_files + +qemu-img create "${IMG}" 24M >/dev/null + +if [[ -n "${part}" ]]; then + setup_part +else + setup_raw +fi + +if [[ -n "${run}" ]]; then + run_qemu +fi

On 11/4/21 04:09, Simon Glass wrote:
It is quite complicated to run U-Boot on QEMU since we have four different builds and they must use different versions of qemu and the UEFI binaries.
Add a script to help. It requires U-Boot itself to be built. Once that is done you can use this script to build an image for use with qemu and optionally run it.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v4:
- Change the patch subject to make it clear this does not build U-Boot
- Update commit message to mention that you have to build U-Boot
Changes in v3:
- Fix 'complicating' typo
- s/qemu/QEMU/
Changes in v2:
Add MAINTAINERS entry
Add support for creating a partition table with a filesystem inside
Add support for running qemu with just a serial console (no display)
MAINTAINERS | 1 + doc/develop/uefi/u-boot_on_efi.rst | 62 +++++++++ scripts/build-efi.sh | 193 +++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100755 scripts/build-efi.sh
diff --git a/MAINTAINERS b/MAINTAINERS index 9d8cba90280..fa7fe900705 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -710,6 +710,7 @@ M: Heinrich Schuchardt xypron.glpk@gmx.de S: Maintained W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: lib/efi/efi_app.c +F: scripts/build-efi.sh
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 43afb11de56..8856af3db56 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -98,6 +98,11 @@ 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.
+You may find the script `scripts/build-efi.sh` helpful for building and testing +U-Boot on UEFI on QEMU. It also includes links to UEFI binaries dating from +2021.
+See `Example run`_ for an example run.
Inner workings
@@ -193,6 +198,63 @@ 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.
+Example run +-----------
+This shows running with serial enabled (see `include/configs/efi-x86_app.h`)::
- $ scripts/build-efi.sh -wsPr
- Packaging efi-x86_app32
- Running qemu-system-i386
- BdsDxe: failed to load Boot0001 "UEFI QEMU HARDDISK QM00005 " from PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0): Not Found
- BdsDxe: loading Boot0002 "EFI Internal Shell" from Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
- BdsDxe: starting Boot0002 "EFI Internal Shell" from Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
- UEFI Interactive Shell v2.2
- EDK II
- UEFI v2.70 (EDK II, 0x00010000)
- Mapping table
FS0: Alias(s):HD0a65535a1:;BLK1:
PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0)/HD(1,GPT,0FFD5E61-3B0C-4326-8049-BDCDC910AF72,0x800,0xB000)
BLK0: Alias(s):
PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0)
- Press ESC in 5 seconds to skip startup.nsh or any other key to continue.
- Shell> fs0:u-boot-app.efi
- U-Boot EFI App (using allocated RAM address 47d4000) key=8d4, image=06a6f610
- starting
- U-Boot 2022.01-rc4 (Sep 19 2021 - 14:03:20 -0600)
- CPU: x86, vendor Intel, device 663h
- DRAM: 32 MiB
- 0: efi_media_0 PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0)
- 1: <partition> PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0)/HD(1,GPT,0FFD5E61-3B0C-4326-8049-BDCDC910AF72,0x800,0xB000)
- Loading Environment from nowhere... OK
- Model: EFI x86 Application
- Hit any key to stop autoboot: 0
- Partition Map for EFI device 0 -- Partition Type: EFI
- Part Start LBA End LBA Name
Attributes
Type GUID
Partition GUID
1 0x00000800 0x0000b7ff "boot"
attrs: 0x0000000000000000
type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
guid: 0ffd5e61-3b0c-4326-8049-bdcdc910af72
19 startup.nsh
528384 u-boot-app.efi
10181 NvVars
- 3 file(s), 0 dir(s)
- => QEMU: Terminated
Future work
This work could be extended in a number of ways:diff --git a/scripts/build-efi.sh b/scripts/build-efi.sh new file mode 100755 index 00000000000..ce761840097 --- /dev/null +++ b/scripts/build-efi.sh @@ -0,0 +1,193 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0+ +# +# Script to build an EFI thing suitable for booting with QEMU, possibly running +# it also.
+# This just an example. It assumes that
+# - you build U-Boot in ${ubdir}/<name> where <name> is the U-Boot board config +# - /mnt/x is a directory used for mounting +# - you have access to the 'pure UEFI' builds for QEMU +# +# UEFI binaries for QEMU used for testing this script: +# +# OVMF-pure-efi.i386.fd at +# https://drive.google.com/file/d/1jWzOAZfQqMmS2_dAK2G518GhIgj9r2RY/view?usp=s...
+# OVMF-pure-efi.x64.fd at +# https://drive.google.com/file/d/1c39YI9QtpByGQ4V0UNNQtGqttEzS-eFV/view?usp=s...
+set -e
+usage() {
- echo "Usage: $0 [-a | -p] [other opts]" 1>&2
- echo 1>&2
- echo " -a - Package up the app" 1>&2
- echo " -o - Use old EFI app build (before 32/64 split)" 1>&2
- echo " -p - Package up the payload" 1>&2
- echo " -P - Create a partition table" 1>&2
- echo " -r - Run QEMU with the image" 1>&2
- echo " -s - Run QEMU with serial only (no display)" 1>&2
- echo " -w - Use word version (32-bit)" 1>&2
- exit 1
+}
+# 32- or 64-bit EFI +bitness=64
+# app or payload ? +type=app
+# create a partition table and put the filesystem in that (otherwise put the +# filesystem in the raw device) +part=
+# run the image with QEMU +run=
+# run QEMU without a display (U-Boot must be set to stdout=serial) +serial=
+# before the 32/64 split of the app +old=
+# Set ubdir to the build directory where you build U-Boot out-of-tree +# We avoid in-tree build because it gets confusing trying different builds +ubdir=/tmp/b/
+while getopts "aopPrsw" opt; do
- case "${opt}" in
- a)
type=app
;;
- p)
type=payload
;;
- r)
run=1
;;
- s)
serial=1
;;
- w)
bitness=32
;;
- o)
old=1
;;
- P)
part=1
;;
- *)
usage
;;
- esac
+done
+run_qemu() {
- extra=
- if [[ "${bitness}" = "64" ]]; then
qemu=qemu-system-x86_64
bios=OVMF-pure-efi.x64.fd
- else
qemu=qemu-system-i386
bios=OVMF-pure-efi.i386.fd
- fi
- if [[ -n "${serial}" ]]; then
extra="-display none -serial mon:stdio"
- fi
- echo "Running ${qemu}"
- # Use 512MB since U-Boot EFI likes to have 256MB to play with
- "${qemu}" -bios "${bios}" \
-m 512 \
-drive id=disk,file="${IMG}",if=none,format=raw \
-nic none -device ahci,id=ahci \
-device ide-hd,drive=disk,bus=ahci.0 ${extra}
+}
+setup_files() {
- echo "Packaging ${BUILD}"
- mkdir -p $TMP
- cat >$TMP/startup.nsh <<EOF
+fs0:u-boot-${type}.efi +EOF
- sudo cp ${ubdir}/${BUILD}/u-boot-${type}.efi $TMP
- # Can copy in other files here:
- #sudo cp ${ubdir}/$BUILD/image.bin $TMP/chromeos.rom
- #sudo cp /boot/vmlinuz-5.4.0-77-generic $TMP/vmlinuz
+}
+# Copy files into the filesystem +copy_files() {
- sudo cp $TMP/* $MNT
Please, don't expect the user to be a sudoer. virt-make-fs is a better solution.
This can be changed in a follow up patch.
+}
+# Create a filesystem on a raw device and copy in the files +setup_raw() {
- mkfs.vfat "${IMG}" >/dev/null
- sudo mount -o loop "${IMG}" $MNT
- copy_files
- sudo umount $MNT
+}
+# Create a partition table and put the filesystem in the first partition +# then copy in the files +setup_part() {
- # Create a gpt partition table with one parittion
%s/parittion/partition/
I will fix this one when merging.
Best regards
Heinrich
- parted "${IMG}" mklabel gpt 2>/dev/null
- # This doesn't work correctly. It creates:
- # Number Start End Size File system Name Flags
- # 1 1049kB 24.1MB 23.1MB boot msftdata
- # Odd if the same is entered interactively it does set the FS type
- parted -s -a optimal -- "${IMG}" mkpart boot fat32 1MiB 23MiB
- # Map this partition to a loop device
- kp="$(sudo kpartx -av ${IMG})"
- read boot_dev<<<$(grep -o 'loop.*p.' <<< "${kp}")
- test "${boot_dev}"
- dev="/dev/mapper/${boot_dev}"
- mkfs.vfat "${dev}" >/dev/null
- sudo mount -o loop "${dev}" $MNT
- copy_files
- # Sync here since this makes kpartx more likely to work the first time
- sync
- sudo umount $MNT
- # For some reason this needs a sleep or it sometimes fails, if it was
- # run recently (in the last few seconds)
- if ! sudo kpartx -d "${IMG}" > /dev/null; then
sleep .5
sudo kpartx -d "${IMG}" > /dev/null || \
echo "Failed to remove ${boot_dev}, use: sudo kpartx -d ${IMG}"
- fi
+}
+TMP="/tmp/efi${bitness}${type}" +MNT=/mnt/x +BUILD="efi-x86_${type}${bitness}" +IMG=try.img
+if [[ -n "${old}" && "${bitness}" = "32" ]]; then
- BUILD="efi-x86_${type}"
+fi
+setup_files
+qemu-img create "${IMG}" 24M >/dev/null
+if [[ -n "${part}" ]]; then
- setup_part
+else
- setup_raw
+fi
+if [[ -n "${run}" ]]; then
- run_qemu
+fi

There is no need to avoid driver model for networking. Drop this.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de ---
(no changes since v2)
Changes in v2: - Add new patch to enable DM_ETH for the app
configs/efi-x86_app_defconfig | 1 - 1 file changed, 1 deletion(-)
diff --git a/configs/efi-x86_app_defconfig b/configs/efi-x86_app_defconfig index b1efafe5066..f0bc8778e37 100644 --- a/configs/efi-x86_app_defconfig +++ b/configs/efi-x86_app_defconfig @@ -32,7 +32,6 @@ CONFIG_ENV_OVERWRITE=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_REGMAP=y CONFIG_SYSCON=y -# CONFIG_DM_ETH is not set # CONFIG_REGEX is not set # CONFIG_GZIP is not set CONFIG_EFI=y

For the EFI app, we must embed the devicetree in the ELF file since that is the only thing that is run by UEFI. Drop the warning to avoid confusion.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de ---
(no changes since v2)
Changes in v2: - Add new patch to drop the OF_EMBED warning for EFI
Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index c45da3ad880..bf78009e370 100644 --- a/Makefile +++ b/Makefile @@ -1094,7 +1094,7 @@ endif ifeq ($(CONFIG_DEPRECATED),y) $(warning "You have deprecated configuration options enabled in your .config! Please check your configuration.") endif -ifeq ($(CONFIG_OF_EMBED),y) +ifeq ($(CONFIG_OF_EMBED)$(CONFIG_EFI_APP),y) @echo >&2 "===================== WARNING ======================" @echo >&2 "CONFIG_OF_EMBED is enabled. This option should only" @echo >&2 "be used for debugging purposes. Please use"

Most EFI implementations use 64-bit but U-Boot only supports running as a 32-bit app at present. While efi-x86_payload64 does boot from 64-bit UEFI it immediately changes back to 32-bit before starting U-Boot.
In order to support a 64-bit U-Boot app, update the Kconfig to add an option for 32/64 bit. Update the prompt for the existing option so it is clear it relates to the stub. Move both up to just under the choice that controls them, since this looks better and the menu.
Use CONFIG_EFI_APP in the Makefile instead of CONFIG_TARGET_EFI_APP, since the latter is specific to a single target and we will have two.
Memory size is set to 32MB for now so that it can run on qemu without increasing the default memory size. We may need to increase the default later.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v3)
Changes in v3: - Update minimum RAM to 256MB!
Changes in v2: - Expand the commit message to make things clearer
arch/x86/cpu/intel_common/Makefile | 2 +- lib/efi/Kconfig | 34 +++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 8b9a810f66d..1dc17b45879 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -27,7 +27,7 @@ obj-y += fast_spi.o obj-y += lpc.o obj-y += lpss.o obj-$(CONFIG_$(SPL_)INTEL_GENERIC_WIFI) += generic_wifi.o -ifndef CONFIG_TARGET_EFI_APP +ifndef CONFIG_EFI_APP obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o ifndef CONFIG_$(SPL_)X86_64 obj-y += microcode.o diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig index 93b85644920..15ce99e1a74 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -26,18 +26,26 @@ config EFI_STUB
endchoice
-config EFI_RAM_SIZE - hex "Amount of EFI RAM for U-Boot" +choice + prompt "EFI app 32/64-bit selection" depends on EFI_APP - default 0x2000000 help - Set the amount of EFI RAM which is claimed by U-Boot for its own - use. U-Boot allocates this from EFI on start-up (along with a few - other smaller amounts) and it can never be increased after that. - It is used as the RAM size in with U-Boot. + EFI does not support mixing 32-bit and 64-bit modes. This is a + significant problem because it means that you must build a stub with + the correct type for EFI to load it correctly. If you are using + 32-bit EFI, select 32-bit here, else select 64-bit. Failure to do + this may produce no error message - it just won't start! + +config EFI_APP_32BIT + bool "Produce an app for running with 32-bit EFI" + +config EFI_APP_64BIT + bool "Produce an app for running with 64-bit EFI" + +endchoice
choice - prompt "EFI 32/64-bit selection" + prompt "EFI stub 32/64-bit selection" depends on EFI_STUB help EFI does not support mixing 32-bit and 64-bit modes. This is a @@ -53,3 +61,13 @@ config EFI_STUB_64BIT bool "Produce a stub for running with 64-bit EFI"
endchoice + +config EFI_RAM_SIZE + hex "Amount of EFI RAM for U-Boot" + depends on EFI_APP + default 0x10000000 + help + Set the amount of EFI RAM which is claimed by U-Boot for its own + use. U-Boot allocates this from EFI on start-up (along with a few + other smaller amounts) and it can never be increased after that. + It is used as the RAM size in with U-Boot.

Most modern platforms use 64-bit EFI so it is useful to have a U-Boot app that runs under that. Add a (non-functional) build for this.
Note that --whole-archive causes the gcc 9.2 linker to crash, so disable this for now. Once this is resolved, things should work.
For now, avoid mentioning the documentation for the 64-bit app, since it does not work.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de ---
Changes in v4: - Make EFI_LOADER depend on !EFI_APP
Changes in v3: - Default to 256MB of RAM for U-Boot instead of 32MB
Changes in v2: - Add MAINTAINERS entry - Add a work-around to avoid a toolchain crash
MAINTAINERS | 3 ++ Makefile | 8 +++- arch/x86/cpu/u-boot-64.lds | 2 + arch/x86/cpu/x86_64/Makefile | 4 ++ arch/x86/cpu/x86_64/cpu.c | 17 --------- arch/x86/cpu/x86_64/misc.c | 25 ++++++++++++ board/efi/Kconfig | 15 +++++++- board/efi/efi-x86_app/Kconfig | 2 +- board/efi/efi-x86_app/MAINTAINERS | 11 +++++- ..._app_defconfig => efi-x86_app32_defconfig} | 2 +- configs/efi-x86_app64_defconfig | 38 +++++++++++++++++++ doc/develop/uefi/u-boot_on_efi.rst | 6 +-- lib/efi_loader/Kconfig | 1 + 13 files changed, 106 insertions(+), 28 deletions(-) create mode 100644 arch/x86/cpu/x86_64/misc.c rename configs/{efi-x86_app_defconfig => efi-x86_app32_defconfig} (97%) create mode 100644 configs/efi-x86_app64_defconfig
diff --git a/MAINTAINERS b/MAINTAINERS index fa7fe900705..00ff572d4d2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -709,6 +709,9 @@ M: Simon Glass sjg@chromium.org M: Heinrich Schuchardt xypron.glpk@gmx.de S: Maintained W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html +F: board/efi/efi-x86_app +F: configs/efi-x86_app* +F: doc/develop/uefi/u-boot_on_efi.rst F: lib/efi/efi_app.c F: scripts/build-efi.sh
diff --git a/Makefile b/Makefile index bf78009e370..ea884fec26f 100644 --- a/Makefile +++ b/Makefile @@ -1756,12 +1756,16 @@ quiet_cmd_u-boot__ ?= LTO $@ -Wl,-Map,u-boot.map; \ $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) else +# Note: Linking efi-x86_app64 causes a segfault in the linker at present +# when using x86_64-linux-gnu-ld.bfd +# For now, disable --whole-archive which makes things link, although not +# correctly quiet_cmd_u-boot__ ?= LD $@ cmd_u-boot__ ?= $(LD) $(KBUILD_LDFLAGS) $(LDFLAGS_u-boot) -o $@ \ -T u-boot.lds $(u-boot-init) \ - --whole-archive \ + $(if $(CONFIG_EFI_APP_64BIT),,--whole-archive) \ $(u-boot-main) \ - --no-whole-archive \ + $(if $(CONFIG_EFI_APP_64BIT),,--no-whole-archive) \ $(PLATFORM_LIBS) -Map u-boot.map; \ $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) endif diff --git a/arch/x86/cpu/u-boot-64.lds b/arch/x86/cpu/u-boot-64.lds index ee0812aefbc..92a30c2a387 100644 --- a/arch/x86/cpu/u-boot-64.lds +++ b/arch/x86/cpu/u-boot-64.lds @@ -15,7 +15,9 @@ SECTIONS /DISCARD/ : { *(.u_boot_list_2_cmd_*) } #endif
+#ifdef CONFIG_SYS_TEXT_BASE . = CONFIG_SYS_TEXT_BASE; /* Location of bootcode in flash */ +#endif __text_start = .;
.text.start : { *(.text.start); } diff --git a/arch/x86/cpu/x86_64/Makefile b/arch/x86/cpu/x86_64/Makefile index 400f0ffe397..e929563b2c1 100644 --- a/arch/x86/cpu/x86_64/Makefile +++ b/arch/x86/cpu/x86_64/Makefile @@ -4,3 +4,7 @@ #
obj-y += cpu.o interrupts.o setjmp.o + +ifndef CONFIG_EFI +obj-y += misc.o +endif diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index 90a766c3c57..8f72c9951a1 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -49,23 +49,6 @@ int x86_mp_init(void) return 0; }
-int misc_init_r(void) -{ - return 0; -} - -#ifndef CONFIG_SYS_COREBOOT -int checkcpu(void) -{ - return 0; -} - -int print_cpuinfo(void) -{ - return 0; -} -#endif - int x86_cpu_reinit_f(void) { return 0; diff --git a/arch/x86/cpu/x86_64/misc.c b/arch/x86/cpu/x86_64/misc.c new file mode 100644 index 00000000000..02587ff0c50 --- /dev/null +++ b/arch/x86/cpu/x86_64/misc.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Google, Inc + * Written by Simon Glass sjg@chromium.org + */ + +#include <common.h> +#include <init.h> + +int misc_init_r(void) +{ + return 0; +} + +#ifndef CONFIG_SYS_COREBOOT +int checkcpu(void) +{ + return 0; +} + +int print_cpuinfo(void) +{ + return 0; +} +#endif diff --git a/board/efi/Kconfig b/board/efi/Kconfig index 291bd2ca154..3df6e31c8ba 100644 --- a/board/efi/Kconfig +++ b/board/efi/Kconfig @@ -4,14 +4,25 @@ choice prompt "Mainboard model" optional
-config TARGET_EFI_APP - bool "efi application" +config TARGET_EFI_APP32 + bool "32-bit efi application" + select EFI_APP help This target is used for running U-Boot on top of EFI. In this case EFI does the early initialisation, and U-Boot takes over once the RAM, video and CPU are fully running. U-Boot is loaded as an application from EFI.
+config TARGET_EFI_APP64 + bool "64-bit efi application" + select EFI_APP + select X86_64 + help + This target is used for running U-Boot on top of EFI in 64-bit mode. + In this case EFI does the early initialisation, and U-Boot + takes over once the RAM, video and CPU are fully running. + U-Boot is loaded as an application from EFI. + config TARGET_EFI_PAYLOAD bool "efi payload" help diff --git a/board/efi/efi-x86_app/Kconfig b/board/efi/efi-x86_app/Kconfig index ae87bf34d37..e412702eed7 100644 --- a/board/efi/efi-x86_app/Kconfig +++ b/board/efi/efi-x86_app/Kconfig @@ -1,4 +1,4 @@ -if TARGET_EFI_APP +if EFI_APP
config SYS_BOARD default "efi-x86_app" diff --git a/board/efi/efi-x86_app/MAINTAINERS b/board/efi/efi-x86_app/MAINTAINERS index fb8a6b1c2fa..b292811a8f0 100644 --- a/board/efi/efi-x86_app/MAINTAINERS +++ b/board/efi/efi-x86_app/MAINTAINERS @@ -1,6 +1,13 @@ -EFI-X86_APP BOARD +EFI-X86_APP32 BOARD M: Simon Glass sjg@chromium.org S: Maintained F: board/efi/efi-x86_app/ F: include/configs/efi-x86_app.h -F: configs/efi-x86_app_defconfig +F: configs/efi-x86_app32_defconfig + +EFI-X86_APP64 BOARD +M: Simon Glass sjg@chromium.org +S: Maintained +F: board/efi/efi-x86_app/ +F: include/configs/efi-x86_app.h +F: configs/efi-x86_app64_defconfig diff --git a/configs/efi-x86_app_defconfig b/configs/efi-x86_app32_defconfig similarity index 97% rename from configs/efi-x86_app_defconfig rename to configs/efi-x86_app32_defconfig index f0bc8778e37..480ef648eaa 100644 --- a/configs/efi-x86_app_defconfig +++ b/configs/efi-x86_app32_defconfig @@ -5,7 +5,7 @@ CONFIG_DEFAULT_DEVICE_TREE="efi-x86_app" CONFIG_DEBUG_UART_BASE=0 CONFIG_DEBUG_UART_CLOCK=0 CONFIG_VENDOR_EFI=y -CONFIG_TARGET_EFI_APP=y +CONFIG_TARGET_EFI_APP32=y CONFIG_DEBUG_UART=y CONFIG_FIT=y CONFIG_SHOW_BOOT_PROGRESS=y diff --git a/configs/efi-x86_app64_defconfig b/configs/efi-x86_app64_defconfig new file mode 100644 index 00000000000..bffbf6958a2 --- /dev/null +++ b/configs/efi-x86_app64_defconfig @@ -0,0 +1,38 @@ +CONFIG_X86=y +CONFIG_NR_DRAM_BANKS=8 +CONFIG_ENV_SIZE=0x1000 +CONFIG_DEFAULT_DEVICE_TREE="efi-x86_app" +CONFIG_DEBUG_UART_BASE=0 +CONFIG_DEBUG_UART_CLOCK=0 +CONFIG_VENDOR_EFI=y +CONFIG_TARGET_EFI_APP64=y +CONFIG_DEBUG_UART=y +CONFIG_FIT=y +CONFIG_SHOW_BOOT_PROGRESS=y +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro" +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_LAST_STAGE_INIT=y +CONFIG_HUSH_PARSER=y +# CONFIG_CMD_BOOTM is not set +CONFIG_CMD_PART=y +# CONFIG_CMD_NET is not set +CONFIG_CMD_TIME=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_MAC_PARTITION=y +CONFIG_ISO_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_OF_EMBED=y +CONFIG_ENV_OVERWRITE=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y +# CONFIG_REGEX is not set +# CONFIG_GZIP is not set +CONFIG_EFI=y +CONFIG_EFI_APP_64BIT=y diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 8856af3db56..f275a524ce7 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -48,10 +48,10 @@ 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_app config (efi-x86_app_defconfig) is set up +and CONFIG_EFI_APP. The efi-x86_app config (efi-x86_app32_defconfig) is set up for this. Just build U-Boot as normal, e.g.::
- make efi-x86_app_defconfig + make efi-x86_app32_defconfig make
To build U-Boot as an EFI payload (32-bit or 64-bit EFI can be used), enable @@ -261,7 +261,7 @@ This work could be extended in a number of ways:
- Add ARM support
-- Add 64-bit application support +- Add 64-bit application support (in progress)
- Figure out how to solve the interrupt problem
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 52f71c07c99..700dc838ddb 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -12,6 +12,7 @@ config EFI_LOADER depends on !EFI_STUB || !X86 || X86_64 || EFI_STUB_32BIT depends on BLK depends on DM_ETH || !NET + depends on !EFI_APP default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8 select LIB_UUID select PARTITION_UUIDS

This variable is already defined by the EFI code. Drop the duplicate definition when building a 64-bit EFI app.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
arch/x86/cpu/x86_64/cpu.c | 15 +-------------- arch/x86/cpu/x86_64/misc.c | 16 ++++++++++++++++ lib/efi/efi.c | 9 +++++++++ 3 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index 8f72c9951a1..a3674e8e29a 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -8,20 +8,7 @@ #include <cpu_func.h> #include <debug_uart.h> #include <init.h> - -/* - * Global declaration of gd. - * - * As we write to it before relocation we have to make sure it is not put into - * a .bss section which may overlap a .rela section. Initialization forces it - * into a .data section which cannot overlap any .rela section. - */ -struct global_data *global_data_ptr = (struct global_data *)~0; - -void arch_setup_gd(gd_t *new_gd) -{ - global_data_ptr = new_gd; -} +#include <asm/global_data.h>
int cpu_has_64bit(void) { diff --git a/arch/x86/cpu/x86_64/misc.c b/arch/x86/cpu/x86_64/misc.c index 02587ff0c50..691b67ff68a 100644 --- a/arch/x86/cpu/x86_64/misc.c +++ b/arch/x86/cpu/x86_64/misc.c @@ -7,6 +7,22 @@ #include <common.h> #include <init.h>
+DECLARE_GLOBAL_DATA_PTR; + +/* + * Global declaration of gd. + * + * As we write to it before relocation we have to make sure it is not put into + * a .bss section which may overlap a .rela section. Initialization forces it + * into a .data section which cannot overlap any .rela section. + */ +struct global_data *global_data_ptr = (struct global_data *)~0; + +void arch_setup_gd(gd_t *new_gd) +{ + global_data_ptr = new_gd; +} + int misc_init_r(void) { return 0; diff --git a/lib/efi/efi.c b/lib/efi/efi.c index 0c16a5fdd38..69e52e45748 100644 --- a/lib/efi/efi.c +++ b/lib/efi/efi.c @@ -17,6 +17,15 @@ #include <efi.h> #include <efi_api.h>
+/* + * Global declaration of gd. + * + * As we write to it before relocation we have to make sure it is not put into + * a .bss section which may overlap a .rela section. Initialization forces it + * into a .data section which cannot overlap any .rela section. + */ +struct global_data *global_data_ptr = (struct global_data *)~0; + /* * Unfortunately we cannot access any code outside what is built especially * for the stub. lib/string.c is already being built for the U-Boot payload

On 11/4/21 04:09, Simon Glass wrote:
This variable is already defined by the EFI code. Drop the duplicate definition when building a 64-bit EFI app.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de

Add a function to return this information along with a stub for the efi_info_get() function, since calling it otherwise hangs U-Boot.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
include/efi.h | 8 +++++++- lib/efi/efi_app.c | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/include/efi.h b/include/efi.h index 18c13e0370a..b5835422b95 100644 --- a/include/efi.h +++ b/include/efi.h @@ -444,9 +444,15 @@ extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[]; * * @return pointer to EFI system table */ - struct efi_system_table *efi_get_sys_table(void);
+/** + * efi_get_boot() - Get access to the EFI boot services table + * + * @return pointer to EFI boot services table + */ +struct efi_boot_services *efi_get_boot(void); + /** * efi_get_ram_base() - Find the base of RAM * diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 907bacd716a..f61665686c5 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -31,11 +31,21 @@ 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; }
+int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) +{ + return -ENOSYS; +} + static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot;

On 11/4/21 04:09, Simon Glass wrote:
Add a function to return this information along with a stub for the efi_info_get() function, since calling it otherwise hangs U-Boot.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v1)
include/efi.h | 8 +++++++-
efi.h is used both by efi_loader as well as efi_app. At long term it would make sense to move efi_app specific stuff to a separate include like we did for efi_loader using efi_loader.h
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
lib/efi/efi_app.c | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/include/efi.h b/include/efi.h index 18c13e0370a..b5835422b95 100644 --- a/include/efi.h +++ b/include/efi.h @@ -444,9 +444,15 @@ extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[];
- @return pointer to EFI system table
*/
- struct efi_system_table *efi_get_sys_table(void);
+/**
- efi_get_boot() - Get access to the EFI boot services table
- @return pointer to EFI boot services table
- */
+struct efi_boot_services *efi_get_boot(void);
- /**
- efi_get_ram_base() - Find the base of RAM
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 907bacd716a..f61665686c5 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -31,11 +31,21 @@ 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; }
+int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) +{
- return -ENOSYS;
+}
- static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot;

The current EFI video driver only works when running in the stub. In that case the stub calls boot services (before jumping to U-Boot proper) and copies the graphics info over to the efi table. This is necessary because the stub exits boot services before jumping to U-Boot.
The app maintains access to boot services throughout its life, so does not need to do this. Update the driver to support calling boot services directly.
Enable video output for the app. Note that this uses the EFI_GRAPHICS_OUTPUT_PROTOCOL protocol, even though it mentions vesa.
A sample qemu command-line for this case is:
qemu-system-x86_64 -bios /usr/share/edk2.git/ovmf-ia32/OVMF-pure-efi.fd -drive id=disk,file=try.img,if=none,format=raw -nic none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v2)
Changes in v2: - Add a note that EFI_GRAPHICS_OUTPUT_PROTOCOL is used - Update documentation
arch/x86/dts/efi-x86_app.dts | 4 +++ board/efi/efi-x86_app/Kconfig | 4 +++ doc/develop/uefi/u-boot_on_efi.rst | 2 +- drivers/video/Kconfig | 2 +- drivers/video/efi.c | 45 ++++++++++++++++++++++++------ include/configs/efi-x86_app.h | 6 ++-- 6 files changed, 50 insertions(+), 13 deletions(-)
diff --git a/arch/x86/dts/efi-x86_app.dts b/arch/x86/dts/efi-x86_app.dts index 04e044a07a8..a5316e2a1a7 100644 --- a/arch/x86/dts/efi-x86_app.dts +++ b/arch/x86/dts/efi-x86_app.dts @@ -25,4 +25,8 @@ compatible = "efi,reset"; u-boot,dm-pre-reloc; }; + efi-fb { + compatible = "efi-fb"; + }; + }; diff --git a/board/efi/efi-x86_app/Kconfig b/board/efi/efi-x86_app/Kconfig index e412702eed7..ecd08d73146 100644 --- a/board/efi/efi-x86_app/Kconfig +++ b/board/efi/efi-x86_app/Kconfig @@ -12,4 +12,8 @@ config SYS_SOC config SYS_CONFIG_NAME default "efi-x86_app"
+config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + imply VIDEO_EFI + endif diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index f275a524ce7..5f2f850f071 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -265,7 +265,7 @@ 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, +- 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.
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2f4650f8309..a58f87f479b 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -250,7 +250,7 @@ config VIDEO_COREBOOT
config VIDEO_EFI bool "Enable EFI framebuffer driver support" - depends on EFI_STUB + depends on EFI_STUB || EFI_APP help Turn on this option to enable a framebuffeer driver when U-Boot is loaded as a payload (see README.u-boot_on_efi) by an EFI BIOS where diff --git a/drivers/video/efi.c b/drivers/video/efi.c index c248bd352a7..4e13a3efcb1 100644 --- a/drivers/video/efi.c +++ b/drivers/video/efi.c @@ -50,6 +50,28 @@ static void efi_find_pixel_bits(u32 mask, u8 *pos, u8 *size) *size = len; }
+static int get_mode_info(struct vesa_mode_info *vesa) +{ + efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + struct efi_boot_services *boot = efi_get_boot(); + struct efi_gop_mode *mode; + struct efi_gop *gop; + int ret; + + if (!boot) + return log_msg_ret("sys", -ENOSYS); + ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); + if (ret) + return log_msg_ret("prot", -ENOTSUPP); + + mode = gop->mode; + vesa->phys_base_ptr = mode->fb_base; + vesa->x_resolution = mode->info->width; + vesa->y_resolution = mode->info->height; + + return 0; +} + static int save_vesa_mode(struct vesa_mode_info *vesa) { struct efi_entry_gopmode *mode; @@ -57,16 +79,23 @@ static int save_vesa_mode(struct vesa_mode_info *vesa) int size; int ret;
- ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); - if (ret == -ENOENT) { - debug("efi graphics output protocol mode not found\n"); - return -ENXIO; + if (IS_ENABLED(CONFIG_EFI_APP)) { + ret = get_mode_info(vesa); + if (ret) { + printf("efi graphics output protocol not found\n"); + return -ENXIO; + } + } else { + ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); + if (ret == -ENOENT) { + printf("efi graphics output protocol mode not found\n"); + return -ENXIO; + } + vesa->phys_base_ptr = mode->fb_base; + vesa->x_resolution = mode->info->width; + vesa->y_resolution = mode->info->height; }
- vesa->phys_base_ptr = mode->fb_base; - vesa->x_resolution = mode->info->width; - vesa->y_resolution = mode->info->height; - if (mode->info->pixel_format < EFI_GOT_BITMASK) { fbinfo = &efi_framebuffer_format_map[mode->info->pixel_format]; vesa->red_mask_size = fbinfo->red.size; diff --git a/include/configs/efi-x86_app.h b/include/configs/efi-x86_app.h index 33418cfbec4..6061a6db0a4 100644 --- a/include/configs/efi-x86_app.h +++ b/include/configs/efi-x86_app.h @@ -10,8 +10,8 @@
#undef CONFIG_TPM_TIS_BASE_ADDRESS
-#define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \ - "stdout=vga,serial\0" \ - "stderr=vga,serial\0" +#define CONFIG_STD_DEVICES_SETTINGS "stdin=serial\0" \ + "stdout=vidconsole\0" \ + "stderr=vidconsole\0"
#endif

On 11/4/21 04:09, Simon Glass wrote:
The current EFI video driver only works when running in the stub. In that case the stub calls boot services (before jumping to U-Boot proper) and copies the graphics info over to the efi table. This is necessary because the stub exits boot services before jumping to U-Boot.
The app maintains access to boot services throughout its life, so does not need to do this. Update the driver to support calling boot services directly.
Enable video output for the app. Note that this uses the EFI_GRAPHICS_OUTPUT_PROTOCOL protocol, even though it mentions vesa.
A sample qemu command-line for this case is:
qemu-system-x86_64 -bios /usr/share/edk2.git/ovmf-ia32/OVMF-pure-efi.fd -drive id=disk,file=try.img,if=none,format=raw -nic none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v2)
Changes in v2:
Add a note that EFI_GRAPHICS_OUTPUT_PROTOCOL is used
Update documentation
arch/x86/dts/efi-x86_app.dts | 4 +++ board/efi/efi-x86_app/Kconfig | 4 +++ doc/develop/uefi/u-boot_on_efi.rst | 2 +- drivers/video/Kconfig | 2 +- drivers/video/efi.c | 45 ++++++++++++++++++++++++------ include/configs/efi-x86_app.h | 6 ++-- 6 files changed, 50 insertions(+), 13 deletions(-)
diff --git a/arch/x86/dts/efi-x86_app.dts b/arch/x86/dts/efi-x86_app.dts index 04e044a07a8..a5316e2a1a7 100644 --- a/arch/x86/dts/efi-x86_app.dts +++ b/arch/x86/dts/efi-x86_app.dts @@ -25,4 +25,8 @@ compatible = "efi,reset"; u-boot,dm-pre-reloc; };
- efi-fb {
compatible = "efi-fb";
- };
- };
diff --git a/board/efi/efi-x86_app/Kconfig b/board/efi/efi-x86_app/Kconfig index e412702eed7..ecd08d73146 100644 --- a/board/efi/efi-x86_app/Kconfig +++ b/board/efi/efi-x86_app/Kconfig @@ -12,4 +12,8 @@ config SYS_SOC config SYS_CONFIG_NAME default "efi-x86_app"
+config BOARD_SPECIFIC_OPTIONS # dummy
- def_bool y
- imply VIDEO_EFI
- endif
diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index f275a524ce7..5f2f850f071 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -265,7 +265,7 @@ 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, +- 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.
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2f4650f8309..a58f87f479b 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -250,7 +250,7 @@ config VIDEO_COREBOOT
config VIDEO_EFI bool "Enable EFI framebuffer driver support"
- depends on EFI_STUB
- depends on EFI_STUB || EFI_APP help Turn on this option to enable a framebuffeer driver when U-Boot is loaded as a payload (see README.u-boot_on_efi) by an EFI BIOS where
diff --git a/drivers/video/efi.c b/drivers/video/efi.c index c248bd352a7..4e13a3efcb1 100644 --- a/drivers/video/efi.c +++ b/drivers/video/efi.c @@ -50,6 +50,28 @@ static void efi_find_pixel_bits(u32 mask, u8 *pos, u8 *size) *size = len; }
+static int get_mode_info(struct vesa_mode_info *vesa) +{
- efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_gop_mode *mode;
- struct efi_gop *gop;
- int ret;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop);
- if (ret)
return log_msg_ret("prot", -ENOTSUPP);
- mode = gop->mode;
- vesa->phys_base_ptr = mode->fb_base;
- vesa->x_resolution = mode->info->width;
- vesa->y_resolution = mode->info->height;
- return 0;
+}
- static int save_vesa_mode(struct vesa_mode_info *vesa) { struct efi_entry_gopmode *mode;
@@ -57,16 +79,23 @@ static int save_vesa_mode(struct vesa_mode_info *vesa) int size; int ret;
- ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size);
- if (ret == -ENOENT) {
debug("efi graphics output protocol mode not found\n");
return -ENXIO;
- if (IS_ENABLED(CONFIG_EFI_APP)) {
ret = get_mode_info(vesa);
if (ret) {
printf("efi graphics output protocol not found\n");
return -ENXIO;
}
- } else {
ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size);
if (ret == -ENOENT) {
printf("efi graphics output protocol mode not found\n");
%s/efi/EFI/
I will correct this when merging.
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
return -ENXIO;
}
vesa->phys_base_ptr = mode->fb_base;
vesa->x_resolution = mode->info->width;
}vesa->y_resolution = mode->info->height;
- vesa->phys_base_ptr = mode->fb_base;
- vesa->x_resolution = mode->info->width;
- vesa->y_resolution = mode->info->height;
- if (mode->info->pixel_format < EFI_GOT_BITMASK) { fbinfo = &efi_framebuffer_format_map[mode->info->pixel_format]; vesa->red_mask_size = fbinfo->red.size;
diff --git a/include/configs/efi-x86_app.h b/include/configs/efi-x86_app.h index 33418cfbec4..6061a6db0a4 100644 --- a/include/configs/efi-x86_app.h +++ b/include/configs/efi-x86_app.h @@ -10,8 +10,8 @@
#undef CONFIG_TPM_TIS_BASE_ADDRESS
-#define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \
"stdout=vga,serial\0" \
"stderr=vga,serial\0"
+#define CONFIG_STD_DEVICES_SETTINGS "stdin=serial\0" \
"stdout=vidconsole\0" \
"stderr=vidconsole\0"
#endif

At present UCLASS_EFI is used to represent an EFI filesystem among other things. The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media so that it can be used with 'part list', for example.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v2)
Changes in v2: - Add MAINTAINERS entry - Show the correct interface type with 'part list' - Update the commit message to explain things better
MAINTAINERS | 3 +++ arch/sandbox/dts/test.dts | 4 ++++ disk/part.c | 5 ++++- drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 20 ++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 11 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/MAINTAINERS b/MAINTAINERS index 00ff572d4d2..3e8f10c72fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -712,8 +712,11 @@ W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: board/efi/efi-x86_app F: configs/efi-x86_app* F: doc/develop/uefi/u-boot_on_efi.rst +F: drivers/block/efi-media-uclass.c +F: drivers/block/sb_efi_media.c F: lib/efi/efi_app.c F: scripts/build-efi.sh +F: test/dm/efi_media.c
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8cd688e8d26..2cea4a43c87 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -498,6 +498,10 @@ compatible = "sandbox,clk-ccf"; };
+ efi-media { + compatible = "sandbox,efi-media"; + }; + eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>; diff --git a/disk/part.c b/disk/part.c index a6a8f7052bd..2560f6a50bc 100644 --- a/disk/part.c +++ b/disk/part.c @@ -296,8 +296,11 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc) case IF_TYPE_VIRTIO: puts("VirtIO"); break; + case IF_TYPE_EFI: + puts("EFI"); + break; default: - puts ("UNKNOWN"); + puts("UNKNOWN"); break; } printf (" device %d -- Partition Type: %s\n\n", diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 56a4eec05ac..755fdccb574 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -61,6 +61,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA + bool "Support EFI media drivers" + default y if EFI || SANDBOX + help + Enable this to support media devices on top of UEFI. This enables + just the uclass so you also need a specific driver to make this do + anything. + + For sandbox there is a test driver. + +if EFI_MEDIA + +config EFI_MEDIA_SANDBOX + bool "Sandbox EFI media driver" + depends on SANDBOX + default y + help + Enables a simple sandbox media driver, used for testing just the + EFI_MEDIA uclass. It does not do anything useful, since sandbox does + not actually support running on top of UEFI. + +endif # EFI_MEDIA + config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o + +obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME, - [IF_TYPE_EFI] = UCLASS_EFI, + [IF_TYPE_EFI] = UCLASS_EFI_MEDIA, [IF_TYPE_VIRTIO] = UCLASS_VIRTIO, [IF_TYPE_PVBLOCK] = UCLASS_PVBLOCK, }; diff --git a/drivers/block/efi-media-uclass.c b/drivers/block/efi-media-uclass.c new file mode 100644 index 00000000000..e012f6f2f4c --- /dev/null +++ b/drivers/block/efi-media-uclass.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Uclass for EFI media devices + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <dm.h> + +UCLASS_DRIVER(efi_media) = { + .id = UCLASS_EFI_MEDIA, + .name = "efi_media", + .flags = DM_UC_FLAG_SEQ_ALIAS, +}; diff --git a/drivers/block/sb_efi_media.c b/drivers/block/sb_efi_media.c new file mode 100644 index 00000000000..52af155a600 --- /dev/null +++ b/drivers/block/sb_efi_media.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI_MEDIA driver for sandbox + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <dm.h> + +static const struct udevice_id sandbox_efi_media_ids[] = { + { .compatible = "sandbox,efi-media" }, + { } +}; + +U_BOOT_DRIVER(sandbox_efi_media) = { + .name = "sandbox_efi_media", + .id = UCLASS_EFI_MEDIA, + .of_match = sandbox_efi_media_ids, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index fd139b9b2a0..5f5a69f5f33 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -49,6 +49,7 @@ enum uclass_id { UCLASS_DSA, /* Distributed (Ethernet) Switch Architecture */ UCLASS_ECDSA, /* Elliptic curve cryptographic device */ UCLASS_EFI, /* EFI managed devices */ + UCLASS_EFI_MEDIA, /* EFI media (e.g. a disk) */ UCLASS_ETH, /* Ethernet device */ UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_FIRMWARE, /* Firmware */ diff --git a/test/dm/Makefile b/test/dm/Makefile index 7de013f6368..900f6ad91a9 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_DMA) += dma.o obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o obj-$(CONFIG_DM_DSA) += dsa.o obj-$(CONFIG_ECDSA_VERIFY) += ecdsa.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += efi_media.o obj-$(CONFIG_DM_ETH) += eth.o ifneq ($(CONFIG_EFI_PARTITION),) obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fastboot.o diff --git a/test/dm/efi_media.c b/test/dm/efi_media.c new file mode 100644 index 00000000000..e343a0e9c85 --- /dev/null +++ b/test/dm/efi_media.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for EFI_MEDIA uclass + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <asm/test.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h> + +/* Test that we can use the EFI_MEDIA uclass */ +static int dm_test_efi_media(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_EFI_MEDIA, &dev)); + + return 0; +} +DM_TEST(dm_test_efi_media, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);

On 11/4/21 04:09, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem among other things. The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media so that it can be used with 'part list', for example.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v2)
Changes in v2:
Add MAINTAINERS entry
Show the correct interface type with 'part list'
Update the commit message to explain things better
MAINTAINERS | 3 +++ arch/sandbox/dts/test.dts | 4 ++++ disk/part.c | 5 ++++- drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 20 ++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 11 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/MAINTAINERS b/MAINTAINERS index 00ff572d4d2..3e8f10c72fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -712,8 +712,11 @@ W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: board/efi/efi-x86_app F: configs/efi-x86_app* F: doc/develop/uefi/u-boot_on_efi.rst +F: drivers/block/efi-media-uclass.c +F: drivers/block/sb_efi_media.c F: lib/efi/efi_app.c F: scripts/build-efi.sh +F: test/dm/efi_media.c
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8cd688e8d26..2cea4a43c87 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -498,6 +498,10 @@ compatible = "sandbox,clk-ccf"; };
- efi-media {
compatible = "sandbox,efi-media";
- };
- eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
diff --git a/disk/part.c b/disk/part.c index a6a8f7052bd..2560f6a50bc 100644 --- a/disk/part.c +++ b/disk/part.c @@ -296,8 +296,11 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc) case IF_TYPE_VIRTIO: puts("VirtIO"); break;
- case IF_TYPE_EFI:
puts("EFI");
default:break;
puts ("UNKNOWN");
break; } printf (" device %d -- Partition Type: %s\n\n",puts("UNKNOWN");
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 56a4eec05ac..755fdccb574 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -61,6 +61,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA
- bool "Support EFI media drivers"
- default y if EFI || SANDBOX
- help
Enable this to support media devices on top of UEFI. This enables
just the uclass so you also need a specific driver to make this do
anything.
For sandbox there is a test driver.
+if EFI_MEDIA
+config EFI_MEDIA_SANDBOX
- bool "Sandbox EFI media driver"
- depends on SANDBOX
- default y
- help
Enables a simple sandbox media driver, used for testing just the
EFI_MEDIA uclass. It does not do anything useful, since sandbox does
not actually support running on top of UEFI.
+endif # EFI_MEDIA
- config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
+obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME,
- [IF_TYPE_EFI] = UCLASS_EFI,
- [IF_TYPE_EFI] = UCLASS_EFI_MEDIA,
Don't break existing code. Create a new if_type here.
Best regards
Heinrich
[IF_TYPE_VIRTIO] = UCLASS_VIRTIO, [IF_TYPE_PVBLOCK] = UCLASS_PVBLOCK, }; diff --git a/drivers/block/efi-media-uclass.c b/drivers/block/efi-media-uclass.c new file mode 100644 index 00000000000..e012f6f2f4c --- /dev/null +++ b/drivers/block/efi-media-uclass.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Uclass for EFI media devices
- Copyright 2021 Google LLC
- */
+#include <common.h> +#include <dm.h>
+UCLASS_DRIVER(efi_media) = {
- .id = UCLASS_EFI_MEDIA,
- .name = "efi_media",
- .flags = DM_UC_FLAG_SEQ_ALIAS,
+}; diff --git a/drivers/block/sb_efi_media.c b/drivers/block/sb_efi_media.c new file mode 100644 index 00000000000..52af155a600 --- /dev/null +++ b/drivers/block/sb_efi_media.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- EFI_MEDIA driver for sandbox
- Copyright 2021 Google LLC
- */
+#include <common.h> +#include <dm.h>
+static const struct udevice_id sandbox_efi_media_ids[] = {
- { .compatible = "sandbox,efi-media" },
- { }
+};
+U_BOOT_DRIVER(sandbox_efi_media) = {
- .name = "sandbox_efi_media",
- .id = UCLASS_EFI_MEDIA,
- .of_match = sandbox_efi_media_ids,
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index fd139b9b2a0..5f5a69f5f33 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -49,6 +49,7 @@ enum uclass_id { UCLASS_DSA, /* Distributed (Ethernet) Switch Architecture */ UCLASS_ECDSA, /* Elliptic curve cryptographic device */ UCLASS_EFI, /* EFI managed devices */
- UCLASS_EFI_MEDIA, /* EFI media (e.g. a disk) */ UCLASS_ETH, /* Ethernet device */ UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_FIRMWARE, /* Firmware */
diff --git a/test/dm/Makefile b/test/dm/Makefile index 7de013f6368..900f6ad91a9 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_DMA) += dma.o obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o obj-$(CONFIG_DM_DSA) += dsa.o obj-$(CONFIG_ECDSA_VERIFY) += ecdsa.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += efi_media.o obj-$(CONFIG_DM_ETH) += eth.o ifneq ($(CONFIG_EFI_PARTITION),) obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fastboot.o diff --git a/test/dm/efi_media.c b/test/dm/efi_media.c new file mode 100644 index 00000000000..e343a0e9c85 --- /dev/null +++ b/test/dm/efi_media.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Test for EFI_MEDIA uclass
- Copyright 2021 Google LLC
- */
+#include <common.h> +#include <dm.h> +#include <asm/test.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h>
+/* Test that we can use the EFI_MEDIA uclass */ +static int dm_test_efi_media(struct unit_test_state *uts) +{
- struct udevice *dev;
- ut_assertok(uclass_first_device_err(UCLASS_EFI_MEDIA, &dev));
- return 0;
+} +DM_TEST(dm_test_efi_media, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);

Hi Heinrich,
On Sun, 7 Nov 2021 at 01:21, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/4/21 04:09, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem among other things. The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media so that it can be used with 'part list', for example.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v2)
Changes in v2:
Add MAINTAINERS entry
Show the correct interface type with 'part list'
Update the commit message to explain things better
MAINTAINERS | 3 +++ arch/sandbox/dts/test.dts | 4 ++++ disk/part.c | 5 ++++- drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 20 ++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 11 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/MAINTAINERS b/MAINTAINERS index 00ff572d4d2..3e8f10c72fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -712,8 +712,11 @@ W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: board/efi/efi-x86_app F: configs/efi-x86_app* F: doc/develop/uefi/u-boot_on_efi.rst +F: drivers/block/efi-media-uclass.c +F: drivers/block/sb_efi_media.c F: lib/efi/efi_app.c F: scripts/build-efi.sh +F: test/dm/efi_media.c
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8cd688e8d26..2cea4a43c87 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -498,6 +498,10 @@ compatible = "sandbox,clk-ccf"; };
efi-media {
compatible = "sandbox,efi-media";
};
eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
diff --git a/disk/part.c b/disk/part.c index a6a8f7052bd..2560f6a50bc 100644 --- a/disk/part.c +++ b/disk/part.c @@ -296,8 +296,11 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc) case IF_TYPE_VIRTIO: puts("VirtIO"); break;
case IF_TYPE_EFI:
puts("EFI");
break; default:
puts ("UNKNOWN");
puts("UNKNOWN"); break; } printf (" device %d -- Partition Type: %s\n\n",
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 56a4eec05ac..755fdccb574 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -61,6 +61,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA
bool "Support EFI media drivers"
default y if EFI || SANDBOX
help
Enable this to support media devices on top of UEFI. This enables
just the uclass so you also need a specific driver to make this do
anything.
For sandbox there is a test driver.
+if EFI_MEDIA
+config EFI_MEDIA_SANDBOX
bool "Sandbox EFI media driver"
depends on SANDBOX
default y
help
Enables a simple sandbox media driver, used for testing just the
EFI_MEDIA uclass. It does not do anything useful, since sandbox does
not actually support running on top of UEFI.
+endif # EFI_MEDIA
- config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
+obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME,
[IF_TYPE_EFI] = UCLASS_EFI,
[IF_TYPE_EFI] = UCLASS_EFI_MEDIA,
Don't break existing code. Create a new if_type here.
My understanding is that this is not actually used at present. The tests appear to pass without trouble.
What problem are you seeing?
Regards, Simon

On Sun, Nov 07, 2021 at 09:43:22AM -0700, Simon Glass wrote:
Hi Heinrich,
On Sun, 7 Nov 2021 at 01:21, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/4/21 04:09, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem among other things. The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media so that it can be used with 'part list', for example.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v2)
Changes in v2:
Add MAINTAINERS entry
Show the correct interface type with 'part list'
Update the commit message to explain things better
MAINTAINERS | 3 +++ arch/sandbox/dts/test.dts | 4 ++++ disk/part.c | 5 ++++- drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 20 ++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 11 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/MAINTAINERS b/MAINTAINERS index 00ff572d4d2..3e8f10c72fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -712,8 +712,11 @@ W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: board/efi/efi-x86_app F: configs/efi-x86_app* F: doc/develop/uefi/u-boot_on_efi.rst +F: drivers/block/efi-media-uclass.c +F: drivers/block/sb_efi_media.c F: lib/efi/efi_app.c F: scripts/build-efi.sh +F: test/dm/efi_media.c
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8cd688e8d26..2cea4a43c87 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -498,6 +498,10 @@ compatible = "sandbox,clk-ccf"; };
efi-media {
compatible = "sandbox,efi-media";
};
eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
diff --git a/disk/part.c b/disk/part.c index a6a8f7052bd..2560f6a50bc 100644 --- a/disk/part.c +++ b/disk/part.c @@ -296,8 +296,11 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc) case IF_TYPE_VIRTIO: puts("VirtIO"); break;
case IF_TYPE_EFI:
puts("EFI");
break; default:
puts ("UNKNOWN");
puts("UNKNOWN"); break; } printf (" device %d -- Partition Type: %s\n\n",
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 56a4eec05ac..755fdccb574 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -61,6 +61,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA
bool "Support EFI media drivers"
default y if EFI || SANDBOX
help
Enable this to support media devices on top of UEFI. This enables
just the uclass so you also need a specific driver to make this do
anything.
For sandbox there is a test driver.
+if EFI_MEDIA
+config EFI_MEDIA_SANDBOX
bool "Sandbox EFI media driver"
depends on SANDBOX
default y
help
Enables a simple sandbox media driver, used for testing just the
EFI_MEDIA uclass. It does not do anything useful, since sandbox does
not actually support running on top of UEFI.
+endif # EFI_MEDIA
- config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
+obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME,
[IF_TYPE_EFI] = UCLASS_EFI,
[IF_TYPE_EFI] = UCLASS_EFI_MEDIA,
Don't break existing code. Create a new if_type here.
My understanding is that this is not actually used at present. The tests appear to pass without trouble.
What problem are you seeing?
I can agree with Simon's claim that the notion of UCLASS_EFI sounds vague. In my understanding, it is expected to represent any UEFI driver/application who will convert "UEFI protocol" to "U-Boot device", the only example right now is "efi_block" device.
One of issues that I can see is that any instance of UCLASS_EFI doesn't appear in DM tree. I have made an experimental patch which makes UCLASS_EFI a pseudo U-Boot device. DM tree would look like: root |-- 'EFI block driver' (CLASS_EFI for block_io_protocol) |-- 'efi_blk' (CLASS_BLK with TYPE_EFI)
This way, the meaning of UCLASS_EFI should be much clearer?
# In fact, the actual implementer of BLOCK_IO_PROTOCOL is # a loaded UEFI application, though.
-Takahiro Akashi
Regards, Simon

On 11/8/21 06:29, AKASHI Takahiro wrote:
On Sun, Nov 07, 2021 at 09:43:22AM -0700, Simon Glass wrote:
Hi Heinrich,
On Sun, 7 Nov 2021 at 01:21, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/4/21 04:09, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem among other things. The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media so that it can be used with 'part list', for example.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v2)
Changes in v2:
Add MAINTAINERS entry
Show the correct interface type with 'part list'
Update the commit message to explain things better
MAINTAINERS | 3 +++ arch/sandbox/dts/test.dts | 4 ++++ disk/part.c | 5 ++++- drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 20 ++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 11 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/MAINTAINERS b/MAINTAINERS index 00ff572d4d2..3e8f10c72fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -712,8 +712,11 @@ W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: board/efi/efi-x86_app F: configs/efi-x86_app* F: doc/develop/uefi/u-boot_on_efi.rst +F: drivers/block/efi-media-uclass.c +F: drivers/block/sb_efi_media.c F: lib/efi/efi_app.c F: scripts/build-efi.sh +F: test/dm/efi_media.c
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8cd688e8d26..2cea4a43c87 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -498,6 +498,10 @@ compatible = "sandbox,clk-ccf"; };
efi-media {
compatible = "sandbox,efi-media";
};
eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
diff --git a/disk/part.c b/disk/part.c index a6a8f7052bd..2560f6a50bc 100644 --- a/disk/part.c +++ b/disk/part.c @@ -296,8 +296,11 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc) case IF_TYPE_VIRTIO: puts("VirtIO"); break;
case IF_TYPE_EFI:
puts("EFI");
break; default:
puts ("UNKNOWN");
puts("UNKNOWN"); break; } printf (" device %d -- Partition Type: %s\n\n",
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 56a4eec05ac..755fdccb574 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -61,6 +61,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA
bool "Support EFI media drivers"
default y if EFI || SANDBOX
help
Enable this to support media devices on top of UEFI. This enables
just the uclass so you also need a specific driver to make this do
anything.
For sandbox there is a test driver.
+if EFI_MEDIA
+config EFI_MEDIA_SANDBOX
bool "Sandbox EFI media driver"
depends on SANDBOX
default y
help
Enables a simple sandbox media driver, used for testing just the
EFI_MEDIA uclass. It does not do anything useful, since sandbox does
not actually support running on top of UEFI.
+endif # EFI_MEDIA
- config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
+obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME,
[IF_TYPE_EFI] = UCLASS_EFI,
[IF_TYPE_EFI] = UCLASS_EFI_MEDIA,
Don't break existing code. Create a new if_type here.
My understanding is that this is not actually used at present. The tests appear to pass without trouble.
None of these tests uses the 'load efi 0:1' command!
The iftype-uclass relationship is used during the look up. Please, stick to separate if_types per uclass.
Best regards
Heinrich
What problem are you seeing?
I can agree with Simon's claim that the notion of UCLASS_EFI sounds vague. In my understanding, it is expected to represent any UEFI driver/application who will convert "UEFI protocol" to "U-Boot device", the only example right now is "efi_block" device.
One of issues that I can see is that any instance of UCLASS_EFI doesn't appear in DM tree. I have made an experimental patch which makes UCLASS_EFI a pseudo U-Boot device. DM tree would look like: root |-- 'EFI block driver' (CLASS_EFI for block_io_protocol) |-- 'efi_blk' (CLASS_BLK with TYPE_EFI)
This way, the meaning of UCLASS_EFI should be much clearer?
# In fact, the actual implementer of BLOCK_IO_PROTOCOL is # a loaded UEFI application, though.
-Takahiro Akashi
Regards, Simon

Hi Heinrich,
On Mon, 8 Nov 2021 at 08:39, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/8/21 06:29, AKASHI Takahiro wrote:
On Sun, Nov 07, 2021 at 09:43:22AM -0700, Simon Glass wrote:
Hi Heinrich,
On Sun, 7 Nov 2021 at 01:21, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/4/21 04:09, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem among other things. The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media so that it can be used with 'part list', for example.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v2)
Changes in v2:
Add MAINTAINERS entry
Show the correct interface type with 'part list'
Update the commit message to explain things better
MAINTAINERS | 3 +++ arch/sandbox/dts/test.dts | 4 ++++ disk/part.c | 5 ++++- drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 20 ++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 11 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/MAINTAINERS b/MAINTAINERS index 00ff572d4d2..3e8f10c72fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -712,8 +712,11 @@ W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: board/efi/efi-x86_app F: configs/efi-x86_app* F: doc/develop/uefi/u-boot_on_efi.rst +F: drivers/block/efi-media-uclass.c +F: drivers/block/sb_efi_media.c F: lib/efi/efi_app.c F: scripts/build-efi.sh +F: test/dm/efi_media.c
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8cd688e8d26..2cea4a43c87 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -498,6 +498,10 @@ compatible = "sandbox,clk-ccf"; };
efi-media {
compatible = "sandbox,efi-media";
};
eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
diff --git a/disk/part.c b/disk/part.c index a6a8f7052bd..2560f6a50bc 100644 --- a/disk/part.c +++ b/disk/part.c @@ -296,8 +296,11 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc) case IF_TYPE_VIRTIO: puts("VirtIO"); break;
case IF_TYPE_EFI:
puts("EFI");
break; default:
puts ("UNKNOWN");
puts("UNKNOWN"); break; } printf (" device %d -- Partition Type: %s\n\n",
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 56a4eec05ac..755fdccb574 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -61,6 +61,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA
bool "Support EFI media drivers"
default y if EFI || SANDBOX
help
Enable this to support media devices on top of UEFI. This enables
just the uclass so you also need a specific driver to make this do
anything.
For sandbox there is a test driver.
+if EFI_MEDIA
+config EFI_MEDIA_SANDBOX
bool "Sandbox EFI media driver"
depends on SANDBOX
default y
help
Enables a simple sandbox media driver, used for testing just the
EFI_MEDIA uclass. It does not do anything useful, since sandbox does
not actually support running on top of UEFI.
+endif # EFI_MEDIA
- config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
+obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME,
[IF_TYPE_EFI] = UCLASS_EFI,
[IF_TYPE_EFI] = UCLASS_EFI_MEDIA,
Don't break existing code. Create a new if_type here.
My understanding is that this is not actually used at present. The tests appear to pass without trouble.
None of these tests uses the 'load efi 0:1' command!
The iftype-uclass relationship is used during the look up. Please, stick to separate if_types per uclass.
Best regards
Heinrich
What problem are you seeing?
I can agree with Simon's claim that the notion of UCLASS_EFI sounds vague. In my understanding, it is expected to represent any UEFI driver/application who will convert "UEFI protocol" to "U-Boot device", the only example right now is "efi_block" device.
One of issues that I can see is that any instance of UCLASS_EFI doesn't appear in DM tree. I have made an experimental patch which makes UCLASS_EFI a pseudo U-Boot device. DM tree would look like: root |-- 'EFI block driver' (CLASS_EFI for block_io_protocol) |-- 'efi_blk' (CLASS_BLK with TYPE_EFI)
This way, the meaning of UCLASS_EFI should be much clearer?
# In fact, the actual implementer of BLOCK_IO_PROTOCOL is # a loaded UEFI application, though.
In which case, do we need it? Or should I rename the existing UCLASS_EFI to UCLASS_EFI_LOADER ? At some point I hope we can clean it up, but this might allow us to make progress.
Regards, Simon

Hi Heinrich,
On Mon, 8 Nov 2021 at 08:58, Simon Glass sjg@chromium.org wrote:
Hi Heinrich,
On Mon, 8 Nov 2021 at 08:39, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/8/21 06:29, AKASHI Takahiro wrote:
On Sun, Nov 07, 2021 at 09:43:22AM -0700, Simon Glass wrote:
Hi Heinrich,
On Sun, 7 Nov 2021 at 01:21, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/4/21 04:09, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem among other things. The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media so that it can be used with 'part list', for example.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v2)
Changes in v2:
Add MAINTAINERS entry
Show the correct interface type with 'part list'
Update the commit message to explain things better
MAINTAINERS | 3 +++ arch/sandbox/dts/test.dts | 4 ++++ disk/part.c | 5 ++++- drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 20 ++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 11 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/MAINTAINERS b/MAINTAINERS index 00ff572d4d2..3e8f10c72fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -712,8 +712,11 @@ W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: board/efi/efi-x86_app F: configs/efi-x86_app* F: doc/develop/uefi/u-boot_on_efi.rst +F: drivers/block/efi-media-uclass.c +F: drivers/block/sb_efi_media.c F: lib/efi/efi_app.c F: scripts/build-efi.sh +F: test/dm/efi_media.c
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8cd688e8d26..2cea4a43c87 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -498,6 +498,10 @@ compatible = "sandbox,clk-ccf"; };
efi-media {
compatible = "sandbox,efi-media";
};
eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
diff --git a/disk/part.c b/disk/part.c index a6a8f7052bd..2560f6a50bc 100644 --- a/disk/part.c +++ b/disk/part.c @@ -296,8 +296,11 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc) case IF_TYPE_VIRTIO: puts("VirtIO"); break;
case IF_TYPE_EFI:
puts("EFI");
break; default:
puts ("UNKNOWN");
puts("UNKNOWN"); break; } printf (" device %d -- Partition Type: %s\n\n",
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 56a4eec05ac..755fdccb574 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -61,6 +61,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA
bool "Support EFI media drivers"
default y if EFI || SANDBOX
help
Enable this to support media devices on top of UEFI. This enables
just the uclass so you also need a specific driver to make this do
anything.
For sandbox there is a test driver.
+if EFI_MEDIA
+config EFI_MEDIA_SANDBOX
bool "Sandbox EFI media driver"
depends on SANDBOX
default y
help
Enables a simple sandbox media driver, used for testing just the
EFI_MEDIA uclass. It does not do anything useful, since sandbox does
not actually support running on top of UEFI.
+endif # EFI_MEDIA
- config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
+obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME,
[IF_TYPE_EFI] = UCLASS_EFI,
[IF_TYPE_EFI] = UCLASS_EFI_MEDIA,
Don't break existing code. Create a new if_type here.
My understanding is that this is not actually used at present. The tests appear to pass without trouble.
None of these tests uses the 'load efi 0:1' command!
The iftype-uclass relationship is used during the look up. Please, stick to separate if_types per uclass.
Best regards
Heinrich
What problem are you seeing?
I can agree with Simon's claim that the notion of UCLASS_EFI sounds vague. In my understanding, it is expected to represent any UEFI driver/application who will convert "UEFI protocol" to "U-Boot device", the only example right now is "efi_block" device.
One of issues that I can see is that any instance of UCLASS_EFI doesn't appear in DM tree. I have made an experimental patch which makes UCLASS_EFI a pseudo U-Boot device. DM tree would look like: root |-- 'EFI block driver' (CLASS_EFI for block_io_protocol) |-- 'efi_blk' (CLASS_BLK with TYPE_EFI)
This way, the meaning of UCLASS_EFI should be much clearer?
# In fact, the actual implementer of BLOCK_IO_PROTOCOL is # a loaded UEFI application, though.
In which case, do we need it? Or should I rename the existing UCLASS_EFI to UCLASS_EFI_LOADER ? At some point I hope we can clean it up, but this might allow us to make progress.
I'd really like to get this series in. Can you please take a look at this? I don't understand what test fails or what the problem is here.
Please unblock this series and let's get things moving. RC1 has already come out and this series was sent out over 2 months ago now. Loads of other things have been applied in the meantime.
If you don't want to be the maintainer for this part of EFI, that's fine with me, but please let me know.
Regards, Simon

On 11/8/21 06:29, AKASHI Takahiro wrote:
On Sun, Nov 07, 2021 at 09:43:22AM -0700, Simon Glass wrote:
Hi Heinrich,
On Sun, 7 Nov 2021 at 01:21, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/4/21 04:09, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem among other things. The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media so that it can be used with 'part list', for example.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v2)
Changes in v2:
Add MAINTAINERS entry
Show the correct interface type with 'part list'
Update the commit message to explain things better
MAINTAINERS | 3 +++ arch/sandbox/dts/test.dts | 4 ++++ disk/part.c | 5 ++++- drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 20 ++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 11 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/MAINTAINERS b/MAINTAINERS index 00ff572d4d2..3e8f10c72fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -712,8 +712,11 @@ W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: board/efi/efi-x86_app F: configs/efi-x86_app* F: doc/develop/uefi/u-boot_on_efi.rst +F: drivers/block/efi-media-uclass.c +F: drivers/block/sb_efi_media.c F: lib/efi/efi_app.c F: scripts/build-efi.sh +F: test/dm/efi_media.c
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8cd688e8d26..2cea4a43c87 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -498,6 +498,10 @@ compatible = "sandbox,clk-ccf"; };
efi-media {
compatible = "sandbox,efi-media";
};
eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
diff --git a/disk/part.c b/disk/part.c index a6a8f7052bd..2560f6a50bc 100644 --- a/disk/part.c +++ b/disk/part.c @@ -296,8 +296,11 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc) case IF_TYPE_VIRTIO: puts("VirtIO"); break;
case IF_TYPE_EFI:
puts("EFI");
break; default:
puts ("UNKNOWN");
puts("UNKNOWN"); break; } printf (" device %d -- Partition Type: %s\n\n",
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 56a4eec05ac..755fdccb574 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -61,6 +61,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA
bool "Support EFI media drivers"
default y if EFI || SANDBOX
help
Enable this to support media devices on top of UEFI. This enables
just the uclass so you also need a specific driver to make this do
anything.
For sandbox there is a test driver.
+if EFI_MEDIA
+config EFI_MEDIA_SANDBOX
bool "Sandbox EFI media driver"
depends on SANDBOX
default y
help
Enables a simple sandbox media driver, used for testing just the
EFI_MEDIA uclass. It does not do anything useful, since sandbox does
not actually support running on top of UEFI.
+endif # EFI_MEDIA
- config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
+obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME,
[IF_TYPE_EFI] = UCLASS_EFI,
[IF_TYPE_EFI] = UCLASS_EFI_MEDIA,
Don't break existing code. Create a new if_type here.
My understanding is that this is not actually used at present. The tests appear to pass without trouble.
What problem are you seeing?
I want the following to be successful:
make sandconfig make menuconfig # set CONFIG_EFI_SELFTEST=y make -j$(nproc) ./u-boot -T setenv efi_selftest block device bootefi selftest ls efi 0:1 load efi 0:1 $fdt_addr_r hello.txt mm.b $fdt_addr_r
A file with the following string is loaded to memory: "Hello world!\r"
It works if I apply
[PATCH 1/1] blk: simplify blk_get_devnum_by_typename() https://lists.denx.de/pipermail/u-boot/2021-October/464585.html
If you want to keep the superfluous if_type-uclass table, please, use a separate if_type for each uclass in this patch and suggest an alternative fix for the test above.
Best regards
Heinrich
I can agree with Simon's claim that the notion of UCLASS_EFI sounds vague. In my understanding, it is expected to represent any UEFI driver/application who will convert "UEFI protocol" to "U-Boot device", the only example right now is "efi_block" device.
One of issues that I can see is that any instance of UCLASS_EFI doesn't appear in DM tree. I have made an experimental patch which makes UCLASS_EFI a pseudo U-Boot device. DM tree would look like: root |-- 'EFI block driver' (CLASS_EFI for block_io_protocol) |-- 'efi_blk' (CLASS_BLK with TYPE_EFI)
This way, the meaning of UCLASS_EFI should be much clearer?
# In fact, the actual implementer of BLOCK_IO_PROTOCOL is # a loaded UEFI application, though.
-Takahiro Akashi
Regards, Simon

Hi Heinrich,
On Sat, 13 Nov 2021 at 02:29, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/8/21 06:29, AKASHI Takahiro wrote:
On Sun, Nov 07, 2021 at 09:43:22AM -0700, Simon Glass wrote:
Hi Heinrich,
On Sun, 7 Nov 2021 at 01:21, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/4/21 04:09, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem among other things. The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media so that it can be used with 'part list', for example.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v2)
Changes in v2:
Add MAINTAINERS entry
Show the correct interface type with 'part list'
Update the commit message to explain things better
MAINTAINERS | 3 +++ arch/sandbox/dts/test.dts | 4 ++++ disk/part.c | 5 ++++- drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 20 ++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 11 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/MAINTAINERS b/MAINTAINERS index 00ff572d4d2..3e8f10c72fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -712,8 +712,11 @@ W: https://u-boot.readthedocs.io/en/latest/develop/uefi/u-boot_on_efi.html F: board/efi/efi-x86_app F: configs/efi-x86_app* F: doc/develop/uefi/u-boot_on_efi.rst +F: drivers/block/efi-media-uclass.c +F: drivers/block/sb_efi_media.c F: lib/efi/efi_app.c F: scripts/build-efi.sh +F: test/dm/efi_media.c
EFI PAYLOAD M: Heinrich Schuchardt xypron.glpk@gmx.de diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8cd688e8d26..2cea4a43c87 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -498,6 +498,10 @@ compatible = "sandbox,clk-ccf"; };
efi-media {
compatible = "sandbox,efi-media";
};
eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
diff --git a/disk/part.c b/disk/part.c index a6a8f7052bd..2560f6a50bc 100644 --- a/disk/part.c +++ b/disk/part.c @@ -296,8 +296,11 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc) case IF_TYPE_VIRTIO: puts("VirtIO"); break;
case IF_TYPE_EFI:
puts("EFI");
break; default:
puts ("UNKNOWN");
puts("UNKNOWN"); break; } printf (" device %d -- Partition Type: %s\n\n",
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 56a4eec05ac..755fdccb574 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -61,6 +61,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA
bool "Support EFI media drivers"
default y if EFI || SANDBOX
help
Enable this to support media devices on top of UEFI. This enables
just the uclass so you also need a specific driver to make this do
anything.
For sandbox there is a test driver.
+if EFI_MEDIA
+config EFI_MEDIA_SANDBOX
bool "Sandbox EFI media driver"
depends on SANDBOX
default y
help
Enables a simple sandbox media driver, used for testing just the
EFI_MEDIA uclass. It does not do anything useful, since sandbox does
not actually support running on top of UEFI.
+endif # EFI_MEDIA
- config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
+obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME,
[IF_TYPE_EFI] = UCLASS_EFI,
[IF_TYPE_EFI] = UCLASS_EFI_MEDIA,
Don't break existing code. Create a new if_type here.
My understanding is that this is not actually used at present. The tests appear to pass without trouble.
What problem are you seeing?
I want the following to be successful:
make sandconfig make menuconfig # set CONFIG_EFI_SELFTEST=y make -j$(nproc) ./u-boot -T setenv efi_selftest block device bootefi selftest ls efi 0:1 load efi 0:1 $fdt_addr_r hello.txt mm.b $fdt_addr_r
A file with the following string is loaded to memory: "Hello world!\r"
OK thanks, I will take a look.
It works if I apply
[PATCH 1/1] blk: simplify blk_get_devnum_by_typename() https://lists.denx.de/pipermail/u-boot/2021-October/464585.html
I wondered why you sent that patch.
If you want to keep the superfluous if_type-uclass table, please, use a separate if_type for each uclass in this patch and suggest an alternative fix for the test above.
OK will do.
Regards, Simon
Best regards
Heinrich
I can agree with Simon's claim that the notion of UCLASS_EFI sounds vague. In my understanding, it is expected to represent any UEFI driver/application who will convert "UEFI protocol" to "U-Boot device", the only example right now is "efi_block" device.
One of issues that I can see is that any instance of UCLASS_EFI doesn't appear in DM tree. I have made an experimental patch which makes UCLASS_EFI a pseudo U-Boot device. DM tree would look like: root |-- 'EFI block driver' (CLASS_EFI for block_io_protocol) |-- 'efi_blk' (CLASS_BLK with TYPE_EFI)
This way, the meaning of UCLASS_EFI should be much clearer?
# In fact, the actual implementer of BLOCK_IO_PROTOCOL is # a loaded UEFI application, though.
-Takahiro Akashi
Regards, Simon

Hi Heinrich,
On Sat, 13 Nov 2021 at 02:29, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/8/21 06:29, AKASHI Takahiro wrote:
On Sun, Nov 07, 2021 at 09:43:22AM -0700, Simon Glass wrote:
Hi Heinrich,
On Sun, 7 Nov 2021 at 01:21, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 11/4/21 04:09, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem among other things. The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media so that it can be used with 'part list', for example.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v2)
Changes in v2:
Add MAINTAINERS entry
Show the correct interface type with 'part list'
Update the commit message to explain things better
MAINTAINERS | 3 +++ arch/sandbox/dts/test.dts | 4 ++++ disk/part.c | 5 ++++- drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 20 ++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 11 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
[..]
[IF_TYPE_NVME] = UCLASS_NVME,
[IF_TYPE_EFI] = UCLASS_EFI,
[IF_TYPE_EFI] = UCLASS_EFI_MEDIA,
Don't break existing code. Create a new if_type here.
My understanding is that this is not actually used at present. The tests appear to pass without trouble.
What problem are you seeing?
I want the following to be successful:
make sandconfig make menuconfig # set CONFIG_EFI_SELFTEST=y make -j$(nproc) ./u-boot -T setenv efi_selftest block device bootefi selftest ls efi 0:1 load efi 0:1 $fdt_addr_r hello.txt mm.b $fdt_addr_r
A file with the following string is loaded to memory: "Hello world!\r"
I still am lost here.
Do you mean CONFIG_CMD_BOOTEFI_SELFTEST=y
I cannot find CONFIG_EFI_SELFTEST
Assuming it is that, this is what I see when I try that on -next :
/tmp/b/sandbox/u-boot -T sandbox_serial serial: pinctrl_select_state_full: uclass_get_device_by_phandle_id: err=-19
U-Boot 2022.01-rc3-00126-gf89615088fb-dirty (Dec 03 2021 - 20:34:58 -0700)
Model: sandbox DRAM: 128 MiB WDT: Not starting gpio-wdt WDT: Not starting wdt@0 MMC: mmc2: 2 (SD), mmc1: 1 (SD), mmc0: 0 (SD) Loading Environment from nowhere... OK In: cros-ec-keyb Out: vidconsole Err: vidconsole Model: sandbox SCSI: Net: eth0: eth@10002000, eth5: eth@10003000, eth3: sbe5, eth6: eth@10004000, eth4: dsa-test-eth, eth2: lan0, eth7: lan1 Hit any key to stop autoboot: 0 => setenv efi_selftest block device => bootefi selftest Scanning disk mmc2.blk... Scanning disk mmc1.blk... Scanning disk mmc0.blk... Found 3 disks No EFI system partition Cannot install EFI_TCG2_PROTOCOL "dfu_alt_info" env variable not defined! Probably dfu_alt_info not defined "dfu_alt_info" env variable not defined! Probably dfu_alt_info not defined
Testing EFI API implementation
Selected test: 'block device'
Setting up 'block device' Setting up 'block device' succeeded
Executing 'block device' lib/efi_selftest/efi_selftest_block_device.c(404): TODO: Wrong volume label '', expected 'U-BOOT TEST' Executing 'block device' succeeded
Tearing down 'block device' Tearing down 'block device' succeeded
Summary: 0 failures
=> ls efi 0:1 Couldn't find partition efi 0:1 => load efi 0:1 $fdt_addr_r hello.txt Couldn't find partition efi 0:1 Can't set block device
What am I missing?
It works if I apply
[PATCH 1/1] blk: simplify blk_get_devnum_by_typename() https://lists.denx.de/pipermail/u-boot/2021-October/464585.html
If you want to keep the superfluous if_type-uclass table, please, use a separate if_type for each uclass in this patch and suggest an alternative fix for the test above.
Regards, Simon [..]

Add a block driver which handles read/write for EFI block devices. This driver actually already exists ('efi_block') but is not really suitable for use as a real U-Boot driver:
- The operations do not provide a udevice - The code is designed for running as part of EFI loader, so uses EFI_PRINT() and EFI_CALL(). - The bind method probes the device, which is not permitted - It uses 'EFI' as its parent device
The new driver is more 'normal', just requiring its platform data be set up in advance.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v2)
Changes in v2: - Drop mention of partitions from the commit message
drivers/block/Kconfig | 10 ++++ drivers/block/Makefile | 1 + drivers/block/efi_blk.c | 115 ++++++++++++++++++++++++++++++++++++++++ include/efi.h | 11 ++++ 4 files changed, 137 insertions(+) create mode 100644 drivers/block/efi_blk.c
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 755fdccb574..8235430497d 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -82,6 +82,16 @@ config EFI_MEDIA_SANDBOX EFI_MEDIA uclass. It does not do anything useful, since sandbox does not actually support running on top of UEFI.
+config EFI_MEDIA_BLK + bool "EFI media block driver" + depends on EFI_APP + default y + help + Enables a block driver for providing access to UEFI devices. This + allows use of block devices detected by the underlying UEFI + implementation. With this it is possible to use filesystems on these + devices, for example. + endif # EFI_MEDIA
config IDE diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 3778633da1d..b221a7c6eea 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o +obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o diff --git a/drivers/block/efi_blk.c b/drivers/block/efi_blk.c new file mode 100644 index 00000000000..c00b0cc0b1c --- /dev/null +++ b/drivers/block/efi_blk.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Block driver for EFI devices + * This supports a media driver of UCLASS_EFI with a child UCLASS_BLK + * It allows block-level access to EFI devices made available via EFI boot + * services + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <blk.h> +#include <dm.h> +#include <efi.h> +#include <efi_api.h> + +struct efi_block_plat { + struct efi_block_io *blkio; +}; + +/** + * Read from block device + * + * @dev: device + * @blknr: first block to be read + * @blkcnt: number of blocks to read + * @buffer: output buffer + * Return: number of blocks transferred + */ +static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + void *buffer) +{ + struct efi_block_plat *plat = dev_get_plat(dev); + struct efi_block_io *io = plat->blkio; + efi_status_t ret; + + log_debug("read buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr, + (ulong)blkcnt); + ret = io->read_blocks(io, io->media->media_id, blknr, + blkcnt * io->media->block_size, buffer); + log_debug("ret=%lx (dec %ld)\n", ret & ~EFI_ERROR_MASK, + ret & ~EFI_ERROR_MASK); + if (ret) + return 0; + + return blkcnt; +} + +/** + * Write to block device + * + * @dev: device + * @blknr: first block to be write + * @blkcnt: number of blocks to write + * @buffer: input buffer + * Return: number of blocks transferred + */ +static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + const void *buffer) +{ + struct efi_block_plat *plat = dev_get_plat(dev); + struct efi_block_io *io = plat->blkio; + efi_status_t ret; + + log_debug("write buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr, + (ulong)blkcnt); + ret = io->write_blocks(io, io->media->media_id, blknr, + blkcnt * io->media->block_size, (void *)buffer); + log_debug("ret=%lx (dec %ld)\n", ret & ~EFI_ERROR_MASK, + ret & ~EFI_ERROR_MASK); + if (ret) + return 0; + + return blkcnt; +} + +/* Block device driver operators */ +static const struct blk_ops efi_blk_ops = { + .read = efi_bl_read, + .write = efi_bl_write, +}; + +U_BOOT_DRIVER(efi_block) = { + .name = "efi_block", + .id = UCLASS_BLK, + .ops = &efi_blk_ops, + .plat_auto = sizeof(struct efi_block_plat), +}; + +static int efi_media_bind(struct udevice *dev) +{ + struct efi_media_plat *plat = dev_get_plat(dev); + struct efi_block_plat *blk_plat; + struct udevice *blk; + int ret; + + ret = blk_create_devicef(dev, "efi_block", "blk", IF_TYPE_EFI, + dev_seq(dev), plat->blkio->media->block_size, + plat->blkio->media->last_block, &blk); + if (ret) { + debug("Cannot create block device\n"); + return ret; + } + blk_plat = dev_get_plat(blk); + blk_plat->blkio = plat->blkio; + + return 0; +} + +U_BOOT_DRIVER(efi_media) = { + .name = "efi_media", + .id = UCLASS_EFI_MEDIA, + .bind = efi_media_bind, + .plat_auto = sizeof(struct efi_media_plat), +}; diff --git a/include/efi.h b/include/efi.h index b5835422b95..0ec5913ddd1 100644 --- a/include/efi.h +++ b/include/efi.h @@ -414,6 +414,17 @@ struct efi_priv { void *next_hdr; };
+/* + * EFI attributes of the udevice handled by efi_media driver + * + * @handle: handle of the controller on which this driver is installed + * @blkio: block io protocol proxied by this driver + */ +struct efi_media_plat { + efi_handle_t handle; + struct efi_block_io *blkio; +}; + /* Base address of the EFI image */ extern char image_base[];

When starting the app, locate all block devices and make them available to U-Boot. This allows listing partitions and accessing files in filesystems.
EFI also has the concept of 'disks', meaning boot media. For now, this is not obviously useful in U-Boot, but add code to at least locate these. This can be expanded later as needed.
Series-changes; 2 - Store device path in struct efi_media_plat - Don't export efi_bind_block() - Only bind devices for media devices, not for partitions - Show devices that are processed - Update documentation
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
doc/develop/uefi/u-boot_on_efi.rst | 4 +- include/efi.h | 6 +- include/efi_api.h | 15 ++ lib/efi/efi_app.c | 223 +++++++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 5 deletions(-)
diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 5f2f850f071..8f81b799072 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -265,9 +265,7 @@ 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 diff --git a/include/efi.h b/include/efi.h index 0ec5913ddd1..908c5dc6ebd 100644 --- a/include/efi.h +++ b/include/efi.h @@ -419,10 +419,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 */ diff --git a/include/efi_api.h b/include/efi_api.h index 0accad08c8e..1f70e9e106c 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1994,4 +1994,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/lib/efi/efi_app.c b/lib/efi/efi_app.c index f61665686c5..e38d46b15db 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -21,6 +21,9 @@ #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;
@@ -46,6 +49,64 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) return -ENOSYS; }
+/** + * efi_print_str() - Print a UFT-16 string to the U-Boot console + * + * @str: String to print + */ +static void efi_print_str(const u16 *str) +{ + while (*str) { + int ch = *str++; + + if (ch > ' ' && ch < 127) + putc(ch); + } +} + +/** + * 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) +{ + struct efi_media_plat plat; + struct udevice *dev; + char name[18]; + int ret; + + 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); + + 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) { struct efi_boot_services *boot = priv->boot; @@ -105,6 +166,168 @@ static void free_memory(struct efi_priv *priv) global_data_ptr = NULL; }
+static int setup_disks(void) +{ + /* This is not fully implemented yet */ + return 0; + + efi_guid_t efi_disk_guid = EFI_DISK_IO_PROTOCOL_GUID; + struct efi_boot_services *boot = efi_get_boot(); + struct efi_disk *disk; + int ret; + + if (!boot) + return log_msg_ret("sys", -ENOSYS); + ret = boot->locate_protocol(&efi_disk_guid, NULL, (void **)&disk); + if (ret) + return log_msg_ret("prot", -ENOTSUPP); + + return 0; +} + +/** + * 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. + * + * @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. + * + * We don't seem to have have a way to print unicode on the + * U-Boot console at present, so use our own function. + */ + printf("%2d: %-12s ", i, dev ? dev->name : "<partition>"); + efi_print_str(name); + printf("\n"); + } + boot->free_pool(handle); + + return 0; +} + +int dm_scan_other(bool pre_reloc_only) +{ + if (gd->flags & GD_FLG_RELOC) { + int ret; + + ret = setup_block(); + if (ret) + return ret; + + /* Not needed at present, but could be useful one day? */ + ret = setup_disks(); + if (ret) + return ret; + } + + return 0; +} + /** * efi_main() - Start an EFI image *

The Exception base class is a very vague and could be confusing to the test system. Use the more specific ValueError exception instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/patman/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/patman/tools.py b/tools/patman/tools.py index 710f1fdcd36..86c4f616206 100644 --- a/tools/patman/tools.py +++ b/tools/patman/tools.py @@ -349,7 +349,7 @@ def Run(name, *args, **kwargs): result = command.RunPipe([all_args], capture=True, capture_stderr=True, env=env, raise_on_error=False, binary=binary) if result.return_code: - raise Exception("Error %d running '%s': %s" % + raise ValueError("Error %d running '%s': %s" % (result.return_code,' '.join(all_args), result.stderr)) return result.stdout

The Exception base class is a very vague and could be confusing to the test system. Use the more specific ValueError exception instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/patman/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Applied to u-boot-dm, thanks!

At present any error from the 'make' command is silently swallowed by the test system. Fix this by showing it when detected.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/elf_test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index 7a128018d9f..bcccd78c0a1 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -70,8 +70,12 @@ def BuildElfTestFiles(target_dir): # correctly. So drop any make flags here. if 'MAKEFLAGS' in os.environ: del os.environ['MAKEFLAGS'] - tools.Run('make', '-C', target_dir, '-f', - os.path.join(testdir, 'Makefile'), 'SRC=%s/' % testdir) + try: + tools.Run('make', '-C', target_dir, '-f', + os.path.join(testdir, 'Makefile'), 'SRC=%s/' % testdir) + except ValueError as e: + # The test system seems to suppress this in a strange way + print(e)
class TestElf(unittest.TestCase):

At present any error from the 'make' command is silently swallowed by the test system. Fix this by showing it when detected.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/elf_test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
Applied to u-boot-dm, thanks!

Binman needs to be able to update the contents of an ELF file after it has been build. To support this, add a function to locate the position of a symbol's contents within the file.
Fix the comments on bss_data.c and Symbol while we are here.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/elf.py | 53 ++++++++++++++++++++++++++++++-- tools/binman/elf_test.py | 37 ++++++++++++++++++++++ tools/binman/test/Makefile | 5 ++- tools/binman/test/bss_data.c | 2 +- tools/binman/test/embed_data.c | 16 ++++++++++ tools/binman/test/embed_data.lds | 23 ++++++++++++++ 6 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 tools/binman/test/embed_data.c create mode 100644 tools/binman/test/embed_data.lds
diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 03b49d7163c..4aca4f847ce 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -24,7 +24,14 @@ try: except: # pragma: no cover ELF_TOOLS = False
-Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak']) +# Information about an EFL symbol: +# section (str): Name of the section containing this symbol +# address (int): Address of the symbol (its value) +# size (int): Size of the symbol in bytes +# weak (bool): True if the symbol is weak +# offset (int or None): Offset of the symbol's data in the ELF file, or None if +# not known +Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak', 'offset'])
# Information about an ELF file: # data: Extracted program contents of ELF file (this would be loaded by an @@ -71,8 +78,48 @@ def GetSymbols(fname, patterns): section, size = parts[:2] if len(parts) > 2: name = parts[2] if parts[2] != '.hidden' else parts[3] - syms[name] = Symbol(section, int(value, 16), int(size,16), - flags[1] == 'w') + syms[name] = Symbol(section, int(value, 16), int(size, 16), + flags[1] == 'w', None) + + # Sort dict by address + return OrderedDict(sorted(syms.items(), key=lambda x: x[1].address)) + +def GetSymbolFileOffset(fname, patterns): + """Get the symbols from an ELF file + + Args: + fname: Filename of the ELF file to read + patterns: List of regex patterns to search for, each a string + + Returns: + None, if the file does not exist, or Dict: + key: Name of symbol + value: Hex value of symbol + """ + def _GetFileOffset(elf, addr): + for seg in elf.iter_segments(): + seg_end = seg['p_vaddr'] + seg['p_filesz'] + if seg.header['p_type'] == 'PT_LOAD': + if addr >= seg['p_vaddr'] and addr < seg_end: + return addr - seg['p_vaddr'] + seg['p_offset'] + + if not ELF_TOOLS: + raise ValueError('Python elftools package is not available') + + syms = {} + with open(fname, 'rb') as fd: + elf = ELFFile(fd) + + re_syms = re.compile('|'.join(patterns)) + for section in elf.iter_sections(): + if isinstance(section, SymbolTableSection): + for symbol in section.iter_symbols(): + if not re_syms or re_syms.search(symbol.name): + addr = symbol.entry['st_value'] + syms[symbol.name] = Symbol( + section.name, addr, symbol.entry['st_size'], + symbol.entry['st_info']['bind'] == 'STB_WEAK', + _GetFileOffset(elf, addr))
# Sort dict by address return OrderedDict(sorted(syms.items(), key=lambda x: x[1].address)) diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index bcccd78c0a1..ac69a95b654 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -6,6 +6,7 @@
import os import shutil +import struct import sys import tempfile import unittest @@ -221,6 +222,42 @@ class TestElf(unittest.TestCase): elf.DecodeElf(data, load + 2)) shutil.rmtree(outdir)
+ def testEmbedData(self): + """Test for the GetSymbolFileOffset() function""" + if not elf.ELF_TOOLS: + self.skipTest('Python elftools not available') + + fname = self.ElfTestFile('embed_data') + offset = elf.GetSymbolFileOffset(fname, ['embed_start', 'embed_end']) + start = offset['embed_start'].offset + end = offset['embed_end'].offset + data = tools.ReadFile(fname) + embed_data = data[start:end] + expect = struct.pack('<III', 0x1234, 0x5678, 0) + self.assertEqual(expect, embed_data) + + def testEmbedFail(self): + """Test calling GetSymbolFileOffset() without elftools""" + try: + old_val = elf.ELF_TOOLS + elf.ELF_TOOLS = False + fname = self.ElfTestFile('embed_data') + with self.assertRaises(ValueError) as e: + elf.GetSymbolFileOffset(fname, ['embed_start', 'embed_end']) + self.assertIn('Python elftools package is not available', + str(e.exception)) + finally: + elf.ELF_TOOLS = old_val + + def testEmbedDataNoSym(self): + """Test for GetSymbolFileOffset() getting no symbols""" + if not elf.ELF_TOOLS: + self.skipTest('Python elftools not available') + + fname = self.ElfTestFile('embed_data') + offset = elf.GetSymbolFileOffset(fname, ['missing_sym']) + self.assertEqual({}, offset) +
if __name__ == '__main__': unittest.main() diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile index 0b19b7d9935..6e6cc6de491 100644 --- a/tools/binman/test/Makefile +++ b/tools/binman/test/Makefile @@ -31,7 +31,7 @@ LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds
TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \ u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \ - u_boot_binman_syms_size u_boot_binman_syms_x86 + u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data
all: $(TARGETS)
@@ -44,6 +44,9 @@ u_boot_ucode_ptr: u_boot_ucode_ptr.c bss_data: CFLAGS += $(SRC)bss_data.lds bss_data: bss_data.c
+embed_data: CFLAGS += $(SRC)embed_data.lds +embed_data: embed_data.c + u_boot_binman_syms.bin: u_boot_binman_syms $(OBJCOPY) -O binary $< -R .note.gnu.build-id $@
diff --git a/tools/binman/test/bss_data.c b/tools/binman/test/bss_data.c index 79537c31b65..4f9b64cef9e 100644 --- a/tools/binman/test/bss_data.c +++ b/tools/binman/test/bss_data.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2016 Google, Inc * - * Simple program to create a _dt_ucode_base_size symbol which can be read + * Simple program to create a bss_data region so the symbol can be read * by binutils. This is used by binman tests. */
diff --git a/tools/binman/test/embed_data.c b/tools/binman/test/embed_data.c new file mode 100644 index 00000000000..47d8c38248c --- /dev/null +++ b/tools/binman/test/embed_data.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * + * Simple program including some embedded data that can be accessed by binman. + * This is used by binman tests. + */ + +int first[10] = {1}; +int embed[3] __attribute__((section(".embed"))) = {0x1234, 0x5678}; +int second[10] = {1}; + +int main(void) +{ + return 0; +} diff --git a/tools/binman/test/embed_data.lds b/tools/binman/test/embed_data.lds new file mode 100644 index 00000000000..908bf66c294 --- /dev/null +++ b/tools/binman/test/embed_data.lds @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2021 Google LLC + */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + _start = .; + __data_start = .; + .data : + { + . = ALIGN(32); + embed_start = .; + *(.embed*) + embed_end = .; + . = ALIGN(32); + *(.data*) + } +}

Binman needs to be able to update the contents of an ELF file after it has been build. To support this, add a function to locate the position of a symbol's contents within the file.
Fix the comments on bss_data.c and Symbol while we are here.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/elf.py | 53 ++++++++++++++++++++++++++++++-- tools/binman/elf_test.py | 37 ++++++++++++++++++++++ tools/binman/test/Makefile | 5 ++- tools/binman/test/bss_data.c | 2 +- tools/binman/test/embed_data.c | 16 ++++++++++ tools/binman/test/embed_data.lds | 23 ++++++++++++++ 6 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 tools/binman/test/embed_data.c create mode 100644 tools/binman/test/embed_data.lds
Applied to u-boot-dm, thanks!

The comment for this function is missing an argument and the return value. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/ftest.py | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 8199a4fc7e0..39a4b94cd0b 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -334,6 +334,11 @@ class TestFunctional(unittest.TestCase): extra_indirs: Extra input directories to add using -I threads: Number of threads to use (None for default, 0 for single-threaded) + test_section_timeout: True to force the first time to timeout, as + used in testThreadTimeout() + + Returns: + int return code, 0 on success """ args = [] if debug:

The comment for this function is missing an argument and the return value. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/ftest.py | 5 +++++ 1 file changed, 5 insertions(+)
Applied to u-boot-dm, thanks!

WIth EFI we must embed the devicetree in an ELF image so that it is loaded as part of the executable file. We want it to include the binman definition in there also, which in some cases cannot be created until the ELF (u-boot) is built. Add an option to binman to support writing the updated dtb to the ELF file u-boot.out
This is useful with the EFI app, which is always packaged as an ELF file.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/binman.rst | 36 ++++++++++ tools/binman/cmdline.py | 2 + tools/binman/control.py | 11 +++ tools/binman/elf.py | 21 ++++++ tools/binman/ftest.py | 83 +++++++++++++++++++++- tools/binman/test/Makefile | 10 ++- tools/binman/test/u_boot_binman_embed.c | 13 ++++ tools/binman/test/u_boot_binman_embed.lds | 29 ++++++++ tools/binman/test/u_boot_binman_embed_sm.c | 13 ++++ 9 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 tools/binman/test/u_boot_binman_embed.c create mode 100644 tools/binman/test/u_boot_binman_embed.lds create mode 100644 tools/binman/test/u_boot_binman_embed_sm.c
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index 614df541c5a..35de93bd898 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -818,6 +818,42 @@ the 'warning' line in scripts/Makefile.lib to see what it has found:: # u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
+Updating an ELF file +==================== + +For the EFI app, where U-Boot is loaded from UEFI and runs as an app, there is +no way to update the devicetree after U-Boot is built. Normally this works by +creating a new u-boot.dtb.out with he updated devicetree, which is automatically +built into the output image. With ELF this is not possible since the ELF is +not part of an image, just a stand-along file. We must create an updated ELF +file with the new devicetree. + +This is handled by the --update-fdt-in-elf option. It takes four arguments, +separated by comma: + + infile - filename of input ELF file, e.g. 'u-boot's + outfile - filename of output ELF file, e.g. 'u-boot.out' + begin_sym - symbol at the start of the embedded devicetree, e.g. + '__dtb_dt_begin' + end_sym - symbol at the start of the embedded devicetree, e.g. + '__dtb_dt_end' + +When this flag is used, U-Boot does all the normal packaging, but as an +additional step, it creates a new ELF file with the new devicetree embedded in +it. + +If logging is enabled you will see a message like this:: + + Updating file 'u-boot' with data length 0x400a (16394) between symbols + '__dtb_dt_begin' and '__dtb_dt_end' + +There must be enough space for the updated devicetree. If not, an error like +the following is produced:: + + ValueError: Not enough space in 'u-boot' for data length 0x400a (16394); + size is 0x1744 (5956) + + Entry Documentation ===================
diff --git a/tools/binman/cmdline.py b/tools/binman/cmdline.py index d6156df408b..23729f16dcc 100644 --- a/tools/binman/cmdline.py +++ b/tools/binman/cmdline.py @@ -71,6 +71,8 @@ controlled by a description in the board device tree.''' 'given') build_parser.add_argument('-u', '--update-fdt', action='store_true', default=False, help='Update the binman node with offset/size info') + build_parser.add_argument('--update-fdt-in-elf', type=str, + help='Update an ELF file with the output dtb: infile,outfile,begin_sym,end_sym')
entry_parser = subparsers.add_parser('entry-docs', help='Write out entry documentation (see entries.rst)') diff --git a/tools/binman/control.py b/tools/binman/control.py index 0dbcbc28e99..a56e65ace64 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -595,6 +595,13 @@ def Binman(args): tools.FinaliseOutputDir() return 0
+ elf_params = None + if args.update_fdt_in_elf: + elf_params = args.update_fdt_in_elf.split(',') + if len(elf_params) != 4: + raise ValueError('Invalid args %s to --update-fdt-in-elf: expected infile,outfile,begin_sym,end_sym' % + elf_params) + # Try to figure out which device tree contains our image description if args.dt: dtb_fname = args.dt @@ -641,6 +648,10 @@ def Binman(args): for dtb_item in state.GetAllFdts(): tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
+ if elf_params: + data = state.GetFdtForEtype('u-boot-dtb').GetContents() + elf.UpdateFile(*elf_params, data) + if missing: tout.Warning("\nSome images are invalid")
diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 4aca4f847ce..de2bb4651fa 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -348,3 +348,24 @@ def DecodeElf(data, location): segment.data()[offset:]) return ElfInfo(output, data_start, elf.header['e_entry'] + virt_to_phys, mem_end - data_start) + +def UpdateFile(infile, outfile, start_sym, end_sym, insert): + tout.Notice("Creating file '%s' with data length %#x (%d) between symbols '%s' and '%s'" % + (outfile, len(insert), len(insert), start_sym, end_sym)) + syms = GetSymbolFileOffset(infile, [start_sym, end_sym]) + if len(syms) != 2: + raise ValueError("Expected two symbols '%s' and '%s': got %d: %s" % + (start_sym, end_sym, len(syms), + ','.join(syms.keys()))) + + size = syms[end_sym].offset - syms[start_sym].offset + if len(insert) > size: + raise ValueError("Not enough space in '%s' for data length %#x (%d); size is %#x (%d)" % + (infile, len(insert), len(insert), size, size)) + + data = tools.ReadFile(infile) + newdata = data[:syms[start_sym].offset] + newdata += insert + tools.GetBytes(0, size - len(insert)) + newdata += data[syms[end_sym].offset:] + tools.WriteFile(outfile, newdata) + tout.Info('Written to offset %#x' % syms[start_sym].offset) diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 39a4b94cd0b..6be003786e8 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -309,7 +309,7 @@ class TestFunctional(unittest.TestCase): entry_args=None, images=None, use_real_dtb=False, use_expanded=False, verbosity=None, allow_missing=False, extra_indirs=None, threads=None, - test_section_timeout=False): + test_section_timeout=False, update_fdt_in_elf=None): """Run binman with a given test file
Args: @@ -336,6 +336,7 @@ class TestFunctional(unittest.TestCase): single-threaded) test_section_timeout: True to force the first time to timeout, as used in testThreadTimeout() + update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Returns: int return code, 0 on success @@ -368,6 +369,8 @@ class TestFunctional(unittest.TestCase): args.append('-a%s=%s' % (arg, value)) if allow_missing: args.append('-M') + if update_fdt_in_elf: + args += ['--update-fdt-in-elf', update_fdt_in_elf] if images: for image in images: args += ['-i', image] @@ -4580,6 +4583,84 @@ class TestFunctional(unittest.TestCase): self.assertIn('read:', stdout.getvalue()) self.assertIn('compress:', stdout.getvalue())
+ def testUpdateFdtInElf(self): + """Test that we can update the devicetree in an ELF file""" + infile = elf_fname = self.ElfTestFile('u_boot_binman_embed') + outfile = os.path.join(self._indir, 'u-boot.out') + begin_sym = 'dtb_embed_begin' + end_sym = 'dtb_embed_end' + retcode = self._DoTestFile( + '060_fdt_update.dts', update_dtb=True, + update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym])) + self.assertEqual(0, retcode) + + # Check that the output file does in fact contact a dtb with the binman + # definition in the correct place + syms = elf.GetSymbolFileOffset(infile, + ['dtb_embed_begin', 'dtb_embed_end']) + data = tools.ReadFile(outfile) + dtb_data = data[syms['dtb_embed_begin'].offset: + syms['dtb_embed_end'].offset] + + dtb = fdt.Fdt.FromData(dtb_data) + dtb.Scan() + props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS) + self.assertEqual({ + 'image-pos': 0, + 'offset': 0, + '_testing:offset': 32, + '_testing:size': 2, + '_testing:image-pos': 32, + 'section@0/u-boot:offset': 0, + 'section@0/u-boot:size': len(U_BOOT_DATA), + 'section@0/u-boot:image-pos': 0, + 'section@0:offset': 0, + 'section@0:size': 16, + 'section@0:image-pos': 0, + + 'section@1/u-boot:offset': 0, + 'section@1/u-boot:size': len(U_BOOT_DATA), + 'section@1/u-boot:image-pos': 16, + 'section@1:offset': 16, + 'section@1:size': 16, + 'section@1:image-pos': 16, + 'size': 40 + }, props) + + def testUpdateFdtInElfInvalid(self): + """Test that invalid args are detected with --update-fdt-in-elf""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred') + self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf", + str(e.exception)) + + def testUpdateFdtInElfNoSyms(self): + """Test that missing symbols are detected with --update-fdt-in-elf""" + infile = elf_fname = self.ElfTestFile('u_boot_binman_embed') + outfile = '' + begin_sym = 'wrong_begin' + end_sym = 'wrong_end' + with self.assertRaises(ValueError) as e: + self._DoTestFile( + '060_fdt_update.dts', + update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym])) + self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:", + str(e.exception)) + + def testUpdateFdtInElfTooSmall(self): + """Test that an over-large dtb is detected with --update-fdt-in-elf""" + infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm') + outfile = os.path.join(self._indir, 'u-boot.out') + begin_sym = 'dtb_embed_begin' + end_sym = 'dtb_embed_end' + with self.assertRaises(ValueError) as e: + self._DoTestFile( + '060_fdt_update.dts', update_dtb=True, + update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym])) + self.assertRegex( + str(e.exception), + "Not enough space in '.*u_boot_binman_embed_sm' for data length.*") +
if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile index 6e6cc6de491..387ba163353 100644 --- a/tools/binman/test/Makefile +++ b/tools/binman/test/Makefile @@ -28,10 +28,12 @@ LDS_UCODE := -T $(SRC)u_boot_ucode_ptr.lds LDS_BINMAN := -T $(SRC)u_boot_binman_syms.lds LDS_BINMAN_BAD := -T $(SRC)u_boot_binman_syms_bad.lds LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds +LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds
TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \ u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \ - u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data + u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data \ + u_boot_binman_embed u_boot_binman_embed_sm
all: $(TARGETS)
@@ -62,6 +64,12 @@ u_boot_binman_syms_bad: u_boot_binman_syms_bad.c u_boot_binman_syms_size: CFLAGS += $(LDS_BINMAN) u_boot_binman_syms_size: u_boot_binman_syms_size.c
+u_boot_binman_embed: CFLAGS += $(LDS_BINMAN_EMBED) +u_boot_binman_embed: u_boot_binman_embed.c + +u_boot_binman_embed_sm: CFLAGS += $(LDS_BINMAN_EMBED) +u_boot_binman_embed_sm: u_boot_binman_embed_sm.c + clean: rm -f $(TARGETS)
diff --git a/tools/binman/test/u_boot_binman_embed.c b/tools/binman/test/u_boot_binman_embed.c new file mode 100644 index 00000000000..75874bb6e23 --- /dev/null +++ b/tools/binman/test/u_boot_binman_embed.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * + * Simple program to embed a devicetree. This is used by binman tests. + */ + +int __attribute__((section(".mydtb"))) dtb_data[4096]; + +int main(void) +{ + return 0; +} diff --git a/tools/binman/test/u_boot_binman_embed.lds b/tools/binman/test/u_boot_binman_embed.lds new file mode 100644 index 00000000000..e213fa8a84c --- /dev/null +++ b/tools/binman/test/u_boot_binman_embed.lds @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2016 Google, Inc + */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 0x00000000; + _start = .; + + . = ALIGN(4); + .text : + { + *(.text*) + } + + . = ALIGN(4); + .data : { + dtb_embed_begin = .; + KEEP(*(.mydtb)); + dtb_embed_end = .; + } + .interp : { *(.interp*) } + +} diff --git a/tools/binman/test/u_boot_binman_embed_sm.c b/tools/binman/test/u_boot_binman_embed_sm.c new file mode 100644 index 00000000000..ae245d78a6a --- /dev/null +++ b/tools/binman/test/u_boot_binman_embed_sm.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * + * Simple program to embed a devicetree. This is used by binman tests. + */ + +int __attribute__((section(".mydtb"))) dtb_data[16]; + +int main(void) +{ + return 0; +}

WIth EFI we must embed the devicetree in an ELF image so that it is loaded as part of the executable file. We want it to include the binman definition in there also, which in some cases cannot be created until the ELF (u-boot) is built. Add an option to binman to support writing the updated dtb to the ELF file u-boot.out
This is useful with the EFI app, which is always packaged as an ELF file.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/binman.rst | 36 ++++++++++ tools/binman/cmdline.py | 2 + tools/binman/control.py | 11 +++ tools/binman/elf.py | 21 ++++++ tools/binman/ftest.py | 83 +++++++++++++++++++++- tools/binman/test/Makefile | 10 ++- tools/binman/test/u_boot_binman_embed.c | 13 ++++ tools/binman/test/u_boot_binman_embed.lds | 29 ++++++++ tools/binman/test/u_boot_binman_embed_sm.c | 13 ++++ 9 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 tools/binman/test/u_boot_binman_embed.c create mode 100644 tools/binman/test/u_boot_binman_embed.lds create mode 100644 tools/binman/test/u_boot_binman_embed_sm.c
Applied to u-boot-dm, thanks!

At present only the backspace key is supported in U-Boot, when running as an EFI app. Add support for arrows, home and end as well, to make the CLI more friendly.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
drivers/serial/serial_efi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c index 33ddbd6080c..0067576389d 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;

Typically the bloblist is positioned at a fixed address in memory until relocation. This is convenient when it is set up in SPL or before relocation.
But for EFI we want to set it up only when U-Boot proper is running. Add a way to allocate it using malloc() and update the documentation to cover this aspect of bloblist.
Note there are no tests of this feature at present, nor any direct testing of bloblist_init().
This can be added, e.g. by making this option controllable at runtime.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
common/Kconfig | 15 +++++++++++++-- common/bloblist.c | 16 ++++++++++++++-- common/board_f.c | 8 +++++++- doc/develop/bloblist.rst | 16 ++++++++++++++++ 4 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/common/Kconfig b/common/Kconfig index d6f77ab7b9c..00ccaf59fa4 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -719,6 +719,8 @@ config TPL_BLOBLIST This enables a bloblist in TPL. The bloblist is set up in TPL and passed to SPL and U-Boot proper.
+if BLOBLIST + config BLOBLIST_SIZE hex "Size of bloblist" depends on BLOBLIST @@ -729,17 +731,24 @@ config BLOBLIST_SIZE is set up in the first part of U-Boot to run (TPL, SPL or U-Boot proper), and this sane bloblist is used for subsequent stages.
+config BLOBLIST_ALLOC + bool "Allocate bloblist" + help + Allocate the bloblist using malloc(). This avoids the need to + specify a fixed address on systems where this is unknown or can + change at runtime. + config BLOBLIST_ADDR hex "Address of bloblist" - depends on BLOBLIST default 0xc000 if SANDBOX help Sets the address of the bloblist, set up by the first part of U-Boot which runs. Subsequent U-Boot stages typically use the same address.
+ This is not used if BLOBLIST_ALLOC is selected. + config BLOBLIST_SIZE_RELOC hex "Size of bloblist after relocation" - depends on BLOBLIST default BLOBLIST_SIZE help Sets the size of the bloblist in bytes after relocation. Since U-Boot @@ -747,6 +756,8 @@ config BLOBLIST_SIZE_RELOC size than the one set up by SPL. This bloblist is set up during the relocation process.
+endif # BLOBLIST + endmenu
source "common/spl/Kconfig" diff --git a/common/bloblist.c b/common/bloblist.c index 1290fff8504..01b04103d91 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -7,6 +7,7 @@ #include <common.h> #include <bloblist.h> #include <log.h> +#include <malloc.h> #include <mapmem.h> #include <spl.h> #include <asm/global_data.h> @@ -416,10 +417,21 @@ int bloblist_init(void) ret = bloblist_check(CONFIG_BLOBLIST_ADDR, CONFIG_BLOBLIST_SIZE); if (ret) { + ulong addr; + log(LOGC_BLOBLIST, expected ? LOGL_WARNING : LOGL_DEBUG, "Existing bloblist not found: creating new bloblist\n"); - ret = bloblist_new(CONFIG_BLOBLIST_ADDR, CONFIG_BLOBLIST_SIZE, - 0); + if (IS_ENABLED(CONFIG_BLOBLIST_ALLOC)) { + void *ptr = memalign(BLOBLIST_ALIGN, + CONFIG_BLOBLIST_SIZE); + + if (!ptr) + return log_msg_ret("alloc", -ENOMEM); + addr = map_to_sysmem(ptr); + } else { + addr = CONFIG_BLOBLIST_ADDR; + } + ret = bloblist_new(addr, CONFIG_BLOBLIST_SIZE, 0); } else { log(LOGC_BLOBLIST, LOGL_DEBUG, "Found existing bloblist\n"); } diff --git a/common/board_f.c b/common/board_f.c index 3dc0eaa59c5..c8d25b5e1de 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -655,8 +655,14 @@ static int reloc_bootstage(void) static int reloc_bloblist(void) { #ifdef CONFIG_BLOBLIST - if (gd->flags & GD_FLG_SKIP_RELOC) + /* + * Relocate only if we are supposed to send it + */ + if ((gd->flags & GD_FLG_SKIP_RELOC) && + CONFIG_BLOBLIST_SIZE == CONFIG_BLOBLIST_SIZE_RELOC) { + debug("Not relocating bloblist\n"); return 0; + } if (gd->new_bloblist) { int size = CONFIG_BLOBLIST_SIZE;
diff --git a/doc/develop/bloblist.rst b/doc/develop/bloblist.rst index 317ebc4919d..47274cf8e26 100644 --- a/doc/develop/bloblist.rst +++ b/doc/develop/bloblist.rst @@ -59,6 +59,22 @@ Bloblist provides a fairly simple API which allows blobs to be created and found. All access is via the blob's tag. Blob records are zeroed when added.
+Placing the bloblist +-------------------- + +The bloblist is typically positioned at a fixed address by TPL, or SPL. This +is controlled by `CONFIG_BLOBLIST_ADDR`. But in some cases it is preferable to +allocate the bloblist in the malloc() space. Use the `CONFIG_BLOBLIST_ALLOC` +option to enable this. + +The bloblist is automatically relocated as part of U-Boot relocation. Sometimes +it is useful to expand the bloblist in U-Boot proper, since it may want to add +information for use by Linux. Note that this does not mean that Linux needs to +know anything about the bloblist format, just that it is convenient to use +bloblist to place things contiguously in memory. Set +`CONFIG_BLOBLIST_SIZE_RELOC` to define the expanded size, if needed. + + Finishing the bloblist ----------------------

Typically the bloblist is positioned at a fixed address in memory until relocation. This is convenient when it is set up in SPL or before relocation.
But for EFI we want to set it up only when U-Boot proper is running. Add a way to allocate it using malloc() and update the documentation to cover this aspect of bloblist.
Note there are no tests of this feature at present, nor any direct testing of bloblist_init().
This can be added, e.g. by making this option controllable at runtime.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
common/Kconfig | 15 +++++++++++++-- common/bloblist.c | 16 ++++++++++++++-- common/board_f.c | 8 +++++++- doc/develop/bloblist.rst | 16 ++++++++++++++++ 4 files changed, 50 insertions(+), 5 deletions(-)
Applied to u-boot-dm/next, thanks!

At present this is disabled, but it should work so long as the kernel does not need EFI services. Enable it and add a note about remaining work.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v2)
Changes in v2: - Update documentation
arch/x86/lib/bootm.c | 11 +++++++---- doc/develop/uefi/u-boot_on_efi.rst | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 667e5e689e3..57cba5c65d3 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/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 8f81b799072..acad6397e81 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -269,7 +269,7 @@ This work could be extended in a number of ways:
- 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? ------------------

If the 'bootm' command is not enabled then this code is not available and this causes a link error. Fix it.
Note that for the EFI app, there is no indication of missing code. It just hangs!
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
arch/x86/lib/zimage.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 7ce02226ef9..9cc04490307 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);

At present only 4KB of spare space is left in the DTB when building the EFI app. Increase this to 32KB so there is plenty of space to insert the binman definition. This cannot be expanded later (as with OF_SEPARATE) because the ELF image has already been built.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
arch/x86/dts/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/dts/Makefile b/arch/x86/dts/Makefile index be209aaaf8f..5c8c05ec499 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))

This is not used anywhere drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v3)
Changes in v3: - Move device_path path change to its own patch
include/efi.h | 1 - 1 file changed, 1 deletion(-)
diff --git a/include/efi.h b/include/efi.h index 908c5dc6ebd..77e599c256e 100644 --- a/include/efi.h +++ b/include/efi.h @@ -402,7 +402,6 @@ static inline struct efi_mem_desc *efi_get_next_mem_desc(
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;

This structure is uncommented. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v3)
Changes in v3: - Drop comments that confuse sphinx - Move device_path path change to its own patch
include/efi.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/include/efi.h b/include/efi.h index 77e599c256e..6622a733e6e 100644 --- a/include/efi.h +++ b/include/efi.h @@ -400,14 +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, in bytes from @info + * @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_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;

The stub checks for failure with efi_init(). Add this for the app as well. It is unlikely that anything can be done, but we may as well stop.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
lib/efi/efi_app.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 23a65c46fd4..e454f1a1564 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -325,8 +325,11 @@ 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); - + ret = efi_init(priv, "App", image, sys_table); + if (ret) { + printf("Failed to set up ARP: err=%lx\n", ret); + return ret; + } efi_set_priv(priv);
/*

This provides access to EFI tables after U-Boot has exited boot services. It is not needed in the app since boot services remain alive and we can just call them whenever needed.
Add a comment to explain this.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v2)
Changes in v2: - Fix 'as' typo
include/efi.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/efi.h b/include/efi.h index ed28c204140..69321cc5cc4 100644 --- a/include/efi.h +++ b/include/efi.h @@ -578,6 +578,10 @@ void efi_putc(struct efi_priv *priv, const char ch); /** * efi_info_get() - get an entry from an EFI table * + * This 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 stuff, 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

Add a message here so that both paths of memory allocation are reported.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v2)
Changes in v2: - Use log_info() instead of printf()
lib/efi/efi_app.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index e454f1a1564..36e3f1de427 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -121,13 +121,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;

Add info about how to select vidconsole or serial.
Also set up a demo boot command.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v2)
Changes in v2: - Add a better boot command too
include/configs/efi-x86_app.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/include/configs/efi-x86_app.h b/include/configs/efi-x86_app.h index 6061a6db0a4..33afb7ca0f9 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

At present this function requires a pointer to struct efi_entry_memmap but the only field used in there is the desc_size. We want to be able to use it from the app, so update it to use desc_size directly.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
arch/x86/cpu/efi/payload.c | 8 ++++---- cmd/efi.c | 34 ++++++++++++++++++---------------- include/efi.h | 4 ++-- 3 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c index 3a9f7d72868..d2aa889a2b9 100644 --- a/arch/x86/cpu/efi/payload.c +++ b/arch/x86/cpu/efi/payload.c @@ -50,7 +50,7 @@ ulong board_get_usable_ram_top(ulong total_size)
end = (struct efi_mem_desc *)((ulong)map + size); desc = map->desc; - for (; desc < end; desc = efi_get_next_mem_desc(map, desc)) { + for (; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) { if (desc->type != EFI_CONVENTIONAL_MEMORY || desc->physical_start >= 1ULL << 32) continue; @@ -88,7 +88,7 @@ int dram_init(void) end = (struct efi_mem_desc *)((ulong)map + size); gd->ram_size = 0; desc = map->desc; - for (; desc < end; desc = efi_get_next_mem_desc(map, desc)) { + for (; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) { if (desc->type < EFI_MMAP_IO) gd->ram_size += desc->num_pages << EFI_PAGE_SHIFT; } @@ -113,7 +113,7 @@ int dram_init_banksize(void) desc = map->desc; for (num_banks = 0; desc < end && num_banks < CONFIG_NR_DRAM_BANKS; - desc = efi_get_next_mem_desc(map, desc)) { + desc = efi_get_next_mem_desc(desc, map->desc_size)) { /* * We only use conventional memory and ignore * anything less than 1MB. @@ -196,7 +196,7 @@ unsigned int install_e820_map(unsigned int max_entries,
end = (struct efi_mem_desc *)((ulong)map + size); for (desc = map->desc; desc < end; - desc = efi_get_next_mem_desc(map, desc)) { + desc = efi_get_next_mem_desc(desc, map->desc_size)) { if (desc->num_pages == 0) continue;
diff --git a/cmd/efi.c b/cmd/efi.c index f2ed26bd4b2..d2400acbbba 100644 --- a/cmd/efi.c +++ b/cmd/efi.c @@ -75,16 +75,17 @@ static int h_cmp_entry(const void *v1, const void *v2) /** * efi_build_mem_table() - make a sorted copy of the memory table * - * @map: Pointer to EFI memory map table + * @desc_base: Pointer to EFI memory map table * @size: Size of table in bytes + * @desc_size: Size of each @desc_base record * @skip_bs: True to skip boot-time memory and merge it with conventional * memory. This will significantly reduce the number of table * entries. * Return: pointer to the new table. It should be freed with free() by the * caller. */ -static void *efi_build_mem_table(struct efi_entry_memmap *map, int size, - bool skip_bs) +static void *efi_build_mem_table(struct efi_mem_desc *desc_base, int size, + int desc_size, bool skip_bs) { struct efi_mem_desc *desc, *end, *base, *dest, *prev; int count; @@ -95,15 +96,16 @@ static void *efi_build_mem_table(struct efi_entry_memmap *map, int size, debug("%s: Cannot allocate %#x bytes\n", __func__, size); return NULL; } - end = (struct efi_mem_desc *)((ulong)map + size); - count = ((ulong)end - (ulong)map->desc) / map->desc_size; - memcpy(base, map->desc, (ulong)end - (ulong)map->desc); - qsort(base, count, map->desc_size, h_cmp_entry); + end = (void *)desc_base + size; + count = ((ulong)end - (ulong)desc_base) / desc_size; + memcpy(base, desc_base, (ulong)end - (ulong)desc_base); + qsort(base, count, desc_size, h_cmp_entry); prev = NULL; addr = 0; dest = base; - end = (struct efi_mem_desc *)((ulong)base + count * map->desc_size); - for (desc = base; desc < end; desc = efi_get_next_mem_desc(map, desc)) { + end = (struct efi_mem_desc *)((ulong)base + count * desc_size); + for (desc = base; desc < end; + desc = efi_get_next_mem_desc(desc, desc_size)) { bool merge = true; u32 type = desc->type;
@@ -116,7 +118,7 @@ static void *efi_build_mem_table(struct efi_entry_memmap *map, int size, if (skip_bs && is_boot_services(desc->type)) type = EFI_CONVENTIONAL_MEMORY;
- memcpy(dest, desc, map->desc_size); + memcpy(dest, desc, desc_size); dest->type = type; if (!skip_bs || !prev) merge = false; @@ -131,7 +133,7 @@ static void *efi_build_mem_table(struct efi_entry_memmap *map, int size, prev->num_pages += desc->num_pages; } else { prev = dest; - dest = efi_get_next_mem_desc(map, dest); + dest = efi_get_next_mem_desc(dest, desc_size); } addr = desc->physical_start + (desc->num_pages << EFI_PAGE_SHIFT); @@ -143,8 +145,8 @@ static void *efi_build_mem_table(struct efi_entry_memmap *map, int size, return base; }
-static void efi_print_mem_table(struct efi_entry_memmap *map, - struct efi_mem_desc *desc, bool skip_bs) +static void efi_print_mem_table(struct efi_mem_desc *desc, int desc_size, + bool skip_bs) { u64 attr_seen[ATTR_SEEN_MAX]; int attr_seen_count; @@ -158,7 +160,7 @@ static void efi_print_mem_table(struct efi_entry_memmap *map, attr_seen_count = 0; addr = 0; for (upto = 0; desc->type != EFI_MAX_MEMORY_TYPE; - upto++, desc = efi_get_next_mem_desc(map, desc)) { + upto++, desc = efi_get_next_mem_desc(desc, desc_size)) { const char *name; u64 size;
@@ -238,13 +240,13 @@ static int do_efi_mem(struct cmd_tbl *cmdtp, int flag, int argc, goto done; }
- desc = efi_build_mem_table(map, size, skip_bs); + desc = efi_build_mem_table(map->desc, size, map->desc_size, skip_bs); if (!desc) { ret = -ENOMEM; goto done; }
- efi_print_mem_table(map, desc, skip_bs); + efi_print_mem_table(desc, map->desc_size, skip_bs); free(desc); done: if (ret) diff --git a/include/efi.h b/include/efi.h index 69321cc5cc4..1dc806a1267 100644 --- a/include/efi.h +++ b/include/efi.h @@ -395,9 +395,9 @@ struct efi_entry_systable { };
static inline struct efi_mem_desc *efi_get_next_mem_desc( - struct efi_entry_memmap *map, struct efi_mem_desc *desc) + struct efi_mem_desc *desc, int desc_size) { - return (struct efi_mem_desc *)((ulong)desc + map->desc_size); + return (struct efi_mem_desc *)((ulong)desc + desc_size); }
/**

At present the 'efi' command only works in the EFI payload. Update it to work in the app too, so the memory map can be examined.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
cmd/Makefile | 2 +- cmd/efi.c | 48 ++++++++++++++++++++++++++++++++--------------- include/efi.h | 15 +++++++++++++++ lib/efi/efi_app.c | 33 ++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 16 deletions(-)
diff --git a/cmd/Makefile b/cmd/Makefile index ed3669411e6..3e9f23ebf30 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_CMD_EXTENSION) += extension_board.o obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o -obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_EFI) += efi.o obj-$(CONFIG_CMD_EFIDEBUG) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o diff --git a/cmd/efi.c b/cmd/efi.c index d2400acbbba..c0384e0db28 100644 --- a/cmd/efi.c +++ b/cmd/efi.c @@ -13,6 +13,8 @@ #include <sort.h> #include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR; + static const char *const type_name[] = { "reserved", "loader_code", @@ -217,37 +219,53 @@ static void efi_print_mem_table(struct efi_mem_desc *desc, int desc_size, static int do_efi_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct efi_mem_desc *desc; - struct efi_entry_memmap *map; + struct efi_mem_desc *orig, *desc; + uint version, key; + int desc_size; int size, ret; bool skip_bs;
skip_bs = !argc || *argv[0] != 'a'; - ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); - switch (ret) { - case -ENOENT: - printf("No EFI table available\n"); - goto done; - case -EPROTONOSUPPORT: - printf("Incorrect EFI table version\n"); - goto done; + if (IS_ENABLED(CONFIG_EFI_APP)) { + ret = efi_get_mmap(&orig, &size, &key, &desc_size, &version); + if (ret) { + printf("Cannot read memory map (err=%d)\n", ret); + return CMD_RET_FAILURE; + } + } else { + struct efi_entry_memmap *map; + + ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); + switch (ret) { + case -ENOENT: + printf("No EFI table available\n"); + goto done; + case -EPROTONOSUPPORT: + printf("Incorrect EFI table version\n"); + goto done; + } + orig = map->desc; + desc_size = map->desc_size; + version = map->version; } - printf("EFI table at %lx, memory map %p, size %x, version %x, descr. size %#x\n", - gd->arch.table, map, size, map->version, map->desc_size); - if (map->version != EFI_MEM_DESC_VERSION) { + printf("EFI table at %lx, memory map %p, size %x, key %x, version %x, descr. size %#x\n", + gd->arch.table, orig, size, key, version, desc_size); + if (version != EFI_MEM_DESC_VERSION) { printf("Incorrect memory map version\n"); ret = -EPROTONOSUPPORT; goto done; }
- desc = efi_build_mem_table(map->desc, size, map->desc_size, skip_bs); + desc = efi_build_mem_table(orig, size, desc_size, skip_bs); if (!desc) { ret = -ENOMEM; goto done; }
- efi_print_mem_table(desc, map->desc_size, skip_bs); + efi_print_mem_table(desc, desc_size, skip_bs); free(desc); + if (IS_ENABLED(CONFIG_EFI_APP)) + free(orig); done: if (ret) printf("Error: %d\n", ret); diff --git a/include/efi.h b/include/efi.h index 1dc806a1267..8a43430d3df 100644 --- a/include/efi.h +++ b/include/efi.h @@ -610,4 +610,19 @@ int efi_store_memory_map(struct efi_priv *priv); */ int efi_call_exit_boot_services(void);
+/** + * efi_get_mmap() - Get the memory map from EFI + * + * This is used in the app. The caller must free *@descp when done + * + * @descp: Returns allocated pointer to EFI memory map table + * @sizep: Returns size of table in bytes + * @keyp: Returns memory-map key + * @desc_sizep: Returns size of each @desc_base record + * @versionp: Returns version number of memory map + * @return 0 on success, -ve on error + */ +int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp, + int *desc_sizep, uint *versionp); + #endif /* _LINUX_EFI_H */ diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 36e3f1de427..55fa1ac57d5 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -32,6 +32,39 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) return -ENOSYS; }
+int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp, + int *desc_sizep, uint *versionp) +{ + struct efi_priv *priv = efi_get_priv(); + struct efi_boot_services *boot = priv->sys_table->boottime; + efi_uintn_t size, desc_size, key; + struct efi_mem_desc *desc; + efi_status_t ret; + u32 version; + + /* Get the memory map so we can switch off EFI */ + size = 0; + ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version); + if (ret != EFI_BUFFER_TOO_SMALL) + return log_msg_ret("get", -ENOMEM); + + desc = malloc(size); + if (!desc) + return log_msg_ret("mem", -ENOMEM); + + ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version); + if (ret) + return log_msg_ret("get", -EINVAL); + + *descp = desc; + *sizep = size; + *desc_sizep = desc_size; + *versionp = version; + *keyp = key; + + return 0; +} + /** * efi_print_str() - Print a UFT-16 string to the U-Boot console *

Show the revision of this table this is can be important.
Alo update the 'efi table' entry to show the actual address of the EFI table rather than our table that points to it. This saves a step and the intermediate table has nothing else in it.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v3)
Changes in v3: - Add new patch to show the system-table revision
Changes in v2: - Add new patch to support the efi command in the app
arch/x86/cpu/efi/payload.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c index d2aa889a2b9..b7778565b19 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); + } }
participants (3)
-
AKASHI Takahiro
-
Heinrich Schuchardt
-
Simon Glass