diff options
author | Jiandi An <anjiandi@codeaurora.org> | 2017-03-24 05:55:45 -0400 |
---|---|---|
committer | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> | 2017-04-03 15:46:03 -0400 |
commit | 08eff49d63ca2bf4cd98c4bdc07dc9d07d52f8f5 (patch) | |
tree | 69be09a53bd37b9743e580c508f9331f4ca669e0 | |
parent | cf8252ca7ca76fa47acf29b717bd52b738538c1e (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/Kconfig | 2 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_crb.c | 67 |
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 | ||
137 | config TCG_CRB | 137 | config 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 { | |||
93 | enum crb_flags { | 96 | enum 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 | ||
98 | struct crb_priv { | 102 | struct 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 | |||
113 | struct 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 | */ |
123 | static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) | 136 | static 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, | |||
167 | static int __maybe_unused crb_cmd_ready(struct device *dev, | 181 | static 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 | */ | ||
286 | static 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 | ||
301 | static 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 | |||
265 | static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) | 308 | static 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; |