summaryrefslogtreecommitdiff
path: root/extra/usb_updater/usb_updater.c
diff options
context:
space:
mode:
Diffstat (limited to 'extra/usb_updater/usb_updater.c')
-rw-r--r--extra/usb_updater/usb_updater.c134
1 files changed, 131 insertions, 3 deletions
diff --git a/extra/usb_updater/usb_updater.c b/extra/usb_updater/usb_updater.c
index 340fc791be..1758bfab28 100644
--- a/extra/usb_updater/usb_updater.c
+++ b/extra/usb_updater/usb_updater.c
@@ -230,7 +230,7 @@ struct transfer_descriptor {
static uint32_t protocol_version;
static char *progname;
-static char *short_opts = "bcd:fhpsu";
+static char *short_opts = "bcd:fhipsu";
static const struct option long_opts[] = {
/* name hasarg *flag val */
{"binvers", 0, NULL, 'b'},
@@ -239,6 +239,7 @@ static const struct option long_opts[] = {
{"fwver", 0, NULL, 'f'},
{"help", 0, NULL, 'h'},
{"post_reset", 0, NULL, 'p'},
+ {"board_id", 2, NULL, 'i'},
{"systemdev", 0, NULL, 's'},
{"upstart", 0, NULL, 'u'},
{},
@@ -364,6 +365,8 @@ static void usage(int errs)
" -d,--device VID:PID USB device (default %04x:%04x)\n"
" -f,--fwver Report running firmware versions.\n"
" -h,--help Show this message\n"
+ " -i,--board_id [ID[:FLAGS]]\n"
+ " Get or set Info1 board ID fields\n"
" -p,--post_reset Request post reset after transfer\n"
" -s,--systemdev Use /dev/tpm0 (-d is ignored)\n"
" -u,--upstart "
@@ -1238,6 +1241,112 @@ static int show_headers_versions(const void *image)
return 0;
}
+struct board_id {
+ uint32_t type; /* Board type */
+ uint32_t type_inv; /* Board type (inverted) */
+ uint32_t flags; /* Flags */
+};
+
+enum board_id_action {
+ bid_none,
+ bid_get,
+ bid_set
+};
+
+/*
+ * The default flag value will allow to run images built for any hardware
+ * generation of a particular board ID.
+ */
+#define DEFAULT_BOARD_ID_FLAG 0xff00
+static int parse_bid(const char *opt,
+ struct board_id *bid,
+ enum board_id_action *bid_action)
+{
+ char *e;
+
+ if (!opt) {
+ *bid_action = bid_get;
+ return 1;
+ }
+
+ bid->type = (uint32_t)strtoul(opt, &e, 0);
+ *bid_action = bid_set; /* Ignored by caller on errors. */
+
+ if (!e || !*e) {
+ bid->flags = DEFAULT_BOARD_ID_FLAG;
+ return 1;
+ }
+
+ if (*e == ':') {
+ bid->flags = (uint32_t)strtoul(e + 1, &e, 0);
+ if (!e || !*e)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void process_bid(struct transfer_descriptor *td,
+ enum board_id_action bid_action,
+ struct board_id *bid)
+{
+ size_t response_size;
+
+ if (bid_action == bid_get) {
+ struct board_id bid;
+
+ response_size = sizeof(bid);
+ send_vendor_command(td, VENDOR_CC_GET_BOARD_ID,
+ &bid, sizeof(bid),
+ &bid, &response_size);
+
+ if (response_size == sizeof(bid)) {
+ printf("Board ID space: %08x:%08x:%08x\n",
+ be32toh(bid.type), be32toh(bid.type_inv),
+ be32toh(bid.flags));
+ return;
+
+ }
+ fprintf(stderr, "Error reading board ID: response size %zd,"
+ " first byte %#02x\n", response_size,
+ response_size ? *(uint8_t *)&bid : -1);
+ exit(update_error);
+ }
+
+ if (bid_action == bid_set) {
+ /* Sending just two fields: type and flags. */
+ uint32_t command_body[2];
+ uint8_t response;
+
+ command_body[0] = htobe32(bid->type);
+ command_body[1] = htobe32(bid->flags);
+
+ response_size = sizeof(command_body);
+ send_vendor_command(td, VENDOR_CC_SET_BOARD_ID,
+ command_body, sizeof(command_body),
+ command_body, &response_size);
+
+ /*
+ * Speculative assignment: the response is expected to be one
+ * byte in size and be placed in the first byte of the buffer.
+ */
+ response = *((uint8_t *)command_body);
+
+ if (response_size == 1) {
+ if (!response)
+ return; /* Success! */
+
+ fprintf(stderr, "Error %d while setting board id\n",
+ response);
+ } else {
+ fprintf(stderr, "Unexpected response size %zd"
+ " while setting board id\n",
+ response_size);
+ }
+ exit(update_error);
+ }
+}
+
int main(int argc, char *argv[])
{
struct transfer_descriptor td;
@@ -1251,6 +1360,8 @@ int main(int argc, char *argv[])
int binary_vers = 0;
int show_fw_ver = 0;
int corrupt_inactive_rw = 0;
+ struct board_id bid;
+ enum board_id_action bid_action;
progname = strrchr(argv[0], '/');
if (progname)
@@ -1262,6 +1373,7 @@ int main(int argc, char *argv[])
memset(&td, 0, sizeof(td));
td.ep_type = usb_xfer;
+ bid_action = bid_none;
errorcnt = 0;
opterr = 0; /* quiet, you */
while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
@@ -1271,7 +1383,8 @@ int main(int argc, char *argv[])
break;
case 'd':
if (!parse_vidpid(optarg, &vid, &pid)) {
- printf("Invalid argument: \"%s\"\n", optarg);
+ printf("Invalid device argument: \"%s\"\n",
+ optarg);
errorcnt++;
}
break;
@@ -1284,6 +1397,18 @@ int main(int argc, char *argv[])
case 'h':
usage(errorcnt);
break;
+ case 'i':
+ if (!optarg && argv[optind] && argv[optind][0] != '-') {
+ /* optional argument present. */
+ optarg = argv[optind];
+ optind++;
+ }
+ if (!parse_bid(optarg, &bid, &bid_action)) {
+ printf("Invalid board id argument: \"%s\"\n",
+ optarg);
+ errorcnt++;
+ }
+ break;
case 's':
td.ep_type = dev_xfer;
break;
@@ -1316,7 +1441,7 @@ int main(int argc, char *argv[])
if (errorcnt)
usage(errorcnt);
- if (!show_fw_ver && !corrupt_inactive_rw) {
+ if (!show_fw_ver && !corrupt_inactive_rw && (bid_action == bid_none)) {
if (optind >= argc) {
fprintf(stderr,
"\nERROR: Missing required <binary image>\n\n");
@@ -1351,6 +1476,9 @@ int main(int argc, char *argv[])
}
}
+ if (bid_action != bid_none)
+ process_bid(&td, bid_action, &bid);
+
if (corrupt_inactive_rw)
invalidate_inactive_rw(&td);