OLD | NEW |
(Empty) | |
| 1 #!/bin/sh |
| 2 # |
| 3 # Copyright (C) 2010 Google Inc. |
| 4 # Written by David Hendricks for Google Inc. |
| 5 # |
| 6 # This program is free software; you can redistribute it and/or modify |
| 7 # it under the terms of the GNU General Public License as published by |
| 8 # the Free Software Foundation; either version 2 of the License, or |
| 9 # (at your option) any later version. |
| 10 # |
| 11 # This program is distributed in the hope that it will be useful, |
| 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 # GNU General Public License for more details. |
| 15 # |
| 16 # You should have received a copy of the GNU General Public License |
| 17 # along with this program; if not, write to the Free Software |
| 18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 19 # |
| 20 # ec.sh: This will attempt to stress partial write capabilities for EC firmware |
| 21 # ROMs. There are two major parts to the test: |
| 22 # 1. Write an alternative firmware image to the "fw" region specified in a |
| 23 # layout file. |
| 24 # 2. Stress partial writes using a known pattern in an unused region of the |
| 25 # EC firmware ROM with 128KB of space. |
| 26 # |
| 27 # REQUIRED ENVIRONMENT VARIABLES |
| 28 # ------------------------------ |
| 29 # Due to the way the test framework copies tests to a temporary location, the |
| 30 # environment variables must specify absolute paths to files they reference. |
| 31 # |
| 32 # $ALT_EC_IMAGE -- Required environment variable |
| 33 # This script requires an alternative EC firmware. Most ECs actively read code |
| 34 # and data from the firmware ROM during run-time. An example of an EC firmware |
| 35 # update process for supported ECs: |
| 36 # 1. Enter update mode -- Copy relevant code and data to internal RAM |
| 37 # 2. Enable programming interface |
| 38 # 3. When host is done programming ROM, issue "exit update mode" |
| 39 # 4. Re-load code/data from ROM. |
| 40 # |
| 41 # Step 4 can cause failure if we attempt to test using patterns. Instead, we |
| 42 # must provide the EC with usable code. For blackbox testing, this essentially |
| 43 # means replacing the current firmware image with a different image which still |
| 44 # works. |
| 45 # |
| 46 # $LAYOUT_FILE -- Another required environment variable |
| 47 # A layout file is required for two reasons: |
| 48 # 1. We need a way of knowing which regions are safe to leave in a clobbered |
| 49 # state after exiting flash update mode. They will be labeled "unused". |
| 50 # 2. We need a way of knowing where the EC firmware resides since some ECs |
| 51 # boot from bottom of ROM and others from top of ROM. This will be the |
| 52 # region labeled "fw" |
| 53 # |
| 54 # The following example is for a 1MB ROM with 128KB occupied by EC firmware. |
| 55 # The EC in this example loads firmware from the lowest address. |
| 56 # 0x000000 0x01ffff fw |
| 57 # 0x020000 0x0fffff unused |
| 58 |
| 59 LOGFILE="${0}.log" |
| 60 ZERO_4K="00_4k.bin" |
| 61 FF_4K="ff_4k.bin" |
| 62 FF_4K_TEXT="ff_4k.txt" |
| 63 NUM_REGIONS=16 |
| 64 |
| 65 TESTFILE="test.bin" |
| 66 |
| 67 partial_writes_ec_fail() |
| 68 { |
| 69 echo "$1" >> ${LOGFILE} |
| 70 echo "$0: failed" >> ${LOGFILE} |
| 71 exit ${EXIT_FAILURE} |
| 72 } |
| 73 |
| 74 which uuencode > /dev/null |
| 75 if [ "$?" != "0" ] ; then |
| 76 partial_writes_ec_fail "uuencode is required to use this script" |
| 77 fi |
| 78 |
| 79 # FIXME: This is a chromium os -ism. Most distros don't strip out "diff". |
| 80 which diff > /dev/null |
| 81 if [ "$?" != "0" ] ; then |
| 82 partial_writes_ec_fail "diff is required to use this script" |
| 83 fi |
| 84 |
| 85 # FIXME: extra chromium os paranoia |
| 86 which printf > /dev/null |
| 87 if [ "$?" != "0" ] ; then |
| 88 partial_writes_ec_fail "printf is required to use this script" |
| 89 fi |
| 90 |
| 91 echo "User-provided \$ALT_EC_IMAGE: ${ALT_EC_IMAGE}" >> ${LOGFILE} |
| 92 if [ -z "$ALT_EC_IMAGE" ] || [ ! -e "$ALT_EC_IMAGE" ]; then |
| 93 partial_writes_ec_fail "Please provide absolute path to alternate EC fir
mware image using the ALT_EC_IMAGE environment variable." |
| 94 fi |
| 95 |
| 96 echo "User-provided \$LAYOUT_FILE: ${LAYOUT_FILE}" >> ${LOGFILE} |
| 97 if [ -z "$LAYOUT_FILE" ] || [ ! -e "$LAYOUT_FILE" ]; then |
| 98 partial_writes_ec_fail "Please provide absolute path to layout file usin
g the LAYOUT_FILE environment variable" |
| 99 fi |
| 100 |
| 101 # |
| 102 # Part 1: Write an alternate firmware image to the "fw" region in EC flash |
| 103 # |
| 104 |
| 105 ./flashrom ${FLASHROM_PARAM} -l ${LAYOUT_FILE} -i fw -w "${ALT_EC_IMAGE}" 2> /de
v/null |
| 106 if [ $? -ne 0 ]; then |
| 107 partial_writes_ec_fail "Failed to write alternate EC firmware" >> ${LOGF
ILE} |
| 108 else |
| 109 echo "Wrote alternate EC firmware image successfully" >> ${LOGFILE} |
| 110 fi |
| 111 |
| 112 # Restore original firmware region |
| 113 ./flashrom ${FLASHROM_PARAM} -l ${LAYOUT_FILE} -i fw -w "${BACKUP}" 2> /dev/null |
| 114 if [ $? -ne 0 ]; then |
| 115 partial_writes_ec_fail "Failed to restore original EC firmware" >> ${LOG
FILE} |
| 116 else |
| 117 echo "Restored original firmware image successfully" >> ${LOGFILE} |
| 118 fi |
| 119 |
| 120 # |
| 121 # Part 2: Write a pattern to an "unused" region in EC flash |
| 122 # |
| 123 |
| 124 ranges=$(awk '{ if ( $2 == "unused" ) print $1 }' "${LAYOUT_FILE}") |
| 125 range_found=0 |
| 126 for range in $ranges; do |
| 127 start=$(echo $range | awk -F":" '{ print $1 }') |
| 128 end=$(echo $range | awk -F":" '{ print $2 }') |
| 129 len=$((${end} - ${start})) |
| 130 |
| 131 echo "Testing if range is usable: ${start}:${end}, len=${len}" >> ${LOGF
ILE} |
| 132 if [ ${len} -lt $(($((${NUM_REGIONS} - 1)) * 4096)) ]; then |
| 133 continue |
| 134 else |
| 135 range_found=1 |
| 136 break |
| 137 fi |
| 138 done |
| 139 |
| 140 if [ $range_found -ne 1 ]; then |
| 141 partial_writes_ec_fail "No suitable unused range found" |
| 142 else |
| 143 echo "Found usable range: ${start}:${end}, len=${len}" |
| 144 fi |
| 145 |
| 146 # Make 4k worth of 0xff bytes |
| 147 echo "begin 640 $FF_4K" > "$FF_4K_TEXT" |
| 148 i=0 |
| 149 while [ $i -le 90 ]; do |
| 150 echo "M____________________________________________________________" >>
"$FF_4K_TEXT" |
| 151 i=$((${i} + 1)) |
| 152 done |
| 153 echo "!_P``" >> "$FF_4K_TEXT" |
| 154 echo "\`" >> "$FF_4K_TEXT" |
| 155 echo "end" >> "$FF_4K_TEXT" |
| 156 uudecode -o "$FF_4K" "$FF_4K_TEXT" |
| 157 rm -f "$FF_4K_TEXT" |
| 158 |
| 159 # Make 4k worth of 0x00 bytes |
| 160 dd if=/dev/zero of="$ZERO_4K" bs=1 count=4096 2> /dev/null |
| 161 echo "ffh pattern written in ${FF_4K}" |
| 162 echo "00h pattern written in ${ZERO_4K}" |
| 163 |
| 164 # Actual tests are performed below. |
| 165 # |
| 166 |
| 167 # Make a layout - 4K regions on 4K boundaries. This will test basic |
| 168 # functionality of erasing and writing specific blocks. |
| 169 for i in `seq 0 $((${NUM_REGIONS} - 1))` ; do |
| 170 offset_00=$((${i} * 8192)) |
| 171 offset_ff=$((${i} * 8192 + 4096)) |
| 172 echo "\ |
| 173 `printf 0x%x $((${start} + ${offset_00}))`:`printf 0x%x $((${start} + ${offset_0
0} + 0xfff))` 00_${i} |
| 174 `printf 0x%x $((${start} + ${offset_ff}))`:`printf 0x%x $((${start} + ${offset_f
f} + 0xfff))` ff_${i} |
| 175 " >> layout_ec_4k_aligned.txt |
| 176 done |
| 177 |
| 178 cp "${BACKUP}" "$TESTFILE" |
| 179 i=0 |
| 180 while [ $i -lt $NUM_REGIONS ] ; do |
| 181 tmpstr="aligned region ${i} test: " |
| 182 offset=$((${start} + $((${i} * 8192)))) |
| 183 dd if=${ZERO_4K} of=${TESTFILE} bs=1 conv=notrunc seek=${offset} 2> /dev
/null |
| 184 dd if=${FF_4K} of=${TESTFILE} bs=1 conv=notrunc seek=$((${offset} + 4096
)) 2> /dev/null |
| 185 |
| 186 ./flashrom ${FLASHROM_PARAM} -l layout_ec_4k_aligned.txt -i 00_${i} -i f
f_${i} -w "$TESTFILE" 2> /dev/null |
| 187 if [ "$?" != "0" ] ; then |
| 188 partial_writes_ec_fail "${tmpstr}failed to flash" |
| 189 fi |
| 190 |
| 191 # download the entire ROM image and use diff to compare to ensure |
| 192 # flashrom logic does not violate user-specified regions |
| 193 flashrom ${FLASHROM_PARAM} -r difftest.bin 2> /dev/null |
| 194 diff -q difftest.bin "$TESTFILE" |
| 195 if [ "$?" != "0" ] ; then |
| 196 partial_writes_ec_fail "${tmpstr}failed diff test" |
| 197 fi |
| 198 rm -f difftest.bin |
| 199 |
| 200 i=$((${i} + 1)) |
| 201 echo "${tmpstr}passed" >> ${LOGFILE} |
| 202 done |
| 203 |
| 204 # Make a layout - 4K regions on 4.5K boundaries. This will help find problems |
| 205 # with logic that only operates on part of a block. For example, if a user |
| 206 # wishes to re-write a fraction of a block, then: |
| 207 # 1. The whole block must be erased. |
| 208 # 2. The old content must be restored at unspecified offsets. |
| 209 # 3. The new content must be written at specified offsets. |
| 210 # |
| 211 # Note: The last chunk of 0xff bytes is too long, so special logic was added to |
| 212 # below to avoid overrunning a 128KB test region. |
| 213 # |
| 214 for i in `seq 0 $((${NUM_REGIONS} - 1))` ; do |
| 215 offset_00=$((${i} * 8192 + 2048)) |
| 216 offset_ff=$((${i} * 8192 + 4096 + 2048)) |
| 217 echo "\ |
| 218 `printf 0x%06x $((${start} + ${offset_00}))`:`printf 0x%06x $((${start} + ${offs
et_00} + 0xfff))` 00_${i} |
| 219 `printf 0x%06x $((${start} + ${offset_ff}))`:`printf 0x%06x $((${start} + ${offs
et_ff} + 0xfff))` ff_${i} |
| 220 " >> layout_ec_unaligned.txt |
| 221 done |
| 222 |
| 223 # reset the test file and ROM to the original state |
| 224 flashrom ${FLASHROM_PARAM} -w "${BACKUP}" > /dev/null |
| 225 cp "$BACKUP" "$TESTFILE" |
| 226 |
| 227 i=0 |
| 228 while [ $i -lt $NUM_REGIONS ] ; do |
| 229 tmpstr="unaligned region ${i} test: " |
| 230 offset=$(($((${i} * 8192)) + 2048)) |
| 231 |
| 232 # Protect against too long write |
| 233 writelen=4096 |
| 234 if [ $((${offset} + 4096 + 4096)) -ge 131072 ]; then |
| 235 writelen=$((131072 - $((${offset} + 4096)))) |
| 236 if [ ${writelen} -lt 0 ]; then |
| 237 writelen=0 |
| 238 fi |
| 239 fi |
| 240 |
| 241 dd if=${ZERO_4K} of=${TESTFILE} bs=1 conv=notrunc seek=$((${start} + ${o
ffset})) 2> /dev/null |
| 242 dd if=${FF_4K} of=${TESTFILE} bs=1 conv=notrunc seek=$((${start} + ${off
set} + 4096)) count=writelen 2> /dev/null |
| 243 |
| 244 ./flashrom ${FLASHROM_PARAM} -l layout_ec_unaligned.txt -i 00_${i} -i ff
_${i} -w "$TESTFILE" 2> /dev/null |
| 245 if [ "$?" != "0" ] ; then |
| 246 partial_writes_ec_fail "${tmpstr}failed to flash region" |
| 247 fi |
| 248 |
| 249 # download the entire ROM image and use diff to compare to ensure |
| 250 # flashrom logic does not violate user-specified regions |
| 251 flashrom ${FLASHROM_PARAM} -r difftest.bin 2> /dev/null |
| 252 diff -q difftest.bin "$TESTFILE" |
| 253 if [ "$?" != "0" ] ; then |
| 254 partial_writes_ec_fail "${tmpstr}failed diff test" |
| 255 fi |
| 256 rm -f difftest.bin |
| 257 |
| 258 i=$((${i} + 1)) |
| 259 echo "${tmpstr}passed" >> ${LOGFILE} |
| 260 done |
| 261 |
| 262 return "$EXIT_SUCCESS" |
OLD | NEW |