1 /*
2  * Copyright Meta Platforms, Inc. and its affiliates.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/coredump.h>
8 #include <zephyr/ztest.h>
9 
10 /* Test will verify that these values are present in the core dump */
11 #define TEST_MEMORY_VALUE_0 0xabababab
12 #define TEST_MEMORY_VALUE_1 0xcdcdcdcd
13 #define TEST_MEMORY_VALUE_2 0xefefefef
14 
15 #if defined(CONFIG_BOARD_QEMU_RISCV32)
16 #define TEST_MEMORY_VALUE_3 0x12121212
17 #define TEST_MEMORY_VALUE_4 0x34343434
18 #define TEST_MEMORY_VALUE_5 0x56565656
19 #define TEST_MEMORY_VALUE_6 0x78787878
20 #define TEST_MEMORY_VALUE_7 0x90909090
21 #endif
22 
23 #define TEST_MEMORY_VALUE_8 0xbabababa
24 
25 #ifdef CONFIG_COVERAGE_DUMP
26 #include <zephyr/debug/gcov.h>
27 #endif
28 
29 static uint32_t values_to_dump[3];
30 static struct coredump_mem_region_node dump_region0 = {
31 	.start = (uintptr_t)&values_to_dump,
32 	.size = sizeof(values_to_dump)
33 };
34 
k_sys_fatal_error_handler(unsigned int reason,const struct arch_esf * pEsf)35 void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf)
36 {
37 	ARG_UNUSED(pEsf);
38 
39 	printk("%s as expected; reason = %u; halting ...\n", __func__, reason);
40 
41 #ifdef CONFIG_COVERAGE_DUMP
42 	gcov_coverage_dump();  /* LCOV_EXCL_LINE */
43 #endif
44 	k_fatal_halt(reason);
45 }
46 
47 
test_coredump_callback(uintptr_t dump_area,size_t dump_area_size)48 static void test_coredump_callback(uintptr_t dump_area, size_t dump_area_size)
49 {
50 	uint32_t expected_size = DT_PROP_BY_IDX(DT_NODELABEL(coredump_devicecb), memory_regions, 1);
51 
52 	zassert_equal(dump_area_size, expected_size, "Size in callback doesn't match device tree");
53 	zassert_not_null((void *)dump_area, "dump_area is NULL");
54 
55 	uint32_t *mem = (uint32_t *)dump_area;
56 	*mem = TEST_MEMORY_VALUE_8;
57 }
58 
coredump_tests_suite_setup(void)59 static void *coredump_tests_suite_setup(void)
60 {
61 #if defined(CONFIG_BOARD_QEMU_RISCV32)
62 	/* Get addresses of memory regions specified in device tree to fill with test data */
63 	uint32_t *mem0 =
64 		(uint32_t *)DT_PROP_BY_IDX(DT_NODELABEL(coredump_device0), memory_regions, 0);
65 	uint32_t *mem1 =
66 		(uint32_t *)DT_PROP_BY_IDX(DT_NODELABEL(coredump_device0), memory_regions, 2);
67 	uint32_t *mem2 =
68 		(uint32_t *)DT_PROP_BY_IDX(DT_NODELABEL(coredump_device1), memory_regions, 0);
69 
70 	*mem0 = TEST_MEMORY_VALUE_3;
71 	*mem1 = TEST_MEMORY_VALUE_4;
72 	mem2[0] = TEST_MEMORY_VALUE_5;
73 	mem2[1] = TEST_MEMORY_VALUE_6;
74 	mem2[2] = TEST_MEMORY_VALUE_7;
75 #endif
76 
77 	return NULL;
78 }
79 
80 ZTEST_SUITE(coredump_tests, NULL, coredump_tests_suite_setup, NULL, NULL, NULL);
81 
ZTEST(coredump_tests,test_register_memory)82 ZTEST(coredump_tests, test_register_memory)
83 {
84 	const struct device *const coredump_dev = DEVICE_DT_GET(DT_NODELABEL(coredump_device0));
85 	const struct device *const coredump_cb_dev = DEVICE_DT_GET(DT_NODELABEL(coredump_devicecb));
86 
87 	zassert_not_null(coredump_dev, "Cannot get coredump device");
88 
89 	/* Verify register callback fails for COREDUMP_TYPE_MEMCPY type device */
90 	zassert_false(coredump_device_register_callback(coredump_dev, test_coredump_callback),
91 		"register callback unexpected succeeded");
92 
93 	/* Verify unregister fails for memory that was never registered */
94 	zassert_false(coredump_device_unregister_memory(coredump_dev, &dump_region0),
95 		"unregister unexpected succeeded");
96 
97 	/* Verify unregister succeeds after registration */
98 	zassert_true(coredump_device_register_memory(coredump_dev, &dump_region0),
99 		"register failed");
100 	zassert_true(coredump_device_unregister_memory(coredump_dev, &dump_region0),
101 		"unregister failed");
102 
103 	/* Register dump_region0 to be collected in core dump and set test values */
104 	zassert_true(coredump_device_register_memory(coredump_dev, &dump_region0),
105 		"register failed");
106 	values_to_dump[0] = TEST_MEMORY_VALUE_0;
107 	values_to_dump[1] = TEST_MEMORY_VALUE_1;
108 	values_to_dump[2] = TEST_MEMORY_VALUE_2;
109 
110 	/* Verify register memory region fails for COREDUMP_TYPE_CALLBACK type device */
111 	zassert_false(coredump_device_register_memory(coredump_cb_dev, &dump_region0),
112 		"register memory unexpected succeeded");
113 
114 	/* Register callback to be invoked for the COREDUMP_TYPE_CALLBACK type device  */
115 	zassert_true(coredump_device_register_callback(coredump_cb_dev, test_coredump_callback),
116 		"register failed");
117 
118 	/* Force a crash */
119 	k_panic();
120 }
121