| Index: scripts/image_signing/tofactory.sh
|
| diff --git a/scripts/image_signing/tofactory.sh b/scripts/image_signing/tofactory.sh
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..38a76fdfb748d297c1082010af1365c9cd70845e
|
| --- /dev/null
|
| +++ b/scripts/image_signing/tofactory.sh
|
| @@ -0,0 +1,185 @@
|
| +#!/bin/sh
|
| +#
|
| +# Copyright (c) 2010 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 converts a Chrome OS device to a pre-factory-install state:
|
| +# * Firmware write protect disabled
|
| +# * H2O BIOS, with RO VPD area copied from the current BIOS
|
| +# * Original EC firmware
|
| +# * Blank SSD (no GPT)
|
| +#
|
| +# Minimal usage:
|
| +# tofactory.sh -b H2OBIOS.bin -e ec_shellball.sh
|
| +
|
| +SCRIPT_BASE="$(dirname "$0")"
|
| +. "$SCRIPT_BASE/common.sh"
|
| +load_shflags || exit 1
|
| +
|
| +# Constants used by DEFINE_*
|
| +VBOOT_BASE='/usr/share/vboot'
|
| +
|
| +# DEFINE_string name default_value description flag
|
| +DEFINE_string bios "" "Path of system firmware (BIOS) binary to write" "b"
|
| +DEFINE_string ec "" "Path of EC shellball to execute" "e"
|
| +DEFINE_string backup_dir "" "Path of directory in whoch to store backups" "k"
|
| +DEFINE_string asset_tag "unspecified_tag" \
|
| + "Asset tag of device, used to name backups" "a"
|
| +DEFINE_string ssd "/dev/sda" "Path to SSD / target drive" "s"
|
| +DEFINE_boolean wipe_ssd $FLAGS_TRUE "Wipe SSD after firmware updates" ""
|
| +DEFINE_boolean nothing $FLAGS_FALSE \
|
| + "Print commands but do not modify device" "n"
|
| +
|
| +# Parse command line
|
| +FLAGS "$@" || exit 1
|
| +eval set -- "$FLAGS_ARGV"
|
| +
|
| +# Globals
|
| +# ----------------------------------------------------------------------------
|
| +set -e
|
| +
|
| +# Flashrom commands with device overrides
|
| +FLASHROM_BIOS="flashrom -p internal:bus=spi"
|
| +FLASHROM_EC="flashrom -p internal:bus=lpc"
|
| +
|
| +# A log file to keep the output results of executed command
|
| +EXEC_LOG="$(make_temp_file)"
|
| +
|
| +# Temporary Work directory
|
| +WORK_DIR="$(make_temp_dir)"
|
| +OLD_BIOS="$WORK_DIR/old_bios.bin"
|
| +NEW_BIOS="$WORK_DIR/new_bios.bin"
|
| +
|
| +# Functions
|
| +# ----------------------------------------------------------------------------
|
| +
|
| +# Error message for write protect disable failure, with reminder
|
| +wp_error() {
|
| + local which_rom=$1
|
| + shift
|
| + echo "ERROR: Unable to disable $which_rom write protect: $*" 1>&2
|
| + echo "Is hardware write protect still enabled?" 1>&2
|
| + exit 1
|
| +}
|
| +
|
| +# Disable write protect for an EEPROM
|
| +disable_wp() {
|
| + local which_rom=$1 # EC or BIOS
|
| + shift
|
| + local flash_rom="$*" # Flashrom command to use
|
| +
|
| + debug_msg "Disabling $which_rom write protect"
|
| + $NOTHING ${flash_rom} --wp-disable || wp_error "$which_rom" "--wp-disable"
|
| + $NOTHING ${flash_rom} --wp-range 0 0 || wp_error "$which_rom" "--wp-range"
|
| +
|
| + # WP status bits should report WP: status: 0x00
|
| + local wp_status="$(${flash_rom} --wp-status | grep "WP: status:")"
|
| + if [ "$wp_status" != "WP: status: 0x00" ]; then
|
| + if [ "$FLAGS_nothing" = $FLAGS_FALSE ]; then
|
| + wp_error "$which_rom" "$wp_status"
|
| + fi
|
| + fi
|
| +}
|
| +
|
| +# Back up current firmware and partition table
|
| +make_backups() {
|
| + debug_msg "Backing up current firmware to $FLAGS_backup_dir"
|
| + mkdir -p "$FLAGS_backup_dir"
|
| + cp "$OLD_BIOS" "$FLAGS_backup_dir/$FLAGS_asset_tag.bios.bin"
|
| + ${FLASHROM_EC} -r "$FLAGS_backup_dir/$FLAGS_asset_tag.ec.bin"
|
| +
|
| + # Copy the VPD info from RAM, since we can't extract it as text
|
| + # from the BIOS binary. Failure of this is only a warning, since
|
| + # the information is still in the old BIOS.
|
| + mosys vpd print all > "$FLAGS_backup_dir/$FLAGS_asset_tag.vpd.txt" ||
|
| + echo "WARNING: unable to save VPD as text."
|
| +
|
| + # Copy the first part of the drive, so we can recreate the partition
|
| + # table.
|
| + local gpt_backup="$FLAGS_backup_dir/$FLAGS_asset_tag.gpt.bin"
|
| + debug_msg "Backing up current GPT table."
|
| + dd if="$FLAGS_ssd" of="$gpt_backup" bs=512 count=34
|
| +
|
| + # Add a script to restore the BIOS and GPT
|
| + local restore_script="$FLAGS_backup_dir/$FLAGS_asset_tag.restore.sh"
|
| + cat >"$restore_script" <<EOF
|
| +#!/bin/sh
|
| +echo "Restoring BIOS"
|
| +${FLASHROM_BIOS} -w "$FLAGS_asset_tag.bios.bin"
|
| +echo "Restoring EC"
|
| +${FLASHROM_EC} -w "$FLAGS_asset_tag.ec.bin"
|
| +echo "Restoring GPT"
|
| +dd of="$FLAGS_ssd" if="$FLAGS_asset_tag.gpt.bin" conv=notrunc
|
| +EOF
|
| + echo "To restore original BIOS and SSD:"
|
| + echo " cd $FLAGS_backup_dir && sh $FLAGS_asset_tag.restore.sh"
|
| +}
|
| +
|
| +# Main
|
| +# ----------------------------------------------------------------------------
|
| +
|
| +main() {
|
| + # Make sure the files we were passed exist
|
| + [ -n "$FLAGS_bios" ] || err_die "Please specify a BIOS file (-b bios.bin)"
|
| + [ -n "$FLAGS_ec" ] || err_die "Please specify an EC updater (-e updater.sh)"
|
| + ensure_files_exist "$FLAGS_bios" "$FLAGS_ec" || exit 1
|
| +
|
| + # If --nothing was specified, keep flashrom from writing
|
| + if [ "$FLAGS_nothing" = $FLAGS_TRUE ]; then
|
| + NOTHING="echo Not executing: "
|
| + fi
|
| +
|
| + # Stop update engine before calling flashrom. Multiple copies of flashrom
|
| + # interfere with each other.
|
| + debug_msg "Stopping update engine"
|
| + initctl stop update-engine
|
| +
|
| + # Read the current firmware
|
| + debug_msg "Reading BIOS from EEPROM"
|
| + ${FLASHROM_BIOS} -r "$OLD_BIOS"
|
| +
|
| + # Copy current info to the backup dir, if specified
|
| + if [ -n "$FLAGS_backup_dir" ]; then
|
| + make_backups
|
| + fi
|
| +
|
| + # Find the RO VPD area in the current firmware
|
| + local t="$(mosys -k eeprom map "$OLD_BIOS" | grep 'RO VPD')"
|
| + local vpd_offset="$(echo $t | sed 's/.*area_offset="\([^"]*\)" .*/\1/' )"
|
| + local vpd_size="$(echo $t | sed 's/.*area_size="\([^"]*\)" .*/\1/' )"
|
| + debug_msg "Found VPD at offset $vpd_offset size $vpd_size"
|
| + # Convert offset and size to decimal, since dd doesn't grok hex
|
| + vpd_offset="$(printf "%d" $vpd_offset)"
|
| + vpd_size="$(printf "%d" $vpd_size)"
|
| + debug_msg "In decimal, VPD is at offset $vpd_offset size $vpd_size"
|
| +
|
| + # Copy the RO VPD from the old firmware to the new firmware
|
| + debug_msg "Copying VPD from old firmware to new firmware"
|
| + cp "$FLAGS_bios" "$NEW_BIOS"
|
| + dd bs=1 seek=$vpd_offset skip=$vpd_offset count=$vpd_size conv=notrunc \
|
| + if="$OLD_BIOS" of="$NEW_BIOS" || err_die "Unable to copy RO VPD"
|
| +
|
| + # Disable write protect
|
| + disable_wp "EC" ${FLASHROM_EC}
|
| + disable_wp "BIOS" ${FLASHROM_BIOS}
|
| +
|
| + # Write new firmware
|
| + debug_msg "Writing EC"
|
| + # TODO: if EC file ends in .bin, use flashrom to write it directly?
|
| + $NOTHING sh "$FLAGS_ec" --factory || err_die "Unable to write EC"
|
| + debug_msg "Writing BIOS"
|
| + $NOTHING ${FLASHROM_BIOS} -w "$NEW_BIOS" || err_die "Unable to write BIOS"
|
| +
|
| + # Wipe SSD
|
| + if [ "$FLAGS_wipe_ssd" = $FLAGS_TRUE ]; then
|
| + debug_msg "Wiping SSD"
|
| + $NOTHING cgpt create -z "$FLAGS_ssd" || err_die "Unable to wipe SSD"
|
| + fi
|
| +
|
| + # Leave the update engine stopped. We've mucked with the firmware
|
| + # and SSD contents, so we shouldn't be attempting an autoupdate this
|
| + # boot anyway.
|
| +}
|
| +
|
| +main
|
|
|