Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c715ebeb authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull TPM updates from James Morris:

 - Migrate away from PM runtime as explicit cmdReady/goIdle transactions
   for every command is a spec requirement. PM runtime adds only a layer
   of complexity on our case.

 - tpm_tis drivers can now specify the hwrng quality.

 - TPM 2.0 code uses now tpm_buf for constructing messages. Jarkko
   thinks Tomas Winkler has done the same for TPM 1.2, and will start
   digging those changes from the patchwork in the near future.

 - Bug fixes and clean ups

* 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  ima: Get rid of ima_used_chip and use ima_tpm_chip != NULL instead
  ima: Use tpm_default_chip() and call TPM functions with a tpm_chip
  tpm: replace TPM_TRANSMIT_RAW with TPM_TRANSMIT_NESTED
  tpm: Convert tpm_find_get_ops() to use tpm_default_chip()
  tpm: Implement tpm_default_chip() to find a TPM chip
  tpm: rename tpm_chip_find_get() to tpm_find_get_ops()
  tpm: Allow tpm_tis drivers to set hwrng quality.
  tpm: Return the actual size when receiving an unsupported command
  tpm: separate cmd_ready/go_idle from runtime_pm
  tpm/tpm_i2c_infineon: switch to i2c_lock_bus(..., I2C_LOCK_SEGMENT)
  tpm_tis_spi: Pass the SPI IRQ down to the driver
  tpm: migrate tpm2_get_random() to use struct tpm_buf
  tpm: migrate tpm2_get_tpm_pt() to use struct tpm_buf
  tpm: migrate tpm2_probe() to use struct tpm_buf
  tpm: migrate tpm2_shutdown() to use struct tpm_buf
parents 04743f89 5da08f7d
Loading
Loading
Loading
Loading
+46 −22
Original line number Diff line number Diff line
@@ -81,43 +81,67 @@ void tpm_put_ops(struct tpm_chip *chip)
EXPORT_SYMBOL_GPL(tpm_put_ops);

/**
 * tpm_chip_find_get() - find and reserve a TPM chip
 * @chip:	a &struct tpm_chip instance, %NULL for the default chip
 *
 * Finds a TPM chip and reserves its class device and operations. The chip must
 * be released with tpm_chip_put_ops() after use.
 *
 * Return:
 * A reserved &struct tpm_chip instance.
 * %NULL if a chip is not found.
 * %NULL if the chip is not available.
 * tpm_default_chip() - find a TPM chip and get a reference to it
 */
struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip)
struct tpm_chip *tpm_default_chip(void)
{
	struct tpm_chip *res = NULL;
	struct tpm_chip *chip, *res = NULL;
	int chip_num = 0;
	int chip_prev;

	mutex_lock(&idr_lock);

	if (!chip) {
	do {
		chip_prev = chip_num;
		chip = idr_get_next(&dev_nums_idr, &chip_num);
			if (chip && !tpm_try_get_ops(chip)) {
		if (chip) {
			get_device(&chip->dev);
			res = chip;
			break;
		}
	} while (chip_prev != chip_num);
	} else {
		if (!tpm_try_get_ops(chip))
			res = chip;
	}

	mutex_unlock(&idr_lock);

	return res;
}
EXPORT_SYMBOL_GPL(tpm_default_chip);

/**
 * tpm_find_get_ops() - find and reserve a TPM chip
 * @chip:	a &struct tpm_chip instance, %NULL for the default chip
 *
 * Finds a TPM chip and reserves its class device and operations. The chip must
 * be released with tpm_put_ops() after use.
 * This function is for internal use only. It supports existing TPM callers
 * by accepting NULL, but those callers should be converted to pass in a chip
 * directly.
 *
 * Return:
 * A reserved &struct tpm_chip instance.
 * %NULL if a chip is not found.
 * %NULL if the chip is not available.
 */
struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip)
{
	int rc;

	if (chip) {
		if (!tpm_try_get_ops(chip))
			return chip;
		return NULL;
	}

	chip = tpm_default_chip();
	if (!chip)
		return NULL;
	rc = tpm_try_get_ops(chip);
	/* release additional reference we got from tpm_default_chip() */
	put_device(&chip->dev);
	if (rc)
		return NULL;
	return chip;
}

/**
 * tpm_dev_release() - free chip memory and the device number
+51 −21
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/freezer.h>
#include <linux/pm_runtime.h>
#include <linux/tpm_eventlog.h>

#include "tpm.h"
@@ -369,10 +368,13 @@ static int tpm_validate_command(struct tpm_chip *chip,
	return -EINVAL;
}

static int tpm_request_locality(struct tpm_chip *chip)
static int tpm_request_locality(struct tpm_chip *chip, unsigned int flags)
{
	int rc;

	if (flags & TPM_TRANSMIT_NESTED)
		return 0;

	if (!chip->ops->request_locality)
		return 0;

@@ -385,10 +387,13 @@ static int tpm_request_locality(struct tpm_chip *chip)
	return 0;
}

static void tpm_relinquish_locality(struct tpm_chip *chip)
static void tpm_relinquish_locality(struct tpm_chip *chip, unsigned int flags)
{
	int rc;

	if (flags & TPM_TRANSMIT_NESTED)
		return;

	if (!chip->ops->relinquish_locality)
		return;

@@ -399,6 +404,28 @@ static void tpm_relinquish_locality(struct tpm_chip *chip)
	chip->locality = -1;
}

static int tpm_cmd_ready(struct tpm_chip *chip, unsigned int flags)
{
	if (flags & TPM_TRANSMIT_NESTED)
		return 0;

	if (!chip->ops->cmd_ready)
		return 0;

	return chip->ops->cmd_ready(chip);
}

static int tpm_go_idle(struct tpm_chip *chip, unsigned int flags)
{
	if (flags & TPM_TRANSMIT_NESTED)
		return 0;

	if (!chip->ops->go_idle)
		return 0;

	return chip->ops->go_idle(chip);
}

static ssize_t tpm_try_transmit(struct tpm_chip *chip,
				struct tpm_space *space,
				u8 *buf, size_t bufsiz,
@@ -423,7 +450,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
		header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
		header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE |
						  TSS2_RESMGR_TPM_RC_LAYER);
		return bufsiz;
		return sizeof(*header);
	}

	if (bufsiz > TPM_BUFSIZE)
@@ -439,24 +466,24 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
		return -E2BIG;
	}

	if (!(flags & TPM_TRANSMIT_UNLOCKED))
	if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED))
		mutex_lock(&chip->tpm_mutex);


	if (chip->ops->clk_enable != NULL)
		chip->ops->clk_enable(chip, true);

	/* Store the decision as chip->locality will be changed. */
	need_locality = chip->locality == -1;

	if (!(flags & TPM_TRANSMIT_RAW) && need_locality) {
		rc = tpm_request_locality(chip);
	if (need_locality) {
		rc = tpm_request_locality(chip, flags);
		if (rc < 0)
			goto out_no_locality;
	}

	if (chip->dev.parent)
		pm_runtime_get_sync(chip->dev.parent);
	rc = tpm_cmd_ready(chip, flags);
	if (rc)
		goto out;

	rc = tpm2_prepare_space(chip, space, ordinal, buf);
	if (rc)
@@ -516,19 +543,22 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
	}

	rc = tpm2_commit_space(chip, space, ordinal, buf, &len);
	if (rc)
		dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc);

out:
	if (chip->dev.parent)
		pm_runtime_put_sync(chip->dev.parent);
	rc = tpm_go_idle(chip, flags);
	if (rc)
		goto out;

	if (need_locality)
		tpm_relinquish_locality(chip);
		tpm_relinquish_locality(chip, flags);

out_no_locality:
	if (chip->ops->clk_enable != NULL)
		chip->ops->clk_enable(chip, false);

	if (!(flags & TPM_TRANSMIT_UNLOCKED))
	if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED))
		mutex_unlock(&chip->tpm_mutex);
	return rc ? rc : len;
}
@@ -930,7 +960,7 @@ int tpm_is_tpm2(struct tpm_chip *chip)
{
	int rc;

	chip = tpm_chip_find_get(chip);
	chip = tpm_find_get_ops(chip);
	if (!chip)
		return -ENODEV;

@@ -954,7 +984,7 @@ int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
{
	int rc;

	chip = tpm_chip_find_get(chip);
	chip = tpm_find_get_ops(chip);
	if (!chip)
		return -ENODEV;
	if (chip->flags & TPM_CHIP_FLAG_TPM2)
@@ -1013,7 +1043,7 @@ int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
	u32 count = 0;
	int i;

	chip = tpm_chip_find_get(chip);
	chip = tpm_find_get_ops(chip);
	if (!chip)
		return -ENODEV;

@@ -1142,7 +1172,7 @@ int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen)
{
	int rc;

	chip = tpm_chip_find_get(chip);
	chip = tpm_find_get_ops(chip);
	if (!chip)
		return -ENODEV;

@@ -1262,7 +1292,7 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
	if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
		return -EINVAL;

	chip = tpm_chip_find_get(chip);
	chip = tpm_find_get_ops(chip);
	if (!chip)
		return -ENODEV;

@@ -1324,7 +1354,7 @@ int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload,
{
	int rc;

	chip = tpm_chip_find_get(chip);
	chip = tpm_find_get_ops(chip);
	if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2))
		return -ENODEV;

@@ -1352,7 +1382,7 @@ int tpm_unseal_trusted(struct tpm_chip *chip,
{
	int rc;

	chip = tpm_chip_find_get(chip);
	chip = tpm_find_get_ops(chip);
	if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2))
		return -ENODEV;

+20 −11
Original line number Diff line number Diff line
@@ -424,23 +424,24 @@ struct tpm_buf {
	u8 *data;
};

static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
	struct tpm_input_header *head;
	head = (struct tpm_input_header *)buf->data;
	head->tag = cpu_to_be16(tag);
	head->length = cpu_to_be32(sizeof(*head));
	head->ordinal = cpu_to_be32(ordinal);
}

static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
	buf->data_page = alloc_page(GFP_HIGHUSER);
	if (!buf->data_page)
		return -ENOMEM;

	buf->flags = 0;
	buf->data = kmap(buf->data_page);

	head = (struct tpm_input_header *) buf->data;

	head->tag = cpu_to_be16(tag);
	head->length = cpu_to_be32(sizeof(*head));
	head->ordinal = cpu_to_be32(ordinal);

	tpm_buf_reset(buf, tag, ordinal);
	return 0;
}

@@ -511,9 +512,17 @@ extern const struct file_operations tpm_fops;
extern const struct file_operations tpmrm_fops;
extern struct idr dev_nums_idr;

/**
 * enum tpm_transmit_flags - flags for tpm_transmit()
 *
 * @TPM_TRANSMIT_UNLOCKED:	do not lock the chip
 * @TPM_TRANSMIT_NESTED:	discard setup steps (power management,
 *				locality) including locking (i.e. implicit
 *				UNLOCKED)
 */
enum tpm_transmit_flags {
	TPM_TRANSMIT_UNLOCKED	= BIT(0),
	TPM_TRANSMIT_RAW	= BIT(1),
	TPM_TRANSMIT_NESTED      = BIT(1),
};

ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
@@ -538,7 +547,7 @@ static inline void tpm_msleep(unsigned int delay_msec)
		     delay_msec * 1000);
};

struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip);
struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip);
__must_check int tpm_try_get_ops(struct tpm_chip *chip);
void tpm_put_ops(struct tpm_chip *chip);

@@ -569,7 +578,7 @@ static inline u32 tpm2_rc_value(u32 rc)
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
		    struct tpm2_digest *digests);
int tpm2_get_random(struct tpm_chip *chip, u8 *out, 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,
			    unsigned int flags);
int tpm2_seal_trusted(struct tpm_chip *chip,
+106 −152
Original line number Diff line number Diff line
@@ -27,46 +27,6 @@ enum tpm2_session_attributes {
	TPM2_SA_CONTINUE_SESSION	= BIT(0),
};

struct tpm2_startup_in {
	__be16	startup_type;
} __packed;

struct tpm2_get_tpm_pt_in {
	__be32	cap_id;
	__be32	property_id;
	__be32	property_cnt;
} __packed;

struct tpm2_get_tpm_pt_out {
	u8	more_data;
	__be32	subcap_id;
	__be32	property_cnt;
	__be32	property_id;
	__be32	value;
} __packed;

struct tpm2_get_random_in {
	__be16	size;
} __packed;

struct tpm2_get_random_out {
	__be16	size;
	u8	buffer[TPM_MAX_RNG_DATA];
} __packed;

union tpm2_cmd_params {
	struct	tpm2_startup_in		startup_in;
	struct	tpm2_get_tpm_pt_in	get_tpm_pt_in;
	struct	tpm2_get_tpm_pt_out	get_tpm_pt_out;
	struct	tpm2_get_random_in	getrandom_in;
	struct	tpm2_get_random_out	getrandom_out;
};

struct tpm2_cmd {
	tpm_cmd_header		header;
	union tpm2_cmd_params	params;
} __packed;

struct tpm2_hash {
	unsigned int crypto_id;
	unsigned int tpm_id;
@@ -321,82 +281,72 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
}


#define TPM2_GETRANDOM_IN_SIZE \
	(sizeof(struct tpm_input_header) + \
	 sizeof(struct tpm2_get_random_in))

static const struct tpm_input_header tpm2_getrandom_header = {
	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
	.length = cpu_to_be32(TPM2_GETRANDOM_IN_SIZE),
	.ordinal = cpu_to_be32(TPM2_CC_GET_RANDOM)
};
struct tpm2_get_random_out {
	__be16 size;
	u8 buffer[TPM_MAX_RNG_DATA];
} __packed;

/**
 * tpm2_get_random() - get random bytes from the TPM RNG
 *
 * @chip: TPM chip to use
 * @out: destination buffer for the random bytes
 * @max: the max number of bytes to write to @out
 * @chip:	a &tpm_chip instance
 * @dest:	destination buffer
 * @max:	the max number of random bytes to pull
 *
 * Return:
 *    Size of the output buffer, or -EIO on error.
 *   size of the buffer on success,
 *   -errno otherwise
 */
int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
	struct tpm2_cmd cmd;
	u32 recd, rlength;
	u32 num_bytes;
	struct tpm2_get_random_out *out;
	struct tpm_buf buf;
	u32 recd;
	u32 num_bytes = max;
	int err;
	int total = 0;
	int retries = 5;
	u8 *dest = out;

	num_bytes = min_t(u32, max, sizeof(cmd.params.getrandom_out.buffer));
	u8 *dest_ptr = dest;

	if (!out || !num_bytes ||
	    max > sizeof(cmd.params.getrandom_out.buffer))
	if (!num_bytes || max > TPM_MAX_RNG_DATA)
		return -EINVAL;

	do {
		cmd.header.in = tpm2_getrandom_header;
		cmd.params.getrandom_in.size = cpu_to_be16(num_bytes);
	err = tpm_buf_init(&buf, 0, 0);
	if (err)
		return err;

		err = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd),
	do {
		tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM);
		tpm_buf_append_u16(&buf, num_bytes);
		err = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
				       offsetof(struct tpm2_get_random_out,
						buffer),
				       0, "attempting get random");
		if (err)
			break;
			goto out;

		recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size),
			     num_bytes);
		rlength = be32_to_cpu(cmd.header.out.length);
		if (rlength < offsetof(struct tpm2_get_random_out, buffer) +
			      recd)
			return -EFAULT;
		memcpy(dest, cmd.params.getrandom_out.buffer, recd);
		out = (struct tpm2_get_random_out *)
			&buf.data[TPM_HEADER_SIZE];
		recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
		if (tpm_buf_length(&buf) <
		    offsetof(struct tpm2_get_random_out, buffer) + recd) {
			err = -EFAULT;
			goto out;
		}
		memcpy(dest_ptr, out->buffer, recd);

		dest += recd;
		dest_ptr += recd;
		total += recd;
		num_bytes -= recd;
	} while (retries-- && total < max);

	tpm_buf_destroy(&buf);
	return total ? total : -EIO;
out:
	tpm_buf_destroy(&buf);
	return err;
}

#define TPM2_GET_TPM_PT_IN_SIZE \
	(sizeof(struct tpm_input_header) + \
	 sizeof(struct tpm2_get_tpm_pt_in))

#define TPM2_GET_TPM_PT_OUT_BODY_SIZE \
	 sizeof(struct tpm2_get_tpm_pt_out)

static const struct tpm_input_header tpm2_get_tpm_pt_header = {
	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
	.length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE),
	.ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY)
};

/**
 * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
 * @chip: TPM chip to use
@@ -471,7 +421,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
{
	unsigned int blob_len;
	struct tpm_buf buf;
	u32 hash, rlength;
	u32 hash;
	int i;
	int rc;

@@ -546,8 +496,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
		rc = -E2BIG;
		goto out;
	}
	rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)->header.out.length);
	if (rlength < TPM_HEADER_SIZE + 4 + blob_len) {
	if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 4 + blob_len) {
		rc = -EFAULT;
		goto out;
	}
@@ -657,7 +606,6 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
	u16 data_len;
	u8 *data;
	int rc;
	u32 rlength;

	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
	if (rc)
@@ -685,9 +633,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
			goto out;
		}

		rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)
					->header.out.length);
		if (rlength < TPM_HEADER_SIZE + 6 + data_len) {
		if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) {
			rc = -EFAULT;
			goto out;
		}
@@ -733,69 +679,71 @@ int tpm2_unseal_trusted(struct tpm_chip *chip,
	return rc;
}

struct tpm2_get_cap_out {
	u8 more_data;
	__be32 subcap_id;
	__be32 property_cnt;
	__be32 property_id;
	__be32 value;
} __packed;

/**
 * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property
 * @chip:		TPM chip to use.
 * @chip:		a &tpm_chip instance
 * @property_id:	property ID.
 * @value:		output variable.
 * @desc:		passed to tpm_transmit_cmd()
 *
 * Return: Same as with tpm_transmit_cmd.
 * Return:
 *   0 on success,
 *   -errno or a TPM return code otherwise
 */
ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,  u32 *value,
			const char *desc)
{
	struct tpm2_cmd cmd;
	struct tpm2_get_cap_out *out;
	struct tpm_buf buf;
	int rc;

	cmd.header.in = tpm2_get_tpm_pt_header;
	cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES);
	cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id);
	cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);

	rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd),
			      TPM2_GET_TPM_PT_OUT_BODY_SIZE, 0, desc);
	if (!rc)
		*value = be32_to_cpu(cmd.params.get_tpm_pt_out.value);

	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
	if (rc)
		return rc;
	tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
	tpm_buf_append_u32(&buf, property_id);
	tpm_buf_append_u32(&buf, 1);
	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, NULL);
	if (!rc) {
		out = (struct tpm2_get_cap_out *)
			&buf.data[TPM_HEADER_SIZE];
		*value = be32_to_cpu(out->value);
	}
	tpm_buf_destroy(&buf);
	return rc;
}
EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);

#define TPM2_SHUTDOWN_IN_SIZE \
	(sizeof(struct tpm_input_header) + \
	 sizeof(struct tpm2_startup_in))

static const struct tpm_input_header tpm2_shutdown_header = {
	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
	.length = cpu_to_be32(TPM2_SHUTDOWN_IN_SIZE),
	.ordinal = cpu_to_be32(TPM2_CC_SHUTDOWN)
};

/**
 * tpm2_shutdown() - send shutdown command to the TPM chip
 * tpm2_shutdown() - send a TPM shutdown command
 *
 * @chip:		TPM chip to use.
 * @shutdown_type:	shutdown type. The value is either
 *			TPM_SU_CLEAR or TPM_SU_STATE.
 * Sends a TPM shutdown command. The shutdown command is used in call
 * sites where the system is going down. If it fails, there is not much
 * that can be done except print an error message.
 *
 * @chip:		a &tpm_chip instance
 * @shutdown_type:	TPM_SU_CLEAR or TPM_SU_STATE.
 */
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
{
	struct tpm2_cmd cmd;
	struct tpm_buf buf;
	int rc;

	cmd.header.in = tpm2_shutdown_header;
	cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);

	rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0,
	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
	if (rc)
		return;
	tpm_buf_append_u16(&buf, shutdown_type);
	tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
			 "stopping the TPM");

	/* In places where shutdown command is sent there's no much we can do
	 * except print the error code on a system failure.
	 */
	if (rc < 0 && rc != -EPIPE)
		dev_warn(&chip->dev, "transmit returned %d while stopping the TPM",
			 rc);
	tpm_buf_destroy(&buf);
}

/*
@@ -863,31 +811,37 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
}

/**
 * tpm2_probe() - probe TPM 2.0
 * @chip: TPM chip to use
 * tpm2_probe() - probe for the TPM 2.0 protocol
 * @chip:	a &tpm_chip instance
 *
 * Return: < 0 error and 0 on success.
 * Send an idempotent TPM 2.0 command and see whether there is TPM2 chip in the
 * other end based on the response tag. The flag TPM_CHIP_FLAG_TPM2 is set by
 * this function if this is the case.
 *
 * Send idempotent TPM 2.0 command and see whether TPM 2.0 chip replied based on
 * the reply tag.
 * Return:
 *   0 on success,
 *   -errno otherwise
 */
int tpm2_probe(struct tpm_chip *chip)
{
	struct tpm2_cmd cmd;
	struct tpm_output_header *out;
	struct tpm_buf buf;
	int rc;

	cmd.header.in = tpm2_get_tpm_pt_header;
	cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES);
	cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100);
	cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);

	rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0, NULL);
	if (rc <  0)
	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
	if (rc)
		return rc;

	if (be16_to_cpu(cmd.header.out.tag) == TPM2_ST_NO_SESSIONS)
	tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
	tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
	tpm_buf_append_u32(&buf, 1);
	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, NULL);
	/* We ignore TPM return codes on purpose. */
	if (rc >=  0) {
		out = (struct tpm_output_header *)buf.data;
		if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
			chip->flags |= TPM_CHIP_FLAG_TPM2;

	}
	tpm_buf_destroy(&buf);
	return 0;
}
EXPORT_SYMBOL_GPL(tpm2_probe);
+6 −6
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
	for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
		if (space->session_tbl[i])
			tpm2_flush_context_cmd(chip, space->session_tbl[i],
					       TPM_TRANSMIT_UNLOCKED);
					       TPM_TRANSMIT_NESTED);
	}
}

@@ -84,7 +84,7 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
	tpm_buf_append(&tbuf, &buf[*offset], body_size);

	rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4,
			      TPM_TRANSMIT_UNLOCKED, NULL);
			      TPM_TRANSMIT_NESTED, NULL);
	if (rc < 0) {
		dev_warn(&chip->dev, "%s: failed with a system error %d\n",
			 __func__, rc);
@@ -133,7 +133,7 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
	tpm_buf_append_u32(&tbuf, handle);

	rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0,
			      TPM_TRANSMIT_UNLOCKED, NULL);
			      TPM_TRANSMIT_NESTED, NULL);
	if (rc < 0) {
		dev_warn(&chip->dev, "%s: failed with a system error %d\n",
			 __func__, rc);
@@ -170,7 +170,7 @@ static void tpm2_flush_space(struct tpm_chip *chip)
	for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
		if (space->context_tbl[i] && ~space->context_tbl[i])
			tpm2_flush_context_cmd(chip, space->context_tbl[i],
					       TPM_TRANSMIT_UNLOCKED);
					       TPM_TRANSMIT_NESTED);

	tpm2_flush_sessions(chip, space);
}
@@ -377,7 +377,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,

	return 0;
out_no_slots:
	tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_UNLOCKED);
	tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_NESTED);
	dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
		 phandle);
	return -ENOMEM;
@@ -465,7 +465,7 @@ static int tpm2_save_space(struct tpm_chip *chip)
			return rc;

		tpm2_flush_context_cmd(chip, space->context_tbl[i],
				       TPM_TRANSMIT_UNLOCKED);
				       TPM_TRANSMIT_NESTED);
		space->context_tbl[i] = ~0;
	}

Loading