diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/Makefile | 1 | ||||
-rw-r--r-- | drivers/block/sandbox.c | 124 | ||||
-rw-r--r-- | drivers/tpm/Makefile | 1 | ||||
-rw-r--r-- | drivers/tpm/tpm_tis_sandbox.c | 260 |
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; +} |