Skip to content

Commit 4d27328

Browse files
mjg59jarkkojs
authored andcommitted
tpm_crb: Add support for CRB devices based on Pluton
Pluton is an integrated security processor present in some recent Ryzen parts. If it's enabled, it presents two devices - an MSFT0101 ACPI device that's broadly an implementation of a Command Response Buffer TPM2, and an MSFT0200 ACPI device whose functionality I haven't examined in detail yet. This patch only attempts to add support for the TPM device. There's a few things that need to be handled here. The first is that the TPM2 ACPI table uses a previously undefined start method identifier. The table format appears to include 16 bytes of startup data, which corresponds to one 64-bit address for a start message and one 64-bit address for a completion response. The second is that the ACPI tables on the Thinkpad Z13 I'm testing this on don't define any memory windows in _CRS (or, more accurately, there are two empty memory windows). This check doesn't seem strictly necessary, so I've skipped that. Finally, it seems like chip needs to be explicitly asked to transition into ready status on every command. Failing to do this means that if two commands are sent in succession without an idle/ready transition in between, everything will appear to work fine but the response is simply the original command. I'm working without any docs here, so I'm not sure if this is actually the required behaviour or if I'm missing something somewhere else, but doing this results in the chip working reliably. Reviewed-by: Jarkko Sakkinen <[email protected]> Signed-off-by: Matthew Garrett <[email protected]> Signed-off-by: Jarkko Sakkinen <[email protected]>
1 parent 0f5d4a0 commit 4d27328

File tree

2 files changed

+91
-10
lines changed

2 files changed

+91
-10
lines changed

drivers/char/tpm/tpm_crb.c

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ struct crb_priv {
9898
u8 __iomem *rsp;
9999
u32 cmd_size;
100100
u32 smc_func_id;
101+
u32 __iomem *pluton_start_addr;
102+
u32 __iomem *pluton_reply_addr;
101103
};
102104

103105
struct tpm2_crb_smc {
@@ -108,6 +110,11 @@ struct tpm2_crb_smc {
108110
u32 smc_func_id;
109111
};
110112

113+
struct tpm2_crb_pluton {
114+
u64 start_addr;
115+
u64 reply_addr;
116+
};
117+
111118
static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
112119
unsigned long timeout)
113120
{
@@ -127,6 +134,25 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
127134
return ((ioread32(reg) & mask) == value);
128135
}
129136

137+
static int crb_try_pluton_doorbell(struct crb_priv *priv, bool wait_for_complete)
138+
{
139+
if (priv->sm != ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON)
140+
return 0;
141+
142+
if (!crb_wait_for_reg_32(priv->pluton_reply_addr, ~0, 1, TPM2_TIMEOUT_C))
143+
return -ETIME;
144+
145+
iowrite32(1, priv->pluton_start_addr);
146+
if (wait_for_complete == false)
147+
return 0;
148+
149+
if (!crb_wait_for_reg_32(priv->pluton_start_addr,
150+
0xffffffff, 0, 200))
151+
return -ETIME;
152+
153+
return 0;
154+
}
155+
130156
/**
131157
* __crb_go_idle - request tpm crb device to go the idle state
132158
*
@@ -145,13 +171,19 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
145171
*/
146172
static int __crb_go_idle(struct device *dev, struct crb_priv *priv)
147173
{
174+
int rc;
175+
148176
if ((priv->sm == ACPI_TPM2_START_METHOD) ||
149177
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
150178
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC))
151179
return 0;
152180

153181
iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req);
154182

183+
rc = crb_try_pluton_doorbell(priv, true);
184+
if (rc)
185+
return rc;
186+
155187
if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_req,
156188
CRB_CTRL_REQ_GO_IDLE/* mask */,
157189
0, /* value */
@@ -188,12 +220,19 @@ static int crb_go_idle(struct tpm_chip *chip)
188220
*/
189221
static int __crb_cmd_ready(struct device *dev, struct crb_priv *priv)
190222
{
223+
int rc;
224+
191225
if ((priv->sm == ACPI_TPM2_START_METHOD) ||
192226
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
193227
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC))
194228
return 0;
195229

196230
iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req);
231+
232+
rc = crb_try_pluton_doorbell(priv, true);
233+
if (rc)
234+
return rc;
235+
197236
if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_req,
198237
CRB_CTRL_REQ_CMD_READY /* mask */,
199238
0, /* value */
@@ -371,6 +410,10 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
371410
return -E2BIG;
372411
}
373412

413+
/* Seems to be necessary for every command */
414+
if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON)
415+
__crb_cmd_ready(&chip->dev, priv);
416+
374417
memcpy_toio(priv->cmd, buf, len);
375418

376419
/* Make sure that cmd is populated before issuing start. */
@@ -394,7 +437,10 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
394437
rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id);
395438
}
396439

397-
return rc;
440+
if (rc)
441+
return rc;
442+
443+
return crb_try_pluton_doorbell(priv, false);
398444
}
399445

400446
static void crb_cancel(struct tpm_chip *chip)
@@ -524,15 +570,18 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
524570
return ret;
525571
acpi_dev_free_resource_list(&acpi_resource_list);
526572

527-
if (resource_type(iores_array) != IORESOURCE_MEM) {
528-
dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n");
529-
return -EINVAL;
530-
} else if (resource_type(iores_array + TPM_CRB_MAX_RESOURCES) ==
531-
IORESOURCE_MEM) {
532-
dev_warn(dev, "TPM2 ACPI table defines too many memory resources\n");
533-
memset(iores_array + TPM_CRB_MAX_RESOURCES,
534-
0, sizeof(*iores_array));
535-
iores_array[TPM_CRB_MAX_RESOURCES].flags = 0;
573+
/* Pluton doesn't appear to define ACPI memory regions */
574+
if (priv->sm != ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) {
575+
if (resource_type(iores_array) != IORESOURCE_MEM) {
576+
dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n");
577+
return -EINVAL;
578+
} else if (resource_type(iores_array + TPM_CRB_MAX_RESOURCES) ==
579+
IORESOURCE_MEM) {
580+
dev_warn(dev, "TPM2 ACPI table defines too many memory resources\n");
581+
memset(iores_array + TPM_CRB_MAX_RESOURCES,
582+
0, sizeof(*iores_array));
583+
iores_array[TPM_CRB_MAX_RESOURCES].flags = 0;
584+
}
536585
}
537586

538587
iores = NULL;
@@ -656,13 +705,30 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
656705
return ret;
657706
}
658707

708+
static int crb_map_pluton(struct device *dev, struct crb_priv *priv,
709+
struct acpi_table_tpm2 *buf, struct tpm2_crb_pluton *crb_pluton)
710+
{
711+
priv->pluton_start_addr = crb_map_res(dev, NULL, NULL,
712+
crb_pluton->start_addr, 4);
713+
if (IS_ERR(priv->pluton_start_addr))
714+
return PTR_ERR(priv->pluton_start_addr);
715+
716+
priv->pluton_reply_addr = crb_map_res(dev, NULL, NULL,
717+
crb_pluton->reply_addr, 4);
718+
if (IS_ERR(priv->pluton_reply_addr))
719+
return PTR_ERR(priv->pluton_reply_addr);
720+
721+
return 0;
722+
}
723+
659724
static int crb_acpi_add(struct acpi_device *device)
660725
{
661726
struct acpi_table_tpm2 *buf;
662727
struct crb_priv *priv;
663728
struct tpm_chip *chip;
664729
struct device *dev = &device->dev;
665730
struct tpm2_crb_smc *crb_smc;
731+
struct tpm2_crb_pluton *crb_pluton;
666732
acpi_status status;
667733
u32 sm;
668734
int rc;
@@ -700,6 +766,20 @@ static int crb_acpi_add(struct acpi_device *device)
700766
priv->smc_func_id = crb_smc->smc_func_id;
701767
}
702768

769+
if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) {
770+
if (buf->header.length < (sizeof(*buf) + sizeof(*crb_pluton))) {
771+
dev_err(dev,
772+
FW_BUG "TPM2 ACPI table has wrong size %u for start method type %d\n",
773+
buf->header.length,
774+
ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON);
775+
return -EINVAL;
776+
}
777+
crb_pluton = ACPI_ADD_PTR(struct tpm2_crb_pluton, buf, sizeof(*buf));
778+
rc = crb_map_pluton(dev, priv, buf, crb_pluton);
779+
if (rc)
780+
return rc;
781+
}
782+
703783
priv->sm = sm;
704784
priv->hid = acpi_device_hid(device);
705785

include/acpi/actbl3.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ struct acpi_tpm2_phy {
443443
#define ACPI_TPM2_RESERVED10 10
444444
#define ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC 11 /* V1.2 Rev 8 */
445445
#define ACPI_TPM2_RESERVED 12
446+
#define ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON 13
446447

447448
/* Optional trailer appears after any start_method subtables */
448449

0 commit comments

Comments
 (0)