drivers/char/tpm/tpm2-space.c

Source file repositories/reference/linux-study-clean/drivers/char/tpm/tpm2-space.c

File Facts

System
Linux kernel
Corpus path
drivers/char/tpm/tpm2-space.c
Extension
.c
Size
14933 bytes
Lines
648
Domain
Driver Families
Bucket
drivers/char
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct tpm2_context {
	__be64 sequence;
	__be32 saved_handle;
	__be32 hierarchy;
	__be16 blob_size;
} __packed;

static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
		if (space->session_tbl[i])
			tpm2_flush_context(chip, space->session_tbl[i]);
	}
}

int tpm2_init_space(struct tpm_space *space, unsigned int buf_size)
{
	space->context_buf = kzalloc(buf_size, GFP_KERNEL);
	if (!space->context_buf)
		return -ENOMEM;

	space->session_buf = kzalloc(buf_size, GFP_KERNEL);
	if (space->session_buf == NULL) {
		kfree(space->context_buf);
		/* Prevent caller getting a dangling pointer. */
		space->context_buf = NULL;
		return -ENOMEM;
	}

	space->buf_size = buf_size;
	return 0;
}

void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
{

	if (tpm_try_get_ops(chip) == 0) {
		tpm2_flush_sessions(chip, space);
		tpm_put_ops(chip);
	}

	kfree(space->context_buf);
	kfree(space->session_buf);
}

int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
		      unsigned int *offset, u32 *handle)
{
	struct tpm_buf tbuf;
	struct tpm2_context *ctx;
	unsigned int body_size;
	int rc;

	rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
	if (rc)
		return rc;

	ctx = (struct tpm2_context *)&buf[*offset];
	body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
	tpm_buf_append(&tbuf, &buf[*offset], body_size);

	rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
	if (rc < 0) {
		dev_warn(&chip->dev, "%s: failed with a system error %d\n",
			 __func__, rc);
		tpm_buf_destroy(&tbuf);
		return -EFAULT;
	} else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
		   rc == TPM2_RC_REFERENCE_H0) {
		/*
		 * TPM_RC_HANDLE means that the session context can't
		 * be loaded because of an internal counter mismatch
		 * that makes the TPM think there might have been a
		 * replay.  This might happen if the context was saved
		 * and loaded outside the space.
		 *
		 * TPM_RC_REFERENCE_H0 means the session has been
		 * flushed outside the space
		 */
		*handle = 0;
		tpm_buf_destroy(&tbuf);
		return -ENOENT;
	} else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) {
		tpm_buf_destroy(&tbuf);
		return -EINVAL;
	} else if (rc > 0) {
		dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
			 __func__, rc);

Annotation

Implementation Notes