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");