blob: c86ea029c8d77c3a93c5dea4a409c1dd0fc053be [file] [log] [blame]
Simon Glass9f407d42018-11-15 18:43:50 -07001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2018 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7#include <common.h>
8#include <bloblist.h>
9#include <log.h>
10#include <mapmem.h>
11#include <spl.h>
Simon Glass3db71102019-11-14 12:57:16 -070012#include <u-boot/crc.h>
Simon Glass9f407d42018-11-15 18:43:50 -070013
14DECLARE_GLOBAL_DATA_PTR;
15
Simon Glass4aed2272020-09-19 18:49:26 -060016static const char *const tag_name[] = {
17 [BLOBLISTT_NONE] = "(none)",
18 [BLOBLISTT_EC_HOSTEVENT] = "EC host event",
19 [BLOBLISTT_SPL_HANDOFF] = "SPL hand-off",
20 [BLOBLISTT_VBOOT_CTX] = "Chrome OS vboot context",
21 [BLOBLISTT_VBOOT_HANDOFF] = "Chrome OS vboot hand-off",
22};
23
24const char *bloblist_tag_name(enum bloblist_tag_t tag)
25{
26 if (tag < 0 || tag >= BLOBLISTT_COUNT)
27 return "invalid";
28
29 return tag_name[tag];
30}
31
32static struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
Simon Glass9f407d42018-11-15 18:43:50 -070033{
34 if (hdr->alloced <= hdr->hdr_size)
35 return NULL;
36 return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size);
37}
38
Simon Glass4aed2272020-09-19 18:49:26 -060039static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
40 struct bloblist_rec *rec)
Simon Glass9f407d42018-11-15 18:43:50 -070041{
42 ulong offset;
43
44 offset = (void *)rec - (void *)hdr;
45 offset += rec->hdr_size + ALIGN(rec->size, BLOBLIST_ALIGN);
46 if (offset >= hdr->alloced)
47 return NULL;
48 return (struct bloblist_rec *)((void *)hdr + offset);
49}
50
51#define foreach_rec(_rec, _hdr) \
52 for (_rec = bloblist_first_blob(_hdr); \
53 _rec; \
54 _rec = bloblist_next_blob(_hdr, _rec))
55
56static struct bloblist_rec *bloblist_findrec(uint tag)
57{
58 struct bloblist_hdr *hdr = gd->bloblist;
59 struct bloblist_rec *rec;
60
61 if (!hdr)
62 return NULL;
63
64 foreach_rec(rec, hdr) {
65 if (rec->tag == tag)
66 return rec;
67 }
68
69 return NULL;
70}
71
72static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp)
73{
74 struct bloblist_hdr *hdr = gd->bloblist;
75 struct bloblist_rec *rec;
76 int new_alloced;
77
Simon Glass02247c12020-01-27 08:49:51 -070078 new_alloced = hdr->alloced + sizeof(*rec) + ALIGN(size, BLOBLIST_ALIGN);
Simon Glass9f407d42018-11-15 18:43:50 -070079 if (new_alloced >= hdr->size) {
80 log(LOGC_BLOBLIST, LOGL_ERR,
Simon Glass02247c12020-01-27 08:49:51 -070081 "Failed to allocate %x bytes size=%x, need size=%x\n",
Simon Glass9f407d42018-11-15 18:43:50 -070082 size, hdr->size, new_alloced);
83 return log_msg_ret("bloblist add", -ENOSPC);
84 }
85 rec = (void *)hdr + hdr->alloced;
86 hdr->alloced = new_alloced;
87
88 rec->tag = tag;
89 rec->hdr_size = sizeof(*rec);
90 rec->size = size;
91 rec->spare = 0;
Simon Glassb83994d2020-01-27 08:49:52 -070092
93 /* Zero the record data */
94 memset(rec + 1, '\0', rec->size);
Simon Glass9f407d42018-11-15 18:43:50 -070095 *recp = rec;
96
97 return 0;
98}
99
100static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size)
101{
102 struct bloblist_rec *rec;
103
104 rec = bloblist_findrec(tag);
105 if (rec) {
Simon Glass5b044542020-01-27 08:49:50 -0700106 if (size && size != rec->size) {
107 *recp = rec;
Simon Glass9f407d42018-11-15 18:43:50 -0700108 return -ESPIPE;
Simon Glass5b044542020-01-27 08:49:50 -0700109 }
Simon Glass9f407d42018-11-15 18:43:50 -0700110 } else {
111 int ret;
112
113 ret = bloblist_addrec(tag, size, &rec);
114 if (ret)
115 return ret;
116 }
117 *recp = rec;
118
119 return 0;
120}
121
122void *bloblist_find(uint tag, int size)
123{
124 struct bloblist_rec *rec;
125
126 rec = bloblist_findrec(tag);
127 if (!rec)
128 return NULL;
129 if (size && size != rec->size)
130 return NULL;
131
132 return (void *)rec + rec->hdr_size;
133}
134
135void *bloblist_add(uint tag, int size)
136{
137 struct bloblist_rec *rec;
138
139 if (bloblist_addrec(tag, size, &rec))
140 return NULL;
141
142 return rec + 1;
143}
144
145int bloblist_ensure_size(uint tag, int size, void **blobp)
146{
147 struct bloblist_rec *rec;
148 int ret;
149
150 ret = bloblist_ensurerec(tag, &rec, size);
151 if (ret)
152 return ret;
153 *blobp = (void *)rec + rec->hdr_size;
154
155 return 0;
156}
157
158void *bloblist_ensure(uint tag, int size)
159{
160 struct bloblist_rec *rec;
161
162 if (bloblist_ensurerec(tag, &rec, size))
163 return NULL;
164
165 return (void *)rec + rec->hdr_size;
166}
167
Simon Glass5b044542020-01-27 08:49:50 -0700168int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp)
169{
170 struct bloblist_rec *rec;
171 int ret;
172
173 ret = bloblist_ensurerec(tag, &rec, *sizep);
174 if (ret == -ESPIPE)
175 *sizep = rec->size;
176 else if (ret)
177 return ret;
178 *blobp = (void *)rec + rec->hdr_size;
179
180 return 0;
181}
182
Simon Glass9f407d42018-11-15 18:43:50 -0700183static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr)
184{
185 struct bloblist_rec *rec;
186 u32 chksum;
187
188 chksum = crc32(0, (unsigned char *)hdr,
189 offsetof(struct bloblist_hdr, chksum));
190 foreach_rec(rec, hdr) {
191 chksum = crc32(chksum, (void *)rec, rec->hdr_size);
192 chksum = crc32(chksum, (void *)rec + rec->hdr_size, rec->size);
193 }
194
195 return chksum;
196}
197
198int bloblist_new(ulong addr, uint size, uint flags)
199{
200 struct bloblist_hdr *hdr;
201
202 if (size < sizeof(*hdr))
203 return log_ret(-ENOSPC);
204 if (addr & (BLOBLIST_ALIGN - 1))
205 return log_ret(-EFAULT);
206 hdr = map_sysmem(addr, size);
207 memset(hdr, '\0', sizeof(*hdr));
208 hdr->version = BLOBLIST_VERSION;
209 hdr->hdr_size = sizeof(*hdr);
210 hdr->flags = flags;
211 hdr->magic = BLOBLIST_MAGIC;
212 hdr->size = size;
213 hdr->alloced = hdr->hdr_size;
214 hdr->chksum = 0;
215 gd->bloblist = hdr;
216
217 return 0;
218}
219
220int bloblist_check(ulong addr, uint size)
221{
222 struct bloblist_hdr *hdr;
223 u32 chksum;
224
225 hdr = map_sysmem(addr, sizeof(*hdr));
226 if (hdr->magic != BLOBLIST_MAGIC)
227 return log_msg_ret("Bad magic", -ENOENT);
228 if (hdr->version != BLOBLIST_VERSION)
229 return log_msg_ret("Bad version", -EPROTONOSUPPORT);
230 if (size && hdr->size != size)
231 return log_msg_ret("Bad size", -EFBIG);
232 chksum = bloblist_calc_chksum(hdr);
233 if (hdr->chksum != chksum) {
234 log(LOGC_BLOBLIST, LOGL_ERR, "Checksum %x != %x\n", hdr->chksum,
235 chksum);
236 return log_msg_ret("Bad checksum", -EIO);
237 }
238 gd->bloblist = hdr;
239
240 return 0;
241}
242
243int bloblist_finish(void)
244{
245 struct bloblist_hdr *hdr = gd->bloblist;
246
247 hdr->chksum = bloblist_calc_chksum(hdr);
248
249 return 0;
250}
251
Simon Glass4aed2272020-09-19 18:49:26 -0600252void bloblist_get_stats(ulong *basep, ulong *sizep, ulong *allocedp)
253{
254 struct bloblist_hdr *hdr = gd->bloblist;
255
256 *basep = map_to_sysmem(gd->bloblist);
257 *sizep = hdr->size;
258 *allocedp = hdr->alloced;
259}
260
261static void show_value(const char *prompt, ulong value)
262{
263 printf("%s:%*s %-5lx ", prompt, 8 - (int)strlen(prompt), "", value);
264 print_size(value, "\n");
265}
266
267void bloblist_show_stats(void)
268{
269 ulong base, size, alloced;
270
271 bloblist_get_stats(&base, &size, &alloced);
272 printf("base: %lx\n", base);
273 show_value("size", size);
274 show_value("alloced", alloced);
275 show_value("free", size - alloced);
276}
277
278void bloblist_show_list(void)
279{
280 struct bloblist_hdr *hdr = gd->bloblist;
281 struct bloblist_rec *rec;
282
283 printf("%-8s %8s Tag Name\n", "Address", "Size");
284 for (rec = bloblist_first_blob(hdr); rec;
285 rec = bloblist_next_blob(hdr, rec)) {
286 printf("%08lx %8x %3d %s\n",
287 (ulong)map_to_sysmem((void *)rec + rec->hdr_size),
288 rec->size, rec->tag, bloblist_tag_name(rec->tag));
289 }
290}
291
Simon Glass9f407d42018-11-15 18:43:50 -0700292int bloblist_init(void)
293{
294 bool expected;
295 int ret = -ENOENT;
296
297 /**
298 * Wed expect to find an existing bloblist in the first phase of U-Boot
299 * that runs
300 */
301 expected = !u_boot_first_phase();
302 if (expected)
303 ret = bloblist_check(CONFIG_BLOBLIST_ADDR,
304 CONFIG_BLOBLIST_SIZE);
305 if (ret) {
306 log(LOGC_BLOBLIST, expected ? LOGL_WARNING : LOGL_DEBUG,
307 "Existing bloblist not found: creating new bloblist\n");
308 ret = bloblist_new(CONFIG_BLOBLIST_ADDR, CONFIG_BLOBLIST_SIZE,
309 0);
310 } else {
311 log(LOGC_BLOBLIST, LOGL_DEBUG, "Found existing bloblist\n");
312 }
313
314 return ret;
315}