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 }