Compare commits

..

1 Commits

Author SHA1 Message Date
Tim Crawford
7e5b28bf86 security/tpm/tspi: Do TPM Restart if TPM Resume fails
The Infineon SLB 9672 on newer Clevo machines regularly fails TPM Resume
on S3 with the error `TPM_RC_VALUE`.

Per TPM2 spec, handle the failure by performing a TPM Restart.

> The startup behavior defined by this specification is different than
> TPM 1.2 with respect to Startup(STATE). A TPM 1.2 device will enter
> Failure Mode if no state is available when the TPM receives
> Startup(STATE). This is not the case in this specification. It is up
> to the CRTM to take corrective action if it the TPM returns
> TPM_RC_VALUE in response to Startup(STATE).

Fixes the following error from being repeatedly logged in Linux:

> kernel: tpm tpm0: A TPM error (256) occurred attempting get random

Ref: Trusted Platform Module Library, Part 1: Architecture, rev 1.59
Change-Id: I3388007d4448c93bd0dda591c8ca7d1a8dc5306b
Signed-off-by: Tim Crawford <tcrawford@system76.com>
2024-05-31 12:16:10 -06:00
6 changed files with 34 additions and 107 deletions

View File

@@ -36,18 +36,6 @@
#define DDR4_SPD_PART_OFF 329 #define DDR4_SPD_PART_OFF 329
#define DDR4_SPD_PART_LEN 20 #define DDR4_SPD_PART_LEN 20
#define DDR4_SPD_SN_OFF 325 #define DDR4_SPD_SN_OFF 325
#define MAX_SPD_PAGE_SIZE_SPD5 128
#define MAX_SPD_SIZE (SPD_PAGE_LEN * 4)
#define SPD_HUB_MEMREG(addr) ((u8)(0x80 | (addr)))
#define SPD5_MR11 0x0B
#define SPD5_MR0 0x00
#define SPD5_MEMREG_REG(addr) ((u8)((~0x80) & (addr)))
#define SPD5_MR0_SPD5_HUB_DEV 0x51
struct spd_offset_table {
u16 start; /* Offset 0 */
u16 end; /* Offset 2 */
};
struct spd_block { struct spd_block {
u8 addr_map[CONFIG_DIMM_MAX]; /* 7 bit I2C addresses */ u8 addr_map[CONFIG_DIMM_MAX]; /* 7 bit I2C addresses */

View File

@@ -209,9 +209,7 @@ enum cb_err spd_fill_from_cache(uint8_t *spd_cache, struct spd_block *blk)
dram_type = *(spd_cache + SC_SPD_OFFSET(i) + SPD_DRAM_TYPE); dram_type = *(spd_cache + SC_SPD_OFFSET(i) + SPD_DRAM_TYPE);
if (dram_type == SPD_DRAM_DDR5) if (dram_type == SPD_DRAM_DDR4)
blk->len = CONFIG_DIMM_SPD_SIZE;
else if (dram_type == SPD_DRAM_DDR4)
blk->len = SPD_PAGE_LEN_DDR4; blk->len = SPD_PAGE_LEN_DDR4;
else else
blk->len = SPD_PAGE_LEN; blk->len = SPD_PAGE_LEN;

View File

@@ -73,6 +73,14 @@ static tpm_result_t tpm_setup_s3_helper(void)
default: default:
printk(BIOS_ERR, "TPM: Resume failed (%#x).\n", rc); printk(BIOS_ERR, "TPM: Resume failed (%#x).\n", rc);
if (CONFIG(TPM2)) {
/*
* TODO: Record EV_SEPARATOR event to indicate to host
* that an error has occurred.
*/
printk(BIOS_WARNING, "TPM: Performing restart\n");
rc = tlcl_startup();
}
break; break;
} }

View File

@@ -112,7 +112,7 @@ int cpu_cl_poll_mailbox_ready(u32 cl_mailbox_addr)
u16 stall_cnt = 0; u16 stall_cnt = 0;
do { do {
cl_mailbox_interface.data = read32((u32 *)(uintptr_t)cl_mailbox_addr); cl_mailbox_interface.data = read32((u32 *)cl_mailbox_addr);
udelay(CPU_CRASHLOG_WAIT_STALL); udelay(CPU_CRASHLOG_WAIT_STALL);
stall_cnt++; stall_cnt++;
} while ((cl_mailbox_interface.fields.busy == 1) } while ((cl_mailbox_interface.fields.busy == 1)
@@ -140,7 +140,7 @@ int cpu_cl_mailbox_cmd(u8 cmd, u8 param)
cl_mailbox_intf.fields.param = param; cl_mailbox_intf.fields.param = param;
cl_mailbox_intf.fields.busy = 1; cl_mailbox_intf.fields.busy = 1;
write32((u32 *)(uintptr_t)(cl_base_addr + cl_get_cpu_mb_int_addr()), write32((u32 *)(cl_base_addr + cl_get_cpu_mb_int_addr()),
cl_mailbox_intf.data); cl_mailbox_intf.data);
cpu_cl_poll_mailbox_ready(cl_base_addr + cl_get_cpu_mb_int_addr()); cpu_cl_poll_mailbox_ready(cl_base_addr + cl_get_cpu_mb_int_addr());
@@ -167,7 +167,7 @@ int pmc_cl_gen_descriptor_table(u32 desc_table_addr,
pmc_crashlog_desc_table_t *descriptor_table) pmc_crashlog_desc_table_t *descriptor_table)
{ {
int total_data_size = 0; int total_data_size = 0;
descriptor_table->numb_regions = read32((u32 *)(uintptr_t)desc_table_addr); descriptor_table->numb_regions = read32((u32 *)desc_table_addr);
printk(BIOS_DEBUG, "CL PMC desc table: numb of regions is 0x%x at addr 0x%x\n", printk(BIOS_DEBUG, "CL PMC desc table: numb of regions is 0x%x at addr 0x%x\n",
descriptor_table->numb_regions, desc_table_addr); descriptor_table->numb_regions, desc_table_addr);
for (int i = 0; i < descriptor_table->numb_regions; i++) { for (int i = 0; i < descriptor_table->numb_regions; i++) {
@@ -178,7 +178,7 @@ int pmc_cl_gen_descriptor_table(u32 desc_table_addr,
break; break;
} }
desc_table_addr += 4; desc_table_addr += 4;
descriptor_table->regions[i].data = read32((u32 *)(uintptr_t)(desc_table_addr)); descriptor_table->regions[i].data = read32((u32 *)(desc_table_addr));
total_data_size += descriptor_table->regions[i].bits.size * sizeof(u32); total_data_size += descriptor_table->regions[i].bits.size * sizeof(u32);
printk(BIOS_DEBUG, "CL PMC desc table: region 0x%x has size 0x%x at offset 0x%x\n", printk(BIOS_DEBUG, "CL PMC desc table: region 0x%x has size 0x%x at offset 0x%x\n",
i, descriptor_table->regions[i].bits.size, i, descriptor_table->regions[i].bits.size,
@@ -295,7 +295,7 @@ bool cl_copy_data_from_sram(u32 src_bar,
u32 src_addr = src_bar + offset; u32 src_addr = src_bar + offset;
u32 data = read32((u32 *)(uintptr_t)src_addr); u32 data = read32((u32 *)src_addr);
/* First 32bits of the record must not be 0xdeadbeef */ /* First 32bits of the record must not be 0xdeadbeef */
if (data == INVALID_CRASHLOG_RECORD) { if (data == INVALID_CRASHLOG_RECORD) {
@@ -320,7 +320,7 @@ bool cl_copy_data_from_sram(u32 src_bar,
u32 copied = 0; u32 copied = 0;
while (copied < size) { while (copied < size) {
/* DW by DW copy: byte access to PMC SRAM not allowed */ /* DW by DW copy: byte access to PMC SRAM not allowed */
*dest_addr = read32((u32 *)(uintptr_t)src_addr); *dest_addr = read32((u32 *)src_addr);
dest_addr++; dest_addr++;
src_addr += 4; src_addr += 4;
copied++; copied++;

View File

@@ -13,11 +13,8 @@ static void update_spd_len(struct spd_block *blk)
if (blk->spd_array[i] != NULL) if (blk->spd_array[i] != NULL)
j |= blk->spd_array[i][SPD_DRAM_TYPE]; j |= blk->spd_array[i][SPD_DRAM_TYPE];
/* If spd used is DDR5, then its length is 1024 byte. */
if (j == SPD_DRAM_DDR5)
blk->len = CONFIG_DIMM_SPD_SIZE;
/* If spd used is DDR4, then its length is 512 byte. */ /* If spd used is DDR4, then its length is 512 byte. */
else if (j == SPD_DRAM_DDR4) if (j == SPD_DRAM_DDR4)
blk->len = SPD_PAGE_LEN_DDR4; blk->len = SPD_PAGE_LEN_DDR4;
else else
blk->len = SPD_PAGE_LEN; blk->len = SPD_PAGE_LEN;
@@ -40,61 +37,6 @@ static void smbus_read_spd(u8 *spd, u8 addr)
} }
} }
static void switch_page(u8 spd_addr, u8 new_page)
{
u32 offset;
/*
* By default,an SPD5 hub accepts 1 byte addressing pointing
* to the first 128 bytes of memory. MR11[2:0] selects the page
* pointer to address the entire 1024 bytes of non-volatile memory.
*/
offset = SPD5_MEMREG_REG(SPD5_MR11);
smbus_write_byte(spd_addr, offset, new_page);
}
/*
* Read the SPD data over the SMBus, at the specified SPD address,
* starting at the specified starting offset and read the given amount of data.
*/
static void smbus_read_spd5(u8 *spd, u8 spd_addr, u16 size)
{
u8 page = ~0;
u32 max_page_size = MAX_SPD_PAGE_SIZE_SPD5;
if (size > MAX_SPD_SIZE) {
printk(BIOS_ERR, "Maximum SPD size reached\n");
return;
}
for (int i = 0; i < size; i++) {
u8 next_page = (u8) (i / max_page_size);
if (next_page != page) {
switch_page(spd_addr, next_page);
page = next_page;
}
unsigned int byte_addr = SPD_HUB_MEMREG(i % max_page_size);
spd[i] = smbus_read_byte(spd_addr, byte_addr);
}
}
/* Read SPD5 MR0 and check if SPD Byte 0 matches the SPD5 HUB MR0 identifier.*/
static int is_spd5_hub(u8 spd_addr)
{
u8 spd_hub_byte;
spd_hub_byte = smbus_read_byte(spd_addr, SPD5_MEMREG_REG(SPD5_MR0));
return spd_hub_byte == SPD5_MR0_SPD5_HUB_DEV;
}
/*
* Reset the SPD page back to page 0 on an SPD5 Hub device at the
* input SPD SMbus address.
*/
static void reset_page_spd5(u8 spd_addr)
{
/* Set SPD5 MR11[2:0] = 0 (Page 0) */
smbus_write_byte(spd_addr, SPD5_MEMREG_REG(SPD5_MR11), 0);
}
/* return -1 if SMBus errors otherwise return 0 */ /* return -1 if SMBus errors otherwise return 0 */
static int get_spd(u8 *spd, u8 addr) static int get_spd(u8 *spd, u8 addr)
{ {
@@ -110,21 +52,13 @@ static int get_spd(u8 *spd, u8 addr)
return -1; return -1;
} }
if (is_spd5_hub(addr)) {
smbus_read_spd5(spd, addr, CONFIG_DIMM_SPD_SIZE);
/* Reset the page for the next loop iteration */
reset_page_spd5(addr);
} else {
if (i2c_eeprom_read(addr, 0, SPD_PAGE_LEN, spd) < 0) { if (i2c_eeprom_read(addr, 0, SPD_PAGE_LEN, spd) < 0) {
printk(BIOS_INFO, "do_i2c_eeprom_read failed, using fallback\n"); printk(BIOS_INFO, "do_i2c_eeprom_read failed, using fallback\n");
smbus_read_spd(spd, addr); smbus_read_spd(spd, addr);
} }
/* Check if module is DDR4, DDR4 spd is 512 byte. */ /* Check if module is DDR4, DDR4 spd is 512 byte. */
if (spd[SPD_DRAM_TYPE] == SPD_DRAM_DDR4 && if (spd[SPD_DRAM_TYPE] == SPD_DRAM_DDR4 && CONFIG_DIMM_SPD_SIZE > SPD_PAGE_LEN) {
CONFIG_DIMM_SPD_SIZE > SPD_PAGE_LEN) {
/* Switch to page 1 */ /* Switch to page 1 */
smbus_write_byte(SPD_PAGE_1, 0, 0); smbus_write_byte(SPD_PAGE_1, 0, 0);
@@ -135,7 +69,6 @@ static int get_spd(u8 *spd, u8 addr)
/* Restore to page 0 */ /* Restore to page 0 */
smbus_write_byte(SPD_PAGE_0, 0, 0); smbus_write_byte(SPD_PAGE_0, 0, 0);
} }
}
return 0; return 0;
} }

View File

@@ -34,7 +34,7 @@ static u32 disc_tab_addr;
static u64 get_disc_tab_header(void) static u64 get_disc_tab_header(void)
{ {
return read64((void *)(uintptr_t)disc_tab_addr); return read64((void *)disc_tab_addr);
} }
/* Get the SRAM BAR. */ /* Get the SRAM BAR. */
@@ -338,7 +338,7 @@ static bool cpu_cl_gen_discovery_table(void)
disc_tab_addr = bar_addr + get_disc_table_offset(); disc_tab_addr = bar_addr + get_disc_table_offset();
u32 dw0 = read32((u32 *)(uintptr_t)disc_tab_addr); u32 dw0 = read32((u32 *)disc_tab_addr);
if (!is_crashlog_data_valid(dw0)) if (!is_crashlog_data_valid(dw0))
return false; return false;
@@ -351,7 +351,7 @@ static bool cpu_cl_gen_discovery_table(void)
for (int i = 0; i < cpu_cl_disc_tab.header.fields.count; i++) { for (int i = 0; i < cpu_cl_disc_tab.header.fields.count; i++) {
cur_offset = 8 + 24 * i; cur_offset = 8 + 24 * i;
dw0 = read32((u32 *)(uintptr_t)disc_tab_addr + cur_offset); dw0 = read32((u32 *)disc_tab_addr + cur_offset);
if (!is_crashlog_data_valid(dw0)) if (!is_crashlog_data_valid(dw0))
continue; continue;
@@ -361,7 +361,7 @@ static bool cpu_cl_gen_discovery_table(void)
break; break;
} }
cpu_cl_disc_tab.buffers[i].data = read64((void *)(uintptr_t)(disc_tab_addr + cur_offset)); cpu_cl_disc_tab.buffers[i].data = read64((void *)(disc_tab_addr + cur_offset));
printk(BIOS_DEBUG, "cpu_crashlog_discovery_table buffer: 0x%x size: " printk(BIOS_DEBUG, "cpu_crashlog_discovery_table buffer: 0x%x size: "
"0x%x offset: 0x%x\n", i, cpu_cl_disc_tab.buffers[i].fields.size, "0x%x offset: 0x%x\n", i, cpu_cl_disc_tab.buffers[i].fields.size,
cpu_cl_disc_tab.buffers[i].fields.offset); cpu_cl_disc_tab.buffers[i].fields.offset);
@@ -450,7 +450,7 @@ void cpu_cl_rearm(void)
cl_punit_control_interface_t punit_ctrl_intfc; cl_punit_control_interface_t punit_ctrl_intfc;
memset(&punit_ctrl_intfc, 0, sizeof(cl_punit_control_interface_t)); memset(&punit_ctrl_intfc, 0, sizeof(cl_punit_control_interface_t));
punit_ctrl_intfc.fields.set_re_arm = 1; punit_ctrl_intfc.fields.set_re_arm = 1;
write32((u32 *)(uintptr_t)(ctrl_sts_intfc_addr), punit_ctrl_intfc.data); write32((u32 *)(ctrl_sts_intfc_addr), punit_ctrl_intfc.data);
if (!wait_and_check(CRASHLOG_RE_ARM_STATUS_MASK)) if (!wait_and_check(CRASHLOG_RE_ARM_STATUS_MASK))
printk(BIOS_ERR, "CPU crashlog re_arm not asserted\n"); printk(BIOS_ERR, "CPU crashlog re_arm not asserted\n");
@@ -480,7 +480,7 @@ void cpu_cl_cleanup(void)
cl_punit_control_interface_t punit_ctrl_intfc; cl_punit_control_interface_t punit_ctrl_intfc;
memset(&punit_ctrl_intfc, 0, sizeof(cl_punit_control_interface_t)); memset(&punit_ctrl_intfc, 0, sizeof(cl_punit_control_interface_t));
punit_ctrl_intfc.fields.set_storage_off = 1; punit_ctrl_intfc.fields.set_storage_off = 1;
write32((u32 *)(uintptr_t)(ctrl_sts_intfc_addr), punit_ctrl_intfc.data); write32((u32 *)(ctrl_sts_intfc_addr), punit_ctrl_intfc.data);
if (!wait_and_check(CRASHLOG_PUNIT_STORAGE_OFF_MASK)) if (!wait_and_check(CRASHLOG_PUNIT_STORAGE_OFF_MASK))
printk(BIOS_ERR, "CPU crashlog storage_off not asserted\n"); printk(BIOS_ERR, "CPU crashlog storage_off not asserted\n");