1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2018 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
13 DECLARE_GLOBAL_DATA_PTR;
15 struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
17 if (hdr->alloced <= hdr->hdr_size)
19 return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size);
22 struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
23 struct bloblist_rec *rec)
27 offset = (void *)rec - (void *)hdr;
28 offset += rec->hdr_size + ALIGN(rec->size, BLOBLIST_ALIGN);
29 if (offset >= hdr->alloced)
31 return (struct bloblist_rec *)((void *)hdr + offset);
34 #define foreach_rec(_rec, _hdr) \
35 for (_rec = bloblist_first_blob(_hdr); \
37 _rec = bloblist_next_blob(_hdr, _rec))
39 static struct bloblist_rec *bloblist_findrec(uint tag)
41 struct bloblist_hdr *hdr = gd->bloblist;
42 struct bloblist_rec *rec;
47 foreach_rec(rec, hdr) {
55 static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp)
57 struct bloblist_hdr *hdr = gd->bloblist;
58 struct bloblist_rec *rec;
61 new_alloced = hdr->alloced + sizeof(*rec) +
62 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);
81 static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size)
83 struct bloblist_rec *rec;
85 rec = bloblist_findrec(tag);
87 if (size && size != rec->size)
92 ret = bloblist_addrec(tag, size, &rec);
101 void *bloblist_find(uint tag, int size)
103 struct bloblist_rec *rec;
105 rec = bloblist_findrec(tag);
108 if (size && size != rec->size)
111 return (void *)rec + rec->hdr_size;
114 void *bloblist_add(uint tag, int size)
116 struct bloblist_rec *rec;
118 if (bloblist_addrec(tag, size, &rec))
124 int bloblist_ensure_size(uint tag, int size, void **blobp)
126 struct bloblist_rec *rec;
129 ret = bloblist_ensurerec(tag, &rec, size);
132 *blobp = (void *)rec + rec->hdr_size;
137 void *bloblist_ensure(uint tag, int size)
139 struct bloblist_rec *rec;
141 if (bloblist_ensurerec(tag, &rec, size))
144 return (void *)rec + rec->hdr_size;
147 static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr)
149 struct bloblist_rec *rec;
152 chksum = crc32(0, (unsigned char *)hdr,
153 offsetof(struct bloblist_hdr, chksum));
154 foreach_rec(rec, hdr) {
155 chksum = crc32(chksum, (void *)rec, rec->hdr_size);
156 chksum = crc32(chksum, (void *)rec + rec->hdr_size, rec->size);
162 int bloblist_new(ulong addr, uint size, uint flags)
164 struct bloblist_hdr *hdr;
166 if (size < sizeof(*hdr))
167 return log_ret(-ENOSPC);
168 if (addr & (BLOBLIST_ALIGN - 1))
169 return log_ret(-EFAULT);
170 hdr = map_sysmem(addr, size);
171 memset(hdr, '\0', sizeof(*hdr));
172 hdr->version = BLOBLIST_VERSION;
173 hdr->hdr_size = sizeof(*hdr);
175 hdr->magic = BLOBLIST_MAGIC;
177 hdr->alloced = hdr->hdr_size;
184 int bloblist_check(ulong addr, uint size)
186 struct bloblist_hdr *hdr;
189 hdr = map_sysmem(addr, sizeof(*hdr));
190 if (hdr->magic != BLOBLIST_MAGIC)
191 return log_msg_ret("Bad magic", -ENOENT);
192 if (hdr->version != BLOBLIST_VERSION)
193 return log_msg_ret("Bad version", -EPROTONOSUPPORT);
194 if (size && hdr->size != size)
195 return log_msg_ret("Bad size", -EFBIG);
196 chksum = bloblist_calc_chksum(hdr);
197 if (hdr->chksum != chksum) {
198 log(LOGC_BLOBLIST, LOGL_ERR, "Checksum %x != %x\n", hdr->chksum,
200 return log_msg_ret("Bad checksum", -EIO);
207 int bloblist_finish(void)
209 struct bloblist_hdr *hdr = gd->bloblist;
211 hdr->chksum = bloblist_calc_chksum(hdr);
216 int bloblist_init(void)
222 * Wed expect to find an existing bloblist in the first phase of U-Boot
225 expected = !u_boot_first_phase();
227 ret = bloblist_check(CONFIG_BLOBLIST_ADDR,
228 CONFIG_BLOBLIST_SIZE);
230 log(LOGC_BLOBLIST, expected ? LOGL_WARNING : LOGL_DEBUG,
231 "Existing bloblist not found: creating new bloblist\n");
232 ret = bloblist_new(CONFIG_BLOBLIST_ADDR, CONFIG_BLOBLIST_SIZE,
235 log(LOGC_BLOBLIST, LOGL_DEBUG, "Found existing bloblist\n");