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

Commit 08eff49d authored by Jiandi An's avatar Jiandi An Committed by Jarkko Sakkinen
Browse files

tpm/tpm_crb: Enable TPM CRB interface for ARM64



This enables TPM Command Response Buffer interface driver for
ARM64 and implements an ARM specific TPM CRB start method that
invokes a Secure Monitor Call (SMC) to request the TrustZone
Firmware to execute or cancel a TPM 2.0 command.

In ARM, TrustZone security extensions enable a secure software
environment with Secure Monitor mode.  A Secure Monitor Call
(SMC) is used to enter the Secure Monitor mode and perform a
Secure Monitor service to communicate with TrustZone firmware
which has control over the TPM hardware.

Signed-off-by: default avatarJiandi An <anjiandi@codeaurora.org>
Tested-by: default avatarShanker Donthineni <shankerd@codeaurora.org>
Reviewed-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> (on x86/PTT)
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
parent cf8252ca
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -136,7 +136,7 @@ config TCG_XEN


config TCG_CRB
config TCG_CRB
	tristate "TPM 2.0 CRB Interface"
	tristate "TPM 2.0 CRB Interface"
	depends on X86 && ACPI
	depends on ACPI
	---help---
	---help---
	  If you have a TPM security chip that is compliant with the
	  If you have a TPM security chip that is compliant with the
	  TCG CRB 2.0 TPM specification say Yes and it will be accessible
	  TCG CRB 2.0 TPM specification say Yes and it will be accessible
+65 −2
Original line number Original line Diff line number Diff line
@@ -20,6 +20,9 @@
#include <linux/rculist.h>
#include <linux/rculist.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/pm_runtime.h>
#ifdef CONFIG_ARM64
#include <linux/arm-smccc.h>
#endif
#include "tpm.h"
#include "tpm.h"


#define ACPI_SIG_TPM2 "TPM2"
#define ACPI_SIG_TPM2 "TPM2"
@@ -93,6 +96,7 @@ enum crb_status {
enum crb_flags {
enum crb_flags {
	CRB_FL_ACPI_START	= BIT(0),
	CRB_FL_ACPI_START	= BIT(0),
	CRB_FL_CRB_START	= BIT(1),
	CRB_FL_CRB_START	= BIT(1),
	CRB_FL_CRB_SMC_START	= BIT(2),
};
};


struct crb_priv {
struct crb_priv {
@@ -103,6 +107,15 @@ struct crb_priv {
	u8 __iomem *cmd;
	u8 __iomem *cmd;
	u8 __iomem *rsp;
	u8 __iomem *rsp;
	u32 cmd_size;
	u32 cmd_size;
	u32 smc_func_id;
};

struct tpm2_crb_smc {
	u32 interrupt;
	u8 interrupt_flags;
	u8 op_flags;
	u16 reserved2;
	u32 smc_func_id;
};
};


/**
/**
@@ -122,7 +135,8 @@ struct crb_priv {
 */
 */
static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv)
static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv)
{
{
	if (priv->flags & CRB_FL_ACPI_START)
	if ((priv->flags & CRB_FL_ACPI_START) ||
	    (priv->flags & CRB_FL_CRB_SMC_START))
		return 0;
		return 0;


	iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req);
	iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req);
@@ -167,7 +181,8 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
static int __maybe_unused crb_cmd_ready(struct device *dev,
static int __maybe_unused crb_cmd_ready(struct device *dev,
					struct crb_priv *priv)
					struct crb_priv *priv)
{
{
	if (priv->flags & CRB_FL_ACPI_START)
	if ((priv->flags & CRB_FL_ACPI_START) ||
	    (priv->flags & CRB_FL_CRB_SMC_START))
		return 0;
		return 0;


	iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req);
	iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req);
@@ -262,6 +277,34 @@ static int crb_do_acpi_start(struct tpm_chip *chip)
	return rc;
	return rc;
}
}


#ifdef CONFIG_ARM64
/*
 * This is a TPM Command Response Buffer start method that invokes a
 * Secure Monitor Call to requrest the firmware to execute or cancel
 * a TPM 2.0 command.
 */
static int tpm_crb_smc_start(struct device *dev, unsigned long func_id)
{
	struct arm_smccc_res res;

	arm_smccc_smc(func_id, 0, 0, 0, 0, 0, 0, 0, &res);
	if (res.a0 != 0) {
		dev_err(dev,
			FW_BUG "tpm_crb_smc_start() returns res.a0 = 0x%lx\n",
			res.a0);
		return -EIO;
	}

	return 0;
}
#else
static int tpm_crb_smc_start(struct device *dev, unsigned long func_id)
{
	dev_err(dev, FW_BUG "tpm_crb: incorrect start method\n");
	return -EINVAL;
}
#endif

static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
{
{
	struct crb_priv *priv = dev_get_drvdata(&chip->dev);
	struct crb_priv *priv = dev_get_drvdata(&chip->dev);
@@ -289,6 +332,11 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
	if (priv->flags & CRB_FL_ACPI_START)
	if (priv->flags & CRB_FL_ACPI_START)
		rc = crb_do_acpi_start(chip);
		rc = crb_do_acpi_start(chip);


	if (priv->flags & CRB_FL_CRB_SMC_START) {
		iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start);
		rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id);
	}

	return rc;
	return rc;
}
}


@@ -483,6 +531,7 @@ static int crb_acpi_add(struct acpi_device *device)
	struct crb_priv *priv;
	struct crb_priv *priv;
	struct tpm_chip *chip;
	struct tpm_chip *chip;
	struct device *dev = &device->dev;
	struct device *dev = &device->dev;
	struct tpm2_crb_smc *crb_smc;
	acpi_status status;
	acpi_status status;
	u32 sm;
	u32 sm;
	int rc;
	int rc;
@@ -515,6 +564,20 @@ static int crb_acpi_add(struct acpi_device *device)
	    sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)
	    sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)
		priv->flags |= CRB_FL_ACPI_START;
		priv->flags |= CRB_FL_ACPI_START;


	if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_SMC) {
		if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) {
			dev_err(dev,
				FW_BUG "TPM2 ACPI table has wrong size %u for start method type %d\n",
				buf->header.length,
				ACPI_TPM2_COMMAND_BUFFER_WITH_SMC);
			return -EINVAL;
		}
		crb_smc = ACPI_ADD_PTR(struct tpm2_crb_smc, buf,
				       ACPI_TPM2_START_METHOD_PARAMETER_OFFSET);
		priv->smc_func_id = crb_smc->smc_func_id;
		priv->flags |= CRB_FL_CRB_SMC_START;
	}

	rc = crb_map_io(device, priv, buf);
	rc = crb_map_io(device, priv, buf);
	if (rc)
	if (rc)
		return rc;
		return rc;