[PATCH v4 01/34] efi: Add a script to build an image for testing on UEFI

Heinrich Schuchardt xypron.glpk at gmx.de
Sun Nov 7 08:43:54 CET 2021



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 at 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 at 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 at 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=sharing
> +
> +# OVMF-pure-efi.x64.fd at
> +# https://drive.google.com/file/d/1c39YI9QtpByGQ4V0UNNQtGqttEzS-eFV/view?usp=sharing
> +
> +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
>


More information about the U-Boot mailing list