xref: /netbsd/distrib/utils/embedded/mkimage (revision af4cbeb0)
1722fa22cSjmcneill#!/bin/sh
2*af4cbeb0Smaya# $NetBSD: mkimage,v 1.78 2021/09/25 08:54:30 maya Exp $
343b25107Schristos#
4df5f4559Schristos# Copyright (c) 2013, 2014 The NetBSD Foundation, Inc.
5267b86c3Sagc# All rights reserved.
6267b86c3Sagc#
7bbaf0399Schristos# This code is derived from software contributed to The NetBSD Foundation
8bbaf0399Schristos# by Christos Zoulas.
9bbaf0399Schristos#
10267b86c3Sagc# Redistribution and use in source and binary forms, with or without
11267b86c3Sagc# modification, are permitted provided that the following conditions
12267b86c3Sagc# are met:
13267b86c3Sagc# 1. Redistributions of source code must retain the above copyright
14267b86c3Sagc#    notice, this list of conditions and the following disclaimer.
15267b86c3Sagc# 2. Redistributions in binary form must reproduce the above copyright
16267b86c3Sagc#    notice, this list of conditions and the following disclaimer in the
17267b86c3Sagc#    documentation and/or other materials provided with the distribution.
18bbaf0399Schristos# 3. Neither the name of The NetBSD Foundation nor the names of its
19bbaf0399Schristos#    contributors may be used to endorse or promote products derived
20bbaf0399Schristos#    from this software without specific prior written permission.
21267b86c3Sagc#
22bbaf0399Schristos# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23bbaf0399Schristos# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24bbaf0399Schristos# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25bbaf0399Schristos# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26bbaf0399Schristos# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27bbaf0399Schristos# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28bbaf0399Schristos# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29bbaf0399Schristos# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30bbaf0399Schristos# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31bbaf0399Schristos# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32bbaf0399Schristos# POSSIBILITY OF SUCH DAMAGE.
33267b86c3Sagc#
34267b86c3Sagc
354935107aShubertf#
364935107aShubertf# Makes a bootable image for the host architecture given.
374935107aShubertf# The host specific functions are pulled in from a /bin/sh script in the
384935107aShubertf# "conf" directory, and is expected to provide the following shell
394935107aShubertf# functions, which are called in the following order:
404935107aShubertf#
414935107aShubertf#  - make_fstab: Creates the host's /etc/fstab with / on ${rootdev}.
424935107aShubertf#    If -m is given, a number of directories are put on a tmpfs RAM disk
434935107aShubertf#  - customize: After unpacking the sets, this gets the system to
444935107aShubertf#    a working state, e. g. by setting up /etc/rc.conf and /dev
454935107aShubertf#  - populate: Add common goods like kernel and bootloader
464935107aShubertf#  - make_label: Prints disklabel to stdout
474935107aShubertf#
484935107aShubertf
49e140236eSjmcneillset -e
50e140236eSjmcneill
51bbaf0399SchristosDIR="$(cd "$(dirname "$0")" && pwd)"
52bbaf0399SchristosPROG="$(basename "$0")"
53267b86c3Sagc
5419b29e2cSjmcneillMAKE=${TOOL_MAKE:-make}
558ccc0b92SchristosDISKLABEL=${TOOL_DISKLABEL:-disklabel}
56bdbfe825SchristosFDISK=${TOOL_FDISK:-fdisk}
575b5842aeSjmcneillGPT=${TOOL_GPT:-gpt}
588ccc0b92SchristosMAKEFS=${TOOL_MAKEFS:-makefs}
59aa7339cdSjmcneillMTREE=${TOOL_MTREE:-mtree}
60df5f4559SchristosINSTALLBOOT=${TOOL_INSTALLBOOT:-installboot}
61141eb037SchristosMKUBOOTIMAGE=${TOOL_MKUBOOTIMAGE:-mkubootimage}
62ec8d7d73SastGZIP_CMD=${TOOL_GZIP:-gzip} # ${GZIP} is special to gzip(1)
638ccc0b92Schristos
64bbaf0399Schristossrc="/usr/src"
65*af4cbeb0Smayasets="base comp etc games gpufw man misc modules rescue tests text"
66bbaf0399Schristosxsets="xbase xcomp xetc xfont xserver"
67bbaf0399Schristosminfree="10%"
68bbaf0399Schristosbar="==="
69267b86c3Sagc
7088c7f048Skretmp="$(mktemp -d "${TMPDIR:-/tmp}/$PROG.XXXXXX")"
71bbaf0399Schristosmnt="${tmp}/mnt"
725b65fdecSchristosmkdir -p "${mnt}/etc" "${mnt}/dev"
73bf62f393Schristos
74bbaf0399Schristostrap "cleanup" 0 1 2 3 15
75bbaf0399Schristos
76bbaf0399Schristoscleanup() {
77bbaf0399Schristos	case "$tmp" in
788c8fbbc3Skre	"${TMPDIR:-/tmp}/$PROG."*)	rm -fr "$tmp";;
79bbaf0399Schristos	esac
80267b86c3Sagc}
81267b86c3Sagc
82d8532e20Skrefail() {
83d8532e20Skre	IFS=' '
84d8532e20Skre	echo >&2 "${PROG}: $*"
85d8532e20Skre	exit 1
86d8532e20Skre}
87d8532e20Skre
88bbaf0399Schristosgetsize() {
89bbaf0399Schristos	set -- $(ls -l $1)
90bbaf0399Schristos	echo $5
91267b86c3Sagc}
92267b86c3Sagc
938b34a10bSjmcneillgetsectors() {
948b34a10bSjmcneill	case "$1" in
958b34a10bSjmcneill	*g)
968b34a10bSjmcneill		m=1073741824
978b34a10bSjmcneill		v=${1%g}
988b34a10bSjmcneill		;;
998b34a10bSjmcneill	*m)
1008b34a10bSjmcneill		m=1048576
1018b34a10bSjmcneill		v=${1%m}
1028b34a10bSjmcneill		;;
1038b34a10bSjmcneill	*k)
1048b34a10bSjmcneill		m=1024
1058b34a10bSjmcneill		v=${1%k}
1068b34a10bSjmcneill		;;
1078b34a10bSjmcneill	*[0-9b])
1088b34a10bSjmcneill		m=1
1098b34a10bSjmcneill		v=${1%b}
1108b34a10bSjmcneill		;;
1118b34a10bSjmcneill	esac
1128b34a10bSjmcneill	echo $((m * v / 512))
1138b34a10bSjmcneill}
1148b34a10bSjmcneill
115632e755aSchristosusage() {
116632e755aSchristos	cat << EOF 1>&2
11790370017SmartinUsage: $PROG -h <host-arch> [-bdmx] [-B <byte-order>] [-K <kerneldir>] [-S <srcdir>] [-D <destdir>] [-c <custom-files-dir>] [-s <Mb size>] [<image>]
1187fc5abe8Schristos
1197fc5abe8Schristos-b	Boot only, no sets loaded
1204b3e41fdSchristos-r	root device kind (sd, wd, ld)
1217fc5abe8Schristos-d	Add the debug sets
122c2c5d53cSchristos-m	Optimize the OS installation to mimimize disk writes for SSDs
1231b551427Shubertf-x	Load the X sets too, not just the base ones
124632e755aSchristosEOF
125632e755aSchristos	exit 1
126632e755aSchristos}
127632e755aSchristos
12809e10ad8Sjmcneill# First pass for options to get the host and src directories
12990370017SmartinOPTS="B:D:K:S:bc:dh:mr:s:x"
130b6e2226dSchristoswhile getopts "$OPTS" f
131b6e2226dSchristosdo
132b6e2226dSchristos	case $f in
133b6e2226dSchristos	h)	h="$OPTARG";;
13409e10ad8Sjmcneill	S)	src="$OPTARG";;
135b6e2226dSchristos	*)	;;
136267b86c3Sagc	esac
137267b86c3Sagcdone
138267b86c3Sagc
139b6e2226dSchristosif [ -z "$h" ]
140b6e2226dSchristosthen
141b6e2226dSchristos	usage
142b6e2226dSchristosfi
143b6e2226dSchristos
1442e39be44Schristosif [ ! -f "${DIR}/conf/${h}.conf" ]
145b6e2226dSchristosthen
1462e39be44Schristos	echo $PROG: ${DIR}/conf/${h}.conf is not present 1>&2
147b6e2226dSchristos	exit 1
148b6e2226dSchristosfi
149b6e2226dSchristos
15052b91797Sjmcneillresize=false
1515b5842aeSjmcneillgpt=false
152cbc8e374Sjmcneillgpt_hybrid=false
15352b91797Sjmcneill
1542e39be44Schristos. "${DIR}/conf/${h}.conf"
155df5f4559Schristosrelease="/usr/obj/${MACHINE}/release"
156b6e2226dSchristos
157bbaf0399Schristosselected_sets="$sets"
158088203b8Sskrlldsets_p=false
159088203b8Sskrllxsets_p=false
1607fc5abe8Schristosminwrites=false
1614b3e41fdSchristosrootdev=ld
16290370017Smartinendian=
163bbaf0399Schristos
164b6e2226dSchristosOPTIND=1
165b6e2226dSchristoswhile getopts "$OPTS" f
166b6e2226dSchristosdo
167b6e2226dSchristos	case $f in
16890370017Smartin	B)	endian="-B $OPTARG";;
169f1ca5eb5Schristos	D)	release="$OPTARG";;
170f1ca5eb5Schristos	K)	kernel="$OPTARG";;
17109e10ad8Sjmcneill	S)	;;
172d2ca0586Schristos	b)	bootonly=true;;
173088203b8Sskrll	d)	dsets_p=true
1747fc5abe8Schristos		selected_sets="$selected_sets debug"
175088203b8Sskrll		if $xsets_p; then
1767fc5abe8Schristos			selected_sets="$selected_sets xdebug"
1777fc5abe8Schristos		fi
1787fc5abe8Schristos		;;
179b6e2226dSchristos	c)	custom="$OPTARG";;
180b6e2226dSchristos	h)	;;
1817fc5abe8Schristos	m)	minwrites=true;;
1824b3e41fdSchristos	r)	rootdev="$OPTARG";;
183b6e2226dSchristos	s)	size="$OPTARG";;
184088203b8Sskrll	x)	xsets_p=true
1857fc5abe8Schristos		selected_sets="$selected_sets $xsets"
186088203b8Sskrll		if $dsets_p; then
1877fc5abe8Schristos		    selected_sets="$selected_sets xdebug"
1887fc5abe8Schristos		fi
1897fc5abe8Schristos		;;
190a76783b5Schristos	*)	usage;;
191b6e2226dSchristos	esac
192b6e2226dSchristosdone
193b6e2226dSchristos
194cd3b1ea3Sjmcneillshift $(( $OPTIND - 1 ))
195b6e2226dSchristosif [ -n "$1" ]; then
196267b86c3Sagc	# take the next argument as being the image name
197267b86c3Sagc	image="$1"
198267b86c3Sagc	shift
199267b86c3Sagcfi
200267b86c3Sagc
201827b25efSchristoscase "$image" in
202827b25efSchristos*.gz)	compress=true; image="${image%.gz}";;
203827b25efSchristos*)	compress=false;;
204827b25efSchristosesac
205827b25efSchristos
206df5f4559Schristosif [ -z "${bootonly}" ]; then
207bbaf0399Schristos	echo ${bar} configuring sets ${bar}
208ef34841fSskrll	(cat "${release}/etc/mtree/NetBSD.dist"
209bbaf0399Schristos	for i in $selected_sets; do
210bbaf0399Schristos		s="${release}/etc/mtree/set.$i"
21153e719b6Schristos		if [ -f "$s" ]; then
21253e719b6Schristos			cat "$s"
21353e719b6Schristos		fi
214bbaf0399Schristos	done) > "$tmp/selected_sets"
215de7cb3aeSgarbledfi
216267b86c3Sagc
217b6e2226dSchristosmake_fstab
218b6e2226dSchristoscustomize
219bbaf0399Schristospopulate
220b6e2226dSchristos
221879faa2aSjmcneillif [ ! "${MKDTB}" = "no" ]; then
222879faa2aSjmcneill	#
223879faa2aSjmcneill	# Part of the dtb set resides on the FAT partition (/boot/dtb/*), and
224879faa2aSjmcneill	# the rest on FFS. Split it up here.
225879faa2aSjmcneill	#
226879faa2aSjmcneill	echo ${bar} Installing devicetree blobs ${bar}
227879faa2aSjmcneill	mkdir -p "${mnt}/boot"
228879faa2aSjmcneill	cp -r "${release}/boot/dtb" "${mnt}/boot/dtb"
229879faa2aSjmcneill
230879faa2aSjmcneill	mkdir -p "${mnt}/etc/mtree"
231879faa2aSjmcneill	cp "${release}/etc/mtree/set.dtb" "${mnt}/etc/mtree/set.dtb"
232879faa2aSjmcneill	echo "./etc/mtree/set.dtb type=file uname=root gname=wheel mode=0444" >> "$tmp/selected_sets"
233879faa2aSjmcneill
234879faa2aSjmcneill	mkdir -p "${mnt}/var/db/obsolete"
235879faa2aSjmcneill	cp "${release}/var/db/obsolete/dtb" "${mnt}/var/db/obsolete/dtb"
236879faa2aSjmcneill	echo "./var/db/obsolete/dtb type=file uname=root gname=wheel mode=0644" >>"$tmp/selected_sets"
237879faa2aSjmcneillfi
238879faa2aSjmcneill
239df5f4559Schristosif [ -n "${msdosid}" ]; then
240bbaf0399Schristos	echo ${bar} Populating msdos filesystem ${bar}
241879faa2aSjmcneill
2427e411275Smartin	case $(( ${msdosid} )) in
2437e411275Smartin	1)	fat_opt=",fat_type=12";;
2447e411275Smartin	4|6|14)	fat_opt=",fat_type=16";;
2457e411275Smartin	11|12)	fat_opt=",fat_type=32";;
2467e411275Smartin	*)	fat_opt=;;
2477e411275Smartin	esac
2487e411275Smartin	${MAKEFS} -N ${release}/etc -t msdos \
2497e411275Smartin	    -o "volume_label=NETBSD${fat_opt}" \
2508b34a10bSjmcneill	    -O $((${init} / 2))m -s $((${boot} / 2))m \
251d2ca0586Schristos	    ${image} ${mnt}/boot
252230874b2Sagcfi
253267b86c3Sagc
254df5f4559Schristosif [ -z "${bootonly}" ]; then
255bbaf0399Schristos	echo ${bar} Populating ffs filesystem ${bar}
25690370017Smartin	${MAKEFS} -rx ${endian} -N ${release}/etc -t ffs \
2575b65fdecSchristos	    -O ${ffsoffset} \
2580cd0818eSjmcneill	    -o d=4096,f=8192,b=65536 -b $((${extra}))m \
259bbaf0399Schristos	    -F "$tmp/selected_sets" ${image} "${release}" "${mnt}"
260de7cb3aeSgarbledfi
261bbaf0399Schristos
262bf62f393Schristosif [ "${size}" = 0 ]; then
263a2448456Srin	size="$(getsize "${image}")"
264b5648ea5Sriastradh	# Round up to a multiple of 4m and add 1m of slop.
265b5648ea5Sriastradh	alignunit=$((4*1024*1024))
266a2448456Srin	alignsize=$((alignunit*((size + alignunit - 1)/alignunit)))
267b5648ea5Sriastradh	alignsize=$((alignsize + 1024*1024))
268a2448456Srin	if [ "${size}" -lt "${alignsize}" ]; then
269a2448456Srin		dd bs=1 count="$((alignsize - size))" if=/dev/zero \
270a2448456Srin			>> "${image}" 2> /dev/null
271a2448456Srin		size="${alignsize}"
272bbaf0399Schristos	fi
273b5648ea5Sriastradhfi
274bbaf0399Schristos
2755b5842aeSjmcneillif $gpt; then
276cbc8e374Sjmcneill	if $gpt_hybrid; then
277cbc8e374Sjmcneill		gpt_flags="-H"
278cbc8e374Sjmcneill	fi
2795b5842aeSjmcneill	initsecs=$((${init} * 1024))
2805b5842aeSjmcneill	bootsecs=$((${boot} * 1024))
2815b5842aeSjmcneill	ffsstart="$(getsectors ${ffsoffset})"
2825b5842aeSjmcneill
2835b5842aeSjmcneill	echo ${bar} Clearing existing partitions ${bar}
284cbc8e374Sjmcneill	${GPT} ${gpt_flags} ${image} destroy || true
2855b5842aeSjmcneill
2865b5842aeSjmcneill	echo ${bar} Creating partitions ${bar}
287cbc8e374Sjmcneill	${GPT} ${gpt_flags} ${image} create ${gpt_create_flags}
288f98b2f22Sjmcneill	${GPT} ${gpt_flags} ${image} add -b ${initsecs} -s ${bootsecs} -l ${gpt_label_boot:-EFI} -t ${gpt_boot_type:-efi}
289cbc8e374Sjmcneill	${GPT} ${gpt_flags} ${image} set -a required -i 1
290cbc8e374Sjmcneill	${GPT} ${gpt_flags} ${image} add -a 4m -b ${ffsstart} -l ${gpt_label_ffs:-netbsd-root} -t ffs
291cbc8e374Sjmcneill	${GPT} ${gpt_flags} ${image} show
292cbc8e374Sjmcneill	if $gpt_hybrid; then
293cbc8e374Sjmcneill		echo ${bar} Creating hybrid MBR ${bar}
294cbc8e374Sjmcneill		${FDISK} -f -g -u -0 -a -s ${msdosid}/${initsecs}/${bootsecs} -F ${image}
295cbc8e374Sjmcneill		${FDISK} -f -g -u -3 -s 238/1/$((${initsecs} - 1)) -F ${image}
296cbc8e374Sjmcneill		${FDISK} -F ${image}
297cbc8e374Sjmcneill	fi
2985b5842aeSjmcneillelse
299df5f4559Schristos	if [ -n "${msdosid}" ]; then
300bbaf0399Schristos		echo ${bar} Running fdisk ${bar}
301e422fefcSjmcneill		initsecs=$((${init} * 1024))
302e422fefcSjmcneill		bootsecs=$((${boot} * 1024))
3038b34a10bSjmcneill		${FDISK} -f -i ${image}
3042ba6908cSskrll		${FDISK} -f -a -u -0 -s ${msdosid}/${initsecs}/${bootsecs} -F ${image}
3058b34a10bSjmcneill		if [ -z "${bootonly}" ]; then
3068b34a10bSjmcneill			ffsstart="$(getsectors ${ffsoffset})"
3078b34a10bSjmcneill			imagesize="$(getsize "${image}")"
3088b34a10bSjmcneill			imagesecs="$(getsectors ${imagesize})"
3098b34a10bSjmcneill			ffssize="$(expr ${imagesecs} - ${ffsstart})"
3108b34a10bSjmcneill			${FDISK} -f -u -1 -s 169/${ffsstart}/${ffssize} -F ${image}
3118b34a10bSjmcneill		fi
312e9957547Sjmcneill
313e9957547Sjmcneill		echo ${bar} Adding label ${bar}
314e9957547Sjmcneill		make_label > ${tmp}/label
315e9957547Sjmcneill		${DISKLABEL} -R -F ${image} ${tmp}/label
316df5f4559Schristos	elif [ -n "${netbsdid}" ]; then
317e9957547Sjmcneill		echo ${bar} Adding label ${bar}
318e9957547Sjmcneill		make_label > ${tmp}/label
319e9957547Sjmcneill		${DISKLABEL} -R -F ${image} ${tmp}/label
320e9957547Sjmcneill
321df5f4559Schristos		echo ${bar} Running fdisk ${bar}
322df5f4559Schristos		${FDISK} -f -i ${image}
32359b548e0Schristos		${FDISK} -f -a -u -0 -s 169/${init} ${image}
324df5f4559Schristos		${INSTALLBOOT} -f -v ${image} ${release}/usr/mdec/bootxx_ffsv1
325bbaf0399Schristos	fi
3265b5842aeSjmcneillfi
327827b25efSchristos
328827b25efSchristosif $compress; then
329827b25efSchristos	echo ${bar} Compressing image ${bar}
330bf62f393Schristos	rm -f "${image}.gz"
331ec8d7d73Sast	${GZIP_CMD} -9 ${image}
332827b25efSchristos	image="${image}.gz"
333827b25efSchristosfi
334827b25efSchristos
335bbaf0399Schristosecho ${bar} Image is ${image} ${bar}
336