diff options
author | Marius Schilder <mschilder@google.com> | 2019-06-25 13:48:42 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-07-29 23:43:53 +0000 |
commit | 7c9aff6ff731db0da18f8fe8232196cf71fd09f4 (patch) | |
tree | 7707f6e58c73a62b316d34e94f523bae2579a32f /chip | |
parent | 234c5298c8369e18eac135b50fc3dec61afe510e (diff) | |
download | chrome-ec-7c9aff6ff731db0da18f8fe8232196cf71fd09f4.tar.gz |
g: reset and wipe dcrypto engine after timeout.
In case of a timeout, we need to clean up state and make sure engine
is ready for a subsequent call.
Added dcrypto_test console command to test the various scenarios:
stack overflow, infinite loop and cfi failure recovery.
Signed-off-by: mschilder@google.com
BUG=b:135772657
BRANCH=none
TEST=run console command dcrypto_test; build and run cr53
Change-Id: I531a59de6f2cf6941c797aeeeabb10eb10f02c9b
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1677229
Reviewed-by: Marius Schilder <mschilder@chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
Tested-by: Marius Schilder <mschilder@chromium.org>
Commit-Queue: Marius Schilder <mschilder@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r-- | chip/g/dcrypto/dcrypto_runtime.c | 225 |
1 files changed, 203 insertions, 22 deletions
diff --git a/chip/g/dcrypto/dcrypto_runtime.c b/chip/g/dcrypto/dcrypto_runtime.c index 052547a436..3f2efb54be 100644 --- a/chip/g/dcrypto/dcrypto_runtime.c +++ b/chip/g/dcrypto/dcrypto_runtime.c @@ -12,13 +12,44 @@ static struct mutex dcrypto_mutex; static volatile task_id_t my_task_id; -static int dcrypto_is_initialized; +static uint8_t dcrypto_is_initialized; -void dcrypto_init_and_lock(void) +static const uint32_t wiped_value = 0xdddddddd; + +static void dcrypto_reset_and_wipe(void) { int i; volatile uint32_t *ptr; + /* Reset. */ + GREG32(CRYPTO, CONTROL) = GC_CRYPTO_CONTROL_RESET_MASK; + GREG32(CRYPTO, CONTROL) = 0; + + /* Reset all the status bits. */ + GREG32(CRYPTO, INT_STATE) = -1; + + /* Wipe state. */ + GREG32(CRYPTO, WIPE_SECRETS) = 1; + + /* Wipe DMEM. */ + ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); + for (i = 0; i < DMEM_NUM_WORDS; ++i) + *ptr++ = wiped_value; +} + +static void dcrypto_wipe_imem(void) +{ + int i; + volatile uint32_t *ptr; + + /* Wipe IMEM. */ + ptr = GREG32_ADDR(CRYPTO, IMEM_DUMMY); + for (i = 0; i < IMEM_NUM_WORDS; ++i) + *ptr++ = wiped_value; +} + +void dcrypto_init_and_lock(void) +{ mutex_lock(&dcrypto_mutex); my_task_id = task_get_current(); @@ -29,9 +60,8 @@ void dcrypto_init_and_lock(void) REG_WRITE_MLV(GR_PMU_PERICLKSET0, GC_PMU_PERICLKSET0_DCRYPTO0_CLK_MASK, GC_PMU_PERICLKSET0_DCRYPTO0_CLK_LSB, 1); - /* Reset. */ - REG_WRITE_MLV(GR_PMU_RST0, GC_PMU_RST0_DCRYPTO0_MASK, - GC_PMU_RST0_DCRYPTO0_LSB, 0); + dcrypto_reset_and_wipe(); + dcrypto_wipe_imem(); /* Turn off random nops (which are enabled by default). */ GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, STALL_EN, 0); @@ -40,25 +70,11 @@ void dcrypto_init_and_lock(void) /* Now turn on random nops. */ GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, STALL_EN, 1); - /* Initialize DMEM. */ - ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); - for (i = 0; i < DMEM_NUM_WORDS; ++i) - *ptr++ = 0xdddddddd; - - /* Initialize IMEM. */ - ptr = GREG32_ADDR(CRYPTO, IMEM_DUMMY); - for (i = 0; i < IMEM_NUM_WORDS; ++i) - *ptr++ = 0xdddddddd; - GREG32(CRYPTO, INT_STATE) = -1; /* Reset all the status bits. */ GREG32(CRYPTO, INT_ENABLE) = -1; /* Enable all status bits. */ task_enable_irq(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT); - /* Reset. */ - GREG32(CRYPTO, CONTROL) = 1; - GREG32(CRYPTO, CONTROL) = 0; - dcrypto_is_initialized = 1; } @@ -72,7 +88,7 @@ void dcrypto_unlock(void) #endif /* * When running on Cr50 this event belongs in the TPM task event space. Make - * sure there is no collision with events defined in ./common/tpm_regsters.c. + * sure there is no collision with events defined in ./common/tpm_registers.c. */ #define TASK_EVENT_DCRYPTO_DONE TASK_EVENT_CUSTOM_BIT(0) @@ -92,8 +108,19 @@ uint32_t dcrypto_call(uint32_t adr) /* TODO(ngm): switch return value to an enum. */ switch (event) { case TASK_EVENT_DCRYPTO_DONE: - return 0; + /* + * We expect only the CMD_RECV status bit to be set at this + * point. CMD_DONE got cleared in the interrupt handler. Any and + * all other bits are indicative of error. + * Except for MOD_OPERAND_OUT_OF_RANGE, which is noise. + */ + if ((GREG32(CRYPTO, INT_STATE) & + ~(GC_CRYPTO_INT_STATE_MOD_OPERAND_OUT_OF_RANGE_MASK | + GC_CRYPTO_INT_STATE_HOST_CMD_RECV_MASK)) == 0) + return 0; + /* fall through */ default: + dcrypto_reset_and_wipe(); return 1; } } @@ -101,7 +128,6 @@ uint32_t dcrypto_call(uint32_t adr) void __keep dcrypto_done_interrupt(void) { GREG32(CRYPTO, INT_STATE) = GC_CRYPTO_INT_STATE_HOST_CMD_DONE_MASK; - task_clear_pending_irq(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT); task_set_event(my_task_id, TASK_EVENT_DCRYPTO_DONE, 0); } DECLARE_IRQ(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT, dcrypto_done_interrupt, 1); @@ -142,3 +168,158 @@ uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words) } return diff; } + +#ifdef DCRYPTO_RUNTIME_TEST +/* + * Add console command "dcrypto_test" that runs a couple of engine failure + * scenarios and checks for adequate handling thereof: + * - error return code + * - dmem erasure on error + * - dmem preservation on success + */ +#include "console.h" + +/* AUTO-GENERATED. DO NOT MODIFY. */ +/* clang-format off */ +static const uint32_t IMEM_test_hang[] = { +/* @0x0: function forever[2] { */ +#define CF_forever_adr 0 +/*forever: */ + 0x10080000, /* b forever */ + 0x0c000000, /* ret */ +/* } */ +/* @0x2: function func17[2] { */ +#define CF_func17_adr 2 + 0x08000000, /* call &forever */ + 0x0c000000, /* ret */ +/* } */ +/* @0x4: function func16[2] { */ +#define CF_func16_adr 4 + 0x08000002, /* call &func17 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x6: function func15[2] { */ +#define CF_func15_adr 6 + 0x08000004, /* call &func16 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x8: function func14[2] { */ +#define CF_func14_adr 8 + 0x08000006, /* call &func15 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xa: function func13[2] { */ +#define CF_func13_adr 10 + 0x08000008, /* call &func14 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xc: function func12[2] { */ +#define CF_func12_adr 12 + 0x0800000a, /* call &func13 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xe: function func11[2] { */ +#define CF_func11_adr 14 + 0x0800000c, /* call &func12 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x10: function func10[2] { */ +#define CF_func10_adr 16 + 0x0800000e, /* call &func11 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x12: function func9[2] { */ +#define CF_func9_adr 18 + 0x08000010, /* call &func10 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x14: function func8[2] { */ +#define CF_func8_adr 20 + 0x08000012, /* call &func9 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x16: function func7[2] { */ +#define CF_func7_adr 22 + 0x08000014, /* call &func8 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x18: function func6[2] { */ +#define CF_func6_adr 24 + 0x08000016, /* call &func7 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1a: function func5[2] { */ +#define CF_func5_adr 26 + 0x08000018, /* call &func6 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1c: function func4[2] { */ +#define CF_func4_adr 28 + 0x0800001a, /* call &func5 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1e: function func3[2] { */ +#define CF_func3_adr 30 + 0x0800001c, /* call &func4 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x20: function func2[2] { */ +#define CF_func2_adr 32 + 0x0800001e, /* call &func3 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x22: function func1[2] { */ +#define CF_func1_adr 34 + 0x08000020, /* call &func2 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x24: function test[2] { */ +#define CF_test_adr 36 + 0x08000022, /* call &func1 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x26: function sigchk[2] { */ +#define CF_sigchk_adr 38 + 0xf8000004, /* sigini #4 */ + 0xf9ccc3c2, /* sigchk #13419458 */ +/* } */ +}; +/* clang-format on */ + +static int command_dcrypto_test(int argc, char *argv[]) +{ + volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); + uint32_t not_wiped = ~wiped_value; + int result; + + dcrypto_init_and_lock(); + dcrypto_imem_load(0, IMEM_test_hang, ARRAY_SIZE(IMEM_test_hang)); + + *ptr = not_wiped; + result = dcrypto_call(CF_func2_adr); /* max legal stack, into hang */ + if (result != 1 || *ptr != wiped_value) + ccprintf("dcrypto_test: fail1 %d,%08x\n", result, *ptr); + + *ptr = not_wiped; + result = dcrypto_call(CF_test_adr); /* stack overflow */ + if (result != 1 || *ptr != wiped_value) + ccprintf("dcrypto_test: fail2 %d,%08x\n", result, *ptr); + + *ptr = not_wiped; + result = dcrypto_call(CF_sigchk_adr); /* cfi trap */ + if (result != 1 || *ptr != wiped_value) + ccprintf("dcrypto_test: fail3 %d,%08x\n", result, *ptr); + + *ptr = not_wiped; + result = dcrypto_call(CF_test_adr + 1); /* simple ret should succeed */ + if (result != 0 || *ptr != not_wiped) + ccprintf("dcrypto_test: fail4 %d,%08x\n", result, *ptr); + + dcrypto_unlock(); + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_test, command_dcrypto_test, "", + "dcrypto test"); + +#endif /* DCRYPTO_RUNTIME_TEST */ |