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

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
...@@ -136,7 +136,7 @@ config TCG_XEN ...@@ -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
......
...@@ -20,6 +20,9 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
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