/ tests / lib / spd_cache-test.c
spd_cache-test.c
  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  
 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  
 29  static int setup_spd_cache_test(void **state)
 30  {
 31  	memset(flash_buffer, 0xff, flash_buffer_size);
 32  	return 0;
 33  }
 34  
 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  
 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. */
 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  
 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  
 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  
 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  
 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  
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.  */
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  
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 */
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  
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  
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  
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  
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  
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  
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  }