Hello Jes Klinke,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/43741
to review the following change.
Change subject: WIP: A bunch of experiments for cr50 long pulses ......................................................................
WIP: A bunch of experiments for cr50 long pulses
Change-Id: If83188fd09fe69c2cda4ce1a8bf5b2efe1ca86da Bug: b:154333137 --- M src/arch/x86/car.ld M src/commonlib/include/commonlib/cbmem_id.h M src/drivers/spi/tpm/tpm.c M src/drivers/spi/tpm/tpm.h M src/mainboard/google/volteer/Kconfig M src/mainboard/google/volteer/chromeos.c M src/mainboard/google/volteer/variants/baseboard/devicetree.cb M src/security/tpm/tss/vendor/cr50/Kconfig M src/security/vboot/Makefile.inc A src/security/vboot/cr50.c A src/security/vboot/cr50.h M src/security/vboot/vboot_logic.c M src/soc/intel/tigerlake/chip.h M src/soc/intel/tigerlake/fsp_params.c 14 files changed, 182 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/41/43741/1
diff --git a/src/arch/x86/car.ld b/src/arch/x86/car.ld index 17b7748..4ba7d9a 100644 --- a/src/arch/x86/car.ld +++ b/src/arch/x86/car.ld @@ -58,6 +58,11 @@ . += 80; _ecar_ehci_dbg_info = .;
+ /* Reserve space for a uint32_t */ + . = ALIGN(4); + _car_tpm_board_cfg = .; + . += 4; + /* _bss and _ebss provide symbols to per-stage * variables that are not shared like the timestamp and the pre-ram * cbmem console. This is useful for clearing this area on a per-stage diff --git a/src/commonlib/include/commonlib/cbmem_id.h b/src/commonlib/include/commonlib/cbmem_id.h index ac271a0..5b9306c 100644 --- a/src/commonlib/include/commonlib/cbmem_id.h +++ b/src/commonlib/include/commonlib/cbmem_id.h @@ -55,6 +55,7 @@ #define CBMEM_ID_TCPA_TCG_LOG 0x54445041 #define CBMEM_ID_TIMESTAMP 0x54494d45 #define CBMEM_ID_TPM2_TCG_LOG 0x54504d32 +#define CBMEM_ID_TPM_BOARD_CFG 0x92263f3b #define CBMEM_ID_VBOOT_HANDOFF 0x780074f0 /* deprecated */ #define CBMEM_ID_VBOOT_SEL_REG 0x780074f1 /* deprecated */ #define CBMEM_ID_VBOOT_WORKBUF 0x78007343 @@ -117,6 +118,7 @@ { CBMEM_ID_TCPA_TCG_LOG, "TCPA TCGLOG" }, \ { CBMEM_ID_TIMESTAMP, "TIME STAMP " }, \ { CBMEM_ID_TPM2_TCG_LOG, "TPM2 TCGLOG" }, \ + { CBMEM_ID_TPM_BOARD_CFG, "TPM BRD CFG" }, \ { CBMEM_ID_VBOOT_HANDOFF, "VBOOT " }, \ { CBMEM_ID_VBOOT_SEL_REG, "VBOOT SEL " }, \ { CBMEM_ID_VBOOT_WORKBUF, "VBOOT WORK " }, \ diff --git a/src/drivers/spi/tpm/tpm.c b/src/drivers/spi/tpm/tpm.c index 24851d1..344ae1a 100644 --- a/src/drivers/spi/tpm/tpm.c +++ b/src/drivers/spi/tpm/tpm.c @@ -31,6 +31,7 @@ #define TPM_DID_VID_REG (TPM_LOCALITY_0_SPI_BASE + 0xf00) #define TPM_RID_REG (TPM_LOCALITY_0_SPI_BASE + 0xf04) #define TPM_FW_VER (TPM_LOCALITY_0_SPI_BASE + 0xf90) +#define TPM_BOARD_CFG (TPM_LOCALITY_0_SPI_BASE + 0xfe0)
#define CR50_TIMEOUT_INIT_MS 30000 /* Very long timeout for TPM init */
@@ -39,6 +40,7 @@
/* Cached TPM device identification. */ static struct tpm2_info tpm_info; +static int cr50_firmware_version[3];
/* * TODO(vbendeb): make CONFIG_DEBUG_TPM an int to allow different level of @@ -59,6 +61,11 @@ *info = tpm_info; }
+const int *cr50_get_firmware_version(void) +{ + return cr50_firmware_version; +} + __weak int tis_plat_irq_status(void) { static int warning_displayed; @@ -344,6 +351,19 @@ }
/* + * XXX + */ +int cr50_read_board_cfg(uint32_t *status) +{ + return tpm2_read_reg(TPM_BOARD_CFG, status, sizeof(*status)); +} + +int cr50_write_board_cfg(uint32_t status) +{ + return tpm2_write_reg(TPM_BOARD_CFG, &status, sizeof(status)); +} + +/* * The TPM may limit the transaction bytes count (burst count) below the 64 * bytes max. The current value is available as a field of the status * register. @@ -493,6 +513,7 @@ * Locality claimed, read the revision value and set up the tpm_info * structure. */ + tpm2_read_reg(TPM_RID_REG, &cmd, sizeof(cmd)); tpm_info.vendor_id = did_vid & 0xffff; tpm_info.device_id = did_vid >> 16; @@ -503,6 +524,7 @@
/* Let's report device FW version if available. */ if (tpm_info.vendor_id == 0x1ae0) { + static const char *version_prefix = " RW_.:"; int chunk_count = 0; size_t chunk_size; /* @@ -511,6 +533,10 @@ */ char vstr[51];
+ const char *pp = version_prefix; + int state = -1; + memset(cr50_firmware_version, 0, sizeof(cr50_firmware_version)); + chunk_size = sizeof(vstr) - 1;
printk(BIOS_INFO, "Firmware version: "); @@ -524,16 +550,40 @@ /* Print it out in sizeof(vstr) - 1 byte chunks. */ vstr[chunk_size] = 0; do { + const char *p; tpm2_read_reg(TPM_FW_VER, vstr, chunk_size); printk(BIOS_INFO, "%s", vstr);
+ for (p = vstr; *p; p++) { + if (state == -1) { + /* Looking for prefix */ + if (*p == *pp || *pp == '.') { + pp++; + } else { + pp = version_prefix; + } + if (!*pp) { + state = 0; + } + } else if (state < 3) { + /* Parsing a version number */ + if (*p >= '0' && *p <= '9') { + cr50_firmware_version[state] = 10 * cr50_firmware_version[state] + (*p - '0'); + } else if (*p == '.') { + ++state; + } else { + state = 3; + } + } + } + /* * While string is not over, and is no longer than 300 * characters. */ } while (vstr[chunk_size - 1] && (chunk_count++ < (300 / chunk_size))); - + printk(BIOS_INFO, "\n"); } return 0; diff --git a/src/drivers/spi/tpm/tpm.h b/src/drivers/spi/tpm/tpm.h index be98ed0..eb2f81b 100644 --- a/src/drivers/spi/tpm/tpm.h +++ b/src/drivers/spi/tpm/tpm.h @@ -41,4 +41,11 @@ /* Get information about previously initialized TPM device. */ void tpm2_get_info(struct tpm2_info *info);
+/* Returns a pointer to an array of three integers. */ +const int *cr50_get_firmware_version(void); + +int cr50_read_board_cfg(uint32_t *value); +int cr50_write_board_cfg(uint32_t value); + + #endif /* ! __COREBOOT_SRC_DRIVERS_SPI_TPM_TPM_H */ diff --git a/src/mainboard/google/volteer/Kconfig b/src/mainboard/google/volteer/Kconfig index 16834ae..d6fcf15 100644 --- a/src/mainboard/google/volteer/Kconfig +++ b/src/mainboard/google/volteer/Kconfig @@ -57,6 +57,9 @@ config DRIVER_TPM_SPI_BUS default 0x1
+config TPM_BOARD_CFG + default 0x1 + config MAINBOARD_DIR string default "google/volteer" diff --git a/src/mainboard/google/volteer/chromeos.c b/src/mainboard/google/volteer/chromeos.c index 09642a0..3c04ebf 100644 --- a/src/mainboard/google/volteer/chromeos.c +++ b/src/mainboard/google/volteer/chromeos.c @@ -6,7 +6,9 @@
#include <baseboard/variants.h> #include <boot/coreboot_tables.h> +#include <cbmem.h> #include <gpio.h> +#include <soc/ramstage.h> #include <variant/gpio.h> #include <vendorcode/google/chromeos/chromeos.h>
@@ -36,3 +38,17 @@ gpios = variant_cros_gpios(&num); chromeos_acpi_gpio_generate(gpios, num); } + +void mainboard_silicon_init_params(FSP_S_CONFIG *params) { + uint32_t *status = (uint32_t*)cbmem_find(CBMEM_ID_TPM_BOARD_CFG); + if (status && (*status & 0x01)) { + printk(BIOS_INFO, "Enabling S0i3.4\n"); + } else { + /* Disable S03.4, preventing the GPIO block from switching to + * slow clock. */ + printk(BIOS_INFO, "Not enabling S0i3.4\n"); + params->LpmStateEnableMask &= ~0x80; + } +} + + diff --git a/src/mainboard/google/volteer/variants/baseboard/devicetree.cb b/src/mainboard/google/volteer/variants/baseboard/devicetree.cb index e0d3bea..dac7fd4 100644 --- a/src/mainboard/google/volteer/variants/baseboard/devicetree.cb +++ b/src/mainboard/google/volteer/variants/baseboard/devicetree.cb @@ -207,6 +207,7 @@
# Enable S0ix register "s0ix_enable" = "1" + register "LpmStateEnableMask" = "0xFF"
# Enable DPTF register "dptf_enable" = "1" diff --git a/src/security/tpm/tss/vendor/cr50/Kconfig b/src/security/tpm/tss/vendor/cr50/Kconfig index f606459..3c16057 100644 --- a/src/security/tpm/tss/vendor/cr50/Kconfig +++ b/src/security/tpm/tss/vendor/cr50/Kconfig @@ -12,4 +12,8 @@ help Power off machine while waiting for CR50 update to take effect.
+config TPM_BOARD_CFG + hex "Value to put into Cr50 BOARD_CFG register from RO firmware" + default 0x0 + endif diff --git a/src/security/vboot/Makefile.inc b/src/security/vboot/Makefile.inc index 90b2756..96057e9 100644 --- a/src/security/vboot/Makefile.inc +++ b/src/security/vboot/Makefile.inc @@ -52,6 +52,11 @@ verstage-y += bootmode.c postcar-y += bootmode.c
+ifneq ($(CONFIG_TPM_BOARD_CFG),0) +romstage-$(CONFIG_TPM_CR50) += cr50.c +verstage-$(CONFIG_TPM_CR50) += cr50.c +endif + verstage-generic-ccopts += -D__VERSTAGE__
bootblock-y += vbnv.c diff --git a/src/security/vboot/cr50.c b/src/security/vboot/cr50.c new file mode 100644 index 0000000..0253e6d --- /dev/null +++ b/src/security/vboot/cr50.c @@ -0,0 +1,67 @@ +#include <cbmem.h> +#include <console/console.h> +#include <drivers/spi/tpm/tpm.h> +#include <string.h> +#include "cr50.h" + +/** + * Variable persisted across CAR stages, defined in car.ld. + */ +extern uint32_t _car_tpm_board_cfg; + +/** + * Set the BOARD_CFG register on the TMP chip to a particular compile-time + * constant value. + */ +void set_cr50_board_cfg(void) { + const int *version = cr50_get_firmware_version(); + + /* Cr50 supports the TPM_BOARD_CFG register from version 0.5.4 / 0.6.4 + * and onwards. */ + if (version[0] == 0 && version[1] < 7 && + (version[1] < 5 || version[2] < 4)) { + printk(BIOS_INFO, "Cr50 firmware does not support" + " TPM_BOARD_CFG, version: %d.%d.%d\n", + version[0], version[1], version[2]); + return; + } + /* Set the TPM_BOARD_CFG register, for e.g. asking cr50 to use + * longer ready pulses. */ + uint32_t status; + if (!cr50_read_board_cfg(&status)) { + printk(BIOS_INFO, "Error reading from cr50\n"); + return; + } + if (status & 0x80000000U) { + /* The high bit is set, meaning that the Cr50 is already locked + * on a particular value for the register. Verify that it is + * the value we wanted. */ + _car_tpm_board_cfg = status & ~0xC0000000U; + printk(BIOS_INFO, "%sCurrent Cr50 TPM_BOARD_CFG = 0x%08x, " + "desired = 0x%08x\n", + (_car_tpm_board_cfg != CONFIG_TPM_BOARD_CFG + ? "Inconsistency!: " : ""), + status, CONFIG_TPM_BOARD_CFG); + return; + } + printk(BIOS_INFO, "Current Cr50 TPM_BOARD_CFG = 0x%08x, " + "setting to 0x%08x\n", + status, CONFIG_TPM_BOARD_CFG); + if (!cr50_write_board_cfg(CONFIG_TPM_BOARD_CFG)) { + printk(BIOS_INFO, "Error writing to cr50\n"); + return; + } + _car_tpm_board_cfg = status; +} + +static void cr50_setup_cbmem(int unused) +{ + /* Move state from CAR to CBMEM. */ + uint32_t *tpm_board_cfg_cbmem = cbmem_add(CBMEM_ID_TPM_BOARD_CFG, + sizeof(_car_tpm_board_cfg)); + if (!tpm_board_cfg_cbmem) + return; + memcpy(tpm_board_cfg_cbmem, &_car_tpm_board_cfg, + sizeof(_car_tpm_board_cfg)); +} +ROMSTAGE_CBMEM_INIT_HOOK(cr50_setup_cbmem) diff --git a/src/security/vboot/cr50.h b/src/security/vboot/cr50.h new file mode 100644 index 0000000..7fcdda1 --- /dev/null +++ b/src/security/vboot/cr50.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __VBOOT_CR50_H__ +#define __VBOOT_CR50_H__ + +void set_cr50_board_cfg(void); + +#endif diff --git a/src/security/vboot/vboot_logic.c b/src/security/vboot/vboot_logic.c index e23dcc4..209aeaf 100644 --- a/src/security/vboot/vboot_logic.c +++ b/src/security/vboot/vboot_logic.c @@ -16,6 +16,7 @@ #include <boot_device.h>
#include "antirollback.h" +#include "cr50.h"
/* The max hash size to expect is for SHA512. */ #define VBOOT_MAX_HASH_SIZE VB2_SHA512_DIGEST_SIZE @@ -299,6 +300,9 @@ if (vboot_setup_tpm(ctx) == TPM_SUCCESS) { antirollback_read_space_firmware(ctx); antirollback_read_space_kernel(ctx); +#if CONFIG(TPM_CR50) && CONFIG_TPM_BOARD_CFG + set_cr50_board_cfg(); +#endif } timestamp_add_now(TS_END_TPMINIT);
diff --git a/src/soc/intel/tigerlake/chip.h b/src/soc/intel/tigerlake/chip.h index 59dab58..2c6d49f 100644 --- a/src/soc/intel/tigerlake/chip.h +++ b/src/soc/intel/tigerlake/chip.h @@ -76,6 +76,9 @@
/* Enable S0iX support */ int s0ix_enable; + /* S0iX: Selectively enable individual sub-states */ + uint8_t LpmStateEnableMask; + /* Support for TCSS xhci, xdci, TBT PCIe root ports and DMA controllers */ uint8_t TcssD3HotEnable; /* Support for TBT PCIe root ports and DMA controllers with D3Hot->D3Cold */ diff --git a/src/soc/intel/tigerlake/fsp_params.c b/src/soc/intel/tigerlake/fsp_params.c index cf24021..fc50c8a 100644 --- a/src/soc/intel/tigerlake/fsp_params.c +++ b/src/soc/intel/tigerlake/fsp_params.c @@ -207,6 +207,13 @@ sizeof(params->SataPortsDevSlp)); }
+ /* S0iX: Selectively enable individual sub-states. + * + * LPM0-s0i2.0, LPM1-s0i2.1, LPM2-s0i2.2, LPM3-s0i3.0, + * LPM4-s0i3.1, LPM5-s0i3.2, LPM6-s0i3.3, LPM7-s0i3.4 + */ + params->LpmStateEnableMask = config->LpmStateEnableMask; + /* * Power Optimizer for DMI and SATA. * DmiPwrOptimizeDisable and SataPwrOptimizeDisable is default to 0.