/ tests / lib / fmap-test.c
fmap-test.c
  1  /* SPDX-License-Identifier: GPL-2.0-only */
  2  
  3  #include <stdlib.h>
  4  #include <string.h>
  5  
  6  #include <tests/test.h>
  7  
  8  #include <fmap.h>
  9  #include <commonlib/region.h>
 10  
 11  #include <tests/lib/fmap/fmap_data.h>
 12  #include <tests/lib/fmap/fmap_config.h>
 13  
 14  static struct region_device flash_rdev_rw;
 15  static struct region_device flash_rdev_ro;
 16  static char *flash_buffer = NULL;
 17  static size_t flash_buffer_size = 0;
 18  
 19  static void prepare_flash_buffer(void)
 20  {
 21  	/* Prepare flash buffer with dummy data and FMAP */
 22  	flash_buffer = malloc(FMAP_SECTION_FLASH_SIZE);
 23  	flash_buffer_size = FMAP_SECTION_FLASH_SIZE;
 24  
 25  	/* Fill first part of buffer with dummy data */
 26  	for (int i = 0; i < FMAP_SECTION_FMAP_START; ++i)
 27  		flash_buffer[i] = 'a' + i % ('z' - 'a');
 28  
 29  	/* Copy FMAP section into buffer */
 30  	memcpy(flash_buffer + FMAP_SECTION_FMAP_START, tests_fmap_bin, FMAP_SIZE);
 31  
 32  	/* Fill rest of buffer with dummy data */
 33  	for (int i = FMAP_SECTION_FMAP_START + FMAP_SECTION_FMAP_SIZE;
 34  	     i < FMAP_SECTION_FLASH_SIZE; ++i)
 35  		flash_buffer[i] = 'a' + i % ('z' - 'a');
 36  }
 37  
 38  static int setup_fmap(void **state)
 39  {
 40  	prepare_flash_buffer();
 41  	rdev_chain_mem_rw(&flash_rdev_rw, flash_buffer, FMAP_SECTION_FLASH_SIZE);
 42  	rdev_chain_mem(&flash_rdev_ro, flash_buffer, FMAP_SECTION_FLASH_SIZE);
 43  	return 0;
 44  }
 45  
 46  static int teardown_fmap(void **state)
 47  {
 48  	rdev_chain_mem_rw(&flash_rdev_rw, NULL, 0);
 49  	rdev_chain_mem(&flash_rdev_ro, NULL, 0);
 50  
 51  	free(flash_buffer);
 52  	flash_buffer = NULL;
 53  	flash_buffer_size = 0;
 54  
 55  	return 0;
 56  }
 57  
 58  void boot_device_init(void)
 59  {
 60  	/* Setup in unit test setup function */
 61  }
 62  
 63  const struct region_device *boot_device_ro(void)
 64  {
 65  	return &flash_rdev_ro;
 66  }
 67  
 68  const struct region_device *boot_device_rw(void)
 69  {
 70  	return &flash_rdev_rw;
 71  }
 72  
 73  static void test_fmap_locate_area_as_rdev(void **state)
 74  {
 75  	const char buffer[] = "abcdefghijk0123456789";
 76  	struct region_device rdev;
 77  
 78  	assert_int_not_equal(-1, fmap_locate_area_as_rdev("RO_VPD", &rdev));
 79  	assert_ptr_equal(flash_buffer + FMAP_SECTION_RO_VPD_START, rdev_mmap_full(&rdev));
 80  	assert_int_equal(FMAP_SECTION_RO_VPD_SIZE, region_device_sz(&rdev));
 81  
 82  	/* Check if locating area second time works */
 83  	assert_int_not_equal(-1, fmap_locate_area_as_rdev("RO_VPD", &rdev));
 84  	assert_ptr_equal(flash_buffer + FMAP_SECTION_RO_VPD_START, rdev_mmap_full(&rdev));
 85  	assert_int_equal(FMAP_SECTION_RO_VPD_SIZE, region_device_sz(&rdev));
 86  
 87  	assert_int_not_equal(-1, fmap_locate_area_as_rdev("RECOVERY_MRC_CACHE", &rdev));
 88  	assert_ptr_equal(flash_buffer + FMAP_SECTION_RECOVERY_MRC_CACHE_START,
 89  			 rdev_mmap_full(&rdev));
 90  	assert_int_equal(FMAP_SECTION_RECOVERY_MRC_CACHE_SIZE, region_device_sz(&rdev));
 91  
 92  	/* Expect error when writing to read-only area */
 93  	assert_int_equal(-1, rdev_writeat(&rdev, buffer, 0, sizeof(buffer)));
 94  
 95  	/* Expect error when looking for incorrect area */
 96  	assert_int_equal(-1, fmap_locate_area_as_rdev("NONEXISTENT_AREA", &rdev));
 97  	assert_int_equal(-1, fmap_locate_area_as_rdev("", &rdev));
 98  	assert_int_equal(-1, fmap_locate_area_as_rdev(NULL, &rdev));
 99  
100  	/* Function fmap_locate_area_as_rdev is not tested with NULL
101  	   as region_device pointer as it is not allowed. */
102  }
103  
104  static void test_fmap_locate_area_as_rdev_rw(void **state)
105  {
106  	struct region_device rdev;
107  	size_t ro_rw_section_size = FMAP_SECTION_MISC_RW_SIZE;
108  	char *buffer1 = malloc(ro_rw_section_size);
109  	char *buffer2 = malloc(ro_rw_section_size);
110  	char *dummy_data = malloc(ro_rw_section_size);
111  
112  	/* Fill buffer with dummy data */
113  	for (int i = 0; i < ro_rw_section_size; ++i)
114  		dummy_data[i] = '0' + i % ('9' - '0');
115  
116  	assert_int_not_equal(-1, fmap_locate_area_as_rdev_rw("RW_SECTION_A", &rdev));
117  	assert_ptr_equal(flash_buffer + FMAP_SECTION_RW_SECTION_A_START, rdev_mmap_full(&rdev));
118  	assert_int_equal(FMAP_SECTION_RW_SECTION_A_SIZE, region_device_sz(&rdev));
119  
120  	/* Check if locating area second time works */
121  	assert_int_not_equal(-1, fmap_locate_area_as_rdev_rw("RW_SECTION_A", &rdev));
122  	assert_ptr_equal(flash_buffer + FMAP_SECTION_RW_SECTION_A_START, rdev_mmap_full(&rdev));
123  	assert_int_equal(FMAP_SECTION_RW_SECTION_A_SIZE, region_device_sz(&rdev));
124  
125  	assert_int_not_equal(-1, fmap_locate_area_as_rdev_rw("MISC_RW", &rdev));
126  	assert_ptr_equal(flash_buffer + FMAP_SECTION_MISC_RW_START, rdev_mmap_full(&rdev));
127  	assert_int_equal(FMAP_SECTION_MISC_RW_SIZE, region_device_sz(&rdev));
128  
129  
130  	/* Expect error when looking for incorrect area */
131  	assert_int_equal(-1, fmap_locate_area_as_rdev_rw("NONEXISTENT_AREA", &rdev));
132  	assert_int_equal(-1, fmap_locate_area_as_rdev_rw("", &rdev));
133  
134  	/* Expect error when passing invalid references */
135  	assert_int_equal(-1, fmap_locate_area_as_rdev_rw(NULL, &rdev));
136  
137  	/* Function fmap_locate_area_as_rdev_rw is not tested with NULL
138  	   as region_device pointer as it is not allowed. */
139  
140  	/* Test if returned section region device is writable */
141  	assert_int_not_equal(-1, fmap_locate_area_as_rdev_rw("MISC_RW", &rdev));
142  	assert_int_equal(ro_rw_section_size,
143  			 rdev_readat(&rdev, buffer1, 0, ro_rw_section_size));
144  	assert_int_equal(ro_rw_section_size,
145  			 rdev_writeat(&rdev, dummy_data, 0, ro_rw_section_size));
146  	/* Check if written data is visible and correct after locating area as RO */
147  	assert_int_not_equal(-1, fmap_locate_area_as_rdev("MISC_RW", &rdev));
148  	assert_int_equal(ro_rw_section_size,
149  			 rdev_readat(&rdev, buffer2, 0, ro_rw_section_size));
150  	assert_memory_not_equal(buffer1, buffer2, ro_rw_section_size);
151  	assert_memory_equal(dummy_data, buffer2, ro_rw_section_size);
152  
153  	free(buffer1);
154  	free(buffer2);
155  	free(dummy_data);
156  }
157  
158  static void test_fmap_locate_area(void **state)
159  {
160  	struct region ar;
161  
162  	/* Try to locate named area */
163  	assert_int_not_equal(-1, fmap_locate_area("COREBOOT", &ar));
164  	assert_int_equal(FMAP_SECTION_COREBOOT_START, region_offset(&ar));
165  	assert_int_equal(FMAP_SECTION_COREBOOT_SIZE, region_sz(&ar));
166  
167  	/* Check if locating area second time works */
168  	assert_int_not_equal(-1, fmap_locate_area("COREBOOT", &ar));
169  	assert_int_equal(FMAP_SECTION_COREBOOT_START, region_offset(&ar));
170  	assert_int_equal(FMAP_SECTION_COREBOOT_SIZE, region_sz(&ar));
171  
172  	/* Look for another area */
173  	assert_int_not_equal(-1, fmap_locate_area("GBB", &ar));
174  	assert_int_equal(FMAP_SECTION_GBB_START, region_offset(&ar));
175  	assert_int_equal(FMAP_SECTION_GBB_SIZE, region_sz(&ar));
176  
177  	/* Expect error when looking for incorrect area */
178  	assert_int_equal(-1, fmap_locate_area("NONEXISTENT_AREA", &ar));
179  	assert_int_equal(-1, fmap_locate_area("", &ar));
180  	assert_int_equal(-1, fmap_locate_area(NULL, &ar));
181  
182  	/* Expect error when passing invalid region pointer */
183  	assert_int_equal(-1, fmap_locate_area("SHARED_DATA", NULL));
184  }
185  
186  static void test_fmap_find_region_name(void **state)
187  {
188  	(void)state;
189  	struct region ar;
190  	char found_area_name[FMAP_STRLEN] = "";
191  	const char *area_name = "RW_PRESERVE";
192  
193  	/* Find area by name */
194  	assert_int_not_equal(-1, fmap_locate_area(area_name, &ar));
195  
196  	/* Find name of previously located region */
197  	assert_int_not_equal(-1, fmap_find_region_name(&ar, found_area_name));
198  	assert_string_equal(area_name, found_area_name);
199  
200  	/* Expect error when passing invalid buffer */
201  	assert_int_equal(-1, fmap_find_region_name(&ar, NULL));
202  
203  	/* Expect error when passing invalid region pointer */
204  	assert_int_equal(-1, fmap_find_region_name(NULL, found_area_name));
205  
206  	/* Try to find area outside of flash region */
207  	ar.offset = FMAP_SECTION_FLASH_START + FMAP_SECTION_FLASH_SIZE + 0x100;
208  	ar.size = 0x1000;
209  	assert_int_equal(-1, fmap_find_region_name(&ar, found_area_name));
210  
211  	/* Try to find area with correct offset and incorrect size */
212  	ar.offset = FMAP_SECTION_COREBOOT_START;
213  	ar.size = FMAP_SECTION_COREBOOT_SIZE / 4;
214  	assert_int_equal(-1, fmap_find_region_name(&ar, found_area_name));
215  
216  	/* Try to find area with correct size and incorrect offset */
217  	ar.offset = FMAP_SECTION_GBB_START - 0x100;
218  	ar.size = FMAP_SECTION_GBB_START;
219  	assert_int_equal(-1, fmap_find_region_name(&ar, found_area_name));
220  
221  	/* Try to find area with correct offset overlapping with another area */
222  	ar.offset = FMAP_SECTION_MISC_RW_START;
223  	ar.size = FMAP_SECTION_MISC_RW_START + 0x1000;
224  	assert_int_equal(-1, fmap_find_region_name(&ar, found_area_name));
225  }
226  
227  static void test_fmap_read_area(void **state)
228  {
229  	const unsigned int section_size = FMAP_SECTION_RW_SECTION_A_SIZE;
230  	const unsigned int section_start = FMAP_SECTION_RW_SECTION_A_START;
231  	char *buffer = malloc(section_size);
232  
233  	/* Find and read area data. Compare with memory device simulating flash. */
234  	assert_int_equal(section_size, fmap_read_area("RW_SECTION_A", buffer, section_size));
235  	assert_memory_equal(flash_buffer + section_start, buffer, section_size);
236  
237  	/* Expect error when reading incorrect area */
238  	assert_int_equal(-1, fmap_read_area("NONEXISTENT_SECTION", buffer, section_size));
239  	assert_int_equal(-1, fmap_read_area("", buffer, section_size));
240  	assert_int_equal(-1, fmap_read_area(NULL, buffer, section_size));
241  
242  	/* Function fmap_read_area is not tested with NULL
243  	   as output buffer pointer as it is not allowed. */
244  
245  	free(buffer);
246  }
247  
248  static void test_fmap_overwrite_area(void **state)
249  {
250  	const char *section_name = "FW_MAIN_A";
251  	const unsigned int section_size = FMAP_SECTION_FW_MAIN_A_SIZE;
252  	char *buffer1 = malloc(section_size);
253  	char *buffer2 = malloc(section_size);
254  	char *new_data = malloc(section_size / 2);
255  	char *zero_buffer = malloc(section_size / 2);
256  	memset(zero_buffer, 0, section_size / 2);
257  	memset(new_data, 0x42, section_size / 2);
258  
259  	/* Save buffer for future comparisons */
260  	assert_int_equal(section_size, fmap_read_area(section_name, buffer1, section_size));
261  
262  	/* Overwrite part of section. */
263  	assert_int_equal(section_size / 2,
264  			 fmap_overwrite_area(section_name, new_data, section_size / 2));
265  
266  	/* Read and check if memory has changed as expected */
267  	assert_int_equal(section_size, fmap_read_area(section_name, buffer2, section_size));
268  	assert_memory_not_equal(buffer1, buffer2, section_size);
269  	/* Check if requested section area was overwritten properly */
270  	assert_memory_equal(buffer2, new_data, section_size / 2);
271  	/* Check if rest of section was zero-filled */
272  	assert_memory_equal(buffer2 + (section_size / 2), zero_buffer, section_size / 2);
273  
274  	/* Expect error when overwriting incorrect section */
275  	assert_int_equal(
276  		-1, fmap_overwrite_area("NONEXISTENT_SECTION", new_data, section_size / 2));
277  	assert_int_equal(-1, fmap_overwrite_area(NULL, new_data, section_size / 2));
278  
279  	/* Function fmap_overwrite_area is not tested with NULL
280  	   as input buffer pointer as it is not allowed. */
281  
282  	free(buffer1);
283  	free(buffer2);
284  	free(new_data);
285  	free(zero_buffer);
286  }
287  
288  int main(void)
289  {
290  	const struct CMUnitTest tests[] = {
291  		cmocka_unit_test_setup_teardown(test_fmap_locate_area_as_rdev, setup_fmap,
292  						teardown_fmap),
293  		cmocka_unit_test_setup_teardown(test_fmap_locate_area_as_rdev_rw, setup_fmap,
294  						teardown_fmap),
295  		cmocka_unit_test_setup_teardown(test_fmap_locate_area, setup_fmap,
296  						teardown_fmap),
297  		cmocka_unit_test_setup_teardown(test_fmap_find_region_name, setup_fmap,
298  						teardown_fmap),
299  		cmocka_unit_test_setup_teardown(test_fmap_read_area, setup_fmap, teardown_fmap),
300  		cmocka_unit_test_setup_teardown(test_fmap_overwrite_area, setup_fmap,
301  						teardown_fmap),
302  	};
303  
304  	return cb_run_group_tests(tests, NULL, NULL);
305  }