David Hendricks has uploaded a new change for review. ( https://review.coreboot.org/19342 )
Change subject: layout: Add -i <region>[:<file>] support.
......................................................................
layout: Add -i <region>[:<file>] support.
This is a rebased version of patch ported from chromiumos that adds
syntax for working with region-sized files when using a layout.
Original patch: http://codereview.chromium.org/6611015
Ported version: https://mail.coreboot.org/pipermail/flashrom/2013-October/011729.html
TODO(dhendrix): Update description.
Change-Id: Ic5465659605d8431d931053967b40290195cfd99
Signed-off-by: David Hendricks <dhendricks(a)fb.com>
---
M cli_classic.c
M dummyflasher.c
M flash.h
M flashrom.8.tmpl
M flashrom.c
M layout.c
M layout.h
7 files changed, 211 insertions(+), 40 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/42/19342/1
diff --git a/cli_classic.c b/cli_classic.c
index 0853a2f..0024483 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -58,7 +58,8 @@
" -A | --noverify-all don't auto-verify whole chip\n"
" -l | --layout <layoutfile> read ROM layout from <layoutfile>\n"
" -d | --ifd read layout from an Intel Firmware Descriptor\n"
- " -i | --image <name> only flash image <name> from flash layout\n"
+ " -i | --include <region>[<:file>] only flash image <region> from layout\n"
+ " (optionally with data from <file>)\n"
" -o | --output <logfile> log output to <logfile>\n"
" -L | --list-supported print supported devices\n"
#if CONFIG_PRINT_WIKI == 1
diff --git a/dummyflasher.c b/dummyflasher.c
index f171128..cea6b35 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -139,8 +139,10 @@
#if EMULATE_CHIP
if (emu_chip != EMULATE_NONE) {
if (emu_persistent_image) {
+ struct flashctx flash = { 0 };
+
msg_pdbg("Writing %s\n", emu_persistent_image);
- write_buf_to_file(flashchip_contents, emu_chip_size, emu_persistent_image);
+ write_buf_to_file(&flash, flashchip_contents, emu_chip_size, emu_persistent_image);
free(emu_persistent_image);
emu_persistent_image = NULL;
}
@@ -382,7 +384,7 @@
msg_pdbg("matches.\n");
msg_pdbg("Reading %s\n", emu_persistent_image);
read_buf_from_file(flashchip_contents, emu_chip_size,
- emu_persistent_image);
+ emu_persistent_image, NULL);
} else {
msg_pdbg("doesn't match.\n");
}
diff --git a/flash.h b/flash.h
index 0e24f61..08a6cf6 100644
--- a/flash.h
+++ b/flash.h
@@ -284,8 +284,8 @@
void print_banner(void);
void list_programmers_linebreak(int startcol, int cols, int paren);
int selfcheck(void);
-int read_buf_from_file(unsigned char *buf, unsigned long size, const char *filename);
-int write_buf_to_file(const unsigned char *buf, unsigned long size, const char *filename);
+int read_buf_from_file(unsigned char *buf, unsigned long size, const char *filename, const char *size_msg);
+int write_buf_to_file(struct flashctx *const flash, const unsigned char *buf, unsigned long size, const char *filename);
int prepare_flash_access(struct flashctx *, bool read_it, bool write_it, bool erase_it, bool verify_it);
int do_read(struct flashctx *, const char *filename);
int do_erase(struct flashctx *);
diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl
index c786a86..3bf9aa8 100644
--- a/flashrom.8.tmpl
+++ b/flashrom.8.tmpl
@@ -46,9 +46,9 @@
.SH SYNOPSIS
.B flashrom \fR[\fB\-h\fR|\fB\-R\fR|\fB\-L\fR|\fB\-z\fR|\
\fB\-p\fR <programmername>[:<parameters>]
- [\fB\-E\fR|\fB\-r\fR <file>|\fB\-w\fR <file>|\fB\-v\fR <file>] \
+ [\fB\-E\fR|\fB\-r\fR <imagefile>|\fB\-w\fR <imagefile>|\fB\-v\fR <imagefile>] \
[\fB\-c\fR <chipname>]
- [(\fB\-l\fR <file>|\fB\-d\fR) [\fB\-i\fR <image>]] [\fB\-n\fR] [\fB\-f\fR]]
+ [(\fB\-l\fR <file>|\fB\-d\fR) [\fB\-i\fR <regionname>[:<regionfile>]] [\fB\-n\fR] [\fB\-f\fR]]
[\fB\-V\fR[\fBV\fR[\fBV\fR]]] [\fB-o\fR <logfile>]
.SH DESCRIPTION
.B flashrom
@@ -80,14 +80,14 @@
.B -p/--programmer
option to be used (please see below).
.TP
-.B "\-r, \-\-read <file>"
+.B "\-r, \-\-read <imagefile>"
Read flash ROM contents and save them into the given
.BR <file> .
If the file already exists, it will be overwritten.
.TP
-.B "\-w, \-\-write <file>"
+.B "\-w, \-\-write <imagefile>"
Write
-.B <file>
+.B <imagefile>
into flash ROM. This will first automatically
.B erase
the chip, then write to it.
@@ -107,14 +107,14 @@
feel that the time for verification takes too long.
.sp
Typical usage is:
-.B "flashrom \-p prog \-n \-w <file>"
+.B "flashrom \-p prog \-n \-w <imagefile>"
.sp
This option is only useful in combination with
.BR \-\-write .
.TP
-.B "\-v, \-\-verify <file>"
+.B "\-v, \-\-verify <imagefile>"
Verify the flash ROM contents against the given
-.BR <file> .
+.BR <imagefile> .
.TP
.B "\-E, \-\-erase"
Erase the flash ROM chip.
@@ -144,7 +144,7 @@
.sp
* Force write even if write is known bad.
.TP
-.B "\-l, \-\-layout <file>"
+.B "\-l, \-\-layout <region>[:<file>]"
Read ROM layout from
.BR <file> .
.sp
@@ -289,6 +289,53 @@
in detail in the
.B PROGRAMMER-SPECIFIC INFORMATION
section. Support for some programmers can be disabled at compile time.
+.TP
+flashrom supports reading/writing/erasing/verifying flash chips in whole (default) or in part. To access only \
+parts of a chip one has to use layout files and respective arguments described below.
+.TP
+.B "\-l, \-\-layout <layoutfile>"
+Read layout entries from
+.BR <layoutfile> .
+.sp
+Each layout entry describes an address region of the flash chip and gives it a name (hereinafter referred to as
+a region). One entry per line is allowed with the following syntax:
+.sp
+.B " startaddr:endaddr regionname"
+.sp
+.BR "startaddr " "and " "endaddr "
+are hexadecimal addresses within the ROM image representing the flash ROM contents and do not refer to any
+physical address. Please note that using a 0x prefix for those hexadecimal numbers is not necessary, but you
+can't specify decimal/octal numbers.
+.BR "regionname " "is the name for the region from " "startaddr " "to " "endaddr " "(both addresses included)."
+Spaces, tabs, newlines, colons, single or double quotes are not allowed in region names.
+.sp
+Example content of file rom.layout:
+.sp
+ 0x00000000:0x00008fff gfx_rom
+ 0x00009000:0x0003ffff normal
+ 0x00040000:0x0007ffff fallback
+.sp
+.TP
+.B "\-i, \-\-include <name>[:<regionfile>]"
+Work on the flash region
+.B name
+instead of the full address space if a layout file is given and parsed correctly.
+Multiple such include parameters can be used to work on the union of different regions.
+.sp
+The optional
+.B regionfile
+parameter specifies the name of a file that is used to map the contents of that very region only.
+The optional file parameter causes the contents of this region to be replaced by the contents of the file
+specified here.
+.sp
+If you only want to update the regions named
+.BR "normal " "and " "gfx_rom " "in a ROM based on the layout mentioned above, run"
+.sp
+.B " flashrom \-p prog \-l rom.layout \-i normal -i "gfx_rom" \-w some.rom"
+.sp
+Overlapping regions are resolved in an implementation-dependent manner (or may even yield an error) - do
+.BR "not " "rely on it."
+.sp
.B "flashrom \-h"
lists all supported programmers.
.TP
diff --git a/flashrom.c b/flashrom.c
index 4db3767..cd976cf 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -1284,8 +1284,7 @@
return chip - flashchips;
}
-int read_buf_from_file(unsigned char *buf, unsigned long size,
- const char *filename)
+int read_buf_from_file(unsigned char *buf, unsigned long size, const char *filename, const char *size_msg)
{
#ifdef __LIBPAYLOAD__
msg_gerr("Error: No file I/O support in libpayload\n");
@@ -1308,6 +1307,10 @@
if (image_stat.st_size != size) {
msg_gerr("Error: Image size (%jd B) doesn't match the flash chip's size (%lu B)!\n",
(intmax_t)image_stat.st_size, size);
+ if (size_msg == NULL)
+ size_msg = "the expected size";
+ msg_gerr("Error: Image size (%jd B) doesn't match %s (%lu B)!\n",
+ (intmax_t)image_stat.st_size, size_msg, size);
ret = 1;
goto out;
}
@@ -1324,12 +1327,22 @@
#endif
}
-int write_buf_to_file(const unsigned char *buf, unsigned long size, const char *filename)
+/**
+ * @brief Writes included layout regions into buffer(s)
+ *
+ * If partial read to file is to be done (-i <region>[:<regionfile>] syntax
+ * used) then this will write to corresponding region-sized files. If an
+ * argument to -r/-w/-v is specified then it will write a chip-sized file. Both
+ * partial read/writes and full read/write may be done at once.
+ *
+ * @param buf Buffer with data to write
+ * @param size Size of buffer
+ * @param filename Filename corresponding to optional argument to -r/-w/-v
+ * @return 0 on success,
+ * 1 if any read fails.
+ */
+static int do_write_buf_to_file(const unsigned char *buf, unsigned long size, const char *filename)
{
-#ifdef __LIBPAYLOAD__
- msg_gerr("Error: No file I/O support in libpayload\n");
- return 1;
-#else
FILE *image;
int ret = 0;
@@ -1337,6 +1350,7 @@
msg_gerr("No filename specified.\n");
return 1;
}
+
if ((image = fopen(filename, "wb")) == NULL) {
msg_gerr("Error: opening file \"%s\" failed: %s\n", filename, strerror(errno));
return 1;
@@ -1373,8 +1387,61 @@
ret = 1;
}
return ret;
+}
+
+static const struct fl_layout *get_layout(const struct flashctx *const flashctx);
+/**
+ * @brief Writes content from buffer to one or more files.
+ *
+ * Writes content from supplied buffer to files. If a filename is specified for
+ * individual regions using the partial read syntax ('-i <region>[:<filename>]')
+ * then this will write files using data from the corresponding region in the
+ * supplied buffer. If a filename is specified for -r/-w/-e options then a chip-
+ * sized file will be created.
+ *
+ * @param flashctx Flash context to be used.
+ * @param buf Chip-sized buffer to read data from
+ * @param size Size of chip-sized buffer
+ * @param filename Optional filename corresponding to -r/-w/-v argument
+ * @return 0 on success,
+ * 1 if all available erase functions failed.
+ */
+int write_buf_to_file(struct flashctx *const flash, const unsigned char *buf, unsigned long size, const char *filename)
+{
+#ifdef __LIBPAYLOAD__
+ msg_gerr("Error: No file I/O support in libpayload\n");
+ return 1;
+#else
+ int ret = 0;
+ const struct fl_layout *const layout = get_layout(flash);
+
+ size_t i;
+ for (i = 0; i < layout->num_entries; i++) {
+ if (!layout->entries[i].included)
+ continue;
+ if (!layout->entries[i].file)
+ continue;
+
+ const chipoff_t region_start = layout->entries[i].start;
+ const chipsize_t region_len = layout->entries[i].end - layout->entries[i].start + 1;
+ const char *region_file = layout->entries[i].file;
+
+ ret = do_write_buf_to_file(buf + region_start, region_len, region_file);
+ if (ret)
+ goto out;
+ }
+
+ if (filename) {
+ ret = do_write_buf_to_file(buf, size, filename);
+ if (ret)
+ goto out;
+ }
+
+out:
+ return ret;
#endif
}
+
static int read_by_layout(struct flashctx *, uint8_t *);
int read_flash_to_file(struct flashctx *flash, const char *filename)
@@ -1400,7 +1467,7 @@
goto out_free;
}
- ret = write_buf_to_file(buf, size, filename);
+ ret = write_buf_to_file(flash, buf, size, filename);
out_free:
free(buf);
msg_cinfo("%s.\n", ret ? "FAILED" : "done");
@@ -2500,7 +2567,7 @@
goto _free_ret;
}
- if (read_buf_from_file(newcontents, flash_size, filename))
+ if (read_buf_from_file(newcontents, flash_size, filename, "the flash chip's size"))
goto _free_ret;
ret = fl_image_write(flash, newcontents, flash_size);
@@ -2521,7 +2588,7 @@
goto _free_ret;
}
- if (read_buf_from_file(newcontents, flash_size, filename))
+ if (read_buf_from_file(newcontents, flash_size, filename, "the flash chip's size"))
goto _free_ret;
ret = fl_image_verify(flash, newcontents, flash_size);
diff --git a/layout.c b/layout.c
index ab80bb8..6656b4b 100644
--- a/layout.c
+++ b/layout.c
@@ -50,7 +50,7 @@
romlayout = fopen(name, "r");
if (!romlayout) {
- msg_gerr("ERROR: Could not open ROM layout (%s).\n",
+ msg_gerr("ERROR: Could not open layout file (%s).\n",
name);
return -1;
}
@@ -59,8 +59,7 @@
char *tstr1, *tstr2;
if (layout.num_entries >= MAX_ROMLAYOUT) {
- msg_gerr("Maximum number of ROM images (%i) in layout "
- "file reached.\n", MAX_ROMLAYOUT);
+ msg_gerr("Maximum number of entries (%i) in layout file reached.\n", MAX_ROMLAYOUT);
(void)fclose(romlayout);
return 1;
}
@@ -82,6 +81,7 @@
layout.entries[layout.num_entries].start = strtol(tstr1, (char **)NULL, 16);
layout.entries[layout.num_entries].end = strtol(tstr2, (char **)NULL, 16);
layout.entries[layout.num_entries].included = 0;
+ layout.entries[layout.num_entries].file = NULL;
layout.num_entries++;
}
@@ -142,7 +142,6 @@
msg_gspew("Looking for region \"%s\"... ", name);
for (i = 0; i < fl_layout->num_entries; i++) {
if (!strcmp(fl_layout->entries[i].name, name)) {
- fl_layout->entries[i].included = 1;
msg_gspew("found.\n");
return i;
}
@@ -162,28 +161,71 @@
if (num_include_args == 0)
return 0;
- /* User has specified an area, but no layout file is loaded. */
+ /* User has specified an include argument, but no layout is loaded. */
if (fl_layout->num_entries == 0) {
- msg_gerr("Region requested (with -i \"%s\"), "
- "but no layout data is available.\n",
+ msg_gerr("Region requested (with -i/--include \"%s\"),\n"
+ "but no layout data is available. Use the -l/--layout parameter to specify\n"
+ "a layout file.\n",
include_args[0]);
return 1;
}
for (i = 0; i < num_include_args; i++) {
- if (find_romentry(fl_layout, include_args[i]) < 0) {
- msg_gerr("Invalid region specified: \"%s\".\n",
- include_args[i]);
+ char *name = include_args[i];
+ char *file = strpbrk(name, ":"); /* -i <region>[:<file>] */
+ if (file != NULL) {
+ *file = '\0';
+ file++;
+ }
+
+ /* Quotes or whitespace are not allowed in region names. */
+ if (strlen(name) == 0 || strpbrk(name, "\" \t\r\n")) {
+ msg_gerr("Invalid region name specified: \"%s\".\n", name);
return 1;
}
- found++;
+
+ int idx = find_romentry(fl_layout, name);
+ if (idx < 0) {
+ msg_gerr("Nonexisting region name specified: \"%s\".\n", name);
+ return 1;
+ }
+ if (fl_layout->entries[idx].included == 0) {
+ fl_layout->entries[idx].included = 1;
+ found++;
+ } else {
+ msg_gerr("Duplicate region name specified: \"%s\".\n", name);
+ return 1;
+ }
+
+ if (file) {
+ if (strlen(file) == 0) {
+ msg_gerr("Empty region file name specified for region \"%s\".\n", name);
+ return 1;
+ }
+#ifdef __LIBPAYLOAD__
+ msg_gerr("Error: No file I/O support in libpayload\n");
+ return 1;
+#else
+ file = strdup(file);
+ if (file == NULL) {
+ msg_gerr("Out of memory!\n");
+ return 1;
+ }
+ fl_layout->entries[idx].file = file;
+#endif
+ }
}
- msg_ginfo("Using region%s: \"%s\"", num_include_args > 1 ? "s" : "",
- include_args[0]);
- for (i = 1; i < num_include_args; i++)
- msg_ginfo(", \"%s\"", include_args[i]);
- msg_ginfo(".\n");
+ msg_gdbg("Using %i region%s: ", found, found > 1 ? "s" : "");
+ for (i = 0; i < fl_layout->num_entries; i++)
+ if (fl_layout->entries[i].included) {
+ msg_gdbg("\"%s\"", fl_layout->entries[i].name);
+ if (fl_layout->entries[i].file)
+ msg_gdbg(":\"%s\"", fl_layout->entries[i].file);
+ if (--found)
+ msg_gdbg(", ");
+ }
+ msg_gdbg(".\n");
return 0;
}
@@ -197,6 +239,8 @@
num_include_args = 0;
for (i = 0; i < layout.num_entries; i++) {
+ free(layout.entries[i].file);
+ layout.entries[i].file = NULL;
layout.entries[i].included = 0;
}
layout.num_entries = 0;
@@ -301,6 +345,15 @@
if (entry->start > start)
copy_old_content(flash, oldcontents_valid, oldcontents, newcontents, start,
entry->start - start);
+
+ /* If a file name is specified for this region, read the file contents and
+ * overwrite @newcontents in the range specified by @entry. */
+ if (entry->file != NULL) {
+ if (read_buf_from_file(newcontents + entry->start, entry->end - entry->start + 1,
+ entry->file, "the region's size") != 0)
+ return 1;
+ }
+
/* Skip to location after current romentry. */
start = entry->end + 1;
/* Catch overflow. */
diff --git a/layout.h b/layout.h
index 71bcac3..92cc6f5 100644
--- a/layout.h
+++ b/layout.h
@@ -40,6 +40,7 @@
chipoff_t end;
bool included;
char name[256];
+ char *file;
};
struct fl_layout {
--
To view, visit https://review.coreboot.org/19342
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic5465659605d8431d931053967b40290195cfd99
Gerrit-PatchSet: 1
Gerrit-Project: flashrom
Gerrit-Branch: staging
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>
David Hendricks has uploaded a new change for review. ( https://review.coreboot.org/19340 )
Change subject: Copy test_v2 directory from chromiumos branch
......................................................................
Copy test_v2 directory from chromiumos branch
This is a straight copy and should not be merged. The full patch
series will eventually be imported, but for now this is just a hack
to get stuff working.
Change-Id: I41bef98d32df61af400ecac46ea9571e722b2ac6
Signed-off-by: David Hendricks <dhendricks(a)fb.com>
---
A tests/tests_v2/cmd.sh
A tests/tests_v2/servo_hooks.sh
A tests/tests_v2/test_v2.sh
3 files changed, 1,371 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/40/19340/1
diff --git a/tests/tests_v2/cmd.sh b/tests/tests_v2/cmd.sh
new file mode 100755
index 0000000..1d1c47a
--- /dev/null
+++ b/tests/tests_v2/cmd.sh
@@ -0,0 +1,137 @@
+#!/bin/sh
+#
+# This file is part of the flashrom project. It is derived from
+# board_status.sh in coreboot.
+#
+# Copyright (C) 2016 Google Inc.
+# Copyright (C) 2014 Sage Electronic Engineering, LLC.
+
+USE_CUSTOM_HOOKS=0
+if [ -n "$CUSTOM_HOOKS_FILENAME" ]; then
+ USE_CUSTOM_HOOKS=1
+ . "$CUSTOM_HOOKS_FILENAME"
+ if [ $? -ne 0 ]; then
+ echo "Failed to source custom hooks file."
+ exit $EXIT_FAILURE
+ fi
+
+ if ! custom_hook_sanity_check; then
+ echo "Failed to run sanity check for custom hooks."
+ exit $EXIT_FAILURE
+ fi
+fi
+
+# test a command
+#
+# $1: 0 ($LOCAL) to run command locally,
+# 1 ($REMOTE) to run remotely if remote host defined
+# $2: command to test
+# $3: 0 ($FATAL) Exit with an error if the command fails
+# 1 ($NONFATAL) Don't exit on command test failure
+test_cmd()
+{
+ local rc
+ local cmd__="$(echo $2 | cut -d ' ' -f -1)"
+ local args="$(echo $2 | cut -d ' ' -f 2-)"
+
+ if [ -e "$cmd__" ]; then
+ return
+ fi
+
+ if [ "$1" -eq "$REMOTE" ] && [ -n "$REMOTE_HOST" ]; then
+ ssh $REMOTE_PORT_OPTION root@${REMOTE_HOST} command -v "$cmd__" $args > /dev/null 2>&1
+ rc=$?
+ else
+ command -v "$cmd__" $args >/dev/null 2>&1
+ rc=$?
+ fi
+
+ if [ $rc -eq 0 ]; then
+ return 0
+ fi
+
+ if [ "$3" = "1" ]; then
+ return 1
+ fi
+
+ echo "$2 not found"
+ exit $EXIT_FAILURE
+}
+
+# Same args as cmd() but with the addition of $4 which determines if the
+# command should be totally silenced or not.
+_cmd()
+{
+ local silent=$4
+ local rc=0
+
+ if [ -n "$3" ]; then
+ pipe_location="${3}"
+ else
+ pipe_location="/dev/null"
+ fi
+
+ if [ $1 -eq $REMOTE ] && [ -n "$REMOTE_HOST" ]; then
+ if [ $silent -eq 0 ]; then
+ ssh $REMOTE_PORT_OPTION "root@${REMOTE_HOST}" "$2" > "$pipe_location" 2>/dev/null
+ rc=$?
+ else
+ ssh $REMOTE_PORT_OPTION "root@${REMOTE_HOST}" "$2" >/dev/null 2>&1
+ rc=$?
+ fi
+ else
+ if [ $USE_CUSTOM_HOOKS -eq 1 ]; then
+ preflash_hook $1 "$2" "$3" $4
+ fi
+
+ if [ $silent -eq 0 ]; then
+ $SUDO_CMD $2 > "$pipe_location" 2>/dev/null
+ rc=$?
+ else
+ $SUDO_CMD $2 >/dev/null 2>&1
+ rc=$?
+ fi
+
+ if [ $USE_CUSTOM_HOOKS -eq 1 ]; then
+ postflash_hook $1 "$2" "$3" $4
+ fi
+ fi
+
+ return $rc
+}
+
+# run a command
+#
+# $1: 0 ($LOCAL) to run command locally,
+# 1 ($REMOTE) to run remotely if remote host defined
+# $2: command
+# $3: filename to direct output of command into
+cmd()
+{
+ _cmd $1 "$2" "$3" 0
+
+ if [ $? -eq 0 ]; then
+ return
+ fi
+
+ echo "Failed to run \"$2\", aborting"
+ rm -f "$3" # don't leave an empty file
+ return $EXIT_FAILURE
+}
+
+# run a command silently
+#
+# $1: 0 ($LOCAL) to run command locally,
+# 1 ($REMOTE) to run remotely if remote host defined
+# $2: command
+scmd()
+{
+ _cmd $1 "$2" "" 1
+
+ if [ $? -eq 0 ]; then
+ return
+ fi
+
+ echo "Failed to run \"$2\", aborting"
+ return $EXIT_FAILURE
+}
diff --git a/tests/tests_v2/servo_hooks.sh b/tests/tests_v2/servo_hooks.sh
new file mode 100644
index 0000000..01033e8
--- /dev/null
+++ b/tests/tests_v2/servo_hooks.sh
@@ -0,0 +1,128 @@
+#!/bin/sh
+#
+# Copyright (C) 2016 Google Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+# Voltage gets exported from test_v2.sh and is mandatory for Servo.
+if [ -z "$VOLTAGE" ]; then
+ echo "Must specify voltage when using Servo."
+ exit $EXIT_FAILURE
+fi
+
+# Users who have multiple Servos attached might need to override port.
+if [ -z "$SERVO_PORT" ]; then
+ SERVO_PORT="9999"
+fi
+
+# Servo's SPI1 channel targets the EC, SPI2 targets the host ROM.
+if [ -z "$SERVO_SPI" ]; then
+ SERVO_SPI="spi2"
+fi
+
+custom_hook_sanity_check()
+{
+ local rc=0
+
+ dut-control --port=${SERVO_PORT} ${SERVO_SPI}_buf_en ${SERVO_SPI}_buf_on_flex_en ${SERVO_SPI}_vref >/dev/null
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ printf "Servo sanity check failed. Some possible causes:\n"
+ printf "\t- Is servod running?\n"
+ printf "\t- If servod is not listening on port 9999, set SERVO_PORT as an environment variable.\n"
+ fi
+
+ return $rc
+}
+
+preflash_hook()
+{
+ local rc=0
+
+ dut-control --port=${SERVO_PORT} ${SERVO_SPI}_buf_en:on ${SERVO_SPI}_buf_on_flex_en:on ${SERVO_SPI}_vref:pp${VOLTAGE}
+ rc=$?
+ sleep 1
+
+ return $rc
+}
+
+postflash_hook()
+{
+ local rc=0
+
+ dut-control --port=${SERVO_PORT} ${SERVO_SPI}_buf_en:off ${SERVO_SPI}_buf_on_flex_en:off
+ rc=$?
+ sleep 1
+
+ return $rc
+}
+
+wp_sanity_check()
+{
+ local rc=0
+
+ dut-control --port=${SERVO_PORT} fw_wp_en fw_wp_vref fw_wp >/dev/null
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ printf "dut-control failed. Check that servod is running.\n"
+ fi
+
+ return $rc
+}
+
+wp_enable_hook()
+{
+ local rc=0
+
+ dut-control --port=${SERVO_PORT} fw_wp_en:on fw_wp_vref:pp${VOLTAGE}
+ rc=$?
+ sleep 1
+
+ return $rc
+}
+
+wp_on_hook()
+{
+ local rc=0
+
+ dut-control --port=${SERVO_PORT} fw_wp:on
+ rc=$?
+ sleep 1
+
+ return $rc
+}
+
+wp_off_hook()
+{
+ local rc=0
+
+ dut-control --port=${SERVO_PORT} fw_wp:off
+ rc=$?
+ sleep 1
+
+ return $rc
+}
+
+wp_disable_hook()
+{
+ local rc=0
+
+ dut-control --port=${SERVO_PORT} fw_wp_en:off fw_wp_vref:off
+ rc=$?
+ sleep 1
+
+ return $rc
+}
diff --git a/tests/tests_v2/test_v2.sh b/tests/tests_v2/test_v2.sh
new file mode 100755
index 0000000..4c15c36
--- /dev/null
+++ b/tests/tests_v2/test_v2.sh
@@ -0,0 +1,1106 @@
+#!/bin/sh
+#
+# Copyright (C) 2016 Google Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Documentation for this script currently resides at: https://goo.gl/qNwdmm
+
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+RC=$EXIT_SUCCESS
+FATAL=0
+NONFATAL=1
+
+#
+# Stuff obtained from command-line
+#
+
+# Generic options
+BACKUP_IMAGE=""
+OLD_FLASHROM=""
+NEW_FLASHROM=""
+NO_CLEAN=0
+SKIP_CONSISTENCY_CHECK=0
+UPLOAD_RESULTS=0
+
+# LOCAL_FLASHROM is required if both a secondary programmer *and* a remote host
+# are used since OLD_FLASHROM and NEW_FLASHROM will be called on the remote
+# host and we need a local copy of flashrom to control the secondary programmer.
+# By default this will be set to the result of `which flashrom`.
+LOCAL_FLASHROM=""
+
+# Primary/Secondary programmer options
+PRIMARY_OPTS=""
+SECONDARY_OPTS=""
+
+# Calls preflash_hook() and postflash_hook() before and after doing a command.
+CUSTOM_HOOKS_FILENAME=""
+
+# if doing wp test, we require the commands that the programmer uses to enable/disable wp
+WP_HOOKS_FILENAME=""
+
+# logfile to store the script's output
+SCRIPT_LOGFILE="flashrom-test_script_output.txt"
+
+# Information stored to restore dut WP state at the end of a writeprotect test.
+HW_WP_STATE=0
+SW_WP_STATE=0
+WP_RANGE_START=0
+WP_RANGE_LEN=0
+
+# Test type
+TEST_TYPE_UNKNOWN=0
+TEST_TYPE_SINGLE=1
+TEST_TYPE_ENDURANCE=2
+TEST_TYPE_WRITEPROTECT=3
+TEST_TYPE=$TEST_TYPE_UNKNOWN
+
+# Region modes
+REGION_MODE_UNKNOWN=0
+REGION_MODE_CLOBBER=1
+REGION_MODE_DESCRIPTOR=2
+REGION_MODE_FLASHMAP=3
+REGION_MODE_LAYOUT=4
+REGION_MODE=$REGION_MODE_UNKNOWN
+DESCRIPTOR_REGION="BIOS"
+FLASHMAP_REGION="RW_SECTION_A"
+LAYOUT_FILE=""
+LAYOUT_REGION="RW"
+SMALL_REGION=0
+
+# Remote testing options
+SSH_PORT=""
+REMOTE_HOST=""
+REMOTE_PORT_OPTION=""
+REMOTE_ONLY=0
+REMOTE_PROGRAMMER_PARAMS=""
+SSH_CMD="ssh $REMOTE_PORT_OPTION root@${REMOTE_HOST} command -v"
+
+LOCAL=0
+REMOTE=1
+DO_REMOTE=0 # boolean to use for cmd() and tests
+
+WP_DISABLE=0
+WP_ENABLE=1
+
+# In case we need to run flashrom locally and we're not already root.
+SUDO_CMD=""
+if [ "$(id -u)" -ne "0" ]; then
+ SUDO_CMD="sudo"
+fi
+
+# 1KB
+K=1024
+
+show_help() {
+ printf "Usage:
+ ${0} <options>
+
+General options:
+ -b, --backup-image <path>
+ Backup image to write unconditionally at end of testing.
+ -h, --help
+ Show this message.
+ -l, --layout-file <path>
+ Layout file (required if mode is \"layout\", resides locally).
+ -m, --mode <arg>
+ Region access mode (clobber, descriptor, flashmap, layout).
+ -n, --new <path>
+ Path to new version of flashrom.
+ -o, --old <path>
+ Path to old (stable) version of flashrom.
+ -p, --primary-programmer <parameters>
+ Primary programmer options.
+ -r, --remote-host <host>
+ Remote host to test primary programmer on.
+ -s, --secondary-programmer <parameters>
+ Secondary programmer options.
+ -t, --type <arg>
+ Test type (single, endurance, writeprotect).
+ -u, --upload-results
+ Upload results to flashrom.org.
+ -v, --voltage
+ Chip voltage in millivolts (usually 1800 or 3300).
+
+Long options:
+ --custom-hooks <filename>
+ Supply a script with custom hooks to run before and after commands.
+ --descriptor-region <name>
+ Specify region to use in descriptor mode (default: $DESCRIPTOR_REGION)
+ --flashmap-region <name>
+ Specify region to use in flashmap mode (default: $FLASHMAP_REGION)
+ --layout-region <name>
+ Specify region to use in layout mode (default: $LAYOUT_REGION)
+ --local-flashrom <path>
+ Path to local version of flashrom when using both a secondary programmer
+ and remote host (default: $($SUDO_CMD which flashrom))
+ --no-clean
+ Do not remove temporary files.
+ --skip-consistency-check
+ Skip the consistency check (two consecutive reads) at beginning.
+ --small-region
+ Omit tests that require large amounts of space (>16KB).
+ --wp-hooks <filename>
+ Supply a script with commands that the connected external programmer
+ uses to enable and disable write protect for the DUT. This is required
+ when running a write-protect test.
+Remote connectivity options:
+ --ssh-port <port>
+ Use a specific SSH port.
+
+See documentation for usage examples (TODO: Migrate https://goo.gl/3jNoL7
+to flashrom wiki).\n
+"
+}
+
+getopt -T
+if [ $? -ne 4 ]; then
+ printf "GNU-compatible getopt(1) required.\n"
+ exit $EXIT_FAILURE
+fi
+
+LONGOPTS="backup-image:,help,,new:,old:,remote-host:,upload-results:"
+LONGOPTS="${LONGOPTS},primary-programmer:,secondary-programmer:,local-flashrom:"
+LONGOPTS="${LONGOPTS},custom-hooks:,mode:,skip-consistency-check,small-region"
+LONGOPTS="${LONGOPTS},wp-hooks:,type:,voltage:"
+LONGOPTS="${LONGOPTS},layout-file:,descriptor-region:,flashmap-region:,layout-region:"
+LONGOPTS="${LONGOPTS},no-clean"
+LONGOPTS="${LONGOPTS},ssh-port:"
+
+ARGS=$(getopt -o b:hl:m:n:o:p:r:s:t:u -l "$LONGOPTS" -n "$0" -- "$@");
+if [ $? != 0 ] ; then printf "Terminating...\n" >&2 ; exit 1 ; fi
+eval set -- "$ARGS"
+while true ; do
+ case "$1" in
+ # Generic options
+ -b|--backup-image)
+ shift
+ BACKUP_IMAGE="$1"
+ ;;
+ -h|--help)
+ show_help
+ exit $EXIT_SUCCESS
+ ;;
+ -l|--layout-file)
+ shift
+ LAYOUT_FILE="$1"
+ ;;
+ -m|--mode)
+ shift
+ if [ "$1" = "clobber" ]; then
+ REGION_MODE=$REGION_MODE_CLOBBER
+ elif [ "$1" = "descriptor" ]; then
+ REGION_MODE=$REGION_MODE_DESCRIPTOR
+ elif [ "$1" = "flashmap" ]; then
+ REGION_MODE=$REGION_MODE_FLASHMAP
+ elif [ "$1" = "layout" ]; then
+ REGION_MODE=$REGION_MODE_LAYOUT
+ else
+ printf "Unknown mode: $1\n"
+ exit $EXIT_FAILURE
+ fi
+ ;;
+ -n|--new)
+ shift
+ NEW_FLASHROM="$1"
+ ;;
+ -o|--old)
+ shift
+ OLD_FLASHROM="$1"
+ ;;
+ -p|--primary_programmer)
+ shift
+ PRIMARY_OPTS="-p $1"
+ ;;
+ -s|--secondary_programmer)
+ shift
+ SECONDARY_OPTS="-p $1"
+ ;;
+ -t|--type)
+ shift
+ if [ "$1" = "single" ]; then
+ TEST_TYPE=$TEST_TYPE_SINGLE
+ elif [ "$1" = "endurance" ]; then
+ TEST_TYPE=$TEST_TYPE_ENDURANCE
+ elif [ "$1" = "writeprotect" ]; then
+ TEST_TYPE=$TEST_TYPE_WRITEPROTECT
+ else
+ printf "Unknown type: $1\n"
+ exit $EXIT_FAILURE
+ fi
+ ;;
+ -r|--remote-host)
+ DO_REMOTE=1
+ shift
+ REMOTE_HOST="$1"
+ ;;
+ -u|--upload-results)
+ UPLOAD_RESULTS=1
+ ;;
+ -v|--voltage)
+ shift
+ VOLTAGE="$1"
+ ;;
+
+ # Longopts only
+ --custom-hooks)
+ shift
+ CUSTOM_HOOKS_FILENAME="$1"
+ ;;
+ --descriptor-region)
+ shift
+ DESCRIPTOR_REGION="$1"
+ ;;
+ --flashmap-region)
+ shift
+ FLASHMAP_REGION="$1"
+ ;;
+ --layout-region)
+ shift
+ LAYOUT_REGION="$1"
+ ;;
+ --local-flashrom)
+ shift
+ LOCAL_FLASHROM="$1"
+ ;;
+ --no-clean)
+ NO_CLEAN=1
+ ;;
+ --skip-consistency-check)
+ SKIP_CONSISTENCY_CHECK=1
+ ;;
+ --small-region)
+ SMALL_REGION=1
+ ;;
+ --wp-hooks)
+ shift
+ WP_HOOKS_FILENAME="$1"
+ ;;
+
+ # Remote testing options
+ --ssh-port)
+ shift
+ REMOTE_PORT_OPTION="-p $1"
+ ;;
+
+ # error handling
+ --)
+ shift
+ if [ -n "$*" ]; then
+ printf "Non-option parameters detected: '$*'\n"
+ exit $EXIT_FAILURE
+ fi
+ break
+ ;;
+ *)
+ printf "error processing options at '$1'\n"
+ exit $EXIT_FAILURE
+ esac
+ shift
+done
+
+# TODO: Implement this.
+if [ $UPLOAD_RESULTS -eq 1 ]; then
+ printf "TODO: Implement ability to upload results.\n"
+ exit $EXIT_FAILURE
+fi
+
+#
+# Source helper scripts
+#
+export REMOTE_HOST REMOTE_PORT_OPTION
+export LOCAL REMOTE FATAL NONFATAL EXIT_SUCCESS EXIT_FAILURE
+export CUSTOM_HOOKS_FILENAME SUDO_CMD VOLTAGE
+. "$(pwd)/tests/tests_v2/cmd.sh"
+
+# We will set up a logs directory within the tmpdirs to store
+# all output logs.
+LOGS="logs"
+
+# Setup temporary working directories:
+# LOCAL_TMPDIR: Working directory on local host.
+# REMOTE_TMPDIR: Working directory on remote host.
+# TMPDIR: The temporary directy in which we do most of the work. This is
+# convenient for commands that depend on $DO_REMOTE.
+LOCAL_TMPDIR=$(mktemp -d --tmpdir flashrom_test.XXXXXXXX)
+if [ $? -ne 0 ] ; then
+ printf "Could not create temporary directory\n"
+ exit $EXIT_FAILURE
+fi
+mkdir "${LOCAL_TMPDIR}/${LOGS}"
+
+if [ $DO_REMOTE -eq 1 ]; then
+ REMOTE_TMPDIR=$(ssh root@${REMOTE_HOST} mktemp -d --tmpdir flashrom_test.XXXXXXXX)
+ if [ $? -ne 0 ] ; then
+ printf "Could not create temporary directory\n"
+ exit $EXIT_FAILURE
+ fi
+ scmd $REMOTE "mkdir ${REMOTE_TMPDIR}/${LOGS}"
+fi
+
+if [ $DO_REMOTE -eq 0 ]; then
+ TMPDIR="$LOCAL_TMPDIR"
+else
+ TMPDIR="$REMOTE_TMPDIR"
+fi
+
+#
+# Test command-line validity.
+#
+if [ $TEST_TYPE -eq $TEST_TYPE_UNKNOWN ]; then
+ printf "Must specify a test type (-t/--type).\n"
+ exit $EXIT_FAILURE
+elif [ $TEST_TYPE -eq $TEST_TYPE_SINGLE ]; then
+ if [ $REGION_MODE -eq $REGION_MODE_UNKNOWN ]; then
+ printf "Must specify a region access mode (-m/--mode).\n"
+ exit $EXIT_FAILURE
+ elif [ $REGION_MODE -eq $REGION_MODE_LAYOUT ]; then
+ if [ -z "$LAYOUT_FILE" ]; then
+ printf "Must specify a layout file when using layout mode.\n"
+ exit $EXIT_FAILURE
+ fi
+
+ scmd $DO_REMOTE "stat $LAYOUT_FILE"
+ if [ $? -ne 0 ]; then
+ if [ $DO_REMOTE -eq 1 ]; then
+ tmp=" on remote host $REMOTE_HOST."
+ else
+ tmp=" on local host."
+ fi
+ printf "Layout file $LAYOUT_FILE not found${tmp}\n"
+ exit $EXIT_FAILURE
+ fi
+
+ if [ $DO_REMOTE -eq 1 ]; then
+ scp root@"${REMOTE_HOST}:$LAYOUT_FILE" "${LOCAL_TMPDIR}/" 2>&1 >/dev/null
+ fi
+ fi
+elif [ $TEST_TYPE -eq $TEST_TYPE_WRITEPROTECT ]; then
+ if [ -z "$WP_HOOKS_FILENAME" ] || [ ! -e "$WP_HOOKS_FILENAME" ]; then
+ printf "Must specify a wp hooks file when doing a write-protect test.\n"
+ exit $EXIT_FAILURE
+ fi
+
+ if [ -z "$VOLTAGE" ]; then
+ printf "Voltage (mV) must be specified when testing write protection.\n"
+ exit $EXIT_FAILURE
+ fi
+
+ . "$WP_HOOKS_FILENAME"
+
+ wp_sanity_check
+ if [ $? -ne $EXIT_SUCCESS ]; then
+ printf "Write-protect sanity check failed.\n"
+ exit $EXIT_FAILURE
+ fi
+fi
+
+if [ -n "$VOLTAGE" ]; then
+ echo "$VOLTAGE" | grep -q '[^0-9]'
+ if [ $? -ne 1 ]; then
+ printf "Voltage must be an integer with units of millivolts."
+ exit $EXIT_FAILURE
+ fi
+fi
+
+if [ $DO_REMOTE -eq 1 ]; then
+ # Test connection to remote host
+ test_cmd $DO_REMOTE "ls /" $NONFATAL
+ if [ $? -ne 0 ]; then
+ printf "Could not connect to remote host ${REMOTE_HOST}\n"
+ exit $EXIT_FAILURE
+ fi
+fi
+
+# Remote host and secondary programmer are in use, so either the user must
+# specify a local version of flashrom to control the secondary programmer
+# or it must be found in the default path.
+if [ $DO_REMOTE -eq 1 ] && [ -n "$SECONDARY_OPTS" ]; then
+ if [ -z "$LOCAL_FLASHROM" ]; then
+ LOCAL_FLASHROM="$($SUDO_CMD which flashrom)"
+ fi
+
+ if [ ! -e "$LOCAL_FLASHROM" ]; then
+ printf "$LOCAL_FLASHROM does not exist\n"
+ exit $EXIT_FAILURE
+ fi
+fi
+
+#
+# Dependencies
+#
+
+# cmp is used to compare files
+test_cmd $DO_REMOTE "cmp" $FATAL
+
+if [ ! -e "/dev/urandom" ]; then
+ printf "This script uses /dev/urandom\n"
+ exit $EXIT_FAILURE
+fi
+
+if [ ! -e "/dev/zero" ]; then
+ printf "This script uses /dev/zero\n"
+ exit $EXIT_FAILURE
+fi
+
+#
+# Setup.
+#
+grep -rH 'projectname = .*flashrom' .git/config >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+ printf "Script must be run from root of flashrom directory\n"
+ exit $EXIT_FAILURE
+fi
+
+if [ -z "$OLD_FLASHROM" ]; then
+ if [ $DO_REMOTE -eq 1 ]; then
+ OLD_FLASHROM="$(ssh root@${REMOTE_HOST} which flashrom)"
+ else
+ OLD_FLASHROM="$($SUDO_CMD which flashrom)"
+ fi
+fi
+test_cmd $DO_REMOTE "$OLD_FLASHROM --help" $NONFATAL
+if [ $? -ne 0 ]; then
+ printf "Old flashrom binary is not usable.\n"
+ exit $EXIT_FAILURE
+fi
+
+# Check if both flashrom binaries support logging
+scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS --flash-name -o ${TMPDIR}/flash_name.txt"
+if [ $? -ne 0 ]; then
+ printf "Old flashrom binary does not support logging.\n"
+ exit $EXIT_FAILURE
+fi
+scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS --flash-name -o ${TMPDIR}/flash_name.txt"
+if [ $? -ne 0 ]; then
+ printf "New flashrom binary does not support logging.\n"
+ exit $EXIT_FAILURE
+fi
+scmd $DO_REMOTE "rm -f ${TMPDIR}/flash_name.txt"
+
+# print $1 and store it in the script log file
+print_and_log()
+{
+ printf "$1" | tee -a "${LOCAL_TMPDIR}/${LOGS}/${SCRIPT_LOGFILE}"
+}
+
+# Copy files from local tmpdir to remote host tmpdir
+copy_to_remote()
+{
+ for F in $@; do
+ scp "${LOCAL_TMPDIR}/${F}" root@"${REMOTE_HOST}:${REMOTE_TMPDIR}" 2>&1 >/dev/null
+ done
+}
+
+# Copy files from remote host tmpdir to local tmpdir
+copy_from_remote()
+{
+ for F in $@; do
+ scp root@"${REMOTE_HOST}:${REMOTE_TMPDIR}/${F}" "${LOCAL_TMPDIR}/" 2>&1 >/dev/null
+ done
+}
+
+# A wrapper for scmd calls to flashrom when we want to log the output
+# $1: 0 ($LOCAL) to run command locally,
+# 1 ($REMOTE) to run remotely if remote host defined
+# $2: arguments to be passed into scmd
+# $3: context of the flashrom call (to be used in the logfile)
+flashrom_log_scmd()
+{
+ local logfile="flashrom-${3}.txt"
+ local rc
+
+ if [ $1 -eq $REMOTE ]; then
+ tmpdir=$REMOTE_TMPDIR
+ else
+ tmpdir=$LOCAL_TMPDIR
+ fi
+
+ scmd $1 "$2 -o ${tmpdir}/${LOGS}/${logfile}"; rc=$?
+ # if the call was successful, we don't want to save the log (only save failure logs)
+ if [ $rc -eq $EXIT_SUCCESS ]; then
+ scmd $1 "rm -f ${tmpdir}/${LOGS}/${logfile}"
+ else
+ # if the log was stored remotely, we want to copy it over to local tmpdir
+ if [ $1 -eq $REMOTE ]; then
+ scp root@"${REMOTE_HOST}:${REMOTE_TMPDIR}/${LOGS}/${logfile}" "${LOCAL_TMPDIR}/${LOGS}" 2>&1 >/dev/null
+ fi
+ fi
+
+ return $rc
+}
+
+# Read current image as backup in case one hasn't already been specified.
+if [ -z "$BACKUP_IMAGE" ]; then
+ backup_file="backup.bin"
+ if [ $DO_REMOTE -eq 1 ]; then
+ BACKUP_IMAGE="${REMOTE_TMPDIR}/${backup_file}"
+ else
+ BACKUP_IMAGE="${LOCAL_TMPDIR}/${backup_file}"
+ fi
+
+ print_and_log "Reading backup image..."
+ flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -r $BACKUP_IMAGE" "read_backup"
+
+ if [ $? -ne 0 ]; then
+ print_and_log "Failed to read backup image, aborting.\n"
+ exit $EXIT_FAILURE
+ fi
+
+ if [ $DO_REMOTE -eq 1 ]; then
+ copy_from_remote "$backup_file"
+ fi
+else
+ if [ $DO_REMOTE -eq 1 ]; then
+ scmd $DO_REMOTE "cp $BACKUP_IMAGE $REMOTE_TMPDIR"
+ copy_from_remote "$(basename $BACKUP_IMAGE)"
+ fi
+fi
+
+# The copy of flashrom to test. If unset, we'll assume the user wants to test
+# a newly built flashrom binary in the current directory.
+if [ -z "$NEW_FLASHROM" ] ; then
+ if [ -x "flashrom" ]; then
+ NEW_FLASHROM="flashrom"
+ else
+ print_and_log "Must supply new flashrom version to test\n"
+ exit $EXIT_FAILURE
+ fi
+fi
+
+print_and_log "Stable flashrom binary: ${OLD_FLASHROM}\n"
+print_and_log "New flashrom binary to test: ${NEW_FLASHROM}\n"
+print_and_log "Local temporary files will be stored in ${LOCAL_TMPDIR}\n"
+if [ $DO_REMOTE -eq 1 ]; then
+ print_and_log "Remote temporary files will be stored in ${REMOTE_HOST}:${REMOTE_TMPDIR}\n"
+ print_and_log "Backup image: ${REMOTE_HOST}:${BACKUP_IMAGE}\n"
+ print_and_log "Backup image also stored at: ${LOCAL_TMPDIR}/$(basename ${BACKUP_IMAGE})\n"
+else
+ print_and_log "Backup image: ${BACKUP_IMAGE}\n"
+fi
+
+#
+# Now the fun begins.
+#
+cmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS --get-size" "${LOCAL_TMPDIR}/chip_size.txt"
+tmp=$(cat ${LOCAL_TMPDIR}/chip_size.txt)
+cmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS --get-size" "${LOCAL_TMPDIR}/chip_size.txt"
+CHIP_SIZE=$(cat ${LOCAL_TMPDIR}/chip_size.txt)
+CHIP_SIZE_KB=$(($CHIP_SIZE / $K))
+CHIP_SIZE_HALF=$(($CHIP_SIZE / 2))
+if [ $CHIP_SIZE -ne $tmp ]; then
+ print_and_log "New flashrom and old flashrom disagree on chip size. Aborting.\n"
+ exit $EXIT_FAILURE
+else
+ print_and_log "Chip size: $CHIP_SIZE_KB KiB\n"
+fi
+
+# Upload results
+#do_upload()
+#{
+# # TODO: implement this
+#}
+
+# Remove temporary files
+do_cleanup()
+{
+ if [ $NO_CLEAN -eq 1 ]; then
+ print_and_log "Skipping cleanup.\n"
+ return $EXIT_SUCCESS
+ fi
+
+ rm -rf "$LOCAL_TMPDIR"
+ if [ -n "$REMOTE_HOST" ]; then
+ ssh root@${REMOTE_HOST} rm -rf "$REMOTE_TMPDIR"
+ fi
+
+ return $EXIT_SUCCESS
+}
+
+# $1: Message to display to user.
+test_fail()
+{
+ print_and_log "$1\n"
+ printf "Skipping cleanup (logs saved).\n"
+ exit $EXIT_FAILURE
+}
+
+write_backup_image()
+{
+ print_and_log "Writing backup image.\n"
+ flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -w $BACKUP_IMAGE" "write_backup"
+}
+
+save_wp_state()
+{
+ print_and_log "Saving initial write protect state\n"
+ if [ $DO_REMOTE -eq $REMOTE ]; then
+ cmd $DO_REMOTE "crossystem wpsw_cur" "${LOCAL_TMPDIR}/hw_wp_state.txt"
+ HW_WP_STATE=$(cat ${LOCAL_TMPDIR}/hw_wp_state.txt )
+ fi
+
+ cmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS --wp-status" "${LOCAL_TMPDIR}/wp_range.txt"
+ if grep -q 'enabled' "${LOCAL_TMPDIR}/wp_range.txt"; then
+ SW_WP_STATE=1
+ else
+ SW_WP_STATE=0
+ fi
+
+ WP_RANGE_START=$(grep 'range' "${LOCAL_TMPDIR}/wp_range.txt" | grep -o -E 'start=0x[0-9]*' | cut -d '=' -f 2-)
+ WP_RANGE_LEN=$(grep 'range' "${LOCAL_TMPDIR}/wp_range.txt" | grep -o -E 'len=0x[0-9]*' | cut -d '=' -f 2-)
+}
+
+restore_wp_state()
+{
+ print_and_log "Restoring initial write protect state\n"
+ local restore_opts="--wp-range $WP_RANGE_START $WP_RANGE_LEN"
+
+ if [ $SW_WP_STATE -eq 1 ]; then
+ restore_opts="--wp-enable $restore_opts"
+ elif [ $SW_WP_STATE -eq 0 ]; then
+ restore_opts="--wp-disable $restore_opts"
+ fi
+
+ wp_enable_hook
+ wp_off_hook
+ scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS $restore_opts"
+ # if we are running on a remote machine, we stored the hw wp state and can restore now
+ if [ $DO_REMOTE -eq $REMOTE ] && [ $HW_WP_STATE -eq 1 ]; then
+ wp_on_hook
+ fi
+ wp_disable_hook
+}
+
+# $1 is 0/1 for disable/enable
+# $2 and $3 are range start and range length
+set_wp_state()
+{
+ local wp_opts="--wp-range $2 $3"
+ if [ $1 -eq $WP_DISABLE ]; then
+ wp_opts="--wp-disable $wp_opts"
+ elif [ $1 -eq $WP_ENABLE ]; then
+ wp_opts="--wp-enable $wp_opts"
+ else
+ #invalid argument
+ return $EXIT_FAILURE
+ fi
+
+ wp_enable_hook
+ wp_off_hook
+ scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS $wp_opts"
+ wp_on_hook
+ wp_disable_hook
+}
+
+# this saves us some repeated code in the writeprotect test
+# $1 is the message to be passed into test_fail()
+wp_test_fail()
+{
+ set_wp_state $WP_DISABLE 0 0 # completely disable wp so we can write the backup
+ write_backup_image
+ restore_wp_state # restore the fw and sw writeprotect states to the initial saved states.
+ test_fail "$1"
+}
+
+# Read a region twice and compare results
+# $1: address of region (in bytes)
+# $2: length of region (in bytes)
+double_read_test()
+{
+ local cmp1="${TMPDIR}/cmp1.bin"
+ local cmp2="${TMPDIR}/cmp2.bin"
+ local layout="double_read_test_layout.txt"
+ local len=$(($2 / $K))
+
+ print_and_log "Doing double read test, size: $len KiB\n"
+ # FIXME: Figure out how to do printf remotely...
+ printf "%06x:%06x region\n" $1 $(($1 + $2 - 1)) > "${LOCAL_TMPDIR}/${layout}"
+ if [ $DO_REMOTE -eq 1 ]; then copy_to_remote "$layout" ; fi
+
+ flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -r -l ${TMPDIR}/${layout} --ignore-fmap -i region:${cmp1}" "double_read_1"
+ # FIXME: second (or maybe third?) read should be done using secondary programmer, if applicable.
+ flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -r -l ${TMPDIR}/${layout} --ignore-fmap -i region:${cmp2}" "double_read_2"
+ scmd $DO_REMOTE "cmp $cmp1 $cmp2"
+ if [ $? -ne 0 ]; then
+ test_fail "Double-read test failed, aborting."
+ fi
+}
+
+PARTIAL_WRITE_TEST_REGION_SIZE=0
+PARTIAL_WRITE_TEST_ALIGN_SIZE_KB=0
+
+# helper function to reduce repetitiveness of partial_write_test
+partial_write_test_helper()
+{
+ local test_name="$1"
+ local offset_kb=$2
+ local size_kb=$3
+ local hex="$4"
+ local oct=""
+
+ oct="\\$(printf "%03o" $hex)"
+ cp "${LOCAL_TMPDIR}/random_4k_test.bin" "${LOCAL_TMPDIR}/${test_name}.bin"
+ dd if=/dev/zero bs=1k count=${size_kb} 2>/dev/null | tr "\000" "$oct" > "${LOCAL_TMPDIR}/${hex}_${size_kb}k.bin"
+ while [ $(($(($offset_kb + $size_kb)) * $K)) -lt $PARTIAL_WRITE_TEST_REGION_SIZE ]; do
+ dd if="${LOCAL_TMPDIR}/${hex}_${size_kb}k.bin" of="${LOCAL_TMPDIR}/${test_name}.bin" bs=1k count=${size_kb} seek=${offset_kb} conv=notrunc 2>/dev/null
+ offset_kb=$(($offset_kb + $PARTIAL_WRITE_TEST_ALIGN_SIZE_KB))
+ done
+}
+
+# Regional partial write test. Given a region name, this will write patterns
+# of bytes designed to test corner cases.
+#
+# We assume that eraseable block size can be either 4KB or 64KB and
+# must test for both. For simplicity, we'll assume the region size is
+# at least 256KB.
+#
+# $1: Region name
+partial_write_test()
+{
+ local opts="--fast-verify"
+ local secondary_opts="" # for secondary programmer
+ local region_name="$1"
+ local filename=""
+ local test_num=0
+ local prev_test_num=0
+
+ if [ $REGION_MODE -ne $REGION_MODE_FLASHMAP ]; then
+ opts="$opts --ignore-fmap"
+ fi
+
+ if [ $TEST_TYPE -eq $TEST_TYPE_SINGLE ]; then
+ if [ $REGION_MODE -eq $REGION_MODE_LAYOUT ]; then
+ opts="$opts -l $LAYOUT_FILE"
+ secondary_opts="$opts"
+ elif [ $REGION_MODE -eq $REGION_MODE_CLOBBER ]; then
+ printf "000000:%06x RW\n" $(($CHIP_SIZE - 1)) > "${LOCAL_TMPDIR}/clobber_mode_layout.txt"
+ if [ $DO_REMOTE -eq 1 ]; then
+ copy_to_remote "clobber_mode_layout.txt"
+ fi
+ secondary_opts="$opts -l ${LOCAL_TMPDIR}/clobber_mode_layout.txt"
+ opts="$opts -l ${TMPDIR}/clobber_mode_layout.txt"
+ fi
+ fi
+
+ if [ $SMALL_REGION -eq 1 ]; then
+ PARTIAL_WRITE_TEST_ALIGN_SIZE_KB=16
+ else
+ PARTIAL_WRITE_TEST_ALIGN_SIZE_KB=256
+ fi
+
+ # FIXME: Add sanity checks.
+
+ print_and_log "Doing region-based partial write test on region \"$region_name\"\n"
+ flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS $opts -r -i ${region_name}:${TMPDIR}/${region_name}.bin" "read_region_${region_name}"
+ if [ $DO_REMOTE -eq 1 ]; then
+ copy_from_remote "${region_name}.bin"
+ fi
+
+ PARTIAL_WRITE_TEST_REGION_SIZE=$(stat --format=%s ${LOCAL_TMPDIR}/${region_name}.bin)
+ if [ $PARTIAL_WRITE_TEST_REGION_SIZE -lt $(($PARTIAL_WRITE_TEST_ALIGN_SIZE_KB * $K)) ]; then
+ print_and_log "Region $region_name is too small\n"
+ return $EXIT_FAILURE
+ fi
+
+ if [ $(($PARTIAL_WRITE_TEST_REGION_SIZE % $(($PARTIAL_WRITE_TEST_ALIGN_SIZE_KB)))) -ne 0 ]; then
+ print_and_log "Region $region_name is not aligned to $PARTIAL_WRITE_TEST_ALIGN_SIZE_KB\n"
+ return $EXIT_FAILURE
+ fi
+
+ # Test procedure:
+ # Clobber region with random content first. Then do writes using the
+ # following sequences for each 128KB:
+ # 0-2K : 0x00 (\000) Partial 4KB sector, lower half
+ # 2K-6K : 0x11 (\021) Crossover 4KB sector boundary
+ # 6K-8K : 0x22 (\042) Partial 4KB sector, upper half
+ # 8K-16K : 0x33 (\063) Full 4KB sectors
+ #
+ # Repeat the above sequence for 64KB-aligned sizes
+ # 0-32K : 0x44 (\104) Partial 64KB block, lower half
+ # 32K-96K : 0x55 (\125) Crossover 64KB block boundary
+ # 96K-128K : 0x66 (\146) Partial 64KB block, upper half
+ # 128K-256K : 0x77 (\167) Full 64KB blocks
+
+ test_num=0
+ dd if=/dev/urandom of="${LOCAL_TMPDIR}/random_4k_test.bin" bs=4k count=$(($PARTIAL_WRITE_TEST_REGION_SIZE / $((4 * $K)))) 2>/dev/null
+
+ # 0-2K : 0x00 (\000) Partial 4KB sector, lower half
+ partial_write_test_helper "4k_test_${test_num}" 0 2 "0x00"
+ prev_test_num=$test_num
+ test_num=$(($test_num + 1))
+
+ # 2K-6K : 0x11 (\021) Crossover 4KB sector boundary
+ partial_write_test_helper "4k_test_${test_num}" 2 4 "0x11"
+ test_num=$(($test_num + 1))
+
+ # 6K-8K : 0x22 (\042) Partial 4KB sector, upper half
+ partial_write_test_helper "4k_test_${test_num}" 6 2 "0x22"
+ test_num=$(($test_num + 1))
+
+ # 8K-16K : 0x33 (\063) Full 4KB sectors
+ partial_write_test_helper "4k_test_${test_num}" 8 8 "0x33"
+
+ for F in ${LOCAL_TMPDIR}/random_4k_test.bin ${LOCAL_TMPDIR}/4k_test_*.bin ; do
+ filename=$(basename $F)
+ if [ $DO_REMOTE -eq 1 ]; then
+ copy_to_remote $filename
+ fi
+
+ flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS $opts -w -i ${region_name}:${TMPDIR}/${filename}" "write_${filename}"
+ if [ $? -ne 0 ]; then
+ test_fail "Failed to write $filename to $region_name"
+ fi
+
+ flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS $opts -v -i ${region_name}:${TMPDIR}/${filename}" "verify_${filename}"
+ if [ $? -ne 0 ]; then
+ test_fail "Failed to verify write of $filename to $region_name"
+ fi
+
+ if [ -n "$SECONDARY_OPTS" ]; then
+ flashrom_log_scmd $LOCAL "$LOCAL_FLASHROM $SECONDARY_OPTS $secondary_opts -v -i ${region_name}:${LOCAL_TMPDIR}/${filename}" "verify_secondary_${filename}"
+ if [ $? -ne 0 ]; then
+ test_fail "Failed to verify write of $filename to $region_name using secondary programmer"
+ fi
+ fi
+
+ print_and_log "\tWrote $filename to $region_name region successfully.\n"
+ done
+
+ if [ $SMALL_REGION -eq 1 ]; then
+ return $EXIT_SUCCESS
+ fi
+
+ #
+ # Second half: Tests for 64KB chunks
+ #
+ test_num=0
+ dd if=/dev/urandom of="${LOCAL_TMPDIR}/random_64k_test.bin" bs=128k count=$(($PARTIAL_WRITE_TEST_REGION_SIZE / $((128*$K)))) 2>/dev/null
+
+ # 0-32K : 0x44 (\104) Partial 64KB block, lower half
+ partial_write_test_helper "64k_test_${test_num}" 0 32 "0x44"
+ prev_test_num=$test_num
+ test_num=$(($test_num + 1))
+
+ # 32K-96K : 0x55 (\125) Crossover 64KB block boundary
+ partial_write_test_helper "64k_test_${test_num}" 32 64 "0x55"
+ test_num=$(($test_num + 1))
+
+ # 96K-128K : 0x66 (\146) Partial 64KB block, upper half
+ partial_write_test_helper "64k_test_${test_num}" 96 32 "0x66"
+ test_num=$(($test_num + 1))
+
+ # 128K-256K : 0x77 (\167) Full 64KB blocks
+ partial_write_test_helper "64k_test_${test_num}" 128 128 "0x77"
+
+ for F in ${LOCAL_TMPDIR}/random_64k_test.bin ${LOCAL_TMPDIR}/64k_test_*.bin ; do
+ filename=$(basename $F)
+ if [ $DO_REMOTE -eq 1 ]; then
+ copy_to_remote $filename
+ fi
+
+ flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS $opts -w -i ${region_name}:${TMPDIR}/${filename}" "write_${filename}"
+ if [ $? -ne 0 ]; then
+ test_fail "Failed to write $filename to $region_name"
+ fi
+
+ flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS $opts -v -i ${region_name}:${TMPDIR}/${filename}" "verify_${filename}"
+ if [ $? -ne 0 ]; then
+ test_fail "Failed to verify write of $filename to $region_name"
+ fi
+
+ if [ -n "$SECONDARY_OPTS" ]; then
+ flashrom_log_scmd $LOCAL "$LOCAL_FLASHROM $SECONDARY_OPTS $secondary_opts -v -i ${region_name}:${LOCAL_TMPDIR}/${filename}" "verify_secondary_${filename}"
+ if [ $? -ne 0 ]; then
+ test_fail "Failed to verify write of $filename to $region_name using secondary programmer"
+ fi
+ fi
+
+ print_and_log "\tWrote $filename to $region_name region successfully.\n"
+ done
+
+ return $EXIT_SUCCESS
+}
+
+# Before anything else, check to see if Flashrom can succesfully probe
+# for and find the flash chips. If not, we will abort.
+flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS" "verify_probe"
+if [ $? -ne 0 ]; then
+ test_fail "Failed to find flash chips while probing, aborting."
+fi
+
+# Read ROM twice to test for consistency.
+if [ $SKIP_CONSISTENCY_CHECK -eq 0 ]; then
+ double_read_test 0 $CHIP_SIZE
+fi
+
+if [ $TEST_TYPE -eq $TEST_TYPE_SINGLE ]; then
+ if [ $REGION_MODE -eq $REGION_MODE_CLOBBER ]; then
+ random_file="${TMPDIR}/random_${CHIP_SIZE_KB}K.bin"
+ cmp_file="${TMPDIR}/cmp.bin"
+
+ scmd $DO_REMOTE "dd if=/dev/urandom of=${random_file} bs=1k count=${CHIP_SIZE_KB}"
+ flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -w $random_file" "clobber_write"
+ flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -r $cmp_file" "clobber_verify"
+ scmd $DO_REMOTE "cmp $random_file $cmp_file"
+ if [ $? -ne 0 ]; then
+ write_backup_image
+ test_fail "Failed to clobber entire ROM."
+ fi
+ scmd $DO_REMOTE "rm -f $cmp_file $random_file"
+
+ partial_write_test "RW"
+ if [ $? -ne 0 ]; then
+ print_and_log "Layout mode test failed\n"
+ RC=$EXIT_FAILURE
+ fi
+ elif [ $REGION_MODE -eq $REGION_MODE_DESCRIPTOR ]; then
+ # FIXME: This depends on descriptor regions being translated into internal
+ # layout representation automatically so we can target them using -i.
+ print_and_log "TODO: Descriptor mode\n"
+ exit $EXIT_FAILURE
+ elif [ $REGION_MODE -eq $REGION_MODE_FLASHMAP ]; then
+ partial_write_test "$FLASHMAP_REGION" 0
+ if [ $? -ne 0 ]; then
+ print_and_log "Flashmap mode test failed\n"
+ RC=$EXIT_FAILURE
+ fi
+ elif [ $REGION_MODE -eq $REGION_MODE_LAYOUT ]; then
+ rw_layout=""
+ addr=""
+ end=""
+ size=""
+ size_kb=""
+
+ # Look for a region name with any amount of leading whitespace
+ # and no trailing whitespace or characters.
+ rw_layout=$(grep "\s${LAYOUT_REGION}$" "${LOCAL_TMPDIR}/$(basename $LAYOUT_FILE)" | head -n 1)
+ if [ -z "$rw_layout" ]; then
+ print_and_log "No region matching \"${LAYOUT_REGION}\" found layout file \"${LAYOUT_FILE}\"\n"
+ test_fail ""
+ fi
+
+ addr="0x$(echo "$rw_layout" | cut -d ' ' -f -1 | awk -F ':' '{ print $1 }')"
+ end="0x$(echo "$rw_layout" | cut -d ' ' -f -1 | awk -F ':' '{ print $2 }')"
+ size="$(($end - $addr + 1))"
+ size_kb="$(($size / $K))"
+
+ print_and_log "\"$LAYOUT_REGION\" region address: ${addr}, size: $size_kb KiB\n"
+ partial_write_test "$LAYOUT_REGION"
+ if [ $? -ne 0 ]; then
+ print_and_log "Layout mode test failed\n"
+ RC=$EXIT_FAILURE
+ fi
+ fi
+elif [ $TEST_TYPE -eq $TEST_TYPE_ENDURANCE ]; then
+ iteration=1
+ terminate=0
+ random_file="${TMPDIR}/random_${CHIP_SIZE_KB}K.bin"
+ cmp_file="${TMPDIR}/cmp.bin"
+ # TODO: We can measure how long the tests take on average, throughput, etc.
+ # i.e. { time $NEW_FLASHROM $PRIMARY_OPTS -w $random_file ; } 2>&1 | grep user | cut -f2
+
+ # For this test we want to run clobber mode until failure
+ while [ $terminate -eq 0 ]
+ do
+ print_and_log "Running iteration #${iteration}\n"
+
+ scmd $DO_REMOTE "dd if=/dev/urandom of=${random_file} bs=1k count=${CHIP_SIZE_KB}"
+ flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -w $random_file" "endurance_write_${iteration}"
+ flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -r $cmp_file" "endurance_verify_${iteration}"
+ scmd $DO_REMOTE "cmp $random_file $cmp_file"
+ if [ $? -ne 0 ]; then
+ terminate=1
+ fi
+ scmd $DO_REMOTE "rm -f $cmp_file $random_file"
+
+ iteration=$(($iteration + 1))
+ done
+
+ # TODO: Determine what to return for the endurance test exit status
+ # i.e. what constitutes a test pass and what constitutes a test fail?
+ print_and_log "Failed on iteration $iteration\n"
+ # TODO - Print performance metrics?
+elif [ $TEST_TYPE -eq $TEST_TYPE_WRITEPROTECT ]; then
+ random_file_protect="${TMPDIR}/random_${CHIP_SIZE_KB}K_protect.bin"
+ random_file_clobber1="${TMPDIR}/random_${CHIP_SIZE_KB}K_clobber1.bin"
+ random_file_clobber2="${TMPDIR}/random_${CHIP_SIZE_KB}K_clobber2.bin"
+ cmp_file="${TMPDIR}/cmp.bin"
+
+ # generate random files
+ scmd $DO_REMOTE "dd if=/dev/urandom of=$random_file_protect bs=1k count=${CHIP_SIZE_KB}"
+ scmd $DO_REMOTE "dd if=/dev/urandom of=$random_file_clobber1 bs=1k count=${CHIP_SIZE_KB}"
+ scmd $DO_REMOTE "dd if=/dev/urandom of=$random_file_clobber2 bs=1k count=${CHIP_SIZE_KB}"
+
+ save_wp_state
+ set_wp_state $WP_DISABLE 0 0
+
+ # clobber ROM with an initial file
+ print_and_log "Clobbering ROM with random initial content\n"
+ flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -w $random_file_protect" "writeprotect_initial_write"
+ flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -r $cmp_file" "writeprotect_initial_verify"
+ scmd $DO_REMOTE "cmp $random_file_protect $cmp_file"
+ if [ $? -ne 0 ]; then
+ wp_test_fail "Failed to clobber ROM initially."
+ fi
+ scmd $DO_REMOTE "rm -f $cmp_file"
+
+ # Protect lower half of ROM, then try clobbering.
+ print_and_log "Starting lower half test\n"
+ set_wp_state $WP_ENABLE 0 $CHIP_SIZE_HALF
+ flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -n -w $random_file_clobber1" "writeprotect_enable_lower_write"
+ flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -r $cmp_file" "writeprotect_enable_lower_verify"
+ scmd $DO_REMOTE "cmp --bytes=$CHIP_SIZE_HALF $random_file_protect $cmp_file"
+ if [ $? -ne 0 ]; then
+ wp_test_fail "Failed to protect lower half of ROM - exiting writeprotect test."
+ fi
+ scmd $DO_REMOTE "cmp --ignore-initial=$CHIP_SIZE_HALF --bytes=$CHIP_SIZE_HALF $random_file_clobber1 $cmp_file"
+ if [ $? -ne 0 ]; then
+ wp_test_fail "Failed to clobber upper half of ROM - exiting writeprotect test."
+ fi
+ scmd $DO_REMOTE "rm -f $cmp_file"
+
+ # Protect upper half of ROM, then try clobbering.
+ print_and_log "Starting upper half test\n"
+ set_wp_state $WP_ENABLE $CHIP_SIZE_HALF $CHIP_SIZE_HALF
+ flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS -n -w $random_file_clobber2" "writeprotect_enable_upper_write"
+ flashrom_log_scmd $DO_REMOTE "$OLD_FLASHROM $PRIMARY_OPTS -r $cmp_file" "writeprotect_enable_upper_verify"
+ scmd $DO_REMOTE "cmp --bytes=$CHIP_SIZE_HALF $random_file_clobber2 $cmp_file"
+ if [ $? -ne 0 ]; then
+ wp_test_fail "Failed to clobber lower half of ROM - exiting writeprotect test."
+ fi
+ scmd $DO_REMOTE "cmp --ignore-initial=$CHIP_SIZE_HALF --bytes=$CHIP_SIZE_HALF $random_file_clobber1 $cmp_file"
+ if [ $? -ne 0 ]; then
+ wp_test_fail "Failed to protect upper half of ROM - exiting writeprotect test."
+ fi
+ scmd $DO_REMOTE "rm -f $cmp_file"
+
+ set_wp_state $WP_DISABLE 0 0 # completely disable wp so we can write the backup
+fi
+
+# restore and cleanup
+write_backup_image
+if [ $TEST_TYPE -eq $TEST_TYPE_WRITEPROTECT ]; then
+ restore_wp_state # restore the fw and sw writeprotect states to the initial saved states.
+fi
+
+if [ $RC -eq 0 ]; then
+ print_and_log "Test status: PASS\n"
+else
+ print_and_log "Test status: FAIL\n"
+fi
+do_cleanup
+
+exit $RC
--
To view, visit https://review.coreboot.org/19340
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I41bef98d32df61af400ecac46ea9571e722b2ac6
Gerrit-PatchSet: 1
Gerrit-Project: flashrom
Gerrit-Branch: staging
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>