summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2017-08-24 19:24:02 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2017-09-14 19:07:23 +0000
commitb78121a5a4f572b142458dd07a02c13a073ed6e9 (patch)
treefe756a1b3a0b34467d515a16887ae17b5fbc857e
parentb401f3ae77e735a129b5e35c2be65bf610f8d65f (diff)
downloadchrome-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.c188
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");