summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Chen <philipchen@google.com>2017-05-12 15:17:32 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2018-03-13 23:56:30 +0000
commitb3af8a7125cef37701af5466fd30064b1bf4ee02 (patch)
tree29ee61791f7d65efdf699803ace5109962617a6f
parent0e8e382e22bcd7e35a25a25b9ef83df36e8615be (diff)
downloadchrome-ec-b3af8a7125cef37701af5466fd30064b1bf4ee02.tar.gz
cr50: Add console and TPM vendor commands to get/set board ID
This patch adds vendor and console commands to read and write the board ID space in the INFO1 block. Current image's board ID settings are saved in the image header by the latest codesigner. Board ID write attempts are rejected if the board ID space is already initialized, or if the currently running image will not be allowed to run with the new board ID space settings. Error codes are returned to the caller as a single byte value. Successful read command returns 12 bytes of the board ID space contents. The console command always allows to read the board ID value, and allows to write it if the image was built with debug enabled. BUG=b:35586335 BRANCH=cr50 TEST=as follows: - verified that board ID can be read by any image and set by debug images. - with the upcoming patches verified the ability to set and read board ID values using vendor commands. Original Change-Id: I35a3e2db92175a29de8011172b80091065b27414 Original Signed-off-by: Philip Chen <philipchen@google.com> Original Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Original Reviewed-on: https://chromium-review.googlesource.com/522234 Original Reviewed-by: Aseda Aboagye <aaboagye@chromium.org> Original Reviewed-by: Mary Ruthven <mruthven@chromium.org> Change-Id: I45da7abfc4209a7a6be423635c0975bd9c858bd0 Reviewed-on: https://chromium-review.googlesource.com/958884 Reviewed-by: Vadim Bendebury <vbendeb@chromium.org> Tested-by: Vadim Bendebury <vbendeb@chromium.org> Tested-by: Marco Chen <marcochen@chromium.org> Commit-Queue: Marco Chen <marcochen@chromium.org>
-rw-r--r--board/cr50/board_id.c269
-rw-r--r--board/cr50/board_id.h31
-rw-r--r--board/cr50/build.mk1
-rw-r--r--chip/g/flash_info.h28
-rw-r--r--chip/g/signed_header.h17
-rw-r--r--include/tpm_vendor_cmds.h4
6 files changed, 347 insertions, 3 deletions
diff --git a/board/cr50/board_id.c b/board/cr50/board_id.c
new file mode 100644
index 0000000000..f6f3202a96
--- /dev/null
+++ b/board/cr50/board_id.c
@@ -0,0 +1,269 @@
+/* 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 "common.h"
+#include "board_id.h"
+#include "endian.h"
+#include "extension.h"
+#include "flash_info.h"
+#include "signed_header.h"
+#include "system.h"
+#include "util.h"
+
+#define CPRINTS(format, args...) cprints(CC_RBOX, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_RBOX, format, ## args)
+
+/**
+ * Return the image header for the current image copy
+ */
+const struct SignedHeader *get_current_image_header(void)
+{
+ return (const struct SignedHeader *)
+ get_program_memory_addr(system_get_image_copy());
+}
+
+/**
+ * Check the current header vs. the supplied Board ID
+ *
+ * @param board_id Pointer to a Board ID structure to check
+ * @param h Pointer to the currently running image's header
+ *
+ * @return 0 if no mismatch, non-zero if mismatch
+ */
+static uint32_t check_board_id_vs_header(const struct board_id *id,
+ const struct SignedHeader *h)
+{
+ uint32_t mismatch;
+ uint32_t header_board_id_type;
+ uint32_t header_board_id_mask;
+ uint32_t header_board_id_flags;
+
+ /* Blank Board ID matches all headers */
+ if (~(id->type & id->type_inv & id->flags) == 0)
+ return 0;
+
+ header_board_id_type = SIGNED_HEADER_PADDING ^ h->board_id_type;
+ header_board_id_mask = SIGNED_HEADER_PADDING ^ h->board_id_type_mask;
+ header_board_id_flags = SIGNED_HEADER_PADDING ^ h->board_id_flags;
+
+ /* Blank header means this is a common image, can run on any device. */
+ if ((header_board_id_type |
+ header_board_id_mask |
+ header_board_id_flags) == 0)
+ return 0;
+
+ /*
+ * Masked bits in header Board ID type must match type and inverse from
+ * flash.
+ */
+ mismatch = header_board_id_type ^ id->type;
+ mismatch |= header_board_id_type ^ ~id->type_inv;
+ mismatch &= header_board_id_mask;
+
+ /*
+ * All 1-bits in header Board ID flags must be present in flags from
+ * flash
+ */
+ mismatch |=
+ ((header_board_id_flags & id->flags) != header_board_id_flags);
+
+ return mismatch;
+}
+
+/**
+ * Check board ID from the flash INFO1 space.
+ *
+ * @param id Pointer to a Board ID structure to fill
+ *
+ * @return EC_SUCCESS of an error code in cases of vairous failures to read.
+ */
+static int read_board_id(struct board_id *id)
+{
+ uint32_t *id_p;
+ int i;
+
+ /*
+ * Board ID structure size is guaranteed to be divisible by 4, and it
+ * is guaranteed to be aligned at 4 bytes.
+ */
+
+ id_p = (uint32_t *)id;
+
+ /* Make sure INFO1 board ID space is readable */
+ if (flash_info_read_enable(INFO_BOARD_SPACE_OFFSET,
+ INFO_BOARD_SPACE_PROTECT_SIZE) !=
+ EC_SUCCESS) {
+ CPRINTS("%s: failed to enable read access to info", __func__);
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ for (i = 0; i < sizeof(*id); i += sizeof(uint32_t)) {
+ int rv;
+
+ rv = flash_physical_info_read_word
+ (INFO_BOARD_SPACE_OFFSET +
+ offsetof(struct info1_board_space, bid) + i,
+ id_p);
+ if (rv != EC_SUCCESS) {
+ CPRINTF("%s: failed to read word %d, error %d\n",
+ i, rv);
+ return rv;
+ }
+ id_p++;
+ }
+ return EC_SUCCESS;
+}
+
+/**
+ * Write board ID into the flash INFO1 space.
+ *
+ * @param id Pointer to a Board ID structure to copy into INFO1
+ *
+ * @return EC_SUCCESS or an error code in cases of various failures to read or
+ * if the space has been already initialized.
+ */
+static int write_board_id(const struct board_id *id)
+{
+ struct board_id id_test;
+ uint32_t rv;
+
+ /*
+ * Make sure the current header will still validate against the
+ * proposed values. If it doesn't, then programming these values
+ * would cause the next boot to fail.
+ */
+ if (check_board_id_vs_header(id, get_current_image_header()) != 0) {
+ CPRINTS("%s: Board ID wouldn't allow current header", __func__);
+ return EC_ERROR_INVAL;
+ }
+
+ /* Fail if Board ID is already programmed */
+ rv = read_board_id(&id_test);
+ if (rv != EC_SUCCESS) {
+ CPRINTS("%s: error reading Board ID", __func__);
+ return rv;
+ }
+
+ if (~(id_test.type & id_test.type_inv & id_test.flags) != 0) {
+ CPRINTS("%s: Board ID already programmed", __func__);
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ /* Enable write access */
+ if (flash_info_write_enable(INFO_BOARD_SPACE_OFFSET,
+ INFO_BOARD_SPACE_PROTECT_SIZE) !=
+ EC_SUCCESS) {
+ CPRINTS("%s: failed to enable write access", __func__);
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ /* Write Board ID */
+ rv = flash_info_physical_write(INFO_BOARD_SPACE_OFFSET +
+ offsetof(struct info1_board_space, bid),
+ sizeof(*id), (const char *)id);
+ if (rv != EC_SUCCESS)
+ CPRINTS("%s: write failed", __func__);
+
+ /* Disable write access */
+ flash_info_write_disable();
+
+ return rv;
+}
+
+static enum vendor_cmd_rc vc_set_board_id(enum vendor_cmd_cc code,
+ void *buf,
+ size_t input_size,
+ size_t *response_size)
+{
+ struct board_id id;
+ uint8_t *pbuf = buf;
+
+ *response_size = 1;
+
+ /* Exactly two fields are expected. */
+ if (input_size != sizeof(id.type) + sizeof(id.flags)) {
+ *pbuf = VENDOR_RC_BOGUS_ARGS;
+ return VENDOR_RC_BOGUS_ARGS;
+ }
+
+ memcpy(&id.type, pbuf, sizeof(id.type));
+ id.type = be32toh(id.type);
+ id.type_inv = ~id.type;
+
+ memcpy(&id.flags, pbuf + sizeof(id.type), sizeof(id.flags));
+ id.flags = be32toh(id.flags);
+
+ /* We care about the LSB only. */
+ *pbuf = write_board_id(&id);
+
+ return *pbuf;
+}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_SET_BOARD_ID, vc_set_board_id);
+
+static int command_board_id(int argc, char **argv)
+{
+ struct board_id id;
+ int rv = EC_ERROR_PARAM_COUNT;
+
+ if (argc == 1) {
+ rv = read_board_id(&id);
+
+ if (rv != EC_SUCCESS) {
+ ccprintf("Failed to read board ID space\n");
+ return rv;
+ }
+ ccprintf("Board ID: %08x, flags %08x\n", id.type, id.flags);
+
+ if ((~id.type | ~id.type_inv | ~id.flags) == 0)
+ return rv; /* The space is not initialized. */
+
+ if (id.type != ~id.type_inv)
+ ccprintf("Inv Type Mismatch (%08x instead of %08x)!\n",
+ id.type_inv, ~id.type);
+ }
+#ifdef CR50_DEV
+ else if (argc == 3) {
+ char *e;
+
+ id.type = strtoi(argv[1], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM1;
+ id.type_inv = ~id.type;
+ id.flags = strtoi(argv[2], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ rv = write_board_id(&id);
+ } else {
+ ccprintf("specify board type and flags\n");
+ rv = EC_ERROR_PARAM_COUNT;
+ }
+#endif
+ return rv;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(bid,
+ command_board_id, NULL, "Set/Get Board ID");
+
+static enum vendor_cmd_rc vc_get_board_id(enum vendor_cmd_cc code,
+ void *buf,
+ size_t input_size,
+ size_t *response_size)
+{
+ struct board_id id;
+
+ if (read_board_id(&id))
+ return VENDOR_RC_READ_FLASH_FAIL;
+
+ /* Convert to line representation. */
+ id.type = htobe32(id.type);
+ id.type_inv = htobe32(id.type_inv);
+ id.flags = htobe32(id.flags);
+
+ memcpy(buf, &id, sizeof(id));
+ *response_size = sizeof(id);
+
+ return VENDOR_RC_SUCCESS;
+}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_GET_BOARD_ID, vc_get_board_id);
diff --git a/board/cr50/board_id.h b/board/cr50/board_id.h
new file mode 100644
index 0000000000..fefcd4c36b
--- /dev/null
+++ b/board/cr50/board_id.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#ifndef __EC_BOARD_CR50_BOARD_ID__H
+#define __EC_BOARD_CR50_BOARD_ID__H
+
+#include "util.h"
+
+/* Structure holding Board ID */
+struct board_id {
+ uint32_t type; /* Board type */
+ uint32_t type_inv; /* Board type (inverted) */
+ uint32_t flags; /* Flags */
+};
+
+/* Info1 Board space contents. */
+struct info1_board_space {
+ struct board_id bid;
+};
+
+#define INFO_BOARD_ID_SIZE sizeof(struct board_id)
+#define INFO_BOARD_SPACE_PROTECT_SIZE 16
+
+BUILD_ASSERT((offsetof(struct info1_board_space, bid) & 3) == 0);
+BUILD_ASSERT((INFO_BOARD_ID_SIZE & 3) == 0);
+BUILD_ASSERT(sizeof(struct info1_board_space) <= INFO_BOARD_SPACE_PROTECT_SIZE);
+
+#endif /* ! __EC_BOARD_CR50_BOARD_ID_H */
diff --git a/board/cr50/build.mk b/board/cr50/build.mk
index 1d8647d496..639743f0b7 100644
--- a/board/cr50/build.mk
+++ b/board/cr50/build.mk
@@ -30,6 +30,7 @@ dirs-y += $(BDIR)/tpm2
# Objects that we need to build
board-y = board.o
+board-y += board_id.o
board-${CONFIG_RDD} += rdd.o
board-${CONFIG_USB_SPI} += usb_spi.o
board-y += tpm2/NVMem.o
diff --git a/chip/g/flash_info.h b/chip/g/flash_info.h
index fae622c24b..dec14042a0 100644
--- a/chip/g/flash_info.h
+++ b/chip/g/flash_info.h
@@ -6,7 +6,33 @@
#ifndef __EC_CHIP_G_FLASH_INFO_H
#define __EC_CHIP_G_FLASH_INFO_H
-void flash_info_write_enable(void);
+#include <stddef.h>
+
+#include "signed_header.h"
+
+/*
+ * Info1 space available to the app firmware is split in four equal size
+ * areas, used as follows:
+ *
+ * Area 0 - RO rollback prevention
+ * Area 1 - RW rollback prevention
+ * Area 2 - Board specific stuff
+ * Area 3 - Crypto scratch
+ */
+#define INFO_AREA_SIZE (INFO_MAX * 4)
+#define INFO_TOTAL_SIZE (INFO_AREA_SIZE * 4)
+
+#define INFO_RO_MAP_OFFSET 0
+#define INFO_RO_MAP_SIZE INFO_AREA_SIZE
+
+#define INFO_RW_MAP_OFFSET (INFO_RO_MAP_OFFSET + INFO_RO_MAP_SIZE)
+#define INFO_RW_MAP_SIZE INFO_AREA_SIZE
+
+#define INFO_BOARD_SPACE_OFFSET (INFO_RW_MAP_OFFSET + INFO_RW_MAP_SIZE)
+
+int flash_info_read_enable(uint32_t offset, size_t size);
+/* This in fact enables both read and write. */
+int flash_info_write_enable(uint32_t offset, size_t size);
void flash_info_write_disable(void);
int flash_info_physical_write(int byte_offset, int num_bytes, const char *data);
int flash_physical_info_read_word(int byte_offset, uint32_t *dst);
diff --git a/chip/g/signed_header.h b/chip/g/signed_header.h
index c4e6726c40..cafe858718 100644
--- a/chip/g/signed_header.h
+++ b/chip/g/signed_header.h
@@ -14,6 +14,9 @@
#define INFO_MAX 128 /* baked in rom! */
#define INFO_IGNORE 0xaa3c55c3 /* baked in rom! */
+/* Default value for _pad[] words */
+#define SIGNED_HEADER_PADDING 0x33333333
+
struct SignedHeader {
uint32_t magic; /* -1 (thanks, boot_sys!) */
uint32_t signature[96];
@@ -42,8 +45,18 @@ struct SignedHeader {
uint32_t err_response_;
/* action to take when expectation is violated */
uint32_t expect_response_;
- uint32_t _pad[256 - 1 - 96 - 1 - 7 - 1 - 96 -
- 5*1 - 4 - 4 - 9*1 - 2 - 1];
+ /*
+ * Padding to bring the total structure size to 1K. Note: First 17
+ * words of _pad[] may be used by a second FIPS-compliant signature,
+ * so don't put anything there.
+ */
+ uint32_t _pad[24];
+ /* Board ID type, mask, flags (stored ^SIGNED_HEADER_PADDING) */
+ uint32_t board_id_type;
+ uint32_t board_id_type_mask;
+ uint32_t board_id_flags;
+ uint32_t dev_id0_; /* node id, if locked */
+ uint32_t dev_id1_;
uint32_t fuses_chk_; /* top 32 bit of expected fuses hash */
uint32_t info_chk_; /* top 32 bit of expected info hash */
};
diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h
index c6a04f17f2..4861457d36 100644
--- a/include/tpm_vendor_cmds.h
+++ b/include/tpm_vendor_cmds.h
@@ -38,6 +38,8 @@ enum vendor_cmd_cc {
VENDOR_CC_REPORT_TPM_STATE = 23,
VENDOR_CC_TURN_UPDATE_ON = 24,
+ VENDOR_CC_GET_BOARD_ID = 25,
+ VENDOR_CC_SET_BOARD_ID = 26,
LAST_VENDOR_COMMAND = 65535,
};
@@ -54,6 +56,8 @@ enum vendor_cmd_rc {
/* Our TPMv2 vendor-specific response codes. */
VENDOR_RC_SUCCESS = 0,
VENDOR_RC_BOGUS_ARGS = 1,
+ VENDOR_RC_READ_FLASH_FAIL = 2,
+ VENDOR_RC_WRITE_FLASH_FAIL = 3,
/* Only 7 bits available; max is 127 */
VENDOR_RC_NO_SUCH_COMMAND = 127,
};