diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2017-08-24 19:24:02 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2017-09-14 19:07:23 +0000 |
commit | b78121a5a4f572b142458dd07a02c13a073ed6e9 (patch) | |
tree | fe756a1b3a0b34467d515a16887ae17b5fbc857e | |
parent | b401f3ae77e735a129b5e35c2be65bf610f8d65f (diff) | |
download | chrome-ec-b78121a5a4f572b142458dd07a02c13a073ed6e9.tar.gz |
usb_updater: allow to communicate with cr50 using trunks_send
It is necessary to be able to access Cr50 using usb_updater without
stopping trunksd services. This patch adds another option for
usb_updater to communicate with Cr50, using the trunks_send command.
A new command line option '-t' is added to allow to choose the new
interface.
When communicating over trunks_send the same processing is used as
when communicating over /dev/tpm0, just instead of talking to the
hardware device, popen() function is used to run trunks_send --raw
command and to gain access to its console output.
BRANCH=none
BUG=none
TEST=ran various commands using the new '-t' option:
# ./usb_updater -t /opt/google/cr50/firmware/cr50.bin.prod
read 524288(0x80000) bytes from /opt/google/cr50/firmware/cr50.bin.prod
start
target running protocol version 6
keyids: RO 0xaa66150f, RW 0xb93d6539
offsets: backup RO at 0x40000, backup RW at 0x4000
sending 0x32288 bytes to 0x4000
-------
update complete
reboot requested
image updated
[reboot...]
# ./usb_updater -t -f
start
target running protocol version 6
keyids: RO 0xaa66150f, RW 0xb93d6539
offsets: backup RO at 0x40000, backup RW at 0x4000
Current versions:
RO 0.0.10
RW 0.0.23
Change-Id: I9c7481c30c2f6908e0d1ac4f204654d2fd1b3b2e
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/634629
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
(cherry picked from commit 8c9f9ad861a48903aef5bd923741e12aa802c65c)
Reviewed-on: https://chromium-review.googlesource.com/660890
(cherry picked from commit 4f905f82740339fba74f7ef824655e60f951403f)
Reviewed-on: https://chromium-review.googlesource.com/666543
-rw-r--r-- | extra/usb_updater/usb_updater.c | 188 |
1 files changed, 176 insertions, 12 deletions
diff --git a/extra/usb_updater/usb_updater.c b/extra/usb_updater/usb_updater.c index c063198b20..f2dac00b09 100644 --- a/extra/usb_updater/usb_updater.c +++ b/extra/usb_updater/usb_updater.c @@ -7,6 +7,7 @@ #include <asm/byteorder.h> #include <ctype.h> #include <endian.h> +#include <errno.h> #include <fcntl.h> #include <getopt.h> #include <libusb.h> @@ -221,7 +222,8 @@ struct transfer_descriptor { uint32_t post_reset; enum transfer_type { usb_xfer = 0, - dev_xfer = 1 + dev_xfer = 1, + ts_xfer = 2 } ep_type; union { struct usb_endpoint uep; @@ -231,7 +233,7 @@ struct transfer_descriptor { static uint32_t protocol_version; static char *progname; -static char *short_opts = "bcd:fhipsu"; +static char *short_opts = "bcd:fhipstu"; static const struct option long_opts[] = { /* name hasarg *flag val */ {"binvers", 0, NULL, 'b'}, @@ -242,13 +244,142 @@ static const struct option long_opts[] = { {"post_reset", 0, NULL, 'p'}, {"board_id", 2, NULL, 'i'}, {"systemdev", 0, NULL, 's'}, + {"trunks_send", 0, NULL, 't'}, {"upstart", 0, NULL, 'u'}, {}, }; -/* Prepare and transfer a block to /dev/tpm0, get a reply. */ -static int tpm_send_pkt(int fd, unsigned int digest, unsigned int addr, - const void *data, int size, + + +/* Helpers to convert between binary and hex ascii and back. */ +static char to_hexascii(uint8_t c) +{ + if (c <= 9) + return '0' + c; + return 'a' + c - 10; +} + +static int from_hexascii(char c) +{ + /* convert to lower case. */ + c = tolower(c); + + if (c < '0' || c > 'f' || ((c > '9') && (c < 'a'))) + return -1; /* Not an ascii character. */ + + if (c <= '9') + return c - '0'; + + return c - 'a' + 10; +} + +/* Functions to communicate with the TPM over the trunks_send --raw channel. */ + +/* File handle to share between write and read sides. */ +static FILE *tpm_output; +static int ts_write(const void *out, size_t len) +{ + const char *cmd_head = "trunks_send --raw "; + size_t head_size = strlen(cmd_head); + char full_command[head_size + 2 * len + 1]; + size_t i; + + strcpy(full_command, cmd_head); + /* + * Need to convert binary input into hex ascii output to pass to the + * trunks_send command. + */ + for (i = 0; i < len; i++) { + uint8_t c = ((const uint8_t *)out)[i]; + + full_command[head_size + 2 * i] = to_hexascii(c >> 4); + full_command[head_size + 2 * i + 1] = to_hexascii(c & 0xf); + } + + /* Make it a proper zero terminated string. */ + full_command[sizeof(full_command) - 1] = 0; + debug("cmd: %s\n", full_command); + tpm_output = popen(full_command, "r"); + if (tpm_output) + return len; + + fprintf(stderr, "Error: failed to launch trunks_send --raw\n"); + return -1; +} + +static int ts_read(void *buf, size_t max_rx_size) +{ + int i; + int pclose_rv; + int rv; + char response[max_rx_size * 2]; + + if (!tpm_output) { + fprintf(stderr, "Error: attempt to read empty output\n"); + return -1; + } + + rv = fread(response, 1, sizeof(response), tpm_output); + if (rv > 0) + rv -= 1; /* Discard the \n character added by trunks_send. */ + + debug("response of size %d, max rx size %zd: %s\n", + rv, max_rx_size, response); + + pclose_rv = pclose(tpm_output); + if (pclose_rv < 0) { + fprintf(stderr, + "Error: pclose failed: error %d (%s)\n", + errno, strerror(errno)); + return -1; + } + + tpm_output = NULL; + + if (rv & 1) { + fprintf(stderr, + "Error: trunks_send returned odd number of bytes: %s\n", + response); + return -1; + } + + for (i = 0; i < rv/2; i++) { + uint8_t byte; + char c; + int nibble; + + c = response[2 * i]; + nibble = from_hexascii(c); + if (nibble < 0) { + fprintf(stderr, "Error: " + "trunks_send returned non hex character %c\n", + c); + return -1; + } + byte = nibble << 4; + + c = response[2 * i + 1]; + nibble = from_hexascii(c); + if (nibble < 0) { + fprintf(stderr, "Error: " + "trunks_send returned non hex character %c\n", + c); + return -1; + } + byte |= nibble; + + ((uint8_t *)buf)[i] = byte; + } + + return rv/2; +} + +/* + * Prepare and transfer a block to either to /dev/tpm0 or through trunks_send + * --raw, get a reply. + */ +static int tpm_send_pkt(struct transfer_descriptor *td, unsigned int digest, + unsigned int addr, const void *data, int size, void *response, size_t *response_size, uint16_t subcmd) { @@ -261,6 +392,8 @@ static int tpm_send_pkt(int fd, unsigned int digest, unsigned int addr, void *payload; size_t header_size; uint32_t rv; + size_t rx_size = sizeof(struct upgrade_pkt) + + sizeof(struct first_response_pdu); debug("%s: sending to %#x %d bytes\n", __func__, addr, size); @@ -296,7 +429,19 @@ static int tpm_send_pkt(int fd, unsigned int digest, unsigned int addr, debug("\n"); } #endif - done = write(fd, out, len); + switch (td->ep_type) { + case dev_xfer: + done = write(td->tpm_fd, out, len); + break; + case ts_xfer: + done = ts_write(out, len); + break; + default: + fprintf(stderr, "Error: %s:%d: unknown transfer type %d\n", + __func__, __LINE__, td->ep_type); + return -1; + } + if (done < 0) { perror("Could not write to TPM"); return -1; @@ -311,8 +456,22 @@ static int tpm_send_pkt(int fd, unsigned int digest, unsigned int addr, * size of the two structures below is sure enough for any expected * response size. */ - len = read(fd, outbuf, sizeof(struct upgrade_pkt) + - sizeof(struct first_response_pdu)); + switch (td->ep_type) { + case dev_xfer: + len = read(td->tpm_fd, outbuf, rx_size); + break; + case ts_xfer: + len = ts_read(outbuf, rx_size); + break; + default: + /* + * This sure will never happen, type is verifed in the + * previous switch statement. + */ + len = -1; + break; + } + #ifdef DEBUG debug("Read %d bytes from TPM\n", len); if (len > 0) { @@ -372,6 +531,8 @@ static void usage(int errs) "character string.\n" " -p,--post_reset Request post reset after transfer\n" " -s,--systemdev Use /dev/tpm0 (-d is ignored)\n" + " -t,--trunks_send Use `trunks_send --raw' " + "(-d is ignored)\n" " -u,--upstart " "Upstart mode (strict header checks)\n" "\n", progname, VID, PID); @@ -716,7 +877,7 @@ static void transfer_section(struct transfer_descriptor *td, * different amount of data is transferred (which * would indicate a synchronization problem). */ - if (tpm_send_pkt(td->tpm_fd, + if (tpm_send_pkt(td, updu.cmd.block_digest, block_addr, data_ptr, @@ -906,7 +1067,7 @@ static void setup_connection(struct transfer_descriptor *td) sizeof(start_resp), 1, &rxed_size); } else { rxed_size = sizeof(start_resp); - if (tpm_send_pkt(td->tpm_fd, 0, 0, NULL, 0, + if (tpm_send_pkt(td, 0, 0, NULL, 0, &start_resp, &rxed_size, EXTENSION_FW_UPGRADE) < 0) { fprintf(stderr, "Failed to start transfer\n"); @@ -1103,7 +1264,7 @@ static uint32_t send_vendor_command(struct transfer_descriptor *td, } } else { - rv = tpm_send_pkt(td->tpm_fd, 0, 0, + rv = tpm_send_pkt(td, 0, 0, command_body, command_body_size, response, response_size, subcommand); @@ -1481,6 +1642,9 @@ int main(int argc, char *argv[]) case 's': td.ep_type = dev_xfer; break; + case 't': + td.ep_type = ts_xfer; + break; case 'p': td.post_reset = 1; break; @@ -1537,7 +1701,7 @@ int main(int argc, char *argv[]) if (td.ep_type == usb_xfer) { usb_findit(vid, pid, &td.uep); - } else { + } else if (td.ep_type == dev_xfer) { td.tpm_fd = open("/dev/tpm0", O_RDWR); if (td.tpm_fd < 0) { perror("Could not open TPM"); |