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