summaryrefslogtreecommitdiff
path: root/test/panic_data.c
blob: 8892c17eceefbaa6044b7323cbc509661d335a48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* Copyright 2022 The ChromiumOS Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "builtin/assert.h"
#include "panic.h"
#include "system.h"
#include "task.h"
#include "test_util.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, const char **argv)
{
	test_reset();
	msleep(30); /* Wait for TASK_ID_TEST to initialize */
	task_wake(TASK_ID_TEST);
}