diff options
author | Randall Spangler <rspangler@chromium.org> | 2011-01-04 16:42:08 -0800 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2011-01-04 16:42:08 -0800 |
commit | e37ff5d5960c3a94809f54d7e412b387a7c396e5 (patch) | |
tree | 73529f01a4ef21a0473a3a779650bbcf0f0be222 /scripts | |
parent | ddc06e4be12392d1f9d6b0d6d7c9c16446cb5566 (diff) | |
download | vboot-e37ff5d5960c3a94809f54d7e412b387a7c396e5.tar.gz |
Check in tofactory script.
Also refactor the other scripts to move more common functions (debug output, etc.) to common.sh.
BUG=chrome-os-partner:1903
TEST=manual; ran on a Chrome notebook, verified the right things got copied.
Review URL: http://codereview.chromium.org/5878005
Change-Id: Ib7131356ecb6f88eee3d529a518f23b94756d0c0
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/image_signing/common.sh | 147 | ||||
-rwxr-xr-x | scripts/image_signing/make_dev_firmware.sh | 18 | ||||
-rwxr-xr-x | scripts/image_signing/make_dev_ssd.sh | 18 | ||||
-rwxr-xr-x | scripts/image_signing/tofactory.sh | 185 |
4 files changed, 279 insertions, 89 deletions
diff --git a/scripts/image_signing/common.sh b/scripts/image_signing/common.sh index 5465feb8..1566b9d3 100755 --- a/scripts/image_signing/common.sh +++ b/scripts/image_signing/common.sh @@ -4,6 +4,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +# Globals +# ---------------------------------------------------------------------------- + # Determine script directory SCRIPT_DIR=$(dirname $0) PROG=$(basename $0) @@ -94,11 +97,81 @@ load_shflags() { echo "ERROR: Cannot find the required shflags library." return 1 fi + + # Add debug option for debug output below + DEFINE_boolean debug $FLAGS_FALSE "Provide debug messages" "d" +} + +# Functions for debug output +# ---------------------------------------------------------------------------- + +# Reports error message and exit(1) +# Args: error message +err_die() { + echo "ERROR: $*" 1>&2 + exit 1 +} + +# Returns true if we're running in debug mode. +# +# Note that if you don't set up shflags by calling load_shflags(), you +# must set $FLAGS_debug and $FLAGS_TRUE yourself. The default +# behavior is that debug will be off if you define neither $FLAGS_TRUE +# nor $FLAGS_debug. +is_debug_mode() { + [ "${FLAGS_debug:-not$FLAGS_TRUE}" = "$FLAGS_TRUE" ] +} + +# Prints messages (in parameters) in debug mode +# Args: debug message +debug_msg() { + if is_debug_mode; then + echo "DEBUG: $*" 1>&2 + fi +} + +# Functions for temporary files and directories +# ---------------------------------------------------------------------------- + +# Create a new temporary file and return its name. +# File is automatically cleaned when cleanup_temps_and_mounts() is called. +make_temp_file() { + local tempfile=$(mktemp) + echo "$tempfile" >> $TEMP_FILE_LIST + echo $tempfile +} + +# Create a new temporary directory and return its name. +# Directory is automatically deleted and any filesystem mounted on it unmounted +# when cleanup_temps_and_mounts() is called. +make_temp_dir() { + local tempdir=$(mktemp -d) + echo "$tempdir" >> $TEMP_DIR_LIST + echo $tempdir } -# List of Temporary files and mount points. -TEMP_FILE_LIST=$(mktemp) -TEMP_DIR_LIST=$(mktemp) +cleanup_temps_and_mounts() { + for i in $(cat $TEMP_FILE_LIST); do + rm -f $i + done + set +e # umount may fail for unmounted directories + for i in $(cat $TEMP_DIR_LIST); do + if [ -n "$i" ]; then + if has_needs_to_be_resigned_tag "$i"; then + echo "Warning: image may be modified. Please resign image." + fi + sudo umount -d $i 2>/dev/null + rm -rf $i + fi + done + set -e + rm -rf $TEMP_DIR_LIST $TEMP_FILE_LIST +} + +trap "cleanup_temps_and_mounts" EXIT + +# Functions for partition management +# ---------------------------------------------------------------------------- # Read GPT table to find the starting location of a specific partition. # Args: DEVICE PARTNUM @@ -185,54 +258,6 @@ replace_image_partition() { dd if=$input_file of=$image bs=512 seek=$offset count=$size conv=notrunc } -# Create a new temporary file and return its name. -# File is automatically cleaned when cleanup_temps_and_mounts() is called. -make_temp_file() { - local tempfile=$(mktemp) - echo "$tempfile" >> $TEMP_FILE_LIST - echo $tempfile -} - -# Create a new temporary directory and return its name. -# Directory is automatically deleted and any filesystem mounted on it unmounted -# when cleanup_temps_and_mounts() is called. -make_temp_dir() { - local tempdir=$(mktemp -d) - echo "$tempdir" >> $TEMP_DIR_LIST - echo $tempdir -} - -cleanup_temps_and_mounts() { - for i in "$(cat $TEMP_FILE_LIST)"; do - rm -f $i - done - set +e # umount may fail for unmounted directories - for i in "$(cat $TEMP_DIR_LIST)"; do - if [ -n "$i" ]; then - if has_needs_to_be_resigned_tag "$i"; then - echo "Warning: image may be modified. Please resign image." - fi - sudo umount -d $i 2>/dev/null - rm -rf $i - fi - done - set -e - rm -rf $TEMP_DIR_LIST $TEMP_FILE_LIST -} - -# Returns true if all files in parameters exist. -ensure_files_exist() { - local filename return_value=0 - for filename in "$@"; do - if [ ! -f "$filename" -a ! -b "$filename" ]; then - echo "ERROR: Cannot find required file: $filename" - return_value=1 - fi - done - - return $return_value -} - # For details, see crosutils.git/common.sh enable_rw_mount() { local rootfs="$1" @@ -307,8 +332,25 @@ rw_mount_disabled() { return 1 } +# Misc functions +# ---------------------------------------------------------------------------- + +# Returns true if all files in parameters exist. +# Args: List of files +ensure_files_exist() { + local filename return_value=0 + for filename in "$@"; do + if [ ! -f "$filename" -a ! -b "$filename" ]; then + echo "ERROR: Cannot find required file: $filename" + return_value=1 + fi + done + + return $return_value +} + # Check if the 'chronos' user already has a password -# ARGS: rootfs +# Args: rootfs no_chronos_password() { local rootfs=$1 sudo grep -q '^chronos:\*:' "$rootfs/etc/shadow" @@ -317,4 +359,3 @@ no_chronos_password() { trap "cleanup" INT TERM EXIT add_cleanup_action "cleanup_temps_and_mounts" - diff --git a/scripts/image_signing/make_dev_firmware.sh b/scripts/image_signing/make_dev_firmware.sh index f4e7d49d..f432c0bd 100755 --- a/scripts/image_signing/make_dev_firmware.sh +++ b/scripts/image_signing/make_dev_firmware.sh @@ -26,7 +26,6 @@ DEFINE_boolean force_backup \ $FLAGS_TRUE "Create backup even if source is not live" "" DEFINE_string backup_dir \ "$DEFAULT_BACKUP_FOLDER" "Path of directory to store firmware backups" "" -DEFINE_boolean debug $FLAGS_FALSE "Provide debug messages" "d" # Parse command line FLAGS "$@" || exit 1 @@ -44,23 +43,6 @@ EXEC_LOG="$(make_temp_file)" # Functions # ---------------------------------------------------------------------------- -# Reports error message and exit(1) -err_die() { - echo "ERROR: $*" 1>&2 - exit 1 -} - -# Returns true if we're running in debug mode -is_debug_mode() { - [ "$FLAGS_debug" = $FLAGS_TRUE ] -} - -# Prints messages (in parameters) in debug mode -debug_msg() { - if is_debug_mode; then - echo "DEBUG: $*" 1>&2 - fi -} # Reads $IMAGE from $FLAGS_from read_image() { diff --git a/scripts/image_signing/make_dev_ssd.sh b/scripts/image_signing/make_dev_ssd.sh index ee493e7a..67a180e7 100755 --- a/scripts/image_signing/make_dev_ssd.sh +++ b/scripts/image_signing/make_dev_ssd.sh @@ -24,7 +24,6 @@ DEFINE_boolean remove_rootfs_verification \ $FLAGS_FALSE "Modify kernel boot config to disable rootfs verification" "" DEFINE_string backup_dir \ "$DEFAULT_BACKUP_FOLDER" "Path of directory to store kernel backups" "" -DEFINE_boolean debug $FLAGS_FALSE "Provide debug messages" "d" DEFINE_string save_config "" \ "Base filename to store kernel configs to, instead of resigning." "" DEFINE_string set_config "" \ @@ -45,23 +44,6 @@ EXEC_LOG="$(make_temp_file)" # Functions # ---------------------------------------------------------------------------- -# Reports error message and exit(1) -err_die() { - echo "ERROR: $*" 1>&2 - exit 1 -} - -# Returns true if we're running in debug mode -is_debug_mode() { - [ "$FLAGS_debug" = $FLAGS_TRUE ] -} - -# Prints messages (in parameters) in debug mode -debug_msg() { - if is_debug_mode; then - echo "DEBUG: $*" 1>&2 - fi -} # Removes rootfs verification from kernel boot parameter remove_rootfs_verification() { diff --git a/scripts/image_signing/tofactory.sh b/scripts/image_signing/tofactory.sh new file mode 100755 index 00000000..38a76fdf --- /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 |