install-boot.sh (394641cf3d2fd8422a6ee79a73d7eca857bddb2e) install-boot.sh (db8b56134506840832bec2d1ce07b9e00d4d6d71)
1#!/bin/sh
2
3# $FreeBSD$
4
5#
6# Installs/updates the necessary boot blocks for the desired boot environment
7#
8# Lightly tested.. Intended to be installed, but until it matures, it will just
9# be a boot tool for regression testing.
10
11# insert code here to guess what you have -- yikes!
12
1#!/bin/sh
2
3# $FreeBSD$
4
5#
6# Installs/updates the necessary boot blocks for the desired boot environment
7#
8# Lightly tested.. Intended to be installed, but until it matures, it will just
9# be a boot tool for regression testing.
10
11# insert code here to guess what you have -- yikes!
12
13# Minimum size of FAT filesystems, in KB.
14fat32min=33292
15fat16min=2100
16
13die() {
14 echo $*
15 exit 1
16}
17
18doit() {
19 echo $*
20 eval $*
21}
22
23find-part() {
24 dev=$1
25 part=$2
26
27 gpart show $dev | tail +2 | awk '$4 == "'$part'" { print $3; }'
28}
29
17die() {
18 echo $*
19 exit 1
20}
21
22doit() {
23 echo $*
24 eval $*
25}
26
27find-part() {
28 dev=$1
29 part=$2
30
31 gpart show $dev | tail +2 | awk '$4 == "'$part'" { print $3; }'
32}
33
30make_esp() {
31 local dev dst mntpt
34get_uefi_bootname() {
32
35
36 case ${TARGET:-$(uname -m)} in
37 amd64) echo bootx64 ;;
38 arm64) echo bootaa64 ;;
39 i386) echo bootia32 ;;
40 arm) echo bootarm ;;
41 *) die "machine type $(uname -m) doesn't support UEFI" ;;
42 esac
43}
44
45make_esp_file() {
46 local file sizekb loader device mntpt fatbits efibootname
47
48 file=$1
49 sizekb=$2
50 loader=$3
51
52 if [ "$sizekb" -ge "$fat32min" ]; then
53 fatbits=32
54 elif [ "$sizekb" -ge "$fat16min" ]; then
55 fatbits=16
56 else
57 fatbits=12
58 fi
59
60 dd if=/dev/zero of="${file}" bs=1k count="${sizekb}"
61 device=$(mdconfig -a -t vnode -f "${file}")
62 newfs_msdos -F "${fatbits}" -c 1 -L EFISYS "/dev/${device}" > /dev/null 2>&1
63 mntpt=$(mktemp -d /tmp/stand-test.XXXXXX)
64 mount -t msdosfs "/dev/${device}" "${mntpt}"
65 mkdir -p "${mntpt}/EFI/BOOT"
66 efibootname=$(get_uefi_bootname)
67 cp "${loader}" "${mntpt}/EFI/BOOT/${efibootname}.efi"
68 umount "${mntpt}"
69 rmdir "${mntpt}"
70 mdconfig -d -u "${device}"
71}
72
73make_esp_device() {
74 local dev file mntpt fstype efibootname kbfree loadersize efibootfile
75 local isboot1 existingbootentryloaderfile bootorder bootentry
76
77 # ESP device node
33 dev=$1
78 dev=$1
34 dst=$2
79 file=$2
35
80
36 newfs_msdos -a 32 ${dev}
37 mntpt=$(mktemp -d /tmp/stand-test.XXXXXX)
81 mntpt=$(mktemp -d /tmp/stand-test.XXXXXX)
38 mount -t msdos ${dev} ${mntpt}
39 mkdir -p ${mntpt}/efi/boot
40 cp ${dst}/boot/loader.efi ${mntpt}/efi/boot/bootx64.efi
41 umount ${mntpt}
42 rmdir ${mntpt}
82
83 # See if we're using an existing (formatted) ESP
84 fstype=$(fstyp "${dev}")
85
86 if [ "${fstype}" != "msdosfs" ]; then
87 newfs_msdos -F 32 -c 1 -L EFISYS "${dev}" > /dev/null 2>&1
88 fi
89
90 mount -t msdosfs "${dev}" "${mntpt}"
91 if [ $? -ne 0 ]; then
92 die "Failed to mount ${dev} as an msdosfs filesystem"
93 fi
94
95 echo "Mounted ESP ${dev} on ${mntpt}"
96
97 efibootname=$(get_uefi_bootname)
98 kbfree=$(df -k "${mntpt}" | tail -1 | cut -w -f 4)
99 loadersize=$(stat -f %z "${file}")
100 loadersize=$((loadersize / 1024))
101
102 # Check if /EFI/BOOT/BOOTxx.EFI is the FreeBSD boot1.efi
103 # If it is, remove it to avoid leaving stale files around
104 efibootfile="${mntpt}/EFI/BOOT/${efibootname}.efi"
105 if [ -f "${efibootfile}" ]; then
106 isboot1=$(strings "${efibootfile}" | grep "FreeBSD EFI boot block")
107
108 if [ -n "${isboot1}" ] && [ "$kbfree" -lt "${loadersize}" ]; then
109 echo "Only ${kbfree}KB space remaining: removing old FreeBSD boot1.efi file /EFI/BOOT/${efibootname}.efi"
110 rm "${efibootfile}"
111 rmdir "${mntpt}/EFI/BOOT"
112 else
113 echo "${kbfree}KB space remaining on ESP: renaming old boot1.efi file /EFI/BOOT/${efibootname}.efi /EFI/BOOT/${efibootname}-old.efi"
114 mv "${efibootfile}" "${mntpt}/EFI/BOOT/${efibootname}-old.efi"
115 fi
116 fi
117
118 if [ ! -f "${mntpt}/EFI/freebsd/loader.efi" ] && [ "$kbfree" -lt "$loadersize" ]; then
119 umount "${mntpt}"
120 rmdir "${mntpt}"
121 echo "Failed to update the EFI System Partition ${dev}"
122 echo "Insufficient space remaining for ${file}"
123 echo "Run e.g \"mount -t msdosfs ${dev} /mnt\" to inspect it for files that can be removed."
124 die
125 fi
126
127 mkdir -p "${mntpt}/EFI/freebsd"
128
129 # Keep a copy of the existing loader.efi in case there's a problem with the new one
130 if [ -f "${mntpt}/EFI/freebsd/loader.efi" ] && [ "$kbfree" -gt "$((loadersize * 2))" ]; then
131 cp "${mntpt}/EFI/freebsd/loader.efi" "${mntpt}/EFI/freebsd/loader-old.efi"
132 fi
133
134 echo "Copying loader to /EFI/freebsd on ESP"
135 cp "${file}" "${mntpt}/EFI/freebsd/loader.efi"
136
137 existingbootentryloaderfile=$(efibootmgr -v | grep "${mntpt}//EFI/freebsd/loader.efi")
138
139 if [ -z "$existingbootentryloaderfile" ]; then
140 # Try again without the double forward-slash in the path
141 existingbootentryloaderfile=$(efibootmgr -v | grep "${mntpt}/EFI/freebsd/loader.efi")
142 fi
143
144 if [ -z "$existingbootentryloaderfile" ]; then
145 echo "Creating UEFI boot entry for FreeBSD"
146 efibootmgr --create --label FreeBSD --loader "${mntpt}/EFI/freebsd/loader.efi" > /dev/null
147 if [ $? -ne 0 ]; then
148 die "Failed to create new boot entry"
149 fi
150
151 # When creating new entries, efibootmgr doesn't mark them active, so we need to
152 # do so. It doesn't make it easy to find which entry it just added, so rely on
153 # the fact that it places the new entry first in BootOrder.
154 bootorder=$(efivar --name 8be4df61-93ca-11d2-aa0d-00e098032b8c-BootOrder --print --no-name --hex | head -1)
155 bootentry=$(echo "${bootorder}" | cut -w -f 3)$(echo "${bootorder}" | cut -w -f 2)
156 echo "Marking UEFI boot entry ${bootentry} active"
157 efibootmgr --activate "${bootentry}" > /dev/null
158 else
159 echo "Existing UEFI FreeBSD boot entry found: not creating a new one"
160 fi
161
162 umount "${mntpt}"
163 rmdir "${mntpt}"
164 echo "Finished updating ESP"
43}
44
165}
166
167make_esp() {
168 local file loaderfile
169
170 file=$1
171 loaderfile=$2
172
173 if [ -f "$file" ]; then
174 make_esp_file ${file} ${fat32min} ${loaderfile}
175 else
176 make_esp_device ${file} ${loaderfile}
177 fi
178}
179
45make_esp_mbr() {
46 dev=$1
47 dst=$2
48
49 s=$(find-part $dev "!239")
50 if [ -z "$s" ] ; then
51 s=$(find-part $dev "efi")
52 if [ -z "$s" ] ; then
53 die "No ESP slice found"
54 fi
55 fi
180make_esp_mbr() {
181 dev=$1
182 dst=$2
183
184 s=$(find-part $dev "!239")
185 if [ -z "$s" ] ; then
186 s=$(find-part $dev "efi")
187 if [ -z "$s" ] ; then
188 die "No ESP slice found"
189 fi
190 fi
56 make_esp /dev/${dev}s${s} ${dst}
191 make_esp /dev/${dev}s${s} ${dst}/boot/loader.efi
57}
58
59make_esp_gpt() {
60 dev=$1
61 dst=$2
62
63 idx=$(find-part $dev "efi")
64 if [ -z "$idx" ] ; then
65 die "No ESP partition found"
66 fi
192}
193
194make_esp_gpt() {
195 dev=$1
196 dst=$2
197
198 idx=$(find-part $dev "efi")
199 if [ -z "$idx" ] ; then
200 die "No ESP partition found"
201 fi
67 make_esp /dev/${dev}p${idx} ${dst}
202 make_esp /dev/${dev}p${idx} ${dst}/boot/loader.efi
68}
69
70boot_nogeli_gpt_ufs_legacy() {
71 dev=$1
72 dst=$2
73
74 idx=$(find-part $dev "freebsd-boot")
75 if [ -z "$idx" ] ; then

--- 137 unchanged lines hidden (view full) ---

213 dev=$1
214 dst=$2
215
216 # For non-native builds, ensure that geom_part(4) supports VTOC8.
217 kldload geom_part_vtoc8.ko
218 doit gpart bootcode -p ${vtoc8} ${dev}
219}
220
203}
204
205boot_nogeli_gpt_ufs_legacy() {
206 dev=$1
207 dst=$2
208
209 idx=$(find-part $dev "freebsd-boot")
210 if [ -z "$idx" ] ; then

--- 137 unchanged lines hidden (view full) ---

348 dev=$1
349 dst=$2
350
351 # For non-native builds, ensure that geom_part(4) supports VTOC8.
352 kldload geom_part_vtoc8.ko
353 doit gpart bootcode -p ${vtoc8} ${dev}
354}
355
221DESTDIR=/
356usage() {
357 printf 'Usage: %s -b bios [-d destdir] -f fs [-g geli] [-h] [-o optargs] -s scheme <bootdev>\n' "$0"
358 printf 'Options:\n'
359 printf ' bootdev device to install the boot code on\n'
360 printf ' -b bios bios type: legacy, uefi or both\n'
361 printf ' -d destdir destination filesystem root\n'
362 printf ' -f fs filesystem type: ufs or zfs\n'
363 printf ' -g geli yes or no\n'
364 printf ' -h this help/usage text\n'
365 printf ' -o optargs optional arguments\n'
366 printf ' -s scheme mbr or gpt\n'
367 exit 0
368}
222
369
370srcroot=/
371
223# Note: we really don't support geli boot in this script yet.
224geli=nogeli
225
372# Note: we really don't support geli boot in this script yet.
373geli=nogeli
374
226while getopts "b:d:f:g:o:s:" opt; do
375while getopts "b:d:f:g:ho:s:" opt; do
227 case "$opt" in
228 b)
229 bios=${OPTARG}
230 ;;
231 d)
376 case "$opt" in
377 b)
378 bios=${OPTARG}
379 ;;
380 d)
232 DESTDIR=${OPTARG}
381 srcroot=${OPTARG}
233 ;;
234 f)
235 fs=${OPTARG}
236 ;;
237 g)
238 case ${OPTARG} in
239 [Yy][Ee][Ss]|geli) geli=geli ;;
240 *) geli=nogeli ;;
241 esac
242 ;;
243 o)
244 opts=${OPTARG}
245 ;;
246 s)
247 scheme=${OPTARG}
248 ;;
382 ;;
383 f)
384 fs=${OPTARG}
385 ;;
386 g)
387 case ${OPTARG} in
388 [Yy][Ee][Ss]|geli) geli=geli ;;
389 *) geli=nogeli ;;
390 esac
391 ;;
392 o)
393 opts=${OPTARG}
394 ;;
395 s)
396 scheme=${OPTARG}
397 ;;
398
399 ?|h)
400 usage
401 ;;
249 esac
250done
251
402 esac
403done
404
252shift $((OPTIND-1))
253dev=$1
405if [ -n "${scheme}" ] && [ -n "${fs}" ] && [ -n "${bios}" ]; then
406 shift $((OPTIND-1))
407 dev=$1
408fi
254
255# For gpt, we need to install pmbr as the primary boot loader
256# it knows about
409
410# For gpt, we need to install pmbr as the primary boot loader
411# it knows about
257gpt0=${DESTDIR}/boot/pmbr
258gpt2=${DESTDIR}/boot/gptboot
259gptzfs2=${DESTDIR}/boot/gptzfsboot
412gpt0=${srcroot}/boot/pmbr
413gpt2=${srcroot}/boot/gptboot
414gptzfs2=${srcroot}/boot/gptzfsboot
260
261# For MBR, we have lots of choices, but select mbr, boot0 has issues with UEFI
415
416# For MBR, we have lots of choices, but select mbr, boot0 has issues with UEFI
262mbr0=${DESTDIR}/boot/mbr
263mbr2=${DESTDIR}/boot/boot
417mbr0=${srcroot}/boot/mbr
418mbr2=${srcroot}/boot/boot
264
265# VTOC8
419
420# VTOC8
266vtoc8=${DESTDIR}/boot/boot1
421vtoc8=${srcroot}/boot/boot1
267
268# sanity check here
269
422
423# sanity check here
424
270eval boot_${geli}_${scheme}_${fs}_${bios} $dev $DESTDIR $opts || echo "Unsupported boot env: ${geli}-${scheme}-${fs}-${bios}"
425# Check if we've been given arguments. If not, this script is probably being
426# sourced, so we shouldn't run anything.
427if [ -n "${dev}" ]; then
428 eval boot_${geli}_${scheme}_${fs}_${bios} $dev $srcroot $opts || echo "Unsupported boot env: ${geli}-${scheme}-${fs}-${bios}"
429fi