Mike Frysinger | 3424c80 | 2018-08-16 15:00:32 -0400 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | # Copyright 2017 The Chromium OS Authors. All rights reserved. |
| 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | # Script to automate firmware update process for a board. |
| 7 | # It works only when the private overlay and firmware ebuild |
| 8 | # file for the board are already in place. |
| 9 | |
| 10 | # Loads script libraries. |
| 11 | CONTRIB_DIR=$(dirname "$(readlink -f "$0")") |
| 12 | . "${CONTRIB_DIR}/common.sh" || exit 1 |
| 13 | |
| 14 | # Flags. |
| 15 | DEFINE_string board "${DEFAULT_BOARD}" "Which board the firmware is for" b |
| 16 | DEFINE_string fw_version "" "Firmware version of the new firmware" v |
| 17 | DEFINE_string output_dir "" "Output directory" o |
| 18 | DEFINE_boolean rw_only "${FLAGS_FALSE}" "Only update RW image" |
| 19 | DEFINE_boolean dev "${FLAGS_FALSE}" "Use image.dev.bin as the main firmware binary" |
| 20 | |
| 21 | FLAGS_HELP="Update chromeos-firmware-${board} ebuild file and tarball in BCS for the new firmware. |
| 22 | |
| 23 | USAGE: $0 [flags] args |
| 24 | |
| 25 | For example: |
| 26 | |
| 27 | To uprev kevin ro/rw firmware to 8785.178.0, run: |
| 28 | $ ./uprev_firmware -b kevin -v 8785.178.0 |
| 29 | |
| 30 | To uprev chell rw firmware to 7820.288.0, run: |
| 31 | $ ./uprev_firmware -b chell -v 7820.288.0 --rw_only |
| 32 | " |
| 33 | |
| 34 | # Parse command line. |
| 35 | FLAGS "$@" || exit 1 |
| 36 | eval set -- "${FLAGS_ARGV}" |
| 37 | set -e |
| 38 | |
| 39 | # Script must run inside the chroot. |
| 40 | assert_inside_chroot |
| 41 | |
| 42 | # Sanity check the arguments and initialize global variables. |
| 43 | init() { |
| 44 | TMP=$(mktemp -d --suffix=.uprev_firmware) |
| 45 | |
| 46 | if [[ -z "${FLAGS_board}" ]]; then |
| 47 | die "-b or --board required." |
| 48 | fi |
| 49 | |
| 50 | # Uppercase the 1st letter of the board name. |
| 51 | BOARD_NAME=${FLAGS_board^} |
| 52 | |
| 53 | if [[ -z "${FLAGS_fw_version}" ]]; then |
| 54 | die "Please specify a firmware version using -v" |
| 55 | fi |
| 56 | |
| 57 | if [[ -z "${FLAGS_output_dir}" ]]; then |
| 58 | info "${TMP} is used as your default output directory\n" |
| 59 | FLAGS_output_dir=${TMP} |
| 60 | fi |
| 61 | |
| 62 | if [[ ! -d "${FLAGS_output_dir}" ]]; then |
| 63 | die "The output directory does not exist\n" |
| 64 | fi |
| 65 | FLAGS_output_dir=$(realpath "${FLAGS_output_dir}") |
| 66 | |
| 67 | if [[ ! -d "/build/${FLAGS_board}" ]]; then |
| 68 | die "Please setup board for ${FLAGS_board} first" |
| 69 | fi |
| 70 | |
| 71 | OVERLAY_DIR="${GCLIENT_ROOT}/src/private-overlays/\ |
| 72 | overlay-${FLAGS_board}-private" |
| 73 | if [[ ! -d "${OVERLAY_DIR}" ]]; then |
| 74 | die "The private overlay is not found: ${OVERLAY_DIR}" |
| 75 | fi |
| 76 | |
| 77 | EBUILD_DIR="${OVERLAY_DIR}/chromeos-base/chromeos-firmware-${FLAGS_board}" |
| 78 | if [[ ! -d "${EBUILD_DIR}" ]]; then |
| 79 | die "The directory doesn't exist: ${EBUILD_DIR}" |
| 80 | fi |
| 81 | |
| 82 | EBUILD_FILE="${EBUILD_DIR}/chromeos-firmware-${FLAGS_board}-9999.ebuild" |
| 83 | if [[ ! -f "${EBUILD_FILE}" ]]; then |
| 84 | die "Please create the initial firmware ebuild manually:\n" \ |
| 85 | "${EBUILD_FILE}" |
| 86 | fi |
| 87 | |
| 88 | if [[ "${FLAGS_dev}" -eq "${FLAGS_TRUE}" ]]; then |
| 89 | MAIN_FW_TAR_NAME="${BOARD_NAME}.${FLAGS_fw_version}.DEV_IMAGE_DO_NOT_SHIP\ |
| 90 | .tbz2" |
| 91 | else |
| 92 | MAIN_FW_TAR_NAME="${BOARD_NAME}.${FLAGS_fw_version}.tbz2" |
| 93 | fi |
| 94 | EC_FW_TAR_NAME="${BOARD_NAME}_EC.${FLAGS_fw_version}.tbz2" |
| 95 | PD_FW_TAR_NAME="${BOARD_NAME}_PD.${FLAGS_fw_version}.tbz2" |
| 96 | } |
| 97 | |
| 98 | # Clean up function when exit. |
| 99 | cleanup() { |
| 100 | rm -rf "${TMP}" |
| 101 | } |
| 102 | |
| 103 | # Prepare new firmware tarballs to upload to BCS |
| 104 | prepare_fw_tarball() { |
| 105 | local build_dir="gs://chromeos-releases/canary-channel/\ |
| 106 | ${FLAGS_board}/${FLAGS_fw_version}" |
| 107 | local build_fw_tar_path=$(gsutil ls "${build_dir}/ChromeOS-firmware-*") |
| 108 | local build_fw_tar_name=$(basename "${build_fw_tar_path}") |
| 109 | |
| 110 | if [[ -z "${build_fw_tar_path}" ]]; then |
| 111 | die "Please ensure your gsutil works and the firmware version is correct" |
| 112 | fi |
| 113 | |
| 114 | # Download the firmware tarball. |
| 115 | gsutil cp "${build_fw_tar_path}" "${TMP}/." |
| 116 | tar -xvf "${TMP}/${build_fw_tar_name}" -C "${TMP}" |
| 117 | if [[ "${FLAGS_dev}" -eq "${FLAGS_TRUE}" ]]; then |
| 118 | mv "${TMP}/image.dev.bin" "${TMP}/image.bin" |
| 119 | warn "You are uploading a developer image with serial output." \ |
| 120 | "Please only do this during early bring-up. Dogfooding should always be" \ |
| 121 | "done with production images since timing differences in developer"\ |
| 122 | "images can hide bugs and the production image must be sufficiently" \ |
| 123 | "tested before shipping.\n" |
| 124 | fi |
| 125 | # Make new tarballs for EC/AP FW binaries. |
| 126 | tar -jcvf "${TMP}/${MAIN_FW_TAR_NAME}" -C "${TMP}" image.bin |
| 127 | if [[ "${FLAGS_rw_only}" -eq "${FLAGS_FALSE}" ]]; then |
| 128 | tar -jcvf "${TMP}/${EC_FW_TAR_NAME}" -C "${TMP}" ec.bin |
| 129 | # Do this for PD FW as well (if available). |
| 130 | if [ -d "${TMP}/${FLAGS_board}_pd" ]; then |
| 131 | tar -jcvf "${TMP}/${PD_FW_TAR_NAME}" -C "${TMP}/${FLAGS_board}_pd" ec.bin |
| 132 | else |
| 133 | PD_FW_TAR_NAME= |
| 134 | fi |
| 135 | fi |
| 136 | |
| 137 | if [[ "${TMP}" != "${FLAGS_output_dir}" ]]; then |
| 138 | mv "${TMP}/${MAIN_FW_TAR_NAME}" "${FLAGS_output_dir}" |
| 139 | if [[ "${FLAGS_rw_only}" -eq "${FLAGS_FALSE}" ]]; then |
| 140 | mv "${TMP}/${EC_FW_TAR_NAME}" "${FLAGS_output_dir}" |
| 141 | if [[ -z "${PD_FW_TAR_NAME}" ]]; then |
| 142 | mv "${TMP}/${PD_FW_TAR_NAME}" "${FLAGS_output_dir}" |
| 143 | fi |
| 144 | fi |
| 145 | fi |
| 146 | |
| 147 | local file_list="${FLAGS_output_dir}/${MAIN_FW_TAR_NAME}\n" |
| 148 | if [[ "${FLAGS_rw_only}" -eq "${FLAGS_FALSE}" ]]; then |
| 149 | file_list+=" ${FLAGS_output_dir}/${EC_FW_TAR_NAME}\n" |
| 150 | if [ -n "${PD_FW_TAR_NAME}" ]; then |
| 151 | file_list+=" ${FLAGS_output_dir}/${PD_FW_TAR_NAME}\n" |
| 152 | fi |
| 153 | fi |
| 154 | |
| 155 | info "Your tarballs are ready at\n" \ |
| 156 | "${file_list}" \ |
| 157 | "To continue, please upload them to BCS manually through CPFE:\n" \ |
| 158 | "https://www.google.com/chromeos/partner/fe/#bcUpload:type=PRIVATE\n" |
| 159 | } |
| 160 | |
| 161 | # Update the firmware ebuild file in the device private overlay |
| 162 | update_fw_ebuild() { |
| 163 | local keyword_main_fw="MAIN_IMAGE=\"bcs:\/\/${BOARD_NAME}" |
| 164 | local keyword_main_rw_fw="CROS_FIRMWARE_MAIN_RW_IMAGE=" |
| 165 | local keyword_ec_fw="EC_IMAGE=\"bcs:\/\/${BOARD_NAME}" |
| 166 | local keyword_pd_fw="PD_IMAGE=\"bcs:\/\/${BOARD_NAME}" |
| 167 | local main_fw_line=$(grep -i "${keyword_main_fw}" "${EBUILD_FILE}") |
| 168 | local main_rw_fw_line=$(grep -i "${keyword_main_rw_fw}" "${EBUILD_FILE}") |
| 169 | local ec_fw_line=$(grep -i "${keyword_ec_fw}" "${EBUILD_FILE}") |
| 170 | local pd_fw_line=$(grep -i "${keyword_pd_fw}" "${EBUILD_FILE}") |
| 171 | local old_main_fw_tar_name="${main_fw_line#*bcs://}" |
| 172 | old_main_fw_tar_name="${old_main_fw_tar_name%'"'}" |
| 173 | local old_ec_fw_tar_name="${ec_fw_line#*bcs://}" |
| 174 | old_ec_fw_tar_name="${old_ec_fw_tar_name%'"'}" |
| 175 | local old_pd_fw_tar_name="${pd_fw_line#*bcs://}" |
| 176 | old_pd_fw_tar_name="${old_pd_fw_tar_name%'"'}" |
| 177 | |
| 178 | # Check if the repo is clean. |
| 179 | local git_output="$(git --git-dir="${OVERLAY_DIR}/.git" \ |
| 180 | --work-tree="${OVERLAY_DIR}" status --porcelain)" |
| 181 | if [[ -n ${git_output} ]]; then |
| 182 | die "Please clean your repo first: ${OVERLAY_DIR}" |
| 183 | fi |
| 184 | |
| 185 | # Update the fw ebuild file. |
| 186 | if [[ -n "${main_rw_fw_line}" ]]; then |
| 187 | sed -i "/${keyword_main_rw_fw}/d" "${EBUILD_FILE}" |
| 188 | fi |
| 189 | if [[ "${FLAGS_rw_only}" -eq "${FLAGS_FALSE}" ]]; then |
| 190 | sed -i -e "s/${old_main_fw_tar_name}/${MAIN_FW_TAR_NAME}/" \ |
| 191 | -e "s/${old_ec_fw_tar_name}/${EC_FW_TAR_NAME}/" "${EBUILD_FILE}" |
| 192 | main_rw_fw_line="${keyword_main_rw_fw}\"\"" |
| 193 | if [[ -n "${PD_FW_TAR_NAME}" ]]; then |
| 194 | sed -i -e "s/${old_pd_fw_tar_name}/${PD_FW_TAR_NAME}/" \ |
| 195 | "${EBUILD_FILE}" |
| 196 | fi |
| 197 | else |
| 198 | main_rw_fw_line="${keyword_main_rw_fw}\"\ |
| 199 | bcs:\/\/${MAIN_FW_TAR_NAME}\"" |
| 200 | fi |
| 201 | # Create a new line for CROS_FIRMWARE_MAIN_RW_IMAGE |
| 202 | sed -i "/${keyword_main_fw}/a ${main_rw_fw_line}" "${EBUILD_FILE}" |
| 203 | |
| 204 | # Update the manifest. |
| 205 | ebuild-"${FLAGS_board}" "${EBUILD_FILE}" manifest |
| 206 | info "Ebuild files and manifest are updated at:\n${EBUILD_DIR}\n" |
| 207 | } |
| 208 | |
| 209 | # Build the firmware updater and verify the firmware version |
| 210 | verify_fw_updater() { |
| 211 | local fw_updater="/build/${FLAGS_board}/usr/sbin/chromeos-firmwareupdate" |
| 212 | local fw_updater_bios_version |
| 213 | cros_workon-"${FLAGS_board}" start "chromeos-firmware-${FLAGS_board}" |
| 214 | emerge-"${FLAGS_board}" "chromeos-firmware-${FLAGS_board}" |
| 215 | cros_workon-"${FLAGS_board}" stop "chromeos-firmware-${FLAGS_board}" |
| 216 | if [[ ! -f "${fw_updater}" ]]; then |
| 217 | die "Firmware updater is not found at ${fw_updater}" |
| 218 | fi |
| 219 | if [[ "${FLAGS_rw_only}" -eq "${FLAGS_TRUE}" ]]; then |
| 220 | fw_updater_bios_version=$(${fw_updater} -V | grep "BIOS (RW) version") |
| 221 | else |
| 222 | fw_updater_bios_version=$(${fw_updater} -V | grep "BIOS version") |
| 223 | fi |
| 224 | fw_updater_bios_version="${fw_updater_bios_version#*Google_}" |
| 225 | fw_updater_bios_version="${fw_updater_bios_version,,}" |
| 226 | if [[ "${FLAGS_board}.${FLAGS_fw_version}" != \ |
| 227 | "${fw_updater_bios_version}" ]]; then |
| 228 | die "The firmware version in the updater is incorrect" |
| 229 | fi |
| 230 | info "The firmware version in the updater is verified:" \ |
| 231 | "${FLAGS_fw_version}\nPlease commit your change.\n" |
| 232 | } |
| 233 | |
| 234 | main() { |
| 235 | TMP="" |
| 236 | trap cleanup EXIT |
| 237 | |
| 238 | if [[ "$#" -ne 0 ]]; then |
| 239 | flags_help |
| 240 | exit 1 |
| 241 | fi |
| 242 | |
| 243 | init |
| 244 | prepare_fw_tarball |
| 245 | |
| 246 | local sure |
| 247 | read -p "Please confirm that you've uploaded the tarballs to BCS [y/N]:" sure |
| 248 | if [[ "${sure}" != "y" ]]; then |
| 249 | die "Aborted..." |
| 250 | fi |
| 251 | update_fw_ebuild |
| 252 | verify_fw_updater |
| 253 | } |
| 254 | |
| 255 | main "$@" |