1#!/bin/sh 2# 3# Copyright (C) 2016 Google Inc. 4# Copyright (C) 2020 Facebook 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 20EXIT_SUCCESS=0 21EXIT_FAILURE=1 22RC=$EXIT_SUCCESS 23FATAL=0 24NONFATAL=1 25 26# 27# Stuff obtained from command-line 28# 29 30# Generic options 31BACKUP_IMAGE="" 32OLD_FLASHROM="" 33NEW_FLASHROM="" 34NO_CLEAN=0 35SKIP_CONSISTENCY_CHECK=0 36UPLOAD_RESULTS=0 37 38# LOCAL_FLASHROM is required if both a secondary programmer *and* a remote host 39# are used since OLD_FLASHROM and NEW_FLASHROM will be called on the remote 40# host and we need a local copy of flashrom to control the secondary programmer. 41# By default this will be set to the result of `which flashrom`. 42LOCAL_FLASHROM="" 43 44# Primary/Secondary programmer options 45PRIMARY_OPTS="" 46SECONDARY_OPTS="" 47 48# Calls preflash_hook() and postflash_hook() before and after doing a command. 49CUSTOM_HOOKS_FILENAME="" 50 51# logfile to store the script's output 52SCRIPT_LOGFILE="flashrom-test_script_output.txt" 53 54# Test type 55TEST_TYPE_UNKNOWN=0 56TEST_TYPE_SINGLE=1 57TEST_TYPE_ENDURANCE=2 58TEST_TYPE=$TEST_TYPE_UNKNOWN 59 60# Region modes 61REGION_MODE_UNKNOWN=0 62REGION_MODE_CLOBBER=1 63REGION_MODE_DESCRIPTOR=2 64REGION_MODE_FLASHMAP=3 65REGION_MODE_LAYOUT=4 66REGION_MODE=$REGION_MODE_UNKNOWN 67DESCRIPTOR_REGION="BIOS" 68FLASHMAP_REGION="RW_SECTION_A" 69LAYOUT_FILE="" 70LAYOUT_REGION="RW" 71SMALL_REGION=0 72 73# Remote testing options 74SSH_PORT="" 75REMOTE_HOST="" 76REMOTE_PORT_OPTION="" 77REMOTE_ONLY=0 78REMOTE_PROGRAMMER_PARAMS="" 79SSH_CMD="ssh $REMOTE_PORT_OPTION root@${REMOTE_HOST} command -v" 80 81LOCAL=0 82REMOTE=1 83DO_REMOTE=0 # boolean to use for cmd() and tests 84 85# relative path from flashrom root directory 86TEST_SCRIPT_PATH="util/testing/test_v2.1.sh" 87 88# In case we need to run flashrom locally and we're not already root. 89SUDO_CMD="" 90if [ "$(id -u)" -ne "0" ]; then 91 SUDO_CMD="sudo" 92fi 93 94# 1KB 95K=1024 96 97show_help() { 98 printf "Usage: 99 ${0} <options> 100 101General options: 102 -b, --backup-image <path> 103 Backup image to write unconditionally at end of testing. 104 -h, --help 105 Show this message. 106 -l, --layout-file <path> 107 Layout file (required if mode is \"layout\", resides locally). 108 -m, --mode <arg> 109 Region access mode (clobber, descriptor, flashmap, layout). 110 -n, --new <path> 111 Path to new version of flashrom. 112 -o, --old <path> 113 Path to old (stable) version of flashrom. 114 -p, --primary-programmer <parameters> 115 Primary programmer options. 116 -r, --remote-host <host> 117 Remote host to test primary programmer on. 118 -s, --secondary-programmer <parameters> 119 Secondary programmer options. 120 -t, --type <arg> 121 Test type (single, endurance). 122 -u, --upload-results 123 Upload results to flashrom.org. 124 -v, --voltage 125 Chip voltage in millivolts (usually 1800 or 3300). 126 127Long options: 128 --custom-hooks <filename> 129 Supply a script with custom hooks to run before and after commands. 130 --descriptor-region <name> 131 Specify region to use in descriptor mode (default: $DESCRIPTOR_REGION) 132 --flashmap-region <name> 133 Specify region to use in flashmap mode (default: $FLASHMAP_REGION) 134 --layout-region <name> 135 Specify region to use in layout mode (default: $LAYOUT_REGION) 136 --local-flashrom <path> 137 Path to local version of flashrom when using both a secondary programmer 138 and remote host (default: $($SUDO_CMD which flashrom)) 139 --no-clean 140 Do not remove temporary files. 141 --skip-consistency-check 142 Skip the consistency check (two consecutive reads) at beginning. 143 --small-region 144 Omit tests that require large amounts of space (>16KB). 145Remote connectivity options: 146 --ssh-port <port> 147 Use a specific SSH port. 148 149See documentation for usage examples (TODO: Migrate https://goo.gl/3jNoL7 150to flashrom wiki).\n 151" 152} 153 154getopt -T 155if [ $? -ne 4 ]; then 156 printf "GNU-compatible getopt(1) required.\n" 157 exit $EXIT_FAILURE 158fi 159 160LONGOPTS="backup-image:,help,,new:,old:,remote-host:,upload-results:" 161LONGOPTS="${LONGOPTS},primary-programmer:,secondary-programmer:,local-flashrom:" 162LONGOPTS="${LONGOPTS},custom-hooks:,mode:,skip-consistency-check,small-region" 163LONGOPTS="${LONGOPTS},type:,voltage:" 164LONGOPTS="${LONGOPTS},layout-file:,descriptor-region:,flashmap-region:,layout-region:" 165LONGOPTS="${LONGOPTS},no-clean" 166LONGOPTS="${LONGOPTS},ssh-port:" 167 168ARGS=$(getopt -o b:hl:m:n:o:p:r:s:t:u -l "$LONGOPTS" -n "$0" -- "$@"); 169if [ $? != 0 ] ; then printf "Terminating...\n" >&2 ; exit 1 ; fi 170eval set -- "$ARGS" 171while true ; do 172 case "$1" in 173 # Generic options 174 -b|--backup-image) 175 shift 176 BACKUP_IMAGE="$1" 177 ;; 178 -h|--help) 179 show_help 180 exit $EXIT_SUCCESS 181 ;; 182 -l|--layout-file) 183 shift 184 LAYOUT_FILE="$1" 185 ;; 186 -m|--mode) 187 shift 188 if [ "$1" = "clobber" ]; then 189 REGION_MODE=$REGION_MODE_CLOBBER 190 elif [ "$1" = "descriptor" ]; then 191 REGION_MODE=$REGION_MODE_DESCRIPTOR 192 elif [ "$1" = "flashmap" ]; then 193 REGION_MODE=$REGION_MODE_FLASHMAP 194 elif [ "$1" = "layout" ]; then 195 REGION_MODE=$REGION_MODE_LAYOUT 196 else 197 printf "Unknown mode: $1\n" 198 exit $EXIT_FAILURE 199 fi 200 ;; 201 -n|--new) 202 shift 203 NEW_FLASHROM="$1" 204 ;; 205 -o|--old) 206 shift 207 OLD_FLASHROM="$1" 208 ;; 209 -p|--primary_programmer) 210 shift 211 PRIMARY_OPTS="-p $1" 212 ;; 213 -s|--secondary_programmer) 214 shift 215 SECONDARY_OPTS="-p $1" 216 ;; 217 -t|--type) 218 shift 219 if [ "$1" = "single" ]; then 220 TEST_TYPE=$TEST_TYPE_SINGLE 221 elif [ "$1" = "endurance" ]; then 222 TEST_TYPE=$TEST_TYPE_ENDURANCE 223 else 224 printf "Unknown type: $1\n" 225 exit $EXIT_FAILURE 226 fi 227 ;; 228 -r|--remote-host) 229 DO_REMOTE=1 230 shift 231 REMOTE_HOST="$1" 232 ;; 233 -u|--upload-results) 234 UPLOAD_RESULTS=1 235 ;; 236 -v|--voltage) 237 shift 238 VOLTAGE="$1" 239 ;; 240 241 # Longopts only 242 --custom-hooks) 243 shift 244 CUSTOM_HOOKS_FILENAME="$1" 245 ;; 246 --descriptor-region) 247 shift 248 DESCRIPTOR_REGION="$1" 249 ;; 250 --flashmap-region) 251 shift 252 FLASHMAP_REGION="$1" 253 ;; 254 --layout-region) 255 shift 256 LAYOUT_REGION="$1" 257 ;; 258 --local-flashrom) 259 shift 260 LOCAL_FLASHROM="$1" 261 ;; 262 --no-clean) 263 NO_CLEAN=1 264 ;; 265 --skip-consistency-check) 266 SKIP_CONSISTENCY_CHECK=1 267 ;; 268 --small-region) 269 SMALL_REGION=1 270 ;; 271 272 # Remote testing options 273 --ssh-port) 274 shift 275 REMOTE_PORT_OPTION="-p $1" 276 ;; 277 278 # error handling 279 --) 280 shift 281 if [ -n "$*" ]; then 282 printf "Non-option parameters detected: '$*'\n" 283 exit $EXIT_FAILURE 284 fi 285 break 286 ;; 287 *) 288 printf "error processing options at '$1'\n" 289 exit $EXIT_FAILURE 290 esac 291 shift 292done 293 294# TODO: Implement this. 295if [ $UPLOAD_RESULTS -eq 1 ]; then 296 printf "TODO: Implement ability to upload results.\n" 297 exit $EXIT_FAILURE 298fi 299 300# 301# Source helper scripts 302# 303export REMOTE_HOST REMOTE_PORT_OPTION 304export LOCAL REMOTE FATAL NONFATAL EXIT_SUCCESS EXIT_FAILURE 305export CUSTOM_HOOKS_FILENAME SUDO_CMD VOLTAGE 306. "$(pwd)/util/testing/cmd.sh" 307 308# We will set up a logs directory within the tmpdirs to store 309# all output logs. 310LOGS="logs" 311 312# Setup temporary working directories: 313# LOCAL_TMPDIR: Working directory on local host. 314# REMOTE_TMPDIR: Working directory on remote host. 315# TMPDIR: The temporary directory in which we do most of the work. This is 316# convenient for commands that depend on $DO_REMOTE. 317LOCAL_TMPDIR=$(mktemp -d --tmpdir flashrom_test.XXXXXXXX) 318if [ $? -ne 0 ] ; then 319 printf "Could not create temporary directory\n" 320 exit $EXIT_FAILURE 321fi 322mkdir "${LOCAL_TMPDIR}/${LOGS}" 323 324if [ $DO_REMOTE -eq 1 ]; then 325 REMOTE_TMPDIR=$(ssh root@${REMOTE_HOST} mktemp -d --tmpdir flashrom_test.XXXXXXXX) 326 if [ $? -ne 0 ] ; then 327 printf "Could not create temporary directory\n" 328 exit $EXIT_FAILURE 329 fi 330 scmd $REMOTE "mkdir ${REMOTE_TMPDIR}/${LOGS}" 331fi 332 333if [ $DO_REMOTE -eq 0 ]; then 334 TMPDIR="$LOCAL_TMPDIR" 335else 336 TMPDIR="$REMOTE_TMPDIR" 337fi 338 339# 340# Test command-line validity. 341# 342if [ $TEST_TYPE -eq $TEST_TYPE_UNKNOWN ]; then 343 printf "Must specify a test type (-t/--type).\n" 344 exit $EXIT_FAILURE 345elif [ $TEST_TYPE -eq $TEST_TYPE_SINGLE ]; then 346 if [ $REGION_MODE -eq $REGION_MODE_UNKNOWN ]; then 347 printf "Must specify a region access mode (-m/--mode).\n" 348 exit $EXIT_FAILURE 349 elif [ $REGION_MODE -eq $REGION_MODE_LAYOUT ]; then 350 if [ -z "$LAYOUT_FILE" ]; then 351 printf "Must specify a layout file when using layout mode.\n" 352 exit $EXIT_FAILURE 353 fi 354 355 scmd $DO_REMOTE "stat $LAYOUT_FILE" 356 if [ $? -ne 0 ]; then 357 if [ $DO_REMOTE -eq 1 ]; then 358 tmp=" on remote host $REMOTE_HOST." 359 else 360 tmp=" on local host." 361 fi 362 printf "Layout file $LAYOUT_FILE not found${tmp}\n" 363 exit $EXIT_FAILURE 364 fi 365 366 if [ $DO_REMOTE -eq 1 ]; then 367 scp root@"${REMOTE_HOST}:$LAYOUT_FILE" "${LOCAL_TMPDIR}/" 2>&1 >/dev/null 368 else 369 cp "$LAYOUT_FILE" "${LOCAL_TMPDIR}/" 370 fi 371 fi 372fi 373 374if [ -n "$VOLTAGE" ]; then 375 echo "$VOLTAGE" | grep -q '[^0-9]' 376 if [ $? -ne 1 ]; then 377 printf "Voltage must be an integer with units of millivolts." 378 exit $EXIT_FAILURE 379 fi 380fi 381 382if [ $DO_REMOTE -eq 1 ]; then 383 # Test connection to remote host 384 test_cmd $DO_REMOTE "ls /" $NONFATAL 385 if [ $? -ne 0 ]; then 386 printf "Could not connect to remote host ${REMOTE_HOST}\n" 387 exit $EXIT_FAILURE 388 fi 389fi 390 391# Remote host and secondary programmer are in use, so either the user must 392# specify a local version of flashrom to control the secondary programmer 393# or it must be found in the default path. 394if [ $DO_REMOTE -eq 1 ] && [ -n "$SECONDARY_OPTS" ]; then 395 if [ -z "$LOCAL_FLASHROM" ]; then 396 LOCAL_FLASHROM="$($SUDO_CMD which flashrom)" 397 fi 398 399 if [ ! -e "$LOCAL_FLASHROM" ]; then 400 printf "$LOCAL_FLASHROM does not exist\n" 401 exit $EXIT_FAILURE 402 fi 403fi 404 405# 406# Dependencies 407# 408 409# cmp is used to compare files 410test_cmd $DO_REMOTE "cmp" $FATAL 411 412if [ ! -e "/dev/urandom" ]; then 413 printf "This script uses /dev/urandom\n" 414 exit $EXIT_FAILURE 415fi 416 417if [ ! -e "/dev/zero" ]; then 418 printf "This script uses /dev/zero\n" 419 exit $EXIT_FAILURE 420fi 421 422# 423# Setup. 424# 425 426# Naive path check 427if [ ! -e "$TEST_SCRIPT_PATH" ] ; then 428 printf "Script must be run from root of flashrom directory\n" 429 exit $EXIT_FAILURE 430fi 431 432if [ -z "$OLD_FLASHROM" ]; then 433 if [ $DO_REMOTE -eq 1 ]; then 434 OLD_FLASHROM="$(ssh root@${REMOTE_HOST} which flashrom)" 435 else 436 OLD_FLASHROM="$($SUDO_CMD which flashrom)" 437 fi 438fi 439test_cmd $DO_REMOTE "$OLD_FLASHROM --help" $NONFATAL 440if [ $? -ne 0 ]; then 441 printf "Old flashrom binary is not usable.\n" 442 exit $EXIT_FAILURE 443fi 444 445# print $1 and store it in the script log file 446print_and_log() 447{ 448 printf "$1" | tee -a "${LOCAL_TMPDIR}/${LOGS}/${SCRIPT_LOGFILE}" 449} 450 451# Copy files from local tmpdir to remote host tmpdir 452copy_to_remote() 453{ 454 for F in $@; do 455 scp "${LOCAL_TMPDIR}/${F}" root@"${REMOTE_HOST}:${REMOTE_TMPDIR}" 2>&1 >/dev/null 456 done 457} 458 459# Copy files from remote host tmpdir to local tmpdir 460copy_from_remote() 461{ 462 for F in $@; do 463 scp root@"${REMOTE_HOST}:${REMOTE_TMPDIR}/${F}" "${LOCAL_TMPDIR}/" 2>&1 >/dev/null 464 done 465} 466 467# A wrapper for scmd calls to flashrom when we want to log the output 468# $1: 0 ($LOCAL) to run command locally, 469# 1 ($REMOTE) to run remotely if remote host defined 470# $2: arguments to be passed into scmd 471# $3: context of the flashrom call (to be used in the logfile) 472flashrom_log_scmd() 473{ 474 local logfile="flashrom-${3}.txt" 475 local rc 476 477 if [ $1 -eq $REMOTE ]; then 478 tmpdir=$REMOTE_TMPDIR 479 else 480 tmpdir=$LOCAL_TMPDIR 481 fi 482 483 scmd $1 "$2 -o ${tmpdir}/${LOGS}/${logfile}"; rc=$? 484 # if the call was successful, we don't want to save the log (only save failure logs) 485 if [ $rc -eq $EXIT_SUCCESS ]; then 486 scmd $1 "rm -f ${tmpdir}/${LOGS}/${logfile}" 487 else 488 # if the log was stored remotely, we want to copy it over to local tmpdir 489 if [ $1 -eq $REMOTE ]; then 490 scp root@"${REMOTE_HOST}:${REMOTE_TMPDIR}/${LOGS}/${logfile}" "${LOCAL_TMPDIR}/${LOGS}" 2>&1 >/dev/null 491 fi 492 fi 493 494 return $rc 495} 496 497# Read current image as backup in case one hasn't already been specified. 498if [ -z "$BACKUP_IMAGE" ]; then 499 backup_file="backup.bin" 500 if [ $DO_REMOTE -eq 1 ]; then 501 BACKUP_IMAGE="${REMOTE_TMPDIR}/${backup_file}" 502 else 503 BACKUP_IMAGE="${LOCAL_TMPDIR}/${backup_file}" 504 fi 505 506 print_and_log "Reading backup image..." 507 flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -r $BACKUP_IMAGE" "read_backup" 508 509 if [ $? -ne 0 ]; then 510 print_and_log "Failed to read backup image, aborting.\n" 511 exit $EXIT_FAILURE 512 fi 513 514 if [ $DO_REMOTE -eq 1 ]; then 515 copy_from_remote "$backup_file" 516 fi 517else 518 if [ $DO_REMOTE -eq 1 ]; then 519 scmd $DO_REMOTE "cp $BACKUP_IMAGE $REMOTE_TMPDIR" 520 copy_from_remote "$(basename $BACKUP_IMAGE)" 521 fi 522fi 523 524# The copy of flashrom to test. If unset, we'll assume the user wants to test 525# a newly built flashrom binary in the current directory. 526if [ -z "$NEW_FLASHROM" ] ; then 527 if [ -x "flashrom" ]; then 528 NEW_FLASHROM="flashrom" 529 else 530 print_and_log "Must supply new flashrom version to test\n" 531 exit $EXIT_FAILURE 532 fi 533fi 534 535print_and_log "Stable flashrom binary: ${OLD_FLASHROM}\n" 536print_and_log "New flashrom binary to test: ${NEW_FLASHROM}\n" 537print_and_log "Local temporary files will be stored in ${LOCAL_TMPDIR}\n" 538if [ $DO_REMOTE -eq 1 ]; then 539 print_and_log "Remote temporary files will be stored in ${REMOTE_HOST}:${REMOTE_TMPDIR}\n" 540 print_and_log "Backup image: ${REMOTE_HOST}:${BACKUP_IMAGE}\n" 541 print_and_log "Backup image also stored at: ${LOCAL_TMPDIR}/$(basename ${BACKUP_IMAGE})\n" 542else 543 print_and_log "Backup image: ${BACKUP_IMAGE}\n" 544fi 545 546# 547# Now the fun begins. 548# 549cmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS --flash-size" "${LOCAL_TMPDIR}/old_chip_size.txt.orig" 550cmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS --flash-size" "${LOCAL_TMPDIR}/new_chip_size.txt.orig" 551# get rid of banner and other superfluous output from flashrom 552tail -n 1 "${LOCAL_TMPDIR}/old_chip_size.txt.orig" > "${LOCAL_TMPDIR}/old_chip_size.txt" 553tail -n 1 "${LOCAL_TMPDIR}/new_chip_size.txt.orig" > "${LOCAL_TMPDIR}/new_chip_size.txt" 554tmp=$(cat ${LOCAL_TMPDIR}/old_chip_size.txt) 555CHIP_SIZE=$(cat ${LOCAL_TMPDIR}/new_chip_size.txt) 556CHIP_SIZE_KB=$(($CHIP_SIZE / $K)) 557CHIP_SIZE_HALF=$(($CHIP_SIZE / 2)) 558if [ $CHIP_SIZE -ne $tmp ]; then 559 print_and_log "New flashrom and old flashrom disagree on chip size. Aborting.\n" 560 exit $EXIT_FAILURE 561else 562 print_and_log "Chip size: $CHIP_SIZE_KB KiB\n" 563fi 564 565# Upload results 566#do_upload() 567#{ 568# # TODO: implement this 569#} 570 571# Remove temporary files 572do_cleanup() 573{ 574 if [ $NO_CLEAN -eq 1 ]; then 575 print_and_log "Skipping cleanup.\n" 576 return $EXIT_SUCCESS 577 fi 578 579 rm -rf "$LOCAL_TMPDIR" 580 if [ -n "$REMOTE_HOST" ]; then 581 ssh root@${REMOTE_HOST} rm -rf "$REMOTE_TMPDIR" 582 fi 583 584 return $EXIT_SUCCESS 585} 586 587# $1: Message to display to user. 588test_fail() 589{ 590 print_and_log "$1\n" 591 printf "Skipping cleanup (logs saved).\n" 592 exit $EXIT_FAILURE 593} 594 595write_backup_image() 596{ 597 print_and_log "Writing backup image.\n" 598 flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -w $BACKUP_IMAGE" "write_backup" 599 if [ $? -ne 0 ]; then 600 test_fail "Failed to write backup image.\n" 601 fi 602} 603 604# Read a region twice and compare results 605# $1: address of region (in bytes) 606# $2: length of region (in bytes) 607double_read_test() 608{ 609 local cmp1="${TMPDIR}/read_test1.bin" 610 local cmp2="${TMPDIR}/read_test2.bin" 611 local layout="double_read_test_layout.txt" 612 local len=$(($2 / $K)) 613 614 print_and_log "Doing double read test, size: $len KiB\n" 615 # FIXME: Figure out how to do printf remotely... 616 printf "%06x:%06x region\n" $1 $(($1 + $2 - 1)) > "${LOCAL_TMPDIR}/${layout}" 617 if [ $DO_REMOTE -eq 1 ]; then copy_to_remote "$layout" ; fi 618 619 flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -l ${TMPDIR}/${layout} -i region -r ${cmp1}" "double_read_1" 620 # FIXME: second (or maybe third?) read should be done using secondary programmer, if applicable. 621 flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -l ${TMPDIR}/${layout} -i region -r ${cmp2}" "double_read_2" 622 scmd $DO_REMOTE "cmp $cmp1 $cmp2" 623 if [ $? -ne 0 ]; then 624 test_fail "Double-read test failed, aborting." 625 fi 626} 627 628PARTIAL_WRITE_TEST_REGION_SIZE=0 629PARTIAL_WRITE_TEST_ALIGN_SIZE_KB=0 630# FIXME: Hack due to lack of region-sized file handling. 631PARTIAL_WRITE_TEST_REGION_BASE_OFFSET=-1 632 633# helper function to reduce repetitiveness of partial_write_test 634partial_write_test_helper() 635{ 636 local test_name="$1" 637 local pattern_offset_kb=$2 638 local pattern_size_kb=$3 639 local hex="$4" 640 local oct="" 641 local base_offset_kb=$(($PARTIAL_WRITE_TEST_REGION_BASE_OFFSET / $K)) 642 643 oct="\\$(printf "%03o" $hex)" 644 cp "${LOCAL_TMPDIR}/random_4k_test.bin" "${LOCAL_TMPDIR}/${test_name}.bin" 645 dd if=/dev/zero bs=1k count=${pattern_size_kb} 2>/dev/null | tr "\000" "$oct" > "${LOCAL_TMPDIR}/${hex}_${pattern_size_kb}k.bin" 646 647 while [ $(($(($pattern_offset_kb + $pattern_size_kb)) * $K)) -lt $PARTIAL_WRITE_TEST_REGION_SIZE ]; do 648 dd if="${LOCAL_TMPDIR}/${hex}_${pattern_size_kb}k.bin" of="${LOCAL_TMPDIR}/${test_name}.bin" bs=1k count=$pattern_size_kb seek=$(($base_offset_kb + $pattern_offset_kb)) conv=notrunc 2>/dev/null 649 pattern_offset_kb=$(($pattern_offset_kb + $PARTIAL_WRITE_TEST_ALIGN_SIZE_KB)) 650 done 651} 652 653# Regional partial write test. Given a region name, this will write patterns 654# of bytes designed to test corner cases. 655# 656# We assume that eraseable block size can be either 4KB or 64KB and 657# must test for both. For simplicity, we'll assume the region size is 658# at least 256KB. 659# 660# $1: Region name 661partial_write_test() 662{ 663 local opts="--noverify-all" 664 local secondary_opts="" # for secondary programmer 665 local region_name="$1" 666 local filename="" 667 local test_num=0 668 local prev_test_num=0 669 670 # FIXME: Hack due to lack of region-sized file handling. 671 if [ $((PARTIAL_WRITE_TEST_REGION_SIZE)) -eq 0 ]; then 672 print_and_log "Size of $region_name unknown\n" 673 return $EXIT_FAILURE 674 fi 675 if [ $((PARTIAL_WRITE_TEST_REGION_BASE_OFFSET)) -lt 0 ]; then 676 print_and_log "Offset of $region_name is unknown\n" 677 return $EXIT_FAILURE 678 fi 679 680 if [ $TEST_TYPE -eq $TEST_TYPE_SINGLE ]; then 681 if [ $REGION_MODE -eq $REGION_MODE_LAYOUT ]; then 682 opts="$opts -l $LAYOUT_FILE" 683 secondary_opts="$opts" 684 elif [ $REGION_MODE -eq $REGION_MODE_CLOBBER ]; then 685 printf "000000:%06x RW\n" $(($CHIP_SIZE - 1)) > "${LOCAL_TMPDIR}/clobber_mode_layout.txt" 686 if [ $DO_REMOTE -eq 1 ]; then 687 copy_to_remote "clobber_mode_layout.txt" 688 fi 689 secondary_opts="$opts -l ${LOCAL_TMPDIR}/clobber_mode_layout.txt" 690 opts="$opts -l ${TMPDIR}/clobber_mode_layout.txt" 691 fi 692 fi 693 694 if [ $SMALL_REGION -eq 1 ]; then 695 PARTIAL_WRITE_TEST_ALIGN_SIZE_KB=16 696 else 697 PARTIAL_WRITE_TEST_ALIGN_SIZE_KB=256 698 fi 699 700 # FIXME: Add sanity checks. 701 702 print_and_log "Doing region-based partial write test on region \"$region_name\"\n" 703 flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS $opts -i ${region_name} -r ${TMPDIR}/${region_name}.bin" "read_region_${region_name}" 704 if [ $DO_REMOTE -eq 1 ]; then 705 copy_from_remote "${region_name}.bin" 706 fi 707 708 if [ $(($PARTIAL_WRITE_TEST_REGION_SIZE % $(($PARTIAL_WRITE_TEST_ALIGN_SIZE_KB)))) -ne 0 ]; then 709 print_and_log "Region $region_name is not aligned to $PARTIAL_WRITE_TEST_ALIGN_SIZE_KB\n" 710 return $EXIT_FAILURE 711 fi 712 713 # Test procedure: 714 # Clobber region with random content first. Then do writes using the 715 # following sequences for each 128KB: 716 # 0-2K : 0x00 (\000) Partial 4KB sector, lower half 717 # 2K-6K : 0x11 (\021) Crossover 4KB sector boundary 718 # 6K-8K : 0x22 (\042) Partial 4KB sector, upper half 719 # 8K-16K : 0x33 (\063) Full 4KB sectors 720 # 721 # Repeat the above sequence for 64KB-aligned sizes 722 # 0-32K : 0x44 (\104) Partial 64KB block, lower half 723 # 32K-96K : 0x55 (\125) Crossover 64KB block boundary 724 # 96K-128K : 0x66 (\146) Partial 64KB block, upper half 725 # 128K-256K : 0x77 (\167) Full 64KB blocks 726 727 test_num=0 728 dd if=/dev/zero of="${LOCAL_TMPDIR}/random_4k_test.bin" bs=1k count=$CHIP_SIZE_KB 2>/dev/null 729 dd if=/dev/urandom of="${LOCAL_TMPDIR}/random_4k_test.bin" bs=4k count=$(($PARTIAL_WRITE_TEST_REGION_SIZE / $((4 * $K)))) seek=$(($((PARTIAL_WRITE_TEST_REGION_BASE_OFFSET)) / $((4 * $K)))) conv=notrunc 2>/dev/null 730 731 # 0-2K : 0x00 (\000) Partial 4KB sector, lower half 732 partial_write_test_helper "4k_test_${test_num}" 0 2 "0x00" 733 prev_test_num=$test_num 734 test_num=$(($test_num + 1)) 735 736 # 2K-6K : 0x11 (\021) Crossover 4KB sector boundary 737 partial_write_test_helper "4k_test_${test_num}" 2 4 "0x11" 738 test_num=$(($test_num + 1)) 739 740 # 6K-8K : 0x22 (\042) Partial 4KB sector, upper half 741 partial_write_test_helper "4k_test_${test_num}" 6 2 "0x22" 742 test_num=$(($test_num + 1)) 743 744 # 8K-16K : 0x33 (\063) Full 4KB sectors 745 partial_write_test_helper "4k_test_${test_num}" 8 8 "0x33" 746 747 for F in ${LOCAL_TMPDIR}/random_4k_test.bin ${LOCAL_TMPDIR}/4k_test_*.bin ; do 748 filename=$(basename $F) 749 if [ $DO_REMOTE -eq 1 ]; then 750 copy_to_remote $filename 751 fi 752 753 flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS $opts -i ${region_name} -w ${TMPDIR}/${filename}" "write_${filename}" 754 if [ $? -ne 0 ]; then 755 test_fail "Failed to write $filename to $region_name" 756 fi 757 758 flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS $opts -i ${region_name} -v ${TMPDIR}/${filename}" "verify_${filename}" 759 if [ $? -ne 0 ]; then 760 test_fail "Failed to verify write of $filename to $region_name" 761 fi 762 763 if [ -n "$SECONDARY_OPTS" ]; then 764 flashrom_log_scmd $LOCAL "$LOCAL_FLASHROM $SECONDARY_OPTS $secondary_opts -i ${region_name} -v ${LOCAL_TMPDIR}/${filename}" "verify_secondary_${filename}" 765 if [ $? -ne 0 ]; then 766 test_fail "Failed to verify write of $filename to $region_name using secondary programmer" 767 fi 768 fi 769 770 print_and_log "\tWrote $filename to $region_name region successfully.\n" 771 done 772 773 if [ $SMALL_REGION -eq 1 ]; then 774 return $EXIT_SUCCESS 775 fi 776 777 # 778 # Second half: Tests for 64KB chunks 779 # 780 test_num=0 781# dd if=/dev/urandom of="${LOCAL_TMPDIR}/random_64k_test.bin" bs=128k count=$(($PARTIAL_WRITE_TEST_REGION_SIZE / $((128*$K)))) 2>/dev/null 782 dd if=/dev/zero of="${LOCAL_TMPDIR}/random_64k_test.bin" bs=1k count=$CHIP_SIZE_KB 2>/dev/null 783 dd if=/dev/urandom of="${LOCAL_TMPDIR}/random_64k_test.bin" bs=128k count=$(($PARTIAL_WRITE_TEST_REGION_SIZE / $((128 * $K)))) seek=$(($((PARTIAL_WRITE_TEST_REGION_BASE_OFFSET)) / $((128 * $K)))) conv=notrunc 2>/dev/null 784 785 # 0-32K : 0x44 (\104) Partial 64KB block, lower half 786 partial_write_test_helper "64k_test_${test_num}" 0 32 "0x44" 787 prev_test_num=$test_num 788 test_num=$(($test_num + 1)) 789 790 # 32K-96K : 0x55 (\125) Crossover 64KB block boundary 791 partial_write_test_helper "64k_test_${test_num}" 32 64 "0x55" 792 test_num=$(($test_num + 1)) 793 794 # 96K-128K : 0x66 (\146) Partial 64KB block, upper half 795 partial_write_test_helper "64k_test_${test_num}" 96 32 "0x66" 796 test_num=$(($test_num + 1)) 797 798 # 128K-256K : 0x77 (\167) Full 64KB blocks 799 partial_write_test_helper "64k_test_${test_num}" 128 128 "0x77" 800 801 for F in ${LOCAL_TMPDIR}/random_64k_test.bin ${LOCAL_TMPDIR}/64k_test_*.bin ; do 802 filename=$(basename $F) 803 if [ $DO_REMOTE -eq 1 ]; then 804 copy_to_remote $filename 805 fi 806 807 flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS $opts -i ${region_name} -w ${TMPDIR}/${filename}" "write_${filename}" 808 if [ $? -ne 0 ]; then 809 test_fail "Failed to write $filename to $region_name" 810 fi 811 812 flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS $opts -i ${region_name} -v ${TMPDIR}/${filename}" "verify_${filename}" 813 if [ $? -ne 0 ]; then 814 test_fail "Failed to verify write of $filename to $region_name" 815 fi 816 817 if [ -n "$SECONDARY_OPTS" ]; then 818 flashrom_log_scmd $LOCAL "$LOCAL_FLASHROM $SECONDARY_OPTS $secondary_opts -i ${region_name} -v ${LOCAL_TMPDIR}/${filename}" "verify_secondary_${filename}" 819 if [ $? -ne 0 ]; then 820 test_fail "Failed to verify write of $filename to $region_name using secondary programmer" 821 fi 822 fi 823 824 print_and_log "\tWrote $filename to $region_name region successfully.\n" 825 done 826 827 return $EXIT_SUCCESS 828} 829 830# Before anything else, check to see if Flashrom can successfully probe 831# for and find the flash chips. If not, we will abort. 832flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS" "verify_probe" 833if [ $? -ne 0 ]; then 834 test_fail "Failed to find flash chips while probing, aborting." 835fi 836 837# Read ROM twice to test for consistency. 838if [ $SKIP_CONSISTENCY_CHECK -eq 0 ]; then 839 double_read_test 0 $CHIP_SIZE 840fi 841 842if [ $TEST_TYPE -eq $TEST_TYPE_SINGLE ]; then 843 if [ $REGION_MODE -eq $REGION_MODE_CLOBBER ]; then 844 random_file="${TMPDIR}/random_${CHIP_SIZE_KB}K.bin" 845 cmp_file="${TMPDIR}/cmp.bin" 846 847 scmd $DO_REMOTE "dd if=/dev/urandom of=${random_file} bs=1k count=${CHIP_SIZE_KB}" 848 flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -w $random_file" "clobber_write" 849 flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -r $cmp_file" "clobber_verify" 850 scmd $DO_REMOTE "cmp $random_file $cmp_file" 851 if [ $? -ne 0 ]; then 852 write_backup_image 853 test_fail "Failed to clobber entire ROM." 854 fi 855 elif [ $REGION_MODE -eq $REGION_MODE_DESCRIPTOR ]; then 856 # FIXME: Need region-sized file handling or some way to get region info 857 print_and_log "Currently broken due to lack of region-sized file handling." 858 exit $EXIT_FAILURE 859 elif [ $REGION_MODE -eq $REGION_MODE_FLASHMAP ]; then 860 # FIXME: Need region-sized file handling or some way to get region info 861 print_and_log "Currently broken due to lack of region-sized file handling." 862 exit $EXIT_FAILURE 863 elif [ $REGION_MODE -eq $REGION_MODE_LAYOUT ]; then 864 rw_layout="" 865 addr="" 866 end="" 867 size="" 868 size_kb="" 869 870 # Look for a region name with any amount of leading whitespace 871 # and no trailing whitespace or characters. 872 rw_layout=$(grep "\s${LAYOUT_REGION}$" "${LOCAL_TMPDIR}/$(basename $LAYOUT_FILE)" | head -n 1) 873 if [ -z "$rw_layout" ]; then 874 print_and_log "No region matching \"${LAYOUT_REGION}\" found layout file \"${LAYOUT_FILE}\"\n" 875 test_fail "" 876 fi 877 878 addr="0x$(echo "$rw_layout" | cut -d ' ' -f -1 | awk -F ':' '{ print $1 }')" 879 end="0x$(echo "$rw_layout" | cut -d ' ' -f -1 | awk -F ':' '{ print $2 }')" 880 size="$(($end - $addr + 1))" 881 size_kb="$(($size / $K))" 882 883 # FIXME: Hack to make this work without region-sized file handling. 884 PARTIAL_WRITE_TEST_REGION_BASE_OFFSET=$addr 885 PARTIAL_WRITE_TEST_REGION_SIZE=$size 886 887 print_and_log "\"$LAYOUT_REGION\" region address: ${addr}, size: $size_kb KiB\n" 888 partial_write_test "$LAYOUT_REGION" 889 if [ $? -ne 0 ]; then 890 print_and_log "Layout mode test failed\n" 891 RC=$EXIT_FAILURE 892 fi 893 fi 894elif [ $TEST_TYPE -eq $TEST_TYPE_ENDURANCE ]; then 895 iteration=1 896 terminate=0 897 random_file="${TMPDIR}/random_${CHIP_SIZE_KB}K.bin" 898 cmp_file="${TMPDIR}/cmp.bin" 899 # TODO: We can measure how long the tests take on average, throughput, etc. 900 # i.e. { time $NEW_FLASHROM $PRIMARY_OPTS -w $random_file ; } 2>&1 | grep user | cut -f2 901 902 # For this test we want to run clobber mode until failure 903 while [ $terminate -eq 0 ] 904 do 905 print_and_log "Running iteration #${iteration}\n" 906 907 scmd $DO_REMOTE "dd if=/dev/urandom of=${random_file} bs=1k count=${CHIP_SIZE_KB}" 908 flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -w $random_file" "endurance_write_${iteration}" 909 flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -r $cmp_file" "endurance_verify_${iteration}" 910 scmd $DO_REMOTE "cmp $random_file $cmp_file" 911 if [ $? -ne 0 ]; then 912 terminate=1 913 fi 914 scmd $DO_REMOTE "rm -f $cmp_file $random_file" 915 916 iteration=$(($iteration + 1)) 917 done 918 919 # TODO: Determine what to return for the endurance test exit status 920 # i.e. what constitutes a test pass and what constitutes a test fail? 921 print_and_log "Failed on iteration $iteration\n" 922 # TODO - Print performance metrics? 923fi 924 925# restore and cleanup 926write_backup_image 927 928if [ $RC -eq 0 ]; then 929 print_and_log "Test status: PASS\n" 930else 931 print_and_log "Test status: FAIL\n" 932fi 933do_cleanup 934 935exit $RC 936