1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2018 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
12 #include <u-boot/crc.h>
14 DECLARE_GLOBAL_DATA_PTR;
16 struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
18 if (hdr->alloced <= hdr->hdr_size)
20 return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size);
23 struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
24 struct bloblist_rec *rec)
28 offset = (void *)rec - (void *)hdr;
29 offset += rec->hdr_size + ALIGN(rec->size, BLOBLIST_ALIGN);
30 if (offset >= hdr->alloced)
32 return (struct bloblist_rec *)((void *)hdr + offset);
35 #define foreach_rec(_rec, _hdr) \
36 for (_rec = bloblist_first_blob(_hdr); \
38 _rec = bloblist_next_blob(_hdr, _rec))
40 static struct bloblist_rec *bloblist_findrec(uint tag)
42 struct bloblist_hdr *hdr = gd->bloblist;
43 struct bloblist_rec *rec;
48 foreach_rec(rec, hdr) {
56 static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp)
58 struct bloblist_hdr *hdr = gd->bloblist;
59 struct bloblist_rec *rec;
62 new_alloced = hdr->alloced + sizeof(*rec) + ALIGN(size, BLOBLIST_ALIGN);
63 if (new_alloced >= hdr->size) {
64 log(LOGC_BLOBLIST, LOGL_ERR,
65 "Failed to allocate %x bytes size=%x, need size=%x\n",
66 size, hdr->size, new_alloced);
67 return log_msg_ret("bloblist add", -ENOSPC);
69 rec = (void *)hdr + hdr->alloced;
70 hdr->alloced = new_alloced;
73 rec->hdr_size = sizeof(*rec);
77 /* Zero the record data */
78 memset(rec + 1, '\0', rec->size);
84 static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size)
86 struct bloblist_rec *rec;
88 rec = bloblist_findrec(tag);
90 if (size && size != rec->size) {
97 ret = bloblist_addrec(tag, size, &rec);
106 void *bloblist_find(uint tag, int size)
108 struct bloblist_rec *rec;
110 rec = bloblist_findrec(tag);
113 if (size && size != rec->size)
116 return (void *)rec + rec->hdr_size;
119 void *bloblist_add(uint tag, int size)
121 struct bloblist_rec *rec;
123 if (bloblist_addrec(tag, size, &rec))
129 int bloblist_ensure_size(uint tag, int size, void **blobp)
131 struct bloblist_rec *rec;
134 ret = bloblist_ensurerec(tag, &rec, size);
137 *blobp = (void *)rec + rec->hdr_size;
142 void *bloblist_ensure(uint tag, int size)
144 struct bloblist_rec *rec;
146 if (bloblist_ensurerec(tag, &rec, size))
149 return (void *)rec + rec->hdr_size;
152 int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp)
154 struct bloblist_rec *rec;
157 ret = bloblist_ensurerec(tag, &rec, *sizep);
162 *blobp = (void *)rec + rec->hdr_size;
167 static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr)
169 struct bloblist_rec *rec;
172 chksum = crc32(0, (unsigned char *)hdr,
173 offsetof(struct bloblist_hdr, chksum));
174 foreach_rec(rec, hdr) {
175 chksum = crc32(chksum, (void *)rec, rec->hdr_size);
176 chksum = crc32(chksum, (void *)rec + rec->hdr_size, rec->size);
182 int bloblist_new(ulong addr, uint size, uint flags)
184 struct bloblist_hdr *hdr;
186 if (size < sizeof(*hdr))
187 return log_ret(-ENOSPC);
188 if (addr & (BLOBLIST_ALIGN - 1))
189 return log_ret(-EFAULT);
190 hdr = map_sysmem(addr, size);
191 memset(hdr, '\0', sizeof(*hdr));
192 hdr->version = BLOBLIST_VERSION;
193 hdr->hdr_size = sizeof(*hdr);
195 hdr->magic = BLOBLIST_MAGIC;
197 hdr->alloced = hdr->hdr_size;
204 int bloblist_check(ulong addr, uint size)
206 struct bloblist_hdr *hdr;
209 hdr = map_sysmem(addr, sizeof(*hdr));
210 if (hdr->magic != BLOBLIST_MAGIC)
211 return log_msg_ret("Bad magic", -ENOENT);
212 if (hdr->version != BLOBLIST_VERSION)
213 return log_msg_ret("Bad version", -EPROTONOSUPPORT);
214 if (size && hdr->size != size)
215 return log_msg_ret("Bad size", -EFBIG);
216 chksum = bloblist_calc_chksum(hdr);
217 if (hdr->chksum != chksum) {
218 log(LOGC_BLOBLIST, LOGL_ERR, "Checksum %x != %x\n", hdr->chksum,
220 return log_msg_ret("Bad checksum", -EIO);
227 int bloblist_finish(void)
229 struct bloblist_hdr *hdr = gd->bloblist;
231 hdr->chksum = bloblist_calc_chksum(hdr);
236 int bloblist_init(void)
242 * Wed expect to find an existing bloblist in the first phase of U-Boot
245 expected = !u_boot_first_phase();
247 ret = bloblist_check(CONFIG_BLOBLIST_ADDR,
248 CONFIG_BLOBLIST_SIZE);
250 log(LOGC_BLOBLIST, expected ? LOGL_WARNING : LOGL_DEBUG,
251 "Existing bloblist not found: creating new bloblist\n");
252 ret = bloblist_new(CONFIG_BLOBLIST_ADDR, CONFIG_BLOBLIST_SIZE,
255 log(LOGC_BLOBLIST, LOGL_DEBUG, "Found existing bloblist\n");