Create new cros_write_firmware tool based on write_tegra_bios.

This tool uses U-Boot instead of the binary bootloader.bin to
do the actual flashing of the boot device.  This gives us more
control over the firmware flashing process.  In particular,
U-Boot has SPI support that we can customize, which allows
us to write a chromium firmware image directly to SPI.

BUG=chromium-os:11981
TEST=Build and boot from SPI U-Boot/kernel/ChromiumOS on Kaen

Change-Id: I37f6b3d00b23bec0e79da2282b2f0e75fce76900

This CL depends on:
 http://codereview.chromium.org/6606011/
 http://codereview.chromium.org/6609003/
 http://codereview.chromium.org/6609004/

Review URL: http://codereview.chromium.org/6594134
diff --git a/host/cros_write_firmware b/host/cros_write_firmware
new file mode 100755
index 0000000..ff93af8
--- /dev/null
+++ b/host/cros_write_firmware
@@ -0,0 +1,173 @@
+#!/bin/bash
+
+# Copyright (c) 2011 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 utility writes a firmware image to a tegra based board.
+
+# Include common CrOS utilities.
+. "/usr/lib/crosutils/common.sh"
+
+get_default_board
+
+# Command line options
+DEFINE_string board "${DEFAULT_BOARD}" "The name of the board to flash."
+DEFINE_string variant "" "Board variant."
+DEFINE_string firmware "" "Path to firmware image to write."
+DEFINE_string flasher "" "Path to flasher image to use."
+DEFINE_string bct "" "Path to bct image to write."
+DEFINE_string map "" "Path to System.map file to read for load address."
+DEFINE_string flash "" "Boot flash parameter file."
+DEFINE_string config "" "Directory for temporary configuration files."
+DEFINE_boolean sign $FLAGS_FALSE "Sign and append a BCT to the firmware image."
+
+# Parse command line.
+FLAGS "$@" || exit 1
+eval set -- "${FLAGS_ARGV}"
+
+# Die on errors.
+set -e
+
+CROS_LOG_PREFIX="cros_write_firmware"
+
+if [ -z "${FLAGS_board}" ]; then
+  error "--board required."
+  exit 1
+fi
+
+get_board_and_variant $FLAGS_board $FLAGS_variant
+
+# Display the U-Boot version string.
+function show_u_boot_info() {
+  local firmware=$1
+  local header=$(strings "${firmware}" | grep "U-Boot" | head -1 )
+
+  info "Using ${header}"
+}
+
+# Given two values in decimal format return the first value rounded up to a
+# multiple of the second value.  The second value must be a power of two.
+function round() {
+  awk "BEGIN { print and(($1 + $2 - 1), compl($2 - 1)) }"
+}
+
+# Given a value in decimal format return that value converted to hexidecimal
+# and formatted as 0xXXXXXXXX.
+function to_hex() {
+  awk "BEGIN { printf \"0x%x\", $1 }"
+}
+
+# Create the flashing script.  This script will be loaded and run by the flasher
+# build of U-Boot.  Most of the script is constant, we just need to append the
+# sizes and address of the payload.
+#
+# TODO(robotboy): Compute the address from the text_base (0xe08000) +
+# flasher image size (0x40000) + script block (0x1000)
+function make_flashing_script() {
+  local firmware=$1
+  local firmware_size=$(stat -c"%s" "${firmware}")
+
+  echo "setenv address       0xe49000"
+  echo "setenv firmware_size $(to_hex ${firmware_size})"
+  echo "setenv length        $(to_hex $(round ${firmware_size} 4096))"
+
+  cat /usr/share/cros_write_firmware/spi.script
+}
+
+# Parse the System.map file generated by the U-Boot build to get the entry
+# point address.
+function get_text_base() {
+  local map=$1
+
+  grep -m1 -E "^[0-9a-fA-F]{8} T _start$" ${map} | cut -d " " -f 1
+}
+
+###############################################################################
+
+u_boot="/build/${BOARD_VARIANT}/u-boot"
+
+# Generate default values for the firmware, flasher, BCT, map and flash config
+# file paths from the board and variant information provided.
+firmware=${FLAGS_firmware:-"${u_boot}/image.bin"}
+flasher=${FLAGS_flasher:-"${u_boot}/u-boot-flasher.bin"}
+bct=${FLAGS_bct:-"${u_boot}/board.bct"}
+map=${FLAGS_map:-"${u_boot}/System.map"}
+flash=${FLAGS_flash:-"${u_boot}/flash.cfg"}
+
+# Extract the load and entry point for U-Boot.
+text_base="0x$(get_text_base "${map}")"
+
+# Verify that all of the files and tools we will need are present.
+check_for_file "firmware" " " "${firmware}"
+check_for_file "flasher" "  " "${flasher}"
+check_for_file "BCT" "      " "${bct}"
+check_for_file "map" "      " "${map}"
+check_for_file "flash" "    " "${flash}"
+
+check_for_tool "nvflash" "nvflash"
+
+show_u_boot_info "${firmware}"
+
+# If the user has not specified a config directory then create one on the fly
+# and remove it when we are done.
+if [ -z "${FLAGS_config}" ]; then
+  config=$(mktemp -d)
+
+  trap "rm -rf ${config}" EXIT
+else
+  mkdir -p "${FLAGS_config}"
+
+  config=${FLAGS_config}
+fi
+
+# Optionally sign the firmware.  This is usefull if you want to write a bare
+# U-Boot to SPI and boot with that instead of a fully build ChromiumOS firmware
+# image.
+if [ $FLAGS_sign -eq $FLAGS_TRUE ]; then
+  signed_firmware=${config}/signed.bin
+
+  cros_sign_bootstub \
+    --bct "${bct}" \
+    --flash "${flash}" \
+    --bootstub "${firmware}" \
+    --output "${signed_firmware}" \
+    --config "${config}" \
+    --text_base "${text_base}"
+else
+  signed_firmware=${firmware}
+fi
+
+# Create the flashing script and turn it into a U-Boot uImage.
+make_flashing_script "${signed_firmware}" > ${config}/script
+
+mkimage -A arm -T script -d ${config}/script ${config}/script.uimg > /dev/null
+
+# Construct RAM image of flasher + script + firmware.  The firmware should
+# already be signed by cbootimage.  The RAM image has a fixed 256K partition
+# for the flasher, followed by the script and payload to be written.
+dd if="${flasher}"            of="${config}/image"          &> /dev/null
+dd if="${config}/script.uimg" of="${config}/image" seek=512 &> /dev/null
+dd if="${signed_firmware}"    of="${config}/image" seek=520 &> /dev/null
+
+# Write the RAM image image to the board.  The flasher will write the payload
+# into the boot device.  The warning below about the failure is due to the
+# way that we are using nvflash.  It expects to be able to talk to the flashing
+# bootloader that is passed down, but U-Boot doesn't talk back the way
+# bootloader.bin did, and nvflash complains.
+sudo nvflash \
+  --configfile /usr/share/cros_write_firmware/nvflash-spi.cfg \
+  --bct "${bct}" \
+  --setbct \
+  --bl "${config}/image" \
+  --go \
+  --setentry "${text_base}" "${text_base}" ||
+  warn "The above 'command failure: go failed' can be ignored."
+
+# TODO(robotboy): Make a U-Boot tool that can compute the same checksum on
+# the host and display it here.  Unfortunately U-Boot uses a slightly different
+# crc32 than zlib, so it's not possible to use zlib's crc32 to do this.  It has
+# to be done by building a tool that uses U-Boots version.
+info "The serial terminal or LCD panel should show before and after CRCs of"
+info "the image written to the boot flash.  If these values match each other"
+info "your flash was probably successful."
diff --git a/host/share/cros_write_firmware/nvflash-spi.cfg b/host/share/cros_write_firmware/nvflash-spi.cfg
new file mode 100644
index 0000000..428cf5e
--- /dev/null
+++ b/host/share/cros_write_firmware/nvflash-spi.cfg
@@ -0,0 +1,22 @@
+# A dummy nvflash config file to make nvflash happy.  Without this
+# file it ignores the BCT passed on the command line and will fail to flash
+# a device with an invalid or missing BCT on the currently selected boot
+# flash.
+#
+# TODO(robotboy): Remove this dummy file once nvflash no longer needs it.
+
+[device]
+type=spi
+instance=0
+
+[partition]
+name=BCT
+id=2
+type=boot_config_table
+allocation_policy=sequential
+filesystem_type=basic
+size=4096
+file_system_attribute=0
+partition_attribute=0
+allocation_attribute=8
+percent_reserved=0
diff --git a/host/share/cros_write_firmware/spi.script b/host/share/cros_write_firmware/spi.script
new file mode 100644
index 0000000..6745d09
--- /dev/null
+++ b/host/share/cros_write_firmware/spi.script
@@ -0,0 +1,16 @@
+setenv _crc    'crc32 ${address} ${firmware_size}'
+setenv _init   'echo Initing SPI;  sf probe            0'
+setenv _erase  'echo Erasing SPI;  sf erase            0 ${length}'
+setenv _write  'echo Writing SPI;  sf write ${address} 0 ${length}'
+setenv _clear  'echo Clearing RAM; mw.b     ${address} 0 ${length}'
+setenv _read   'echo Reading SPI;  sf read  ${address} 0 ${length}'
+
+run _crc
+run _init
+run _erase
+run _write
+run _clear
+run _read
+run _crc
+
+echo If the 2 CRCs above are equal, flash was successful