blob: b1c15564f81cd489595b75d2aa70896234bf4d8b [file] [log] [blame]
#!/bin/bash
# Copyright 2019 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.
CURRENT_DIR="$(dirname "$(readlink -f "$0")")"
SCRIPT_ROOT="${CURRENT_DIR}/../../scripts"
. "${SCRIPT_ROOT}/common.sh" || exit 1
# Lookup table for default firmware version for RO.
# Should give 2.2.64 for nocturne, 2.2.144 for nami.
BOARD_TO_FACTORY_RO_VERSION="\
nocturne 10984.21.0
nami 10984.82.0"
DEFINE_string board "" "The board name. e.g. nocturne" b
DEFINE_string ro_version "" \
"The firmware version of the target file for RO part. e.g. 10984.88.0" r
DEFINE_string rw_version "" \
"The firmware version of the target file for RW part. e.g. 10984.88.0" w
DEFINE_string channel "dev" \
"The channel of the target file. One of canary, dev, beta, or stable" c
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
set -e
# The temporary working directory.
TMP=""
# The base URL of the downloaded files (RO version).
GS_URL_BASE_RO=""
# The base URL of the downloaded files (RW version).
GS_URL_BASE_RW=""
# The directory on gs containing the required firmware binaries.
# This can be different from the board name, e.g. board "nami" is in directory
# "nocturne".
DIRECTORY_NAME=""
# Version number of RO part of FP firmware
FP_RO_VERSION_NUMBER=""
# Version number of RW part of FP firmware
FP_RW_VERSION_NUMBER=""
# Name of final output file
OUTPUT_TAR=""
get_fw_version_for_RO() {
local board_name="${1}"
local key
local value
echo "${BOARD_TO_FACTORY_RO_VERSION}" | while read key value; do
if [[ "${key}" == "${board_name}" ]]; then
echo "${value}"
fi
done
}
# verify_mp (file): Verify that |file| is signed by mp key.
verify_mp() {
local file="$1"
local version="$(futility verify "${file}" \
| grep "Version:" \
| grep -o "0x0000000[0-9]")"
local expected
# Key versions for nocturne were different but it was a 1-off and should not
# happen again.
if [[ "${FLAGS_board}" == "nocturne" ]]; then
expected="0x00000002"
else
expected="0x00000003"
fi
if [[ "${version}" != "${expected}" ]]; then
die "${file} may not be signed with mp key! Key version: ${version}."
fi
}
init() {
TMP="$(mktemp -d)"
echo "Create temp work directory: ${TMP}"
cd "${TMP}"
if [[ -z "${FLAGS_board}" ]]; then
die_notrace "Please specify the board name using -b"
fi
if [[ -z "${FLAGS_ro_version}" ]]; then
FLAGS_ro_version="$(get_fw_version_for_RO "${FLAGS_board}")"
if [[ -z "${FLAGS_ro_version}" ]]; then
die_notrace \
"Please specify a firmware version for RO part using -r, e.g. 10984.88.0"
fi
fi
if [[ -z "${FLAGS_rw_version}" ]]; then
die_notrace \
"Please specify a firmware version for RW part using -w, e.g. 10984.88.0"
fi
if [[ -z "${FLAGS_channel}" ]]; then
die_notrace "Please specify a channel using -c, e.g. canary"
fi
# Due to historical reasons, the nami_fp firmware are put in nocturne
# directory.
if [[ "${FLAGS_board}" == "nami" ]]; then
DIRECTORY_NAME="nocturne"
else
DIRECTORY_NAME="${FLAGS_board}"
fi
local gs_url_base="gs://chromeos-releases/${FLAGS_channel}-channel/"\
"${DIRECTORY_NAME}"
GS_URL_BASE_RO="${gs_url_base}/${FLAGS_ro_version}"
echo "Looking for RO part at URL: ${GS_URL_BASE_RO}"
if ! gsutil ls "${GS_URL_BASE_RO}" > /dev/null; then
die_notrace \
"${GS_URL_BASE_RO} is not a valid URL. Please check the argument."
fi
GS_URL_BASE_RW="${gs_url_base}/${FLAGS_rw_version}"
echo "Looking for RW part at URL: ${GS_URL_BASE_RW}"
if ! gsutil ls "${GS_URL_BASE_RW}" > /dev/null; then
die_notrace \
"${GS_URL_BASE_RW} is not a valid URL. Please check the argument."
fi
}
cleanup() {
cd "${CURRENT_DIR}"
if [[ ( -n "${TMP}" ) && ( -d "${TMP}" ) ]]; then
rm -rf "${TMP}"
fi
}
# get_ec_file_path (ro|rw): Get the full path to latest mp signed fp binary.
get_ec_file_path() {
local image_type="$1"
local version
local url
if [[ "${image_type}" == "ro" ]]; then
version="${FLAGS_ro_version}"
url="${GS_URL_BASE_RO}"
else
version="${FLAGS_rw_version}"
url="${GS_URL_BASE_RW}"
fi
# Normally there should be only one mp signed fp firmware, but in case there
# are more, sort by version.
local file_name="$(gsutil ls "${url}" \
| grep -E "chromeos_${version}_${FLAGS_board}-fp_mp(-v[0-9]+)?.bin$" \
| sort -V \
| tail -n1)"
if [[ -z "${file_name}" ]]; then
die_notrace \
"Cannot find any mp signed FP firmware for board ${FLAGS_board} at ${url}"
fi
echo "${file_name}"
}
process_ec_file() {
local ec_ro="ec_ro.bin"
local ec_rw="ec_rw.bin"
# Download the two binaries as ec_ro.bin and ec_rw.bin.
gsutil cp "$(get_ec_file_path ro)" "${ec_ro}" &> /dev/null
gsutil cp "$(get_ec_file_path rw)" "${ec_rw}" &> /dev/null
verify_mp "${ec_ro}"
verify_mp "${ec_rw}"
# Print RO and RW versions.
local fmap_frid=($(dump_fmap -p "${ec_ro}" RO_FRID))
local fmap_fwid=($(dump_fmap -p "${ec_rw}" RW_FWID))
# fmap_frid[0]="RO_FRID" fmap_frid[1]=offset fmap_frid[2]=size (decimal)
# Same for fmap_fwid.
local ro_version_string="$(dd bs=1 skip="${fmap_frid[1]}" \
count="${fmap_frid[2]}" if="${ec_ro}" 2>/dev/null; echo)"
local rw_version_string="$(dd bs=1 skip="${fmap_fwid[1]}" \
count="${fmap_fwid[2]}" if="${ec_rw}" 2>/dev/null; echo)"
echo "Using FP firmware RO version: ${ro_version_string}"
echo "Using FP firmware RW version: ${rw_version_string}"
FP_RO_VERSION_NUMBER="$(echo "${ro_version_string}" \
| grep -o -E "[0-9]+\.[0-9]+\.[0-9]+")"
FP_RW_VERSION_NUMBER="$(echo "${rw_version_string}" \
| grep -o -E "[0-9]+\.[0-9]+\.[0-9]+")"
# Use RW firmware version as file name.
local new_file="${rw_version_string}.bin"
# fmap_rw_section[0]="EC_RW"
# fmap_rw_section[1]=offset
# fmap_rw_section[2]=size (decimal)
local fmap_rw_section=($(dump_fmap -p "${ec_ro}" EC_RW))
# Inject RW into the existing RO file.
echo "Merging files..."
cp "${ec_ro}" "${new_file}"
dd if="${ec_rw}" of="${new_file}" \
bs=1 skip="${fmap_rw_section[1]}" seek="${fmap_rw_section[1]}" \
count="${fmap_rw_section[2]}" conv=notrunc &> /dev/null
# Verify the resulting image is signed properly.
echo "Verifiying output file..."
verify_mp "${new_file}"
if ! futility verify --strict "${new_file}" >&2; then
die "Cannot verify ${new_file}."
fi
echo "Merged into new binary: ${new_file}"
OUTPUT_TAR="${FLAGS_board}_fp_${FP_RW_VERSION_NUMBER}.tbz2"
tar jcf "${OUTPUT_TAR}" "${new_file}"
echo "Generating the FP firmware tarball: ${OUTPUT_TAR}"
mv "${OUTPUT_TAR}" "${CURRENT_DIR}"
}
main() {
TMP=""
trap cleanup EXIT
assert_inside_chroot
init
# Download and extract EC firmware.
process_ec_file
# Print out the update instruction.
cat <<EOF
${V_BOLD_GREEN}Successfully generated the FPMCU EC tarball with RO version \
${FP_RO_VERSION_NUMBER} and RW version ${FP_RW_VERSION_NUMBER}.
Please upload the tarball ${OUTPUT_TAR} to CPFE and update the corresponding \
ebuild.
${V_VIDOFF}
EOF
}
main "$@"