Files
OpenCellular/include/update_fw.h
Nicolas Boichat 23b0d417f5 update_fw: Add support for touchpad update over virtual address
In the field, we want to update touchpad FW using the same USB
update protocol as the main EC FW.

To distinguish between EC FW update and touchpad FW update, we
use a virtual address, defined by CONFIG_TOUCHPAD_VIRTUAL_OFF,
that does not map to anything on the EC chip.

Also, this will allow us to verify hashes of each block of the
flashed touchpad firmware, so that we can ensure its integrity
before flashing it into the touchpad. A stub is implemented in
update_fw.c:contents_allowed.

BRANCH=none
BUG=b:63993173
TEST=With follow-up CLs, ./usb_updater2 -p 144.0_2.0.bin

Change-Id: I4de1d7d138fc01fe1552a4173c8ef208ecb834a7
Signed-off-by: Nicolas Boichat <drinkcat@google.com>
Reviewed-on: https://chromium-review.googlesource.com/593373
Commit-Ready: Nicolas Boichat <drinkcat@chromium.org>
Tested-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Chun-ta Lin <itspeter@chromium.org>
2017-08-10 01:14:59 -07:00

244 lines
7.2 KiB
C

/* 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.
*/
#ifndef __CROS_EC_UPDATE_FW_H
#define __CROS_EC_UPDATE_FW_H
#include <stddef.h>
/*
* This file contains structures used to facilitate EC firmware updates
* over USB (and over TPM for cr50).
*
* The firmware update protocol consists of two phases: connection
* establishment and actual image transfer.
*
* Image transfer is done in 1K blocks. The host supplying the image
* encapsulates blocks in PDUs by prepending a header including the flash
* offset where the block is destined and its digest.
*
* The EC device responds to each PDU with a confirmation which is 1 byte
* response. Zero value means success, non zero value is the error code
* reported by EC.
*
* To establish the connection, the host sends a different PDU, which
* contains no data and is destined to offset 0. Receiving such a PDU
* signals the EC that the host intends to transfer a new image.
*
* The connection establishment response is described by the
* first_response_pdu structure below.
*/
#define UPDATE_PROTOCOL_VERSION 6
/*
* This is the format of the update PDU header.
*
* block digest: the first four bytes of the sha1 digest of the rest of the
* structure (can be 0 on boards where digest is ignored).
* block_base: offset of this PDU into the flash SPI.
*/
struct update_command {
uint32_t block_digest;
uint32_t block_base;
/* The actual payload goes here. */
} __packed;
/*
* This is the frame format the host uses when sending update PDUs over USB.
*
* The PDUs are up to 1K bytes in size, they are fragmented into USB chunks of
* 64 bytes each and reassembled on the receive side before being passed to
* the flash update function.
*
* The flash update function receives the unframed PDU body (starting at the
* cmd field below), and puts its reply into the same buffer the PDU was in.
*/
struct update_frame_header {
uint32_t block_size; /* Total frame size, including this field. */
struct update_command cmd;
};
/*
* A convenience structure which allows to group together various revision
* fields of the header created by the signer (cr50-specific).
*
* These fields are compared when deciding if versions of two images are the
* same or when deciding which one of the available images to run.
*/
struct signed_header_version {
uint32_t minor;
uint32_t major;
uint32_t epoch;
};
/*
* Response to the connection establishment request.
*
* When responding to the very first packet of the update sequence, the
* original USB update implementation was responding with a four byte value,
* just as to any other block of the transfer sequence.
*
* It became clear that there is a need to be able to enhance the update
* protocol, while staying backwards compatible.
*
* All newer protocol versions (starting with version 2) respond to the very
* first packet with an 8 byte or larger response, where the first 4 bytes are
* a version specific data, and the second 4 bytes - the protocol version
* number.
*
* This way the host receiving of a four byte value in response to the first
* packet is considered an indication of the target running the 'legacy'
* protocol, version 1. Receiving of an 8 byte or longer response would
* communicates the protocol version in the second 4 bytes.
*/
struct first_response_pdu {
uint32_t return_value;
/* The below fields are present in versions 2 and up. */
/* Type of header following (one of first_response_pdu_header_type) */
uint16_t header_type;
/* Must be UPDATE_PROTOCOL_VERSION */
uint16_t protocol_version;
/* In version 6 and up, a board-specific header follows. */
union {
/* cr50 (header_type = UPDATE_HEADER_TYPE_CR50) */
struct {
/* The below fields are present in versions 3 and up. */
uint32_t backup_ro_offset;
uint32_t backup_rw_offset;
/* The below fields are present in versions 4 and up. */
/*
* Versions of the currently active RO and RW sections.
*/
struct signed_header_version shv[2];
/* The below fields are present in versions 5 and up */
/* keyids of the currently active RO and RW sections. */
uint32_t keyid[2];
} cr50;
/* Common code (header_type = UPDATE_HEADER_TYPE_COMMON) */
struct {
/* Maximum PDU size */
uint32_t maximum_pdu_size;
/* Flash protection status */
uint32_t flash_protection;
/* Offset of the other region */
uint32_t offset;
/* Version string of the other region */
char version[32];
/* Minimum rollback version that RO will accept */
int32_t min_rollback;
/* RO public key version */
uint32_t key_version;
} common;
};
};
enum first_response_pdu_header_type {
UPDATE_HEADER_TYPE_CR50 = 0, /* Must be 0 for backwards compatibility */
UPDATE_HEADER_TYPE_COMMON = 1,
};
/* TODO: Handle this in update_fw.c, not usb_update.c */
#define UPDATE_DONE 0xB007AB1E
#define UPDATE_EXTRA_CMD 0xB007AB1F
enum update_extra_command {
UPDATE_EXTRA_CMD_IMMEDIATE_RESET = 0,
UPDATE_EXTRA_CMD_JUMP_TO_RW = 1,
UPDATE_EXTRA_CMD_STAY_IN_RO = 2,
UPDATE_EXTRA_CMD_UNLOCK_RW = 3,
UPDATE_EXTRA_CMD_UNLOCK_ROLLBACK = 4,
UPDATE_EXTRA_CMD_INJECT_ENTROPY = 5,
UPDATE_EXTRA_CMD_PAIR_CHALLENGE = 6,
UPDATE_EXTRA_CMD_TOUCHPAD_INFO = 7,
};
/*
* Pair challenge (from host), note that the packet, with header, must fit
* in a single USB packet (64 bytes), so its maximum length is 50 bytes.
*/
struct pair_challenge {
uint8_t host_public[32]; /* X22519 public key from host */
uint8_t nonce[16]; /* nonce to be used for HMAC */
};
/*
* Pair challenge response (from device).
*/
struct pair_challenge_response {
uint8_t status; /* = EC_RES_SUCCESS */
uint8_t device_public[32]; /* X22519 device public key of device */
/*
* Truncated output of
* HMAC_SHA256(x25519(device_private, host_public), nonce)
*/
uint8_t authenticator[16];
} __packed;
struct touchpad_info {
uint8_t status; /* = EC_RES_SUCCESS */
uint8_t reserved; /* padding */
uint16_t vendor; /* Vendor USB id */
/*
* Virtual address to write to to update TP FW over USB update protocol,
* and FW size. Both are 0 if unsupported.
*/
uint32_t fw_address;
uint32_t fw_size;
/* Vendor specific data. */
struct {
uint16_t id;
uint16_t fw_version;
uint16_t fw_checksum;
} elan;
} __packed;
void fw_update_command_handler(void *body,
size_t cmd_size,
size_t *response_size);
/* Used to tell fw update the update ran successfully and is finished */
void fw_update_complete(void);
/* Verify integrity of the PDU received. */
int update_pdu_valid(struct update_command *cmd_body, size_t cmd_size);
/* Various update command return values. */
enum {
UPDATE_SUCCESS = 0,
UPDATE_BAD_ADDR = 1,
UPDATE_ERASE_FAILURE = 2,
UPDATE_DATA_ERROR = 3,
UPDATE_WRITE_FAILURE = 4,
UPDATE_VERIFY_ERROR = 5,
UPDATE_GEN_ERROR = 6,
UPDATE_MALLOC_ERROR = 7,
UPDATE_ROLLBACK_ERROR = 8,
UPDATE_RATE_LIMIT_ERROR = 9,
UPDATE_RWSIG_BUSY = 10,
};
/* Obtain touchpad information */
int touchpad_get_info(struct touchpad_info *tp);
/* Touchpad FW update: Write a FW block. */
int touchpad_update_write(int offset, int size, const uint8_t *data);
#endif /* ! __CROS_EC_UPDATE_FW_H */