]>
Commit | Line | Data |
---|---|---|
6b2f8290 SG |
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 | 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 | ||
109 | setup_files() { | |
110 | echo "Packaging ${BUILD}" | |
111 | mkdir -p $TMP | |
112 | cat >$TMP/startup.nsh <<EOF | |
113 | fs0:u-boot-${type}.efi | |
114 | EOF | |
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 | |
123 | copy_files() { | |
124 | sudo cp $TMP/* $MNT | |
125 | } | |
126 | ||
127 | # Create a filesystem on a raw device and copy in the files | |
128 | setup_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 | |
137 | setup_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 | ||
172 | TMP="/tmp/efi${bitness}${type}" | |
173 | MNT=/mnt/x | |
174 | BUILD="efi-x86_${type}${bitness}" | |
175 | IMG=try.img | |
176 | ||
177 | if [[ -n "${old}" && "${bitness}" = "32" ]]; then | |
178 | BUILD="efi-x86_${type}" | |
179 | fi | |
180 | ||
181 | setup_files | |
182 | ||
183 | qemu-img create "${IMG}" 24M >/dev/null | |
184 | ||
185 | if [[ -n "${part}" ]]; then | |
186 | setup_part | |
187 | else | |
188 | setup_raw | |
189 | fi | |
190 | ||
191 | if [[ -n "${run}" ]]; then | |
192 | run_qemu | |
193 | fi |