uboot/scripts/build-efi.sh
<<
>>
Prefs
   1#!/bin/bash
   2# SPDX-License-Identifier: GPL-2.0+
   3#
   4# Script to build an EFI thing suitable for booting with QEMU, possibly running
   5# it also.
   6
   7# This just an example. It assumes that
   8
   9# - you build U-Boot in ${ubdir}/<name> where <name> is the U-Boot board config
  10# - /mnt/x is a directory used for mounting
  11# - you have access to the 'pure UEFI' builds for QEMU
  12#
  13# UEFI binaries for QEMU used for testing this script:
  14#
  15# OVMF-pure-efi.i386.fd at
  16# https://drive.google.com/file/d/1jWzOAZfQqMmS2_dAK2G518GhIgj9r2RY/view?usp=sharing
  17
  18# OVMF-pure-efi.x64.fd at
  19# https://drive.google.com/file/d/1c39YI9QtpByGQ4V0UNNQtGqttEzS-eFV/view?usp=sharing
  20
  21set -e
  22
  23usage() {
  24        echo "Usage: $0 [-a | -p] [other opts]" 1>&2
  25        echo 1>&2
  26        echo "   -a   - Package up the app" 1>&2
  27        echo "   -o   - Use old EFI app build (before 32/64 split)" 1>&2
  28        echo "   -p   - Package up the payload" 1>&2
  29        echo "   -P   - Create a partition table" 1>&2
  30        echo "   -r   - Run QEMU with the image" 1>&2
  31        echo "   -s   - Run QEMU with serial only (no display)" 1>&2
  32        echo "   -w   - Use word version (32-bit)" 1>&2
  33        exit 1
  34}
  35
  36# 32- or 64-bit EFI
  37bitness=64
  38
  39# app or payload ?
  40type=app
  41
  42# create a partition table and put the filesystem in that (otherwise put the
  43# filesystem in the raw device)
  44part=
  45
  46# run the image with QEMU
  47run=
  48
  49# run QEMU without a display (U-Boot must be set to stdout=serial)
  50serial=
  51
  52# before the 32/64 split of the app
  53old=
  54
  55# Set ubdir to the build directory where you build U-Boot out-of-tree
  56# We avoid in-tree build because it gets confusing trying different builds
  57ubdir=/tmp/b/
  58
  59while getopts "aopPrsw" opt; do
  60        case "${opt}" in
  61        a)
  62                type=app
  63                ;;
  64        p)
  65                type=payload
  66                ;;
  67        r)
  68                run=1
  69                ;;
  70        s)
  71                serial=1
  72                ;;
  73        w)
  74                bitness=32
  75                ;;
  76        o)
  77                old=1
  78                ;;
  79        P)
  80                part=1
  81                ;;
  82        *)
  83                usage
  84                ;;
  85        esac
  86done
  87
  88run_qemu() {
  89        extra=
  90        if [[ "${bitness}" = "64" ]]; then
  91                qemu=qemu-system-x86_64
  92                bios=OVMF-pure-efi.x64.fd
  93        else
  94                qemu=qemu-system-i386
  95                bios=OVMF-pure-efi.i386.fd
  96        fi
  97        if [[ -n "${serial}" ]]; then
  98                extra="-display none -serial mon:stdio"
  99        fi
 100        echo "Running ${qemu}"
 101        # Use 512MB since U-Boot EFI likes to have 256MB to play with
 102        "${qemu}" -bios "${bios}" \
 103                -m 512 \
 104                -drive id=disk,file="${IMG}",if=none,format=raw \
 105                -nic none -device ahci,id=ahci \
 106                -device ide-hd,drive=disk,bus=ahci.0 ${extra}
 107}
 108
 109setup_files() {
 110        echo "Packaging ${BUILD}"
 111        mkdir -p $TMP
 112        cat >$TMP/startup.nsh <<EOF
 113fs0:u-boot-${type}.efi
 114EOF
 115        sudo cp ${ubdir}/${BUILD}/u-boot-${type}.efi $TMP
 116
 117        # Can copy in other files here:
 118        #sudo cp ${ubdir}/$BUILD/image.bin $TMP/chromeos.rom
 119        #sudo cp /boot/vmlinuz-5.4.0-77-generic $TMP/vmlinuz
 120}
 121
 122# Copy files into the filesystem
 123copy_files() {
 124        sudo cp $TMP/* $MNT
 125}
 126
 127# Create a filesystem on a raw device and copy in the files
 128setup_raw() {
 129        mkfs.vfat "${IMG}" >/dev/null
 130        sudo mount -o loop "${IMG}" $MNT
 131        copy_files
 132        sudo umount $MNT
 133}
 134
 135# Create a partition table and put the filesystem in the first partition
 136# then copy in the files
 137setup_part() {
 138        # Create a gpt partition table with one partition
 139        parted "${IMG}" mklabel gpt 2>/dev/null
 140
 141        # This doesn't work correctly. It creates:
 142        # Number  Start   End     Size    File system  Name  Flags
 143        #  1      1049kB  24.1MB  23.1MB               boot  msftdata
 144        # Odd if the same is entered interactively it does set the FS type
 145        parted -s -a optimal -- "${IMG}" mkpart boot fat32 1MiB 23MiB
 146
 147        # Map this partition to a loop device
 148        kp="$(sudo kpartx -av ${IMG})"
 149        read boot_dev<<<$(grep -o 'loop.*p.' <<< "${kp}")
 150        test "${boot_dev}"
 151        dev="/dev/mapper/${boot_dev}"
 152
 153        mkfs.vfat "${dev}" >/dev/null
 154
 155        sudo mount -o loop "${dev}" $MNT
 156
 157        copy_files
 158
 159        # Sync here since this makes kpartx more likely to work the first time
 160        sync
 161        sudo umount $MNT
 162
 163        # For some reason this needs a sleep or it sometimes fails, if it was
 164        # run recently (in the last few seconds)
 165        if ! sudo kpartx -d "${IMG}" > /dev/null; then
 166                sleep .5
 167                sudo kpartx -d "${IMG}" > /dev/null || \
 168                        echo "Failed to remove ${boot_dev}, use: sudo kpartx -d ${IMG}"
 169        fi
 170}
 171
 172TMP="/tmp/efi${bitness}${type}"
 173MNT=/mnt/x
 174BUILD="efi-x86_${type}${bitness}"
 175IMG=try.img
 176
 177if [[ -n "${old}" && "${bitness}" = "32" ]]; then
 178        BUILD="efi-x86_${type}"
 179fi
 180
 181setup_files
 182
 183qemu-img create "${IMG}" 24M >/dev/null
 184
 185if [[ -n "${part}" ]]; then
 186        setup_part
 187else
 188        setup_raw
 189fi
 190
 191if [[ -n "${run}" ]]; then
 192        run_qemu
 193fi
 194