summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2016-09-21 16:58:26 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-09-24 16:22:14 -0700
commit4250da3ba977fd6bfb80b1bf6086cd142c461e5a (patch)
tree486186f63516d68ef1f7738523a640727fb306b7
parente29005abe7497988e14e0ef87f602a5417d003e6 (diff)
downloadchrome-ec-4250da3ba977fd6bfb80b1bf6086cd142c461e5a.tar.gz
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>
-rw-r--r--board/cr50/board.c2
-rw-r--r--board/cr50/board.h3
-rw-r--r--common/tpm_registers.c48
-rw-r--r--core/cortex-m/ec.lds.S10
-rw-r--r--include/tpm_registers.h11
5 files changed, 63 insertions, 11 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c
index 31a8d2fef1..c967871c8e 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -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)
diff --git a/board/cr50/board.h b/board/cr50/board.h
index cc7589e750..7d11abd60d 100644
--- a/board/cr50/board.h
+++ b/board/cr50/board.h
@@ -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) */
diff --git a/common/tpm_registers.c b/common/tpm_registers.c
index 6fcd6eb839..5728dc6f92 100644
--- a/common/tpm_registers.c
+++ b/common/tpm_registers.c
@@ -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;
diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S
index 5b756cec58..9e791f0380 100644
--- a/core/cortex-m/ec.lds.S
+++ b/core/cortex-m/ec.lds.S
@@ -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);
diff --git a/include/tpm_registers.h b/include/tpm_registers.h
index 35f6dff471..037fc73441 100644
--- a/include/tpm_registers.h
+++ b/include/tpm_registers.h
@@ -32,6 +32,17 @@ void sps_tpm_disable(void);
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.
*