1#!/bin/bash
2
3# Copyright 2019 Google Inc. All rights reserved.
4
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8
9#     http://www.apache.org/licenses/LICENSE-2.0
10
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17set -e
18set -u
19
20script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
21
22if [ -z $ANDROID_BUILD_TOP ]; then
23	echo "error: please run script after 'lunch'"
24	export ANDROID_BUILD_TOP=$(realpath "${script_dir}"/../../../..)
25	echo "error: set ANDROID_BUILD_TOP as ${ANDROID_BUILD_TOP}"
26fi
27
28source "${ANDROID_BUILD_TOP}/external/shflags/shflags"
29
30UBOOT_DIST=
31KERNEL_DIST=
32OUTPUT_IMAGE=
33
34FLAGS_HELP="USAGE: $0 [UBOOT_DIST] [KERNEL_DIST] [OUTPUT_IMAGE] [flags]"
35
36FLAGS "$@" || exit $?
37eval set -- "${FLAGS_ARGV}"
38
39for arg in "$@" ; do
40	if [ -z $UBOOT_DIST ]; then
41		UBOOT_DIST=$arg
42	elif [ -z $KERNEL_DIST ]; then
43		KERNEL_DIST=$arg
44	elif [ -z $OUTPUT_IMAGE ]; then
45		OUTPUT_IMAGE=$arg
46	else
47		flags_help
48		exit 1
49	fi
50done
51
52if [ -z "${KERNEL_DIST}" ]; then
53	OUTPUT_IMAGE="${UBOOT_DIST}"
54	UBOOT_DIST=
55fi
56
57if [ ! -e "${UBOOT_DIST}" ]; then
58	echo "No UBOOT_DIST, use prebuilts"
59	UBOOT_DIST="${ANDROID_BUILD_TOP}"/device/google/cuttlefish_prebuilts/bootloader/rockpi_aarch64
60fi
61if [ ! -e "${KERNEL_DIST}" ]; then
62	echo "No KERNEL_DIST, use prebuilts"
63	KERNEL_DIST=$(find "${ANDROID_BUILD_TOP}"/device/google/cuttlefish_prebuilts/kernel -name '*-arm64-rockpi' | sort | tail -n 1)
64fi
65
66WRITE_TO_IMAGE=`[ -z "${OUTPUT_IMAGE}" ] && echo "0" || echo "1"`
67
68if [ $WRITE_TO_IMAGE -eq 0 ]; then
69	init_devs=`lsblk --nodeps -oNAME -n`
70	echo "Reinsert device (to write to) into PC"
71	while true; do
72		devs=`lsblk --nodeps -oNAME -n`
73		new_devs="$(echo -e "${init_devs}\n${devs}" | sort | uniq -u | awk 'NF')"
74		num_devs=`echo "${new_devs}" | wc -l`
75		if [[ "${new_devs}" == "" ]]; then
76			num_devs=0
77		fi
78		if [[ ${num_devs} -gt 1 ]]; then
79			echo "error: too many new devices detected! aborting..."
80			exit 1
81		fi
82		if [[ ${num_devs} -eq 1 ]]; then
83			if [[ "${new_devs}" != "${mmc_dev}" ]]; then
84				if [[ "${mmc_dev}" != "" ]]; then
85					echo "error: block device name mismatch ${new_devs} != ${mmc_dev}"
86					echo "Reinsert device (to write to) into PC"
87				fi
88				mmc_dev=${new_devs}
89				continue
90			fi
91			echo "${init_devs}" | grep "${mmc_dev}" >/dev/null
92			if [[ $? -eq 0 ]]; then
93				init_devs="${devs}"
94				continue
95			fi
96			break
97		fi
98	done
99	# now inform the user
100	echo "Detected device at /dev/${mmc_dev}"
101fi
102
103bootenv_src=`mktemp`
104bootenv=`mktemp`
105cat > ${bootenv_src} << "EOF"
106bootdelay=2
107baudrate=1500000
108scriptaddr=0x00500000
109boot_targets=mmc1 mmc0
110bootcmd=run distro_bootcmd
111distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done
112bootcmd_mmc0=devnum=0; run mmc_boot
113bootcmd_mmc1=devnum=1; run mmc_boot
114mmc_boot=if mmc dev ${devnum}; then ; run scan_for_boot_part; fi
115scan_for_boot_part=part list mmc ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype mmc ${devnum}:${distro_bootpart} bootfstype; then run find_script; fi; done; setenv devplist;
116find_script=if test -e mmc ${devnum}:${distro_bootpart} /boot/boot.scr; then echo Found U-Boot script /boot/boot.scr; run run_scr; fi
117run_scr=load mmc ${devnum}:${distro_bootpart} ${scriptaddr} /boot/boot.scr; source ${scriptaddr}
118fastboot_raw_partition_raw1=0x0 0x2000000
119EOF
120echo "Sha=`${script_dir}/gen_sha.sh --uboot ${UBOOT_DIST} --kernel ${KERNEL_DIST}`" >> ${bootenv_src}
121mkenvimage -s 32768 -o ${bootenv} - < ${bootenv_src}
122rm -f ${bootenv_src}
123
124IMAGE=`mktemp`
125kernel_dist_dir=$(echo ${KERNEL_DIST})
126kernel_dist_dir=$(realpath ${kernel_dist_dir})
127if [ ! -d "${kernel_dist_dir}" ]; then
128    echo "error: running realpath on KERNEL_DIST fail"
129    echo KERNEL_DIST="${KERNEL_DIST}"
130    echo kernel_dist_dir="${kernel_dist_dir}"
131    exit 1
132fi
133${ANDROID_BUILD_TOP}/kernel/tests/net/test/build_rootfs.sh \
134	-a arm64 -s bullseye-rockpi -n ${IMAGE} -r ${IMAGE}.initrd -e -g \
135	-k ${kernel_dist_dir}/Image -i ${kernel_dist_dir}/initramfs.img \
136	-d ${kernel_dist_dir}/rk3399-rock-pi-4b.dtb:rockchip
137if [ $? -ne 0 ]; then
138	echo "error: failed to build rootfs. exiting..."
139	rm -f ${IMAGE}
140	exit 1
141fi
142rm -f ${IMAGE}.initrd
143
144if [ ${WRITE_TO_IMAGE} -eq 0 ]; then
145	device=/dev/${mmc_dev}
146	devicep=${device}
147
148	# Burn the whole disk image with partition table
149	sudo dd if=${IMAGE} of=${device} bs=1M conv=fsync
150
151	# Update partition table for 32GB eMMC
152	end_sector=61071326
153	sudo sgdisk --delete=7 ${device}
154	sudo sgdisk --new=7:145M:${end_sector} --typecode=7:8305 --change-name=7:rootfs --attributes=7:set:2 ${device}
155
156	# Rescan the partition table and resize the rootfs
157	sudo partx -v --add ${device}
158	sudo resize2fs ${devicep}7 >/dev/null 2>&1
159else
160	# Minimize rootfs filesystem
161	rootfs_partition_start=$(partx -g -o START -s -n 7 "${IMAGE}" | xargs)
162	rootfs_partition_end=$(partx -g -o END -s -n 7 "${IMAGE}" | xargs)
163	rootfs_partition_num_sectors=$((${rootfs_partition_end} - ${rootfs_partition_start} + 1))
164	rootfs_partition_offset=$((${rootfs_partition_start} * 512))
165	rootfs_partition_size=$((${rootfs_partition_num_sectors} * 512))
166	e2fsck -fy ${IMAGE}?offset=${rootfs_partition_offset} >/dev/null 2>&1
167	imagesize=`stat -c %s "${IMAGE}"`
168	rootfs_partition_tempfile=$(mktemp)
169	dd if="${IMAGE}" of="${rootfs_partition_tempfile}" bs=512 skip=${rootfs_partition_start} count=${rootfs_partition_num_sectors}
170	while true; do
171		out=`resize2fs -M ${rootfs_partition_tempfile} 2>&1`
172		if [[ $out =~ "Nothing to do" ]]; then
173			break
174		fi
175	done
176	dd if="${rootfs_partition_tempfile}" of="${IMAGE}" bs=512 seek=${rootfs_partition_start} count=${rootfs_partition_num_sectors} conv=fsync,notrunc
177	rm -f "${rootfs_partition_tempfile}"
178	truncate -s "${imagesize}" "${IMAGE}"
179	sgdisk -e "${IMAGE}"
180	e2fsck -fy ${IMAGE}?offset=${rootfs_partition_offset} || true
181
182	# Minimize rootfs file size
183	block_count=`tune2fs -l ${IMAGE}?offset=${rootfs_partition_offset} | grep "Block count:" | sed 's/.*: *//'`
184	block_size=`tune2fs -l ${IMAGE}?offset=${rootfs_partition_offset} | grep "Block size:" | sed 's/.*: *//'`
185	sector_size=512
186	start_sector=`partx -g -o START -s -n 7 "${IMAGE}" | xargs`
187	fs_size=$(( block_count*block_size ))
188	fs_sectors=$(( fs_size/sector_size ))
189	part_sectors=$(( ((fs_sectors-1)/2048+1)*2048 ))  # 1MB-aligned
190	end_sector=$(( start_sector+part_sectors-1 ))
191	secondary_gpt_sectors=33
192	fs_end=$(( (end_sector+secondary_gpt_sectors+1)*sector_size ))
193	image_size=$(( part_sectors*sector_size ))
194
195        # Disable ext3/4 journal for flashing to SD-Card
196	tune2fs -O ^has_journal ${IMAGE}?offset=${rootfs_partition_offset}
197	e2fsck -fy ${IMAGE}?offset=${rootfs_partition_offset} >/dev/null 2>&1
198
199	# Update partition table
200	sgdisk --delete=7 ${IMAGE}
201	sgdisk --new=7:145M:${end_sector} --typecode=7:8305 --change-name=7:rootfs --attributes=7:set:2 ${IMAGE}
202fi
203
204# idbloader
205if [ ${WRITE_TO_IMAGE} -eq 0 ]; then
206	sudo dd if=${UBOOT_DIST}/idbloader.img of=${devicep}1 conv=fsync
207else
208	idbloader_partition_start=$(partx -g -o START -s -n 1 "${IMAGE}" | xargs)
209	dd if=${UBOOT_DIST}/idbloader.img of="${IMAGE}" bs=512 seek=${idbloader_partition_start} conv=fsync,notrunc
210fi
211# prebuilt
212# sudo dd if=${ANDROID_BUILD_TOP}/device/google/cuttlefish_prebuilts/uboot_bin/idbloader.img of=${devicep}1 conv=fsync
213
214# uboot_env
215if [ ${WRITE_TO_IMAGE} -eq 0 ]; then
216	sudo dd if=${bootenv} of=${devicep}2 conv=fsync
217else
218	ubootenv_partition_start=$(partx -g -o START -s -n 2 "${IMAGE}" | xargs)
219	dd if=${bootenv} of="${IMAGE}" bs=512 seek=${ubootenv_partition_start} conv=fsync,notrunc
220fi
221# uboot
222if [ ${WRITE_TO_IMAGE} -eq 0 ]; then
223	sudo dd if=${UBOOT_DIST}/u-boot.itb of=${devicep}3 conv=fsync
224else
225	uboot_partition_start=$(partx -g -o START -s -n 3 "${IMAGE}" | xargs)
226	dd if=${UBOOT_DIST}/u-boot.itb of="${IMAGE}" bs=512 seek=${uboot_partition_start} conv=fsync,notrunc
227fi
228# prebuilt
229# sudo dd if=${ANDROID_BUILD_TOP}/device/google/cuttlefish_prebuilts/uboot_bin/u-boot.itb of=${devicep}3 conv=fsync
230
231if [ ${WRITE_TO_IMAGE} -eq 1 ]; then
232	truncate -s ${fs_end} ${IMAGE}
233	sgdisk --move-second-header ${IMAGE}
234	mv -f ${IMAGE} ${OUTPUT_IMAGE}
235fi
236