summaryrefslogtreecommitdiff
path: root/extra
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2016-07-07 22:00:30 -0600
committerchrome-bot <chrome-bot@chromium.org>2016-07-15 16:51:40 -0700
commit9249a3569c35df1ffbecf6ef67fbcc4976861d8f (patch)
tree9b65c2fcacb8ed13f9e37af4e0b2853464630035 /extra
parent13518652d27ce739d9af71d441e41765c9851941 (diff)
downloadchrome-ec-9249a3569c35df1ffbecf6ef67fbcc4976861d8f.tar.gz
cr50: Modify USB updater to allow updates over /dev/tmp0 too
A new option is being added to the set of command line options, '-s', once it is specified, the utility tries to update the CR50 using /dev/tpm0. BRANCH=none BUG=chrome-os-partner:54992 TEST=emerge-gru ec-utils, copy /build/kevin/usr/sbin/usb_updater and ~/trunk/src/platform/ec/build/cr50/ec.bin to the DUT, try running the update command on the DUT: $ <path to>/usb_updater -s <path to>/ec.bin observe in the end of the log: vvvvvvvvvvvvvvvvvvvvvvvvvvvvv ------- update complete bye ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ restart the cr50 and verify that it is running the new image. Change-Id: Idb755328f911f3065f01df420488c7a1b4a32500 Signed-off-by: Simon Glass <sjg@chromium.org> Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/358967 Reviewed-by: Andrey Pronin <apronin@chromium.org>
Diffstat (limited to 'extra')
-rw-r--r--extra/usb_updater/usb_updater.c197
1 files changed, 174 insertions, 23 deletions
diff --git a/extra/usb_updater/usb_updater.c b/extra/usb_updater/usb_updater.c
index 1b071b46e6..cfd232e758 100644
--- a/extra/usb_updater/usb_updater.c
+++ b/extra/usb_updater/usb_updater.c
@@ -4,7 +4,9 @@
* found in the LICENSE file.
*/
+#include <asm/byteorder.h>
#include <endian.h>
+#include <fcntl.h>
#include <getopt.h>
#include <libusb.h>
#include <openssl/sha.h>
@@ -25,6 +27,13 @@
#include "upgrade_fw.h"
#include "config_chip.h"
#include "board.h"
+#include "compile_time_macros.h"
+
+#ifdef DEBUG
+#define debug printf
+#else
+#define debug(fmt, args...)
+#endif
/* Look for Cr50 FW update interface */
#define VID USB_VID_GOOGLE
@@ -32,23 +41,114 @@
#define SUBCLASS USB_SUBCLASS_GOOGLE_CR50
#define PROTOCOL USB_PROTOCOL_GOOGLE_CR50_NON_HC_FW_UPDATE
+
+/*
+ * Need to create an entire TPM PDU when upgrading over /dev/tpm0 and need to
+ * have space to prepare the entire PDU.
+ */
+struct upgrade_pkt {
+ __be16 tag;
+ __be32 length;
+ __be32 ordinal;
+ __be16 subcmd;
+ __be32 digest;
+ __be32 address;
+ char data[0];
+} __packed;
+
+#define SIGNED_TRANSFER_SIZE 1024
+#define MAX_BUF_SIZE (SIGNED_TRANSFER_SIZE + sizeof(struct upgrade_pkt))
+#define EXT_CMD 0xbaccd00a
+#define FW_UPGRADE 4
+
struct usb_endpoint {
struct libusb_device_handle *devh;
uint8_t ep_num;
int chunk_len;
};
-/* Globals */
+struct transfer_endpoint {
+ enum transfer_type {
+ usb_xfer = 0,
+ spi_xfer = 1
+ } ep_type;
+ union {
+ struct usb_endpoint uep;
+ int tpm_fd;
+ };
+};
+
static uint32_t protocol_version;
static char *progname;
-static char *short_opts = ":d:h";
+static char *short_opts = ":d:hs";
static const struct option long_opts[] = {
/* name hasarg *flag val */
{"device", 1, NULL, 'd'},
{"help", 0, NULL, 'h'},
- {NULL, 0, NULL, 0},
+ {"spi", 0, NULL, 's'},
+ {NULL, 0, NULL, 0},
};
+/* 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,
+ void *response, int *response_size)
+{
+ /* Used by transfer to /dev/tpm0 */
+ static uint8_t outbuf[MAX_BUF_SIZE];
+
+ struct upgrade_pkt *out = (struct upgrade_pkt *)outbuf;
+ /* Use the same structure, it will not be filled completely. */
+ struct upgrade_pkt reply;
+ int len, done;
+ int response_offset = offsetof(struct upgrade_pkt, digest);
+
+ debug("%s: sending to %#x %d bytes\n", __func__, addr, size);
+
+ len = size + sizeof(struct upgrade_pkt);
+
+ out->tag = __cpu_to_be16(0x8001);
+ out->length = __cpu_to_be32(len);
+ out->ordinal = __cpu_to_be32(EXT_CMD);
+ out->subcmd = __cpu_to_be16(FW_UPGRADE);
+ out->digest = digest;
+ out->address = __cpu_to_be32(addr);
+ memcpy(out->data, data, size);
+#ifdef DEBUG
+ {
+ int i;
+
+ debug("Writing %d bytes to TPM at %x\n", len, addr);
+ for (i = 0; i < 20; i++)
+ debug("%2.2x ", outbuf[i]);
+ debug("\n");
+ }
+#endif
+ done = write(fd, out, len);
+ if (done < 0) {
+ perror("Could not write to TPM");
+ return -1;
+ } else if (done != len) {
+ fprintf(stderr, "Error: Wrote %x bytes, expected to write %x\n",
+ done, len);
+ return -1;
+ }
+
+ len = read(fd, &reply, sizeof(reply));
+ if ((len < response_offset) ||
+ (len > ((int)(response_offset + sizeof(uint32_t))))) {
+ fprintf(stderr, "Problems reading from TPM, got %d bytes\n",
+ len);
+ return -1;
+ }
+
+ debug("Read %x bytes from TPM\n", len);
+ len = len - response_offset;
+ memcpy(response, &reply.digest, len);
+ *response_size = len;
+ return 0;
+}
+
/* Release USB device and return error to the OS. */
static void shut_down(struct usb_endpoint *uep)
{
@@ -68,6 +168,7 @@ static void usage(int errs)
"\n"
" -d,--device VID:PID USB device (default %04x:%04x)\n"
" -h,--help Show this message\n"
+ " -s,--spi Use /dev/tmp0 (-d is ignored)\n"
"\n", progname, VID, PID);
exit(!!errs);
@@ -291,7 +392,6 @@ static void usb_findit(uint16_t vid, uint16_t pid, struct usb_endpoint *uep)
printf("READY\n-------\n");
}
-#define SIGNED_TRANSFER_SIZE 1024
struct upgrade_command {
uint32_t block_digest;
uint32_t block_base;
@@ -366,7 +466,7 @@ static int transfer_block(struct usb_endpoint *uep, struct update_pdu *updu,
return 0;
}
-static void transfer_and_reboot(struct usb_endpoint *uep,
+static void transfer_and_reboot(struct transfer_endpoint *tep,
uint8_t *data, uint32_t data_len)
{
uint32_t out;
@@ -376,6 +476,7 @@ static void transfer_and_reboot(struct usb_endpoint *uep,
struct update_pdu updu;
struct startup_resp first_resp;
int rxed_size;
+ struct usb_endpoint *uep = &tep->uep;
/* Send start/erase request */
printf("erase\n");
@@ -383,8 +484,17 @@ static void transfer_and_reboot(struct usb_endpoint *uep,
memset(&updu, 0, sizeof(updu));
updu.block_size = htobe32(sizeof(updu));
- do_xfer(uep, &updu, sizeof(updu), &first_resp, sizeof(first_resp),
- 1, &rxed_size);
+ if (tep->ep_type == usb_xfer) {
+ do_xfer(uep, &updu, sizeof(updu), &first_resp,
+ sizeof(first_resp), 1, &rxed_size);
+ } else {
+ rxed_size = sizeof(first_resp);
+ if (tpm_send_pkt(tep->tpm_fd, 0, 0, NULL, 0,
+ &first_resp, &rxed_size) < 0) {
+ perror("Failed to start transfer");
+ return;
+ }
+ }
if (rxed_size == sizeof(uint32_t))
protocol_version = 0;
@@ -401,8 +511,6 @@ static void transfer_and_reboot(struct usb_endpoint *uep,
}
next_offset = reply - FLASH_BASE;
- printf("Updating at offset 0x%08x\n", next_offset);
-
data_ptr = data + next_offset;
data_len = CONFIG_RW_SIZE;
@@ -410,7 +518,8 @@ static void transfer_and_reboot(struct usb_endpoint *uep,
while (data_len && (data_ptr[data_len - 1] == 0xff))
data_len--;
- printf("sending 0x%x/0x%x bytes\n", data_len, CONFIG_RW_SIZE);
+ printf("sending 0x%x/0x%x bytes to %#x\n", data_len, CONFIG_RW_SIZE,
+ next_offset);
while (data_len) {
size_t payload_size;
SHA_CTX ctx;
@@ -434,15 +543,38 @@ static void transfer_and_reboot(struct usb_endpoint *uep,
/* Copy the first few bytes. */
memcpy(&updu.cmd.block_digest, digest,
sizeof(updu.cmd.block_digest));
+ if (tep->ep_type == usb_xfer) {
+ for (max_retries = 10; max_retries; max_retries--)
+ if (!transfer_block(uep, &updu,
+ data_ptr, payload_size))
+ break;
+
+ if (!max_retries) {
+ fprintf(stderr,
+ "Failed to trasfer block, %d to go\n",
+ data_len);
+ exit(1);
+ }
+ } else {
+ rxed_size = sizeof(first_resp);
+ if (tpm_send_pkt(tep->tpm_fd,
+ updu.cmd.block_digest,
+ next_offset + FLASH_BASE,
+ data_ptr,
+ payload_size, &first_resp,
+ &rxed_size) < 0) {
+ fprintf(stderr,
+ "Failed to trasfer block, %d to go\n",
+ data_len);
+ exit(1);
+ }
+ if ((rxed_size != 1) || *((uint8_t *)&first_resp)) {
+ fprintf(stderr,
+ "got response of size %d, value %#x\n",
+ rxed_size, first_resp.value);
- for (max_retries = 10; max_retries; max_retries--)
- if (!transfer_block(uep, &updu, data_ptr, payload_size))
- break;
-
- if (!max_retries) {
- fprintf(stderr, "Failed to trasfer block, %d to go\n",
- data_len);
- exit(1);
+ exit(1);
+ }
}
data_len -= payload_size;
data_ptr += payload_size;
@@ -450,6 +582,8 @@ static void transfer_and_reboot(struct usb_endpoint *uep,
}
printf("-------\nupdate complete\n");
+ if (tep->ep_type != usb_xfer)
+ return;
/* Send stop request, ignorign reply. */
out = htobe32(UPGRADE_DONE);
@@ -463,7 +597,7 @@ static void transfer_and_reboot(struct usb_endpoint *uep,
int main(int argc, char *argv[])
{
- struct usb_endpoint uep;
+ struct transfer_endpoint tep;
int errorcnt;
uint8_t *data = 0;
uint32_t data_len = 0;
@@ -476,6 +610,10 @@ int main(int argc, char *argv[])
else
progname = argv[0];
+ /* Usb transfer - default mode. */
+ memset(&tep, 0, sizeof(tep));
+ tep.ep_type = usb_xfer;
+
errorcnt = 0;
opterr = 0; /* quiet, you */
while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
@@ -489,6 +627,9 @@ int main(int argc, char *argv[])
case 'h':
usage(errorcnt);
break;
+ case 's':
+ tep.ep_type = spi_xfer;
+ break;
case 0: /* auto-handled option */
break;
case '?':
@@ -525,14 +666,24 @@ int main(int argc, char *argv[])
exit(1);
}
- usb_findit(vid, pid, &uep);
+ if (tep.ep_type == usb_xfer) {
+ usb_findit(vid, pid, &tep.uep);
+ } else {
+ tep.tpm_fd = open("/dev/tpm0", O_RDWR);
+ if (tep.tpm_fd < 0) {
+ perror("Could not open TPM");
+ exit(1);
+ }
+ }
- transfer_and_reboot(&uep, data, data_len);
+ transfer_and_reboot(&tep, data, data_len);
printf("bye\n");
free(data);
- libusb_close(uep.devh);
- libusb_exit(NULL);
+ if (tep.ep_type == usb_xfer) {
+ libusb_close(tep.uep.devh);
+ libusb_exit(NULL);
+ }
return 0;
}