xref: /aosp_15_r20/external/coreboot/tests/lib/spd_cache-test.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <crc_byte.h>
4 #include <spd_bin.h>
5 #include <spd_cache.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <tests/test.h>
9 #include <tests/lib/spd_cache_data.h>
10 
11 struct region_device flash_rdev_rw;
12 static char *flash_buffer = NULL;
13 static size_t flash_buffer_size = 0;
14 
setup_spd_cache(void ** state)15 static int setup_spd_cache(void **state)
16 {
17 	flash_buffer_size = SC_SPD_TOTAL_LEN + SC_CRC_LEN;
18 	flash_buffer = malloc(flash_buffer_size);
19 
20 	if (flash_buffer == NULL) {
21 		flash_buffer_size = 0;
22 		return -1;
23 	}
24 
25 	rdev_chain_mem_rw(&flash_rdev_rw, flash_buffer, flash_buffer_size);
26 	return 0;
27 }
28 
setup_spd_cache_test(void ** state)29 static int setup_spd_cache_test(void **state)
30 {
31 	memset(flash_buffer, 0xff, flash_buffer_size);
32 	return 0;
33 }
34 
teardown_spd_cache(void ** state)35 static int teardown_spd_cache(void **state)
36 {
37 	rdev_chain_mem_rw(&flash_rdev_rw, NULL, 0);
38 	free(flash_buffer);
39 	flash_buffer = NULL;
40 	flash_buffer_size = 0;
41 	return 0;
42 }
43 
44 
fmap_locate_area_as_rdev(const char * name,struct region_device * area)45 int fmap_locate_area_as_rdev(const char *name, struct region_device *area)
46 {
47 	return rdev_chain(area, &flash_rdev_rw, 0, flash_buffer_size);
48 }
49 
50 /* This test verifies if load_spd_cache() correctly loads spd_cache pointer and size
51    from provided region_device. Memory region device is returned by our
52    fmap_locate_area_as_rdev() override. */
test_load_spd_cache(void ** state)53 static void test_load_spd_cache(void **state)
54 {
55 	uint8_t *spd_cache;
56 	size_t spd_cache_sz;
57 
58 	assert_int_equal(CB_SUCCESS, load_spd_cache(&spd_cache, &spd_cache_sz));
59 	assert_ptr_equal(flash_buffer, spd_cache);
60 	assert_int_equal(SC_SPD_TOTAL_LEN + SC_CRC_LEN, spd_cache_sz);
61 }
62 
calc_spd_cache_crc(uint8_t * spd_cache)63 static void calc_spd_cache_crc(uint8_t *spd_cache)
64 {
65 	*(uint16_t *)(spd_cache + SC_CRC_OFFSET) = CRC(spd_cache, SC_SPD_TOTAL_LEN, crc16_byte);
66 }
67 
fill_spd_cache_ddr3(uint8_t * spd_cache,size_t spd_cache_sz)68 __attribute__((unused)) static void fill_spd_cache_ddr3(uint8_t *spd_cache, size_t spd_cache_sz)
69 {
70 	assert_true(spd_cache_sz >= (spd_data_ddr3_1_sz + sizeof(uint16_t)));
71 
72 	memcpy(spd_cache, spd_data_ddr3_1, spd_data_ddr3_1_sz);
73 	memset(spd_cache + spd_data_ddr3_1_sz, 0, spd_cache_sz - spd_data_ddr3_1_sz);
74 	calc_spd_cache_crc(spd_cache);
75 }
76 
fill_spd_cache_ddr4(uint8_t * spd_cache,size_t spd_cache_sz)77 __attribute__((unused)) static void fill_spd_cache_ddr4(uint8_t *spd_cache, size_t spd_cache_sz)
78 {
79 	assert_true(spd_cache_sz
80 		    >= (spd_data_ddr4_1_sz + spd_data_ddr4_2_sz + sizeof(uint16_t)));
81 
82 	memcpy(spd_cache, spd_data_ddr4_1, spd_data_ddr4_1_sz);
83 	memcpy(spd_cache + spd_data_ddr4_1_sz, spd_data_ddr4_2, spd_data_ddr4_2_sz);
84 	memset(spd_cache + spd_data_ddr4_1_sz + spd_data_ddr4_2_sz, 0,
85 	       spd_cache_sz - (spd_data_ddr4_1_sz + spd_data_ddr4_2_sz));
86 	calc_spd_cache_crc(spd_cache);
87 }
88 
test_spd_fill_from_cache(void ** state)89 static void test_spd_fill_from_cache(void **state)
90 {
91 	struct spd_block blk;
92 	uint8_t *spd_cache;
93 	size_t spd_cache_sz;
94 	assert_int_equal(CB_SUCCESS, load_spd_cache(&spd_cache, &spd_cache_sz));
95 
96 	/* Empty spd cache */
97 	assert_int_equal(CB_ERR, spd_fill_from_cache(spd_cache, &blk));
98 
99 #if __TEST_SPD_CACHE_DDR == 3
100 	fill_spd_cache_ddr3(spd_cache, spd_cache_sz);
101 #elif __TEST_SPD_CACHE_DDR == 4
102 	fill_spd_cache_ddr4(spd_cache, spd_cache_sz);
103 #endif
104 	assert_int_equal(CB_SUCCESS, spd_fill_from_cache(spd_cache, &blk));
105 }
106 
107 
test_spd_cache_is_valid(void ** state)108 static void test_spd_cache_is_valid(void **state)
109 {
110 	uint8_t *spd_cache;
111 	size_t spd_cache_sz;
112 	assert_int_equal(CB_SUCCESS, load_spd_cache(&spd_cache, &spd_cache_sz));
113 
114 	/* Empty, incorrect SPD */
115 	assert_false(spd_cache_is_valid(spd_cache, spd_cache_sz));
116 
117 #if __TEST_SPD_CACHE_DDR == 3
118 	fill_spd_cache_ddr3(spd_cache, spd_cache_sz);
119 #elif __TEST_SPD_CACHE_DDR == 4
120 	fill_spd_cache_ddr4(spd_cache, spd_cache_sz);
121 #endif
122 	assert_true(spd_cache_is_valid(spd_cache, spd_cache_sz));
123 }
124 
125 
126 /* Used for setting `sn` parameter value */
127 static u32 get_spd_sn_ret_sn[SC_SPD_NUMS] = {0};
128 static size_t get_spd_sn_ret_sn_idx = 0;
129 /* Implementation for testing purposes.  */
get_spd_sn(u8 addr,u32 * sn)130 enum cb_err get_spd_sn(u8 addr, u32 *sn)
131 {
132 	*sn = get_spd_sn_ret_sn[get_spd_sn_ret_sn_idx];
133 	get_spd_sn_ret_sn_idx = (get_spd_sn_ret_sn_idx + 1) % ARRAY_SIZE(get_spd_sn_ret_sn);
134 
135 	return mock_type(enum cb_err);
136 }
137 
get_sn_from_spd_cache(uint8_t * spd_cache,u32 arr[])138 static void get_sn_from_spd_cache(uint8_t *spd_cache, u32 arr[])
139 {
140 	for (int i = 0; i < SC_SPD_NUMS; ++i)
141 		arr[i] = *(u32 *)(spd_cache + SC_SPD_OFFSET(i) + DDR4_SPD_SN_OFF);
142 }
143 
144 /* check_if_dimm_changed() has is used only with DDR4, so there tests are not used for DDR3 */
test_check_if_dimm_changed_not_changed(void ** state)145 __attribute__((unused)) static void test_check_if_dimm_changed_not_changed(void **state)
146 {
147 	uint8_t *spd_cache;
148 	size_t spd_cache_sz;
149 	struct spd_block blk = {.addr_map = {0x50, 0x51, 0x52, 0x53},
150 				.spd_array = {0}, .len = 0};
151 
152 	assert_int_equal(CB_SUCCESS, load_spd_cache(&spd_cache, &spd_cache_sz));
153 	fill_spd_cache_ddr4(spd_cache, spd_cache_sz);
154 	assert_int_equal(CB_SUCCESS, spd_fill_from_cache(spd_cache, &blk));
155 
156 	get_sn_from_spd_cache(spd_cache, get_spd_sn_ret_sn);
157 	get_spd_sn_ret_sn_idx = 0;
158 	will_return_count(get_spd_sn, CB_SUCCESS, SC_SPD_NUMS);
159 	assert_false(check_if_dimm_changed(spd_cache, &blk));
160 }
161 
test_check_if_dimm_changed_sn_error(void ** state)162 __attribute__((unused)) static void test_check_if_dimm_changed_sn_error(void **state)
163 {
164 	uint8_t *spd_cache;
165 	size_t spd_cache_sz;
166 	struct spd_block blk = {.addr_map = {0x50, 0x51, 0x52, 0x53},
167 				.spd_array = {0}, .len = 0};
168 
169 	assert_int_equal(CB_SUCCESS, load_spd_cache(&spd_cache, &spd_cache_sz));
170 	fill_spd_cache_ddr4(spd_cache, spd_cache_sz);
171 	assert_int_equal(CB_SUCCESS, spd_fill_from_cache(spd_cache, &blk));
172 
173 	/* Simulate error */
174 	will_return_count(get_spd_sn, CB_ERR, 1);
175 	assert_true(check_if_dimm_changed(spd_cache, &blk));
176 }
177 
test_check_if_dimm_changed_sodimm_lost(void ** state)178 __attribute__((unused)) static void test_check_if_dimm_changed_sodimm_lost(void **state)
179 {
180 	uint8_t *spd_cache;
181 	size_t spd_cache_sz;
182 	struct spd_block blk = {.addr_map = {0x50, 0x51, 0x52, 0x53},
183 				.spd_array = {0}, .len = 0};
184 
185 	assert_int_equal(CB_SUCCESS, load_spd_cache(&spd_cache, &spd_cache_sz));
186 	fill_spd_cache_ddr4(spd_cache, spd_cache_sz);
187 	assert_int_equal(CB_SUCCESS, spd_fill_from_cache(spd_cache, &blk));
188 	get_sn_from_spd_cache(spd_cache, get_spd_sn_ret_sn);
189 	memset(spd_cache + spd_data_ddr4_1_sz, 0xff, spd_data_ddr4_2_sz);
190 
191 	get_spd_sn_ret_sn_idx = 0;
192 	will_return_always(get_spd_sn, CB_SUCCESS);
193 	assert_true(check_if_dimm_changed(spd_cache, &blk));
194 }
195 
test_check_if_dimm_changed_new_sodimm(void ** state)196 __attribute__((unused)) static void test_check_if_dimm_changed_new_sodimm(void **state)
197 {
198 	uint8_t *spd_cache;
199 	size_t spd_cache_sz;
200 	struct spd_block blk = {.addr_map = {0x50, 0x51, 0x52, 0x53},
201 				.spd_array = {0}, .len = 0};
202 
203 	assert_int_equal(CB_SUCCESS, load_spd_cache(&spd_cache, &spd_cache_sz));
204 	fill_spd_cache_ddr4(spd_cache, spd_cache_sz);
205 	assert_int_equal(CB_SUCCESS, spd_fill_from_cache(spd_cache, &blk));
206 	get_sn_from_spd_cache(spd_cache, get_spd_sn_ret_sn);
207 	memcpy(spd_cache + spd_data_ddr4_1_sz + spd_data_ddr4_2_sz, spd_data_ddr4_2,
208 	       spd_data_ddr4_2_sz);
209 
210 	get_spd_sn_ret_sn_idx = 0;
211 	will_return_always(get_spd_sn, CB_SUCCESS);
212 	assert_true(check_if_dimm_changed(spd_cache, &blk));
213 }
214 
test_check_if_dimm_changed_sn_changed(void ** state)215 __attribute__((unused)) static void test_check_if_dimm_changed_sn_changed(void **state)
216 {
217 	uint8_t *spd_cache;
218 	size_t spd_cache_sz;
219 	struct spd_block blk = {.addr_map = {0x50, 0x51, 0x52, 0x53},
220 				.spd_array = {0}, .len = 0};
221 
222 	assert_int_equal(CB_SUCCESS, load_spd_cache(&spd_cache, &spd_cache_sz));
223 	fill_spd_cache_ddr4(spd_cache, spd_cache_sz);
224 	assert_int_equal(CB_SUCCESS, spd_fill_from_cache(spd_cache, &blk));
225 	get_sn_from_spd_cache(spd_cache, get_spd_sn_ret_sn);
226 	*(u32 *)(spd_cache + SC_SPD_OFFSET(0) + DDR4_SPD_SN_OFF) = 0x43211234;
227 
228 	get_spd_sn_ret_sn_idx = 0;
229 	will_return_always(get_spd_sn, CB_SUCCESS);
230 	assert_true(check_if_dimm_changed(spd_cache, &blk));
231 }
232 
test_check_if_dimm_changed_with_nonexistent(void ** state)233 __attribute__((unused)) static void test_check_if_dimm_changed_with_nonexistent(void **state)
234 {
235 	uint8_t *spd_cache;
236 	size_t spd_cache_sz;
237 	struct spd_block blk = {.addr_map = {0x50, 0, 0, 0},
238 				.spd_array = {0}, .len = 0};
239 
240 	assert_int_equal(CB_SUCCESS, load_spd_cache(&spd_cache, &spd_cache_sz));
241 	memcpy(spd_cache, spd_data_ddr4_1, spd_data_ddr4_1_sz);
242 	memset(spd_cache + spd_data_ddr4_1_sz, 0xff, spd_cache_sz - spd_data_ddr4_1_sz);
243 	calc_spd_cache_crc(spd_cache);
244 	assert_int_equal(CB_SUCCESS, spd_fill_from_cache(spd_cache, &blk));
245 
246 	get_sn_from_spd_cache(spd_cache, get_spd_sn_ret_sn);
247 	get_spd_sn_ret_sn_idx = 0;
248 	will_return_always(get_spd_sn, CB_SUCCESS);
249 	assert_false(check_if_dimm_changed(spd_cache, &blk));
250 }
251 
main(void)252 int main(void)
253 {
254 	const struct CMUnitTest tests[] = {
255 		cmocka_unit_test_setup(test_load_spd_cache, setup_spd_cache_test),
256 		cmocka_unit_test_setup(test_spd_fill_from_cache, setup_spd_cache_test),
257 		cmocka_unit_test_setup(test_spd_cache_is_valid, setup_spd_cache_test),
258 #if __TEST_SPD_CACHE_DDR == 4
259 		cmocka_unit_test_setup(test_check_if_dimm_changed_not_changed,
260 				       setup_spd_cache_test),
261 		cmocka_unit_test_setup(test_check_if_dimm_changed_sn_error,
262 				       setup_spd_cache_test),
263 		cmocka_unit_test_setup(test_check_if_dimm_changed_sodimm_lost,
264 				       setup_spd_cache_test),
265 		cmocka_unit_test_setup(test_check_if_dimm_changed_new_sodimm,
266 				       setup_spd_cache_test),
267 		cmocka_unit_test_setup(test_check_if_dimm_changed_sn_changed,
268 				       setup_spd_cache_test),
269 		cmocka_unit_test_setup(test_check_if_dimm_changed_with_nonexistent,
270 				       setup_spd_cache_test),
271 #endif
272 	};
273 
274 	return cb_run_group_tests(tests, setup_spd_cache, teardown_spd_cache);
275 }
276