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