diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-05-18 13:18:31 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-05-18 13:42:15 +0300 |
commit | 437fd90c0250dee670290f9b714253671a990160 (patch) | |
tree | b871786c360704244a07411c69fb58da9ead4a06 /qemu/roms/seabios/src/hw/tpm_drivers.c | |
parent | 5bbd6fe9b8bab2a93e548c5a53b032d1939eec05 (diff) |
These changes are the raw update to qemu-2.6.
Collission happened in the following patches:
migration: do cleanup operation after completion(738df5b9)
Bug fix.(1750c932f86)
kvmclock: add a new function to update env->tsc.(b52baab2)
The code provided by the patches was already in the upstreamed
version.
Change-Id: I3cc11841a6a76ae20887b2e245710199e1ea7f9a
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'qemu/roms/seabios/src/hw/tpm_drivers.c')
-rw-r--r-- | qemu/roms/seabios/src/hw/tpm_drivers.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/qemu/roms/seabios/src/hw/tpm_drivers.c b/qemu/roms/seabios/src/hw/tpm_drivers.c new file mode 100644 index 000000000..444eac39b --- /dev/null +++ b/qemu/roms/seabios/src/hw/tpm_drivers.c @@ -0,0 +1,291 @@ +// Implementation of a TPM driver for the TPM TIS interface +// +// Copyright (C) 2006-2011 IBM Corporation +// +// Authors: +// Stefan Berger <stefanb@linux.vnet.ibm.com> +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "config.h" // CONFIG_TPM_TIS_SHA1THRESHOLD +#include "string.h" // memcpy +#include "util.h" // msleep +#include "x86.h" // readl +#include "hw/tpm_drivers.h" // struct tpm_driver +#include "tcgbios.h" // TCG_* + +static const u32 tis_default_timeouts[4] = { + TIS_DEFAULT_TIMEOUT_A, + TIS_DEFAULT_TIMEOUT_B, + TIS_DEFAULT_TIMEOUT_C, + TIS_DEFAULT_TIMEOUT_D, +}; + +static const u32 tpm_default_durations[3] = { + TPM_DEFAULT_DURATION_SHORT, + TPM_DEFAULT_DURATION_MEDIUM, + TPM_DEFAULT_DURATION_LONG, +}; + +/* determined values */ +static u32 tpm_default_dur[3]; +static u32 tpm_default_to[4]; + + +/* if device is not there, return '0', '1' otherwise */ +static u32 tis_probe(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID)); + + if ((didvid != 0) && (didvid != 0xffffffff)) + rc = 1; + + return rc; +} + +static u32 tis_init(void) +{ + if (!CONFIG_TCGBIOS) + return 1; + + writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0); + + if (tpm_drivers[TIS_DRIVER_IDX].durations == NULL) { + u32 *durations = tpm_default_dur; + memcpy(durations, tpm_default_durations, + sizeof(tpm_default_durations)); + tpm_drivers[TIS_DRIVER_IDX].durations = durations; + } + + if (tpm_drivers[TIS_DRIVER_IDX].timeouts == NULL) { + u32 *timeouts = tpm_default_to; + memcpy(timeouts, tis_default_timeouts, + sizeof(tis_default_timeouts)); + tpm_drivers[TIS_DRIVER_IDX].timeouts = timeouts; + } + + return 1; +} + + +static void set_timeouts(u32 timeouts[4], u32 durations[3]) +{ + if (!CONFIG_TCGBIOS) + return; + + u32 *tos = tpm_drivers[TIS_DRIVER_IDX].timeouts; + u32 *dus = tpm_drivers[TIS_DRIVER_IDX].durations; + + if (tos && tos != tis_default_timeouts && timeouts) + memcpy(tos, timeouts, 4 * sizeof(u32)); + if (dus && dus != tpm_default_durations && durations) + memcpy(dus, durations, 3 * sizeof(u32)); +} + + +static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 1; + + while (time > 0) { + u8 sts = readb(TIS_REG(locty, TIS_REG_STS)); + if ((sts & mask) == expect) { + rc = 0; + break; + } + msleep(1); + time--; + } + return rc; +} + +static u32 tis_activate(u8 locty) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u8 acc; + int l; + u32 timeout_a = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_A]; + + if (!(readb(TIS_REG(locty, TIS_REG_ACCESS)) & + TIS_ACCESS_ACTIVE_LOCALITY)) { + /* release locality in use top-downwards */ + for (l = 4; l >= 0; l--) + writeb(TIS_REG(l, TIS_REG_ACCESS), + TIS_ACCESS_ACTIVE_LOCALITY); + } + + /* request access to locality */ + writeb(TIS_REG(locty, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE); + + acc = readb(TIS_REG(locty, TIS_REG_ACCESS)); + if ((acc & TIS_ACCESS_ACTIVE_LOCALITY)) { + writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY); + rc = tis_wait_sts(locty, timeout_a, + TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY); + } + + return rc; +} + +static u32 tis_find_active_locality(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u8 locty; + + for (locty = 0; locty <= 4; locty++) { + if ((readb(TIS_REG(locty, TIS_REG_ACCESS)) & + TIS_ACCESS_ACTIVE_LOCALITY)) + return locty; + } + + tis_activate(0); + + return 0; +} + +static u32 tis_ready(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u8 locty = tis_find_active_locality(); + u32 timeout_b = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_B]; + + writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY); + rc = tis_wait_sts(locty, timeout_b, + TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY); + + return rc; +} + +static u32 tis_senddata(const u8 *const data, u32 len) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u32 offset = 0; + u32 end = 0; + u16 burst = 0; + u32 ctr = 0; + u8 locty = tis_find_active_locality(); + u32 timeout_d = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_D]; + + do { + while (burst == 0 && ctr < timeout_d) { + burst = readl(TIS_REG(locty, TIS_REG_STS)) >> 8; + if (burst == 0) { + msleep(1); + ctr++; + } + } + + if (burst == 0) { + rc = TCG_RESPONSE_TIMEOUT; + break; + } + + while (1) { + writeb(TIS_REG(locty, TIS_REG_DATA_FIFO), data[offset++]); + burst--; + + if (burst == 0 || offset == len) + break; + } + + if (offset == len) + end = 1; + } while (end == 0); + + return rc; +} + +static u32 tis_readresp(u8 *buffer, u32 *len) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u32 offset = 0; + u32 sts; + u8 locty = tis_find_active_locality(); + + while (offset < *len) { + buffer[offset] = readb(TIS_REG(locty, TIS_REG_DATA_FIFO)); + offset++; + sts = readb(TIS_REG(locty, TIS_REG_STS)); + /* data left ? */ + if ((sts & TIS_STS_DATA_AVAILABLE) == 0) + break; + } + + *len = offset; + + return rc; +} + + +static u32 tis_waitdatavalid(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u8 locty = tis_find_active_locality(); + u32 timeout_c = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C]; + + if (tis_wait_sts(locty, timeout_c, TIS_STS_VALID, TIS_STS_VALID) != 0) + rc = TCG_NO_RESPONSE; + + return rc; +} + +static u32 tis_waitrespready(enum tpmDurationType to_t) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u8 locty = tis_find_active_locality(); + u32 timeout = tpm_drivers[TIS_DRIVER_IDX].durations[to_t]; + + writeb(TIS_REG(locty ,TIS_REG_STS), TIS_STS_TPM_GO); + + if (tis_wait_sts(locty, timeout, + TIS_STS_DATA_AVAILABLE, TIS_STS_DATA_AVAILABLE) != 0) + rc = TCG_NO_RESPONSE; + + return rc; +} + + +struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = { + [TIS_DRIVER_IDX] = + { + .timeouts = NULL, + .durations = NULL, + .set_timeouts = set_timeouts, + .probe = tis_probe, + .init = tis_init, + .activate = tis_activate, + .ready = tis_ready, + .senddata = tis_senddata, + .readresp = tis_readresp, + .waitdatavalid = tis_waitdatavalid, + .waitrespready = tis_waitrespready, + .sha1threshold = 100 * 1024, + }, +}; |