summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichał Żygowski <michal.zygowski@3mdeb.com>2022-04-29 13:25:07 +0200
committerMichał Żygowski <michal.zygowski@3mdeb.com>2022-10-05 11:00:36 +0000
commitd02bb67dd62e340bb09b3f629cf60a47a1e1adc8 (patch)
treeb4106bd7904ed68ebea69dd818db745a7531233e
parent598c0dda158bd2062442cbf0b42214d5ed95006f (diff)
drivers/crb: Initialize Intel PTT control area
On newer systems such as Alder Lake it has been noticed that Intel PTT control area is not writable until PTT is switched to ready state. The EDK2 CRB drivers always initialize the command/response buffer address and size registers before invoking the TPM command. See STEP 2 in PtpCrbTpmCommand function in tianocore/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c Doing the same in coreboot allowed to perform PTT TPM startup successfully and measure the components to PCRs in ramstage on an Alder Lake S platform. TEST=Enable measured boot and see Intel PTT is started successfully and no errors occur during PCR extends on MSI PRO Z690-A DDR4 WIFI. Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com> Change-Id: Ia8e473ecc1a520851d6d48ccad9da35c6f91005d Reviewed-on: https://review.coreboot.org/c/coreboot/+/63957 Reviewed-by: Paul Menzel <paulepanter@mailbox.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Krystian Hebel <krystian.hebel@3mdeb.com>
-rw-r--r--src/drivers/crb/tpm.c46
-rw-r--r--src/drivers/crb/tpm.h1
2 files changed, 47 insertions, 0 deletions
diff --git a/src/drivers/crb/tpm.c b/src/drivers/crb/tpm.c
index 1bdca0039f..858aeb728c 100644
--- a/src/drivers/crb/tpm.c
+++ b/src/drivers/crb/tpm.c
@@ -48,6 +48,22 @@ static void crb_readControlArea(void)
control_area.response_size = read32(CRB_REG(cur_loc, CRB_REG_RESP_SIZE));
control_area.response_bfr =
(void *)(uintptr_t)read64(CRB_REG(cur_loc, CRB_REG_RESP_ADDR));
+
+ /*
+ * Intel PTT has to write the command/response address and size
+ * register before each command submission otherwise the control area
+ * is all zeroed. This has been observed on Alder Lake S CPU and may be
+ * applicable to other new microarchitectures. Update the local control
+ * area data to make tpm2_process_command not fail on buffer checks.
+ * PTT command/response buffer is fixed to be at offset 0x80 and spans
+ * up to the end of 4KB region for the current locality.
+ */
+ if (CONFIG(HAVE_INTEL_PTT)) {
+ control_area.command_size = 0x1000 - CRB_REG_DATA_BUFF;
+ control_area.response_size = control_area.command_size;
+ control_area.command_bfr = CRB_REG(cur_loc, CRB_REG_DATA_BUFF);
+ control_area.response_bfr = CRB_REG(cur_loc, CRB_REG_DATA_BUFF);
+ }
}
/* Wait for Reg to be expected Value */
@@ -115,6 +131,7 @@ static uint8_t crb_activate_locality(void)
int rc = crb_wait_for_reg32(CRB_REG(locality, CRB_REG_LOC_STATE), 750,
LOC_STATE_LOC_ASSIGN, LOC_STATE_LOC_ASSIGN);
+
if (!rc && (locality == 0))
return locality;
@@ -181,12 +198,33 @@ int tpm2_init(void)
/* Read back control area structure */
crb_readControlArea();
+ /*
+ * PTT may have no assigned locality before startup. Request locality here to save
+ * some precious milliseconds which would be wasted in crb_activate_locality polling
+ * for LOC_STATE_LOC_ASSIGN bit for the first time.
+ */
+ if (CONFIG(HAVE_INTEL_PTT)) {
+ uint8_t locality = (read8(CRB_REG(0, CRB_REG_LOC_STATE)) >> 2) & 0x07;
+ write8(CRB_REG(locality, CRB_REG_LOC_CTRL), LOC_CTRL_REQ_ACCESS);
+ }
+
/* Good to go. */
printk(BIOS_SPEW, "TPM: CRB TPM initialized successfully\n");
return 0;
}
+static void set_ptt_cmd_resp_buffers(void)
+{
+ write32(CRB_REG(cur_loc, CRB_REG_CMD_ADDR + 4), 0);
+ write32(CRB_REG(cur_loc, CRB_REG_CMD_ADDR),
+ (uintptr_t)CRB_REG(cur_loc, CRB_REG_DATA_BUFF));
+ write32(CRB_REG(cur_loc, CRB_REG_CMD_SIZE), control_area.command_size);
+ write64(CRB_REG(cur_loc, CRB_REG_RESP_ADDR),
+ (uintptr_t)CRB_REG(cur_loc, CRB_REG_DATA_BUFF));
+ write32(CRB_REG(cur_loc, CRB_REG_RESP_SIZE), control_area.response_size);
+}
+
/*
* tpm2_process_command
*/
@@ -220,6 +258,14 @@ size_t tpm2_process_command(const void *tpm2_command, size_t command_size, void
// Write to Command Buffer
memcpy(control_area.command_bfr, tpm2_command, command_size);
+ /*
+ * Initialize CRB addresses and sizes for PTT. It seems to be possible
+ * only after CRB is switched to ready and before writing start bit.
+ * This is also what EDK2 TPM CRB drivers do.
+ */
+ if (CONFIG(HAVE_INTEL_PTT))
+ set_ptt_cmd_resp_buffers();
+
// Write Start Bit
write8(CRB_REG(cur_loc, CRB_REG_START), 0x1);
diff --git a/src/drivers/crb/tpm.h b/src/drivers/crb/tpm.h
index c43beb6843..be26be2d24 100644
--- a/src/drivers/crb/tpm.h
+++ b/src/drivers/crb/tpm.h
@@ -33,6 +33,7 @@
#define CRB_REG_CMD_ADDR 0x5C
#define CRB_REG_RESP_SIZE 0x64
#define CRB_REG_RESP_ADDR 0x68
+#define CRB_REG_DATA_BUFF 0x80
/* CRB INTF BIT MASK */
#define CRB_INTF_REG_CAP_CRB (1<<14)