Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Jiandi An and committed by
Jarkko Sakkinen
08eff49d cf8252ca

+66 -3
+1 -1
drivers/char/tpm/Kconfig
··· 136 136 137 137 config TCG_CRB 138 138 tristate "TPM 2.0 CRB Interface" 139 - depends on X86 && ACPI 139 + depends on ACPI 140 140 ---help--- 141 141 If you have a TPM security chip that is compliant with the 142 142 TCG CRB 2.0 TPM specification say Yes and it will be accessible
+65 -2
drivers/char/tpm/tpm_crb.c
··· 20 20 #include <linux/rculist.h> 21 21 #include <linux/module.h> 22 22 #include <linux/pm_runtime.h> 23 + #ifdef CONFIG_ARM64 24 + #include <linux/arm-smccc.h> 25 + #endif 23 26 #include "tpm.h" 24 27 25 28 #define ACPI_SIG_TPM2 "TPM2" ··· 96 93 enum crb_flags { 97 94 CRB_FL_ACPI_START = BIT(0), 98 95 CRB_FL_CRB_START = BIT(1), 96 + CRB_FL_CRB_SMC_START = BIT(2), 99 97 }; 100 98 101 99 struct crb_priv { ··· 107 103 u8 __iomem *cmd; 108 104 u8 __iomem *rsp; 109 105 u32 cmd_size; 106 + u32 smc_func_id; 107 + }; 108 + 109 + struct tpm2_crb_smc { 110 + u32 interrupt; 111 + u8 interrupt_flags; 112 + u8 op_flags; 113 + u16 reserved2; 114 + u32 smc_func_id; 110 115 }; 111 116 112 117 /** ··· 135 122 */ 136 123 static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) 137 124 { 138 - if (priv->flags & CRB_FL_ACPI_START) 125 + if ((priv->flags & CRB_FL_ACPI_START) || 126 + (priv->flags & CRB_FL_CRB_SMC_START)) 139 127 return 0; 140 128 141 129 iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req); ··· 181 167 static int __maybe_unused crb_cmd_ready(struct device *dev, 182 168 struct crb_priv *priv) 183 169 { 184 - if (priv->flags & CRB_FL_ACPI_START) 170 + if ((priv->flags & CRB_FL_ACPI_START) || 171 + (priv->flags & CRB_FL_CRB_SMC_START)) 185 172 return 0; 186 173 187 174 iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req); ··· 277 262 return rc; 278 263 } 279 264 265 + #ifdef CONFIG_ARM64 266 + /* 267 + * This is a TPM Command Response Buffer start method that invokes a 268 + * Secure Monitor Call to requrest the firmware to execute or cancel 269 + * a TPM 2.0 command. 270 + */ 271 + static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) 272 + { 273 + struct arm_smccc_res res; 274 + 275 + arm_smccc_smc(func_id, 0, 0, 0, 0, 0, 0, 0, &res); 276 + if (res.a0 != 0) { 277 + dev_err(dev, 278 + FW_BUG "tpm_crb_smc_start() returns res.a0 = 0x%lx\n", 279 + res.a0); 280 + return -EIO; 281 + } 282 + 283 + return 0; 284 + } 285 + #else 286 + static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) 287 + { 288 + dev_err(dev, FW_BUG "tpm_crb: incorrect start method\n"); 289 + return -EINVAL; 290 + } 291 + #endif 292 + 280 293 static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) 281 294 { 282 295 struct crb_priv *priv = dev_get_drvdata(&chip->dev); ··· 331 288 332 289 if (priv->flags & CRB_FL_ACPI_START) 333 290 rc = crb_do_acpi_start(chip); 291 + 292 + if (priv->flags & CRB_FL_CRB_SMC_START) { 293 + iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); 294 + rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); 295 + } 334 296 335 297 return rc; 336 298 } ··· 531 483 struct crb_priv *priv; 532 484 struct tpm_chip *chip; 533 485 struct device *dev = &device->dev; 486 + struct tpm2_crb_smc *crb_smc; 534 487 acpi_status status; 535 488 u32 sm; 536 489 int rc; ··· 563 514 if (sm == ACPI_TPM2_START_METHOD || 564 515 sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) 565 516 priv->flags |= CRB_FL_ACPI_START; 517 + 518 + if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_SMC) { 519 + if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) { 520 + dev_err(dev, 521 + FW_BUG "TPM2 ACPI table has wrong size %u for start method type %d\n", 522 + buf->header.length, 523 + ACPI_TPM2_COMMAND_BUFFER_WITH_SMC); 524 + return -EINVAL; 525 + } 526 + crb_smc = ACPI_ADD_PTR(struct tpm2_crb_smc, buf, 527 + ACPI_TPM2_START_METHOD_PARAMETER_OFFSET); 528 + priv->smc_func_id = crb_smc->smc_func_id; 529 + priv->flags |= CRB_FL_CRB_SMC_START; 530 + } 566 531 567 532 rc = crb_map_io(device, priv, buf); 568 533 if (rc)