summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/sandbox.c124
-rw-r--r--drivers/tpm/Makefile1
-rw-r--r--drivers/tpm/tpm_tis_sandbox.c260
4 files changed, 386 insertions, 0 deletions
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 4e94378..8697da4 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -18,5 +18,6 @@ obj-$(CONFIG_SATA_DWC) += sata_dwc.o
obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o
obj-$(CONFIG_SATA_SIL) += sata_sil.o
obj-$(CONFIG_IDE_SIL680) += sil680.o
+obj-$(CONFIG_SANDBOX) += sandbox.o
obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o
obj-$(CONFIG_SYSTEMACE) += systemace.o
diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c
new file mode 100644
index 0000000..73f4c4a
--- /dev/null
+++ b/drivers/block/sandbox.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013 Henrik Nordstrom <henrik@henriknordstrom.net>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <part.h>
+#include <os.h>
+#include <malloc.h>
+#include <sandboxblockdev.h>
+#include <asm/errno.h>
+
+static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES];
+
+static struct host_block_dev *find_host_device(int dev)
+{
+ if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES)
+ return &host_devices[dev];
+
+ return NULL;
+}
+
+static unsigned long host_block_read(int dev, unsigned long start,
+ lbaint_t blkcnt, void *buffer)
+{
+ struct host_block_dev *host_dev = find_host_device(dev);
+
+ if (!host_dev)
+ return -1;
+ if (os_lseek(host_dev->fd,
+ start * host_dev->blk_dev.blksz,
+ OS_SEEK_SET) == -1) {
+ printf("ERROR: Invalid position\n");
+ return -1;
+ }
+ ssize_t len = os_read(host_dev->fd, buffer,
+ blkcnt * host_dev->blk_dev.blksz);
+ if (len >= 0)
+ return len / host_dev->blk_dev.blksz;
+ return -1;
+}
+
+static unsigned long host_block_write(int dev, unsigned long start,
+ lbaint_t blkcnt, const void *buffer)
+{
+ struct host_block_dev *host_dev = find_host_device(dev);
+ if (os_lseek(host_dev->fd,
+ start * host_dev->blk_dev.blksz,
+ OS_SEEK_SET) == -1) {
+ printf("ERROR: Invalid position\n");
+ return -1;
+ }
+ ssize_t len = os_write(host_dev->fd, buffer, blkcnt *
+ host_dev->blk_dev.blksz);
+ if (len >= 0)
+ return len / host_dev->blk_dev.blksz;
+ return -1;
+}
+
+int host_dev_bind(int dev, char *filename)
+{
+ struct host_block_dev *host_dev = find_host_device(dev);
+
+ if (!host_dev)
+ return -1;
+ if (host_dev->blk_dev.priv) {
+ os_close(host_dev->fd);
+ host_dev->blk_dev.priv = NULL;
+ }
+ if (host_dev->filename)
+ free(host_dev->filename);
+ if (filename && *filename) {
+ host_dev->filename = strdup(filename);
+ } else {
+ host_dev->filename = NULL;
+ return 0;
+ }
+
+ host_dev->fd = os_open(host_dev->filename, OS_O_RDWR);
+ if (host_dev->fd == -1) {
+ printf("Failed to access host backing file '%s'\n",
+ host_dev->filename);
+ return 1;
+ }
+
+ block_dev_desc_t *blk_dev = &host_dev->blk_dev;
+ blk_dev->if_type = IF_TYPE_HOST;
+ blk_dev->priv = host_dev;
+ blk_dev->blksz = 512;
+ blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz;
+ blk_dev->block_read = host_block_read;
+ blk_dev->block_write = host_block_write;
+ blk_dev->dev = dev;
+ blk_dev->part_type = PART_TYPE_UNKNOWN;
+ init_part(blk_dev);
+
+ return 0;
+}
+
+int host_get_dev_err(int dev, block_dev_desc_t **blk_devp)
+{
+ struct host_block_dev *host_dev = find_host_device(dev);
+
+ if (!host_dev)
+ return -ENODEV;
+
+ if (!host_dev->blk_dev.priv)
+ return -ENOENT;
+
+ *blk_devp = &host_dev->blk_dev;
+ return 0;
+}
+
+block_dev_desc_t *host_get_dev(int dev)
+{
+ block_dev_desc_t *blk_dev;
+
+ if (host_get_dev_err(dev, &blk_dev))
+ return NULL;
+
+ return blk_dev;
+}
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
index 2f2353f..150570e 100644
--- a/drivers/tpm/Makefile
+++ b/drivers/tpm/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
obj-$(CONFIG_TPM_TIS_I2C) += tpm.o
obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o
obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
+obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c
new file mode 100644
index 0000000..ed4b039
--- /dev/null
+++ b/drivers/tpm/tpm_tis_sandbox.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/state.h>
+#include <asm/unaligned.h>
+#include <linux/crc8.h>
+
+/* TPM NVRAM location indices. */
+#define FIRMWARE_NV_INDEX 0x1007
+#define KERNEL_NV_INDEX 0x1008
+
+#define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60
+
+/* Kernel TPM space - KERNEL_NV_INDEX, locked with physical presence */
+#define ROLLBACK_SPACE_KERNEL_VERSION 2
+#define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */
+
+struct rollback_space_kernel {
+ /* Struct version, for backwards compatibility */
+ uint8_t struct_version;
+ /* Unique ID to detect space redefinition */
+ uint32_t uid;
+ /* Kernel versions */
+ uint32_t kernel_versions;
+ /* Reserved for future expansion */
+ uint8_t reserved[3];
+ /* Checksum (v2 and later only) */
+ uint8_t crc8;
+} __packed rollback_space_kernel;
+
+/*
+ * These numbers derive from adding the sizes of command fields as shown in
+ * the TPM commands manual.
+ */
+#define TPM_REQUEST_HEADER_LENGTH 10
+#define TPM_RESPONSE_HEADER_LENGTH 10
+
+/* These are the different non-volatile spaces that we emulate */
+enum {
+ NV_GLOBAL_LOCK,
+ NV_SEQ_FIRMWARE,
+ NV_SEQ_KERNEL,
+ NV_SEQ_COUNT,
+};
+
+/* Size of each non-volatile space */
+#define NV_DATA_SIZE 0x20
+
+/*
+ * Information about our TPM emulation. This is preserved in the sandbox
+ * state file if enabled.
+ */
+static struct tpm_state {
+ uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE];
+} state;
+
+/**
+ * sandbox_tpm_read_state() - read the sandbox EC state from the state file
+ *
+ * If data is available, then blob and node will provide access to it. If
+ * not this function sets up an empty TPM.
+ *
+ * @blob: Pointer to device tree blob, or NULL if no data to read
+ * @node: Node offset to read from
+ */
+static int sandbox_tpm_read_state(const void *blob, int node)
+{
+ const char *prop;
+ int len;
+ int i;
+
+ if (!blob)
+ return 0;
+
+ for (i = 0; i < NV_SEQ_COUNT; i++) {
+ char prop_name[20];
+
+ sprintf(prop_name, "nvdata%d", i);
+ prop = fdt_getprop(blob, node, prop_name, &len);
+ if (prop && len == NV_DATA_SIZE)
+ memcpy(state.nvdata[i], prop, NV_DATA_SIZE);
+ }
+
+ return 0;
+}
+
+/**
+ * cros_ec_write_state() - Write out our state to the state file
+ *
+ * The caller will ensure that there is a node ready for the state. The node
+ * may already contain the old state, in which case it is overridden.
+ *
+ * @blob: Device tree blob holding state
+ * @node: Node to write our state into
+ */
+static int sandbox_tpm_write_state(void *blob, int node)
+{
+ int i;
+
+ /*
+ * We are guaranteed enough space to write basic properties.
+ * We could use fdt_add_subnode() to put each set of data in its
+ * own node - perhaps useful if we add access informaiton to each.
+ */
+ for (i = 0; i < NV_SEQ_COUNT; i++) {
+ char prop_name[20];
+
+ sprintf(prop_name, "nvdata%d", i);
+ fdt_setprop(blob, node, prop_name, state.nvdata[i],
+ NV_DATA_SIZE);
+ }
+
+ return 0;
+}
+
+SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state,
+ sandbox_tpm_write_state);
+
+static int index_to_seq(uint32_t index)
+{
+ switch (index) {
+ case FIRMWARE_NV_INDEX:
+ return NV_SEQ_FIRMWARE;
+ case KERNEL_NV_INDEX:
+ return NV_SEQ_KERNEL;
+ case 0:
+ return NV_GLOBAL_LOCK;
+ }
+
+ printf("Invalid nv index %#x\n", index);
+ return -1;
+}
+
+int tis_sendrecv(const u8 *sendbuf, size_t send_size,
+ u8 *recvbuf, size_t *recv_len)
+{
+ struct tpm_state *tpm = &state;
+ uint32_t code, index, length, type;
+ uint8_t *data;
+ int seq;
+
+ code = get_unaligned_be32(sendbuf + sizeof(uint16_t) +
+ sizeof(uint32_t));
+ printf("tpm: %zd bytes, recv_len %zd, cmd = %x\n", send_size,
+ *recv_len, code);
+ print_buffer(0, sendbuf, 1, send_size, 0);
+ switch (code) {
+ case 0x65: /* get flags */
+ type = get_unaligned_be32(sendbuf + 14);
+ switch (type) {
+ case 4:
+ index = get_unaligned_be32(sendbuf + 18);
+ printf("Get flags index %#02x\n", index);
+ *recv_len = 22;
+ memset(recvbuf, '\0', *recv_len);
+ put_unaligned_be32(22, recvbuf +
+ TPM_RESPONSE_HEADER_LENGTH);
+ data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
+ sizeof(uint32_t);
+ switch (index) {
+ case FIRMWARE_NV_INDEX:
+ break;
+ case KERNEL_NV_INDEX:
+ /* TPM_NV_PER_PPWRITE */
+ put_unaligned_be32(1, data +
+ NV_DATA_PUBLIC_PERMISSIONS_OFFSET);
+ break;
+ }
+ break;
+ case 0x11: /* TPM_CAP_NV_INDEX */
+ index = get_unaligned_be32(sendbuf + 18);
+ printf("Get cap nv index %#02x\n", index);
+ put_unaligned_be32(22, recvbuf +
+ TPM_RESPONSE_HEADER_LENGTH);
+ break;
+ default:
+ printf(" ** Unknown 0x65 command type %#02x\n",
+ type);
+ return -1;
+ }
+ break;
+ case 0xcd: /* nvwrite */
+ index = get_unaligned_be32(sendbuf + 10);
+ length = get_unaligned_be32(sendbuf + 18);
+ seq = index_to_seq(index);
+ if (seq < 0)
+ return -1;
+ printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
+ memcpy(&tpm->nvdata[seq], sendbuf + 22, length);
+ *recv_len = 12;
+ memset(recvbuf, '\0', *recv_len);
+ break;
+ case 0xcf: /* nvread */
+ index = get_unaligned_be32(sendbuf + 10);
+ length = get_unaligned_be32(sendbuf + 18);
+ seq = index_to_seq(index);
+ if (seq < 0)
+ return -1;
+ printf("tpm: nvread index=%#02x, len=%#02x\n", index, length);
+ *recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
+ length;
+ memset(recvbuf, '\0', *recv_len);
+ put_unaligned_be32(length, recvbuf +
+ TPM_RESPONSE_HEADER_LENGTH);
+ if (seq == NV_SEQ_KERNEL) {
+ struct rollback_space_kernel rsk;
+
+ data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
+ sizeof(uint32_t);
+ rsk.struct_version = 2;
+ rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
+ rsk.kernel_versions = 0;
+ rsk.crc8 = crc8((unsigned char *)&rsk,
+ offsetof(struct rollback_space_kernel,
+ crc8));
+ memcpy(data, &rsk, sizeof(rsk));
+ } else {
+ memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
+ sizeof(uint32_t), &tpm->nvdata[seq], length);
+ }
+ break;
+ case 0x14: /* tpm extend */
+ case 0x15: /* pcr read */
+ case 0x5d: /* force clear */
+ case 0x6f: /* physical enable */
+ case 0x72: /* physical set deactivated */
+ case 0x99: /* startup */
+ case 0x4000000a: /* assert physical presence */
+ *recv_len = 12;
+ memset(recvbuf, '\0', *recv_len);
+ break;
+ default:
+ printf("Unknown tpm command %02x\n", code);
+ return -1;
+ }
+
+ return 0;
+}
+
+int tis_open(void)
+{
+ printf("%s\n", __func__);
+ return 0;
+}
+
+int tis_close(void)
+{
+ printf("%s\n", __func__);
+ return 0;
+}
+
+int tis_init(void)
+{
+ printf("%s\n", __func__);
+ return 0;
+}