From 2a657bc6b1a9d0f28b74e2c538fa0149dd4bd4bb Mon Sep 17 00:00:00 2001 From: Matt Vertescher Date: Mon, 24 Oct 2022 11:19:35 -0700 Subject: gsctool: Add AP RO verify write protect descriptors config command 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 Change-Id: I0d7cc6a98d6cf442592a1b9b81ef1c86193dd068 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3983416 Reviewed-by: Mary Ruthven Tested-by: Jett Rink Commit-Queue: Jett Rink Reviewed-by: Jett Rink --- extra/usb_updater/gsctool.c | 235 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) 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 @@ -356,6 +356,33 @@ enum arv_config_spi_addr_mode_choice_e { arv_config_spi_addr_mode_choice_set_4byte = 3, }; +/* + * 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"; @@ -3638,6 +3835,37 @@ int main(int argc, char *argv[]) case 'e': 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; @@ -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); -- cgit v1.2.1