diff options
Diffstat (limited to 'docs/usb_updater.md')
-rw-r--r-- | docs/usb_updater.md | 201 |
1 files changed, 0 insertions, 201 deletions
diff --git a/docs/usb_updater.md b/docs/usb_updater.md deleted file mode 100644 index f1505550d1..0000000000 --- a/docs/usb_updater.md +++ /dev/null @@ -1,201 +0,0 @@ -# EC update over USB - -chip/g (Cr50) and common code (hammer, servo_micro/v4) update over USB protocols -share a lot in terms of protocol and ideas, but use different code bases. - -chip/g EC-side implementation is found in `chip/g/*upgrade*`, and the userspace -tool which provides updates over USB among with supporting other features and -interfaces is found in `extra/usb_updater/gsctool.c`. - -Common code uses implementations in `common/*update*.c` and -`include/*update*.h`, and `extra/usb_updater/usb_updater2.c` for the userspace -updater. - -## Cr50-specific notes - -The Cr50 firmware image consists of multiple sections, of interest to the USB -updater are the RO and RW code sections, two of each. When firmware update -session is established, the Cr50 device reports locations of backup RW and RO -sections (those not currently used by the device). - -Based on this information the updater carves out the appropriate sections from -the full Cr50 firmware binary image and sends them to the device for programming -into flash. Once the new sections are programmed and the device is restarted, -the new RO and RW are used if they pass verification and are logically newer -than the existing sections. - -There are two ways to communicate with the Cr50 device: USB and `/dev/tpm0` -(when `gsctool` is running on a chromebook with the Cr50 device). Originally -different protocols were used to communicate over different channels, starting -with version 3 the same protocol is used. - -## Common-code notes - -For non-Cr50 or chip/g devices (common code), the layout is a bit different, as -devices usually have a single RO and a single RW, where RO is truly read-only in -production, and verifies RW before jumping to it. - -For testing and development, `usb_updater2` is provided, while production code -will use `hammerd` (in `src/platform/hammerd`) to update the device. - -## Update protocol - -The host (either a local AP or a workstation) is the master of the firmware -update protocol, it sends data to the Cr50 device, which processes it and -responds. - -The encapsulation format is different between the `/dev/tpm0` and USB cases: - -``` - 4 bytes 4 bytes 4 bytes variable size -+-----------+--------------+---------------+----------~~--------------+ -+ total size| block digest | dest address | data | -+-----------+--------------+---------------+----------~~--------------+ - \ \ / - \ \ / - \ +----- FW update PDU sent over /dev/tpm0 -----------+ - \ / - +--------- USB frame, requires total size field ------------+ -``` - -The update protocol data units (PDUs) are passed over `/dev/tpm0`, the -encapsulation includes integrity verification and destination address of the -data (more of this later). `/dev/tpm0` transactions pretty much do not have size -limits, whereas the USB data is sent in chunks of the size determined when the -USB connection is set up. This is why USB requires an additional encapsulation -into frames to communicate the PDU size to the client side so that the PDU can -be reassembled before passing to the programming function. - -In general, the protocol consists of two phases: connection establishment and -actual image transfer. - -The very first PDU of the transfer session is used to establish the connection. -The first PDU does not have any data, and the `dest address` field is set to -zero. Receiving such a PDU signals the programming function that the host -intends to transfer a new image. - -The response to the first PDU varies depending on the protocol version. - -Note that protocol versions before 5 are described here for completeness, but -are not supported any more. - -Version 1 is used over `/dev/tpm0`. The response is either 4 or 1 bytes in size. -The 4 byte response is the *base address* of the backup RW section, and there is -no support for RO updates. The one byte response is an error indication, -possibly reporting flash erase failure, command format error, etc. - -Version 2 is used over USB. The response is 8 bytes in size. The first four -bytes are either the *base address* of the backup RW section (still no RO -updates), or an error code, the same as in Version 1. The second 4 bytes are the -protocol version number (set to 2). - -All versions above 2 behave the same over `/dev/tpm0` and USB. - -Version 3 response is 16 bytes in size. The first 4 bytes are the error code the -second 4 bytes are the protocol version (set to 3) and then 4 byte *offset* of -the RO section followed by the 4 byte *offset* of the RW section. - -Version 4 response in addition to version 3 provides header revision fields for -active RO and RW images running on the target. - -Once the connection is established, the image to be programmed into flash is -transferred to the Cr50 in 1K PDUs. In versions 1 and 2 the address in the -header is the absolute address to place the block to, in version 3 and later it -is the offset into the flash. - -Protocol version 5 includes RO and RW key ID information into the first PDU -response. The key ID could be used to tell between prod and dev signing modes, -among other things. - -Protocol version 6 does not change the format of the first PDU response, but it -indicates the target's ability to channel TPM vendor commands through USB -connection. - -Common-code updater also uses protocol version 6, but has a fairly different -`first_response_pdu` header, indicated by setting `1` in the higher 16-bit for -the protocol version field (`header_type`). The response includes fields such as -maximum PDU size (which is not fixed to 1KB like for Cr50), flash protection -status, version string, and a minimum rollback version. - -Details can be found in `include/update_fw.h`. - -### State machine (update over USB) - -This describes the EC-side state machine for update over USB. - -IDLE state: - -* If host sends update start PDU (a command without any payload, digest = 0 - and base = 0): - - * Reply with `first_update_pdu` block. Go to OUTSIDE_BLOCK state. - -* If host sends a vendor command (see below), execute that, reply, and stay in - IDLE state. Note that vendor commands are only accepted in IDLE state. - -OUTSIDE_BLOCK (preparing to receive start of PDU): - -* If no data is received in 5 seconds, go back to IDLE state. -* If host sends `UPDATE_DONE` command (by setting `dest address` to - `0xb007ab1e`), go back to IDLE state. -* If host sends a valid block start with a valid address, copy the rest of the - payload and go to INSIDE_BLOCK state. - -INSIDE_BLOCK (in a middle of a PDU): - -* If no data is received in 5 seconds, go back to IDLE state. -* Copy data to a buffer. - - * If buffer is full (i.e. matches the total expected PDU size), write the - data and go to OUTSIDE_BLOCK. - * Else, stay in INSIDE_BLOCK. - -### Vendor commands (channeled TPM command, Cr50) - -When channeling TPM vendor commands the USB frame looks as follows: - -``` - 4 bytes 4 bytes 4 bytes 2 bytes variable size -+-----------+--------------+---------------+-----------+------~~~-------+ -+ total size| block digest | EXT_CMD | vend. sub.| data | -+-----------+--------------+---------------+-----------+------~~~-------+ -``` - -Where `Vend. sub` is the vendor subcommand, and data field is subcommand -dependent. The target tells between update PDUs and encapsulated vendor -subcommands by looking at the `EXT_CMD` value - it is set to `0xbaccd00a` and as -such is guaranteed not to be a valid update PDU destination address. - -These commands cannot exceed the USB packet size (typically 64 bytes), as no -reassembly is performed for such frames. - -The vendor command response size is not fixed, it is subcommand dependent. - -The Cr50 device responds to each update PDU with a confirmation which is 4 bytes -in size in protocol version 2, and 1 byte in size in all other versions. Zero -value means success, non-zero value is the error code reported by Cr50. - -Again, vendor command responses are subcommand specific. - -### Vendor commands (common code) - -Vendor commands for command code look very similar to the TPM vendor commands -above, except that we use `UPDATE_EXTRA_CMD` (`b007ab1f`) instead of `EXT_CMD`, -and `Vend. sub.` have a limit set of values (unless otherwise noted, commands -take no parameter, and reply with a single 1-byte status code): - -* UPDATE_EXTRA_CMD_IMMEDIATE_RESET (0): Tell EC to reboot immediately. -* UPDATE_EXTRA_CMD_JUMP_TO_RW (1): Tell EC (in RO) to jump to RW, if the - signature verifies. -* UPDATE_EXTRA_CMD_STAY_IN_RO (2): Tell EC (in RO), to stay in RO, and not - jump to RW automatically. After this command is sent, a reset is necessary - for the EC to accept to jump to RW again. -* UPDATE_EXTRA_CMD_UNLOCK_RW (3): Tell EC to unlock RW on next reset. -* UPDATE_EXTRA_CMD_UNLOCK_ROLLBACK (4): Tell EC to unlock ROLLBACK on next - reset. -* UPDATE_EXTRA_CMD_INJECT_ENTROPY (5): Inject entropy into the device-specific - unique identifier (takes at least CONFIG_ROLLBACK_SECRET_SIZE=32 bytes of - data). -* UPDATE_EXTRA_CMD_PAIR_CHALLENGE (6): Tell EC to answer a X25519 challenge - for pairing. Takes in a `struct pair_challenge` as data, answers with a - `struct pair_challenge_response`. |