summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extra/usb_updater/gsctool.c205
1 files changed, 198 insertions, 7 deletions
diff --git a/extra/usb_updater/gsctool.c b/extra/usb_updater/gsctool.c
index d65f1b9699..be5f6309a3 100644
--- a/extra/usb_updater/gsctool.c
+++ b/extra/usb_updater/gsctool.c
@@ -40,6 +40,85 @@
#include "usb_descriptor.h"
#include "verify_ro.h"
+
+/*
+ * This enum must match CcdCap enum in applications/sys_mgr/src/ccd.rs in the
+ * Ti50 common git tree.
+ */
+enum Ti50CcdCapabilities {
+ TI50_CCD_CAP_UART_GSC_RX_AP_TX = 0,
+ TI50_CCD_CAP_UART_GSC_TX_AP_RX,
+ TI50_CCD_CAP_UART_GSC_RX_EC_TX,
+ TI50_CCD_CAP_UART_GSC_TX_EC_RX,
+ TI50_CCD_CAP_UART_GSC_RX_FPMCU_TX,
+ TI50_CCD_CAP_UART_GSC_TX_FPMCU_RX,
+ TI50_CCD_CAP_FLASH_AP,
+ TI50_CCD_CAP_FLASH_EC,
+ TI50_CCD_CAP_OVERRIDE_WP,
+ TI50_CCD_CAP_REBOOT_ECAP,
+ TI50_CCD_CAP_GSC_FULL_CONSOLE,
+ TI50_CCD_CAP_UNLOCK_NO_REBOOT,
+ TI50_CCD_CAP_UNLOCK_NO_SHORT_PP,
+ TI50_CCD_CAP_OPEN_NO_TPM_WIPE,
+ TI50_CCD_CAP_OPEN_NO_LONG_PP,
+ TI50_CCD_CAP_REMOVE_BATTERY_BYPASS_PP,
+ TI50_CCD_CAP_I2_C,
+ TI50_CCD_CAP_FLASH_READ,
+ TI50_CCD_CAP_OPEN_NO_DEV_MODE,
+ TI50_CCD_CAP_OPEN_FROM_USB,
+ TI50_CCD_CAP_OVERRIDE_BATT,
+ TI50_CCD_CAP_BOOT_UNVERIFIED_RO,
+ TI50_CCD_CAP_COUNT,
+};
+
+static const struct ccd_capability_info ti50_cap_info[] = {
+ {"UartGscRxAPTx", CCD_CAP_STATE_ALWAYS},
+ {"UartGscTxAPRx", CCD_CAP_STATE_ALWAYS},
+ {"UartGscRxECTx", CCD_CAP_STATE_ALWAYS},
+ {"UartGscTxECRx", CCD_CAP_STATE_IF_OPENED},
+ {"UartGscRxFpmcuTx", CCD_CAP_STATE_ALWAYS},
+ {"UartGscTxFpmcuRx", CCD_CAP_STATE_IF_OPENED},
+ {"FlashAP", CCD_CAP_STATE_IF_OPENED},
+ {"FlashEC", CCD_CAP_STATE_IF_OPENED},
+ {"OverrideWP", CCD_CAP_STATE_IF_OPENED},
+ {"RebootECAP", CCD_CAP_STATE_IF_OPENED},
+ {"GscFullConsole", CCD_CAP_STATE_IF_OPENED},
+ {"UnlockNoReboot", CCD_CAP_STATE_ALWAYS},
+ {"UnlockNoShortPP", CCD_CAP_STATE_ALWAYS},
+ {"OpenNoTPMWipe", CCD_CAP_STATE_IF_OPENED},
+ {"OpenNoLongPP", CCD_CAP_STATE_IF_OPENED},
+ {"RemoveBatteryBypassPP", CCD_CAP_STATE_ALWAYS},
+ {"I2C", CCD_CAP_STATE_IF_OPENED},
+ {"FlashRead", CCD_CAP_STATE_ALWAYS},
+ /*
+ * The below two settings do not match ccd.rs value, which is
+ * controlled at compile time.
+ */
+ {"OpenNoDevMode", CCD_CAP_STATE_IF_OPENED},
+ {"OpenFromUSB", CCD_CAP_STATE_IF_OPENED},
+ {"OverrideBatt", CCD_CAP_STATE_IF_OPENED},
+ /* The below capability is presently set to 'never' in ccd.rs. */
+ {"BootUnverifiedRo", CCD_CAP_STATE_IF_OPENED},
+};
+
+#define CR50_CCD_CAP_COUNT CCD_CAP_COUNT
+
+/*
+ * One of the basic assumptions of the code handling multiple ccd_info layouts
+ * is that the number of words in the capabilities array is the same for all
+ * layouts. Let's verify this at compile time.
+ */
+BUILD_ASSERT((CR50_CCD_CAP_COUNT/32) == (TI50_CCD_CAP_COUNT/32));
+
+/*
+ * Version 0 CCD info packet does not include the header, the actual packet
+ * size is used to conclude that the received payload is of version 0.
+ *
+ * Let's hardcode this size to make sure that it is fixed even if the
+ * underlying structure (struct ccd_info_response) size changes in the future.
+ */
+#define CCD_INFO_V0_SIZE 23
+
/*
* This file contains the source code of a Linux application used to update
* CR50 device firmware.
@@ -163,6 +242,33 @@
#define PROTOCOL USB_PROTOCOL_GOOGLE_CR50_NON_HC_FW_UPDATE
/*
+ * CCD Info from GSC is communicated using different structure layouts.
+ * Version 0 does not have a header and includes just the payload information.
+ * Version 2 is prepended by a header which has a distinct value in the first
+ * word, and the version number and the total size in the two halfwords after
+ * that.
+ *
+ * Once the payload is received, the absence of the distinct value in the
+ * first word and the match of the payload size to the expected size of the
+ * version 0 payload indicates that this is indeed a version 0 packet. The
+ * distinct first header value and the match of the size field indicates that
+ * this is a later version packet.
+ */
+#define CCD_INFO_MAGIC 0x49444343 /* This is 'CCDI' in little endian. */
+#define CCD_VERSION 1 /* Ti50 CCD INFO layout. */
+
+struct ccd_info_response_header {
+ uint32_t ccd_magic;
+ uint16_t ccd_version;
+ uint16_t ccd_size;
+} __packed;
+
+struct ccd_info_response_packet {
+ struct ccd_info_response_header cir_header;
+ struct ccd_info_response cir_body;
+};
+
+/*
* Need to create an entire TPM PDU when upgrading over /dev/tpm0 and need to
* have space to prepare the entire PDU.
*/
@@ -2091,22 +2197,101 @@ void poll_for_pp(struct transfer_descriptor *td,
}
+/* Determine the longest capability name found in the passed in table. */
+static size_t longest_cap_name_len(const struct ccd_capability_info *table,
+ size_t count)
+{
+ size_t i;
+ size_t result = 0;
+
+ for (i = 0; i < count; i++) {
+ size_t this_size;
+
+ this_size = strlen(table[i].name);
+ if (this_size > result)
+ result = this_size;
+ }
+ return result;
+}
+
+/*
+ * Print the passed in capability name padded to the longest length determined
+ * earlier.
+ */
+static void print_aligned(const char *name, size_t field_size)
+{
+ size_t name_len;
+
+ name_len = strlen(name);
+
+ printf("%s", name);
+ while (name_len < field_size) {
+ printf(" ");
+ name_len++;
+ }
+}
+
static void print_ccd_info(void *response, size_t response_size)
{
+ struct ccd_info_response_header ccd_info_header;
struct ccd_info_response ccd_info;
size_t i;
- const struct ccd_capability_info cap_info[] = CAP_INFO_DATA;
+ const struct ccd_capability_info cr50_cap_info[] = CAP_INFO_DATA;
const char *state_names[] = CCD_STATE_NAMES;
const char *cap_state_names[] = CCD_CAP_STATE_NAMES;
uint32_t caps_bitmap = 0;
+ uint32_t ccd_info_version;
- if (response_size != sizeof(ccd_info)) {
+ /*
+ * CCD info structure is different for different GSCs. Two layouts are
+ * defined at this time, version 0 (Cr50) and version 1 (Ti50). The
+ * array below indexed by version number provides access to version
+ * specific information about the layout.
+ */
+ const struct {
+ size_t cap_count;
+ const struct ccd_capability_info *info_table;
+ } version_to_ccd[] = {
+ {CR50_CCD_CAP_COUNT, cr50_cap_info},
+ {TI50_CCD_CAP_COUNT, ti50_cap_info},
+ };
+
+ /* Run time determined properties of the CCD info table. */
+ size_t gsc_cap_count;
+ const struct ccd_capability_info *gsc_capability_info;
+ size_t name_column_width;
+
+ if (response_size < sizeof(ccd_info_header)) {
+ fprintf(stderr, "CCD info response too short %zd\n",
+ response_size);
+ exit(update_error);
+ }
+
+ /* Let's check if this is a newer version response. */
+ memcpy(&ccd_info_header, response, sizeof(ccd_info_header));
+ if ((ccd_info_header.ccd_magic == CCD_INFO_MAGIC) &&
+ (ccd_info_header.ccd_size == response_size) &&
+ /* Verify that payload size matches ccd_info size. */
+ ((response_size - sizeof(ccd_info_header)) == sizeof(ccd_info))) {
+ ccd_info_version = ccd_info_header.ccd_version;
+ memcpy(&ccd_info,
+ (uint8_t *)response +
+ sizeof(struct ccd_info_response_header),
+ sizeof(ccd_info));
+ } else if (response_size == CCD_INFO_V0_SIZE) {
+ ccd_info_version = 0; /* Default, Cr50 case. */
+ memcpy(&ccd_info, response, sizeof(ccd_info));
+ } else {
fprintf(stderr, "Unexpected CCD info response size %zd\n",
response_size);
exit(update_error);
}
- memcpy(&ccd_info, response, sizeof(ccd_info));
+ if (ccd_info_version >= ARRAY_SIZE(version_to_ccd)) {
+ fprintf(stderr, "Unsupported CCD info version number %d\n",
+ ccd_info_version);
+ exit(update_error);
+ }
/* Convert it back to host endian format. */
ccd_info.ccd_flags = be32toh(ccd_info.ccd_flags);
@@ -2124,7 +2309,12 @@ static void print_ccd_info(void *response, size_t response_size)
CCD_INDICATOR_BIT_HAS_PASSWORD) ? "Set" : "None");
printf("Flags: %#06x\n", ccd_info.ccd_flags);
printf("Capabilities, current and default:\n");
- for (i = 0; i < CCD_CAP_COUNT; i++) {
+
+ gsc_cap_count = version_to_ccd[ccd_info_version].cap_count;
+ gsc_capability_info = version_to_ccd[ccd_info_version].info_table;
+ name_column_width = longest_cap_name_len(gsc_capability_info,
+ gsc_cap_count) + 1;
+ for (i = 0; i < gsc_cap_count; i++) {
int is_enabled;
int index;
int shift;
@@ -2157,8 +2347,9 @@ static void print_ccd_info(void *response, size_t response_size)
}
}
- printf(" %-15s %c %s",
- cap_info[i].name,
+ printf(" ");
+ print_aligned(gsc_capability_info[i].name, name_column_width);
+ printf("%c %s",
is_enabled ? 'Y' : '-',
cap_state_names[cap_current]);
@@ -2180,7 +2371,7 @@ static void process_ccd_state(struct transfer_descriptor *td, int ccd_unlock,
{
uint8_t payload;
/* Max possible response size is when ccd_info is requested. */
- uint8_t response[sizeof(struct ccd_info_response)];
+ uint8_t response[sizeof(struct ccd_info_response_packet)];
size_t response_size;
int rv;