|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +set -e |
| 4 | + |
| 5 | +# deps: |
| 6 | +# - dpkg (dpkg-deb) |
| 7 | +# - openssl |
| 8 | +# - zstd |
| 9 | +# - cpio |
| 10 | + |
| 11 | +. /usr/local/bin/terminal-functions.sh |
| 12 | + |
| 13 | +read_config |
| 14 | + |
| 15 | +TMPDIR="${TMPDIR:=/tmp}" |
| 16 | + |
| 17 | +if [[ -z "${1}" ]]; then |
| 18 | + >&2 echo "No linux image specified" |
| 19 | + exit 1 |
| 20 | +fi |
| 21 | + |
| 22 | +if [[ -z "${RPI_DEVICE_FAMILY}" ]]; then |
| 23 | + >&2 echo "'RPI_DEVICE_FAMILY' not specified" |
| 24 | + exit 1 |
| 25 | +fi |
| 26 | + |
| 27 | +if [[ -z "${BOOT_IMAGE_VENDOR}" ]]; then |
| 28 | + >&2 echo "'BOOT_IMAGE_VENDOR' not specified" |
| 29 | + exit 1 |
| 30 | +fi |
| 31 | + |
| 32 | +if [[ -z "${BOOT_IMAGE_MAINTAINER}" ]]; then |
| 33 | + >&2 echo "'BOOT_IMAGE_MAINTAINER' not specified" |
| 34 | + exit 1 |
| 35 | +fi |
| 36 | + |
| 37 | +if [[ -z "${OPENSSL}" || ! -f "${OPENSSL}" ]]; then |
| 38 | + >&2 echo "'OPENSSL' not set or binary does not exist" |
| 39 | + exit 1 |
| 40 | +fi |
| 41 | + |
| 42 | +if [[ -z "${CUSTOMER_KEY_FILE_PEM}" || ! -f "${CUSTOMER_KEY_FILE_PEM}" ]]; then |
| 43 | + >&2 echo "'CUSTOMER_KEY_FILE_PEM' not set or file does not exist" |
| 44 | + exit 1 |
| 45 | +fi |
| 46 | + |
| 47 | +LINUX_IMAGE="${1}" |
| 48 | + |
| 49 | +# Should be set by systemd |
| 50 | +SERVICE_NAME="make-boot-image@$(systemd-escape $LINUX_IMAGE).service" |
| 51 | +CACHE_DIRECTORY="${CACHE_DIRECTORY:=/var/cache/${SERVICE_NAME}}" |
| 52 | +RUNTUME_DIRECTORY="${RUNTIME_DIRECTORY:=/run/${SERVICE_NAME}}" |
| 53 | + |
| 54 | +# TODO: Might be interesting to start rpi-package-download with --no-block to |
| 55 | +# allow multiple simultaneous downloads. |
| 56 | +function download_package() { |
| 57 | + systemctl start \ |
| 58 | + --wait \ |
| 59 | + rpi-package-download@$(systemd-escape ${1}).service |
| 60 | +} |
| 61 | + |
| 62 | +KERNEL_2711="linux-image-${LINUX_IMAGE}" |
| 63 | +>&2 echo "Downloading ${KERNEL_2711}" |
| 64 | +download_package "$KERNEL_2711" |
| 65 | + |
| 66 | +PACKAGE_NAME="boot-image-${BOOT_IMAGE_VENDOR}-${LINUX_IMAGE}" |
| 67 | + |
| 68 | +# Temp directory cleanup |
| 69 | +TEMP_DIRS=() |
| 70 | +function remove_temp_dirs() { |
| 71 | + >&2 echo "Removing temporary directories" |
| 72 | + for dir in "${TEMP_DIRS[@]}" |
| 73 | + do |
| 74 | + rm -rf "$dir" |
| 75 | + done |
| 76 | +} |
| 77 | +trap remove_temp_dirs EXIT |
| 78 | + |
| 79 | +>&2 echo -n "Creating filesystem hierarchy for deb package: " |
| 80 | +DEB_HIER="$(mktemp --directory --tmpdir debhier.XXX)" |
| 81 | +TEMP_DIRS+=("${DEB_HIER}") |
| 82 | +>&2 echo "${DEB_HIER}" |
| 83 | + |
| 84 | +>&2 echo -n "Create rootfs working directory: " |
| 85 | +WORK_DIR="$(mktemp --directory --tmpdir boot-image-rootfs.XXX)" |
| 86 | +TEMP_DIRS+=("${WORK_DIR}") |
| 87 | +>&2 echo "${WORK_DIR}" |
| 88 | + |
| 89 | +function latest_pkg_dir() { |
| 90 | + echo "/var/cache/rpi-package-download@$(systemd-escape ${1}).service/latest" |
| 91 | +} |
| 92 | + |
| 93 | +>&2 echo "Extracting package contents" |
| 94 | +dpkg-deb --raw-extract "$(latest_pkg_dir $KERNEL_2711)/package.deb" "${WORK_DIR}" |
| 95 | + |
| 96 | +function get_dctrl_field() { |
| 97 | + grep-dctrl \ |
| 98 | + --field=Package \ |
| 99 | + --exact-match "${2}" \ |
| 100 | + --no-field-names \ |
| 101 | + --show-field="${3}" \ |
| 102 | + "${1}" |
| 103 | +} |
| 104 | + |
| 105 | +# Determine package version for later reuse |
| 106 | +KERNEL_2711_VERSION="$(get_dctrl_field ${WORK_DIR}/DEBIAN/control ${KERNEL_2711} Version)" |
| 107 | +>&2 echo "Extracted ${KERNEL_2711}, version ${KERNEL_2711_VERSION}" |
| 108 | + |
| 109 | +# rootfs kernel modules |
| 110 | +>&2 echo "Copy kernel modules into deb package" |
| 111 | +mkdir -p "${DEB_HIER}/lib/modules" |
| 112 | +rsync -crt "${WORK_DIR}/lib/modules/"* "${DEB_HIER}/lib/modules" |
| 113 | + |
| 114 | +>&2 echo -n "Create ramdisk working directory: " |
| 115 | +BFS_DIR="$(mktemp --directory --tmpdir boot-image-bootfs.XXX)" |
| 116 | +TEMP_DIRS+=("${BFS_DIR}") |
| 117 | +>&2 echo "${BFS_DIR}" |
| 118 | + |
| 119 | +# Kernel Images |
| 120 | +>&2 echo "Copy kernel to ramdisk" |
| 121 | +cp "${WORK_DIR}/boot/vmlinuz-${LINUX_IMAGE}" "${BFS_DIR}/zImage" |
| 122 | + |
| 123 | +# Overlays |
| 124 | +>&2 echo "Copy overlays to ramdisk" |
| 125 | +OVERLAY_PATH="${WORK_DIR}/usr/lib/${KERNEL_2711}/overlays" |
| 126 | +rsync -crt "${OVERLAY_PATH}"/*.dtb* "${OVERLAY_PATH}/README" "${BFS_DIR}/overlays" |
| 127 | + |
| 128 | +# DTBs |
| 129 | +>&2 echo "Copy DTBs to ramdisk" |
| 130 | +DTB_PATH="${WORK_DIR}/usr/lib/${KERNEL_2711}/broadcom" |
| 131 | +rsync -crt "${DTB_PATH}"/bcm27*.dtb "${BFS_DIR}" |
| 132 | + |
| 133 | +# Insert an initramfs |
| 134 | +>&2 echo "Add cryptoot initramfs to ramdisk (with necessary kernel modules)" |
| 135 | +INITRAMFS_EXTRACT="$(mktemp --directory --tmpdir initramfs-extract.XXX)" |
| 136 | +TEMP_DIRS+=("${INITRAMFS_EXTRACT}") |
| 137 | +zstd -q -d "$(get_cryptroot)" -o "${INITRAMFS_EXTRACT}/initramfs.cpio" |
| 138 | +mkdir -p "${INITRAMFS_EXTRACT}/initramfs" |
| 139 | +pushd "${INITRAMFS_EXTRACT}/initramfs" > /dev/null |
| 140 | +cpio --quiet -id < ../initramfs.cpio > /dev/null |
| 141 | +rm ../initramfs.cpio |
| 142 | +pushd "${WORK_DIR}" > /dev/null |
| 143 | +find lib/modules \ |
| 144 | + \( \ |
| 145 | + -name 'dm-mod.*' \ |
| 146 | + -o \ |
| 147 | + -name 'dm-crypt.*' \ |
| 148 | + -o \ |
| 149 | + -name 'af_alg.*' \ |
| 150 | + -o \ |
| 151 | + -name 'algif_skcipher.*' \ |
| 152 | + -o \ |
| 153 | + -name 'libaes.*' \ |
| 154 | + -o \ |
| 155 | + -name 'aes_generic.*' \ |
| 156 | + -o \ |
| 157 | + -name 'aes-arm64.*' \ |
| 158 | + \) \ |
| 159 | + -exec cp -r --parents "{}" "${INITRAMFS_EXTRACT}/initramfs/usr/" \; |
| 160 | +popd > /dev/null |
| 161 | +find . -print0 | cpio --quiet --null -ov --format=newc > ../initramfs.cpio 2> /dev/null |
| 162 | +popd > /dev/null |
| 163 | +zstd -q -6 "${INITRAMFS_EXTRACT}/initramfs.cpio" -o "${BFS_DIR}/rootfs.cpio.zst" |
| 164 | + |
| 165 | +# raspi-firmware |
| 166 | +>&2 echo "Downloading raspi-firmware" |
| 167 | +download_package raspi-firmware |
| 168 | + |
| 169 | +>&2 echo -n "Create temp directory to extract firmware: " |
| 170 | +FW_EXTRACT_DIR="$(mktemp --directory --tmpdir boot-image-firmware.XXX)" |
| 171 | +TEMP_DIRS+=("${FW_EXTRACT_DIR}") |
| 172 | +>&2 echo "${FW_EXTRACT_DIR}" |
| 173 | + |
| 174 | +>&2 echo "Extracting firmware package contents" |
| 175 | +dpkg-deb --raw-extract "$(latest_pkg_dir raspi-firmware)/package.deb" "${FW_EXTRACT_DIR}" |
| 176 | + |
| 177 | +>&2 echo "Add firmware to ramdisk" |
| 178 | +rsync -v -crt "${FW_EXTRACT_DIR}/usr/lib/raspi-firmware/" "${BFS_DIR}" |
| 179 | + |
| 180 | +# cmdline.txt |
| 181 | +>&2 echo "Add cmdline.txt to ramdisk" |
| 182 | +cp "$(get_ramdisk_cmdline_file)" "${BFS_DIR}/cmdline.txt" |
| 183 | + |
| 184 | +# Inner config.txt |
| 185 | +>&2 echo "Add config.txt to ramdisk" |
| 186 | +cp "$(get_internal_config_file)" "${BFS_DIR}/config.txt" |
| 187 | + |
| 188 | +# Invoke make-boot-image |
| 189 | +>&2 echo "Finalise ramdisk in deb package (boot.img)" |
| 190 | +mkdir -p "${DEB_HIER}/boot/firmware" |
| 191 | +make-boot-image \ |
| 192 | + -b pi${RPI_DEVICE_FAMILY} \ |
| 193 | + -d "${BFS_DIR}" \ |
| 194 | + -o "${DEB_HIER}/boot/firmware/boot.img" > /dev/null |
| 195 | + |
| 196 | +# Outer config.txt |
| 197 | +>&2 echo "Add config.txt to deb package (ensure boot.img is used)" |
| 198 | +cp "$(get_fastboot_config_file)" "${DEB_HIER}/boot/firmware/config.txt" |
| 199 | + |
| 200 | +# boot.sig generation |
| 201 | +>&2 echo "Signing ramdisk image" |
| 202 | +sha256sum "${DEB_HIER}/boot/firmware/boot.img" | awk '{print $1}' > "${DEB_HIER}/boot/firmware/boot.sig" |
| 203 | +echo -n "rsa2048: " >> "${DEB_HIER}/boot/firmware/boot.sig" |
| 204 | +${OPENSSL} dgst \ |
| 205 | + -sign "${CUSTOMER_KEY_FILE_PEM}" \ |
| 206 | + -keyform PEM \ |
| 207 | + -sha256 \ |
| 208 | + "${DEB_HIER}/boot/firmware/boot.img" \ |
| 209 | + | xxd -c 4096 -p >> "${DEB_HIER}/boot/firmware/boot.sig" |
| 210 | + |
| 211 | +# Insert control file |
| 212 | +mkdir "${DEB_HIER}/DEBIAN" |
| 213 | +echo \ |
| 214 | +"Package: ${PACKAGE_NAME} |
| 215 | +Source: linux |
| 216 | +Version: ${KERNEL_2711_VERSION} |
| 217 | +Architecture: arm64 |
| 218 | +Maintainer: ${BOOT_IMAGE_MAINTAINER} |
| 219 | +Section: kernel |
| 220 | +Priority: optional |
| 221 | +Homepage: https://github.com/raspberrypi/linux/ |
| 222 | +Provides: ${KERNEL_2711} |
| 223 | +Conflicts: ${KERNEL_2711} |
| 224 | +Replaces: ${KERNEL_2711} |
| 225 | +Description: Repackaged ${KERNEL_2711} for signed/cryptroot boot" \ |
| 226 | +> "${DEB_HIER}/DEBIAN/control" |
| 227 | + |
| 228 | +# Create Debian package |
| 229 | +dpkg-deb --build "${DEB_HIER}" "${CACHE_DIRECTORY}" |
0 commit comments