]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
efi: Add a script to build an image for testing on UEFI
authorSimon Glass <sjg@chromium.org>
Thu, 4 Nov 2021 03:09:03 +0000 (21:09 -0600)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Sun, 7 Nov 2021 17:36:55 +0000 (18:36 +0100)
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>
MAINTAINERS
doc/develop/uefi/u-boot_on_efi.rst
scripts/build-efi.sh [new file with mode: 0755]

index 9d8cba9028001e44afe05ad452a801f41546f5db..fa7fe90070515a05edfe476c806be1ba072149d5 100644 (file)
@@ -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>
index 43afb11de561542cd47ec7ffaf38fb20dbcae6a8..8856af3db56bcc4e8abf628cace0a8873aff7653 100644 (file)
@@ -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 (executable)
index 0000000..bc9aeeb
--- /dev/null
@@ -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
+}
+
+# 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 partition
+       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