bloblist: Add a command
[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
99         /* Add a record and check that we can find it */
100         data = bloblist_add(TEST_TAG, TEST_SIZE);
101         rec = (void *)(hdr + 1);
102         ut_asserteq_ptr(rec + 1, data);
103         data = bloblist_find(TEST_TAG, TEST_SIZE);
104         ut_asserteq_ptr(rec + 1, data);
105
106         /* Check the data is zeroed */
107         ut_assertok(check_zero(data, TEST_SIZE));
108
109         /* Check the 'ensure' method */
110         ut_asserteq_ptr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
111         ut_assertnull(bloblist_ensure(TEST_TAG, TEST_SIZE2));
112         rec2 = (struct bloblist_rec *)(data + ALIGN(TEST_SIZE, BLOBLIST_ALIGN));
113         ut_assertok(check_zero(data, TEST_SIZE));
114
115         /* Check for a non-existent record */
116         ut_asserteq_ptr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
117         ut_asserteq_ptr(rec2 + 1, bloblist_ensure(TEST_TAG2, TEST_SIZE2));
118         ut_assertnull(bloblist_find(TEST_TAG_MISSING, 0));
119
120         return 0;
121 }
122 BLOBLIST_TEST(bloblist_test_blob, 0);
123
124 /* Check bloblist_ensure_size_ret() */
125 static int bloblist_test_blob_ensure(struct unit_test_state *uts)
126 {
127         void *data, *data2;
128         int size;
129
130         /* At the start there should be no records */
131         clear_bloblist();
132         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
133
134         /* Test with an empty bloblist */
135         size = TEST_SIZE;
136         ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
137         ut_asserteq(TEST_SIZE, size);
138         ut_assertok(check_zero(data, TEST_SIZE));
139
140         /* Check that we get the same thing again */
141         ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data2));
142         ut_asserteq(TEST_SIZE, size);
143         ut_asserteq_ptr(data, data2);
144
145         /* Check that the size remains the same */
146         size = TEST_SIZE2;
147         ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
148         ut_asserteq(TEST_SIZE, size);
149
150         /* Check running out of space */
151         size = TEST_SIZE_LARGE;
152         ut_asserteq(-ENOSPC, bloblist_ensure_size_ret(TEST_TAG2, &size, &data));
153
154         return 0;
155 }
156 BLOBLIST_TEST(bloblist_test_blob_ensure, 0);
157
158 static int bloblist_test_bad_blob(struct unit_test_state *uts)
159 {
160         struct bloblist_hdr *hdr;
161         void *data;
162
163         hdr = clear_bloblist();
164         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
165         data = hdr + 1;
166         data += sizeof(struct bloblist_rec);
167         ut_asserteq_ptr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
168         ut_asserteq_ptr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
169
170         return 0;
171 }
172 BLOBLIST_TEST(bloblist_test_bad_blob, 0);
173
174 static int bloblist_test_checksum(struct unit_test_state *uts)
175 {
176         struct bloblist_hdr *hdr;
177         char *data, *data2;
178
179         hdr = clear_bloblist();
180         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
181         ut_assertok(bloblist_finish());
182         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
183
184         /*
185          * Now change things amd make sure that the checksum notices. We cannot
186          * change the size or alloced fields, since that will crash the code.
187          * It has to rely on these being correct.
188          */
189         hdr->flags--;
190         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
191         hdr->flags++;
192
193         hdr->size--;
194         ut_asserteq(-EFBIG, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
195         hdr->size++;
196
197         hdr->spare++;
198         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
199         hdr->spare--;
200
201         hdr->chksum++;
202         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
203         hdr->chksum--;
204
205         /* Make sure the checksum changes when we add blobs */
206         data = bloblist_add(TEST_TAG, TEST_SIZE);
207         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
208
209         data2 = bloblist_add(TEST_TAG2, TEST_SIZE2);
210         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
211         ut_assertok(bloblist_finish());
212
213         /* It should also change if we change the data */
214         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
215         *data += 1;
216         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
217         *data -= 1;
218
219         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
220         *data2 += 1;
221         ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
222         *data2 -= 1;
223
224         /*
225          * Changing data outside the range of valid data should not affect
226          * the checksum.
227          */
228         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
229         data[TEST_SIZE]++;
230         data2[TEST_SIZE2]++;
231         ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
232
233         return 0;
234 }
235 BLOBLIST_TEST(bloblist_test_checksum, 0);
236
237 /* Test the 'bloblist info' command */
238 static int bloblist_test_cmd_info(struct unit_test_state *uts)
239 {
240         struct sandbox_state *state = state_get_current();
241         struct bloblist_hdr *hdr;
242         char *data, *data2;
243
244         hdr = clear_bloblist();
245         ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
246         data = bloblist_ensure(TEST_TAG, TEST_SIZE);
247         data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
248
249         console_record_reset_enable();
250         if (!state->show_test_output)
251                 gd->flags |= GD_FLG_SILENT;
252         console_record_reset();
253         run_command("bloblist info", 0);
254         ut_assert_nextline("base:     %x", map_to_sysmem(hdr));
255         ut_assert_nextline("size:     100    256 Bytes");
256         ut_assert_nextline("alloced:  70     112 Bytes");
257         ut_assert_nextline("free:     90     144 Bytes");
258         ut_assert_console_end();
259         gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
260
261         return 0;
262 }
263 BLOBLIST_TEST(bloblist_test_cmd_info, 0);
264
265 /* Test the 'bloblist list' command */
266 static int bloblist_test_cmd_list(struct unit_test_state *uts)
267 {
268         struct sandbox_state *state = state_get_current();
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         if (!state->show_test_output)
279                 gd->flags |= GD_FLG_SILENT;
280         console_record_reset();
281         run_command("bloblist list", 0);
282         ut_assert_nextline("Address       Size  Tag Name");
283         ut_assert_nextline("%08x  %8x    1 EC host event", map_to_sysmem(data),
284                            TEST_SIZE);
285         ut_assert_nextline("%08x  %8x    2 SPL hand-off", map_to_sysmem(data2),
286                            TEST_SIZE2);
287         ut_assert_console_end();
288         gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
289
290         return 0;
291 }
292 BLOBLIST_TEST(bloblist_test_cmd_list, 0);
293
294 int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
295                    char *const argv[])
296 {
297         struct unit_test *tests = ll_entry_start(struct unit_test,
298                                                  bloblist_test);
299         const int n_ents = ll_entry_count(struct unit_test, bloblist_test);
300
301         return cmd_ut_category("bloblist", "bloblist_test_",
302                                tests, n_ents, argc, argv);
303 }