summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHung-Te Lin <hungte@chromium.org>2018-08-21 23:26:33 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-09-05 09:15:17 -0700
commit48e48b777a8e8ec7603829805b3939b8d771f0c8 (patch)
tree9aa6b47ce5d22d74a5ee6bb96bf9645e5ae322a7
parent7fbbf2df700d0ab8f984114d535445c16a3d9699 (diff)
downloadvboot-48e48b777a8e8ec7603829805b3939b8d771f0c8.tar.gz
futility: cmd_update: Use real system write protection status
The updater logic is heavily based on write protection status. The write protection must be decided by two sources: hardware ("write protection switch", known as `wpsw` in crossystem) and software (on most SPI, this is controlled by SRP0 register using flashrom). When debugging firmware updating issues, it is very important to have complete logs for status of all WP sources (hw and sw, and the final decision by updater itself - maybe overridden by --wp). This change tries to handle WP properly and also leaving enough information of how the WP logic was decided. BUG=chromium:875551 TEST=make futil; tests/futility/run_test_scripts.sh $(pwd)/build/futility BRANCH=None Change-Id: I15dc2dbcefc421c1194aa623e15f00d793653e93 Signed-off-by: Hung-Te Lin <hungte@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1183658 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--futility/cmd_update.c104
1 files changed, 97 insertions, 7 deletions
diff --git a/futility/cmd_update.c b/futility/cmd_update.c
index 9172763a..95832a72 100644
--- a/futility/cmd_update.c
+++ b/futility/cmd_update.c
@@ -18,7 +18,9 @@
#include "host_misc.h"
#include "utility.h"
+#define COMMAND_BUFFER_SIZE 256
#define RETURN_ON_FAILURE(x) do {int r = (x); if (r) return r;} while (0);
+#define FLASHROM_OUTPUT_WP_PATTERN "write protect is "
/* FMAP section names. */
static const char * const FMAP_RO_FRID = "RO_FRID",
@@ -37,7 +39,11 @@ static const char * const FMAP_RO_FRID = "RO_FRID",
/* System environment values. */
static const char * const FWACT_A = "A",
- * const FWACT_B = "B";
+ * const FWACT_B = "B",
+ * const FLASHROM_OUTPUT_WP_ENABLED =
+ FLASHROM_OUTPUT_WP_PATTERN "enabled",
+ * const FLASHROM_OUTPUT_WP_DISABLED =
+ FLASHROM_OUTPUT_WP_PATTERN "disabled";
/* flashrom programmers. */
static const char * const PROG_HOST = "host",
@@ -64,6 +70,7 @@ enum active_slot {
enum flashrom_ops {
FLASHROM_READ,
FLASHROM_WRITE,
+ FLASHROM_WP_STATUS,
};
struct firmware_image {
@@ -103,6 +110,59 @@ struct updater_config {
struct system_property system_properties[SYS_PROP_MAX];
};
+/*
+ * Strip a string (usually from shell execution output) by removing all the
+ * trailing space characters (space, new line, tab, ... etc).
+ */
+static void strip(char *s)
+{
+ int len;
+ assert(s);
+
+ len = strlen(s);
+ while (len-- > 0) {
+ if (!isascii(s[len]) || !isspace(s[len]))
+ break;
+ s[len] = '\0';
+ }
+}
+
+/*
+ * Executes a command on current host and returns stripped command output.
+ * If the command has failed (exit code is not zero), returns an empty string.
+ * The caller is responsible for releasing the returned string.
+ */
+static char *host_shell(const char *command)
+{
+ /* Currently all commands we use do not have large output. */
+ char buf[COMMAND_BUFFER_SIZE];
+
+ int result;
+ FILE *fp = popen(command, "r");
+
+ Debug("%s: %s\n", __FUNCTION__, command);
+ buf[0] = '\0';
+ if (!fp) {
+ Debug("%s: Execution error for %s.\n", __FUNCTION__, command);
+ return strdup(buf);
+ }
+
+ if (fgets(buf, sizeof(buf), fp))
+ strip(buf);
+ result = pclose(fp);
+ if (!WIFEXITED(result) || WEXITSTATUS(result) != 0) {
+ Debug("%s: Execution failure with exit code %d: %s\n",
+ __FUNCTION__, WEXITSTATUS(result), command);
+ /*
+ * Discard all output if command failed, for example command
+ * syntax failure may lead to garbage in stdout.
+ */
+ buf[0] = '\0';
+ }
+ return strdup(buf);
+}
+
+
/* An helper function to return "mainfw_act" system property. */
static int host_get_mainfw_act()
{
@@ -122,8 +182,14 @@ static int host_get_mainfw_act()
/* A helper function to return the "hardware write protection" status. */
static int host_get_wp_hw()
{
- /* TODO(hungte) Implement this with calling VbGetSystemPropertyInt . */
- return WP_ENABLED;
+ /* wpsw refers to write protection 'switch', not 'software'. */
+ int v = VbGetSystemPropertyInt("wpsw_cur");
+
+ /* wpsw_cur may be not available, especially in recovery mode. */
+ if (v < 0)
+ v = VbGetSystemPropertyInt("wpsw_boot");
+
+ return v;
}
/*
@@ -134,7 +200,7 @@ static int host_flashrom(enum flashrom_ops op, const char *image_path,
const char *programmer, int verbose,
const char *section_name)
{
- char *command;
+ char *command, *result;
const char *op_cmd, *dash_i = "-i", *postfix = "", *ignore_lock = "";
int r;
@@ -164,6 +230,15 @@ static int host_flashrom(enum flashrom_ops op, const char *image_path,
assert(image_path);
break;
+ case FLASHROM_WP_STATUS:
+ op_cmd = "--wp-status";
+ assert(image_path == NULL);
+ image_path = "";
+ /* grep is needed because host_shell only returns 1 line. */
+ postfix = " 2>/dev/null | grep \"" \
+ FLASHROM_OUTPUT_WP_PATTERN "\"";
+ break;
+
default:
assert(0);
return -1;
@@ -184,16 +259,31 @@ static int host_flashrom(enum flashrom_ops op, const char *image_path,
if (verbose)
printf("Executing: %s\n", command);
- r = system(command);
+ if (op != FLASHROM_WP_STATUS) {
+ r = system(command);
+ free(command);
+ return r;
+ }
+
+ result = host_shell(command);
+ strip(result);
free(command);
+ Debug("%s: wp-status: %s\n", __FUNCTION__, result);
+
+ if (strstr(result, FLASHROM_OUTPUT_WP_ENABLED))
+ r = WP_ENABLED;
+ else if (strstr(result, FLASHROM_OUTPUT_WP_DISABLED))
+ r = WP_DISABLED;
+ else
+ r = -1;
+ free(result);
return r;
}
/* Helper function to return software write protection switch status. */
static int host_get_wp_sw()
{
- /* TODO(hungte) Implement this with calling flashrom. */
- return WP_ENABLED;
+ return host_flashrom(FLASHROM_WP_STATUS, NULL, PROG_HOST, 0, NULL);
}
/*