Commit 74673fc5 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull TPM updates from James Morris:

 - Support for partial reads of /dev/tpm0.

 - Clean up for TPM 1.x code: move the commands to tpm1-cmd.c and make
   everything to use the same data structure for building TPM commands
   i.e. struct tpm_buf.

* 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (25 commits)
  tpm: add support for partial reads
  tpm: tpm_ibmvtpm: fix kdoc warnings
  tpm: fix kdoc for tpm2_flush_context_cmd()
  tpm: tpm_try_transmit() refactor error flow.
  tpm: use u32 instead of int for PCR index
  tpm1: reimplement tpm1_continue_selftest() using tpm_buf
  tpm1: reimplement SAVESTATE using tpm_buf
  tpm1: rename tpm1_pcr_read_dev to tpm1_pcr_read()
  tpm1: implement tpm1_pcr_read_dev() using tpm_buf structure
  tpm: tpm1: rewrite tpm1_get_random() using tpm_buf structure
  tpm: tpm-space.c remove unneeded semicolon
  tpm: tpm-interface.c drop unused macros
  tpm: add tpm_auto_startup() into tpm-interface.c
  tpm: factor out tpm_startup function
  tpm: factor out tpm 1.x pm suspend flow into tpm1-cmd.c
  tpm: move tpm 1.x selftest code from tpm-interface.c tpm1-cmd.c
  tpm: factor out tpm1_get_random into tpm1-cmd.c
  tpm: move tpm_getcap to tpm1-cmd.c
  tpm: move tpm1_pcr_extend to tpm1-cmd.c
  tpm: factor out tpm_get_timeouts()
  ...
parents 19f2e267 0db51ef2
...@@ -3,9 +3,19 @@ ...@@ -3,9 +3,19 @@
# Makefile for the kernel tpm device drivers. # Makefile for the kernel tpm device drivers.
# #
obj-$(CONFIG_TCG_TPM) += tpm.o obj-$(CONFIG_TCG_TPM) += tpm.o
tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ tpm-y := tpm-chip.o
tpm-dev-common.o tpmrm-dev.o eventlog/common.o eventlog/tpm1.o \ tpm-y += tpm-dev-common.o
eventlog/tpm2.o tpm2-space.o tpm-y += tpm-dev.o
tpm-y += tpm-interface.o
tpm-y += tpm1-cmd.o
tpm-y += tpm2-cmd.o
tpm-y += tpmrm-dev.o
tpm-y += tpm2-space.o
tpm-y += tpm-sysfs.o
tpm-y += eventlog/common.o
tpm-y += eventlog/tpm1.o
tpm-y += eventlog/tpm2.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o eventlog/acpi.o tpm-$(CONFIG_ACPI) += tpm_ppi.o eventlog/acpi.o
tpm-$(CONFIG_EFI) += eventlog/efi.o tpm-$(CONFIG_EFI) += eventlog/efi.o
tpm-$(CONFIG_OF) += eventlog/of.o tpm-$(CONFIG_OF) += eventlog/of.o
......
...@@ -649,7 +649,7 @@ int st33zp24_pm_resume(struct device *dev) ...@@ -649,7 +649,7 @@ int st33zp24_pm_resume(struct device *dev)
} else { } else {
ret = tpm_pm_resume(dev); ret = tpm_pm_resume(dev);
if (!ret) if (!ret)
tpm_do_selftest(chip); tpm1_do_selftest(chip);
} }
return ret; return ret;
} /* st33zp24_pm_resume() */ } /* st33zp24_pm_resume() */
......
...@@ -451,14 +451,9 @@ int tpm_chip_register(struct tpm_chip *chip) ...@@ -451,14 +451,9 @@ int tpm_chip_register(struct tpm_chip *chip)
{ {
int rc; int rc;
if (chip->ops->flags & TPM_OPS_AUTO_STARTUP) { rc = tpm_auto_startup(chip);
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (rc)
rc = tpm2_auto_startup(chip); return rc;
else
rc = tpm1_auto_startup(chip);
if (rc)
return rc;
}
tpm_sysfs_add_device(chip); tpm_sysfs_add_device(chip);
......
...@@ -40,7 +40,7 @@ static void tpm_async_work(struct work_struct *work) ...@@ -40,7 +40,7 @@ static void tpm_async_work(struct work_struct *work)
tpm_put_ops(priv->chip); tpm_put_ops(priv->chip);
if (ret > 0) { if (ret > 0) {
priv->data_pending = ret; priv->response_length = ret;
mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
} }
mutex_unlock(&priv->buffer_mutex); mutex_unlock(&priv->buffer_mutex);
...@@ -63,7 +63,8 @@ static void tpm_timeout_work(struct work_struct *work) ...@@ -63,7 +63,8 @@ static void tpm_timeout_work(struct work_struct *work)
timeout_work); timeout_work);
mutex_lock(&priv->buffer_mutex); mutex_lock(&priv->buffer_mutex);
priv->data_pending = 0; priv->response_read = true;
priv->response_length = 0;
memset(priv->data_buffer, 0, sizeof(priv->data_buffer)); memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
mutex_unlock(&priv->buffer_mutex); mutex_unlock(&priv->buffer_mutex);
wake_up_interruptible(&priv->async_wait); wake_up_interruptible(&priv->async_wait);
...@@ -74,6 +75,7 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip, ...@@ -74,6 +75,7 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip,
{ {
priv->chip = chip; priv->chip = chip;
priv->space = space; priv->space = space;
priv->response_read = true;
mutex_init(&priv->buffer_mutex); mutex_init(&priv->buffer_mutex);
timer_setup(&priv->user_read_timer, user_reader_timeout, 0); timer_setup(&priv->user_read_timer, user_reader_timeout, 0);
...@@ -90,22 +92,35 @@ ssize_t tpm_common_read(struct file *file, char __user *buf, ...@@ -90,22 +92,35 @@ ssize_t tpm_common_read(struct file *file, char __user *buf,
ssize_t ret_size = 0; ssize_t ret_size = 0;
int rc; int rc;
del_singleshot_timer_sync(&priv->user_read_timer);
flush_work(&priv->timeout_work);
mutex_lock(&priv->buffer_mutex); mutex_lock(&priv->buffer_mutex);
if (priv->data_pending) { if (priv->response_length) {
ret_size = min_t(ssize_t, size, priv->data_pending); priv->response_read = true;
if (ret_size > 0) {
rc = copy_to_user(buf, priv->data_buffer, ret_size); ret_size = min_t(ssize_t, size, priv->response_length);
memset(priv->data_buffer, 0, priv->data_pending); if (!ret_size) {
if (rc) priv->response_length = 0;
ret_size = -EFAULT; goto out;
} }
priv->data_pending = 0; rc = copy_to_user(buf, priv->data_buffer + *off, ret_size);
if (rc) {
memset(priv->data_buffer, 0, TPM_BUFSIZE);
priv->response_length = 0;
ret_size = -EFAULT;
} else {
memset(priv->data_buffer + *off, 0, ret_size);
priv->response_length -= ret_size;
*off += ret_size;
}
} }
out:
if (!priv->response_length) {
*off = 0;
del_singleshot_timer_sync(&priv->user_read_timer);
flush_work(&priv->timeout_work);
}
mutex_unlock(&priv->buffer_mutex); mutex_unlock(&priv->buffer_mutex);
return ret_size; return ret_size;
} }
...@@ -125,7 +140,8 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, ...@@ -125,7 +140,8 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
* tpm_read or a user_read_timer timeout. This also prevents split * tpm_read or a user_read_timer timeout. This also prevents split
* buffered writes from blocking here. * buffered writes from blocking here.
*/ */
if (priv->data_pending != 0 || priv->command_enqueued) { if ((!priv->response_read && priv->response_length) ||
priv->command_enqueued) {
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
...@@ -150,6 +166,10 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, ...@@ -150,6 +166,10 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
goto out; goto out;
} }
priv->response_length = 0;
priv->response_read = false;
*off = 0;
/* /*
* If in nonblocking mode schedule an async job to send * If in nonblocking mode schedule an async job to send
* the command return the size. * the command return the size.
...@@ -168,7 +188,7 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, ...@@ -168,7 +188,7 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
tpm_put_ops(priv->chip); tpm_put_ops(priv->chip);
if (ret > 0) { if (ret > 0) {
priv->data_pending = ret; priv->response_length = ret;
mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
ret = size; ret = size;
} }
...@@ -184,7 +204,7 @@ __poll_t tpm_common_poll(struct file *file, poll_table *wait) ...@@ -184,7 +204,7 @@ __poll_t tpm_common_poll(struct file *file, poll_table *wait)
poll_wait(file, &priv->async_wait, wait); poll_wait(file, &priv->async_wait, wait);
if (priv->data_pending) if (!priv->response_read || priv->response_length)
mask = EPOLLIN | EPOLLRDNORM; mask = EPOLLIN | EPOLLRDNORM;
else else
mask = EPOLLOUT | EPOLLWRNORM; mask = EPOLLOUT | EPOLLWRNORM;
...@@ -201,7 +221,7 @@ void tpm_common_release(struct file *file, struct file_priv *priv) ...@@ -201,7 +221,7 @@ void tpm_common_release(struct file *file, struct file_priv *priv)
del_singleshot_timer_sync(&priv->user_read_timer); del_singleshot_timer_sync(&priv->user_read_timer);
flush_work(&priv->timeout_work); flush_work(&priv->timeout_work);
file->private_data = NULL; file->private_data = NULL;
priv->data_pending = 0; priv->response_length = 0;
} }
int __init tpm_dev_common_init(void) int __init tpm_dev_common_init(void)
......
...@@ -9,14 +9,13 @@ struct file_priv { ...@@ -9,14 +9,13 @@ struct file_priv {
struct tpm_chip *chip; struct tpm_chip *chip;
struct tpm_space *space; struct tpm_space *space;
/* Holds the amount of data passed or an error code from async op */
ssize_t data_pending;
struct mutex buffer_mutex; struct mutex buffer_mutex;
struct timer_list user_read_timer; /* user needs to claim result */ struct timer_list user_read_timer; /* user needs to claim result */
struct work_struct timeout_work; struct work_struct timeout_work;
struct work_struct async_work; struct work_struct async_work;
wait_queue_head_t async_wait; wait_queue_head_t async_wait;
size_t response_length;
bool response_read;
bool command_enqueued; bool command_enqueued;
u8 data_buffer[TPM_BUFSIZE]; u8 data_buffer[TPM_BUFSIZE];
......
...@@ -33,297 +33,32 @@ ...@@ -33,297 +33,32 @@
#include "tpm.h" #include "tpm.h"
#define TPM_MAX_ORDINAL 243
#define TSC_MAX_ORDINAL 12
#define TPM_PROTECTED_COMMAND 0x00
#define TPM_CONNECTION_COMMAND 0x40
/* /*
* Bug workaround - some TPM's don't flush the most * Bug workaround - some TPM's don't flush the most
* recently changed pcr on suspend, so force the flush * recently changed pcr on suspend, so force the flush
* with an extend to the selected _unused_ non-volatile pcr. * with an extend to the selected _unused_ non-volatile pcr.
*/ */
static int tpm_suspend_pcr; static u32 tpm_suspend_pcr;
module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644); module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
MODULE_PARM_DESC(suspend_pcr, MODULE_PARM_DESC(suspend_pcr,
"PCR to use for dummy writes to facilitate flush on suspend."); "PCR to use for dummy writes to facilitate flush on suspend.");
/* /**
* Array with one entry per ordinal defining the maximum amount * tpm_calc_ordinal_duration() - calculate the maximum command duration
* of time the chip could take to return the result. The ordinal * @chip: TPM chip to use.
* designation of short, medium or long is defined in a table in * @ordinal: TPM command ordinal.
* TCG Specification TPM Main Part 2 TPM Structures Section 17. The *
* values of the SHORT, MEDIUM, and LONG durations are retrieved * The function returns the maximum amount of time the chip could take
* from the chip during initialization with a call to tpm_get_timeouts. * to return the result for a particular ordinal in jiffies.
*/ *
static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { * Return: A maximal duration time for an ordinal in jiffies.
TPM_UNDEFINED, /* 0 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 5 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 10 */
TPM_SHORT,
TPM_MEDIUM,
TPM_LONG,
TPM_LONG,
TPM_MEDIUM, /* 15 */
TPM_SHORT,
TPM_SHORT,
TPM_MEDIUM,
TPM_LONG,
TPM_SHORT, /* 20 */
TPM_SHORT,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_SHORT, /* 25 */
TPM_SHORT,
TPM_MEDIUM,
TPM_SHORT,
TPM_SHORT,
TPM_MEDIUM, /* 30 */
TPM_LONG,
TPM_MEDIUM,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT, /* 35 */
TPM_MEDIUM,
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_MEDIUM, /* 40 */
TPM_LONG,
TPM_MEDIUM,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT, /* 45 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_LONG,
TPM_MEDIUM, /* 50 */
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 55 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_MEDIUM, /* 60 */
TPM_MEDIUM,
TPM_MEDIUM,
TPM_SHORT,
TPM_SHORT,
TPM_MEDIUM, /* 65 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 70 */
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 75 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_LONG, /* 80 */
TPM_UNDEFINED,
TPM_MEDIUM,
TPM_LONG,
TPM_SHORT,
TPM_UNDEFINED, /* 85 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 90 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED, /* 95 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_MEDIUM, /* 100 */
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 105 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 110 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT, /* 115 */
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_LONG, /* 120 */
TPM_LONG,
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_SHORT,
TPM_SHORT, /* 125 */
TPM_SHORT,
TPM_LONG,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT, /* 130 */
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_SHORT,
TPM_MEDIUM,
TPM_UNDEFINED, /* 135 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 140 */
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 145 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 150 */
TPM_MEDIUM,
TPM_MEDIUM,
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED, /* 155 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 160 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 165 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_LONG, /* 170 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 175 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_MEDIUM, /* 180 */
TPM_SHORT,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_MEDIUM, /* 185 */
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 190 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 195 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 200 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT,
TPM_SHORT, /* 205 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_MEDIUM, /* 210 */
TPM_UNDEFINED,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_UNDEFINED, /* 215 */
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT,
TPM_SHORT, /* 220 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED, /* 225 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 230 */
TPM_LONG,
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 235 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 240 */
TPM_UNDEFINED,
TPM_MEDIUM,
};
/*
* Returns max number of jiffies to wait
*/ */
unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
u32 ordinal)
{ {
int duration_idx = TPM_UNDEFINED; if (chip->flags & TPM_CHIP_FLAG_TPM2)
int duration = 0; return tpm2_calc_ordinal_duration(chip, ordinal);
/*
* We only have a duration table for protected commands, where the upper
* 16 bits are 0. For the few other ordinals the fallback will be used.
*/
if (ordinal < TPM_MAX_ORDINAL)
duration_idx = tpm_ordinal_duration[ordinal];
if (duration_idx != TPM_UNDEFINED)
duration = chip->duration[duration_idx];
if (duration <= 0)
return 2 * 60 * HZ;
else else
return duration; return tpm1_calc_ordinal_duration(chip, ordinal);
} }
EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
...@@ -477,13 +212,15 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, ...@@ -477,13 +212,15 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
if (need_locality) { if (need_locality) {
rc = tpm_request_locality(chip, flags); rc = tpm_request_locality(chip, flags);
if (rc < 0) if (rc < 0) {
goto out_no_locality; need_locality = false;
goto out_locality;
}
} }
rc = tpm_cmd_ready(chip, flags); rc = tpm_cmd_ready(chip, flags);
if (rc) if (rc)
goto out; goto out_locality;
rc = tpm2_prepare_space(chip, space, ordinal, buf); rc = tpm2_prepare_space(chip, space, ordinal, buf);
if (rc) if (rc)
...@@ -500,10 +237,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, ...@@ -500,10 +237,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
if (chip->flags & TPM_CHIP_FLAG_IRQ) if (chip->flags & TPM_CHIP_FLAG_IRQ)
goto out_recv; goto out_recv;
if (chip->flags & TPM_CHIP_FLAG_TPM2) stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
else
stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
do { do {
u8 status = chip->ops->status(chip); u8 status = chip->ops->status(chip);
if ((status & chip->ops->req_complete_mask) == if ((status & chip->ops->req_complete_mask) ==
...@@ -547,14 +281,13 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, ...@@ -547,14 +281,13 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc); dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc);
out: out:
rc = tpm_go_idle(chip, flags); /* may fail but do not override previous error value in rc */
if (rc) tpm_go_idle(chip, flags);
goto out;
out_locality:
if (need_locality) if (need_locality)
tpm_relinquish_locality(chip, flags); tpm_relinquish_locality(chip, flags);
out_no_locality:
if (chip->ops->clk_enable != NULL) if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, false); chip->ops->clk_enable(chip, false);
...@@ -677,277 +410,18 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, ...@@ -677,277 +410,18 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
} }
EXPORT_SYMBOL_GPL(tpm_transmit_cmd); EXPORT_SYMBOL_GPL(tpm_transmit_cmd);
#define TPM_ORD_STARTUP 153
#define TPM_ST_CLEAR 1
/**
* tpm_startup - turn on the TPM
* @chip: TPM chip to use
*
* Normally the firmware should start the TPM. This function is provided as a
* workaround if this does not happen. A legal case for this could be for
* example when a TPM emulator is used.
*
* Return: same as tpm_transmit_cmd()
*/
int tpm_startup(struct tpm_chip *chip)
{
struct tpm_buf buf;
int rc;
dev_info(&chip->dev, "starting up the TPM manually\n");
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
if (rc < 0)
return rc;
tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
} else {
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
if (rc < 0)
return rc;
tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
}
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
"attempting to start the TPM");
tpm_buf_destroy(&buf);
return rc;
}
#define TPM_DIGEST_SIZE 20
#define TPM_RET_CODE_IDX 6
#define TPM_INTERNAL_RESULT_SIZE 200
#define TPM_ORD_GET_CAP 101
#define TPM_ORD_GET_RANDOM 70
static const struct tpm_input_header tpm_getcap_header = {
.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(22),
.ordinal = cpu_to_be32(TPM_ORD_GET_CAP)
};
ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
if (rc)
return rc;
if (subcap_id == TPM_CAP_VERSION_1_1 ||
subcap_id == TPM_CAP_VERSION_1_2) {
tpm_buf_append_u32(&buf, subcap_id);
tpm_buf_append_u32(&buf, 0);
} else {
if (subcap_id == TPM_CAP_FLAG_PERM ||
subcap_id == TPM_CAP_FLAG_VOL)
tpm_buf_append_u32(&buf, TPM_CAP_FLAG);
else
tpm_buf_append_u32(&buf, TPM_CAP_PROP);
tpm_buf_append_u32(&buf, 4);
tpm_buf_append_u32(&buf, subcap_id);
}
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
min_cap_length, 0, desc);
if (!rc)
*cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
tpm_buf_destroy(&buf);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_getcap);
int tpm_get_timeouts(struct tpm_chip *chip) int tpm_get_timeouts(struct tpm_chip *chip)
{ {
cap_t cap;
unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4];
ssize_t rc;
if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS) if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS)
return 0; return 0;
if (chip->flags & TPM_CHIP_FLAG_TPM2) { if (chip->flags & TPM_CHIP_FLAG_TPM2)
/* Fixed timeouts for TPM2 */ return tpm2_get_timeouts(chip);
chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); else
chip->timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B); return tpm1_get_timeouts(chip);
chip->timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
chip->timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
chip->duration[TPM_SHORT] =
msecs_to_jiffies(TPM2_DURATION_SHORT);
chip->duration[TPM_MEDIUM] =
msecs_to_jiffies(TPM2_DURATION_MEDIUM);
chip->duration[TPM_LONG] =
msecs_to_jiffies(TPM2_DURATION_LONG);
chip->duration[TPM_LONG_LONG] =
msecs_to_jiffies(TPM2_DURATION_LONG_LONG);
chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS;
return 0;
}
rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL,
sizeof(cap.timeout));
if (rc == TPM_ERR_INVALID_POSTINIT) {
if (tpm_startup(chip))
return rc;
rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
"attempting to determine the timeouts",
sizeof(cap.timeout));
}
if (rc) {
dev_err(&chip->dev,
"A TPM error (%zd) occurred attempting to determine the timeouts\n",
rc);
return rc;
}
timeout_old[0] = jiffies_to_usecs(chip->timeout_a);
timeout_old[1] = jiffies_to_usecs(chip->timeout_b);
timeout_old[2] = jiffies_to_usecs(chip->timeout_c);
timeout_old[3] = jiffies_to_usecs(chip->timeout_d);
timeout_chip[0] = be32_to_cpu(cap.timeout.a);
timeout_chip[1] = be32_to_cpu(cap.timeout.b);
timeout_chip[2] = be32_to_cpu(cap.timeout.c);
timeout_chip[3] = be32_to_cpu(cap.timeout.d);
memcpy(timeout_eff, timeout_chip, sizeof(timeout_eff));
/*
* Provide ability for vendor overrides of timeout values in case
* of misreporting.
*/
if (chip->ops->update_timeouts != NULL)
chip->timeout_adjusted =
chip->ops->update_timeouts(chip, timeout_eff);
if (!chip->timeout_adjusted) {
/* Restore default if chip reported 0 */
int i;
for (i = 0; i < ARRAY_SIZE(timeout_eff); i++) {
if (timeout_eff[i])
continue;
timeout_eff[i] = timeout_old[i];
chip->timeout_adjusted = true;
}
if (timeout_eff[0] != 0 && timeout_eff[0] < 1000) {
/* timeouts in msec rather usec */
for (i = 0; i != ARRAY_SIZE(timeout_eff); i++)
timeout_eff[i] *= 1000;
chip->timeout_adjusted = true;
}
}
/* Report adjusted timeouts */
if (chip->timeout_adjusted) {
dev_info(&chip->dev,
HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
timeout_chip[0], timeout_eff[0],
timeout_chip[1], timeout_eff[1],
timeout_chip[2], timeout_eff[2],
timeout_chip[3], timeout_eff[3]);
}
chip->timeout_a = usecs_to_jiffies(timeout_eff[0]);
chip->timeout_b = usecs_to_jiffies(timeout_eff[1]);
chip->timeout_c = usecs_to_jiffies(timeout_eff[2]);
chip->timeout_d = usecs_to_jiffies(timeout_eff[3]);
rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap,
"attempting to determine the durations",
sizeof(cap.duration));
if (rc)
return rc;
chip->duration[TPM_SHORT] =
usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short));
chip->duration[TPM_MEDIUM] =
usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium));
chip->duration[TPM_LONG] =
usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_long));
chip->duration[TPM_LONG_LONG] = 0; /* not used under 1.2 */
/* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
* value wrong and apparently reports msecs rather than usecs. So we
* fix up the resulting too-small TPM_SHORT value to make things work.
* We also scale the TPM_MEDIUM and -_LONG values by 1000.
*/
if (chip->duration[TPM_SHORT] < (HZ / 100)) {
chip->duration[TPM_SHORT] = HZ;
chip->duration[TPM_MEDIUM] *= 1000;
chip->duration[TPM_LONG] *= 1000;
chip->duration_adjusted = true;
dev_info(&chip->dev, "Adjusting TPM timeout parameters.");
}
chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS;
return 0;
} }
EXPORT_SYMBOL_GPL(tpm_get_timeouts); EXPORT_SYMBOL_GPL(tpm_get_timeouts);
#define TPM_ORD_CONTINUE_SELFTEST 83
#define CONTINUE_SELFTEST_RESULT_SIZE 10
static const struct tpm_input_header continue_selftest_header = {
.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(10),
.ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST),
};
/**
* tpm_continue_selftest -- run TPM's selftest
* @chip: TPM chip to use
*
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
* a TPM error code.
*/
static int tpm_continue_selftest(struct tpm_chip *chip)
{
int rc;
struct tpm_cmd_t cmd;
cmd.header.in = continue_selftest_header;
rc = tpm_transmit_cmd(chip, NULL, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
0, 0, "continue selftest");
return rc;
}
#define TPM_ORDINAL_PCRREAD 21
#define READ_PCR_RESULT_SIZE 30
#define READ_PCR_RESULT_BODY_SIZE 20
static const struct tpm_input_header pcrread_header = {
.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(14),
.ordinal = cpu_to_be32(TPM_ORDINAL_PCRREAD)
};
int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
{
int rc;
struct tpm_cmd_t cmd;
cmd.header.in = pcrread_header;
cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
rc = tpm_transmit_cmd(chip, NULL, &cmd, READ_PCR_RESULT_SIZE,
READ_PCR_RESULT_BODY_SIZE, 0,
"attempting to read a pcr value");
if (rc == 0)
memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
TPM_DIGEST_SIZE);
return rc;
}
/** /**
* tpm_is_tpm2 - do we a have a TPM2 chip? * tpm_is_tpm2 - do we a have a TPM2 chip?
* @chip: a &struct tpm_chip instance, %NULL for the default chip * @chip: a &struct tpm_chip instance, %NULL for the default chip
...@@ -981,50 +455,24 @@ EXPORT_SYMBOL_GPL(tpm_is_tpm2); ...@@ -981,50 +455,24 @@ EXPORT_SYMBOL_GPL(tpm_is_tpm2);
* *
* Return: same as with tpm_transmit_cmd() * Return: same as with tpm_transmit_cmd()
*/ */
int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
{ {
int rc; int rc;
chip = tpm_find_get_ops(chip); chip = tpm_find_get_ops(chip);
if (!chip) if (!chip)
return -ENODEV; return -ENODEV;
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2)
rc = tpm2_pcr_read(chip, pcr_idx, res_buf); rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
else else
rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); rc = tpm1_pcr_read(chip, pcr_idx, res_buf);
tpm_put_ops(chip); tpm_put_ops(chip);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(tpm_pcr_read); EXPORT_SYMBOL_GPL(tpm_pcr_read);
#define TPM_ORD_PCR_EXTEND 20
#define EXTEND_PCR_RESULT_SIZE 34
#define EXTEND_PCR_RESULT_BODY_SIZE 20
static const struct tpm_input_header pcrextend_header = {
.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(34),
.ordinal = cpu_to_be32(TPM_ORD_PCR_EXTEND)
};
static int tpm1_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash,
char *log_msg)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
if (rc)
return rc;
tpm_buf_append_u32(&buf, pcr_idx);
tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, NULL, buf.data, EXTEND_PCR_RESULT_SIZE,
EXTEND_PCR_RESULT_BODY_SIZE, 0, log_msg);
tpm_buf_destroy(&buf);
return rc;
}
/** /**
* tpm_pcr_extend - extend a PCR value in SHA1 bank. * tpm_pcr_extend - extend a PCR value in SHA1 bank.
* @chip: a &struct tpm_chip instance, %NULL for the default chip * @chip: a &struct tpm_chip instance, %NULL for the default chip
...@@ -1037,7 +485,7 @@ static int tpm1_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash, ...@@ -1037,7 +485,7 @@ static int tpm1_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash,
* *
* Return: same as with tpm_transmit_cmd() * Return: same as with tpm_transmit_cmd()
*/ */
int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash)
{ {
int rc; int rc;
struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)]; struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)];
...@@ -1070,97 +518,6 @@ int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) ...@@ -1070,97 +518,6 @@ int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
} }
EXPORT_SYMBOL_GPL(tpm_pcr_extend); EXPORT_SYMBOL_GPL(tpm_pcr_extend);
/**
* tpm_do_selftest - have the TPM continue its selftest and wait until it
* can receive further commands
* @chip: TPM chip to use
*
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
* a TPM error code.
*/
int tpm_do_selftest(struct tpm_chip *chip)
{
int rc;
unsigned int loops;
unsigned int delay_msec = 100;
unsigned long duration;
u8 dummy[TPM_DIGEST_SIZE];
duration = tpm_calc_ordinal_duration(chip, TPM_ORD_CONTINUE_SELFTEST);
loops = jiffies_to_msecs(duration) / delay_msec;
rc = tpm_continue_selftest(chip);
if (rc == TPM_ERR_INVALID_POSTINIT) {
chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED;
dev_info(&chip->dev, "TPM not ready (%d)\n", rc);
}
/* This may fail if there was no TPM driver during a suspend/resume
* cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
*/
if (rc)
return rc;
do {
/* Attempt to read a PCR value */
rc = tpm_pcr_read_dev(chip, 0, dummy);
/* Some buggy TPMs will not respond to tpm_tis_ready() for
* around 300ms while the self test is ongoing, keep trying
* until the self test duration expires. */
if (rc == -ETIME) {
dev_info(
&chip->dev, HW_ERR
"TPM command timed out during continue self test");
tpm_msleep(delay_msec);
continue;
}
if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
dev_info(&chip->dev,
"TPM is disabled/deactivated (0x%X)\n", rc);
/* TPM is disabled and/or deactivated; driver can
* proceed and TPM does handle commands for
* suspend/resume correctly
*/
return 0;
}
if (rc != TPM_WARN_DOING_SELFTEST)
return rc;
tpm_msleep(delay_msec);
} while (--loops > 0);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_do_selftest);
/**
* tpm1_auto_startup - Perform the standard automatic TPM initialization
* sequence
* @chip: TPM chip to use
*
* Returns 0 on success, < 0 in case of fatal error.
*/
int tpm1_auto_startup(struct tpm_chip *chip)
{
int rc;
rc = tpm_get_timeouts(chip);
if (rc)
goto out;
rc = tpm_do_selftest(chip);
if (rc) {
dev_err(&chip->dev, "TPM self test failed\n");
goto out;
}
return rc;
out:
if (rc > 0)
rc = -ENODEV;
return rc;
}
/** /**
* tpm_send - send a TPM command * tpm_send - send a TPM command
* @chip: a &struct tpm_chip instance, %NULL for the default chip * @chip: a &struct tpm_chip instance, %NULL for the default chip
...@@ -1184,14 +541,20 @@ int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) ...@@ -1184,14 +541,20 @@ int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen)
} }
EXPORT_SYMBOL_GPL(tpm_send); EXPORT_SYMBOL_GPL(tpm_send);
#define TPM_ORD_SAVESTATE 152 int tpm_auto_startup(struct tpm_chip *chip)
#define SAVESTATE_RESULT_SIZE 10 {
int rc;
static const struct tpm_input_header savestate_header = { if (!(chip->ops->flags & TPM_OPS_AUTO_STARTUP))
.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), return 0;
.length = cpu_to_be32(10),
.ordinal = cpu_to_be32(TPM_ORD_SAVESTATE) if (chip->flags & TPM_CHIP_FLAG_TPM2)
}; rc = tpm2_auto_startup(chip);
else
rc = tpm1_auto_startup(chip);
return rc;
}
/* /*
* We are about to suspend. Save the TPM state * We are about to suspend. Save the TPM state
...@@ -1200,54 +563,18 @@ static const struct tpm_input_header savestate_header = { ...@@ -1200,54 +563,18 @@ static const struct tpm_input_header savestate_header = {
int tpm_pm_suspend(struct device *dev) int tpm_pm_suspend(struct device *dev)
{ {
struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_chip *chip = dev_get_drvdata(dev);
struct tpm_cmd_t cmd; int rc = 0;
int rc, try;
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 }; if (!chip)
if (chip == NULL)
return -ENODEV; return -ENODEV;
if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
return 0; return 0;
if (chip->flags & TPM_CHIP_FLAG_TPM2) { if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_shutdown(chip, TPM2_SU_STATE); tpm2_shutdown(chip, TPM2_SU_STATE);
return 0; else
} rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
/* for buggy tpm, flush pcrs with extend to selected dummy */
if (tpm_suspend_pcr)
rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
"extending dummy pcr before suspend");
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
cmd.header.in = savestate_header;
rc = tpm_transmit_cmd(chip, NULL, &cmd, SAVESTATE_RESULT_SIZE,
0, 0, NULL);
/*
* If the TPM indicates that it is too busy to respond to
* this command then retry before giving up. It can take
* several seconds for this TPM to be ready.
*
* This can happen if the TPM has already been sent the
* SaveState command before the driver has loaded. TCG 1.2
* specification states that any communication after SaveState
* may cause the TPM to invalidate previously saved state.
*/
if (rc != TPM_WARN_RETRY)
break;
tpm_msleep(TPM_TIMEOUT_RETRY);
}
if (rc)
dev_err(&chip->dev,
"Error (%d) sending savestate before suspend\n", rc);
else if (try > 0)
dev_warn(&chip->dev, "TPM savestate took %dms\n",
try * TPM_TIMEOUT_RETRY);
return rc; return rc;
} }
...@@ -1268,75 +595,32 @@ int tpm_pm_resume(struct device *dev) ...@@ -1268,75 +595,32 @@ int tpm_pm_resume(struct device *dev)
} }
EXPORT_SYMBOL_GPL(tpm_pm_resume); EXPORT_SYMBOL_GPL(tpm_pm_resume);
#define TPM_GETRANDOM_RESULT_SIZE 18
static const struct tpm_input_header tpm_getrandom_header = {
.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(14),
.ordinal = cpu_to_be32(TPM_ORD_GET_RANDOM)
};
/** /**
* tpm_get_random() - get random bytes from the TPM's RNG * tpm_get_random() - get random bytes from the TPM's RNG
* @chip: a &struct tpm_chip instance, %NULL for the default chip * @chip: a &struct tpm_chip instance, %NULL for the default chip
* @out: destination buffer for the random bytes * @out: destination buffer for the random bytes
* @max: the max number of bytes to write to @out * @max: the max number of bytes to write to @out
* *
* Return: same as with tpm_transmit_cmd() * Return: number of random bytes read or a negative error value.
*/ */
int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
{ {
struct tpm_cmd_t tpm_cmd; int rc;
u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength;
int err, total = 0, retries = 5;
u8 *dest = out;
if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) if (!out || max > TPM_MAX_RNG_DATA)
return -EINVAL; return -EINVAL;
chip = tpm_find_get_ops(chip); chip = tpm_find_get_ops(chip);
if (!chip) if (!chip)
return -ENODEV; return -ENODEV;
if (chip->flags & TPM_CHIP_FLAG_TPM2) { if (chip->flags & TPM_CHIP_FLAG_TPM2)
err = tpm2_get_random(chip, out, max); rc = tpm2_get_random(chip, out, max);
tpm_put_ops(chip); else
return err; rc = tpm1_get_random(chip, out, max);
}
do {
tpm_cmd.header.in = tpm_getrandom_header;
tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
err = tpm_transmit_cmd(chip, NULL, &tpm_cmd,
TPM_GETRANDOM_RESULT_SIZE + num_bytes,
offsetof(struct tpm_getrandom_out,
rng_data),
0, "attempting get random");
if (err)
break;
recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len);
if (recd > num_bytes) {
total = -EFAULT;
break;
}
rlength = be32_to_cpu(tpm_cmd.header.out.length);
if (rlength < TPM_HEADER_SIZE +
offsetof(struct tpm_getrandom_out, rng_data) +
recd) {
total = -EFAULT;
break;
}
memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd);
dest += recd;
total += recd;
num_bytes -= recd;
} while (retries-- && total < max);
tpm_put_ops(chip); tpm_put_ops(chip);
return total ? total : -EIO; return rc;
} }
EXPORT_SYMBOL_GPL(tpm_get_random); EXPORT_SYMBOL_GPL(tpm_get_random);
......
...@@ -102,19 +102,19 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, ...@@ -102,19 +102,19 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr,
cap_t cap; cap_t cap;
u8 digest[TPM_DIGEST_SIZE]; u8 digest[TPM_DIGEST_SIZE];
ssize_t rc; ssize_t rc;
int i, j, num_pcrs; u32 i, j, num_pcrs;
char *str = buf; char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev); struct tpm_chip *chip = to_tpm_chip(dev);
rc = tpm_getcap(chip, TPM_CAP_PROP_PCR, &cap, rc = tpm1_getcap(chip, TPM_CAP_PROP_PCR, &cap,
"attempting to determine the number of PCRS", "attempting to determine the number of PCRS",
sizeof(cap.num_pcrs)); sizeof(cap.num_pcrs));
if (rc) if (rc)
return 0; return 0;
num_pcrs = be32_to_cpu(cap.num_pcrs); num_pcrs = be32_to_cpu(cap.num_pcrs);
for (i = 0; i < num_pcrs; i++) { for (i = 0; i < num_pcrs; i++) {
rc = tpm_pcr_read_dev(chip, i, digest); rc = tpm1_pcr_read(chip, i, digest);
if (rc) if (rc)
break; break;
str += sprintf(str, "PCR-%02d: ", i); str += sprintf(str, "PCR-%02d: ", i);
...@@ -132,9 +132,9 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, ...@@ -132,9 +132,9 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
cap_t cap; cap_t cap;
ssize_t rc; ssize_t rc;
rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
"attempting to determine the permanent enabled state", "attempting to determine the permanent enabled state",
sizeof(cap.perm_flags)); sizeof(cap.perm_flags));
if (rc) if (rc)
return 0; return 0;
...@@ -149,9 +149,9 @@ static ssize_t active_show(struct device *dev, struct device_attribute *attr, ...@@ -149,9 +149,9 @@ static ssize_t active_show(struct device *dev, struct device_attribute *attr,
cap_t cap; cap_t cap;
ssize_t rc; ssize_t rc;
rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
"attempting to determine the permanent active state", "attempting to determine the permanent active state",
sizeof(cap.perm_flags)); sizeof(cap.perm_flags));
if (rc) if (rc)
return 0; return 0;
...@@ -166,9 +166,9 @@ static ssize_t owned_show(struct device *dev, struct device_attribute *attr, ...@@ -166,9 +166,9 @@ static ssize_t owned_show(struct device *dev, struct device_attribute *attr,
cap_t cap; cap_t cap;
ssize_t rc; ssize_t rc;
rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap, rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap,
"attempting to determine the owner state", "attempting to determine the owner state",
sizeof(cap.owned)); sizeof(cap.owned));
if (rc) if (rc)
return 0; return 0;
...@@ -183,9 +183,9 @@ static ssize_t temp_deactivated_show(struct device *dev, ...@@ -183,9 +183,9 @@ static ssize_t temp_deactivated_show(struct device *dev,
cap_t cap; cap_t cap;
ssize_t rc; ssize_t rc;
rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap, rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap,
"attempting to determine the temporary state", "attempting to determine the temporary state",
sizeof(cap.stclear_flags)); sizeof(cap.stclear_flags));
if (rc) if (rc)
return 0; return 0;
...@@ -202,18 +202,18 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, ...@@ -202,18 +202,18 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
ssize_t rc; ssize_t rc;
char *str = buf; char *str = buf;
rc = tpm_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap, rc = tpm1_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap,
"attempting to determine the manufacturer", "attempting to determine the manufacturer",
sizeof(cap.manufacturer_id)); sizeof(cap.manufacturer_id));
if (rc) if (rc)
return 0; return 0;
str += sprintf(str, "Manufacturer: 0x%x\n", str += sprintf(str, "Manufacturer: 0x%x\n",
be32_to_cpu(cap.manufacturer_id)); be32_to_cpu(cap.manufacturer_id));
/* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
rc = tpm_getcap(chip, TPM_CAP_VERSION_1_2, &cap, rc = tpm1_getcap(chip, TPM_CAP_VERSION_1_2, &cap,
"attempting to determine the 1.2 version", "attempting to determine the 1.2 version",
sizeof(cap.tpm_version_1_2)); sizeof(cap.tpm_version_1_2));
if (!rc) { if (!rc) {
str += sprintf(str, str += sprintf(str,
"TCG version: %d.%d\nFirmware version: %d.%d\n", "TCG version: %d.%d\nFirmware version: %d.%d\n",
...@@ -223,9 +223,9 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, ...@@ -223,9 +223,9 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
cap.tpm_version_1_2.revMinor); cap.tpm_version_1_2.revMinor);
} else { } else {
/* Otherwise just use TPM_STRUCT_VER */ /* Otherwise just use TPM_STRUCT_VER */
rc = tpm_getcap(chip, TPM_CAP_VERSION_1_1, &cap, rc = tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
"attempting to determine the 1.1 version", "attempting to determine the 1.1 version",
sizeof(cap.tpm_version)); sizeof(cap.tpm_version));
if (rc) if (rc)
return 0; return 0;
str += sprintf(str, str += sprintf(str,
......
...@@ -134,22 +134,31 @@ enum tpm2_algorithms { ...@@ -134,22 +134,31 @@ enum tpm2_algorithms {
}; };
enum tpm2_command_codes { enum tpm2_command_codes {
TPM2_CC_FIRST = 0x011F, TPM2_CC_FIRST = 0x011F,
TPM2_CC_CREATE_PRIMARY = 0x0131, TPM2_CC_HIERARCHY_CONTROL = 0x0121,
TPM2_CC_SELF_TEST = 0x0143, TPM2_CC_HIERARCHY_CHANGE_AUTH = 0x0129,
TPM2_CC_STARTUP = 0x0144, TPM2_CC_CREATE_PRIMARY = 0x0131,
TPM2_CC_SHUTDOWN = 0x0145, TPM2_CC_SEQUENCE_COMPLETE = 0x013E,
TPM2_CC_CREATE = 0x0153, TPM2_CC_SELF_TEST = 0x0143,
TPM2_CC_LOAD = 0x0157, TPM2_CC_STARTUP = 0x0144,
TPM2_CC_UNSEAL = 0x015E, TPM2_CC_SHUTDOWN = 0x0145,
TPM2_CC_CONTEXT_LOAD = 0x0161, TPM2_CC_NV_READ = 0x014E,
TPM2_CC_CONTEXT_SAVE = 0x0162, TPM2_CC_CREATE = 0x0153,
TPM2_CC_FLUSH_CONTEXT = 0x0165, TPM2_CC_LOAD = 0x0157,
TPM2_CC_GET_CAPABILITY = 0x017A, TPM2_CC_SEQUENCE_UPDATE = 0x015C,
TPM2_CC_GET_RANDOM = 0x017B, TPM2_CC_UNSEAL = 0x015E,
TPM2_CC_PCR_READ = 0x017E, TPM2_CC_CONTEXT_LOAD = 0x0161,
TPM2_CC_PCR_EXTEND = 0x0182, TPM2_CC_CONTEXT_SAVE = 0x0162,
TPM2_CC_LAST = 0x018F, TPM2_CC_FLUSH_CONTEXT = 0x0165,
TPM2_CC_VERIFY_SIGNATURE = 0x0177,
TPM2_CC_GET_CAPABILITY = 0x017A,
TPM2_CC_GET_RANDOM = 0x017B,
TPM2_CC_PCR_READ = 0x017E,
TPM2_CC_PCR_EXTEND = 0x0182,
TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
TPM2_CC_HASH_SEQUENCE_START = 0x0186,
TPM2_CC_CREATE_LOADED = 0x0191,
TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
}; };
enum tpm2_permanent_handles { enum tpm2_permanent_handles {
...@@ -368,18 +377,6 @@ enum tpm_sub_capabilities { ...@@ -368,18 +377,6 @@ enum tpm_sub_capabilities {
TPM_CAP_PROP_TIS_DURATION = 0x120, TPM_CAP_PROP_TIS_DURATION = 0x120,
}; };
typedef union {
struct tpm_input_header in;
struct tpm_output_header out;
} tpm_cmd_header;
struct tpm_pcrread_out {
u8 pcr_result[TPM_DIGEST_SIZE];
} __packed;
struct tpm_pcrread_in {
__be32 pcr_idx;
} __packed;
/* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18 /* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18
* bytes, but 128 is still a relatively large number of random bytes and * bytes, but 128 is still a relatively large number of random bytes and
...@@ -387,28 +384,6 @@ struct tpm_pcrread_in { ...@@ -387,28 +384,6 @@ struct tpm_pcrread_in {
* compiler warnings about stack frame size. */ * compiler warnings about stack frame size. */
#define TPM_MAX_RNG_DATA 128 #define TPM_MAX_RNG_DATA 128
struct tpm_getrandom_out {
__be32 rng_data_len;
u8 rng_data[TPM_MAX_RNG_DATA];
} __packed;
struct tpm_getrandom_in {
__be32 num_bytes;
} __packed;
typedef union {
struct tpm_pcrread_in pcrread_in;
struct tpm_pcrread_out pcrread_out;
struct tpm_getrandom_in getrandom_in;
struct tpm_getrandom_out getrandom_out;
} tpm_cmd_params;
struct tpm_cmd_t {
tpm_cmd_header header;
tpm_cmd_params params;
} __packed;
/* A string buffer type for constructing TPM commands. This is based on the /* A string buffer type for constructing TPM commands. This is based on the
* ideas of string buffer code in security/keys/trusted.h but is heap based * ideas of string buffer code in security/keys/trusted.h but is heap based
* in order to keep the stack usage minimal. * in order to keep the stack usage minimal.
...@@ -531,12 +506,20 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, ...@@ -531,12 +506,20 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
void *buf, size_t bufsiz, void *buf, size_t bufsiz,
size_t min_rsp_body_length, unsigned int flags, size_t min_rsp_body_length, unsigned int flags,
const char *desc); const char *desc);
int tpm_startup(struct tpm_chip *chip);
ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length);
int tpm_get_timeouts(struct tpm_chip *); int tpm_get_timeouts(struct tpm_chip *);
int tpm_auto_startup(struct tpm_chip *chip);
int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr);
int tpm1_auto_startup(struct tpm_chip *chip); int tpm1_auto_startup(struct tpm_chip *chip);
int tpm_do_selftest(struct tpm_chip *chip); int tpm1_do_selftest(struct tpm_chip *chip);
int tpm1_get_timeouts(struct tpm_chip *chip);
unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
const char *log_msg);
int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf);
ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length);
int tpm1_get_random(struct tpm_chip *chip, u8 *out, size_t max);
unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal); unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
int tpm_pm_suspend(struct device *dev); int tpm_pm_suspend(struct device *dev);
int tpm_pm_resume(struct device *dev); int tpm_pm_resume(struct device *dev);
...@@ -560,7 +543,6 @@ void tpm_chip_unregister(struct tpm_chip *chip); ...@@ -560,7 +543,6 @@ void tpm_chip_unregister(struct tpm_chip *chip);
void tpm_sysfs_add_device(struct tpm_chip *chip); void tpm_sysfs_add_device(struct tpm_chip *chip);
int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
extern void tpm_add_ppi(struct tpm_chip *chip); extern void tpm_add_ppi(struct tpm_chip *chip);
...@@ -575,8 +557,9 @@ static inline u32 tpm2_rc_value(u32 rc) ...@@ -575,8 +557,9 @@ static inline u32 tpm2_rc_value(u32 rc)
return (rc & BIT(7)) ? rc & 0xff : rc; return (rc & BIT(7)) ? rc & 0xff : rc;
} }
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); int tpm2_get_timeouts(struct tpm_chip *chip);
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf);
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count,
struct tpm2_digest *digests); struct tpm2_digest *digests);
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max); int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max);
void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2004 IBM Corporation
* Copyright (C) 2014 Intel Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
* Dave Safford <safford@watson.ibm.com>
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
*/
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/freezer.h>
#include <linux/tpm_eventlog.h>
#include "tpm.h"
#define TPM_MAX_ORDINAL 243
/*
* Array with one entry per ordinal defining the maximum amount
* of time the chip could take to return the result. The ordinal
* designation of short, medium or long is defined in a table in
* TCG Specification TPM Main Part 2 TPM Structures Section 17. The
* values of the SHORT, MEDIUM, and LONG durations are retrieved
* from the chip during initialization with a call to tpm_get_timeouts.
*/
static const u8 tpm1_ordinal_duration[TPM_MAX_ORDINAL] = {
TPM_UNDEFINED, /* 0 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 5 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 10 */
TPM_SHORT,
TPM_MEDIUM,
TPM_LONG,
TPM_LONG,
TPM_MEDIUM, /* 15 */
TPM_SHORT,
TPM_SHORT,
TPM_MEDIUM,
TPM_LONG,
TPM_SHORT, /* 20 */
TPM_SHORT,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_SHORT, /* 25 */
TPM_SHORT,
TPM_MEDIUM,
TPM_SHORT,
TPM_SHORT,
TPM_MEDIUM, /* 30 */
TPM_LONG,
TPM_MEDIUM,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT, /* 35 */
TPM_MEDIUM,
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_MEDIUM, /* 40 */
TPM_LONG,
TPM_MEDIUM,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT, /* 45 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_LONG,
TPM_MEDIUM, /* 50 */
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 55 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_MEDIUM, /* 60 */
TPM_MEDIUM,
TPM_MEDIUM,
TPM_SHORT,
TPM_SHORT,
TPM_MEDIUM, /* 65 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 70 */
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 75 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_LONG, /* 80 */
TPM_UNDEFINED,
TPM_MEDIUM,
TPM_LONG,
TPM_SHORT,
TPM_UNDEFINED, /* 85 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 90 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED, /* 95 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_MEDIUM, /* 100 */
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 105 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 110 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT, /* 115 */
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_LONG, /* 120 */
TPM_LONG,
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_SHORT,
TPM_SHORT, /* 125 */
TPM_SHORT,
TPM_LONG,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT, /* 130 */
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_SHORT,
TPM_MEDIUM,
TPM_UNDEFINED, /* 135 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 140 */
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 145 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 150 */
TPM_MEDIUM,
TPM_MEDIUM,
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED, /* 155 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 160 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 165 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_LONG, /* 170 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 175 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_MEDIUM, /* 180 */
TPM_SHORT,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_MEDIUM, /* 185 */
TPM_SHORT,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 190 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 195 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 200 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT,
TPM_SHORT, /* 205 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_MEDIUM, /* 210 */
TPM_UNDEFINED,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_MEDIUM,
TPM_UNDEFINED, /* 215 */
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT,
TPM_SHORT, /* 220 */
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_SHORT,
TPM_UNDEFINED, /* 225 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 230 */
TPM_LONG,
TPM_MEDIUM,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED, /* 235 */
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_UNDEFINED,
TPM_SHORT, /* 240 */
TPM_UNDEFINED,
TPM_MEDIUM,
};
/**
* tpm1_calc_ordinal_duration() - calculate the maximum command duration
* @chip: TPM chip to use.
* @ordinal: TPM command ordinal.
*
* The function returns the maximum amount of time the chip could take
* to return the result for a particular ordinal in jiffies.
*
* Return: A maximal duration time for an ordinal in jiffies.
*/
unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
{
int duration_idx = TPM_UNDEFINED;
int duration = 0;
/*
* We only have a duration table for protected commands, where the upper
* 16 bits are 0. For the few other ordinals the fallback will be used.
*/
if (ordinal < TPM_MAX_ORDINAL)
duration_idx = tpm1_ordinal_duration[ordinal];
if (duration_idx != TPM_UNDEFINED)
duration = chip->duration[duration_idx];
if (duration <= 0)
return 2 * 60 * HZ;
else
return duration;
}
#define TPM_ORD_STARTUP 153
#define TPM_ST_CLEAR 1
/**
* tpm_startup() - turn on the TPM
* @chip: TPM chip to use
*
* Normally the firmware should start the TPM. This function is provided as a
* workaround if this does not happen. A legal case for this could be for
* example when a TPM emulator is used.
*
* Return: same as tpm_transmit_cmd()
*/
static int tpm1_startup(struct tpm_chip *chip)
{
struct tpm_buf buf;
int rc;
dev_info(&chip->dev, "starting up the TPM manually\n");
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
if (rc < 0)
return rc;
tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
"attempting to start the TPM");
tpm_buf_destroy(&buf);
return rc;
}
int tpm1_get_timeouts(struct tpm_chip *chip)
{
cap_t cap;
unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4];
ssize_t rc;
rc = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL,
sizeof(cap.timeout));
if (rc == TPM_ERR_INVALID_POSTINIT) {
if (tpm1_startup(chip))
return rc;
rc = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
"attempting to determine the timeouts",
sizeof(cap.timeout));
}
if (rc) {
dev_err(&chip->dev, "A TPM error (%zd) occurred attempting to determine the timeouts\n",
rc);
return rc;
}
timeout_old[0] = jiffies_to_usecs(chip->timeout_a);
timeout_old[1] = jiffies_to_usecs(chip->timeout_b);
timeout_old[2] = jiffies_to_usecs(chip->timeout_c);
timeout_old[3] = jiffies_to_usecs(chip->timeout_d);
timeout_chip[0] = be32_to_cpu(cap.timeout.a);
timeout_chip[1] = be32_to_cpu(cap.timeout.b);
timeout_chip[2] = be32_to_cpu(cap.timeout.c);
timeout_chip[3] = be32_to_cpu(cap.timeout.d);
memcpy(timeout_eff, timeout_chip, sizeof(timeout_eff));
/*
* Provide ability for vendor overrides of timeout values in case
* of misreporting.
*/
if (chip->ops->update_timeouts)
chip->timeout_adjusted =
chip->ops->update_timeouts(chip, timeout_eff);
if (!chip->timeout_adjusted) {
/* Restore default if chip reported 0 */
unsigned int i;
for (i = 0; i < ARRAY_SIZE(timeout_eff); i++) {
if (timeout_eff[i])
continue;
timeout_eff[i] = timeout_old[i];
chip->timeout_adjusted = true;
}
if (timeout_eff[0] != 0 && timeout_eff[0] < 1000) {
/* timeouts in msec rather usec */
for (i = 0; i != ARRAY_SIZE(timeout_eff); i++)
timeout_eff[i] *= 1000;
chip->timeout_adjusted = true;
}
}
/* Report adjusted timeouts */
if (chip->timeout_adjusted) {
dev_info(&chip->dev, HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
timeout_chip[0], timeout_eff[0],
timeout_chip[1], timeout_eff[1],
timeout_chip[2], timeout_eff[2],
timeout_chip[3], timeout_eff[3]);
}
chip->timeout_a = usecs_to_jiffies(timeout_eff[0]);
chip->timeout_b = usecs_to_jiffies(timeout_eff[1]);
chip->timeout_c = usecs_to_jiffies(timeout_eff[2]);
chip->timeout_d = usecs_to_jiffies(timeout_eff[3]);
rc = tpm1_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap,
"attempting to determine the durations",
sizeof(cap.duration));
if (rc)
return rc;
chip->duration[TPM_SHORT] =
usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short));
chip->duration[TPM_MEDIUM] =
usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium));
chip->duration[TPM_LONG] =
usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_long));
chip->duration[TPM_LONG_LONG] = 0; /* not used under 1.2 */
/* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
* value wrong and apparently reports msecs rather than usecs. So we
* fix up the resulting too-small TPM_SHORT value to make things work.
* We also scale the TPM_MEDIUM and -_LONG values by 1000.
*/
if (chip->duration[TPM_SHORT] < (HZ / 100)) {
chip->duration[TPM_SHORT] = HZ;
chip->duration[TPM_MEDIUM] *= 1000;
chip->duration[TPM_LONG] *= 1000;
chip->duration_adjusted = true;
dev_info(&chip->dev, "Adjusting TPM timeout parameters.");
}
chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS;
return 0;
}
#define TPM_ORD_PCR_EXTEND 20
int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
const char *log_msg)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
if (rc)
return rc;
tpm_buf_append_u32(&buf, pcr_idx);
tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
TPM_DIGEST_SIZE, 0, log_msg);
tpm_buf_destroy(&buf);
return rc;
}
#define TPM_ORD_GET_CAP 101
ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
if (rc)
return rc;
if (subcap_id == TPM_CAP_VERSION_1_1 ||
subcap_id == TPM_CAP_VERSION_1_2) {
tpm_buf_append_u32(&buf, subcap_id);
tpm_buf_append_u32(&buf, 0);
} else {
if (subcap_id == TPM_CAP_FLAG_PERM ||
subcap_id == TPM_CAP_FLAG_VOL)
tpm_buf_append_u32(&buf, TPM_CAP_FLAG);
else
tpm_buf_append_u32(&buf, TPM_CAP_PROP);
tpm_buf_append_u32(&buf, 4);
tpm_buf_append_u32(&buf, subcap_id);
}
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
min_cap_length, 0, desc);
if (!rc)
*cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
tpm_buf_destroy(&buf);
return rc;
}
EXPORT_SYMBOL_GPL(tpm1_getcap);
#define TPM_ORD_GET_RANDOM 70
struct tpm1_get_random_out {
__be32 rng_data_len;
u8 rng_data[TPM_MAX_RNG_DATA];
} __packed;
/**
* tpm1_get_random() - get random bytes from the TPM's RNG
* @chip: a &struct tpm_chip instance
* @dest: destination buffer for the random bytes
* @max: the maximum number of bytes to write to @dest
*
* Return:
* * number of bytes read
* * -errno or a TPM return code otherwise
*/
int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm1_get_random_out *out;
u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
struct tpm_buf buf;
u32 total = 0;
int retries = 5;
u32 recd;
int rc;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
if (rc)
return rc;
do {
tpm_buf_append_u32(&buf, num_bytes);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
sizeof(out->rng_data_len), 0,
"attempting get random");
if (rc)
goto out;
out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
recd = be32_to_cpu(out->rng_data_len);
if (recd > num_bytes) {
rc = -EFAULT;
goto out;
}
if (tpm_buf_length(&buf) < TPM_HEADER_SIZE +
sizeof(out->rng_data_len) + recd) {
rc = -EFAULT;
goto out;
}
memcpy(dest, out->rng_data, recd);
dest += recd;
total += recd;
num_bytes -= recd;
tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
} while (retries-- && total < max);
rc = total ? (int)total : -EIO;
out:
tpm_buf_destroy(&buf);
return rc;
}
#define TPM_ORD_PCRREAD 21
int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
if (rc)
return rc;
tpm_buf_append_u32(&buf, pcr_idx);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
TPM_DIGEST_SIZE, 0,
"attempting to read a pcr value");
if (rc)
goto out;
if (tpm_buf_length(&buf) < TPM_DIGEST_SIZE) {
rc = -EFAULT;
goto out;
}
memcpy(res_buf, &buf.data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
out:
tpm_buf_destroy(&buf);
return rc;
}
#define TPM_ORD_CONTINUE_SELFTEST 83
/**
* tpm_continue_selftest() - run TPM's selftest
* @chip: TPM chip to use
*
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
* a TPM error code.
*/
static int tpm1_continue_selftest(struct tpm_chip *chip)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
if (rc)
return rc;
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
0, 0, "continue selftest");
tpm_buf_destroy(&buf);
return rc;
}
/**
* tpm1_do_selftest - have the TPM continue its selftest and wait until it
* can receive further commands
* @chip: TPM chip to use
*
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
* a TPM error code.
*/
int tpm1_do_selftest(struct tpm_chip *chip)
{
int rc;
unsigned int loops;
unsigned int delay_msec = 100;
unsigned long duration;
u8 dummy[TPM_DIGEST_SIZE];
duration = tpm1_calc_ordinal_duration(chip, TPM_ORD_CONTINUE_SELFTEST);
loops = jiffies_to_msecs(duration) / delay_msec;
rc = tpm1_continue_selftest(chip);
if (rc == TPM_ERR_INVALID_POSTINIT) {
chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED;
dev_info(&chip->dev, "TPM not ready (%d)\n", rc);
}
/* This may fail if there was no TPM driver during a suspend/resume
* cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
*/
if (rc)
return rc;
do {
/* Attempt to read a PCR value */
rc = tpm1_pcr_read(chip, 0, dummy);
/* Some buggy TPMs will not respond to tpm_tis_ready() for
* around 300ms while the self test is ongoing, keep trying
* until the self test duration expires.
*/
if (rc == -ETIME) {
dev_info(&chip->dev, HW_ERR "TPM command timed out during continue self test");
tpm_msleep(delay_msec);
continue;
}
if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
dev_info(&chip->dev, "TPM is disabled/deactivated (0x%X)\n",
rc);
/* TPM is disabled and/or deactivated; driver can
* proceed and TPM does handle commands for
* suspend/resume correctly
*/
return 0;
}
if (rc != TPM_WARN_DOING_SELFTEST)
return rc;
tpm_msleep(delay_msec);
} while (--loops > 0);
return rc;
}
EXPORT_SYMBOL_GPL(tpm1_do_selftest);
/**
* tpm1_auto_startup - Perform the standard automatic TPM initialization
* sequence
* @chip: TPM chip to use
*
* Returns 0 on success, < 0 in case of fatal error.
*/
int tpm1_auto_startup(struct tpm_chip *chip)
{
int rc;
rc = tpm1_get_timeouts(chip);
if (rc)
goto out;
rc = tpm1_do_selftest(chip);
if (rc) {
dev_err(&chip->dev, "TPM self test failed\n");
goto out;
}
return rc;
out:
if (rc > 0)
rc = -ENODEV;
return rc;
}
#define TPM_ORD_SAVESTATE 152
/**
* tpm1_pm_suspend() - pm suspend handler
* @chip: TPM chip to use.
* @tpm_suspend_pcr: flush pcr for buggy TPM chips.
*
* The functions saves the TPM state to be restored on resume.
*
* Return:
* * 0 on success,
* * < 0 on error.
*/
int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
{
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
struct tpm_buf buf;
unsigned int try;
int rc;
/* for buggy tpm, flush pcrs with extend to selected dummy */
if (tpm_suspend_pcr)
rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
"extending dummy pcr before suspend");
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
if (rc)
return rc;
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
0, 0, NULL);
/*
* If the TPM indicates that it is too busy to respond to
* this command then retry before giving up. It can take
* several seconds for this TPM to be ready.
*
* This can happen if the TPM has already been sent the
* SaveState command before the driver has loaded. TCG 1.2
* specification states that any communication after SaveState
* may cause the TPM to invalidate previously saved state.
*/
if (rc != TPM_WARN_RETRY)
break;
tpm_msleep(TPM_TIMEOUT_RETRY);
tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
}
if (rc)
dev_err(&chip->dev, "Error (%d) sending savestate before suspend\n",
rc);
else if (try > 0)
dev_warn(&chip->dev, "TPM savestate took %dms\n",
try * TPM_TIMEOUT_RETRY);
tpm_buf_destroy(&buf);
return rc;
}
...@@ -40,129 +40,121 @@ static struct tpm2_hash tpm2_hash_map[] = { ...@@ -40,129 +40,121 @@ static struct tpm2_hash tpm2_hash_map[] = {
{HASH_ALGO_SM3_256, TPM2_ALG_SM3_256}, {HASH_ALGO_SM3_256, TPM2_ALG_SM3_256},
}; };
/* int tpm2_get_timeouts(struct tpm_chip *chip)
* Array with one entry per ordinal defining the maximum amount {
* of time the chip could take to return the result. The values /* Fixed timeouts for TPM2 */
* of the SHORT, MEDIUM, and LONG durations are taken from the chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
* PC Client Profile (PTP) specification. chip->timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
* LONG_LONG is for commands that generates keys which empirically chip->timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
* takes longer time on some systems. chip->timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
/* PTP spec timeouts */
chip->duration[TPM_SHORT] = msecs_to_jiffies(TPM2_DURATION_SHORT);
chip->duration[TPM_MEDIUM] = msecs_to_jiffies(TPM2_DURATION_MEDIUM);
chip->duration[TPM_LONG] = msecs_to_jiffies(TPM2_DURATION_LONG);
/* Key creation commands long timeouts */
chip->duration[TPM_LONG_LONG] =
msecs_to_jiffies(TPM2_DURATION_LONG_LONG);
chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS;
return 0;
}
/**
* tpm2_ordinal_duration_index() - returns an index to the chip duration table
* @ordinal: TPM command ordinal.
*
* The function returns an index to the chip duration table
* (enum tpm_duration), that describes the maximum amount of
* time the chip could take to return the result for a particular ordinal.
*
* The values of the MEDIUM, and LONG durations are taken
* from the PC Client Profile (PTP) specification (750, 2000 msec)
*
* LONG_LONG is for commands that generates keys which empirically takes
* a longer time on some systems.
*
* Return:
* * TPM_MEDIUM
* * TPM_LONG
* * TPM_LONG_LONG
* * TPM_UNDEFINED
*/ */
static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { static u8 tpm2_ordinal_duration_index(u32 ordinal)
TPM_UNDEFINED, /* 11F */ {
TPM_UNDEFINED, /* 120 */ switch (ordinal) {
TPM_LONG, /* 121 */ /* Startup */
TPM_UNDEFINED, /* 122 */ case TPM2_CC_STARTUP: /* 144 */
TPM_UNDEFINED, /* 123 */ return TPM_MEDIUM;
TPM_UNDEFINED, /* 124 */
TPM_UNDEFINED, /* 125 */ case TPM2_CC_SELF_TEST: /* 143 */
TPM_UNDEFINED, /* 126 */ return TPM_LONG;
TPM_UNDEFINED, /* 127 */
TPM_UNDEFINED, /* 128 */ case TPM2_CC_GET_RANDOM: /* 17B */
TPM_LONG, /* 129 */ return TPM_LONG;
TPM_UNDEFINED, /* 12a */
TPM_UNDEFINED, /* 12b */ case TPM2_CC_SEQUENCE_UPDATE: /* 15C */
TPM_UNDEFINED, /* 12c */ return TPM_MEDIUM;
TPM_UNDEFINED, /* 12d */ case TPM2_CC_SEQUENCE_COMPLETE: /* 13E */
TPM_UNDEFINED, /* 12e */ return TPM_MEDIUM;
TPM_UNDEFINED, /* 12f */ case TPM2_CC_EVENT_SEQUENCE_COMPLETE: /* 185 */
TPM_UNDEFINED, /* 130 */ return TPM_MEDIUM;
TPM_LONG_LONG, /* 131 */ case TPM2_CC_HASH_SEQUENCE_START: /* 186 */
TPM_UNDEFINED, /* 132 */ return TPM_MEDIUM;
TPM_UNDEFINED, /* 133 */
TPM_UNDEFINED, /* 134 */ case TPM2_CC_VERIFY_SIGNATURE: /* 177 */
TPM_UNDEFINED, /* 135 */ return TPM_LONG;
TPM_UNDEFINED, /* 136 */
TPM_UNDEFINED, /* 137 */ case TPM2_CC_PCR_EXTEND: /* 182 */
TPM_UNDEFINED, /* 138 */ return TPM_MEDIUM;
TPM_UNDEFINED, /* 139 */
TPM_UNDEFINED, /* 13a */ case TPM2_CC_HIERARCHY_CONTROL: /* 121 */
TPM_UNDEFINED, /* 13b */ return TPM_LONG;
TPM_UNDEFINED, /* 13c */ case TPM2_CC_HIERARCHY_CHANGE_AUTH: /* 129 */
TPM_UNDEFINED, /* 13d */ return TPM_LONG;
TPM_MEDIUM, /* 13e */
TPM_UNDEFINED, /* 13f */ case TPM2_CC_GET_CAPABILITY: /* 17A */
TPM_UNDEFINED, /* 140 */ return TPM_MEDIUM;
TPM_UNDEFINED, /* 141 */
TPM_UNDEFINED, /* 142 */ case TPM2_CC_NV_READ: /* 14E */
TPM_LONG, /* 143 */ return TPM_LONG;
TPM_MEDIUM, /* 144 */
TPM_UNDEFINED, /* 145 */ case TPM2_CC_CREATE_PRIMARY: /* 131 */
TPM_UNDEFINED, /* 146 */ return TPM_LONG_LONG;
TPM_UNDEFINED, /* 147 */ case TPM2_CC_CREATE: /* 153 */
TPM_UNDEFINED, /* 148 */ return TPM_LONG_LONG;
TPM_UNDEFINED, /* 149 */ case TPM2_CC_CREATE_LOADED: /* 191 */
TPM_UNDEFINED, /* 14a */ return TPM_LONG_LONG;
TPM_UNDEFINED, /* 14b */
TPM_UNDEFINED, /* 14c */ default:
TPM_UNDEFINED, /* 14d */ return TPM_UNDEFINED;
TPM_LONG, /* 14e */ }
TPM_UNDEFINED, /* 14f */ }
TPM_UNDEFINED, /* 150 */
TPM_UNDEFINED, /* 151 */ /**
TPM_UNDEFINED, /* 152 */ * tpm2_calc_ordinal_duration() - calculate the maximum command duration
TPM_LONG_LONG, /* 153 */ * @chip: TPM chip to use.
TPM_UNDEFINED, /* 154 */ * @ordinal: TPM command ordinal.
TPM_UNDEFINED, /* 155 */ *
TPM_UNDEFINED, /* 156 */ * The function returns the maximum amount of time the chip could take
TPM_UNDEFINED, /* 157 */ * to return the result for a particular ordinal in jiffies.
TPM_UNDEFINED, /* 158 */ *
TPM_UNDEFINED, /* 159 */ * Return: A maximal duration time for an ordinal in jiffies.
TPM_UNDEFINED, /* 15a */ */
TPM_UNDEFINED, /* 15b */ unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
TPM_MEDIUM, /* 15c */ {
TPM_UNDEFINED, /* 15d */ unsigned int index;
TPM_UNDEFINED, /* 15e */
TPM_UNDEFINED, /* 15f */ index = tpm2_ordinal_duration_index(ordinal);
TPM_UNDEFINED, /* 160 */
TPM_UNDEFINED, /* 161 */ if (index != TPM_UNDEFINED)
TPM_UNDEFINED, /* 162 */ return chip->duration[index];
TPM_UNDEFINED, /* 163 */ else
TPM_UNDEFINED, /* 164 */ return msecs_to_jiffies(TPM2_DURATION_DEFAULT);
TPM_UNDEFINED, /* 165 */ }
TPM_UNDEFINED, /* 166 */
TPM_UNDEFINED, /* 167 */
TPM_UNDEFINED, /* 168 */
TPM_UNDEFINED, /* 169 */
TPM_UNDEFINED, /* 16a */
TPM_UNDEFINED, /* 16b */
TPM_UNDEFINED, /* 16c */
TPM_UNDEFINED, /* 16d */
TPM_UNDEFINED, /* 16e */
TPM_UNDEFINED, /* 16f */
TPM_UNDEFINED, /* 170 */
TPM_UNDEFINED, /* 171 */
TPM_UNDEFINED, /* 172 */
TPM_UNDEFINED, /* 173 */
TPM_UNDEFINED, /* 174 */
TPM_UNDEFINED, /* 175 */
TPM_UNDEFINED, /* 176 */
TPM_LONG, /* 177 */
TPM_UNDEFINED, /* 178 */
TPM_UNDEFINED, /* 179 */
TPM_MEDIUM, /* 17a */
TPM_LONG, /* 17b */
TPM_UNDEFINED, /* 17c */
TPM_UNDEFINED, /* 17d */
TPM_UNDEFINED, /* 17e */
TPM_UNDEFINED, /* 17f */
TPM_UNDEFINED, /* 180 */
TPM_UNDEFINED, /* 181 */
TPM_MEDIUM, /* 182 */
TPM_UNDEFINED, /* 183 */
TPM_UNDEFINED, /* 184 */
TPM_MEDIUM, /* 185 */
TPM_MEDIUM, /* 186 */
TPM_UNDEFINED, /* 187 */
TPM_UNDEFINED, /* 188 */
TPM_UNDEFINED, /* 189 */
TPM_UNDEFINED, /* 18a */
TPM_UNDEFINED, /* 18b */
TPM_UNDEFINED, /* 18c */
TPM_UNDEFINED, /* 18d */
TPM_UNDEFINED, /* 18e */
TPM_UNDEFINED /* 18f */
};
struct tpm2_pcr_read_out { struct tpm2_pcr_read_out {
__be32 update_cnt; __be32 update_cnt;
...@@ -183,7 +175,7 @@ struct tpm2_pcr_read_out { ...@@ -183,7 +175,7 @@ struct tpm2_pcr_read_out {
* *
* Return: Same as with tpm_transmit_cmd. * Return: Same as with tpm_transmit_cmd.
*/ */
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
{ {
int rc; int rc;
struct tpm_buf buf; struct tpm_buf buf;
...@@ -233,7 +225,7 @@ struct tpm2_null_auth_area { ...@@ -233,7 +225,7 @@ struct tpm2_null_auth_area {
* *
* Return: Same as with tpm_transmit_cmd. * Return: Same as with tpm_transmit_cmd.
*/ */
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count,
struct tpm2_digest *digests) struct tpm2_digest *digests)
{ {
struct tpm_buf buf; struct tpm_buf buf;
...@@ -280,7 +272,6 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, ...@@ -280,7 +272,6 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
return rc; return rc;
} }
struct tpm2_get_random_out { struct tpm2_get_random_out {
__be16 size; __be16 size;
u8 buffer[TPM_MAX_RNG_DATA]; u8 buffer[TPM_MAX_RNG_DATA];
...@@ -351,11 +342,10 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) ...@@ -351,11 +342,10 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
/** /**
* tpm2_flush_context_cmd() - execute a TPM2_FlushContext command * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
* @chip: TPM chip to use * @chip: TPM chip to use
* @payload: the key data in clear and encrypted form * @handle: context handle
* @options: authentication values and other options * @flags: tpm transmit flags - bitmap
* *
* Return: same as with tpm_transmit_cmd
*/ */
void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
unsigned int flags) unsigned int flags)
...@@ -748,32 +738,6 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) ...@@ -748,32 +738,6 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
} }
/*
* tpm2_calc_ordinal_duration() - maximum duration for a command
*
* @chip: TPM chip to use.
* @ordinal: command code number.
*
* Return: maximum duration for a command
*/
unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
{
int index = TPM_UNDEFINED;
int duration = 0;
if (ordinal >= TPM2_CC_FIRST && ordinal <= TPM2_CC_LAST)
index = tpm2_ordinal_duration[ordinal - TPM2_CC_FIRST];
if (index != TPM_UNDEFINED)
duration = chip->duration[index];
if (duration <= 0)
duration = msecs_to_jiffies(TPM2_DURATION_DEFAULT);
return duration;
}
EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration);
/** /**
* tpm2_do_selftest() - ensure that all self tests have passed * tpm2_do_selftest() - ensure that all self tests have passed
* *
...@@ -982,6 +946,36 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip) ...@@ -982,6 +946,36 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
return rc; return rc;
} }
/**
* tpm2_startup - turn on the TPM
* @chip: TPM chip to use
*
* Normally the firmware should start the TPM. This function is provided as a
* workaround if this does not happen. A legal case for this could be for
* example when a TPM emulator is used.
*
* Return: same as tpm_transmit_cmd()
*/
static int tpm2_startup(struct tpm_chip *chip)
{
struct tpm_buf buf;
int rc;
dev_info(&chip->dev, "starting up the TPM manually\n");
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
if (rc < 0)
return rc;
tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
"attempting to start the TPM");
tpm_buf_destroy(&buf);
return rc;
}
/** /**
* tpm2_auto_startup - Perform the standard automatic TPM initialization * tpm2_auto_startup - Perform the standard automatic TPM initialization
* sequence * sequence
...@@ -993,7 +987,7 @@ int tpm2_auto_startup(struct tpm_chip *chip) ...@@ -993,7 +987,7 @@ int tpm2_auto_startup(struct tpm_chip *chip)
{ {
int rc; int rc;
rc = tpm_get_timeouts(chip); rc = tpm2_get_timeouts(chip);
if (rc) if (rc)
goto out; goto out;
...@@ -1002,7 +996,7 @@ int tpm2_auto_startup(struct tpm_chip *chip) ...@@ -1002,7 +996,7 @@ int tpm2_auto_startup(struct tpm_chip *chip)
goto out; goto out;
if (rc == TPM2_RC_INITIALIZE) { if (rc == TPM2_RC_INITIALIZE) {
rc = tpm_startup(chip); rc = tpm2_startup(chip);
if (rc) if (rc)
goto out; goto out;
......
...@@ -373,7 +373,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, ...@@ -373,7 +373,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
dev_err(&chip->dev, "%s: unknown handle 0x%08X\n", dev_err(&chip->dev, "%s: unknown handle 0x%08X\n",
__func__, phandle); __func__, phandle);
break; break;
}; }
return 0; return 0;
out_no_slots: out_no_slots:
......
...@@ -369,6 +369,7 @@ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -369,6 +369,7 @@ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len)
struct device *dev = chip->dev.parent; struct device *dev = chip->dev.parent;
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
u32 ordinal; u32 ordinal;
unsigned long duration;
size_t count = 0; size_t count = 0;
int burst_count, bytes2write, retries, rc = -EIO; int burst_count, bytes2write, retries, rc = -EIO;
...@@ -455,12 +456,12 @@ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -455,12 +456,12 @@ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len)
return rc; return rc;
} }
ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
rc = i2c_nuvoton_wait_for_data_avail(chip, duration = tpm_calc_ordinal_duration(chip, ordinal);
tpm_calc_ordinal_duration(chip,
ordinal), rc = i2c_nuvoton_wait_for_data_avail(chip, duration, &priv->read_queue);
&priv->read_queue);
if (rc) { if (rc) {
dev_err(dev, "%s() timeout command duration\n", __func__); dev_err(dev, "%s() timeout command duration %ld\n",
__func__, duration);
i2c_nuvoton_ready(chip); i2c_nuvoton_ready(chip);
return rc; return rc;
} }
......
...@@ -39,8 +39,7 @@ static const struct vio_device_id tpm_ibmvtpm_device_table[] = { ...@@ -39,8 +39,7 @@ static const struct vio_device_id tpm_ibmvtpm_device_table[] = {
MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table); MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
/** /**
* * ibmvtpm_send_crq_word() - Send a CRQ request
* ibmvtpm_send_crq_word - Send a CRQ request
* @vdev: vio device struct * @vdev: vio device struct
* @w1: pre-constructed first word of tpm crq (second word is reserved) * @w1: pre-constructed first word of tpm crq (second word is reserved)
* *
...@@ -54,8 +53,7 @@ static int ibmvtpm_send_crq_word(struct vio_dev *vdev, u64 w1) ...@@ -54,8 +53,7 @@ static int ibmvtpm_send_crq_word(struct vio_dev *vdev, u64 w1)
} }
/** /**
* * ibmvtpm_send_crq() - Send a CRQ request
* ibmvtpm_send_crq - Send a CRQ request
* *
* @vdev: vio device struct * @vdev: vio device struct
* @valid: Valid field * @valid: Valid field
......
...@@ -473,11 +473,7 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len) ...@@ -473,11 +473,7 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
if (chip->flags & TPM_CHIP_FLAG_IRQ) { if (chip->flags & TPM_CHIP_FLAG_IRQ) {
ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
if (chip->flags & TPM_CHIP_FLAG_TPM2) dur = tpm_calc_ordinal_duration(chip, ordinal);
dur = tpm2_calc_ordinal_duration(chip, ordinal);
else
dur = tpm_calc_ordinal_duration(chip, ordinal);
if (wait_for_tpm_stat if (wait_for_tpm_stat
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur, (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
&priv->read_queue, false) < 0) { &priv->read_queue, false) < 0) {
...@@ -668,7 +664,7 @@ static int tpm_tis_gen_interrupt(struct tpm_chip *chip) ...@@ -668,7 +664,7 @@ static int tpm_tis_gen_interrupt(struct tpm_chip *chip)
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2)
return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc); return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc);
else else
return tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, return tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc,
0); 0);
} }
...@@ -1060,7 +1056,7 @@ int tpm_tis_resume(struct device *dev) ...@@ -1060,7 +1056,7 @@ int tpm_tis_resume(struct device *dev)
* an error code but for unknown reason it isn't handled. * an error code but for unknown reason it isn't handled.
*/ */
if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
tpm_do_selftest(chip); tpm1_do_selftest(chip);
return 0; return 0;
} }
......
...@@ -53,8 +53,8 @@ struct tpm_class_ops { ...@@ -53,8 +53,8 @@ struct tpm_class_ops {
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
extern int tpm_is_tpm2(struct tpm_chip *chip); extern int tpm_is_tpm2(struct tpm_chip *chip);
extern int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); extern int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf);
extern int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); extern int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash);
extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen); extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen);
extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max); extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max);
extern int tpm_seal_trusted(struct tpm_chip *chip, extern int tpm_seal_trusted(struct tpm_chip *chip,
...@@ -69,15 +69,18 @@ static inline int tpm_is_tpm2(struct tpm_chip *chip) ...@@ -69,15 +69,18 @@ static inline int tpm_is_tpm2(struct tpm_chip *chip)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
static inline int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx,
static inline int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
const u8 *hash) const u8 *hash)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) static inline int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen)
{ {
return -ENODEV; return -ENODEV;
......
...@@ -643,7 +643,7 @@ int ima_calc_buffer_hash(const void *buf, loff_t len, ...@@ -643,7 +643,7 @@ int ima_calc_buffer_hash(const void *buf, loff_t len,
return calc_buffer_shash(buf, len, hash); return calc_buffer_shash(buf, len, hash);
} }
static void __init ima_pcrread(int idx, u8 *pcr) static void __init ima_pcrread(u32 idx, u8 *pcr)
{ {
if (!ima_tpm_chip) if (!ima_tpm_chip)
return; return;
...@@ -659,7 +659,8 @@ static int __init ima_calc_boot_aggregate_tfm(char *digest, ...@@ -659,7 +659,8 @@ static int __init ima_calc_boot_aggregate_tfm(char *digest,
struct crypto_shash *tfm) struct crypto_shash *tfm)
{ {
u8 pcr_i[TPM_DIGEST_SIZE]; u8 pcr_i[TPM_DIGEST_SIZE];
int rc, i; int rc;
u32 i;
SHASH_DESC_ON_STACK(shash, tfm); SHASH_DESC_ON_STACK(shash, tfm);
shash->tfm = tfm; shash->tfm = tfm;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment