Merge tag 'v2021.04-rc5' into next
[platform/kernel/u-boot.git] / test / bloblist.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2018, Google Inc. All rights reserved.
4  */
5
6 #include <common.h>
7 #include <bloblist.h>
8 #include <log.h>
9 #include <mapmem.h>
10 #include <asm/global_data.h>
11 #include <test/suites.h>
12 #include <test/test.h>
13 #include <test/ut.h>
14
15 DECLARE_GLOBAL_DATA_PTR;
16
17 /* Declare a new compression test */
18 #define BLOBLIST_TEST(_name, _flags) \
19                 UNIT_TEST(_name, _flags, bloblist_test)
20
21 enum {
22         TEST_TAG                = 1,
23         TEST_TAG2               = 2,
24         TEST_TAG_MISSING        = 3,
25
26         TEST_SIZE               = 10,
27         TEST_SIZE2              = 20,
28         TEST_SIZE_LARGE         = 0x3e0,
29
30         TEST_ADDR               = CONFIG_BLOBLIST_ADDR,
31         TEST_BLOBLIST_SIZE      = 0x400,
32
33         ERASE_BYTE              = '\xff',
34 };
35
36 static struct bloblist_hdr *clear_bloblist(void)
37 {
38         struct bloblist_hdr *hdr;
39
40         /*
41          * Clear out any existing bloblist so we have a clean slate. Zero the
42          * header so that existing records are removed, but set everything else
43          * to 0xff for testing purposes.
44          */
45         hdr = map_sysmem(CONFIG_BLOBLIST_ADDR, TEST_BLOBLIST_SIZE);
46         memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
47         memset(hdr, '\0', sizeof(*hdr));
48
49         return hdr;
50 }
51
52 static int check_zero(void *data, int size)
53 {
54         u8 *ptr;
55         int i;
56
57         for (ptr = data, i = 0; i < size; i++, ptr++) {
58                 if (*ptr)
59                         return -EINVAL;
60         }
61
62         return 0;
63 }
64
65 static int bloblist_test_init(struct unit_test_state *uts)
66 {
67         struct bloblist_hdr *hdr;
68
69         hdr = clear_bloblist();
70         ut_asserteq(-ENOENT, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
71         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
72         hdr->version++;
73         ut_asserteq(-EPROTONOSUPPORT, bloblist_check(TEST_ADDR,
74                                                      TEST_BLOBLIST_SIZE));
75
76         ut_asserteq(-ENOSPC, bloblist_new(TEST_ADDR, 0x10, 0));
77         ut_asserteq(-EFAULT, bloblist_new(1, TEST_BLOBLIST_SIZE, 0));
78         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
79
80         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
81         ut_assertok(bloblist_finish());
82         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
83         hdr->flags++;
84         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
85
86         return 1;
87 }
88 BLOBLIST_TEST(bloblist_test_init, 0);
89
90 static int bloblist_test_blob(struct unit_test_state *uts)
91 {
92         struct bloblist_hdr *hdr;
93         struct bloblist_rec *rec, *rec2;
94         char *data;
95
96         /* At the start there should be no records */
97         hdr = clear_bloblist();
98         ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
99         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
100         ut_asserteq(map_to_sysmem(hdr), TEST_ADDR);
101
102         /* Add a record and check that we can find it */
103         data = bloblist_add(TEST_TAG, TEST_SIZE, 0);
104         rec = (void *)(hdr + 1);
105         ut_asserteq_addr(rec + 1, data);
106         data = bloblist_find(TEST_TAG, TEST_SIZE);
107         ut_asserteq_addr(rec + 1, data);
108
109         /* Check the data is zeroed */
110         ut_assertok(check_zero(data, TEST_SIZE));
111
112         /* Check the 'ensure' method */
113         ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
114         ut_assertnull(bloblist_ensure(TEST_TAG, TEST_SIZE2));
115         rec2 = (struct bloblist_rec *)(data + ALIGN(TEST_SIZE, BLOBLIST_ALIGN));
116         ut_assertok(check_zero(data, TEST_SIZE));
117
118         /* Check for a non-existent record */
119         ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
120         ut_asserteq_addr(rec2 + 1, bloblist_ensure(TEST_TAG2, TEST_SIZE2));
121         ut_assertnull(bloblist_find(TEST_TAG_MISSING, 0));
122
123         return 0;
124 }
125 BLOBLIST_TEST(bloblist_test_blob, 0);
126
127 /* Check bloblist_ensure_size_ret() */
128 static int bloblist_test_blob_ensure(struct unit_test_state *uts)
129 {
130         void *data, *data2;
131         int size;
132
133         /* At the start there should be no records */
134         clear_bloblist();
135         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
136
137         /* Test with an empty bloblist */
138         size = TEST_SIZE;
139         ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
140         ut_asserteq(TEST_SIZE, size);
141         ut_assertok(check_zero(data, TEST_SIZE));
142
143         /* Check that we get the same thing again */
144         ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data2));
145         ut_asserteq(TEST_SIZE, size);
146         ut_asserteq_addr(data, data2);
147
148         /* Check that the size remains the same */
149         size = TEST_SIZE2;
150         ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
151         ut_asserteq(TEST_SIZE, size);
152
153         /* Check running out of space */
154         size = TEST_SIZE_LARGE;
155         ut_asserteq(-ENOSPC, bloblist_ensure_size_ret(TEST_TAG2, &size, &data));
156
157         return 0;
158 }
159 BLOBLIST_TEST(bloblist_test_blob_ensure, 0);
160
161 static int bloblist_test_bad_blob(struct unit_test_state *uts)
162 {
163         struct bloblist_hdr *hdr;
164         void *data;
165
166         hdr = clear_bloblist();
167         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
168         data = hdr + 1;
169         data += sizeof(struct bloblist_rec);
170         ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
171         ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
172
173         return 0;
174 }
175 BLOBLIST_TEST(bloblist_test_bad_blob, 0);
176
177 static int bloblist_test_checksum(struct unit_test_state *uts)
178 {
179         struct bloblist_hdr *hdr;
180         char *data, *data2;
181
182         hdr = clear_bloblist();
183         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
184         ut_assertok(bloblist_finish());
185         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
186
187         /*
188          * Now change things amd make sure that the checksum notices. We cannot
189          * change the size or alloced fields, since that will crash the code.
190          * It has to rely on these being correct.
191          */
192         hdr->flags--;
193         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
194         hdr->flags++;
195
196         hdr->size--;
197         ut_asserteq(-EFBIG, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
198         hdr->size++;
199
200         hdr->spare++;
201         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
202         hdr->spare--;
203
204         hdr->chksum++;
205         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
206         hdr->chksum--;
207
208         /* Make sure the checksum changes when we add blobs */
209         data = bloblist_add(TEST_TAG, TEST_SIZE, 0);
210         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
211
212         data2 = bloblist_add(TEST_TAG2, TEST_SIZE2, 0);
213         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
214         ut_assertok(bloblist_finish());
215
216         /* It should also change if we change the data */
217         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
218         *data += 1;
219         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
220         *data -= 1;
221
222         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
223         *data2 += 1;
224         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
225         *data2 -= 1;
226
227         /*
228          * Changing data outside the range of valid data should not affect
229          * the checksum.
230          */
231         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
232         data[TEST_SIZE]++;
233         data2[TEST_SIZE2]++;
234         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
235
236         return 0;
237 }
238 BLOBLIST_TEST(bloblist_test_checksum, 0);
239
240 /* Test the 'bloblist info' command */
241 static int bloblist_test_cmd_info(struct unit_test_state *uts)
242 {
243         struct bloblist_hdr *hdr;
244         char *data, *data2;
245
246         hdr = clear_bloblist();
247         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
248         data = bloblist_ensure(TEST_TAG, TEST_SIZE);
249         data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
250
251         console_record_reset_enable();
252         ut_silence_console(uts);
253         console_record_reset();
254         run_command("bloblist info", 0);
255         ut_assert_nextline("base:     %lx", (ulong)map_to_sysmem(hdr));
256         ut_assert_nextline("size:     400    1 KiB");
257         ut_assert_nextline("alloced:  70     112 Bytes");
258         ut_assert_nextline("free:     390    912 Bytes");
259         ut_assert_console_end();
260         ut_unsilence_console(uts);
261
262         return 0;
263 }
264 BLOBLIST_TEST(bloblist_test_cmd_info, 0);
265
266 /* Test the 'bloblist list' command */
267 static int bloblist_test_cmd_list(struct unit_test_state *uts)
268 {
269         struct bloblist_hdr *hdr;
270         char *data, *data2;
271
272         hdr = clear_bloblist();
273         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
274         data = bloblist_ensure(TEST_TAG, TEST_SIZE);
275         data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
276
277         console_record_reset_enable();
278         ut_silence_console(uts);
279         console_record_reset();
280         run_command("bloblist list", 0);
281         ut_assert_nextline("Address       Size  Tag Name");
282         ut_assert_nextline("%08lx  %8x    1 EC host event",
283                            (ulong)map_to_sysmem(data), TEST_SIZE);
284         ut_assert_nextline("%08lx  %8x    2 SPL hand-off",
285                            (ulong)map_to_sysmem(data2), TEST_SIZE2);
286         ut_assert_console_end();
287         ut_unsilence_console(uts);
288
289         return 0;
290 }
291 BLOBLIST_TEST(bloblist_test_cmd_list, 0);
292
293 /* Test alignment of bloblist blobs */
294 static int bloblist_test_align(struct unit_test_state *uts)
295 {
296         struct bloblist_hdr *hdr;
297         ulong addr;
298         char *data;
299         int i;
300
301         /* At the start there should be no records */
302         hdr = clear_bloblist();
303         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
304         ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
305
306         /* Check the default alignment */
307         for (i = 0; i < 3; i++) {
308                 int size = i * 3;
309                 ulong addr;
310                 char *data;
311                 int j;
312
313                 data = bloblist_add(i, size, 0);
314                 ut_assertnonnull(data);
315                 addr = map_to_sysmem(data);
316                 ut_asserteq(0, addr & (BLOBLIST_ALIGN - 1));
317
318                 /* Only the bytes in the blob data should be zeroed */
319                 for (j = 0; j < size; j++)
320                         ut_asserteq(0, data[j]);
321                 for (; j < BLOBLIST_ALIGN; j++)
322                         ut_asserteq(ERASE_BYTE, data[j]);
323         }
324
325         /* Check larger alignment */
326         for (i = 0; i < 3; i++) {
327                 int align = 32 << i;
328
329                 data = bloblist_add(3 + i, i * 4, align);
330                 ut_assertnonnull(data);
331                 addr = map_to_sysmem(data);
332                 ut_asserteq(0, addr & (align - 1));
333         }
334
335         /* Check alignment with an bloblist starting on a smaller alignment */
336         hdr = map_sysmem(TEST_ADDR + BLOBLIST_ALIGN, TEST_BLOBLIST_SIZE);
337         memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
338         memset(hdr, '\0', sizeof(*hdr));
339         ut_assertok(bloblist_new(TEST_ADDR + BLOBLIST_ALIGN, TEST_BLOBLIST_SIZE,
340                                  0));
341
342         data = bloblist_add(1, 5, BLOBLIST_ALIGN * 2);
343         ut_assertnonnull(data);
344         addr = map_to_sysmem(data);
345         ut_asserteq(0, addr & (BLOBLIST_ALIGN * 2 - 1));
346
347         return 0;
348 }
349 BLOBLIST_TEST(bloblist_test_align, 0);
350
351 /* Test relocation of a bloblist */
352 static int bloblist_test_reloc(struct unit_test_state *uts)
353 {
354         const uint large_size = TEST_BLOBLIST_SIZE;
355         const uint small_size = 0x20;
356         void *old_ptr, *new_ptr;
357         void *blob1, *blob2;
358         ulong new_addr;
359         ulong new_size;
360
361         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
362         old_ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
363
364         /* Add one blob and then one that won't fit */
365         blob1 = bloblist_add(TEST_TAG, small_size, 0);
366         ut_assertnonnull(blob1);
367         blob2 = bloblist_add(TEST_TAG2, large_size, 0);
368         ut_assertnull(blob2);
369
370         /* Relocate the bloblist somewhere else, a bit larger */
371         new_addr = TEST_ADDR + TEST_BLOBLIST_SIZE;
372         new_size = TEST_BLOBLIST_SIZE + 0x100;
373         new_ptr = map_sysmem(new_addr, TEST_BLOBLIST_SIZE);
374         bloblist_reloc(new_ptr, new_size, old_ptr, TEST_BLOBLIST_SIZE);
375         gd->bloblist = new_ptr;
376
377         /* Check the old blob is there and that we can now add the bigger one */
378         ut_assertnonnull(bloblist_find(TEST_TAG, small_size));
379         ut_assertnull(bloblist_find(TEST_TAG2, small_size));
380         blob2 = bloblist_add(TEST_TAG2, large_size, 0);
381         ut_assertnonnull(blob2);
382
383         return 0;
384 }
385 BLOBLIST_TEST(bloblist_test_reloc, 0);
386
387 int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
388                    char *const argv[])
389 {
390         struct unit_test *tests = UNIT_TEST_SUITE_START(bloblist_test);
391         const int n_ents = UNIT_TEST_SUITE_COUNT(bloblist_test);
392
393         return cmd_ut_category("bloblist", "bloblist_test_",
394                                tests, n_ents, argc, argv);
395 }