blob: 84256f6c2262467b5a7d66cfee6c23d9e73d7a28 [file] [log] [blame]
#!/bin/sh
# Copyright 2017 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# This script is expected to run by update_engine on each reboot (usually after
# 60s) via chromeos-setgoodkernel. Same as chromeos-setgoodkernel, this script
# will mark active firmware as the "good one".
# For vboot1 systems always taking RW_SECTION_A as default firmware, this must
# be done by "cloning active to the other RW section".
# For vboot2 systems, just set fw_result to success and zero fw_try_count.
COMPLETE_EVENT="chromeos-setgoodfirmware"
BOARD_SCRIPT="/usr/sbin/board-setgoodfirmware"
# Prints arguments as error messages and aborts.
# Usage: die <messages>
die() {
echo "ERROR: $0: $*" >&2
exit 1
}
info() {
echo "INFO: $0: $*"
}
# Clones an AP firmware slot to another one using flashrom.
# Usage: clone_firmware <from_slot> <to_slot>
clone_firmware() {
local from="$1" to="$2"
local image rw_section
image="$(mktemp)"
rw_section="$(mktemp)"
# shellcheck disable=SC2064
trap "rm -f ${image} ${rw_section}" EXIT
echo "Cloning firmware ${from} to ${to}..."
flashrom -p host -r "${image}" -i FMAP \
-i "RW_SECTION_${from}:${rw_section}" 2>&1 || \
die "Fail to read RW firmware slot ${from}."
flashrom -p host -w "${image}" --noverify \
-i "RW_SECTION_${to}:${rw_section}" 2>&1 || \
die "Fail to write RW firmware slot ${to}."
# The main script may do "exec ${BOARD_SCRIPT} so trap of EXIT may not work
# outside this function.
trap - EXIT
rm -f "${image}" "${rw_section}"
}
# Checks if the system has EC. crbug.com/733014: `crossystem ecfw_act` will
# return 'RO' on x86 Chromeboxes so we have to check EC availability again
# before starting the update plan.
has_ec() {
mosys ec info -s name >/dev/null 2>&1
}
# Clones "good" (active) firmware to other slot.
# Usage: clone_good_firmware
clone_good_firmware() {
local mainfw_act
mainfw_act="$(crossystem mainfw_act)"
case "${mainfw_act}" in
A)
clone_firmware A B
;;
B)
clone_firmware B A
;;
*)
die "Abnormal active firmware: ${mainfw_act}."
;;
esac
if [ "$(crossystem ecfw_act || true)" = "RO" ] && has_ec; then
# TODO(hungte) We need to handle one special case in future: user boot with
# recovery button pressed and then never hard-reset device, and then EC will
# always be in RO until we rewrite the EC firmware (i.e., next startup
# update).
echo "EC was boot by RO and may need an update/recovery."
crossystem fwupdate_tries=6
fi
}
# Notifies Upstart jobs that we have finished setting a good firmware.
# Usage: emit_complete_event
emit_complete_event() {
initctl emit -n "${COMPLETE_EVENT}" || true
}
# Main entry.
main() {
case "$(crossystem fw_vboot2)" in
1)
crossystem fw_result=success fw_try_count=0 ||
die "Fail to set good kernel with vboot2 firmware."
emit_complete_event
info "Active vboot2 firmware set as good firmware."
;;
0)
# Vboot1, copy main firmware to the spare slot.
clone_good_firmware
crossystem fwb_tries=0
emit_complete_event
info "Active vboot1 firmware set as good firmware."
;;
*)
die "Unknown vboot firmware type."
;;
esac
if [ -x "${BOARD_SCRIPT}" ]; then
info "Running board script ${BOARD_SCRIPT}..."
exec "${BOARD_SCRIPT}"
fi
}
main "$@"