diff options
-rw-r--r-- | chip/g/build.mk | 1 | ||||
-rw-r--r-- | chip/g/usb_hid_keyboard.c | 159 | ||||
-rw-r--r-- | common/build.mk | 4 | ||||
-rw-r--r-- | common/update_fw.c | 334 | ||||
-rw-r--r-- | common/usb_update.c | 594 | ||||
-rw-r--r-- | include/config.h | 15 |
6 files changed, 0 insertions, 1107 deletions
diff --git a/chip/g/build.mk b/chip/g/build.mk index a46a6e8c55..bb28bee410 100644 --- a/chip/g/build.mk +++ b/chip/g/build.mk @@ -76,7 +76,6 @@ chip-$(CONFIG_WATCHDOG)+=watchdog.o chip-$(CONFIG_USB)+=usb.o usb_endpoints.o chip-$(CONFIG_USB_CONSOLE)+=usb_console.o -chip-$(CONFIG_USB_HID_KEYBOARD)+=usb_hid_keyboard.o chip-$(CONFIG_USB_BLOB)+=blob.o chip-$(CONFIG_USB_SPI)+=usb_spi.o chip-$(CONFIG_RDD)+=rdd.o diff --git a/chip/g/usb_hid_keyboard.c b/chip/g/usb_hid_keyboard.c deleted file mode 100644 index d6b529839f..0000000000 --- a/chip/g/usb_hid_keyboard.c +++ /dev/null @@ -1,159 +0,0 @@ -/* Copyright 2014 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 "clock.h" -#include "common.h" -#include "config.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "link_defs.h" -#include "registers.h" -#include "task.h" -#include "timer.h" -#include "util.h" -#include "usb_descriptor.h" -#include "usb_hid.h" - -/* Console output macro */ -#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args) - -#define HID_REPORT_SIZE 8 - -/* HID descriptors */ -const struct usb_interface_descriptor USB_IFACE_DESC(USB_IFACE_HID) = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_IFACE_HID_KEYBOARD, - .bAlternateSetting = 0, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_HID, - .bInterfaceSubClass = USB_HID_SUBCLASS_BOOT, - .bInterfaceProtocol = USB_HID_PROTOCOL_KEYBOARD, - .iInterface = USB_STR_HID_KEYBOARD_NAME, -}; -const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_HID, 81) = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x80 | USB_EP_HID_KEYBOARD, - .bmAttributes = 0x03 /* Interrupt endpoint */, - .wMaxPacketSize = HID_REPORT_SIZE, - .bInterval = 32 /* ms polling interval */ -}; -const struct usb_hid_descriptor USB_CUSTOM_DESC(USB_IFACE_HID, hid) = { - .bLength = 9, - .bDescriptorType = USB_HID_DT_HID, - .bcdHID = 0x0100, - .bCountryCode = 0x00, /* Hardware target country */ - .bNumDescriptors = 1, - .desc = { - {.bDescriptorType = USB_HID_DT_REPORT, - .wDescriptorLength = 45} - } -}; - -/* HID : Report Descriptor */ -static const uint8_t report_desc[] = { - 0x05, 0x01, /* Usage Page (Generic Desktop) */ - 0x09, 0x06, /* Usage (Keyboard) */ - 0xA1, 0x01, /* Collection (Application) */ - 0x05, 0x07, /* Usage Page (Key Codes) */ - 0x19, 0xE0, /* Usage Minimum (224) */ - 0x29, 0xE7, /* Usage Maximum (231) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x75, 0x01, /* Report Size (1) */ - 0x95, 0x08, /* Report Count (8) */ - 0x81, 0x02, /* Input (Data, Variable, Absolute), ;Modifier byte */ - - 0x95, 0x01, /* Report Count (1) */ - 0x75, 0x08, /* Report Size (8) */ - 0x81, 0x01, /* Input (Constant), ;Reserved byte */ - - 0x95, 0x06, /* Report Count (6) */ - 0x75, 0x08, /* Report Size (8) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0x65, /* Logical Maximum(101) */ - 0x05, 0x07, /* Usage Page (Key Codes) */ - 0x19, 0x00, /* Usage Minimum (0) */ - 0x29, 0x65, /* Usage Maximum (101) */ - 0x81, 0x00, /* Input (Data, Array), ;Key arrays (6 bytes) */ - 0xC0, /* End Collection */ - 0x00 /* Padding */ -}; - -static uint8_t hid_ep_buf[HID_REPORT_SIZE]; -static struct g_usb_desc hid_ep_desc; - -void set_keyboard_report(uint64_t rpt) -{ - memcpy(hid_ep_buf, &rpt, sizeof(rpt)); - hid_ep_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY | DIEPDMA_IOC | - DIEPDMA_TXBYTES(HID_REPORT_SIZE); - /* enable TX */ - GR_USB_DIEPCTL(USB_EP_HID_KEYBOARD) |= DXEPCTL_CNAK | DXEPCTL_EPENA; -} - -static void hid_tx(void) -{ - /* clear IT */ - GR_USB_DIEPINT(USB_EP_HID_KEYBOARD) = 0xffffffff; - return; -} - -static void hid_reset(void) -{ - hid_ep_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY | DIEPDMA_IOC; - hid_ep_desc.addr = hid_ep_buf; - GR_USB_DIEPDMA(USB_EP_HID_KEYBOARD) = (uint32_t)&hid_ep_desc; - GR_USB_DIEPCTL(USB_EP_HID_KEYBOARD) = DXEPCTL_MPS(HID_REPORT_SIZE) | - DXEPCTL_USBACTEP | DXEPCTL_EPTYPE_INT | - DXEPCTL_TXFNUM(USB_EP_HID_KEYBOARD); - GR_USB_DAINTMSK |= DAINT_INEP(USB_EP_HID_KEYBOARD); -} - -USB_DECLARE_EP(USB_EP_HID_KEYBOARD, hid_tx, hid_tx, hid_reset); - -static int hid_iface_request(struct usb_setup_packet *req) -{ - if ((req->bmRequestType & USB_DIR_IN) && - req->bRequest == USB_REQ_GET_DESCRIPTOR && - req->wValue == (USB_HID_DT_REPORT << 8)) { - /* Setup : HID specific : Get Report descriptor */ - return load_in_fifo(report_desc, - MIN(req->wLength, - sizeof(report_desc))); - } - - /* Anything else we'll stall */ - return -1; -} -USB_DECLARE_IFACE(USB_IFACE_HID_KEYBOARD, hid_iface_request); - -#ifdef CR50_DEV -/* Just for debugging */ -static int command_hid(int argc, char **argv) -{ - uint8_t keycode = 0x0a; /* 'G' key */ - - if (argc >= 2) { - char *e; - - keycode = strtoi(argv[1], &e, 16); - if (*e) - return EC_ERROR_PARAM1; - } - - /* press then release the key */ - set_keyboard_report((uint32_t)keycode << 16); - udelay(50 * MSEC); - set_keyboard_report(0x000000); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(hid, command_hid, - "[<HID keycode>]", - "test USB HID driver"); -#endif diff --git a/common/build.mk b/common/build.mk index 5e803b970b..0032ea069c 100644 --- a/common/build.mk +++ b/common/build.mk @@ -147,7 +147,6 @@ common-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_protocol.o usb_pd_policy.o endif common-$(CONFIG_USB_PD_LOGGING)+=event_log.o pd_log.o common-$(CONFIG_USB_PD_TCPC)+=usb_pd_tcpc.o -common-$(CONFIG_USB_UPDATE)+=usb_update.o update_fw.o common-$(CONFIG_USBC_PPC)+=usbc_ppc.o common-$(CONFIG_VBOOT_EFS)+=vboot/vboot.o common-$(CONFIG_VBOOT_HASH)+=sha256.o vboot_hash.o @@ -215,9 +214,6 @@ endif endif # CONFIG_BOOTBLOCK ifneq ($(CONFIG_TOUCHPAD_HASH_FW),) -$(out)/RO/common/update_fw.o: $(out)/touchpad_fw_hash.h -$(out)/RW/common/update_fw.o: $(out)/touchpad_fw_hash.h - $(out)/touchpad_fw_hash.h: $(out)/util/gen_touchpad_hash $(out)/.touchpad_fw $(call quiet,tp_hash,TPHASH ) diff --git a/common/update_fw.c b/common/update_fw.c deleted file mode 100644 index 2501f29934..0000000000 --- a/common/update_fw.c +++ /dev/null @@ -1,334 +0,0 @@ -/* 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. - */ - -#include "byteorder.h" -#include "console.h" -#include "extension.h" -#include "flash.h" -#include "hooks.h" -#include "include/compile_time_macros.h" -#include "rollback.h" -#include "rwsig.h" -#include "sha256.h" -#include "system.h" -#include "uart.h" -#include "update_fw.h" -#include "util.h" -#include "vb21_struct.h" - -#if defined(CONFIG_TOUCHPAD_VIRTUAL_OFF) && defined(CONFIG_TOUCHPAD_HASH_FW) -#define CONFIG_TOUCHPAD_FW_CHUNKS \ - (CONFIG_TOUCHPAD_VIRTUAL_SIZE / CONFIG_UPDATE_PDU_SIZE) - -#include "touchpad_fw_hash.h" - -BUILD_ASSERT(sizeof(touchpad_fw_hashes) == - (CONFIG_TOUCHPAD_FW_CHUNKS * SHA256_DIGEST_SIZE)); -BUILD_ASSERT(sizeof(touchpad_fw_hashes[0]) == SHA256_DIGEST_SIZE); - -BUILD_ASSERT(sizeof(touchpad_fw_full_hash) == SHA256_DIGEST_SIZE); -#endif - -#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args) - -/* Section to be updated (i.e. not the current section). */ -struct { - uint32_t base_offset; - uint32_t top_offset; -} update_section; - -#ifdef CONFIG_TOUCHPAD_VIRTUAL_OFF -/* - * Check if a block is within touchpad FW virtual address region, and - * is therefore meant to be flashed to the touchpad. - */ -static int is_touchpad_block(uint32_t block_offset, size_t body_size) -{ - return (block_offset >= CONFIG_TOUCHPAD_VIRTUAL_OFF) && - (block_offset + body_size) <= - (CONFIG_TOUCHPAD_VIRTUAL_OFF + - CONFIG_TOUCHPAD_VIRTUAL_SIZE); -} -#endif - -/* - * Verify that the passed in block fits into the valid area. If it does, and - * is destined to the base address of the area - erase the area contents. - * - * Return success, or indication of an erase failure or chunk not fitting into - * valid area. - * - * TODO(b/36375666): Each board/chip should be able to re-define this. - */ -static uint8_t check_update_chunk(uint32_t block_offset, size_t body_size) -{ - uint32_t base; - uint32_t size; - - /* Is this an RW chunk? */ - if (update_section.base_offset != update_section.top_offset && - (block_offset >= update_section.base_offset) && - ((block_offset + body_size) <= update_section.top_offset)) { - - base = update_section.base_offset; - size = update_section.top_offset - - update_section.base_offset; - /* - * If this is the first chunk for this section, it needs to - * be erased. - */ - if (block_offset == base) { - if (flash_physical_erase(base, size) != EC_SUCCESS) { - CPRINTF("%s:%d erase failure of 0x%x..+0x%x\n", - __func__, __LINE__, base, size); - return UPDATE_ERASE_FAILURE; - } - } - - return UPDATE_SUCCESS; - } - -#ifdef CONFIG_TOUCHPAD_VIRTUAL_OFF - if (is_touchpad_block(block_offset, body_size)) - return UPDATE_SUCCESS; -#endif - - CPRINTF("%s:%d %x, %d section base %x top %x\n", - __func__, __LINE__, - block_offset, body_size, - update_section.base_offset, - update_section.top_offset); - - return UPDATE_BAD_ADDR; - -} - -/* TODO(b/36375666): These need to be overridden for chip/g. */ -int update_pdu_valid(struct update_command *cmd_body, size_t cmd_size) -{ - return 1; -} - -static int chunk_came_too_soon(uint32_t block_offset) -{ - return 0; -} - -static void new_chunk_written(uint32_t block_offset) -{ -} - -static int contents_allowed(uint32_t block_offset, - size_t body_size, void *update_data) -{ -#if defined(CONFIG_TOUCHPAD_VIRTUAL_OFF) && defined(CONFIG_TOUCHPAD_HASH_FW) - if (is_touchpad_block(block_offset, body_size)) { - struct sha256_ctx ctx; - uint8_t *tmp; - uint32_t fw_offset = block_offset - CONFIG_TOUCHPAD_VIRTUAL_OFF; - unsigned int chunk = fw_offset / CONFIG_UPDATE_PDU_SIZE; - int good = 0; - - if (chunk >= CONFIG_TOUCHPAD_FW_CHUNKS || - (fw_offset % CONFIG_UPDATE_PDU_SIZE) != 0) { - CPRINTF("%s: TP invalid offset %08x\n", - __func__, fw_offset); - return 0; - } - - SHA256_init(&ctx); - SHA256_update(&ctx, update_data, body_size); - tmp = SHA256_final(&ctx); - - good = !memcmp(tmp, touchpad_fw_hashes[chunk], - SHA256_DIGEST_SIZE); - - CPRINTF("%s: TP %08x %02x..%02x (%s)\n", __func__, - fw_offset, tmp[0], tmp[31], good ? "GOOD" : "BAD"); - - return good; - } -#endif - return 1; -} - -/* - * Setup internal state (e.g. valid sections, and fill first response). - * - * Assumes rpdu is already prefilled with 0, and that version has already - * been set. May set a return_value != 0 on error. - */ -void fw_update_start(struct first_response_pdu *rpdu) -{ - const char *version; -#ifdef CONFIG_RWSIG_TYPE_RWSIG - const struct vb21_packed_key *vb21_key; -#endif - - rpdu->header_type = htobe16(UPDATE_HEADER_TYPE_COMMON); - - /* Determine the valid update section. */ - switch (system_get_image_copy()) { - case SYSTEM_IMAGE_RO: - /* RO running, so update RW */ - update_section.base_offset = CONFIG_RW_MEM_OFF; - update_section.top_offset = CONFIG_RW_MEM_OFF + CONFIG_RW_SIZE; - version = system_get_version(SYSTEM_IMAGE_RW); - break; - case SYSTEM_IMAGE_RW: - /* RW running, so update RO */ - update_section.base_offset = CONFIG_RO_MEM_OFF; - update_section.top_offset = CONFIG_RO_MEM_OFF + CONFIG_RO_SIZE; - version = system_get_version(SYSTEM_IMAGE_RO); - break; - default: - CPRINTF("%s:%d\n", __func__, __LINE__); - rpdu->return_value = htobe32(UPDATE_GEN_ERROR); - return; - } - - rpdu->common.maximum_pdu_size = htobe32(CONFIG_UPDATE_PDU_SIZE); - rpdu->common.flash_protection = htobe32(flash_get_protect()); - rpdu->common.offset = htobe32(update_section.base_offset); - if (version) - memcpy(rpdu->common.version, version, - sizeof(rpdu->common.version)); - -#ifdef CONFIG_ROLLBACK - rpdu->common.min_rollback = htobe32(rollback_get_minimum_version()); -#else - rpdu->common.min_rollback = htobe32(-1); -#endif - -#ifdef CONFIG_RWSIG_TYPE_RWSIG - vb21_key = (const struct vb21_packed_key *)CONFIG_RO_PUBKEY_ADDR; - rpdu->common.key_version = htobe32(vb21_key->key_version); -#endif - -#ifdef HAS_TASK_RWSIG - /* Do not allow the update to start if RWSIG is still running. */ - if (rwsig_get_status() == RWSIG_IN_PROGRESS) { - CPRINTF("RWSIG in progress\n"); - rpdu->return_value = htobe32(UPDATE_RWSIG_BUSY); - } -#endif -} - -void fw_update_command_handler(void *body, - size_t cmd_size, - size_t *response_size) -{ - struct update_command *cmd_body = body; - void *update_data; - uint8_t *error_code = body; /* Cache the address for code clarity. */ - size_t body_size; - uint32_t block_offset; - - *response_size = 1; /* One byte response unless this is a start PDU. */ - - if (cmd_size < sizeof(struct update_command)) { - CPRINTF("%s:%d\n", __func__, __LINE__); - *error_code = UPDATE_GEN_ERROR; - return; - } - body_size = cmd_size - sizeof(struct update_command); - - if (!cmd_body->block_base && !body_size) { - struct first_response_pdu *rpdu = body; - - /* - * This is the connection establishment request, the response - * allows the server to decide what sections of the image to - * send to program into the flash. - */ - - /* First, prepare the response structure. */ - memset(rpdu, 0, sizeof(*rpdu)); - /* - * TODO(b/36375666): The response size can be shorter depending - * on which board-specific type of response we provide. This - * may send trailing 0 bytes, which should be harmless. - */ - *response_size = sizeof(*rpdu); - rpdu->protocol_version = htobe16(UPDATE_PROTOCOL_VERSION); - - /* Setup internal state (e.g. valid sections, and fill rpdu) */ - fw_update_start(rpdu); - return; - } - - block_offset = be32toh(cmd_body->block_base); - - if (!update_pdu_valid(cmd_body, cmd_size)) { - *error_code = UPDATE_DATA_ERROR; - return; - } - - update_data = cmd_body + 1; - if (!contents_allowed(block_offset, body_size, update_data)) { - *error_code = UPDATE_ROLLBACK_ERROR; - return; - } - - /* Check if the block will fit into the valid area. */ - *error_code = check_update_chunk(block_offset, body_size); - if (*error_code) - return; - - if (chunk_came_too_soon(block_offset)) { - *error_code = UPDATE_RATE_LIMIT_ERROR; - return; - } - - /* - * TODO(b/36375666): chip/g code has some cr50-specific stuff right - * here, which should probably be merged into contents_allowed... - */ - -#ifdef CONFIG_TOUCHPAD_VIRTUAL_OFF - if (is_touchpad_block(block_offset, body_size)) { - if (touchpad_update_write( - block_offset - CONFIG_TOUCHPAD_VIRTUAL_OFF, - body_size, update_data) != EC_SUCCESS) { - *error_code = UPDATE_WRITE_FAILURE; - CPRINTF("%s:%d update write error\n", - __func__, __LINE__); - return; - } - - new_chunk_written(block_offset); - - *error_code = UPDATE_SUCCESS; - return; - } -#endif - - CPRINTF("update: 0x%x\n", block_offset + CONFIG_PROGRAM_MEMORY_BASE); - if (flash_physical_write(block_offset, body_size, update_data) - != EC_SUCCESS) { - *error_code = UPDATE_WRITE_FAILURE; - CPRINTF("%s:%d update write error\n", __func__, __LINE__); - return; - } - - new_chunk_written(block_offset); - - /* Verify that data was written properly. */ - if (memcmp(update_data, (void *) - (block_offset + CONFIG_PROGRAM_MEMORY_BASE), - body_size)) { - *error_code = UPDATE_VERIFY_ERROR; - CPRINTF("%s:%d update verification error\n", - __func__, __LINE__); - return; - } - - *error_code = UPDATE_SUCCESS; -} - -/* TODO(b/36375666): This need to be overridden for chip/g. */ -void fw_update_complete(void) -{ -} diff --git a/common/usb_update.c b/common/usb_update.c deleted file mode 100644 index 64875fd798..0000000000 --- a/common/usb_update.c +++ /dev/null @@ -1,594 +0,0 @@ -/* 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. - */ - -#include "byteorder.h" -#include "common.h" -#include "console.h" -#include "consumer.h" -#include "curve25519.h" -#include "extension.h" -#include "flash.h" -#include "queue_policies.h" -#include "host_command.h" -#include "rollback.h" -#include "rwsig.h" -#include "sha256.h" -#include "system.h" -#include "uart.h" -#include "update_fw.h" -#include "usb-stream.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USB, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args) - -/* - * This file is an adaptation layer between the USB interface and the firmware - * update engine. The engine expects to receive long blocks of data, 1K or so - * in size, prepended by the offset where the data needs to be programmed into - * the flash and a 4 byte integrity check value. - * - * The USB transfer, on the other hand, operates on much shorter chunks of - * data, typically 64 bytes in this case. This module reassembles firmware - * programming blocks from the USB chunks, and invokes the programmer passing - * it the full block. - * - * The programmer reports results by putting the return value into the same - * buffer where the block was passed in. This wrapper retrieves the - * programmer's return value, and sends it back to the host. The return value - * is usually one byte in size, the only exception is the connection - * establishment phase where the return value is 16 bytes in size. - * - * In the end of the successful image transfer and programming, the host sends - * the reset command, and the device reboots itself. - */ - -struct consumer const update_consumer; -struct usb_stream_config const usb_update; - -static struct queue const update_to_usb = QUEUE_DIRECT(64, uint8_t, - null_producer, - usb_update.consumer); -static struct queue const usb_to_update = QUEUE_DIRECT(64, uint8_t, - usb_update.producer, - update_consumer); - -USB_STREAM_CONFIG_FULL(usb_update, - USB_IFACE_UPDATE, - USB_CLASS_VENDOR_SPEC, - USB_SUBCLASS_GOOGLE_UPDATE, - USB_PROTOCOL_GOOGLE_UPDATE, - USB_STR_UPDATE_NAME, - USB_EP_UPDATE, - USB_MAX_PACKET_SIZE, - USB_MAX_PACKET_SIZE, - usb_to_update, - update_to_usb) - - -/* The receiver can be in one of the states below. */ -enum rx_state { - rx_idle, /* Nothing happened yet. */ - rx_inside_block, /* Assembling a block to pass to the programmer. */ - rx_outside_block, /* Waiting for the next block to start or for the - reset command. */ -}; - -enum rx_state rx_state_ = rx_idle; -static uint8_t block_buffer[sizeof(struct update_command) + - CONFIG_UPDATE_PDU_SIZE]; -static uint32_t block_size; -static uint32_t block_index; - -#ifdef CONFIG_USB_PAIRING -#define KEY_CONTEXT "device-identity" - -static int pair_challenge(struct pair_challenge *challenge) -{ - uint8_t response; - - /* Scratchpad for device secret and x25519 public/shared key. */ - uint8_t tmp[32]; - BUILD_ASSERT(sizeof(tmp) >= X25519_PUBLIC_VALUE_LEN); - BUILD_ASSERT(sizeof(tmp) >= X25519_PRIVATE_KEY_LEN); - BUILD_ASSERT(sizeof(tmp) >= CONFIG_ROLLBACK_SECRET_SIZE); - - /* Scratchpad for device_private and authenticator. */ - uint8_t tmp2[32]; - BUILD_ASSERT(sizeof(tmp2) >= X25519_PRIVATE_KEY_LEN); - BUILD_ASSERT(sizeof(tmp2) >= SHA256_DIGEST_SIZE); - - /* tmp = device_secret */ - if (rollback_get_secret(tmp) != EC_SUCCESS) { - response = EC_RES_UNAVAILABLE; - QUEUE_ADD_UNITS(&update_to_usb, &response, sizeof(response)); - return 1; - } - - /* - * Nothing can fail from now on, let's push data to the queue as soon as - * possible to save some temporary variables. - */ - response = EC_RES_SUCCESS; - QUEUE_ADD_UNITS(&update_to_usb, &response, sizeof(response)); - - /* - * tmp2 = device_private - * = HMAC_SHA256(device_secret, "device-identity") - */ - hmac_SHA256(tmp2, tmp, CONFIG_ROLLBACK_SECRET_SIZE, - KEY_CONTEXT, sizeof(KEY_CONTEXT) - 1); - - /* tmp = device_public = x25519(device_private, x25519_base_point) */ - X25519_public_from_private(tmp, tmp2); - QUEUE_ADD_UNITS(&update_to_usb, tmp, sizeof(tmp)); - - /* tmp = shared_secret = x25519(device_private, host_public) */ - X25519(tmp, tmp2, challenge->host_public); - - /* tmp2 = authenticator = HMAC_SHA256(shared_secret, nonce) */ - hmac_SHA256(tmp2, tmp, sizeof(tmp), - challenge->nonce, sizeof(challenge->nonce)); - QUEUE_ADD_UNITS(&update_to_usb, tmp2, - member_size(struct pair_challenge_response, authenticator)); - return 1; -} -#endif - -/* - * Fetches a transfer start frame from the queue. This can be either an update - * start frame (block_size = 0, all of cmd = 0), or the beginning of a frame - * (block_size > 0, valid block_base in cmd). - */ -static int fetch_transfer_start(struct consumer const *consumer, size_t count, - struct update_frame_header *pupfr) -{ - int i; - - /* - * Let's just make sure we drain the queue no matter what the contents - * are. This way they won't be in the way during next callback, even - * if these contents are not what's expected. - * - * Note: If count > sizeof(*pupfr), pupfr will be corrupted. This is - * ok as we will immediately fail after this. - */ - i = count; - while (i > 0) { - QUEUE_REMOVE_UNITS(consumer->queue, pupfr, - MIN(i, sizeof(*pupfr))); - i -= sizeof(*pupfr); - } - - if (count != sizeof(struct update_frame_header)) { - CPRINTS("FW update: wrong first block, size %d", count); - return 0; - } - - return 1; -} - -static int try_vendor_command(struct consumer const *consumer, size_t count) -{ - char buffer[USB_MAX_PACKET_SIZE]; - struct update_frame_header *cmd_buffer = (void *)buffer; - int rv = 0; - - /* Validate count (too short, or too long). */ - if (count < sizeof(*cmd_buffer) || count > sizeof(buffer)) - return 0; - - /* - * Let's copy off the queue the update frame header, to see if this - * is a channeled vendor command. - */ - queue_peek_units(consumer->queue, cmd_buffer, 0, sizeof(*cmd_buffer)); - if (be32toh(cmd_buffer->cmd.block_base) != UPDATE_EXTRA_CMD) - return 0; - - if (be32toh(cmd_buffer->block_size) != count) { - CPRINTS("%s: problem: block size and count mismatch (%d != %d)", - __func__, be32toh(cmd_buffer->block_size), count); - return 0; - } - - /* Get the entire command, don't remove it from the queue just yet. */ - queue_peek_units(consumer->queue, cmd_buffer, 0, count); - - /* Looks like this is a vendor command, let's verify it. */ - if (update_pdu_valid(&cmd_buffer->cmd, - count - offsetof(struct update_frame_header, cmd))) { - enum update_extra_command subcommand; - uint8_t response; - size_t response_size = sizeof(response); - int __attribute__((unused)) header_size; - int __attribute__((unused)) data_count; - - /* looks good, let's process it. */ - rv = 1; - - /* Now remove it from the queue. */ - queue_advance_head(consumer->queue, count); - - subcommand = be16toh(*((uint16_t *)(cmd_buffer + 1))); - - /* - * header size: update frame header + 2 bytes for subcommand - * data_count: Some commands take in extra data as parameter - */ - header_size = sizeof(*cmd_buffer) + sizeof(uint16_t); - data_count = count - header_size; - - switch (subcommand) { - case UPDATE_EXTRA_CMD_IMMEDIATE_RESET: - CPRINTS("Rebooting!"); - CPRINTF("\n\n"); - cflush(); - system_reset(SYSTEM_RESET_MANUALLY_TRIGGERED); - /* Unreachable, unless something bad happens. */ - response = EC_RES_ERROR; - break; - case UPDATE_EXTRA_CMD_JUMP_TO_RW: -#ifdef CONFIG_RWSIG - /* - * Tell rwsig task to jump to RW. This does nothing if - * verification failed, and will only jump later on if - * verification is still in progress. - */ - rwsig_continue(); - - switch (rwsig_get_status()) { - case RWSIG_VALID: - response = EC_RES_SUCCESS; - break; - case RWSIG_INVALID: - response = EC_RES_INVALID_CHECKSUM; - break; - case RWSIG_IN_PROGRESS: - response = EC_RES_IN_PROGRESS; - break; - default: - response = EC_RES_ERROR; - } -#else - system_run_image_copy(SYSTEM_IMAGE_RW); -#endif - break; -#ifdef CONFIG_RWSIG - case UPDATE_EXTRA_CMD_STAY_IN_RO: - rwsig_abort(); - response = EC_RES_SUCCESS; - break; -#endif - case UPDATE_EXTRA_CMD_UNLOCK_RW: - flash_set_protect(EC_FLASH_PROTECT_RW_AT_BOOT, 0); - response = EC_RES_SUCCESS; - break; -#ifdef CONFIG_ROLLBACK - case UPDATE_EXTRA_CMD_UNLOCK_ROLLBACK: - flash_set_protect(EC_FLASH_PROTECT_ROLLBACK_AT_BOOT, 0); - response = EC_RES_SUCCESS; - break; -#ifdef CONFIG_ROLLBACK_SECRET_SIZE -#ifdef CONFIG_ROLLBACK_UPDATE - case UPDATE_EXTRA_CMD_INJECT_ENTROPY: { - if (data_count < CONFIG_ROLLBACK_SECRET_SIZE) { - CPRINTS("Entropy too short"); - response = EC_RES_INVALID_PARAM; - break; - } - - CPRINTS("Adding %db of entropy", data_count); - /* Add the entropy to secret. */ - rollback_add_entropy(buffer + header_size, data_count); - break; - } -#endif /* CONFIG_ROLLBACK_UPDATE */ -#ifdef CONFIG_USB_PAIRING - case UPDATE_EXTRA_CMD_PAIR_CHALLENGE: { - if (data_count < sizeof(struct pair_challenge)) { - CPRINTS("Challenge data too short"); - response = EC_RES_INVALID_PARAM; - break; - } - - /* pair_challenge takes care of answering */ - return pair_challenge((struct pair_challenge *) - (buffer + header_size)); - } -#endif -#endif /* CONFIG_ROLLBACK_SECRET_SIZE */ -#endif /* CONFIG_ROLLBACK */ -#ifdef CONFIG_TOUCHPAD - case UPDATE_EXTRA_CMD_TOUCHPAD_INFO: { - struct touchpad_info tp = { 0 }; - - if (data_count != 0) { - response = EC_RES_INVALID_PARAM; - break; - } - - response_size = touchpad_get_info(&tp); - if (response_size < 1) { - response = EC_RES_ERROR; - break; - } - -#ifdef CONFIG_TOUCHPAD_VIRTUAL_OFF - tp.fw_address = CONFIG_TOUCHPAD_VIRTUAL_OFF; - tp.fw_size = CONFIG_TOUCHPAD_VIRTUAL_SIZE; - -#ifdef CONFIG_TOUCHPAD_HASH_FW - memcpy(tp.allowed_fw_hash, touchpad_fw_full_hash, - sizeof(tp.allowed_fw_hash)); -#endif -#endif /* CONFIG_TOUCHPAD_VIRTUAL_OFF */ - QUEUE_ADD_UNITS(&update_to_usb, - &tp, response_size); - return 1; - } - case UPDATE_EXTRA_CMD_TOUCHPAD_DEBUG: { - uint8_t *data = NULL; - unsigned int write_count = 0; - - /* - * Let the touchpad driver decide what it wants to do - * with the payload data, and put the response in data. - */ - response = touchpad_debug(buffer + header_size, - data_count, &data, &write_count); - - /* - * On error, or if there is no data to write back, just - * write back response. - */ - if (response != EC_RES_SUCCESS || write_count == 0) - break; - - /* Check that we can write all the data to the queue. */ - if (write_count > queue_space(&update_to_usb)) - return EC_RES_BUSY; - - QUEUE_ADD_UNITS(&update_to_usb, data, write_count); - return 1; - } -#endif -#ifdef CONFIG_USB_CONSOLE_READ - /* - * TODO(b/112877237): move this to a new interface, so we can - * support reading log and other commands at the same time? - */ - case UPDATE_EXTRA_CMD_CONSOLE_READ_INIT: - response = uart_console_read_buffer_init(); - break; - case UPDATE_EXTRA_CMD_CONSOLE_READ_NEXT: { - uint8_t *data = buffer + header_size; - uint8_t output[64]; - uint16_t write_count = 0; - - if (data_count != 1) { - response = EC_RES_INVALID_PARAM; - break; - } - - response = uart_console_read_buffer( - data[0], - (char *)output, - MIN(sizeof(output), - queue_space(&update_to_usb)), - &write_count); - if (response != EC_RES_SUCCESS || write_count == 0) - break; - - QUEUE_ADD_UNITS(&update_to_usb, output, write_count); - return 1; - } -#endif - default: - response = EC_RES_INVALID_COMMAND; - } - - QUEUE_ADD_UNITS(&update_to_usb, &response, response_size); - } - - return rv; -} - -/* - * When was last time a USB callback was called, in microseconds, free running - * timer. - */ -static uint64_t prev_activity_timestamp; - -/* - * A flag indicating that at least one valid PDU containing flash update block - * has been received in the current transfer session. - */ -static uint8_t data_was_transferred; - -/* Reply with an error to remote side, reset state. */ -static void send_error_reset(uint8_t resp_value) -{ - QUEUE_ADD_UNITS(&update_to_usb, &resp_value, 1); - rx_state_ = rx_idle; - data_was_transferred = 0; -} - -/* Called to deal with data from the host */ -static void update_out_handler(struct consumer const *consumer, size_t count) -{ - struct update_frame_header upfr; - size_t resp_size; - uint8_t resp_value; - uint64_t delta_time; - - /* How much time since the previous USB callback? */ - delta_time = get_time().val - prev_activity_timestamp; - prev_activity_timestamp += delta_time; - - /* If timeout exceeds 5 seconds - let's start over. */ - if ((delta_time > 5000000) && (rx_state_ != rx_idle)) { - rx_state_ = rx_idle; - CPRINTS("FW update: recovering after timeout"); - } - - if (rx_state_ == rx_idle) { - /* - * The payload must be an update initiating PDU. - * - * The size of the response returned in the same buffer will - * exceed the received frame size; Let's make sure there is - * enough room for the response in the buffer. - */ - union { - struct update_frame_header upfr; - struct { - uint32_t unused; - struct first_response_pdu startup_resp; - }; - } u; - - /* Check is this is a channeled TPM extension command. */ - if (try_vendor_command(consumer, count)) - return; - - /* - * An update start PDU is a command without any payload, with - * digest = 0, and base = 0. - */ - if (!fetch_transfer_start(consumer, count, &u.upfr) || - be32toh(u.upfr.block_size) != - sizeof(struct update_frame_header) || - u.upfr.cmd.block_digest != 0 || - u.upfr.cmd.block_base != 0) { - /* - * Something is wrong, this payload is not a valid - * update start PDU. Let'w indicate this by returning - * a single byte error code. - */ - CPRINTS("FW update: invalid start."); - send_error_reset(UPDATE_GEN_ERROR); - return; - } - - CPRINTS("FW update: starting..."); - fw_update_command_handler(&u.upfr.cmd, count - - offsetof(struct update_frame_header, - cmd), - &resp_size); - - if (!u.startup_resp.return_value) { - rx_state_ = rx_outside_block; /* We're in business. */ - data_was_transferred = 0; /* No data received yet. */ - } - - /* Let the host know what updater had to say. */ - QUEUE_ADD_UNITS(&update_to_usb, &u.startup_resp, resp_size); - return; - } - - if (rx_state_ == rx_outside_block) { - /* - * Expecting to receive the beginning of the block or the - * reset command if all data blocks have been processed. - */ - if (count == 4) { - uint32_t command; - - QUEUE_REMOVE_UNITS(consumer->queue, &command, - sizeof(command)); - command = be32toh(command); - if (command == UPDATE_DONE) { - CPRINTS("FW update: done"); - - if (data_was_transferred) { - fw_update_complete(); - data_was_transferred = 0; - } - - resp_value = 0; - QUEUE_ADD_UNITS(&update_to_usb, - &resp_value, 1); - rx_state_ = rx_idle; - return; - } - } - - /* - * At this point we expect a block start message. It is - * sizeof(upfr) bytes in size. - */ - if (!fetch_transfer_start(consumer, count, &upfr)) { - CPRINTS("Invalid block start."); - send_error_reset(UPDATE_GEN_ERROR); - return; - } - - /* Let's allocate a large enough buffer. */ - block_size = be32toh(upfr.block_size) - - offsetof(struct update_frame_header, cmd); - - /* - * Only update start PDU is allowed to have a size 0 payload. - */ - if (block_size <= sizeof(struct update_command) || - block_size > sizeof(block_buffer)) { - CPRINTS("Invalid block size (%d).", block_size); - send_error_reset(UPDATE_GEN_ERROR); - return; - } - - /* - * Copy the rest of the message into the block buffer to pass - * to the updater. - */ - block_index = sizeof(upfr) - - offsetof(struct update_frame_header, cmd); - memcpy(block_buffer, &upfr.cmd, block_index); - block_size -= block_index; - rx_state_ = rx_inside_block; - return; - } - - /* Must be inside block. */ - QUEUE_REMOVE_UNITS(consumer->queue, block_buffer + block_index, count); - block_index += count; - block_size -= count; - - if (block_size) { - if (count <= sizeof(upfr)) { - /* - * A block header size instead of chunk size message - * has been received, let's abort the transfer. - */ - CPRINTS("Unexpected header"); - send_error_reset(UPDATE_GEN_ERROR); - return; - } - return; /* More to come. */ - } - - /* - * Ok, the entire block has been received and reassembled, pass it to - * the updater for verification and programming. - */ - fw_update_command_handler(block_buffer, block_index, &resp_size); - - /* - * There was at least an attempt to program the flash, set the - * flag. - */ - data_was_transferred = 1; - resp_value = block_buffer[0]; - QUEUE_ADD_UNITS(&update_to_usb, &resp_value, sizeof(resp_value)); - rx_state_ = rx_outside_block; -} - -struct consumer const update_consumer = { - .queue = &usb_to_update, - .ops = &((struct consumer_ops const) { - .written = update_out_handler, - }), -}; diff --git a/include/config.h b/include/config.h index bc51beb4a6..00ea17e4fd 100644 --- a/include/config.h +++ b/include/config.h @@ -3566,7 +3566,6 @@ * Enable touchpad FW update over USB update protocol, and define touchpad * virtual address and size. */ -#undef CONFIG_TOUCHPAD_VIRTUAL_OFF #undef CONFIG_TOUCHPAD_VIRTUAL_SIZE /* @@ -4064,12 +4063,6 @@ /* Support USB HID interface. */ #undef CONFIG_USB_HID -/* Support USB HID keyboard interface. */ -#undef CONFIG_USB_HID_KEYBOARD - -/* Support USB HID keyboard backlight. */ -#undef CONFIG_USB_HID_KEYBOARD_BACKLIGHT - /* Support USB HID touchpad interface. */ #undef CONFIG_USB_HID_TOUCHPAD @@ -4332,14 +4325,6 @@ /* Firmware updates using other than HC channel(s). */ #undef CONFIG_NON_HC_FW_UPDATE #undef CONFIG_USB_FW_UPDATE -/* A different config for the same update. TODO(vbendeb): dedupe these */ -#undef CONFIG_USB_UPDATE - -/* Add support for pairing over the USB update interface. */ -#undef CONFIG_USB_PAIRING - -/* Add support for reading UART buffer from USB update interface. */ -#undef CONFIG_USB_CONSOLE_READ /* PDU size for fw update over USB (or TPM). */ #define CONFIG_UPDATE_PDU_SIZE 1024 |