OLD | NEW |
(Empty) | |
| 1 #!/bin/bash |
| 2 # |
| 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 # |
| 7 # Script which ensures that a given image has an up-to-date |
| 8 # kernel partition, rootfs integrity hashes, and legacy bootloader configs. |
| 9 |
| 10 # Load common constants. This should be the first executable line. |
| 11 # The path to common.sh should be relative to your script's location. |
| 12 COMMON_PATH="$(dirname "$0")/../common.sh" |
| 13 if [ ! -r "${COMMON_PATH}" ]; then |
| 14 echo "ERROR! Cannot find common.sh: ${COMMON_PATH}" 1>&2 |
| 15 exit 1 |
| 16 fi |
| 17 . "$(dirname "$0")/../common.sh" |
| 18 |
| 19 set -e |
| 20 . "$(dirname "$0")/../chromeos-common.sh" # for partoffset and partsize |
| 21 |
| 22 if [ ${#} -ne 2 ]; then |
| 23 die "Usage: $0 /path/to/image/dir image_name" |
| 24 fi |
| 25 |
| 26 BOOT_DESC_FILE="${1}/boot.desc" |
| 27 IMAGE="${1}/${2}" |
| 28 |
| 29 if [ ! -r "${BOOT_DESC_FILE}" ]; then |
| 30 warning "${BOOT_DESC_FILE} cannot be read!" |
| 31 warning "Falling back to command line parsing" |
| 32 BOOT_DESC="${@}" |
| 33 else |
| 34 BOOT_DESC="$(cat ${BOOT_DESC_FILE} | tr -s '\n' ' ')" |
| 35 info "Boot-time configuration for $(dirname ${IMAGE}): " |
| 36 cat ${BOOT_DESC_FILE} | while read line; do |
| 37 info " ${line}" |
| 38 done |
| 39 fi |
| 40 |
| 41 if [ ! -r "${IMAGE}" ]; then |
| 42 die "${IMAGE} cannot be read!" |
| 43 fi |
| 44 |
| 45 # Script must be run inside the chroot. |
| 46 restart_in_chroot_if_needed $* |
| 47 |
| 48 locate_gpt |
| 49 set +e |
| 50 |
| 51 # Now parse the build settings from ${OUTPUT_DIR}/boot.desc |
| 52 |
| 53 DEFINE_string output_dir "/tmp" \ |
| 54 "Directory to place output in." |
| 55 DEFINE_string image "chromiumos_base.img" \ |
| 56 "Full path to the chromiumos image to make bootable." |
| 57 DEFINE_string arch "x86" \ |
| 58 "Architecture to make bootable for: arm or x86" |
| 59 DEFINE_string usb_disk "/dev/sdb3" \ |
| 60 "Path syslinux should use to do a usb boot." |
| 61 DEFINE_boolean cleanup_dirs ${FLAGS_TRUE} \ |
| 62 "Whether the mount dirs should be removed on completion." |
| 63 |
| 64 DEFINE_integer rootfs_size 720 \ |
| 65 "rootfs filesystem size in MBs." |
| 66 # ceil(0.1 * rootfs_size) is a good minimum. |
| 67 DEFINE_integer rootfs_hash_pad 8 \ |
| 68 "MBs reserved at the end of the rootfs image." |
| 69 |
| 70 DEFINE_string rootfs_hash "/tmp/rootfs.hash" \ |
| 71 "Path where the rootfs hash should be stored." |
| 72 DEFINE_boolean enable_rootfs_verification ${FLAGS_FALSE} \ |
| 73 "Default all bootloaders to use kernel-based root fs integrity checking." |
| 74 DEFINE_integer verity_error_behavior 2 \ |
| 75 "Kernel verified boot error behavior (0: I/O errors, 1: reboot, 2: nothing)" |
| 76 DEFINE_integer verity_depth 1 \ |
| 77 "Kernel verified boot hash tree depth" |
| 78 DEFINE_integer verity_max_ios 1024 \ |
| 79 "Number of outstanding I/O operations dm-verity caps at." |
| 80 DEFINE_string verity_algorithm "sha1" \ |
| 81 "Cryptographic hash algorithm used for kernel vboot." |
| 82 |
| 83 DEFINE_string keys_dir "/usr/share/vboot/devkeys" \ |
| 84 "Directory containing the signing keys." |
| 85 |
| 86 DEFINE_string rootfs_mountpoint "/tmp/rootfs" \ |
| 87 "Path where the rootfs can be safely mounted" |
| 88 DEFINE_string statefulfs_mountpoint "/tmp/statefulfs" \ |
| 89 "Path where the statefulfs can be safely mounted" |
| 90 DEFINE_string espfs_mountpoint "/tmp/espfs" \ |
| 91 "Path where the espfs can be safely mounted" |
| 92 |
| 93 # Parse the boot.desc |
| 94 eval set -- "${BOOT_DESC}" |
| 95 FLAGS "${@}" || exit 1 |
| 96 eval set -- "${FLAGS_ARGV}" |
| 97 |
| 98 # Only now can we die on error. shflags functions leak non-zero error codes, |
| 99 # so will die prematurely if 'set -e' is specified before now. |
| 100 set -e -u |
| 101 |
| 102 # $1 - Directory where developer rootfs is mounted. |
| 103 # $2 - Directory where developer stateful_partition is mounted. |
| 104 # $3 - Directory where the ESP partition is mounted. |
| 105 mount_gpt_cleanup() { |
| 106 local rootfs="${1-$FLAGS_rootfs_mountpoint}" |
| 107 local statefs="${2-$FLAGS_statefulfs_mountpoint}" |
| 108 local espfs="${3-$FLAGS_espfs_mountpoint}" |
| 109 "${SCRIPTS_DIR}/mount_gpt_image.sh" \ |
| 110 -u -r "${rootfs}" -s "${statefs}" -e "${espfs}" |
| 111 } |
| 112 |
| 113 make_image_bootable() { |
| 114 local image="$1" |
| 115 |
| 116 cros_root=/dev/sd%D%P |
| 117 if [[ "${FLAGS_arch}" = "arm" ]]; then |
| 118 # TODO(wad) assumed like in build_gpt for now. |
| 119 cros_root=/dev/mmcblk1p3 |
| 120 fi |
| 121 if [[ ${FLAGS_enable_rootfs_verification} -eq ${FLAGS_TRUE} ]]; then |
| 122 cros_root=/dev/dm-0 |
| 123 fi |
| 124 |
| 125 trap "mount_gpt_cleanup" EXIT |
| 126 ${SCRIPTS_DIR}/mount_gpt_image.sh --from "$(dirname ${image})" \ |
| 127 --image "$(basename ${image})" -r "${FLAGS_rootfs_mountpoint}" \ |
| 128 -s "${FLAGS_statefulfs_mountpoint}" |
| 129 |
| 130 # The rootfs should never be mounted rw again after this point without |
| 131 # re-calling make_image_bootable. |
| 132 sudo mount -o remount,ro "${FLAGS_rootfs_mountpoint}" |
| 133 root_dev=$(mount | grep -- "on ${FLAGS_rootfs_mountpoint} type" | |
| 134 cut -f1 -d' ' | tail -1) |
| 135 |
| 136 # Builds the kernel partition image. The temporary files are kept around |
| 137 # so that we can perform a load_kernel_test later on the final image. |
| 138 ${SCRIPTS_DIR}/build_kernel_image.sh \ |
| 139 --arch="${FLAGS_arch}" \ |
| 140 --to="${FLAGS_output_dir}/vmlinuz.image" \ |
| 141 --hd_vblock="${FLAGS_output_dir}/vmlinuz_hd.vblock" \ |
| 142 --vmlinuz="${FLAGS_rootfs_mountpoint}/boot/vmlinuz" \ |
| 143 --working_dir="${FLAGS_output_dir}" \ |
| 144 --keep_work \ |
| 145 --rootfs_image=${root_dev} \ |
| 146 --rootfs_hash=${FLAGS_rootfs_hash} \ |
| 147 --verity_hash_alg=${FLAGS_verity_algorithm} \ |
| 148 --verity_tree_depth=${FLAGS_verity_depth} \ |
| 149 --verity_max_ios=${FLAGS_verity_max_ios} \ |
| 150 --verity_error_behavior=${FLAGS_verity_error_behavior} \ |
| 151 --root=${cros_root} \ |
| 152 --keys_dir="${FLAGS_keys_dir}" |
| 153 |
| 154 local rootfs_hash_size=$(stat -c '%s' ${FLAGS_rootfs_hash}) |
| 155 info "Appending rootfs.hash (${rootfs_hash_size} bytes) to the root fs" |
| 156 if [[ ${rootfs_hash_size} -gt $((FLAGS_rootfs_hash_pad * 1024 * 1024)) ]] |
| 157 then |
| 158 die "--rootfs_hash_pad reserves less than the needed ${rootfs_hash_size}" |
| 159 fi |
| 160 # Unfortunately, mount_gpt_image uses mount and not losetup to create the |
| 161 # loop devices. This means that they are not the correct size. We have to |
| 162 # write directly to the image to append the hash tree data. |
| 163 local hash_offset="$(partoffset ${image} 3)" |
| 164 hash_offset=$((hash_offset + ((1024 * 1024 * ${FLAGS_rootfs_size}) / 512))) |
| 165 sudo dd bs=512 \ |
| 166 seek=${hash_offset} \ |
| 167 if="${FLAGS_rootfs_hash}" \ |
| 168 of="${image}" \ |
| 169 conv=notrunc |
| 170 # We don't need to keep the file around anymore. |
| 171 sudo rm "${FLAGS_rootfs_hash}" |
| 172 |
| 173 # Move the verification block needed for the hard disk install to the |
| 174 # stateful partition. Mount stateful fs, copy file, and umount fs. |
| 175 # In original CL: http://codereview.chromium.org/2868044, this was done in |
| 176 # create_base_image(). However, it could break the build if it is a clean |
| 177 # build because vmlinuz_hd.vblock hasn't been created by build_kernel_image.sh |
| 178 if [[ "${FLAGS_arch}" = "x86" ]]; then |
| 179 sudo cp "${FLAGS_output_dir}/vmlinuz_hd.vblock" \ |
| 180 "${FLAGS_statefulfs_mountpoint}" |
| 181 fi |
| 182 |
| 183 # START_KERN_A is set by the first call to install the gpt. |
| 184 local koffset="$(partoffset ${image} 2)" |
| 185 sudo dd if="${FLAGS_output_dir}/vmlinuz.image" of="${image}" \ |
| 186 conv=notrunc bs=512 seek=${koffset} |
| 187 |
| 188 # Update the bootloaders. For legacy/efi x86, the EFI system partition |
| 189 # will be updated and for arm, the mbr will be updated (for u-boot). |
| 190 local kernel_part= |
| 191 local bootloader_to= |
| 192 local bootloader_to_flags= |
| 193 local usb_disk="${FLAGS_usb_disk}" |
| 194 |
| 195 if [[ "${FLAGS_arch}" = "x86" ]]; then |
| 196 # x86 should update the esp in place in the image. |
| 197 bootloader_to="${image}" |
| 198 local esp_offset="$(partoffset ${image} 12)" |
| 199 esp_offset=$((esp_offset * 512)) # sectors to bytes |
| 200 local esp_size="$(partsize ${image} 12)" |
| 201 esp_size=$((esp_size * 512)) # sectors to bytes |
| 202 bootloader_to_flags="--to_offset=${esp_offset} --to_size=${esp_size}" |
| 203 # Use the kernel partition to acquire configuration flags. |
| 204 kernel_part="--kernel_partition='${FLAGS_output_dir}/vmlinuz.image'" |
| 205 # Install syslinux on the EFI System Partition. |
| 206 kernel_part="${kernel_part} --install_syslinux" |
| 207 elif [[ "${FLAGS_arch}" = "arm" ]]; then |
| 208 # TODO(wad) mmcblk1p3 is hardcoded for arm for now! |
| 209 usb_disk="/dev/mmcblk1p3" |
| 210 # ARM doesn't support using the kernel image for kernel cmdline flags yet. |
| 211 kernel_part="--kernel_cmdline=\"${FLAGS_arm_extra_bootargs}\" " |
| 212 # TODO(wad) Integrate dmtable extraction into the arm build |
| 213 # E.g. $(cat ${FLAGS_output_dir}/boot.config | tr -s '\n' ' ')" |
| 214 local kpart_offset="--kernel_partition_offset=${koffset}" |
| 215 local kpart_size="--kernel_partition_sectors=" |
| 216 kpart_size="${kpart_size}$(partsize ${image} 2)" |
| 217 kernel_part="${kernel_part} ${kpart_size} ${kpart_offset}" |
| 218 info "Using addition bootloader arguments: ${kernel_part}" |
| 219 bootloader_to="${FLAGS_output_dir}/arm.mbr" |
| 220 fi |
| 221 |
| 222 # Update partition 12 / legacy bootloaders and arm. |
| 223 ${SCRIPTS_DIR}/update_bootloaders.sh \ |
| 224 --arch=${FLAGS_arch} \ |
| 225 --to="${bootloader_to}" \ |
| 226 --from="${FLAGS_rootfs_mountpoint}"/boot \ |
| 227 --vmlinuz="${FLAGS_rootfs_mountpoint}"/boot/vmlinuz \ |
| 228 --usb_disk="${usb_disk}" \ |
| 229 ${bootloader_to_flags} \ |
| 230 $kernel_part |
| 231 |
| 232 if [[ "${FLAGS_arch}" == "arm" ]]; then |
| 233 sudo dd bs=1 conv=notrunc if="${bootloader_to}" of="${image}" |
| 234 sudo rm "${bootloader_to}" |
| 235 fi |
| 236 |
| 237 trap - EXIT |
| 238 ${SCRIPTS_DIR}/mount_gpt_image.sh -u -r "${FLAGS_rootfs_mountpoint}" \ |
| 239 -s "${FLAGS_statefulfs_mountpoint}" |
| 240 } |
| 241 |
| 242 # Create the directories if they don't exist. |
| 243 mkdir -p ${FLAGS_rootfs_mountpoint} |
| 244 mkdir -p ${FLAGS_statefulfs_mountpoint} |
| 245 mkdir -p ${FLAGS_espfs_mountpoint} |
| 246 |
| 247 make_image_bootable ${IMAGE} |
| 248 |
| 249 if [ ${FLAGS_cleanup_dirs} -eq ${FLAGS_TRUE} ]; then |
| 250 rmdir ${FLAGS_rootfs_mountpoint} |
| 251 rmdir ${FLAGS_statefulfs_mountpoint} |
| 252 rmdir ${FLAGS_espfs_mountpoint} |
| 253 fi |
OLD | NEW |