summaryrefslogtreecommitdiff
path: root/util/signer/create_released_image.sh
diff options
context:
space:
mode:
Diffstat (limited to 'util/signer/create_released_image.sh')
-rwxr-xr-xutil/signer/create_released_image.sh222
1 files changed, 222 insertions, 0 deletions
diff --git a/util/signer/create_released_image.sh b/util/signer/create_released_image.sh
new file mode 100755
index 0000000000..9dccd02aba
--- /dev/null
+++ b/util/signer/create_released_image.sh
@@ -0,0 +1,222 @@
+#!/bin/bash
+
+#
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# This script is a utility which allows to sign prod CR50 images for release
+# and place them in a tarball suitable for uploading to the BCS.
+#
+# The util/signer/ec_RW-manifest-prod.json manifest present in the EC
+# directory is used for signing.
+#
+
+set -u
+
+# A very crude RO verification function. The key signature found at a fixed
+# offset into the RO blob must match the RO type. Prod keys have bit D2 set to
+# one, dev keys have this bit set to zero.
+verify_ro() {
+ local ro_bin="${1}"
+ local type_expected="${2}"
+ local key_byte
+
+ if [ ! -f "${ro_bin}" ]; then
+ echo "${ro_bin} not a file!" >&2
+ exit 1
+ fi
+
+ # Key signature's lowest byte is byte #5 in the line at offset 0001a0.
+ key_byte="$(od -Ax -t x1 -v "${ro_bin}" | awk '/0001a0/ {print $6};')"
+ case "${key_byte}" in
+ (?[4567cdef])
+ if [ "${type_expected}" == "prod" ]; then
+ return 0
+ fi
+ ;;
+ (?[012389ab])
+ if [ "${type_expected}" == "dev" ]; then
+ return 0
+ fi
+ ;;
+ esac
+
+ echo "RO key in ${ro_bin} does not match type ${type_expected}" >&2
+ exit 1
+}
+
+# This function prepares a full CR50 image, consisting of two ROs and two RWs
+# placed at their respective offsets into the resulting blob. It invokes the
+# bs (binary signer) script to actually convert elf versions of RWs into
+# binaries and sign them.
+#
+# The signed image is placed in the directory named as concatenation of RO and
+# RW version numbers and board ID fields, if set to non-default. The ebuild
+# downloading the tarball from the BCS expects the image to be in that
+# directory.
+prepare_image() {
+ local awk_prog
+ local count=0
+ local extra_param=
+ local image_type="${1}"
+ local raw_version
+ local ro_a_hex="$(readlink -f "${2}")"
+ local ro_b_hex="$(readlink -f "${3}")"
+ local rw_a="$(readlink -f "${4}")"
+ local rw_b="$(readlink -f "${5}")"
+ local version
+
+ for f in "${ro_a_hex}" "${ro_b_hex}"; do
+ if ! objcopy -I ihex "${f}" -O binary "${TMPD}/${count}.bin"; then
+ echo "failed to convert ${f} from hex to bin" >&2
+ exit 1
+ fi
+ verify_ro "${TMPD}/${count}.bin" "${image_type}"
+ : $(( count += 1 ))
+ done
+
+ if [ "${image_type}" == "prod" ]; then
+ extra_param+=' prod'
+ fi
+
+ if ! "${EC_ROOT}/util/signer/bs" ${extra_param} elves \
+ "${rw_a}" "${rw_b}" > /dev/null;
+ then
+ echo "Failed invoking ${EC_ROOT}/util/signer/bs ${extra_param} " \
+ "elves ${rw_a} ${rw_b}" >&2
+ exit 1
+ fi
+
+ dd if="${TMPD}/0.bin" of="${RESULT_FILE}" conv=notrunc
+ dd if="${TMPD}/1.bin" of="${RESULT_FILE}" seek=262144 bs=1 conv=notrunc
+
+ # A typical Cr50 version reported by gsctool looks as follows:
+ # RO_A:0.0.10 RW_A:0.0.22[ABCD:00000013:00000012] ...(the same for R[OW]_B).
+ #
+ # In case Board ID field is not set in the image, it is reported as
+ # [00000000:00000000:00000000]
+ #
+ # We want the generated tarball file name to include all relevant version
+ # fields. Let's retrieve the version string and process it using awk to
+ # generate the proper file name. Only the RO_A and RW_A version numbers are
+ # used, this script trusts the user to submit for processing a proper image
+ # where both ROs and both RWs are of the same version respectively.
+ #
+ # As a result, blob versions are converted as follows:
+ # RO_A:0.0.10 RW_A:0.0.22[ABCD:00000013:00000012] into
+ # r0.0.10.w0.0.22_ABCD_00000013_00000012
+ #
+ # RO_A:0.0.10 RW_A:0.0.22[00000000:00000000:00000000] into
+ # r0.0.10.w0.0.22
+ #
+ # The below awk program accomplishes this preprocessing.
+ awk_prog='/^RO_A:/ {
+ # drop the RO_A/RW_A strings
+ gsub(/R[OW]_A:/, "")
+ # Drop default mask value completely.
+ gsub(/\[00000000:00000000:00000000\]/, "")
+ # If there is a non-default mask:
+ # - replace opening brackets and colons with underscores.
+ gsub(/[\[\:]/, "_")
+ # - drop the trailing bracket.
+ gsub(/\]/, "")
+ # Print filtered out RO_A and RW_A values
+ print "r" $1 ".w" $2
+}'
+
+ raw_version="$("${GSCTOOL}" -b "${RESULT_FILE}")" ||
+ ( echo "${ME}: Failed to retrieve blob version" >&2 && exit 1 )
+
+ version="$(awk "${awk_prog}" <<< "${raw_version}" )"
+ if [ -z "${dest_dir}" ]; then
+ # Note that this is a global variable
+ dest_dir="cr50.${version}"
+ if [ ! -d "${dest_dir}" ]; then
+ mkdir "${dest_dir}"
+ else
+ echo "${dest_dir} already exists, will overwrite" >&2
+ fi
+ elif [ "${dest_dir}" != "cr50.${version}" ]; then
+ echo "dev and prod versions mismatch!" >&2
+ exit 1
+ fi
+
+ cp "${RESULT_FILE}" "${dest_dir}/cr50.bin.${image_type}"
+ echo "saved ${image_type} binary in ${dest_dir}/cr50.bin.${image_type}"
+}
+
+# Execution starts here ===========================
+ME="$(basename $0)"
+
+if [ -z "${CROS_WORKON_SRCROOT}" ]; then
+ echo "${ME}: This script must run inside Chrome OS chroot" >&2
+ exit 1
+fi
+
+SCRIPT_ROOT="${CROS_WORKON_SRCROOT}/src/scripts"
+. "${SCRIPT_ROOT}/build_library/build_common.sh" || exit 1
+
+TMPD="$(mktemp -d /tmp/${ME}.XXXXX)"
+trap "/bin/rm -rf ${TMPD}" SIGINT SIGTERM EXIT
+
+EC_ROOT="${CROS_WORKON_SRCROOT}/src/platform/ec"
+RESULT_FILE="${TMPD}/release.bin"
+dest_dir=
+IMAGE_SIZE='524288'
+export RESULT_FILE
+
+GSCTOOL="/usr/sbin/gsctool"
+if [[ ! -x "${GSCTOOL}" ]]; then
+ emerge_command="USE=cr50_onboard sudo -E emerge ec-utils"
+ echo "${ME}: gsctool not found, run \"${emerge_command}\"" >&2
+ exit 1
+fi
+
+DEFINE_string cr50_board_id "" \
+ "Optional string representing Board ID field of the Cr50 RW header.
+Consists of three fields separated by colon: <RLZ>:<hex mask>:<hex flags>"
+
+# Do not put this before the DEFINE_ invocations - they routinely experience
+# error return values.
+set -e
+
+FLAGS_HELP="usage: ${ME} [flags] <blobs>
+
+blobs are:
+ <prod RO A>.hex <prod RO B>.hex <RW.elf> <RW_B.elf>"
+
+# Parse command line.
+FLAGS "$@" || exit 1
+
+eval set -- "${FLAGS_ARGV}"
+if [ "${#*}" != "4" ]; then
+ flags_help
+ exit 1
+fi
+
+dd if=/dev/zero bs="${IMAGE_SIZE}" count=1 2>/dev/null |
+ tr \\000 \\377 > "${RESULT_FILE}"
+if [ "$(stat -c '%s' "${RESULT_FILE}")" != "${IMAGE_SIZE}" ]; then
+ echo "Failed creating ${RESULT_FILE}" >&2
+ exit 1
+fi
+
+prod_ro_a="${1}"
+prod_ro_b="${2}"
+rw_a="${3}"
+rw_b="${4}"
+
+# Used by the bs script.
+export CR50_BOARD_ID="${FLAGS_cr50_board_id}"
+
+prepare_image 'prod' "${prod_ro_a}" "${prod_ro_b}" "${rw_a}" "${rw_b}"
+tarball="${dest_dir}.tbz2"
+tar jcf "${tarball}" "${dest_dir}"
+rm -rf "${dest_dir}"
+
+bcs_path="gs://chromeos-localmirror/distfiles"
+echo "SUCCESS!!!!!!"
+echo "use the below commands to copy the new image to the BCS"
+echo "gsutil cp ${tarball} ${bcs_path}"
+echo "gsutil acl ch -u AllUsers:R ${bcs_path}/${tarball}"