| /* Copyright 2021 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "assert.h" |
| #include "panic.h" |
| #include "system.h" |
| #include "task.h" |
| #include "test_util.h" |
| |
| #if !(defined(CORE_CORTEX_M) || defined(CORE_CORTEX_M0)) |
| #error "Architecture not supported" |
| #endif |
| |
| struct reg_vals { |
| int index; |
| uint32_t val; |
| }; |
| |
| static const struct reg_vals EXPECTED[] = { |
| { .index = CORTEX_PANIC_REGISTER_R4, .val = 0xecec0004 }, |
| { .index = CORTEX_PANIC_REGISTER_R5, .val = 0xecec0005 }, |
| { .index = CORTEX_PANIC_REGISTER_R6, .val = 0xecec0006 }, |
| { .index = CORTEX_PANIC_REGISTER_R7, .val = 0xecec0007 }, |
| { .index = CORTEX_PANIC_REGISTER_R8, .val = 0xecec0008 }, |
| { .index = CORTEX_PANIC_REGISTER_R9, .val = 0xecec0009 }, |
| { .index = CORTEX_PANIC_REGISTER_R10, .val = 0xecec000a }, |
| { .index = CORTEX_PANIC_REGISTER_R11, .val = 0xecec000b }, |
| }; |
| |
| test_static int test_exception_panic_registers(void) |
| { |
| if (IS_ENABLED(CORE_CORTEX_M)) { |
| asm volatile("ldr r0, =0xecec0000\n" |
| "ldr r1, =0xecec0001\n" |
| "ldr r2, =0xecec0002\n" |
| "ldr r3, =0xecec0003\n" |
| "ldr r4, =0xecec0004\n" |
| "ldr r5, =0xecec0005\n" |
| "ldr r6, =0xecec0006\n" |
| "ldr r7, =0xecec0007\n" |
| "ldr r8, =0xecec0008\n" |
| "ldr r9, =0xecec0009\n" |
| "ldr r10, =0xecec000a\n" |
| "ldr r11, =0xecec000b\n" |
| "ldr r14, =0xecec000e\n" |
| /* Undefined instruction. */ |
| "udf #0\n"); |
| } else if (IS_ENABLED(CORE_CORTEX_M0)) { |
| asm volatile("ldr r1, =0xecec0001\n" |
| "ldr r2, =0xecec0002\n" |
| "ldr r3, =0xecec0003\n" |
| "ldr r4, =0xecec0004\n" |
| "ldr r5, =0xecec0005\n" |
| "ldr r6, =0xecec0006\n" |
| "ldr r7, =0xecec0007\n" |
| "ldr r0, =0xecec0008\n" |
| "mov r8, r0\n" |
| "ldr r0, =0xecec0009\n" |
| "mov r9, r0\n" |
| "ldr r0, =0xecec000a\n" |
| "mov r10, r0\n" |
| "ldr r0, =0xecec000b\n" |
| "mov r11, r0\n" |
| "ldr r0, =0xecec000e\n" |
| "mov r14, r0\n" |
| /* Undefined instruction. */ |
| "udf #0\n"); |
| } |
| __builtin_unreachable(); |
| } |
| |
| test_static void run_test_step1(void) |
| { |
| ccprintf("Step 1: Panic\n"); |
| system_set_scratchpad(TEST_STATE_MASK(TEST_STATE_STEP_2)); |
| RUN_TEST(test_exception_panic_registers); |
| } |
| |
| test_static int run_test_step2(void) |
| { |
| struct panic_data *data; |
| int i; |
| |
| ccprintf("Step 2: Read panic data\n"); |
| data = panic_get_data(); |
| for (i = 0; i < ARRAY_SIZE(EXPECTED); i++) { |
| TEST_EQ(EXPECTED[i].val, data->cm.regs[EXPECTED[i].index], |
| "%04x"); |
| cflush(); |
| } |
| return EC_SUCCESS; |
| } |
| |
| void test_run_step(uint32_t state) |
| { |
| int ret; |
| |
| if (state & TEST_STATE_MASK(TEST_STATE_STEP_1)) |
| run_test_step1(); |
| else if (state & TEST_STATE_MASK(TEST_STATE_STEP_2)) { |
| ret = run_test_step2(); |
| if (ret == EC_SUCCESS) |
| test_reboot_to_next_step(TEST_STATE_PASSED); |
| else |
| test_reboot_to_next_step(TEST_STATE_FAILED); |
| } |
| } |
| |
| int task_test(void *unused) |
| { |
| test_run_multistep(); |
| return EC_SUCCESS; |
| } |
| |
| void run_test(int argc, const char **argv) |
| { |
| msleep(30); /* Wait for TASK_ID_TEST to initialize */ |
| task_wake(TASK_ID_TEST); |
| } |