summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Vertescher <mvertescher@google.com>2022-10-24 11:19:35 -0700
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-12-07 09:22:45 +0000
commit8ee9891e13fe841b9d2e93acecf6783d2c19b05c (patch)
tree83104bc746e04ceee00bd35c36157b60ad435334
parent3c32038a5fd72f538923bf235d3f819d9fdb3f58 (diff)
downloadchrome-ec-factory-nissa-15199.B-cr50_stab.tar.gz
gsctool: Add AP RO verify write protect descriptors config commandfactory-nissa-15199.B-cr50_stab
This patch adds the ability to get and set the AP RO verification write protect descriptors registers from `gsctool` by adding a new `-E` command flag with an optional argument. BUG=b:250972056 TEST=Running gsctool locally to set and get the write protect descriptors to verify communication and handlers are working properly: $ gsctool -D -E ... not provisioned $ gsctool -D -E "0xff 0xf" ... expected values: 1: ff & 0f $ gsctool -D -E "ff 0f f" ... Invalid the write protect descriptors hex string length $ gsctool -D -E "ff f 0x00 ff" ... $ gsctool -D -E ... expected values: 1: ff & 0f, 2: 00 & ff $ gsctool -D -E "0xff 0xf 0x00 0xff 0xf0 f0" ... $ gsctool -D -E ... expected values: 1: ff & 0f, 2: 00 & ff, 3: f0 & f0 Signed-off-by: Matt Vertescher <mvertescher@google.com> Change-Id: I0d7cc6a98d6cf442592a1b9b81ef1c86193dd068 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3983416 Reviewed-by: Mary Ruthven <mruthven@chromium.org> Tested-by: Jett Rink <jettrink@chromium.org> Commit-Queue: Jett Rink <jettrink@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org> (cherry picked from commit 2a657bc6b1a9d0f28b74e2c538fa0149dd4bd4bb) Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4084743 Reviewed-by: Victor Ding <victording@chromium.org> Commit-Queue: Sam McNally <sammc@chromium.org> Commit-Queue: Victor Ding <victording@chromium.org> Auto-Submit: Sam McNally <sammc@chromium.org> Tested-by: Sam McNally <sammc@chromium.org>
-rw-r--r--extra/usb_updater/gsctool.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/extra/usb_updater/gsctool.c b/extra/usb_updater/gsctool.c
index 24efaeb747..0492bc309a 100644
--- a/extra/usb_updater/gsctool.c
+++ b/extra/usb_updater/gsctool.c
@@ -357,6 +357,33 @@ enum arv_config_spi_addr_mode_choice_e {
};
/*
+ * AP RO verification write protect descriptor configuration choices
+ */
+enum arv_config_wpsr_choice_e {
+ arv_config_wpsr_choice_none = 0,
+ arv_config_wpsr_choice_get = 1,
+ arv_config_wpsr_choice_set = 2,
+};
+
+/*
+ * AP RO verification write protect descriptor information
+ */
+struct __attribute__((__packed__)) arv_config_wpd {
+ /* See `arv_config_setting_state_e` */
+ uint8_t state;
+ uint8_t expected_value;
+ uint8_t mask;
+};
+
+/*
+ * AP RO verification write protect descriptors. This is a helper type to
+ * represent the three write protect descriptors.
+ */
+struct __attribute__((__packed__)) arv_config_wpds {
+ struct arv_config_wpd data[3];
+};
+
+/*
* This by far exceeds the largest vendor command response size we ever
* expect.
*/
@@ -417,6 +444,11 @@ static const struct option_container cmd_line_options[] = {
"RW and RO headers, do not update"},
{{"apro_config_spi_mode", optional_argument, NULL, 'C'},
"Get/set the ap ro verify spi mode either to `3byte` or `4byte`"},
+ {{"apro_config_write_protect", optional_argument, NULL,
+ 'E'},
+ "Get/set the ap ro verify write protect descriptors with hex "
+ "bytes (ex: 0x01, 0x1, 01 or 1) in the following format: "
+ "[sr1 mask1 [sr2 mask2] [sr3 mask3]]"},
{{"corrupt", no_argument, NULL, 'c'},
"Corrupt the inactive rw"},
{{"dauntless", no_argument, NULL, 'D'},
@@ -2763,6 +2795,167 @@ static int process_arv_config_spi_addr_mode(struct transfer_descriptor *td,
return 0;
}
+/*
+ * Reads an ascii hex byte in the following forms:
+ * - 0x01
+ * - 0x1
+ * - 01
+ * - 0
+ *
+ * 1 is returned on success, 0 on failure.
+ */
+static int read_hex_byte_string(char *s, uint8_t *byte)
+{
+ uint8_t b = 0;
+
+ if (!strncmp(s, "0x", 2))
+ s += 2;
+
+ if (strlen(s) == 0)
+ return 0;
+
+ for (const char *end = s + 2; s < end; ++s) {
+ if (*s >= '0' && *s <= '9')
+ b = b * 16 + *s - '0';
+ else if (*s >= 'A' && *s <= 'F')
+ b = b * 16 + 10 + *s - 'A';
+ else if (*s >= 'a' && *s <= 'f')
+ b = b * 16 + 10 + *s - 'a';
+ else if (*s == '\0')
+ /* Single nibble, do nothing instead of `break`
+ * to keep checkpatch happy
+ */
+ ;
+ else
+ /* Invalid nibble */
+ return 0;
+ }
+ *byte = b;
+ return 1;
+}
+
+static int parse_wpsrs(const char *opt, struct arv_config_wpds *wpds)
+{
+ size_t len = strlen(opt);
+ char *ptr, *p, *delim = " ";
+ uint8_t b;
+ int rv = 0;
+ struct arv_config_wpd *wpd;
+
+ ptr = malloc(len + 1);
+ strcpy(ptr, opt);
+ p = strtok(ptr, delim);
+
+ while (p != NULL) {
+ if (read_hex_byte_string(p, &b)) {
+ wpd = &wpds->data[rv / 2];
+ if (rv % 2 == 0) {
+ wpd->expected_value = b;
+ } else {
+ wpd->mask = b;
+ wpd->state =
+ arv_config_setting_state_present;
+ }
+ rv++;
+ } else {
+ break;
+ }
+ p = strtok(NULL, delim);
+ }
+ free(ptr);
+
+ return rv;
+}
+
+static void print_wpd(size_t i, struct arv_config_wpd *wpd)
+{
+ if (wpd->state ==
+ arv_config_setting_state_not_present) {
+ printf("not provisioned");
+ return;
+ } else if (wpd->state ==
+ arv_config_setting_state_corrupted) {
+ printf("corrupted");
+ return;
+ } else if (wpd->state ==
+ arv_config_setting_state_invalid) {
+ printf("invalid");
+ return;
+ }
+
+ printf("%zu: %02x & %02x",
+ i,
+ wpd->expected_value,
+ wpd->mask);
+}
+
+static int process_arv_config_wpds(struct transfer_descriptor *td,
+ enum arv_config_wpsr_choice_e choice,
+ struct arv_config_wpds *wpds)
+{
+ struct __attribute__((__packed__)) arv_config_wpds_message {
+ uint8_t version;
+ /* See `arv_config_setting_command_e` */
+ uint8_t command;
+ struct arv_config_wpds wpds;
+ };
+ int rv = 0;
+
+ struct arv_config_wpds_message msg = {
+ .version = ARV_CONFIG_SETTING_CURRENT_VERSION,
+ .command = arv_config_setting_command_write_protect_descriptors,
+ };
+ size_t response_size = sizeof(msg);
+
+ if (choice == arv_config_wpsr_choice_get) {
+ rv = send_vendor_command(td, VENDOR_CC_GET_AP_RO_VERIFY_SETTING,
+ &msg, sizeof(msg), &msg, &response_size);
+ if (rv != VENDOR_RC_SUCCESS) {
+ fprintf(stderr,
+ "Error %d getting ap ro write protect descriptors\n",
+ rv);
+ return update_error;
+ }
+
+ if (response_size != sizeof(msg)) {
+ fprintf(stderr,
+ "Error getting ap ro write protect descriptors response\n");
+ return update_error;
+ }
+
+ if (msg.wpds.data[0].state ==
+ arv_config_setting_state_present) {
+ printf("expected values: ");
+ }
+ print_wpd(1, &msg.wpds.data[0]);
+ if (msg.wpds.data[1].state !=
+ arv_config_setting_state_not_present) {
+ printf(", ");
+ print_wpd(2, &msg.wpds.data[1]);
+ }
+ if (msg.wpds.data[2].state !=
+ arv_config_setting_state_not_present) {
+ printf(", ");
+ print_wpd(3, &msg.wpds.data[2]);
+ }
+
+ printf("\n");
+ } else if (choice == arv_config_wpsr_choice_set) {
+ msg.wpds = *wpds;
+
+ rv = send_vendor_command(td, VENDOR_CC_SET_AP_RO_VERIFY_SETTING,
+ &msg, sizeof(msg), &msg, &response_size);
+ if (rv != VENDOR_RC_SUCCESS) {
+ fprintf(stderr,
+ "Error %d setting ap ro write protect descriptors\n",
+ rv);
+ return update_error;
+ }
+ }
+
+ return 0;
+}
+
static int process_get_boot_mode(struct transfer_descriptor *td)
{
size_t response_size;
@@ -3497,6 +3690,7 @@ static int getopt_all(int argc, char *argv[])
int main(int argc, char *argv[])
{
struct transfer_descriptor td;
+ int rv = 0;
int errorcnt;
uint8_t *data = 0;
size_t data_len = 0;
@@ -3533,6 +3727,9 @@ int main(int argc, char *argv[])
const char *tstamp_arg = NULL;
enum arv_config_spi_addr_mode_choice_e arv_config_spi_addr_mode =
arv_config_spi_addr_mode_choice_none;
+ enum arv_config_wpsr_choice_e arv_config_wpsr_choice =
+ arv_config_wpsr_choice_none;
+ struct arv_config_wpds arv_config_wpds = { 0 };
const char *exclusive_opt_error =
"Options -a, -s and -t are mutually exclusive\n";
@@ -3639,6 +3836,37 @@ int main(int argc, char *argv[])
get_endorsement_seed = 1;
endorsement_seed_str = optarg;
break;
+ case 'E':
+ if (!optarg) {
+ arv_config_wpsr_choice =
+ arv_config_wpsr_choice_get;
+ } else if (optarg && strlen(optarg) > 0) {
+ arv_config_wpds.data[0].state =
+ arv_config_setting_state_not_present;
+ arv_config_wpds.data[1].state =
+ arv_config_setting_state_not_present;
+ arv_config_wpds.data[2].state =
+ arv_config_setting_state_not_present;
+
+ rv = parse_wpsrs(optarg, &arv_config_wpds);
+ if (rv == 2 || rv == 4 || rv == 6) {
+ arv_config_wpsr_choice =
+ arv_config_wpsr_choice_set;
+ } else {
+ fprintf(stderr,
+ "Invalid write protect descriptors "
+ "hex string: \"%s\"\n",
+ optarg);
+ exit(update_error);
+ }
+ } else {
+ fprintf(stderr,
+ "Invalid the write protect descriptors "
+ "hex string length\n");
+ exit(update_error);
+ }
+
+ break;
case 'F':
factory_mode = 1;
factory_mode_arg = optarg;
@@ -3770,6 +3998,8 @@ int main(int argc, char *argv[])
if ((bid_action == bid_none) &&
(arv_config_spi_addr_mode ==
arv_config_spi_addr_mode_choice_none) &&
+ (arv_config_wpsr_choice ==
+ arv_config_wpsr_choice_none) &&
!ccd_info &&
!ccd_lock &&
!ccd_open &&
@@ -3918,6 +4148,11 @@ int main(int argc, char *argv[])
exit(process_arv_config_spi_addr_mode(&td,
arv_config_spi_addr_mode));
+ if (arv_config_wpsr_choice)
+ exit(process_arv_config_wpds(&td,
+ arv_config_wpsr_choice,
+ &arv_config_wpds));
+
if (data || show_fw_ver) {
setup_connection(&td);