aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiandi An <anjiandi@codeaurora.org>2017-03-24 05:55:45 -0400
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>2017-04-03 15:46:03 -0400
commit08eff49d63ca2bf4cd98c4bdc07dc9d07d52f8f5 (patch)
tree69be09a53bd37b9743e580c508f9331f4ca669e0
parentcf8252ca7ca76fa47acf29b717bd52b738538c1e (diff)
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: Jiandi An <anjiandi@codeaurora.org> Tested-by: Shanker Donthineni <shankerd@codeaurora.org> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> (on x86/PTT) Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
-rw-r--r--drivers/char/tpm/Kconfig2
-rw-r--r--drivers/char/tpm/tpm_crb.c67
2 files changed, 66 insertions, 3 deletions
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index d520ac51c11c..a30352202f1f 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -136,7 +136,7 @@ config TCG_XEN
136 136
137config TCG_CRB 137config TCG_CRB
138 tristate "TPM 2.0 CRB Interface" 138 tristate "TPM 2.0 CRB Interface"
139 depends on X86 && ACPI 139 depends on ACPI
140 ---help--- 140 ---help---
141 If you have a TPM security chip that is compliant with the 141 If you have a TPM security chip that is compliant with the
142 TCG CRB 2.0 TPM specification say Yes and it will be accessible 142 TCG CRB 2.0 TPM specification say Yes and it will be accessible
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index d91e47dc2d79..72b03c328198 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -20,6 +20,9 @@
20#include <linux/rculist.h> 20#include <linux/rculist.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/pm_runtime.h> 22#include <linux/pm_runtime.h>
23#ifdef CONFIG_ARM64
24#include <linux/arm-smccc.h>
25#endif
23#include "tpm.h" 26#include "tpm.h"
24 27
25#define ACPI_SIG_TPM2 "TPM2" 28#define ACPI_SIG_TPM2 "TPM2"
@@ -93,6 +96,7 @@ enum crb_status {
93enum crb_flags { 96enum crb_flags {
94 CRB_FL_ACPI_START = BIT(0), 97 CRB_FL_ACPI_START = BIT(0),
95 CRB_FL_CRB_START = BIT(1), 98 CRB_FL_CRB_START = BIT(1),
99 CRB_FL_CRB_SMC_START = BIT(2),
96}; 100};
97 101
98struct crb_priv { 102struct crb_priv {
@@ -103,6 +107,15 @@ struct crb_priv {
103 u8 __iomem *cmd; 107 u8 __iomem *cmd;
104 u8 __iomem *rsp; 108 u8 __iomem *rsp;
105 u32 cmd_size; 109 u32 cmd_size;
110 u32 smc_func_id;
111};
112
113struct tpm2_crb_smc {
114 u32 interrupt;
115 u8 interrupt_flags;
116 u8 op_flags;
117 u16 reserved2;
118 u32 smc_func_id;
106}; 119};
107 120
108/** 121/**
@@ -122,7 +135,8 @@ struct crb_priv {
122 */ 135 */
123static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) 136static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv)
124{ 137{
125 if (priv->flags & CRB_FL_ACPI_START) 138 if ((priv->flags & CRB_FL_ACPI_START) ||
139 (priv->flags & CRB_FL_CRB_SMC_START))
126 return 0; 140 return 0;
127 141
128 iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req); 142 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,
167static int __maybe_unused crb_cmd_ready(struct device *dev, 181static int __maybe_unused crb_cmd_ready(struct device *dev,
168 struct crb_priv *priv) 182 struct crb_priv *priv)
169{ 183{
170 if (priv->flags & CRB_FL_ACPI_START) 184 if ((priv->flags & CRB_FL_ACPI_START) ||
185 (priv->flags & CRB_FL_CRB_SMC_START))
171 return 0; 186 return 0;
172 187
173 iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req); 188 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 return rc; 277 return rc;
263} 278}
264 279
280#ifdef CONFIG_ARM64
281/*
282 * This is a TPM Command Response Buffer start method that invokes a
283 * Secure Monitor Call to requrest the firmware to execute or cancel
284 * a TPM 2.0 command.
285 */
286static int tpm_crb_smc_start(struct device *dev, unsigned long func_id)
287{
288 struct arm_smccc_res res;
289
290 arm_smccc_smc(func_id, 0, 0, 0, 0, 0, 0, 0, &res);
291 if (res.a0 != 0) {
292 dev_err(dev,
293 FW_BUG "tpm_crb_smc_start() returns res.a0 = 0x%lx\n",
294 res.a0);
295 return -EIO;
296 }
297
298 return 0;
299}
300#else
301static int tpm_crb_smc_start(struct device *dev, unsigned long func_id)
302{
303 dev_err(dev, FW_BUG "tpm_crb: incorrect start method\n");
304 return -EINVAL;
305}
306#endif
307
265static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) 308static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
266{ 309{
267 struct crb_priv *priv = dev_get_drvdata(&chip->dev); 310 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 if (priv->flags & CRB_FL_ACPI_START) 332 if (priv->flags & CRB_FL_ACPI_START)
290 rc = crb_do_acpi_start(chip); 333 rc = crb_do_acpi_start(chip);
291 334
335 if (priv->flags & CRB_FL_CRB_SMC_START) {
336 iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start);
337 rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id);
338 }
339
292 return rc; 340 return rc;
293} 341}
294 342
@@ -483,6 +531,7 @@ static int crb_acpi_add(struct acpi_device *device)
483 struct crb_priv *priv; 531 struct crb_priv *priv;
484 struct tpm_chip *chip; 532 struct tpm_chip *chip;
485 struct device *dev = &device->dev; 533 struct device *dev = &device->dev;
534 struct tpm2_crb_smc *crb_smc;
486 acpi_status status; 535 acpi_status status;
487 u32 sm; 536 u32 sm;
488 int rc; 537 int rc;
@@ -515,6 +564,20 @@ static int crb_acpi_add(struct acpi_device *device)
515 sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) 564 sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)
516 priv->flags |= CRB_FL_ACPI_START; 565 priv->flags |= CRB_FL_ACPI_START;
517 566
567 if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_SMC) {
568 if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) {
569 dev_err(dev,
570 FW_BUG "TPM2 ACPI table has wrong size %u for start method type %d\n",
571 buf->header.length,
572 ACPI_TPM2_COMMAND_BUFFER_WITH_SMC);
573 return -EINVAL;
574 }
575 crb_smc = ACPI_ADD_PTR(struct tpm2_crb_smc, buf,
576 ACPI_TPM2_START_METHOD_PARAMETER_OFFSET);
577 priv->smc_func_id = crb_smc->smc_func_id;
578 priv->flags |= CRB_FL_CRB_SMC_START;
579 }
580
518 rc = crb_map_io(device, priv, buf); 581 rc = crb_map_io(device, priv, buf);
519 if (rc) 582 if (rc)
520 return rc; 583 return rc;