summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatryk Duda <pdk@semihalf.com>2022-03-22 09:55:12 +0100
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-04-06 15:10:19 +0000
commit3b9284b13cc4be2f2a8283ff2e63c23b3564a31b (patch)
tree0028764a2e7d9ab86eafc0d916472816b16379a4
parentae35143aa53abfb74f1cd285f10e49a331e2f731 (diff)
downloadchrome-ec-3b9284b13cc4be2f2a8283ff2e63c23b3564a31b.tar.gz
test: Introduce panic data persistency test
The test is going to check if panic data are correct after crash, soft reboot and hard reboot. In the last case we expect to have only 16 bits of a panic reason and info associated with reason. Checking panic data after soft reboot will make sure that RO doesn't overwrite part of panic data created by RW (eg. when doing sysjump). Doing the same checks after hard reboot will make sure that RO is able to restore panic data from backup RAM and RW is restoring any additional data which RO is not aware of (eg. panic flags) correctly. BUG=b:221087395 BRANCH=none TEST=./test/run_device_tests.py -b dartmonkey --test panic_data.* TEST=./test/run_device_tests.py -b bloonchipper --test panic_data.* Signed-off-by: Patryk Duda <pdk@semihalf.com> Change-Id: If84af40fc0045b633effbb32d61061ec20505516 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3555750 Reviewed-by: Andrea Grandi <agrandi@google.com> Reviewed-by: Bobby Casey <bobbycasey@google.com> Reviewed-by: Tom Hughes <tomhughes@chromium.org> Commit-Queue: Patryk Duda <patrykd@google.com>
-rw-r--r--board/hatch_fp/build.mk1
-rw-r--r--board/nocturne_fp/build.mk1
-rw-r--r--test/build.mk1
-rw-r--r--test/panic_data.c140
-rw-r--r--test/panic_data.tasklist10
-rwxr-xr-xtest/run_device_tests.py48
6 files changed, 200 insertions, 1 deletions
diff --git a/board/hatch_fp/build.mk b/board/hatch_fp/build.mk
index 81b5bf4c8b..97dc4e91e4 100644
--- a/board/hatch_fp/build.mk
+++ b/board/hatch_fp/build.mk
@@ -37,6 +37,7 @@ test-list-y=\
fpsensor_hw \
mpu \
mutex \
+ panic_data \
pingpong \
printf \
queue \
diff --git a/board/nocturne_fp/build.mk b/board/nocturne_fp/build.mk
index 1c4a7d187e..6eff719d9b 100644
--- a/board/nocturne_fp/build.mk
+++ b/board/nocturne_fp/build.mk
@@ -37,6 +37,7 @@ test-list-y=\
fpsensor_hw \
mpu \
mutex \
+ panic_data \
pingpong \
printf \
queue \
diff --git a/test/build.mk b/test/build.mk
index c0c9b3cc9e..87606f8751 100644
--- a/test/build.mk
+++ b/test/build.mk
@@ -192,6 +192,7 @@ kasa-y=kasa.o
mpu-y=mpu.o
mutex-y=mutex.o
newton_fit-y=newton_fit.o
+panic_data-y=panic_data.o
pingpong-y=pingpong.o
power_button-y=power_button.o
powerdemo-y=powerdemo.o
diff --git a/test/panic_data.c b/test/panic_data.c
new file mode 100644
index 0000000000..9abbcb7745
--- /dev/null
+++ b/test/panic_data.c
@@ -0,0 +1,140 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "test_util.h"
+
+#include "assert.h"
+#include "panic.h"
+#include "system.h"
+#include "task.h"
+
+static int get_assert_line(void)
+{
+ /* Returned number should point to ASSERT(0) line below */
+ return __LINE__ + 5;
+}
+
+static void crash_system(void)
+{
+ ASSERT(0);
+}
+
+test_static int test_panic_data(void)
+{
+ struct panic_data *pdata = panic_get_data();
+
+ /* Check panic reason. */
+ TEST_EQ(pdata->cm.regs[CORTEX_PANIC_REGISTER_R4], PANIC_SW_ASSERT,
+ "%08x");
+
+ /* Check panic info. */
+ TEST_EQ(pdata->cm.regs[CORTEX_PANIC_REGISTER_R5], get_assert_line(),
+ "%d");
+
+ /*
+ * Check panic exception - it should be always 0 because panic didn't
+ * happen during interrupt processing.
+ */
+ TEST_EQ(pdata->cm.regs[CORTEX_PANIC_REGISTER_IPSR], 0, "%d");
+
+ /* Check panic flags. */
+ TEST_EQ(pdata->flags,
+ PANIC_DATA_FLAG_FRAME_VALID | PANIC_DATA_FLAG_OLD_HOSTEVENT,
+ "%02x");
+
+ return EC_SUCCESS;
+}
+
+/*
+ * After hard reboot we expect to have panic flags, panic exception and lower
+ * 16 bits of panic reason and info (upper 16 bits should be zero). This
+ * information is saved in backup RAM because hard reboot clears memory. The
+ * backup RAM only has 16 bits available for this information. Check if lower
+ * 16 bits of reason and info are present and upper 16 bits are zero.
+ */
+test_static int test_panic_data_half(void)
+{
+ struct panic_data *pdata = panic_get_data();
+
+ /* Check panic reason. */
+ TEST_EQ(pdata->cm.regs[CORTEX_PANIC_REGISTER_R4],
+ (PANIC_SW_ASSERT & 0xffff), "%08x");
+
+ /* Check panic info. */
+ TEST_EQ(pdata->cm.regs[CORTEX_PANIC_REGISTER_R5],
+ (get_assert_line() & 0xffff), "%d");
+
+ /*
+ * Check panic exception - it should be always 0 because panic didn't
+ * happen during interrupt processing.
+ */
+ TEST_EQ(pdata->cm.regs[CORTEX_PANIC_REGISTER_IPSR], 0, "%d");
+
+ /* Check panic flags. */
+ TEST_EQ(pdata->flags,
+ PANIC_DATA_FLAG_FRAME_VALID | PANIC_DATA_FLAG_OLD_HOSTEVENT,
+ "%02x");
+
+ return EC_SUCCESS;
+}
+
+void test_run_step(uint32_t state)
+{
+ /* Step 1: Crash system to get panic data. */
+ if (state & TEST_STATE_MASK(TEST_STATE_STEP_1)) {
+ test_set_next_step(TEST_STATE_STEP_2);
+ /* Crash the system */
+ ccprintf("Crash the system!\n");
+ cflush();
+ crash_system();
+ }
+ /* Step 2: Check panic data after crash and do soft reboot. */
+ else if (state & TEST_STATE_MASK(TEST_STATE_STEP_2)) {
+ RUN_TEST(test_panic_data);
+ if (!test_get_error_count()) {
+ test_set_next_step(TEST_STATE_STEP_3);
+ /* Do a soft system reset */
+ ccprintf("Perform soft reboot\n");
+ cflush();
+ system_reset(0);
+ } else
+ test_reboot_to_next_step(TEST_STATE_FAILED);
+ }
+ /* Step 3: Check panic data after soft reboot and do hard reboot. */
+ else if (state & TEST_STATE_MASK(TEST_STATE_STEP_3)) {
+ RUN_TEST(test_panic_data);
+ if (!test_get_error_count()) {
+ test_set_next_step(TEST_STATE_STEP_4);
+ /* Do a hard system reset */
+ ccprintf("Perform hard reboot\n");
+ cflush();
+ system_reset(SYSTEM_RESET_HARD);
+ } else
+ test_reboot_to_next_step(TEST_STATE_FAILED);
+ }
+ /* Step 4: Check panic data after hard reboot */
+ else if (state & TEST_STATE_MASK(TEST_STATE_STEP_4)) {
+ RUN_TEST(test_panic_data_half);
+ if (!test_get_error_count())
+ test_reboot_to_next_step(TEST_STATE_PASSED);
+ else
+ test_reboot_to_next_step(TEST_STATE_FAILED);
+ }
+}
+
+int task_test(void *unused)
+{
+ if (IS_ENABLED(SECTION_IS_RW))
+ test_run_multistep();
+
+ return EC_SUCCESS;
+}
+
+void run_test(int argc, char **argv)
+{
+ test_reset();
+ msleep(30); /* Wait for TASK_ID_TEST to initialize */
+ task_wake(TASK_ID_TEST);
+}
diff --git a/test/panic_data.tasklist b/test/panic_data.tasklist
new file mode 100644
index 0000000000..6a2f1834ca
--- /dev/null
+++ b/test/panic_data.tasklist
@@ -0,0 +1,10 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**
+ * See CONFIG_TASK_LIST in config.h for details.
+ */
+#define CONFIG_TEST_TASK_LIST \
+ TASK_TEST(TEST, task_test, NULL, TASK_STACK_SIZE)
diff --git a/test/run_device_tests.py b/test/run_device_tests.py
index 2643634062..e138051d0c 100755
--- a/test/run_device_tests.py
+++ b/test/run_device_tests.py
@@ -67,6 +67,18 @@ SERVO_MICRO = 'servo_micro'
GCC = 'gcc'
CLANG = 'clang'
+TEST_ASSETS_BUCKET = 'gs://chromiumos-test-assets-public/fpmcu/RO'
+DARTMONKEY_IMAGE_PATH = os.path.join(
+ TEST_ASSETS_BUCKET, 'dartmonkey_v2.0.2887-311310808.bin')
+NOCTURNE_FP_IMAGE_PATH = os.path.join(
+ TEST_ASSETS_BUCKET, 'nocturne_fp_v2.2.64-58cf5974e.bin')
+NAMI_FP_IMAGE_PATH = os.path.join(
+ TEST_ASSETS_BUCKET, 'nami_fp_v2.2.144-7a08e07eb.bin')
+BLOONCHIPPER_V4277_IMAGE_PATH = os.path.join(
+ TEST_ASSETS_BUCKET, 'bloonchipper_v2.0.4277-9f652bb3.bin')
+BLOONCHIPPER_V5938_IMAGE_PATH = os.path.join(
+ TEST_ASSETS_BUCKET, 'bloonchipper_v2.0.5938-197506c1.bin')
+
class ImageType(Enum):
"""EC Image type to use for the test."""
@@ -78,13 +90,15 @@ class BoardConfig:
"""Board-specific configuration."""
def __init__(self, name, servo_uart_name, servo_power_enable,
- rollback_region0_regex, rollback_region1_regex, mpu_regex):
+ rollback_region0_regex, rollback_region1_regex, mpu_regex,
+ variants):
self.name = name
self.servo_uart_name = servo_uart_name
self.servo_power_enable = servo_power_enable
self.rollback_region0_regex = rollback_region0_regex
self.rollback_region1_regex = rollback_region1_regex
self.mpu_regex = mpu_regex
+ self.variants = variants
class TestConfig:
@@ -204,6 +218,15 @@ class AllTests:
if board_config.name == BLOONCHIPPER:
tests['stm32f_rtc'] = TestConfig(name='stm32f_rtc')
+ # Run panic data tests for all boards and RO versions.
+ for variant_name, variant_info in board_config.variants.items():
+ tests['panic_data_' + variant_name] = (
+ TestConfig(name='panic_data',
+ fail_regexes=[SINGLE_CHECK_FAILED_REGEX,
+ ALL_TESTS_FAILED_REGEX],
+ ro_image=variant_info.get('ro_image_path'),
+ build_board=variant_info.get('build_board')))
+
return tests
@@ -214,6 +237,14 @@ BLOONCHIPPER_CONFIG = BoardConfig(
rollback_region0_regex=DATA_ACCESS_VIOLATION_8020000_REGEX,
rollback_region1_regex=DATA_ACCESS_VIOLATION_8040000_REGEX,
mpu_regex=DATA_ACCESS_VIOLATION_20000000_REGEX,
+ variants={
+ 'bloonchipper_v2.0.4277': {
+ 'ro_image_path': BLOONCHIPPER_V4277_IMAGE_PATH
+ },
+ 'bloonchipper_v2.0.5938': {
+ 'ro_image_path': BLOONCHIPPER_V5938_IMAGE_PATH
+ }
+ }
)
DARTMONKEY_CONFIG = BoardConfig(
@@ -223,6 +254,21 @@ DARTMONKEY_CONFIG = BoardConfig(
rollback_region0_regex=DATA_ACCESS_VIOLATION_80C0000_REGEX,
rollback_region1_regex=DATA_ACCESS_VIOLATION_80E0000_REGEX,
mpu_regex=DATA_ACCESS_VIOLATION_24000000_REGEX,
+ # For dartmonkey board, run panic data test also on nocturne_fp and
+ # nami_fp boards with appropriate RO image.
+ variants={
+ 'dartmonkey_v2.0.2887': {
+ 'ro_image_path': DARTMONKEY_IMAGE_PATH
+ },
+ 'nocturne_fp_v2.2.64': {
+ 'ro_image_path': NOCTURNE_FP_IMAGE_PATH,
+ 'build_board': 'nocturne_fp'
+ },
+ 'nami_fp_v2.2.144': {
+ 'ro_image_path': NAMI_FP_IMAGE_PATH,
+ 'build_board': 'nami_fp'
+ }
+ }
)
BOARD_CONFIGS = {