Cr50: Add mostly-synchronous tpm_reset() function.

To reset the TPM task, we send it an event so that it will reset
only when it's not busy doing actual TPM stuff that might fiddle
with the stack or shared memory. But that means that we can't
always know when the task finally gets around to resetting
itself.

This CL adds a tpm_reset() function that blocks until the reset
actually occurs. Obviously it can't do that if it's being called
in interrupt context or from the TPM task itself, but otherwise
it does.

BUG=chrome-os-partner:52366
BRANCH=none
CQ-DEPEND=CL:361680
TEST=make buildall, test on Gru, manual tests

In addition to the normal rebooting, logging in/out, and so
forth. I added a temporary console command to call tpm_reset()
and scattered a bunch of ccprintfs around it. When called due to
SYS_RST_L, it didn't block. When invoked with the console
command, it did.

Change-Id: I51e8b1299dbdcd1a12273cf48a890e93ed32a8c8
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/388125
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Bill Richardson
2016-09-21 16:58:26 -07:00
committed by chrome-bot
parent e29005abe7
commit 4250da3ba9
5 changed files with 63 additions and 11 deletions

View File

@@ -395,7 +395,7 @@ void sys_rst_asserted(enum gpio_signal signal)
return;
/* Re-initialize the TPM software state */
task_set_event(TASK_ID_TPM, TPM_EVENT_RESET, 0);
tpm_reset();
}
void assert_sys_rst(void)

View File

@@ -136,9 +136,6 @@ void assert_ec_rst(void);
void deassert_ec_rst(void);
int is_ec_rst_asserted(void);
/* Event to request a reset/re-initialization of the TPM task */
#define TPM_EVENT_RESET (TASK_EVENT_CUSTOM(1))
#endif /* !__ASSEMBLER__ */
/* USB interface indexes (use define rather than enum to expand them) */

View File

@@ -570,7 +570,39 @@ static void call_extension_command(struct tpm_cmd_header *tpmh,
}
#endif
static void tpm_reset(void)
/* Event (to TPM task) to request reset, or (from TPM task) on completion. */
#define TPM_EVENT_RESET (TASK_EVENT_CUSTOM(1))
/* Calling task to notify when the TPM reset has completed. */
static task_id_t waiting_for_reset
/* This must not be affected by the reset, or we'll forget who to tell. */
__attribute__((section(".data.noreinit"))) = TASK_ID_INVALID;
int tpm_reset(void)
{
uint32_t evt;
cprints(CC_TASK, "%s", __func__);
task_set_event(TASK_ID_TPM, TPM_EVENT_RESET, 0);
if (in_interrupt_context() ||
task_get_current() == TASK_ID_TPM)
return 0; /* Can't sleep. Clown'll eat me. */
/* Try to wait until the TPM is reset, but timeout eventually */
waiting_for_reset = task_get_current();
evt = task_wait_event_mask(TPM_EVENT_RESET, SECOND);
/* Timeout is bad */
if (evt & TASK_EVENT_TIMER)
return -1;
/* Otherwise, good */
return 1;
}
static void tpm_reset_now(void)
{
/* This is more related to TPM task activity than TPM transactions */
cprints(CC_TASK, "%s", __func__);
@@ -585,16 +617,20 @@ static void tpm_reset(void)
memset(__bss_libtpm2_start, __bss_libtpm2_end - __bss_libtpm2_start, 0);
/*
* TPM reset currently only clears BSS for the TPM library. It does
* not reset any initialized variables in data. So, make sure there
* aren't any.
* NOTE: Any initialized variables in this file must be placed in a
* separate section (NOT .data). If they need resetting, do so here.
*/
ASSERT(__data_libtpm2_start == __data_libtpm2_end);
/* Re-initialize our registers */
tpm_init();
sps_tpm_enable();
if (waiting_for_reset != TASK_ID_INVALID) {
/* Wake the waiting task, if any */
task_set_event(waiting_for_reset, TPM_EVENT_RESET, 0);
waiting_for_reset = TASK_ID_INVALID;
}
}
void tpm_task(void)
@@ -614,7 +650,7 @@ void tpm_task(void)
/* Wait for the next command event */
evt = task_wait_event(-1);
if (evt & TPM_EVENT_RESET) {
tpm_reset();
tpm_reset_now();
continue;
}
tpmh = (struct tpm_cmd_header *)tpm_.regs.data_fifo;

View File

@@ -300,7 +300,15 @@ SECTIONS
STRINGIFY(OUTDIR/common/tpm_registers.o*)(.data)
__data_libtpm2_end = .;
*(.data)
/*
* TPM reset currently only clears BSS for the TPM library. It does
* not reset any initialized variables in data. So, make sure there
* aren't any.
*/
ASSERT(__data_libtpm2_start == __data_libtpm2_end,
"libtpm2 .data section is nonzero");
*(.data*)
#ifdef CONFIG_MPU
/* It has to be aligned by 32 bytes to be a valid MPU region. */
. = ALIGN(32);

View File

@@ -31,6 +31,17 @@ void sps_tpm_disable(void);
/* Get the current value of the burst size field of the status register. */
size_t tpm_get_burst_size(void);
/*
* Reset the TPM. This sends a request to the TPM task, so that the reset can
* happen when the TPM task finishes whatever it's doing at the moment.
*
* Returns 0 if the request was made, but we can't wait for it to complete
* because we're in interrupt context or something similar. Otherwise, it
* blocks and returns 1 after the TPM has been cleared, or returns -1 if the
* request timed out.
*/
int tpm_reset(void);
/*
* This structure describes the header of all commands and responses sent and
* received over TPM FIFO.