summaryrefslogtreecommitdiff
path: root/extra/usb_updater
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /extra/usb_updater
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14442.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'extra/usb_updater')
-rw-r--r--extra/usb_updater/.gitignore6
-rw-r--r--extra/usb_updater/Makefile55
-rw-r--r--extra/usb_updater/c2d2.json15
-rw-r--r--extra/usb_updater/desc_parser.c377
-rw-r--r--extra/usb_updater/desc_parser.h58
l---------extra/usb_updater/ecusb1
-rwxr-xr-xextra/usb_updater/fw_update.py426
-rw-r--r--extra/usb_updater/sample_descriptor87
-rw-r--r--extra/usb_updater/servo_micro.json15
-rwxr-xr-xextra/usb_updater/servo_updater.py456
-rw-r--r--extra/usb_updater/servo_v4.json15
-rw-r--r--extra/usb_updater/servo_v4p1.json15
-rw-r--r--extra/usb_updater/sweetberry.json14
-rw-r--r--extra/usb_updater/usb_updater2.c1244
14 files changed, 0 insertions, 2784 deletions
diff --git a/extra/usb_updater/.gitignore b/extra/usb_updater/.gitignore
deleted file mode 100644
index 37c3bd3808..0000000000
--- a/extra/usb_updater/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-generated_version.h
-gsctool
-usb_updater2
-*.d
-*.o
-dp \ No newline at end of file
diff --git a/extra/usb_updater/Makefile b/extra/usb_updater/Makefile
deleted file mode 100644
index 1dfbc55645..0000000000
--- a/extra/usb_updater/Makefile
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2015 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-CC ?= gcc
-PKG_CONFIG ?= pkg-config
-PROGRAMS := usb_updater2
-LIBS :=
-LFLAGS :=
-CFLAGS := -std=gnu99 \
- -g \
- -Wall \
- -Werror \
- -Wpointer-arith \
- -Wcast-align \
- -Wcast-qual \
- -Wundef \
- -Wsign-compare \
- -Wredundant-decls \
- -Wmissing-declarations
-
-ifeq (DEBUG,)
-CFLAGS += -O3
-else
-CFLAGS += -O0
-endif
-
-#
-# Add libusb-1.0 required flags
-#
-LIBS += $(shell $(PKG_CONFIG) --libs libusb-1.0)
-CFLAGS += $(shell $(PKG_CONFIG) --cflags libusb-1.0)
-CFLAGS += -I../../include -I../../util -I../../fuzz -I../../test
-
-VPATH = ../../util
-
-LIBS_common = -lfmap
-
-all: $(PROGRAMS)
-
-%.o: %.c
- $(CC) $(CFLAGS) -c -MMD -MF $(basename $@).d -o $@ $<
-
-# common EC code USB updater
-usb_updater2: usb_updater2.c Makefile
- $(CC) $(CFLAGS) $< $(LFLAGS) $(LIBS) $(LIBS_common) -o $@
-
-.PHONY: clean
-
-clean:
- rm -rf $(PROGRAMS) *~ *.o *.d dp
-
-parser_debug: desc_parser.c
- gcc -g -O0 -DTEST_PARSER desc_parser.c -o dp
-
diff --git a/extra/usb_updater/c2d2.json b/extra/usb_updater/c2d2.json
deleted file mode 100644
index 79fc6f0992..0000000000
--- a/extra/usb_updater/c2d2.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "Comment": "This file describes the updateable sections of the flash.",
- "board": "c2d2",
- "vid": "0x18d1",
- "pid": "0x5041",
- "console": "3",
- "Comment on flash": "This is the base address of writeable flash",
- "flash": "0x8000000",
- "Comment on region format": "name: [baseoffset, length]",
- "regions": {
- "RW": ["0x10000", "0x10000"],
- "PSTATE": ["0xf000", "0x1000"],
- "RO": ["0x0000", "0xf000"]
- }
-}
diff --git a/extra/usb_updater/desc_parser.c b/extra/usb_updater/desc_parser.c
deleted file mode 100644
index 5bd996bdda..0000000000
--- a/extra/usb_updater/desc_parser.c
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright 2018 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <malloc.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include "desc_parser.h"
-
-static FILE *hash_file_;
-static int line_count_;
-static int section_count_;
-
-/*
- * This is used to verify consistency of the description database, namely that
- * all hash sections include the same number of hash variants.
- */
-static size_t variant_count;
-
-/* Size of the retrieved string or negative OS error value. */
-static ssize_t get_next_line(char *next_line, size_t line_size)
-{
- size_t index = 0;
-
- while (fgets(next_line + index, line_size - index, hash_file_)) {
- line_count_++;
-
- if (next_line[index] == '#')
- continue; /* Skip the comment */
-
- if (next_line[index] == '\n') {
- /*
- * This is an empty line, return all collected data,
- * pontintially an array of size zero if this is a
- * repeated empty line.
- */
- next_line[index] = '\0';
- return index;
- }
-
- /* Make sure next string overwrites this string's newline. */
- index += strlen(next_line + index) - 1;
-
- if (index >= (line_size - 1)) {
- fprintf(stderr, "%s: Input overflow in line %d\n",
- __func__, line_count_);
- return -EOVERFLOW;
- }
- }
-
- if (index) {
- /*
- * This must be the last line in the file with no empty line
- * after it. Drop the closing newline, if it is there.
- */
- if (next_line[index] == '\n')
- next_line[index--] = '\0';
-
- return index;
- }
- return errno ? -errno : -ENODATA;
-}
-
-static int get_next_token(char *input, size_t expected_size, char **output)
-{
- char *next_colon;
-
- next_colon = strchr(input, ':');
- if (next_colon)
- *next_colon = '\0';
- if (!next_colon || (expected_size &&
- strlen(input) != expected_size)) {
- fprintf(stderr, "Invalid entry in section %d\n",
- section_count_);
- return -EINVAL;
- }
-
- *output = next_colon + 1;
- return 0;
-}
-
-static int get_hex_value(char *input, char **output)
-{
- char *e;
- long int value;
-
- if (strchr(input, ':'))
- get_next_token(input, 0, output);
- else
- *output = NULL;
-
- value = strtol(input, &e, 16);
- if ((e && *e) || (strlen(input) > 8)) {
- fprintf(stderr, "Invalid hex value %s in section %d\n",
- input, section_count_);
- return -EINVAL;
- }
-
- return value;
-}
-
-static int parse_range(char *next_line,
- size_t line_len,
- struct addr_range *parsed_range)
-{
- char *line_cursor;
- char *next_token;
- int is_a_hash_range;
- struct result_node *node;
- int value;
-
- section_count_++;
- line_cursor = next_line;
-
- /* Range type. */
- if (get_next_token(line_cursor, 1, &next_token))
- return -EINVAL;
-
- switch (*line_cursor) {
- case 'a':
- parsed_range->range_type = AP_RANGE;
- break;
- case 'e':
- parsed_range->range_type = EC_RANGE;
- break;
- case 'g':
- parsed_range->range_type = EC_GANG_RANGE;
- break;
- default:
- fprintf(stderr, "Invalid range type %c in section %d\n",
- *line_cursor, section_count_);
- return -EINVAL;
- }
- line_cursor = next_token;
-
- /* Hash or dump? */
- if (get_next_token(line_cursor, 1, &next_token))
- return -EINVAL;
-
- switch (*line_cursor) {
- case 'd':
- is_a_hash_range = 0;
- break;
- case 'h':
- is_a_hash_range = 1;
- break;
- default:
- fprintf(stderr, "Invalid entry kind %c in section %d\n",
- *line_cursor, section_count_);
- return -EINVAL;
- }
- line_cursor = next_token;
-
- /* Range base address. */
- value = get_hex_value(line_cursor, &next_token);
- if (value < 0)
- return -EINVAL;
- parsed_range->base_addr = value;
-
- /* Range size. */
- line_cursor = next_token;
- value = get_hex_value(line_cursor, &next_token);
- if (value < 0)
- return -EINVAL;
- parsed_range->range_size = value;
-
- if (!next_token && is_a_hash_range) {
- fprintf(stderr, "Missing hash in section %d\n", section_count_);
- return -EINVAL;
- }
-
- if (next_token && !is_a_hash_range) {
- fprintf(stderr, "Unexpected data in section %d\n",
- section_count_);
- return -EINVAL;
- }
-
- parsed_range->variant_count = 0;
- if (!is_a_hash_range)
- return 0; /* No more input for dump ranges. */
-
- node = parsed_range->variants;
- do { /* While line is not over. */
- char c;
- int i = 0;
-
- line_cursor = next_token;
- next_token = strchr(line_cursor, ':');
- if (next_token)
- *next_token++ = '\0';
- if (strlen(line_cursor) != (2 * sizeof(*node))) {
- fprintf(stderr,
- "Invalid hash %zd size %zd in section %d\n",
- parsed_range->variant_count + 1,
- strlen(line_cursor), section_count_);
- return -EINVAL;
- }
-
- while ((c = *line_cursor++) != 0) {
- uint8_t nibble;
-
- if (!isxdigit(c)) {
- fprintf(stderr,
- "Invalid hash %zd value in section %d\n",
- parsed_range->variant_count + 1,
- section_count_);
- return -EINVAL;
- }
-
- if (c <= '9')
- nibble = c - '0';
- else if (c >= 'a')
- nibble = c - 'a' + 10;
- else
- nibble = c - 'A' + 10;
-
- if (i & 1)
- node->expected_result[i / 2] |= nibble;
- else
- node->expected_result[i / 2] = nibble << 4;
-
- i++;
- }
-
- node++;
- parsed_range->variant_count++;
-
- } while (next_token);
-
- return 0;
-}
-
-int parser_get_next_range(struct addr_range **range)
-{
- char next_line[1000]; /* Should be enough for the largest descriptor. */
- ssize_t entry_size;
- struct addr_range *new_range;
- int rv;
-
- /*
- * We come here after hash descriptor database file was opened and the
- * current board's section has been found. Just in case check if the
- * file has been opened.
- */
- if (!hash_file_ || !range)
- return -EIO;
-
- *range = NULL;
- do {
- entry_size = get_next_line(next_line, sizeof(next_line));
- if (entry_size < 0)
- return entry_size;
- } while (!entry_size); /* Skip empty lines. */
-
- if (entry_size == 4) /* Next board's entry must have been reached. */
- return -ENODATA;
-
- /* This sure will be enough to fit parsed structure contents. */
- new_range = malloc(sizeof(*new_range) + entry_size);
- if (!new_range) {
- fprintf(stderr, "Failed to allocate %zd bytes\n",
- sizeof(*new_range) + entry_size);
- return -ENOMEM;
- }
-
- /* This must be a new descriptor section, lets parse it. */
- rv = parse_range(next_line, entry_size, new_range);
-
- if (rv) {
- free(new_range);
- return rv;
- }
-
- if (new_range->variant_count) {
- /*
- * A new range was found, if this is the first hash range we
- * encountered, save its dimensions for future reference.
- *
- * If this is not the first one - verify that it has the same
- * number of hash variants as all previous hash blocks.
- */
- if (!variant_count) {
- variant_count = new_range->variant_count;
- } else if (variant_count != new_range->variant_count) {
- fprintf(stderr,
- "Unexpected number of variants in section %d\n",
- section_count_);
- free(new_range);
- return -EINVAL;
- }
- }
-
- *range = new_range;
- return 0;
-
-}
-
-int parser_find_board(const char *hash_file_name, const char *board_id)
-{
- char next_line[1000]; /* Should be enough for the largest descriptor. */
- ssize_t id_len = strlen(board_id);
-
- if (!hash_file_) {
- hash_file_ = fopen(hash_file_name, "r");
- if (!hash_file_) {
- fprintf(stderr, "Error:%s can not open file '%s'\n",
- strerror(errno), hash_file_name);
- return errno;
- }
- }
-
- while (1) {
- ssize_t entry_size;
-
- entry_size = get_next_line(next_line, sizeof(next_line));
- if (entry_size < 0) {
- return entry_size;
- }
-
- if ((entry_size == id_len) &&
- !memcmp(next_line, board_id, id_len)) {
- variant_count = 0;
- return 0;
- }
- }
-
- return -ENODATA;
-}
-
-void parser_done(void)
-{
- if (!hash_file_)
- return;
-
- fclose(hash_file_);
- hash_file_ = NULL;
-}
-
-#ifdef TEST_PARSER
-int main(int argc, char **argv)
-{
- const char *board_name = "QZUX";
- char next_line[1000]; /* Should be enough for the largest descriptor. */
- int rv;
- int count;
-
- if (argc < 2) {
- fprintf(stderr, "Name of the file to parse is required.\n");
- return -1;
- }
-
- if (parser_find_board(argv[1], board_name)) {
- fprintf(stderr, "Board %s NOT found\n", board_name);
- return -1;
- }
-
- count = 0;
- do {
- struct addr_range *range;
-
- rv = parser_get_next_range(&range);
- count++;
- printf("Section %d, rv %d\n", count, rv);
- free(range); /* Freeing NULL is OK. */
-
- } while (rv != -ENODATA);
-
- return 0;
-}
-#endif
diff --git a/extra/usb_updater/desc_parser.h b/extra/usb_updater/desc_parser.h
deleted file mode 100644
index faa80d1a63..0000000000
--- a/extra/usb_updater/desc_parser.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2018 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef __EXTRA_USB_UPDATER_DESC_PARSER_H
-#define __EXTRA_USB_UPDATER_DESC_PARSER_H
-
-#include <stddef.h>
-#include <stdint.h>
-
-struct result_node {
- uint8_t expected_result[32];
-};
-
-enum range_type_t {
- NOT_A_RANGE,
- AP_RANGE,
- EC_RANGE,
- EC_GANG_RANGE,
-};
-
-struct addr_range {
- enum range_type_t range_type;
- uint32_t base_addr;
- uint32_t range_size;
- size_t variant_count; /* Set to zero for dump ranges. */
- struct result_node variants[0];
-};
-
-/* Board description retrieval API includes the following functions. */
-
-/*
- * In the given hash database file find board by its ID. Return zero on
- * success, or OS error of error. In particular ENODATA is returned if the
- * section for the required board ID is not found in the file.
- */
-int parser_find_board(const char *hash_file_name, const char board_id[4]);
-
-/*
- * Find next range for the previousely defined board, parse it into the
- * addr_range structure and return pointer to the parsed structure to the
- * caller, set pointer to NULL if no more entries are available or in case of
- * error.
- *
- * Caller of this function is responsible for returning memory allocated for
- * the entry.
- *
- * Return value set to zero on success, or to OS error if one occurs. EIO is
- * used if an attmept to get next range is made before hash database file was
- * opened and board entry in it was found.
- */
-int parser_get_next_range(struct addr_range **range);
-
-/* Close the hash database file. */
-void parser_done(void);
-
-#endif // __EXTRA_USB_UPDATER_DESC_PARSER_H
diff --git a/extra/usb_updater/ecusb b/extra/usb_updater/ecusb
deleted file mode 120000
index c06ee0f51b..0000000000
--- a/extra/usb_updater/ecusb
+++ /dev/null
@@ -1 +0,0 @@
-../tigertool/ecusb/ \ No newline at end of file
diff --git a/extra/usb_updater/fw_update.py b/extra/usb_updater/fw_update.py
deleted file mode 100755
index 0d7a570fc3..0000000000
--- a/extra/usb_updater/fw_update.py
+++ /dev/null
@@ -1,426 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-#
-# Ignore indention messages, since legacy scripts use 2 spaces instead of 4.
-# pylint: disable=bad-indentation,docstring-section-indent
-# pylint: disable=docstring-trailing-quotes
-
-# Upload firmware over USB
-# Note: This is a py2/3 compatible file.
-
-from __future__ import print_function
-
-import argparse
-import array
-import json
-import os
-import struct
-import sys
-import time
-from pprint import pprint
-import usb
-
-
-debug = False
-def debuglog(msg):
- if debug:
- print(msg)
-
-def log(msg):
- print(msg)
- sys.stdout.flush()
-
-
-"""Sends firmware update to CROS EC usb endpoint."""
-
-class Supdate(object):
- """Class to access firmware update endpoints.
-
- Usage:
- d = Supdate()
-
- Instance Variables:
- _dev: pyUSB device object
- _read_ep: pyUSB read endpoint for this interface
- _write_ep: pyUSB write endpoint for this interface
- """
- USB_SUBCLASS_GOOGLE_UPDATE = 0x53
- USB_CLASS_VENDOR = 0xFF
-
- def __init__(self):
- pass
-
-
- def connect_usb(self, serialname=None):
- """Initial discovery and connection to USB endpoint.
-
- This searches for a USB device matching the VID:PID specified
- in the config file, optionally matching a specified serialname.
-
- Args:
- serialname: Find the device with this serial, in case multiple
- devices are attached.
-
- Returns:
- True on success.
- Raises:
- Exception on error.
- """
- # Find the stm32.
- vendor = self._brdcfg['vid']
- product = self._brdcfg['pid']
-
- dev_g = usb.core.find(idVendor=vendor, idProduct=product, find_all=True)
- dev_list = list(dev_g)
- if dev_list is None:
- raise Exception("Update", "USB device not found")
-
- # Check if we have multiple stm32s and we've specified the serial.
- dev = None
- if serialname:
- for d in dev_list:
- if usb.util.get_string(d, d.iSerialNumber) == serialname:
- dev = d
- break
- if dev is None:
- raise SusbError("USB device(%s) not found" % serialname)
- else:
- try:
- dev = dev_list[0]
- except:
- dev = dev_list.next()
-
- debuglog("Found stm32: %04x:%04x" % (vendor, product))
- self._dev = dev
-
- # Get an endpoint instance.
- try:
- dev.set_configuration()
- except:
- pass
- cfg = dev.get_active_configuration()
-
- intf = usb.util.find_descriptor(cfg, custom_match=lambda i: \
- i.bInterfaceClass==self.USB_CLASS_VENDOR and \
- i.bInterfaceSubClass==self.USB_SUBCLASS_GOOGLE_UPDATE)
-
- self._intf = intf
- debuglog("Interface: %s" % intf)
- debuglog("InterfaceNumber: %s" % intf.bInterfaceNumber)
-
- read_ep = usb.util.find_descriptor(
- intf,
- # match the first IN endpoint
- custom_match = \
- lambda e: \
- usb.util.endpoint_direction(e.bEndpointAddress) == \
- usb.util.ENDPOINT_IN
- )
-
- self._read_ep = read_ep
- debuglog("Reader endpoint: 0x%x" % read_ep.bEndpointAddress)
-
- write_ep = usb.util.find_descriptor(
- intf,
- # match the first OUT endpoint
- custom_match = \
- lambda e: \
- usb.util.endpoint_direction(e.bEndpointAddress) == \
- usb.util.ENDPOINT_OUT
- )
-
- self._write_ep = write_ep
- debuglog("Writer endpoint: 0x%x" % write_ep.bEndpointAddress)
-
- return True
-
-
- def wr_command(self, write_list, read_count=1, wtimeout=100, rtimeout=2000):
- """Write command to logger logic..
-
- This function writes byte command values list to stm, then reads
- byte status.
-
- Args:
- write_list: list of command byte values [0~255].
- read_count: number of status byte values to read.
- wtimeout: mS to wait for write success
- rtimeout: mS to wait for read success
-
- Returns:
- status byte, if one byte is read,
- byte list, if multiple bytes are read,
- None, if no bytes are read.
-
- Interface:
- write: [command, data ... ]
- read: [status ]
- """
- debuglog("wr_command(write_list=[%s] (%d), read_count=%s)" % (
- list(bytearray(write_list)), len(write_list), read_count))
-
- # Clean up args from python style to correct types.
- write_length = 0
- if write_list:
- write_length = len(write_list)
- if not read_count:
- read_count = 0
-
- # Send command to stm32.
- if write_list:
- cmd = write_list
- ret = self._write_ep.write(cmd, wtimeout)
- debuglog("RET: %s " % ret)
-
- # Read back response if necessary.
- if read_count:
- bytesread = self._read_ep.read(512, rtimeout)
- debuglog("BYTES: [%s]" % bytesread)
-
- if len(bytesread) != read_count:
- debuglog("Unexpected bytes read: %d, expected: %d" % (len(bytesread), read_count))
- pass
-
- debuglog("STATUS: 0x%02x" % int(bytesread[0]))
- if read_count == 1:
- return bytesread[0]
- else:
- return bytesread
-
- return None
-
- def stop(self):
- """Finalize system flash and exit."""
- cmd = struct.pack(">I", 0xB007AB1E)
- read = self.wr_command(cmd, read_count=4)
-
- if len(read) == 4:
- log("Finished flashing")
- return
-
- raise Exception("Update", "Stop failed [%s]" % read)
-
-
- def write_file(self):
- """Write the update region packet by packet to USB
-
- This sends write packets of size 128B out, in 32B chunks.
- Overall, this will write all data in the inactive code region.
-
- Raises:
- Exception if write failed or address out of bounds.
- """
- region = self._region
- flash_base = self._brdcfg["flash"]
- offset = self._base - flash_base
- if offset != self._brdcfg['regions'][region][0]:
- raise Exception("Update", "Region %s offset 0x%x != available offset 0x%x" % (
- region, self._brdcfg['regions'][region][0], offset))
-
- length = self._brdcfg['regions'][region][1]
- log("Sending")
-
- # Go to the correct region in the ec.bin file.
- self._binfile.seek(offset)
-
- # Send 32 bytes at a time. Must be less than the endpoint's max packet size.
- maxpacket = 32
-
- # While data is left, create update packets.
- while length > 0:
- # Update packets are 128B. We can use any number
- # but the micro must malloc this memory.
- pagesize = min(length, 128)
-
- # Packet is:
- # packet size: page bytes transferred plus 3 x 32b values header.
- # cmd: n/a
- # base: flash address to write this packet.
- # data: 128B of data to write into flash_base
- cmd = struct.pack(">III", pagesize + 12, 0, offset + flash_base)
- read = self.wr_command(cmd, read_count=0)
-
- # Push 'todo' bytes out the pipe.
- todo = pagesize
- while todo > 0:
- packetsize = min(maxpacket, todo)
- data = self._binfile.read(packetsize)
- if len(data) != packetsize:
- raise Exception("Update", "No more data from file")
- for i in range(0, 10):
- try:
- self.wr_command(data, read_count=0)
- break
- except:
- log("Timeout fail")
- todo -= packetsize
- # Done with this packet, move to the next one.
- length -= pagesize
- offset += pagesize
-
- # Validate that the micro thinks it successfully wrote the data.
- read = self.wr_command(''.encode(), read_count=4)
- result = struct.unpack("<I", read)
- result = result[0]
- if result != 0:
- raise Exception("Update", "Upload failed with rc: 0x%x" % result)
-
-
- def start(self):
- """Start a transaction and erase currently inactive region.
-
- This function sends a start command, and receives the base of the
- preferred inactive region. This could be RW, RW_B,
- or RO (if there's no RW_B)
-
- Note that the region is erased here, so you'd better program the RO if
- you just erased it. TODO(nsanders): Modify the protocol to allow active
- region select or query before erase.
- """
-
- # Size is 3 uint32 fields
- # packet: [packetsize, cmd, base]
- size = 4 + 4 + 4
- # Return value is [status, base_addr]
- expected = 4 + 4
-
- cmd = struct.pack("<III", size, 0, 0)
- read = self.wr_command(cmd, read_count=expected)
-
- if len(read) == 4:
- raise Exception("Update", "Protocol version 0 not supported")
- elif len(read) == expected:
- base, version = struct.unpack(">II", read)
- log("Update protocol v. %d" % version)
- log("Available flash region base: %x" % base)
- else:
- raise Exception("Update", "Start command returned %d bytes" % len(read))
-
- if base < 256:
- raise Exception("Update", "Start returned error code 0x%x" % base)
-
- self._base = base
- flash_base = self._brdcfg["flash"]
- self._offset = self._base - flash_base
-
- # Find our active region.
- for region in self._brdcfg['regions']:
- if (self._offset >= self._brdcfg['regions'][region][0]) and \
- (self._offset < (self._brdcfg['regions'][region][0] + \
- self._brdcfg['regions'][region][1])):
- log("Active region: %s" % region)
- self._region = region
-
-
- def load_board(self, brdfile):
- """Load firmware layout file.
-
- example as follows:
- {
- "board": "servo micro",
- "vid": 6353,
- "pid": 20506,
- "flash": 134217728,
- "regions": {
- "RW": [65536, 65536],
- "PSTATE": [61440, 4096],
- "RO": [0, 61440]
- }
- }
-
- Args:
- brdfile: path to board description file.
- """
- with open(brdfile) as data_file:
- data = json.load(data_file)
-
- # TODO(nsanders): validate this data before moving on.
- self._brdcfg = data;
- if debug:
- pprint(data)
-
- log("Board is %s" % self._brdcfg['board'])
- # Cast hex strings to int.
- self._brdcfg['flash'] = int(self._brdcfg['flash'], 0)
- self._brdcfg['vid'] = int(self._brdcfg['vid'], 0)
- self._brdcfg['pid'] = int(self._brdcfg['pid'], 0)
-
- log("Flash Base is %x" % self._brdcfg['flash'])
- self._flashsize = 0
- for region in self._brdcfg['regions']:
- base = int(self._brdcfg['regions'][region][0], 0)
- length = int(self._brdcfg['regions'][region][1], 0)
- log("region %s\tbase:0x%08x size:0x%08x" % (
- region, base, length))
- self._flashsize += length
-
- # Convert these to int because json doesn't support hex.
- self._brdcfg['regions'][region][0] = base
- self._brdcfg['regions'][region][1] = length
-
- log("Flash Size: 0x%x" % self._flashsize)
-
- def load_file(self, binfile):
- """Open and verify size of the target ec.bin file.
-
- Args:
- binfile: path to ec.bin
-
- Raises:
- Exception on file not found or filesize not matching.
- """
- self._filesize = os.path.getsize(binfile)
- self._binfile = open(binfile, 'rb')
-
- if self._filesize != self._flashsize:
- raise Exception("Update", "Flash size 0x%x != file size 0x%x" % (self._flashsize, self._filesize))
-
-
-
-# Generate command line arguments
-parser = argparse.ArgumentParser(description="Update firmware over usb")
-parser.add_argument('-b', '--board', type=str, help="Board configuration json file", default="board.json")
-parser.add_argument('-f', '--file', type=str, help="Complete ec.bin file", default="ec.bin")
-parser.add_argument('-s', '--serial', type=str, help="Serial number", default="")
-parser.add_argument('-l', '--list', action="store_true", help="List regions")
-parser.add_argument('-v', '--verbose', action="store_true", help="Chatty output")
-
-def main():
- global debug
- args = parser.parse_args()
-
-
- brdfile = args.board
- serial = args.serial
- binfile = args.file
- if args.verbose:
- debug = True
-
- with open(brdfile) as data_file:
- names = json.load(data_file)
-
- p = Supdate()
- p.load_board(brdfile)
- p.connect_usb(serialname=serial)
- p.load_file(binfile)
-
- # List solely prints the config.
- if (args.list):
- return
-
- # Start transfer and erase.
- p.start()
- # Upload the bin file
- log("Uploading %s" % binfile)
- p.write_file()
-
- # Finalize
- log("Done. Finalizing.")
- p.stop()
-
-if __name__ == "__main__":
- main()
-
-
diff --git a/extra/usb_updater/sample_descriptor b/extra/usb_updater/sample_descriptor
deleted file mode 100644
index 1566e9e2e1..0000000000
--- a/extra/usb_updater/sample_descriptor
+++ /dev/null
@@ -1,87 +0,0 @@
-# Copyright 2018 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-#
-# Hash descriptor database file consists of sections for various Chrome OS
-# boards. Each board description section starts with a line of 4 characters
-# which is the board ID (the same as the board's RLZ code).
-#
-# Each board description section includes variable number of range
-# descriptor entries, each entry consisting of semicolon separated fields:
-#
-# {a|e|g}:{h|d}:base_addr:size[:value[:value[:value...]]]]
-#
-# Where
-#
-# - the first sindgle character field defines the way the range is accessed:
-# a - AP flash
-# e - EC flash
-# g - EC flash requiring gang programming mode
-# - the second single character field defines the range type
-# h - Cr50 returns the hash of the range
-# d - Cr50 returns actual contents of the range (hex dump)
-# - the third and and forth fields are base address and size of the range
-# - ranges of type 'h' include one or more values for the hash of the range.
-#
-# Descriptor entries can be split along multiple lines. Each entry is
-# terminated by an empty line. Board description section is completed when
-# another board ID or end of file is encountered.
-#
-# All values are expressed in hex. Repeating empty lines and lines starting
-# with '#' are ignored.
-#
-
-QZUX
-
-# 1: Valid hash section.
-a:h:0:10000:
-756c41b90ac9aa23a6c98ce13549dccd72e0a83f8537eb834d9cfc3d12bf3503:
-336c41b90ac9aa23a6c98ce13549dccd72e0a83f8537eb834d9cfc3d12bf3503:
-446c41b90ac9aa23a6c98ce13549dccd72e0a83f8537eb834d9cfc3d12bf3503
-
-# 2: Valid dump section.
-a:d:10:10
-
-# 3: Valid hash section.
-e:h:0:100:
-55d262badc1116520a7ae1d3fda380c0382b4b87f0db10de6495053ba3aadb87:
-444442badc1116520a7ae1d3fda380c0382b4b87f0db10de6495053ba3aadb87:
-443322badc1116520a7ae1d3fda380c0382b4b87f0db10de6495053ba3aadb87
-
-# 4: Invalid dump section (includes hash)
-a:d:20:10:55d262badc1116520a7ae1d3fda380c0382b4b87f0db10de6495053ba3aadb87
-
-# 5: Invalid hash section (does not include hash)
-e:h:0:100:
-
-# 6: Another invalid hash section (does not include hash)
-e:h:0:100:
-
-# extra empty lines
-
-
-# 7: Invalid hash section (hash too short)
-e:h:0:100:
-55d262badc1116520a7ae1d3fda380c0382b4b87f0db10de6495053ba3aadb8
-
-# 8: Invalid hash section (hash too long)
-a:h:0:10000:
-756c41b90ac9aa23a6c98ce13549dccd72e0a83f8537eb834d9cfc3d12bf35034:
-336c41b90ac9aa23a6c98ce13549dccd72e0a83f8537eb834d9cfc3d12bf3503
-
-# 9: Invalid hash section (hash includes non-hex value)
-a:h:0:10000:
-756c41b90ac9aa23a6c98ce13549dccd7xe0a83f8537eb834d9cfc3d12bf3503:
-336c41b90ac9aa23a6c98ce13549dccd72e0a83f8537eb834d9cfc3d12bf3505
-
-# 10: Invalid hash section (hash does not include 3 variants)
-a:h:0:10000:
-756c41b90ac9aa23a6c98ce13549dccd75e0a83f8537eb834d9cfc3d12bf3503:
-336c41b90ac9aa23a6c98ce13549dccd72e0a83f8537eb834d9cfc3d12bf3505
-
-# 11: Invalid dump section (size includes non hex character)
-a:d:10:10x
-
-ABCD
-
-a:d:10:10
diff --git a/extra/usb_updater/servo_micro.json b/extra/usb_updater/servo_micro.json
deleted file mode 100644
index 71b1fd25dc..0000000000
--- a/extra/usb_updater/servo_micro.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "Comment": "This file describes the updateable sections of the flash.",
- "board": "servo_micro",
- "vid": "0x18d1",
- "pid": "0x501a",
- "console": "3",
- "Comment on flash": "This is the base address of writeable flash",
- "flash": "0x8000000",
- "Comment on region format": "name: [baseoffset, length]",
- "regions": {
- "RW": ["0x10000", "0x10000"],
- "PSTATE": ["0xf000", "0x1000"],
- "RO": ["0x0000", "0xf000"]
- }
-}
diff --git a/extra/usb_updater/servo_updater.py b/extra/usb_updater/servo_updater.py
deleted file mode 100755
index 4dff264182..0000000000
--- a/extra/usb_updater/servo_updater.py
+++ /dev/null
@@ -1,456 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-#
-# Ignore indention messages, since legacy scripts use 2 spaces instead of 4.
-# pylint: disable=bad-indentation,docstring-section-indent
-# pylint: disable=docstring-trailing-quotes
-
-# Note: This is a py2/3 compatible file.
-
-from __future__ import print_function
-
-import argparse
-import errno
-import os
-import re
-import subprocess
-import time
-import tempfile
-
-import json
-
-import fw_update
-import ecusb.tiny_servo_common as c
-from ecusb import tiny_servod
-
-class ServoUpdaterException(Exception):
- """Raised on exceptions generated by servo_updater."""
-
-BOARD_C2D2 = 'c2d2'
-BOARD_SERVO_MICRO = 'servo_micro'
-BOARD_SERVO_V4 = 'servo_v4'
-BOARD_SERVO_V4P1 = 'servo_v4p1'
-BOARD_SWEETBERRY = 'sweetberry'
-
-DEFAULT_BOARD = BOARD_SERVO_V4
-
-# These lists are to facilitate exposing choices in the command-line tool
-# below.
-BOARDS = [BOARD_C2D2, BOARD_SERVO_MICRO, BOARD_SERVO_V4, BOARD_SERVO_V4P1,
- BOARD_SWEETBERRY]
-
-# Servo firmware bundles four channels of firmware. We need to make sure the
-# user does not request a non-existing channel, so keep the lists around to
-# guard on command-line usage.
-
-DEFAULT_CHANNEL = STABLE_CHANNEL = 'stable'
-
-PREV_CHANNEL = 'prev'
-
-# The ordering here matters. From left to right it's the channel that the user
-# is most likely to be running. This is used to inform and warn the user if
-# there are issues. e.g. if the all channels are the same, we want to let the
-# user know they are running the 'stable' version before letting them know they
-# are running 'dev' or even 'alpah' which (while true) might cause confusion.
-
-CHANNELS = [DEFAULT_CHANNEL, PREV_CHANNEL, 'dev', 'alpha']
-
-DEFAULT_BASE_PATH = '/usr/'
-TEST_IMAGE_BASE_PATH = '/usr/local/'
-
-COMMON_PATH = 'share/servo_updater'
-
-FIRMWARE_DIR = "firmware/"
-CONFIGS_DIR = "configs/"
-
-RETRIES_COUNT = 10
-RETRIES_DELAY = 1
-
-def do_with_retries(func, *args):
- """
- Call function passed as argument and check if no error happened.
- If exception was raised by function,
- it will be retried up to RETRIES_COUNT times.
-
- Args:
- func: function that will be called
- args: arguments passed to 'func'
-
- Returns:
- If call to function was successful, its result will be returned.
- If retries count was exceeded, exception will be raised.
- """
-
- retry = 0
- while retry < RETRIES_COUNT:
- try:
- return func(*args)
- except Exception as e:
- print("Retrying function %s: %s" % (func.__name__, e))
- retry = retry + 1
- time.sleep(RETRIES_DELAY)
- continue
-
- raise Exception("'{}' failed after {} retries".format(func.__name__, RETRIES_COUNT))
-
-def flash(brdfile, serialno, binfile):
- """
- Call fw_update to upload to updater USB endpoint.
-
- Args:
- brdfile: path to board configuration file
- serialno: device serial number
- binfile: firmware file
- """
-
- p = fw_update.Supdate()
- p.load_board(brdfile)
- p.connect_usb(serialname=serialno)
- p.load_file(binfile)
-
- # Start transfer and erase.
- p.start()
- # Upload the bin file
- print("Uploading %s" % binfile)
- p.write_file()
-
- # Finalize
- print("Done. Finalizing.")
- p.stop()
-
-def flash2(vidpid, serialno, binfile):
- """
- Call fw update via usb_updater2 commandline.
-
- Args:
- vidpid: vendor id and product id of device
- serialno: device serial number (optional)
- binfile: firmware file
- """
-
- tool = 'usb_updater2'
- cmd = "%s -d %s" % (tool, vidpid)
- if serialno:
- cmd += " -S %s" % serialno
- cmd += " -n"
- cmd += " %s" % binfile
-
- print(cmd)
- help_cmd = '%s --help' % tool
- with open('/dev/null') as devnull:
- valid_check = subprocess.call(help_cmd.split(), stdout=devnull,
- stderr=devnull)
- if valid_check:
- raise ServoUpdaterException('%s exit with res = %d. Make sure the tool '
- 'is available on the device.' % (help_cmd,
- valid_check))
- res = subprocess.call(cmd.split())
-
- if res in (0, 1, 2):
- return res
- else:
- raise ServoUpdaterException("%s exit with res = %d" % (cmd, res))
-
-def select(tinys, region):
- """
- Ensure the servo is in the expected ro/rw region.
- This function jumps to the required region and verify if jump was
- successful by executing 'sysinfo' command and reading current region.
- If response was not received or region is invalid, exception is raised.
-
- Args:
- tinys: TinyServod object
- region: region to jump to, only "rw" and "ro" is allowed
- """
-
- if region not in ["rw", "ro"]:
- raise Exception("Region must be ro or rw")
-
- if region is "ro":
- cmd = "reboot"
- else:
- cmd = "sysjump %s" % region
-
- tinys.pty._issue_cmd(cmd)
-
- tinys.close()
- time.sleep(2)
- tinys.reinitialize()
-
- res = tinys.pty._issue_cmd_get_results("sysinfo", ["Copy:[\s]+(RO|RW)"])
- current_region = res[0][1].lower()
- if current_region != region:
- raise Exception("Invalid region: %s/%s" % (current_region, region))
-
-def do_version(tinys):
- """Check version via ec console 'pty'.
-
- Args:
- tinys: TinyServod object
-
- Returns:
- detected version number
-
- Commands are:
- # > version
- # ...
- # Build: tigertail_v1.1.6749-74d1a312e
- """
- cmd = '\r\nversion\r\n'
- regex = 'Build:\s+(\S+)[\r\n]+'
-
- results = tinys.pty._issue_cmd_get_results(cmd, [regex])[0]
-
- return results[1].strip(' \t\r\n\0')
-
-def do_updater_version(tinys):
- """Check whether this uses python updater or c++ updater
-
- Args:
- tinys: TinyServod object
-
- Returns:
- updater version number. 2 or 6.
- """
- vers = do_version(tinys)
-
- # Servo versions below 58 are from servo-9040.B. Versions starting with _v2
- # are newer than anything _v1, no need to check the exact number. Updater
- # version is not directly queryable.
- if re.search('_v[2-9]\.\d', vers):
- return 6
- m = re.search('_v1\.1\.(\d\d\d\d)', vers)
- if m:
- version_number = int(m.group(1))
- if version_number < 5800:
- return 2
- else:
- return 6
- raise ServoUpdaterException(
- "Can't determine updater target from vers: [%s]" % vers)
-
-def _extract_version(boardname, binfile):
- """Find the version string from |binfile|.
-
- Args:
- boardname: the name of the board, eg. "servo_micro"
- binfile: path to the binary to search
-
- Returns:
- the version string.
- """
- if boardname is None:
- # cannot extract the version if the name is None
- return None
- rawstrings = subprocess.check_output(
- ['cbfstool', binfile, 'read', '-r', 'RO_FRID', '-f', '/dev/stdout'],
- **c.get_subprocess_args())
- m = re.match(r'%s_v\S+' % boardname, rawstrings)
- if m:
- newvers = m.group(0).strip(' \t\r\n\0')
- else:
- raise ServoUpdaterException("Can't find version from file: %s." % binfile)
-
- return newvers
-
-def get_firmware_channel(bname, version):
- """Find out which channel |version| for |bname| came from.
-
- Args:
- bname: board name
- version: current version string
-
- Returns:
- one of the channel names if |version| came from one of those, or None
- """
- for channel in CHANNELS:
- # Pass |bname| as cname to find the board specific file, and pass None as
- # fname to ensure the default directory is searched
- _, _, vers = get_files_and_version(bname, None, channel=channel)
- if version == vers:
- return channel
- # None of the channels matched. This firmware is currently unknown.
- return None
-
-def get_files_and_version(cname, fname=None, channel=DEFAULT_CHANNEL):
- """Select config and firmware binary files.
-
- This checks default file names and paths.
- In: /usr/share/servo_updater/[firmware|configs]
- check for board.json, board.bin
-
- Args:
- cname: board name, or config name. eg. "servo_v4" or "servo_v4.json"
- fname: firmware binary name. Can be None to try default.
- channel: the channel requested for servo firmware. See |CHANNELS| above.
-
- Returns:
- cname, fname, version: validated filenames selected from the path.
- """
- for p in (DEFAULT_BASE_PATH, TEST_IMAGE_BASE_PATH):
- updater_path = os.path.join(p, COMMON_PATH)
- if os.path.exists(updater_path):
- break
- else:
- raise ServoUpdaterException('servo_updater/ dir not found in known spots.')
-
- firmware_path = os.path.join(updater_path, FIRMWARE_DIR)
- configs_path = os.path.join(updater_path, CONFIGS_DIR)
-
- for p in (firmware_path, configs_path):
- if not os.path.exists(p):
- raise ServoUpdaterException('Could not find required path %r' % p)
-
- if not os.path.isfile(cname):
- # If not an existing file, try checking on the default path.
- newname = os.path.join(configs_path, cname)
- if os.path.isfile(newname):
- cname = newname
- else:
- # Try appending ".json" to convert board name to config file.
- cname = newname + ".json"
- if not os.path.isfile(cname):
- raise ServoUpdaterException("Can't find config file: %s." % cname)
-
- # Always retrieve the boardname
- with open(cname) as data_file:
- data = json.load(data_file)
- boardname = data['board']
-
- if not fname:
- # If no |fname| supplied, look for the default locations with the board
- # and channel requested.
- binary_file = '%s.%s.bin' % (boardname, channel)
- newname = os.path.join(firmware_path, binary_file)
- if os.path.isfile(newname):
- fname = newname
- else:
- raise ServoUpdaterException("Can't find firmware binary: %s." %
- binary_file)
- elif not os.path.isfile(fname):
- # If a name is specified but not found, try the default path.
- newname = os.path.join(firmware_path, fname)
- if os.path.isfile(newname):
- fname = newname
- else:
- raise ServoUpdaterException("Can't find file: %s." % fname)
-
- # Lastly, retrieve the version as well for decision making, debug, and
- # informational purposes.
- binvers = _extract_version(boardname, fname)
-
- return cname, fname, binvers
-
-def main():
- parser = argparse.ArgumentParser(description="Image a servo device")
- parser.add_argument('-p', '--print', dest='print_only', action='store_true',
- default=False,
- help='only print available firmware for board/channel')
- parser.add_argument('-s', '--serialno', type=str,
- help="serial number to program", default=None)
- parser.add_argument('-b', '--board', type=str,
- help="Board configuration json file",
- default=DEFAULT_BOARD, choices=BOARDS)
- parser.add_argument('-c', '--channel', type=str,
- help="Firmware channel to use",
- default=DEFAULT_CHANNEL, choices=CHANNELS)
- parser.add_argument('-f', '--file', type=str,
- help="Complete ec.bin file", default=None)
- parser.add_argument('--force', action="store_true",
- help="Update even if version match", default=False)
- parser.add_argument('-v', '--verbose', action="store_true",
- help="Chatty output")
- parser.add_argument('-r', '--reboot', action="store_true",
- help="Always reboot, even after probe.")
-
- args = parser.parse_args()
-
- brdfile, binfile, newvers = get_files_and_version(args.board, args.file,
- args.channel)
-
- # If the user only cares about the information then just print it here,
- # and exit.
- if args.print_only:
- output = ('board: %s\n'
- 'channel: %s\n'
- 'firmware: %s') % (args.board, args.channel, newvers)
- print(output)
- return
-
- serialno = args.serialno
-
- with open(brdfile) as data_file:
- data = json.load(data_file)
- vid, pid = int(data['vid'], 0), int(data['pid'], 0)
- vidpid = "%04x:%04x" % (vid, pid)
- iface = int(data['console'], 0)
- boardname = data['board']
-
- # Make sure device is up.
- print("===== Waiting for USB device =====")
- c.wait_for_usb(vidpid, serialname=serialno)
- # We need a tiny_servod to query some information. Set it up first.
- tinys = tiny_servod.TinyServod(vid, pid, iface, serialno, args.verbose)
-
- if not args.force:
- vers = do_version(tinys)
- print("Current %s version is %s" % (boardname, vers))
- print("Available %s version is %s" % (boardname, newvers))
-
- if newvers == vers:
- print("No version update needed")
- if args.reboot:
- select(tinys, 'ro')
- return
- else:
- print("Updating to recommended version.")
-
- # Make sure the servo MCU is in RO
- print("===== Jumping to RO =====")
- do_with_retries(select, tinys, 'ro')
-
- print("===== Flashing RW =====")
- vers = do_with_retries(do_updater_version, tinys)
- # To make sure that the tiny_servod here does not interfere with other
- # processes, close it out.
- tinys.close()
-
- if vers == 2:
- flash(brdfile, serialno, binfile)
- elif vers == 6:
- flash2(vidpid, serialno, binfile)
- else:
- raise ServoUpdaterException("Can't detect updater version")
-
- # Make sure device is up.
- c.wait_for_usb(vidpid, serialname=serialno)
- # After we have made sure that it's back/available, reconnect the tiny servod.
- tinys.reinitialize()
-
- # Make sure the servo MCU is in RW
- print("===== Jumping to RW =====")
- do_with_retries(select, tinys, 'rw')
-
- print("===== Flashing RO =====")
- vers = do_with_retries(do_updater_version, tinys)
-
- if vers == 2:
- flash(brdfile, serialno, binfile)
- elif vers == 6:
- flash2(vidpid, serialno, binfile)
- else:
- raise ServoUpdaterException("Can't detect updater version")
-
- # Make sure the servo MCU is in RO
- print("===== Rebooting =====")
- do_with_retries(select, tinys, 'ro')
- # Perform additional reboot to free USB/UART resources, taken by tiny servod.
- # See https://issuetracker.google.com/196021317 for background.
- tinys.pty._issue_cmd("reboot")
-
- print("===== Finished =====")
-
-if __name__ == "__main__":
- main()
diff --git a/extra/usb_updater/servo_v4.json b/extra/usb_updater/servo_v4.json
deleted file mode 100644
index e041f56b68..0000000000
--- a/extra/usb_updater/servo_v4.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "Comment": "This file describes the updateable sections of the flash.",
- "board": "servo_v4",
- "vid": "0x18d1",
- "pid": "0x501b",
- "console": "0",
- "Comment on flash": "This is the base address of writeable flash",
- "flash": "0x8000000",
- "Comment on region format": "name: [baseoffset, length]",
- "regions": {
- "RW": ["0x10000", "0x10000"],
- "PSTATE": ["0xf000", "0x1000"],
- "RO": ["0x0000", "0xf000"]
- }
-}
diff --git a/extra/usb_updater/servo_v4p1.json b/extra/usb_updater/servo_v4p1.json
deleted file mode 100644
index 46efbf24ad..0000000000
--- a/extra/usb_updater/servo_v4p1.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "Comment": "This file describes the updateable sections of the flash.",
- "board": "servo_v4p1",
- "vid": "0x18d1",
- "pid": "0x520d",
- "console": "0",
- "Comment on flash": "This is the base address of writeable flash",
- "flash": "0x8000000",
- "Comment on region format": "name: [baseoffset, length]",
- "regions": {
- "RW": ["0x10000", "0x10000"],
- "PSTATE": ["0xf000", "0x1000"],
- "RO": ["0x0000", "0xf000"]
- }
-}
diff --git a/extra/usb_updater/sweetberry.json b/extra/usb_updater/sweetberry.json
deleted file mode 100644
index 6b70d19fad..0000000000
--- a/extra/usb_updater/sweetberry.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "Comment": "This file describes the updateable sections of the flash.",
- "board": "sweetberry",
- "vid": "0x18d1",
- "pid": "0x5020",
- "console": "0",
- "Comment on flash": "This is the base address of writeable flash",
- "flash": "0x8000000",
- "Comment on region format": "name: [baseoffset, length]",
- "regions": {
- "RW": ["0x40000", "0x40000"],
- "RO": ["0x0000", "0x40000"]
- }
-}
diff --git a/extra/usb_updater/usb_updater2.c b/extra/usb_updater/usb_updater2.c
deleted file mode 100644
index 12ee1615fc..0000000000
--- a/extra/usb_updater/usb_updater2.c
+++ /dev/null
@@ -1,1244 +0,0 @@
-/*
- * Copyright 2017 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include <asm/byteorder.h>
-#include <endian.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <libusb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <fmap.h>
-
-#ifndef __packed
-#define __packed __attribute__((packed))
-#endif
-
-#include "compile_time_macros.h"
-#include "misc_util.h"
-#include "usb_descriptor.h"
-#include "update_fw.h"
-#include "vb21_struct.h"
-
-#ifdef DEBUG
-#define debug printf
-#else
-#define debug(fmt, args...)
-#endif
-
-/*
- * This file contains the source code of a Linux application used to update
- * EC device firmware (common code only, gsctool takes care of cr50).
- */
-
-#define VID USB_VID_GOOGLE
-#define PID 0x5022
-#define SUBCLASS USB_SUBCLASS_GOOGLE_UPDATE
-#define PROTOCOL USB_PROTOCOL_GOOGLE_UPDATE
-
-enum exit_values {
- noop = 0, /* All up to date, no update needed. */
- all_updated = 1, /* Update completed, reboot required. */
- rw_updated = 2, /* RO was not updated, reboot required. */
- update_error = 3 /* Something went wrong. */
-};
-
-struct usb_endpoint {
- struct libusb_device_handle *devh;
- uint8_t ep_num;
- int chunk_len;
-};
-
-struct transfer_descriptor {
- /*
- * offsets of section available for update (not currently active).
- */
- uint32_t offset;
-
- struct usb_endpoint uep;
-};
-
-/* Information about the target */
-static struct first_response_pdu targ;
-
-static uint16_t protocol_version;
-static uint16_t header_type;
-static char *progname;
-static char *short_opts = "bd:efg:hjlnp:rsS:tuw";
-static const struct option long_opts[] = {
- /* name hasarg *flag val */
- {"binvers", 1, NULL, 'b'},
- {"device", 1, NULL, 'd'},
- {"entropy", 0, NULL, 'e'},
- {"fwver", 0, NULL, 'f'},
- {"tp_debug", 1, NULL, 'g'},
- {"help", 0, NULL, 'h'},
- {"jump_to_rw", 0, NULL, 'j'},
- {"follow_log", 0, NULL, 'l'},
- {"no_reset", 0, NULL, 'n'},
- {"tp_update", 1, NULL, 'p'},
- {"reboot", 0, NULL, 'r'},
- {"stay_in_ro", 0, NULL, 's'},
- {"serial", 1, NULL, 'S'},
- {"tp_info", 0, NULL, 't'},
- {"unlock_rollback", 0, NULL, 'u'},
- {"unlock_rw", 0, NULL, 'w'},
- {},
-};
-
-/* Release USB device and return error to the OS. */
-static void shut_down(struct usb_endpoint *uep)
-{
- libusb_close(uep->devh);
- libusb_exit(NULL);
- exit(update_error);
-}
-
-static void usage(int errs)
-{
- printf("\nUsage: %s [options] <binary image>\n"
- "\n"
- "This updates EC firmware over USB (common code EC, no cr50).\n"
- "The required argument is the full RO+RW image.\n"
- "\n"
- "Options:\n"
- "\n"
- " -b,--binvers Report versions of image's "
- "RW and RO, do not update\n"
- " -d,--device VID:PID USB device (default %04x:%04x)\n"
- " -e,--entropy Add entropy to device secret\n"
- " -f,--fwver Report running firmware versions.\n"
- " -g,--tp_debug <hex data> Touchpad debug command\n"
- " -h,--help Show this message\n"
- " -j,--jump_to_rw Tell EC to jump to RW\n"
- " -l,--follow_log Get console log\n"
- " -p,--tp_update file Update touchpad FW\n"
- " -r,--reboot Tell EC to reboot\n"
- " -s,--stay_in_ro Tell EC to stay in RO\n"
- " -S,--serial Device serial number\n"
- " -t,--tp_info Get touchpad information\n"
- " -u,--unlock_rollback Tell EC to unlock the rollback region\n"
- " -w,--unlock_rw Tell EC to unlock the RW region\n"
- "\n", progname, VID, PID);
-
- exit(errs ? update_error : noop);
-}
-
-static void str2hex(const char *str, uint8_t *data, int *len)
-{
- int i;
- int slen = strlen(str);
-
- if (slen/2 > *len) {
- fprintf(stderr, "Hex string too long.\n");
- exit(update_error);
- }
-
- if (slen % 2 != 0) {
- fprintf(stderr, "Hex string length not a multiple of 2.\n");
- exit(update_error);
- }
-
- for (i = 0, *len = 0; i < slen; i += 2, (*len)++) {
- char *end;
- char tmp[3];
-
- tmp[0] = str[i];
- tmp[1] = str[i+1];
- tmp[2] = 0;
-
- data[*len] = strtol(tmp, &end, 16);
-
- if (*end != 0) {
- fprintf(stderr, "Invalid hex string.\n");
- exit(update_error);
- }
- }
-}
-
-static void hexdump(const uint8_t *data, int len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- printf("%02x", data[i]);
- if ((i % 16) == 15)
- printf("\n");
- }
-
- if ((len % 16) != 0)
- printf("\n");
-}
-
-static void dump_touchpad_info(const uint8_t *data, int len)
-{
- const struct touchpad_info *info = (const struct touchpad_info *)data;
-
- if (len != sizeof(struct touchpad_info)) {
- fprintf(stderr, "Hex string length is not %zu",
- sizeof(struct touchpad_info));
- hexdump(data, len);
- return;
- }
-
- printf("\n");
- printf("status: 0x%02x\n", info->status);
- printf("vendor: 0x%04x\n", info->vendor);
- printf("fw_address: 0x%08x\n", info->fw_address);
- printf("fw_size: 0x%08x\n", info->fw_size);
-
- printf("allowed_fw_hash:\n");
- hexdump(info->allowed_fw_hash, sizeof(info->allowed_fw_hash));
-
- switch (info->vendor) {
- case 0x04f3: /* ELAN */
- case 0x0483: /* ST */
- printf("id: 0x%04x\n", info->elan.id);
- printf("fw_version: 0x%04x\n", info->elan.fw_version);
- printf("fw_fw_checksum: 0x%04x\n", info->elan.fw_checksum);
- break;
- default:
- fprintf(stderr, "Unknown vendor, vendor specific data:\n");
- hexdump((const uint8_t *)&info->elan, sizeof(info->elan));
- break;
- }
-}
-
-/* Read file into buffer */
-static uint8_t *get_file_or_die(const char *filename, size_t *len_ptr)
-{
- FILE *fp;
- struct stat st;
- uint8_t *data;
- size_t len;
-
- fp = fopen(filename, "rb");
- if (!fp) {
- perror(filename);
- exit(update_error);
- }
- if (fstat(fileno(fp), &st)) {
- perror("stat");
- exit(update_error);
- }
-
- len = st.st_size;
-
- data = malloc(len);
- if (!data) {
- perror("malloc");
- exit(update_error);
- }
-
- if (fread(data, st.st_size, 1, fp) != 1) {
- perror("fread");
- exit(update_error);
- }
-
- fclose(fp);
-
- *len_ptr = len;
- return data;
-}
-
-#define USB_ERROR(m, r) \
- fprintf(stderr, "%s:%d, %s returned %d (%s)\n", __FILE__, __LINE__, \
- m, r, libusb_strerror(r))
-
-/*
- * Actual USB transfer function, the 'allow_less' flag indicates that the
- * valid response could be shortef than allotted memory, the 'rxed_count'
- * pointer, if provided along with 'allow_less' lets the caller know how mavy
- * bytes were received.
- */
-static void do_xfer(struct usb_endpoint *uep, void *outbuf, int outlen,
- void *inbuf, int inlen, int allow_less,
- size_t *rxed_count)
-{
-
- int r, actual;
-
- /* Send data out */
- if (outbuf && outlen) {
- actual = 0;
- r = libusb_bulk_transfer(uep->devh, uep->ep_num,
- outbuf, outlen,
- &actual, 2000);
- if (r < 0) {
- USB_ERROR("libusb_bulk_transfer", r);
- exit(update_error);
- }
- if (actual != outlen) {
- fprintf(stderr, "%s:%d, only sent %d/%d bytes\n",
- __FILE__, __LINE__, actual, outlen);
- shut_down(uep);
- }
- }
-
- /* Read reply back */
- if (inbuf && inlen) {
-
- actual = 0;
- r = libusb_bulk_transfer(uep->devh, uep->ep_num | 0x80,
- inbuf, inlen,
- &actual, 5000);
- if (r < 0) {
- USB_ERROR("libusb_bulk_transfer", r);
- exit(update_error);
- }
- if ((actual != inlen) && !allow_less) {
- fprintf(stderr, "%s:%d, only received %d/%d bytes\n",
- __FILE__, __LINE__, actual, inlen);
- hexdump(inbuf, actual);
- shut_down(uep);
- }
-
- if (rxed_count)
- *rxed_count = actual;
- }
-}
-
-static void xfer(struct usb_endpoint *uep, void *outbuf,
- size_t outlen, void *inbuf, size_t inlen, int allow_less)
-{
- do_xfer(uep, outbuf, outlen, inbuf, inlen, allow_less, NULL);
-}
-
-/* Return 0 on error, since it's never gonna be EP 0 */
-static int find_endpoint(const struct libusb_interface_descriptor *iface,
- struct usb_endpoint *uep)
-{
- const struct libusb_endpoint_descriptor *ep;
-
- if (iface->bInterfaceClass == 255 &&
- iface->bInterfaceSubClass == SUBCLASS &&
- iface->bInterfaceProtocol == PROTOCOL &&
- iface->bNumEndpoints) {
- ep = &iface->endpoint[0];
- uep->ep_num = ep->bEndpointAddress & 0x7f;
- uep->chunk_len = ep->wMaxPacketSize;
- return 1;
- }
-
- return 0;
-}
-
-/* Return -1 on error */
-static int find_interface(struct usb_endpoint *uep)
-{
- int iface_num = -1;
- int r, i, j;
- struct libusb_device *dev;
- struct libusb_config_descriptor *conf = 0;
- const struct libusb_interface *iface0;
- const struct libusb_interface_descriptor *iface;
-
- dev = libusb_get_device(uep->devh);
- r = libusb_get_active_config_descriptor(dev, &conf);
- if (r < 0) {
- USB_ERROR("libusb_get_active_config_descriptor", r);
- goto out;
- }
-
- for (i = 0; i < conf->bNumInterfaces; i++) {
- iface0 = &conf->interface[i];
- for (j = 0; j < iface0->num_altsetting; j++) {
- iface = &iface0->altsetting[j];
- if (find_endpoint(iface, uep)) {
- iface_num = i;
- goto out;
- }
- }
- }
-
-out:
- libusb_free_config_descriptor(conf);
- return iface_num;
-}
-
-/* Returns true if parsed. */
-static int parse_vidpid(const char *input, uint16_t *vid_ptr, uint16_t *pid_ptr)
-{
- char *copy, *s, *e = 0;
-
- copy = strdup(input);
-
- s = strchr(copy, ':');
- if (!s)
- return 0;
- *s++ = '\0';
-
- *vid_ptr = (uint16_t) strtoull(copy, &e, 16);
- if (!*optarg || (e && *e))
- return 0;
-
- *pid_ptr = (uint16_t) strtoull(s, &e, 16);
- if (!*optarg || (e && *e))
- return 0;
-
- return 1;
-}
-
-static libusb_device_handle *check_device(libusb_device *dev,
- uint16_t vid, uint16_t pid, char *serialno)
-{
- struct libusb_device_descriptor desc;
- libusb_device_handle *handle = NULL;
- char sn[256];
- int ret;
- int match = 1;
- int snvalid = 0;
-
- ret = libusb_get_device_descriptor(dev, &desc);
- if (ret < 0)
- return NULL;
-
- ret = libusb_open(dev, &handle);
-
- if (ret != LIBUSB_SUCCESS)
- return NULL;
-
- if (desc.iSerialNumber) {
- ret = libusb_get_string_descriptor_ascii(handle,
- desc.iSerialNumber, (unsigned char *)sn, sizeof(sn));
- if (ret > 0)
- snvalid = 1;
- }
-
- if (vid != 0 && vid != desc.idVendor)
- match = 0;
- if (pid != 0 && pid != desc.idProduct)
- match = 0;
- if (serialno != NULL && (!snvalid || strstr(sn, serialno) == NULL))
- match = 0;
-
- if (match)
- return handle;
-
- libusb_close(handle);
- return NULL;
-}
-
-static void usb_findit(uint16_t vid, uint16_t pid,
- char *serialno, struct usb_endpoint *uep)
-{
- int iface_num, r, i;
- libusb_device **devs;
- libusb_device_handle *devh = NULL;
- ssize_t count;
-
- memset(uep, 0, sizeof(*uep));
-
- r = libusb_init(NULL);
- if (r < 0) {
- USB_ERROR("libusb_init", r);
- exit(update_error);
- }
-
- count = libusb_get_device_list(NULL, &devs);
- if (count < 0)
- return;
-
- for (i = 0; devs[i]; i++) {
- devh = check_device(devs[i], vid, pid, serialno);
- if (devh) {
- printf("Found device.\n");
- break;
- }
- }
-
- libusb_free_device_list(devs, 1);
-
- if (!devh) {
- fprintf(stderr, "Can't find device\n");
- exit(update_error);
- }
-
- uep->devh = devh;
-
- iface_num = find_interface(uep);
- if (iface_num < 0) {
- fprintf(stderr, "USB FW update not supported by that device\n");
- shut_down(uep);
- }
- if (!uep->chunk_len) {
- fprintf(stderr, "wMaxPacketSize isn't valid\n");
- shut_down(uep);
- }
-
- printf("found interface %d endpoint %d, chunk_len %d\n",
- iface_num, uep->ep_num, uep->chunk_len);
-
- libusb_set_auto_detach_kernel_driver(uep->devh, 1);
- r = libusb_claim_interface(uep->devh, iface_num);
- if (r < 0) {
- USB_ERROR("libusb_claim_interface", r);
- shut_down(uep);
- }
-
- printf("READY\n-------\n");
-}
-
-static int transfer_block(struct usb_endpoint *uep,
- struct update_frame_header *ufh,
- uint8_t *transfer_data_ptr, size_t payload_size)
-{
- size_t transfer_size;
- uint32_t reply;
- int actual;
- int r;
-
- /* First send the header. */
- xfer(uep, ufh, sizeof(*ufh), NULL, 0, 0);
-
- /* Now send the block, chunk by chunk. */
- for (transfer_size = 0; transfer_size < payload_size;) {
- int chunk_size;
-
- chunk_size = MIN(uep->chunk_len, payload_size - transfer_size);
- xfer(uep, transfer_data_ptr, chunk_size, NULL, 0, 0);
- transfer_data_ptr += chunk_size;
- transfer_size += chunk_size;
- }
-
- /* Now get the reply. */
- r = libusb_bulk_transfer(uep->devh, uep->ep_num | 0x80,
- (void *) &reply, sizeof(reply),
- &actual, 5000);
- if (r) {
- if (r == -7) {
- fprintf(stderr, "Timeout!\n");
- return r;
- }
- USB_ERROR("libusb_bulk_transfer", r);
- shut_down(uep);
- }
-
- reply = *((uint8_t *)&reply);
- if (reply) {
- fprintf(stderr, "Error: status %#x\n", reply);
- exit(update_error);
- }
-
- return 0;
-}
-
-/**
- * Transfer an image section (typically RW or RO).
- *
- * td - transfer descriptor to use to communicate with the target
- * data_ptr - pointer at the section base in the image
- * section_addr - address of the section in the target memory space
- * data_len - section size
- * smart_update - non-zero to enable the smart trailing of 0xff.
- */
-static void transfer_section(struct transfer_descriptor *td,
- uint8_t *data_ptr,
- uint32_t section_addr,
- size_t data_len,
- uint8_t smart_update)
-{
- /*
- * Actually, we can skip trailing chunks of 0xff, as the entire
- * section space must be erased before the update is attempted.
- *
- * FIXME: We can be smarter than this and skip blocks within the image.
- */
- if (smart_update)
- while (data_len && (data_ptr[data_len - 1] == 0xff))
- data_len--;
-
- printf("sending 0x%zx bytes to %#x\n", data_len, section_addr);
- while (data_len) {
- size_t payload_size;
- uint32_t block_base;
- int max_retries;
-
- /* prepare the header to prepend to the block. */
- payload_size = MIN(data_len, targ.common.maximum_pdu_size);
-
- block_base = htobe32(section_addr);
-
- struct update_frame_header ufh;
-
- ufh.block_size = htobe32(payload_size +
- sizeof(struct update_frame_header));
- ufh.cmd.block_base = block_base;
- ufh.cmd.block_digest = 0;
- for (max_retries = 10; max_retries; max_retries--)
- if (!transfer_block(&td->uep, &ufh,
- data_ptr, payload_size))
- break;
-
- if (!max_retries) {
- fprintf(stderr,
- "Failed to transfer block, %zd to go\n",
- data_len);
- exit(update_error);
- }
- data_len -= payload_size;
- data_ptr += payload_size;
- section_addr += payload_size;
- }
-}
-
-/*
- * Each RO or RW section of the new image can be in one of the following
- * states.
- */
-enum upgrade_status {
- not_needed = 0, /* Version below or equal that on the target. */
- not_possible, /*
- * RO is newer, but can't be transferred due to
- * target RW shortcomings.
- */
- needed /*
- * This section needs to be transferred to the
- * target.
- */
-};
-
-/* This array describes all sections of the new image. */
-static struct {
- const char *name;
- uint32_t offset;
- uint32_t size;
- enum upgrade_status ustatus;
- char version[32];
- int32_t rollback;
- uint32_t key_version;
-} sections[] = {
- {"RO"},
- {"RW"}
-};
-
-static const struct fmap_area *fmap_find_area_or_die(const struct fmap *fmap,
- const char *name)
-{
- const struct fmap_area *fmaparea;
-
- fmaparea = fmap_find_area(fmap, name);
- if (!fmaparea) {
- fprintf(stderr, "Cannot find FMAP area %s\n", name);
- exit(update_error);
- }
-
- return fmaparea;
-}
-
-/*
- * Scan the new image and retrieve versions of all sections.
- */
-static void fetch_header_versions(const uint8_t *image, size_t len)
-{
- const struct fmap *fmap;
- const struct fmap_area *fmaparea;
- long int offset;
- size_t i;
-
- offset = fmap_find(image, len);
- if (offset < 0) {
- fprintf(stderr, "Cannot find FMAP in image\n");
- exit(update_error);
- }
- fmap = (const struct fmap *)(image+offset);
-
- /* FIXME: validate fmap struct more than this? */
- if (fmap->size != len) {
- fprintf(stderr, "Mismatch between FMAP size and image size\n");
- exit(update_error);
- }
-
- for (i = 0; i < ARRAY_SIZE(sections); i++) {
- const char *fmap_name;
- const char *fmap_fwid_name;
- const char *fmap_rollback_name = NULL;
- const char *fmap_key_name = NULL;
-
- if (!strcmp(sections[i].name, "RO")) {
- fmap_name = "EC_RO";
- fmap_fwid_name = "RO_FRID";
- } else if (!strcmp(sections[i].name, "RW")) {
- fmap_name = "EC_RW";
- fmap_fwid_name = "RW_FWID";
- fmap_rollback_name = "RW_RBVER";
- /*
- * Key version comes from key RO (RW signature does not
- * contain the key version.
- */
- fmap_key_name = "KEY_RO";
- } else {
- fprintf(stderr, "Invalid section name\n");
- exit(update_error);
- }
-
- fmaparea = fmap_find_area_or_die(fmap, fmap_name);
-
- /* FIXME: endianness? */
- sections[i].offset = fmaparea->offset;
- sections[i].size = fmaparea->size;
-
- fmaparea = fmap_find_area_or_die(fmap, fmap_fwid_name);
-
- if (fmaparea->size != sizeof(sections[i].version)) {
- fprintf(stderr, "Invalid fwid size\n");
- exit(update_error);
- }
- memcpy(sections[i].version, image+fmaparea->offset,
- fmaparea->size);
-
- sections[i].rollback = -1;
- if (fmap_rollback_name) {
- fmaparea = fmap_find_area(fmap, fmap_rollback_name);
- if (fmaparea)
- memcpy(&sections[i].rollback,
- image+fmaparea->offset,
- sizeof(sections[i].rollback));
- }
-
- sections[i].key_version = -1;
- if (fmap_key_name) {
- fmaparea = fmap_find_area(fmap, fmap_key_name);
- if (fmaparea) {
- const struct vb21_packed_key *key =
- (const void *)(image+fmaparea->offset);
- sections[i].key_version = key->key_version;
- }
- }
- }
-}
-
-static int show_headers_versions(const void *image)
-{
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE(sections); i++) {
- printf("%s off=%08x/%08x v=%.32s rb=%d kv=%d\n",
- sections[i].name, sections[i].offset, sections[i].size,
- sections[i].version, sections[i].rollback,
- sections[i].key_version);
- }
- return 0;
-}
-
-/*
- * Pick sections to transfer based on information retrieved from the target,
- * the new image, and the protocol version the target is running.
- */
-static void pick_sections(struct transfer_descriptor *td)
-{
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE(sections); i++) {
- uint32_t offset = sections[i].offset;
-
- /* Skip currently active section. */
- if (offset != td->offset)
- continue;
-
- sections[i].ustatus = needed;
- }
-}
-
-static void setup_connection(struct transfer_descriptor *td)
-{
- size_t rxed_size;
- size_t i;
- uint32_t error_code;
-
- /*
- * Need to be backwards compatible, communicate with targets running
- * different protocol versions.
- */
- union {
- struct first_response_pdu rpdu;
- uint32_t legacy_resp;
- } start_resp;
-
- /* Send start request. */
- printf("start\n");
-
- struct update_frame_header ufh;
- uint8_t inbuf[td->uep.chunk_len];
- int actual = 0;
-
- /* Flush all data from endpoint to recover in case of error. */
- while (!libusb_bulk_transfer(td->uep.devh,
- td->uep.ep_num | 0x80,
- (void *)&inbuf, td->uep.chunk_len,
- &actual, 10)) {
- printf("flush\n");
- }
-
- memset(&ufh, 0, sizeof(ufh));
- ufh.block_size = htobe32(sizeof(ufh));
- do_xfer(&td->uep, &ufh, sizeof(ufh), &start_resp,
- sizeof(start_resp), 1, &rxed_size);
-
- /* We got something. Check for errors in response */
- if (rxed_size < 8) {
- fprintf(stderr, "Unexpected response size %zd: ", rxed_size);
- for (i = 0; i < rxed_size; i++)
- fprintf(stderr, " %02x", ((uint8_t *)&start_resp)[i]);
- fprintf(stderr, "\n");
- exit(update_error);
- }
-
- protocol_version = be16toh(start_resp.rpdu.protocol_version);
- if (protocol_version < 5 || protocol_version > 6) {
- fprintf(stderr, "Unsupported protocol version %d\n",
- protocol_version);
- exit(update_error);
- }
-
- header_type = be16toh(start_resp.rpdu.header_type);
-
- printf("target running protocol version %d (type %d)\n",
- protocol_version, header_type);
- if (header_type != UPDATE_HEADER_TYPE_COMMON) {
- fprintf(stderr, "Unsupported header type %d\n",
- header_type);
- exit(update_error);
- }
-
- error_code = be32toh(start_resp.rpdu.return_value);
-
- if (error_code) {
- fprintf(stderr, "Target reporting error %d\n", error_code);
- shut_down(&td->uep);
- exit(update_error);
- }
-
- td->offset = be32toh(start_resp.rpdu.common.offset);
- memcpy(targ.common.version, start_resp.rpdu.common.version,
- sizeof(start_resp.rpdu.common.version));
- targ.common.maximum_pdu_size =
- be32toh(start_resp.rpdu.common.maximum_pdu_size);
- targ.common.flash_protection =
- be32toh(start_resp.rpdu.common.flash_protection);
- targ.common.min_rollback = be32toh(start_resp.rpdu.common.min_rollback);
- targ.common.key_version = be32toh(start_resp.rpdu.common.key_version);
-
- printf("maximum PDU size: %d\n", targ.common.maximum_pdu_size);
- printf("Flash protection status: %04x\n", targ.common.flash_protection);
- printf("version: %32s\n", targ.common.version);
- printf("key_version: %d\n", targ.common.key_version);
- printf("min_rollback: %d\n", targ.common.min_rollback);
- printf("offset: writable at %#x\n", td->offset);
-
- pick_sections(td);
-}
-
-/*
- * Channel TPM extension/vendor command over USB. The payload of the USB frame
- * in this case consists of the 2 byte subcommand code concatenated with the
- * command body. The caller needs to indicate if a response is expected, and
- * if it is - of what maximum size.
- */
-static int ext_cmd_over_usb(struct usb_endpoint *uep, uint16_t subcommand,
- void *cmd_body, size_t body_size,
- void *resp, size_t *resp_size,
- int allow_less)
-{
- struct update_frame_header *ufh;
- uint16_t *frame_ptr;
- size_t usb_msg_size;
-
- usb_msg_size = sizeof(struct update_frame_header) +
- sizeof(subcommand) + body_size;
-
- ufh = malloc(usb_msg_size);
- if (!ufh) {
- printf("%s: failed to allocate %zd bytes\n",
- __func__, usb_msg_size);
- return -1;
- }
-
- ufh->block_size = htobe32(usb_msg_size);
- ufh->cmd.block_digest = 0;
- ufh->cmd.block_base = htobe32(UPDATE_EXTRA_CMD);
- frame_ptr = (uint16_t *)(ufh + 1);
- *frame_ptr = htobe16(subcommand);
-
- if (body_size)
- memcpy(frame_ptr + 1, cmd_body, body_size);
-
- xfer(uep, ufh, usb_msg_size, resp, resp_size ? *resp_size : 0,
- allow_less);
-
- free(ufh);
- return 0;
-}
-
-/*
- * Indicate to the target that update image transfer has been completed. Upon
- * receiveing of this message the target state machine transitions into the
- * 'rx_idle' state. The host may send an extension command to reset the target
- * after this.
- */
-static void send_done(struct usb_endpoint *uep)
-{
- uint32_t out;
-
- /* Send stop request, ignoring reply. */
- out = htobe32(UPDATE_DONE);
- xfer(uep, &out, sizeof(out), &out, 1, 0);
-}
-
-static void send_subcommand(struct transfer_descriptor *td, uint16_t subcommand,
- void *cmd_body, size_t body_size,
- uint8_t *response, size_t response_size)
-{
- send_done(&td->uep);
-
- ext_cmd_over_usb(&td->uep, subcommand,
- cmd_body, body_size,
- response, &response_size, 0);
- printf("sent command %x, resp %x\n", subcommand, response[0]);
-}
-
-/* Returns number of successfully transmitted image sections. */
-static int transfer_image(struct transfer_descriptor *td,
- uint8_t *data, size_t data_len)
-{
- size_t i;
- int num_txed_sections = 0;
-
- for (i = 0; i < ARRAY_SIZE(sections); i++)
- if (sections[i].ustatus == needed) {
- transfer_section(td,
- data + sections[i].offset,
- sections[i].offset,
- sections[i].size, 1);
- num_txed_sections++;
- }
-
- /*
- * Move USB receiver sate machine to idle state so that vendor
- * commands can be processed later, if any.
- */
- send_done(&td->uep);
-
- if (!num_txed_sections)
- printf("nothing to do\n");
- else
- printf("-------\nupdate complete\n");
- return num_txed_sections;
-}
-
-static void generate_reset_request(struct transfer_descriptor *td)
-{
- size_t response_size;
- uint8_t response;
- uint16_t subcommand;
- uint8_t command_body[2]; /* Max command body size. */
- size_t command_body_size;
-
- if (protocol_version < 6) {
- /*
- * Send a second stop request, which should reboot
- * without replying.
- */
- send_done(&td->uep);
- /* Nothing we can do over /dev/tpm0 running versions below 6. */
- return;
- }
-
- /*
- * If the user explicitly wants it, request post reset instead of
- * immediate reset. In this case next time the target reboots, the h1
- * will reboot as well, and will consider running the uploaded code.
- *
- * In case target RW version is 19 or above, to reset the target the
- * host is supposed to send the command to enable the uploaded image
- * disabled by default.
- *
- * Otherwise the immediate reset command would suffice.
- */
- /* Most common case. */
- command_body_size = 0;
- response_size = 1;
- subcommand = UPDATE_EXTRA_CMD_IMMEDIATE_RESET;
- ext_cmd_over_usb(&td->uep, subcommand,
- command_body, command_body_size,
- &response, &response_size, 0);
-
- printf("reboot not triggered\n");
-}
-
-static void get_random(uint8_t *data, int len)
-{
- FILE *fp;
- int i = 0;
-
- fp = fopen("/dev/random", "rb");
- if (!fp) {
- perror("Can't open /dev/random");
- exit(update_error);
- }
-
- while (i < len) {
- int ret = fread(data+i, len-i, 1, fp);
-
- if (ret < 0) {
- perror("fread");
- exit(update_error);
- }
-
- i += ret;
- }
-
- fclose(fp);
-}
-
-static void read_console(struct transfer_descriptor *td)
-{
- uint8_t payload[] = { 0x1 };
- uint8_t response[64];
- size_t response_size = 64;
- struct timespec sleep_duration = { /* 100 ms */
- .tv_sec = 0,
- .tv_nsec = 100l * 1000l * 1000l,
- };
-
- send_done(&td->uep);
-
- printf("\n");
- while (1) {
- response_size = 1;
- ext_cmd_over_usb(&td->uep,
- UPDATE_EXTRA_CMD_CONSOLE_READ_INIT,
- NULL, 0,
- response, &response_size, 0);
-
- while (1) {
- response_size = 64;
- ext_cmd_over_usb(&td->uep,
- UPDATE_EXTRA_CMD_CONSOLE_READ_NEXT,
- payload, sizeof(payload),
- response, &response_size, 1);
- if (response[0] == 0)
- break;
- /* make sure it's null-terminated. */
- response[response_size - 1] = 0;
- printf("%s", (const char *)response);
- }
- nanosleep(&sleep_duration, NULL);
- }
-}
-
-int main(int argc, char *argv[])
-{
- struct transfer_descriptor td;
- int errorcnt;
- uint8_t *data = 0;
- size_t data_len = 0;
- uint16_t vid = VID, pid = PID;
- char *serialno = NULL;
- int i;
- size_t j;
- int transferred_sections = 0;
- int binary_vers = 0;
- int show_fw_ver = 0;
- int no_reset_request = 0;
- int touchpad_update = 0;
- int extra_command = -1;
- uint8_t extra_command_data[50];
- int extra_command_data_len = 0;
- uint8_t extra_command_answer[64];
- int extra_command_answer_len = 1;
-
- progname = strrchr(argv[0], '/');
- if (progname)
- progname++;
- else
- progname = argv[0];
-
- /* Usb transfer - default mode. */
- memset(&td, 0, sizeof(td));
-
- errorcnt = 0;
- opterr = 0; /* quiet, you */
- while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
- switch (i) {
- case 'b':
- binary_vers = 1;
- break;
- case 'd':
- if (!parse_vidpid(optarg, &vid, &pid)) {
- printf("Invalid argument: \"%s\"\n", optarg);
- errorcnt++;
- }
- break;
- case 'e':
- get_random(extra_command_data, 32);
- extra_command_data_len = 32;
- extra_command = UPDATE_EXTRA_CMD_INJECT_ENTROPY;
- break;
- case 'f':
- show_fw_ver = 1;
- break;
- case 'g':
- extra_command = UPDATE_EXTRA_CMD_TOUCHPAD_DEBUG;
- /* Maximum length. */
- extra_command_data_len = 50;
- str2hex(optarg,
- extra_command_data, &extra_command_data_len);
- hexdump(extra_command_data, extra_command_data_len);
- extra_command_answer_len = 64;
- break;
- case 'h':
- usage(errorcnt);
- break;
- case 'j':
- extra_command = UPDATE_EXTRA_CMD_JUMP_TO_RW;
- break;
- case 'l':
- extra_command = UPDATE_EXTRA_CMD_CONSOLE_READ_INIT;
- break;
- case 'n':
- no_reset_request = 1;
- break;
- case 'p':
- touchpad_update = 1;
-
- data = get_file_or_die(optarg, &data_len);
- printf("read %zd(%#zx) bytes from %s\n",
- data_len, data_len, argv[optind - 1]);
-
- break;
- case 'r':
- extra_command = UPDATE_EXTRA_CMD_IMMEDIATE_RESET;
- break;
- case 's':
- extra_command = UPDATE_EXTRA_CMD_STAY_IN_RO;
- break;
- case 'S':
- serialno = optarg;
- break;
- case 't':
- extra_command = UPDATE_EXTRA_CMD_TOUCHPAD_INFO;
- extra_command_answer_len =
- sizeof(struct touchpad_info);
- break;
- case 'u':
- extra_command = UPDATE_EXTRA_CMD_UNLOCK_ROLLBACK;
- break;
- case 'w':
- extra_command = UPDATE_EXTRA_CMD_UNLOCK_RW;
- break;
- case 0: /* auto-handled option */
- break;
- case '?':
- if (optopt)
- printf("Unrecognized option: -%c\n", optopt);
- else
- printf("Unrecognized option: %s\n",
- argv[optind - 1]);
- errorcnt++;
- break;
- case ':':
- printf("Missing argument to %s\n", argv[optind - 1]);
- errorcnt++;
- break;
- default:
- printf("Internal error at %s:%d\n", __FILE__, __LINE__);
- exit(update_error);
- }
- }
-
- if (errorcnt)
- usage(errorcnt);
-
- if (!show_fw_ver && extra_command == -1 && !touchpad_update) {
- if (optind >= argc) {
- fprintf(stderr,
- "\nERROR: Missing required <binary image>\n\n");
- usage(1);
- }
-
- data = get_file_or_die(argv[optind], &data_len);
- printf("read %zd(%#zx) bytes from %s\n",
- data_len, data_len, argv[optind]);
-
- fetch_header_versions(data, data_len);
-
- if (binary_vers)
- exit(show_headers_versions(data));
- } else {
- if (optind < argc)
- printf("Ignoring binary image %s\n", argv[optind]);
- }
-
- usb_findit(vid, pid, serialno, &td.uep);
-
- setup_connection(&td);
-
- if (show_fw_ver) {
- printf("Current versions:\n");
- printf("Writable %32s\n", targ.common.version);
- }
-
- if (data) {
- if (touchpad_update) {
- transfer_section(&td,
- data,
- 0x80000000,
- data_len, 0);
- free(data);
-
- send_done(&td.uep);
- } else {
- transferred_sections = transfer_image(&td,
- data, data_len);
- free(data);
-
- if (transferred_sections && !no_reset_request)
- generate_reset_request(&td);
- }
- } else if (extra_command == UPDATE_EXTRA_CMD_CONSOLE_READ_INIT) {
- read_console(&td);
- } else if (extra_command > -1) {
- send_subcommand(&td, extra_command,
- extra_command_data, extra_command_data_len,
- extra_command_answer, extra_command_answer_len);
-
- switch (extra_command) {
- case UPDATE_EXTRA_CMD_TOUCHPAD_INFO:
- dump_touchpad_info(extra_command_answer,
- extra_command_answer_len);
- break;
- case UPDATE_EXTRA_CMD_TOUCHPAD_DEBUG:
- hexdump(extra_command_answer, extra_command_answer_len);
- break;
- }
- }
-
- libusb_close(td.uep.devh);
- libusb_exit(NULL);
-
- if (!transferred_sections)
- return noop;
- /*
- * We should indicate if RO update was not done because of the
- * insufficient RW version.
- */
- for (j = 0; j < ARRAY_SIZE(sections); j++)
- if (sections[j].ustatus == not_possible) {
- /* This will allow scripting repeat attempts. */
- printf("Failed to update RO, run the command again\n");
- return rw_updated;
- }
-
- printf("image updated\n");
- return all_updated;
-}