bloblist: Compare addresses rather than pointers in tests
[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/state.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         = 0xe0,
29
30         TEST_ADDR               = CONFIG_BLOBLIST_ADDR,
31         TEST_BLOBLIST_SIZE      = 0x100,
32 };
33
34 static struct bloblist_hdr *clear_bloblist(void)
35 {
36         struct bloblist_hdr *hdr;
37
38         /*
39          * Clear out any existing bloblist so we have a clean slate. Zero the
40          * header so that existing records are removed, but set everything else
41          * to 0xff for testing purposes.
42          */
43         hdr = map_sysmem(CONFIG_BLOBLIST_ADDR, TEST_BLOBLIST_SIZE);
44         memset(hdr, '\xff', TEST_BLOBLIST_SIZE);
45         memset(hdr, '\0', sizeof(*hdr));
46
47         return hdr;
48 }
49
50 static int check_zero(void *data, int size)
51 {
52         u8 *ptr;
53         int i;
54
55         for (ptr = data, i = 0; i < size; i++, ptr++) {
56                 if (*ptr)
57                         return -EINVAL;
58         }
59
60         return 0;
61 }
62
63 static int bloblist_test_init(struct unit_test_state *uts)
64 {
65         struct bloblist_hdr *hdr;
66
67         hdr = clear_bloblist();
68         ut_asserteq(-ENOENT, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
69         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
70         hdr->version++;
71         ut_asserteq(-EPROTONOSUPPORT, bloblist_check(TEST_ADDR,
72                                                      TEST_BLOBLIST_SIZE));
73
74         ut_asserteq(-ENOSPC, bloblist_new(TEST_ADDR, 0x10, 0));
75         ut_asserteq(-EFAULT, bloblist_new(1, TEST_BLOBLIST_SIZE, 0));
76         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
77
78         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
79         ut_assertok(bloblist_finish());
80         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
81         hdr->flags++;
82         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
83
84         return 1;
85 }
86 BLOBLIST_TEST(bloblist_test_init, 0);
87
88 static int bloblist_test_blob(struct unit_test_state *uts)
89 {
90         struct bloblist_hdr *hdr;
91         struct bloblist_rec *rec, *rec2;
92         char *data;
93
94         /* At the start there should be no records */
95         hdr = clear_bloblist();
96         ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
97         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
98         ut_asserteq(map_to_sysmem(hdr), TEST_ADDR);
99
100         /* Add a record and check that we can find it */
101         data = bloblist_add(TEST_TAG, TEST_SIZE);
102         rec = (void *)(hdr + 1);
103         ut_asserteq_addr(rec + 1, data);
104         data = bloblist_find(TEST_TAG, TEST_SIZE);
105         ut_asserteq_addr(rec + 1, data);
106
107         /* Check the data is zeroed */
108         ut_assertok(check_zero(data, TEST_SIZE));
109
110         /* Check the 'ensure' method */
111         ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
112         ut_assertnull(bloblist_ensure(TEST_TAG, TEST_SIZE2));
113         rec2 = (struct bloblist_rec *)(data + ALIGN(TEST_SIZE, BLOBLIST_ALIGN));
114         ut_assertok(check_zero(data, TEST_SIZE));
115
116         /* Check for a non-existent record */
117         ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
118         ut_asserteq_addr(rec2 + 1, bloblist_ensure(TEST_TAG2, TEST_SIZE2));
119         ut_assertnull(bloblist_find(TEST_TAG_MISSING, 0));
120
121         return 0;
122 }
123 BLOBLIST_TEST(bloblist_test_blob, 0);
124
125 /* Check bloblist_ensure_size_ret() */
126 static int bloblist_test_blob_ensure(struct unit_test_state *uts)
127 {
128         void *data, *data2;
129         int size;
130
131         /* At the start there should be no records */
132         clear_bloblist();
133         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
134
135         /* Test with an empty bloblist */
136         size = TEST_SIZE;
137         ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
138         ut_asserteq(TEST_SIZE, size);
139         ut_assertok(check_zero(data, TEST_SIZE));
140
141         /* Check that we get the same thing again */
142         ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data2));
143         ut_asserteq(TEST_SIZE, size);
144         ut_asserteq_addr(data, data2);
145
146         /* Check that the size remains the same */
147         size = TEST_SIZE2;
148         ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
149         ut_asserteq(TEST_SIZE, size);
150
151         /* Check running out of space */
152         size = TEST_SIZE_LARGE;
153         ut_asserteq(-ENOSPC, bloblist_ensure_size_ret(TEST_TAG2, &size, &data));
154
155         return 0;
156 }
157 BLOBLIST_TEST(bloblist_test_blob_ensure, 0);
158
159 static int bloblist_test_bad_blob(struct unit_test_state *uts)
160 {
161         struct bloblist_hdr *hdr;
162         void *data;
163
164         hdr = clear_bloblist();
165         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
166         data = hdr + 1;
167         data += sizeof(struct bloblist_rec);
168         ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
169         ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
170
171         return 0;
172 }
173 BLOBLIST_TEST(bloblist_test_bad_blob, 0);
174
175 static int bloblist_test_checksum(struct unit_test_state *uts)
176 {
177         struct bloblist_hdr *hdr;
178         char *data, *data2;
179
180         hdr = clear_bloblist();
181         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
182         ut_assertok(bloblist_finish());
183         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
184
185         /*
186          * Now change things amd make sure that the checksum notices. We cannot
187          * change the size or alloced fields, since that will crash the code.
188          * It has to rely on these being correct.
189          */
190         hdr->flags--;
191         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
192         hdr->flags++;
193
194         hdr->size--;
195         ut_asserteq(-EFBIG, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
196         hdr->size++;
197
198         hdr->spare++;
199         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
200         hdr->spare--;
201
202         hdr->chksum++;
203         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
204         hdr->chksum--;
205
206         /* Make sure the checksum changes when we add blobs */
207         data = bloblist_add(TEST_TAG, TEST_SIZE);
208         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
209
210         data2 = bloblist_add(TEST_TAG2, TEST_SIZE2);
211         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
212         ut_assertok(bloblist_finish());
213
214         /* It should also change if we change the data */
215         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
216         *data += 1;
217         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
218         *data -= 1;
219
220         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
221         *data2 += 1;
222         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
223         *data2 -= 1;
224
225         /*
226          * Changing data outside the range of valid data should not affect
227          * the checksum.
228          */
229         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
230         data[TEST_SIZE]++;
231         data2[TEST_SIZE2]++;
232         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
233
234         return 0;
235 }
236 BLOBLIST_TEST(bloblist_test_checksum, 0);
237
238 /* Test the 'bloblist info' command */
239 static int bloblist_test_cmd_info(struct unit_test_state *uts)
240 {
241         struct sandbox_state *state = state_get_current();
242         struct bloblist_hdr *hdr;
243         char *data, *data2;
244
245         hdr = clear_bloblist();
246         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
247         data = bloblist_ensure(TEST_TAG, TEST_SIZE);
248         data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
249
250         console_record_reset_enable();
251         if (!state->show_test_output)
252                 gd->flags |= GD_FLG_SILENT;
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:     100    256 Bytes");
257         ut_assert_nextline("alloced:  70     112 Bytes");
258         ut_assert_nextline("free:     90     144 Bytes");
259         ut_assert_console_end();
260         gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
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 sandbox_state *state = state_get_current();
270         struct bloblist_hdr *hdr;
271         char *data, *data2;
272
273         hdr = clear_bloblist();
274         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
275         data = bloblist_ensure(TEST_TAG, TEST_SIZE);
276         data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
277
278         console_record_reset_enable();
279         if (!state->show_test_output)
280                 gd->flags |= GD_FLG_SILENT;
281         console_record_reset();
282         run_command("bloblist list", 0);
283         ut_assert_nextline("Address       Size  Tag Name");
284         ut_assert_nextline("%08lx  %8x    1 EC host event",
285                            (ulong)map_to_sysmem(data), TEST_SIZE);
286         ut_assert_nextline("%08lx  %8x    2 SPL hand-off",
287                            (ulong)map_to_sysmem(data2), TEST_SIZE2);
288         ut_assert_console_end();
289         gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
290
291         return 0;
292 }
293 BLOBLIST_TEST(bloblist_test_cmd_list, 0);
294
295 int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
296                    char *const argv[])
297 {
298         struct unit_test *tests = ll_entry_start(struct unit_test,
299                                                  bloblist_test);
300         const int n_ents = ll_entry_count(struct unit_test, bloblist_test);
301
302         return cmd_ut_category("bloblist", "bloblist_test_",
303                                tests, n_ents, argc, argv);
304 }