Merge tag 'efi-next-20230313' of https://source.denx.de/u-boot/custodians/u-boot...
[platform/kernel/u-boot.git] / scripts / build-efi.sh
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
21 set -e
22
23 usage() {
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
37 bitness=64
38
39 # app or payload ?
40 type=app
41
42 # create a partition table and put the filesystem in that (otherwise put the
43 # filesystem in the raw device)
44 part=
45
46 # run the image with QEMU
47 run=
48
49 # run QEMU without a display (U-Boot must be set to stdout=serial)
50 serial=
51
52 # before the 32/64 split of the app
53 old=
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
57 ubdir=/tmp/b/
58
59 while 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
86 done
87
88 run_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         else
100                 extra="-serial mon:stdio"
101         fi
102         echo "Running ${qemu}"
103         # Use 512MB since U-Boot EFI likes to have 256MB to play with
104         "${qemu}" -bios "${bios}" \
105                 -m 512 \
106                 -drive id=disk,file="${IMG}",if=none,format=raw \
107                 -nic none -device ahci,id=ahci \
108                 -device ide-hd,drive=disk,bus=ahci.0 ${extra}
109 }
110
111 setup_files() {
112         echo "Packaging ${BUILD}"
113         mkdir -p $TMP
114         cat >$TMP/startup.nsh <<EOF
115 fs0:u-boot-${type}.efi
116 EOF
117         sudo cp ${ubdir}/${BUILD}/u-boot-${type}.efi $TMP
118
119         # Can copy in other files here:
120         #sudo cp ${ubdir}/$BUILD/image.bin $TMP/chromeos.rom
121         #sudo cp /boot/vmlinuz-5.4.0-77-generic $TMP/vmlinuz
122 }
123
124 # Copy files into the filesystem
125 copy_files() {
126         sudo cp $TMP/* $MNT
127 }
128
129 # Create a filesystem on a raw device and copy in the files
130 setup_raw() {
131         mkfs.vfat "${IMG}" >/dev/null
132         sudo mount -o loop "${IMG}" $MNT
133         copy_files
134         sudo umount $MNT
135 }
136
137 # Create a partition table and put the filesystem in the first partition
138 # then copy in the files
139 setup_part() {
140         # Create a gpt partition table with one partition
141         parted "${IMG}" mklabel gpt 2>/dev/null
142
143         # This doesn't work correctly. It creates:
144         # Number  Start   End     Size    File system  Name  Flags
145         #  1      1049kB  24.1MB  23.1MB               boot  msftdata
146         # Odd if the same is entered interactively it does set the FS type
147         parted -s -a optimal -- "${IMG}" mkpart boot fat32 1MiB 23MiB
148
149         # Map this partition to a loop device
150         kp="$(sudo kpartx -av ${IMG})"
151         read boot_dev<<<$(grep -o 'loop.*p.' <<< "${kp}")
152         test "${boot_dev}"
153         dev="/dev/mapper/${boot_dev}"
154
155         mkfs.vfat "${dev}" >/dev/null
156
157         sudo mount -o loop "${dev}" $MNT
158
159         copy_files
160
161         # Sync here since this makes kpartx more likely to work the first time
162         sync
163         sudo umount $MNT
164
165         # For some reason this needs a sleep or it sometimes fails, if it was
166         # run recently (in the last few seconds)
167         if ! sudo kpartx -d "${IMG}" > /dev/null; then
168                 sleep .5
169                 sudo kpartx -d "${IMG}" > /dev/null || \
170                         echo "Failed to remove ${boot_dev}, use: sudo kpartx -d ${IMG}"
171         fi
172 }
173
174 TMP="/tmp/efi${bitness}${type}"
175 MNT=/mnt/x
176 BUILD="efi-x86_${type}${bitness}"
177 IMG=try.img
178
179 if [[ -n "${old}" && "${bitness}" = "32" ]]; then
180         BUILD="efi-x86_${type}"
181 fi
182
183 setup_files
184
185 qemu-img create "${IMG}" 24M >/dev/null
186
187 if [[ -n "${part}" ]]; then
188         setup_part
189 else
190         setup_raw
191 fi
192
193 if [[ -n "${run}" ]]; then
194         run_qemu
195 fi