]>
Commit | Line | Data |
---|---|---|
6c9e3d1f | 1 | // SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause |
9f407d4e SG |
2 | /* |
3 | * Copyright 2018 Google, Inc | |
4 | * Written by Simon Glass <sjg@chromium.org> | |
5 | */ | |
6 | ||
1d8bbd76 SG |
7 | #define LOG_CATEGORY LOGC_BLOBLIST |
8 | ||
9f407d4e | 9 | #include <bloblist.h> |
4e4bf944 | 10 | #include <display_options.h> |
9f407d4e | 11 | #include <log.h> |
d5b6e91b | 12 | #include <malloc.h> |
9f407d4e SG |
13 | #include <mapmem.h> |
14 | #include <spl.h> | |
997dac6e | 15 | #include <tables_csum.h> |
401d1c4f | 16 | #include <asm/global_data.h> |
3db71108 | 17 | #include <u-boot/crc.h> |
9f407d4e | 18 | |
751b7c79 SG |
19 | /* |
20 | * A bloblist is a single contiguous chunk of memory with a header | |
21 | * (struct bloblist_hdr) and a number of blobs in it. | |
22 | * | |
23 | * Each blob starts on a BLOBLIST_ALIGN boundary relative to the start of the | |
24 | * bloblist and consists of a struct bloblist_rec, some padding to the required | |
25 | * alignment for the blog and then the actual data. The padding ensures that the | |
26 | * start address of the data in each blob is aligned as required. Note that | |
27 | * each blob's *data* is aligned to BLOBLIST_ALIGN regardless of the alignment | |
28 | * of the bloblist itself or the blob header. | |
751b7c79 SG |
29 | */ |
30 | ||
9f407d4e SG |
31 | DECLARE_GLOBAL_DATA_PTR; |
32 | ||
f16ec777 SG |
33 | static struct tag_name { |
34 | enum bloblist_tag_t tag; | |
35 | const char *name; | |
36 | } tag_name[] = { | |
e748e4b7 | 37 | { BLOBLISTT_VOID, "(void)" }, |
f16ec777 SG |
38 | |
39 | /* BLOBLISTT_AREA_FIRMWARE_TOP */ | |
e748e4b7 SG |
40 | { BLOBLISTT_CONTROL_FDT, "Control FDT" }, |
41 | { BLOBLISTT_HOB_BLOCK, "HOB block" }, | |
42 | { BLOBLISTT_HOB_LIST, "HOB list" }, | |
43 | { BLOBLISTT_ACPI_TABLES, "ACPI tables for x86" }, | |
44 | { BLOBLISTT_TPM_EVLOG, "TPM event log defined by TCG EFI" }, | |
45 | { BLOBLISTT_TPM_CRB_BASE, "TPM Command Response Buffer address" }, | |
f16ec777 SG |
46 | |
47 | /* BLOBLISTT_AREA_FIRMWARE */ | |
f16ec777 SG |
48 | { BLOBLISTT_TPM2_TCG_LOG, "TPM v2 log space" }, |
49 | { BLOBLISTT_TCPA_LOG, "TPM log space" }, | |
e748e4b7 SG |
50 | { BLOBLISTT_ACPI_GNVS, "ACPI GNVS" }, |
51 | ||
52 | /* BLOBLISTT_AREA_TF */ | |
53 | { BLOBLISTT_OPTEE_PAGABLE_PART, "OP-TEE pagable part" }, | |
54 | ||
55 | /* BLOBLISTT_AREA_OTHER */ | |
56 | { BLOBLISTT_INTEL_VBT, "Intel Video-BIOS table" }, | |
f16ec777 SG |
57 | { BLOBLISTT_SMBIOS_TABLES, "SMBIOS tables for x86" }, |
58 | { BLOBLISTT_VBOOT_CTX, "Chrome OS vboot context" }, | |
59 | ||
60 | /* BLOBLISTT_PROJECT_AREA */ | |
61 | { BLOBLISTT_U_BOOT_SPL_HANDOFF, "SPL hand-off" }, | |
14d9f63d | 62 | { BLOBLISTT_VBE, "VBE" }, |
03fe79c0 | 63 | { BLOBLISTT_U_BOOT_VIDEO, "SPL video handoff" }, |
f16ec777 SG |
64 | |
65 | /* BLOBLISTT_VENDOR_AREA */ | |
4aed2276 SG |
66 | }; |
67 | ||
68 | const char *bloblist_tag_name(enum bloblist_tag_t tag) | |
69 | { | |
f16ec777 | 70 | int i; |
4aed2276 | 71 | |
f16ec777 SG |
72 | for (i = 0; i < ARRAY_SIZE(tag_name); i++) { |
73 | if (tag_name[i].tag == tag) | |
74 | return tag_name[i].name; | |
75 | } | |
76 | ||
77 | return "invalid"; | |
4aed2276 SG |
78 | } |
79 | ||
80 | static struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr) | |
9f407d4e | 81 | { |
b86b2d94 | 82 | if (hdr->used_size <= hdr->hdr_size) |
9f407d4e SG |
83 | return NULL; |
84 | return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size); | |
85 | } | |
86 | ||
1f06ed41 SG |
87 | static inline uint rec_hdr_size(struct bloblist_rec *rec) |
88 | { | |
b6e83826 SG |
89 | return (rec->tag_and_hdr_size & BLOBLISTR_HDR_SIZE_MASK) >> |
90 | BLOBLISTR_HDR_SIZE_SHIFT; | |
1f06ed41 SG |
91 | } |
92 | ||
93 | static inline uint rec_tag(struct bloblist_rec *rec) | |
94 | { | |
b6e83826 SG |
95 | return (rec->tag_and_hdr_size & BLOBLISTR_TAG_MASK) >> |
96 | BLOBLISTR_TAG_SHIFT; | |
1f06ed41 SG |
97 | } |
98 | ||
1fe59375 SG |
99 | static ulong bloblist_blob_end_ofs(struct bloblist_hdr *hdr, |
100 | struct bloblist_rec *rec) | |
9f407d4e SG |
101 | { |
102 | ulong offset; | |
103 | ||
104 | offset = (void *)rec - (void *)hdr; | |
b6e83826 SG |
105 | /* |
106 | * The data section of next TE should start from an address aligned | |
107 | * to 1 << hdr->align_log2. | |
108 | */ | |
109 | offset += rec_hdr_size(rec) + rec->size; | |
110 | offset = round_up(offset + rec_hdr_size(rec), 1 << hdr->align_log2); | |
111 | offset -= rec_hdr_size(rec); | |
1fe59375 SG |
112 | |
113 | return offset; | |
114 | } | |
115 | ||
116 | static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr, | |
117 | struct bloblist_rec *rec) | |
118 | { | |
119 | ulong offset = bloblist_blob_end_ofs(hdr, rec); | |
120 | ||
b86b2d94 | 121 | if (offset >= hdr->used_size) |
9f407d4e SG |
122 | return NULL; |
123 | return (struct bloblist_rec *)((void *)hdr + offset); | |
124 | } | |
125 | ||
126 | #define foreach_rec(_rec, _hdr) \ | |
127 | for (_rec = bloblist_first_blob(_hdr); \ | |
128 | _rec; \ | |
129 | _rec = bloblist_next_blob(_hdr, _rec)) | |
130 | ||
131 | static struct bloblist_rec *bloblist_findrec(uint tag) | |
132 | { | |
133 | struct bloblist_hdr *hdr = gd->bloblist; | |
134 | struct bloblist_rec *rec; | |
135 | ||
136 | if (!hdr) | |
137 | return NULL; | |
138 | ||
139 | foreach_rec(rec, hdr) { | |
1f06ed41 | 140 | if (rec_tag(rec) == tag) |
9f407d4e SG |
141 | return rec; |
142 | } | |
143 | ||
144 | return NULL; | |
145 | } | |
146 | ||
1a2e02f9 | 147 | static int bloblist_addrec(uint tag, int size, int align_log2, |
4c1497e7 | 148 | struct bloblist_rec **recp) |
9f407d4e SG |
149 | { |
150 | struct bloblist_hdr *hdr = gd->bloblist; | |
151 | struct bloblist_rec *rec; | |
f9ef9fb0 | 152 | int data_start, aligned_start, new_alloced; |
751b7c79 | 153 | |
1a2e02f9 | 154 | if (!align_log2) |
b6e83826 | 155 | align_log2 = BLOBLIST_BLOB_ALIGN_LOG2; |
4c1497e7 | 156 | |
751b7c79 | 157 | /* Figure out where the new data will start */ |
b86b2d94 | 158 | data_start = map_to_sysmem(hdr) + hdr->used_size + sizeof(*rec); |
4c1497e7 | 159 | |
b86b2d94 | 160 | /* Align the address and then calculate the offset from used size */ |
f9ef9fb0 SG |
161 | aligned_start = ALIGN(data_start, 1U << align_log2) - data_start; |
162 | ||
163 | /* If we need to create a dummy record, create it */ | |
164 | if (aligned_start) { | |
165 | int void_size = aligned_start - sizeof(*rec); | |
166 | struct bloblist_rec *vrec; | |
167 | int ret; | |
168 | ||
169 | ret = bloblist_addrec(BLOBLISTT_VOID, void_size, 0, &vrec); | |
170 | if (ret) | |
171 | return log_msg_ret("void", ret); | |
172 | ||
173 | /* start the record after that */ | |
b86b2d94 | 174 | data_start = map_to_sysmem(hdr) + hdr->used_size + sizeof(*vrec); |
f9ef9fb0 | 175 | } |
9f407d4e | 176 | |
751b7c79 | 177 | /* Calculate the new allocated total */ |
f9ef9fb0 SG |
178 | new_alloced = data_start - map_to_sysmem(hdr) + |
179 | ALIGN(size, 1U << align_log2); | |
4c1497e7 | 180 | |
b86b2d94 SG |
181 | if (new_alloced > hdr->total_size) { |
182 | log_err("Failed to allocate %x bytes\n", size); | |
183 | log_err("Used size=%x, total size=%x\n", | |
184 | hdr->used_size, hdr->total_size); | |
9f407d4e SG |
185 | return log_msg_ret("bloblist add", -ENOSPC); |
186 | } | |
b86b2d94 | 187 | rec = (void *)hdr + hdr->used_size; |
9f407d4e | 188 | |
b6e83826 | 189 | rec->tag_and_hdr_size = tag | sizeof(*rec) << BLOBLISTR_HDR_SIZE_SHIFT; |
9f407d4e | 190 | rec->size = size; |
b83994de SG |
191 | |
192 | /* Zero the record data */ | |
1f06ed41 | 193 | memset((void *)rec + rec_hdr_size(rec), '\0', rec->size); |
751b7c79 | 194 | |
b86b2d94 | 195 | hdr->used_size = new_alloced; |
9f407d4e SG |
196 | *recp = rec; |
197 | ||
198 | return 0; | |
199 | } | |
200 | ||
4c1497e7 | 201 | static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size, |
1a2e02f9 | 202 | int align_log2) |
9f407d4e SG |
203 | { |
204 | struct bloblist_rec *rec; | |
205 | ||
206 | rec = bloblist_findrec(tag); | |
207 | if (rec) { | |
5b044548 SG |
208 | if (size && size != rec->size) { |
209 | *recp = rec; | |
9f407d4e | 210 | return -ESPIPE; |
5b044548 | 211 | } |
9f407d4e SG |
212 | } else { |
213 | int ret; | |
214 | ||
1a2e02f9 | 215 | ret = bloblist_addrec(tag, size, align_log2, &rec); |
9f407d4e SG |
216 | if (ret) |
217 | return ret; | |
218 | } | |
219 | *recp = rec; | |
220 | ||
221 | return 0; | |
222 | } | |
223 | ||
224 | void *bloblist_find(uint tag, int size) | |
bb894c5d RM |
225 | { |
226 | void *blob = NULL; | |
227 | int blob_size; | |
228 | ||
229 | blob = bloblist_get_blob(tag, &blob_size); | |
230 | ||
231 | if (size && size != blob_size) | |
232 | return NULL; | |
233 | ||
234 | return blob; | |
235 | } | |
236 | ||
237 | void *bloblist_get_blob(uint tag, int *sizep) | |
9f407d4e SG |
238 | { |
239 | struct bloblist_rec *rec; | |
240 | ||
241 | rec = bloblist_findrec(tag); | |
242 | if (!rec) | |
243 | return NULL; | |
bb894c5d RM |
244 | |
245 | *sizep = rec->size; | |
9f407d4e | 246 | |
1f06ed41 | 247 | return (void *)rec + rec_hdr_size(rec); |
9f407d4e SG |
248 | } |
249 | ||
1a2e02f9 | 250 | void *bloblist_add(uint tag, int size, int align_log2) |
9f407d4e SG |
251 | { |
252 | struct bloblist_rec *rec; | |
253 | ||
1a2e02f9 | 254 | if (bloblist_addrec(tag, size, align_log2, &rec)) |
9f407d4e SG |
255 | return NULL; |
256 | ||
1f06ed41 | 257 | return (void *)rec + rec_hdr_size(rec); |
9f407d4e SG |
258 | } |
259 | ||
1a2e02f9 | 260 | int bloblist_ensure_size(uint tag, int size, int align_log2, void **blobp) |
9f407d4e SG |
261 | { |
262 | struct bloblist_rec *rec; | |
263 | int ret; | |
264 | ||
1a2e02f9 | 265 | ret = bloblist_ensurerec(tag, &rec, size, align_log2); |
9f407d4e SG |
266 | if (ret) |
267 | return ret; | |
1f06ed41 | 268 | *blobp = (void *)rec + rec_hdr_size(rec); |
9f407d4e SG |
269 | |
270 | return 0; | |
271 | } | |
272 | ||
273 | void *bloblist_ensure(uint tag, int size) | |
274 | { | |
275 | struct bloblist_rec *rec; | |
276 | ||
4c1497e7 | 277 | if (bloblist_ensurerec(tag, &rec, size, 0)) |
9f407d4e SG |
278 | return NULL; |
279 | ||
1f06ed41 | 280 | return (void *)rec + rec_hdr_size(rec); |
9f407d4e SG |
281 | } |
282 | ||
5b044548 SG |
283 | int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp) |
284 | { | |
285 | struct bloblist_rec *rec; | |
286 | int ret; | |
287 | ||
4c1497e7 | 288 | ret = bloblist_ensurerec(tag, &rec, *sizep, 0); |
5b044548 SG |
289 | if (ret == -ESPIPE) |
290 | *sizep = rec->size; | |
291 | else if (ret) | |
292 | return ret; | |
1f06ed41 | 293 | *blobp = (void *)rec + rec_hdr_size(rec); |
5b044548 SG |
294 | |
295 | return 0; | |
296 | } | |
297 | ||
1fe59375 SG |
298 | static int bloblist_resize_rec(struct bloblist_hdr *hdr, |
299 | struct bloblist_rec *rec, | |
300 | int new_size) | |
301 | { | |
302 | int expand_by; /* Number of bytes to expand by (-ve to contract) */ | |
b86b2d94 | 303 | int new_alloced; |
1fe59375 SG |
304 | ulong next_ofs; /* Offset of the record after @rec */ |
305 | ||
b6e83826 | 306 | expand_by = ALIGN(new_size - rec->size, BLOBLIST_BLOB_ALIGN); |
b86b2d94 | 307 | new_alloced = ALIGN(hdr->used_size + expand_by, BLOBLIST_BLOB_ALIGN); |
1fe59375 | 308 | if (new_size < 0) { |
1d8bbd76 SG |
309 | log_debug("Attempt to shrink blob size below 0 (%x)\n", |
310 | new_size); | |
1fe59375 SG |
311 | return log_msg_ret("size", -EINVAL); |
312 | } | |
b86b2d94 SG |
313 | if (new_alloced > hdr->total_size) { |
314 | log_err("Failed to allocate %x bytes\n", new_size); | |
315 | log_err("Used size=%x, total size=%x\n", | |
316 | hdr->used_size, hdr->total_size); | |
1fe59375 SG |
317 | return log_msg_ret("alloc", -ENOSPC); |
318 | } | |
319 | ||
320 | /* Move the following blobs up or down, if this is not the last */ | |
321 | next_ofs = bloblist_blob_end_ofs(hdr, rec); | |
b86b2d94 | 322 | if (next_ofs != hdr->used_size) { |
1fe59375 SG |
323 | memmove((void *)hdr + next_ofs + expand_by, |
324 | (void *)hdr + next_ofs, new_alloced - next_ofs); | |
325 | } | |
b86b2d94 | 326 | hdr->used_size = new_alloced; |
1fe59375 SG |
327 | |
328 | /* Zero the new part of the blob */ | |
329 | if (expand_by > 0) { | |
1f06ed41 | 330 | memset((void *)rec + rec_hdr_size(rec) + rec->size, '\0', |
1fe59375 SG |
331 | new_size - rec->size); |
332 | } | |
333 | ||
334 | /* Update the size of this blob */ | |
335 | rec->size = new_size; | |
336 | ||
337 | return 0; | |
338 | } | |
339 | ||
340 | int bloblist_resize(uint tag, int new_size) | |
341 | { | |
342 | struct bloblist_hdr *hdr = gd->bloblist; | |
343 | struct bloblist_rec *rec; | |
344 | int ret; | |
345 | ||
346 | rec = bloblist_findrec(tag); | |
347 | if (!rec) | |
348 | return log_msg_ret("find", -ENOENT); | |
349 | ret = bloblist_resize_rec(hdr, rec, new_size); | |
350 | if (ret) | |
351 | return log_msg_ret("resize", ret); | |
352 | ||
353 | return 0; | |
354 | } | |
355 | ||
9f407d4e SG |
356 | static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr) |
357 | { | |
997dac6e | 358 | u8 chksum; |
9f407d4e | 359 | |
b86b2d94 | 360 | chksum = table_compute_checksum(hdr, hdr->used_size); |
997dac6e | 361 | chksum += hdr->chksum; |
9f407d4e SG |
362 | |
363 | return chksum; | |
364 | } | |
365 | ||
7d790a80 | 366 | int bloblist_new(ulong addr, uint size, uint flags, uint align_log2) |
9f407d4e SG |
367 | { |
368 | struct bloblist_hdr *hdr; | |
369 | ||
370 | if (size < sizeof(*hdr)) | |
371 | return log_ret(-ENOSPC); | |
372 | if (addr & (BLOBLIST_ALIGN - 1)) | |
373 | return log_ret(-EFAULT); | |
374 | hdr = map_sysmem(addr, size); | |
375 | memset(hdr, '\0', sizeof(*hdr)); | |
376 | hdr->version = BLOBLIST_VERSION; | |
377 | hdr->hdr_size = sizeof(*hdr); | |
378 | hdr->flags = flags; | |
379 | hdr->magic = BLOBLIST_MAGIC; | |
b86b2d94 SG |
380 | hdr->used_size = hdr->hdr_size; |
381 | hdr->total_size = size; | |
7d790a80 | 382 | hdr->align_log2 = align_log2 ? align_log2 : BLOBLIST_BLOB_ALIGN_LOG2; |
9f407d4e SG |
383 | hdr->chksum = 0; |
384 | gd->bloblist = hdr; | |
385 | ||
386 | return 0; | |
387 | } | |
388 | ||
389 | int bloblist_check(ulong addr, uint size) | |
390 | { | |
391 | struct bloblist_hdr *hdr; | |
392 | u32 chksum; | |
393 | ||
394 | hdr = map_sysmem(addr, sizeof(*hdr)); | |
395 | if (hdr->magic != BLOBLIST_MAGIC) | |
396 | return log_msg_ret("Bad magic", -ENOENT); | |
397 | if (hdr->version != BLOBLIST_VERSION) | |
398 | return log_msg_ret("Bad version", -EPROTONOSUPPORT); | |
67254214 | 399 | if (!hdr->total_size || (size && hdr->total_size > size)) |
b86b2d94 SG |
400 | return log_msg_ret("Bad total size", -EFBIG); |
401 | if (hdr->used_size > hdr->total_size) | |
402 | return log_msg_ret("Bad used size", -ENOENT); | |
403 | if (hdr->hdr_size != sizeof(struct bloblist_hdr)) | |
404 | return log_msg_ret("Bad header size", -ENOENT); | |
405 | ||
9f407d4e SG |
406 | chksum = bloblist_calc_chksum(hdr); |
407 | if (hdr->chksum != chksum) { | |
1d8bbd76 | 408 | log_err("Checksum %x != %x\n", hdr->chksum, chksum); |
9f407d4e SG |
409 | return log_msg_ret("Bad checksum", -EIO); |
410 | } | |
411 | gd->bloblist = hdr; | |
412 | ||
413 | return 0; | |
414 | } | |
415 | ||
416 | int bloblist_finish(void) | |
417 | { | |
418 | struct bloblist_hdr *hdr = gd->bloblist; | |
419 | ||
420 | hdr->chksum = bloblist_calc_chksum(hdr); | |
b86b2d94 | 421 | log_debug("Finished bloblist size %lx at %lx\n", (ulong)hdr->used_size, |
99047f5d | 422 | (ulong)map_to_sysmem(hdr)); |
9f407d4e SG |
423 | |
424 | return 0; | |
425 | } | |
426 | ||
e50a24a0 SG |
427 | ulong bloblist_get_base(void) |
428 | { | |
429 | return map_to_sysmem(gd->bloblist); | |
430 | } | |
431 | ||
432 | ulong bloblist_get_size(void) | |
433 | { | |
434 | struct bloblist_hdr *hdr = gd->bloblist; | |
435 | ||
b86b2d94 SG |
436 | return hdr->used_size; |
437 | } | |
438 | ||
439 | ulong bloblist_get_total_size(void) | |
440 | { | |
441 | struct bloblist_hdr *hdr = gd->bloblist; | |
442 | ||
443 | return hdr->total_size; | |
e50a24a0 SG |
444 | } |
445 | ||
b86b2d94 | 446 | void bloblist_get_stats(ulong *basep, ulong *tsizep, ulong *usizep) |
4aed2276 SG |
447 | { |
448 | struct bloblist_hdr *hdr = gd->bloblist; | |
449 | ||
450 | *basep = map_to_sysmem(gd->bloblist); | |
b86b2d94 SG |
451 | *tsizep = hdr->total_size; |
452 | *usizep = hdr->used_size; | |
4aed2276 SG |
453 | } |
454 | ||
455 | static void show_value(const char *prompt, ulong value) | |
456 | { | |
b86b2d94 | 457 | printf("%s:%*s %-5lx ", prompt, 10 - (int)strlen(prompt), "", value); |
4aed2276 SG |
458 | print_size(value, "\n"); |
459 | } | |
460 | ||
461 | void bloblist_show_stats(void) | |
462 | { | |
b86b2d94 | 463 | ulong base, tsize, usize; |
4aed2276 | 464 | |
b86b2d94 SG |
465 | bloblist_get_stats(&base, &tsize, &usize); |
466 | printf("base: %lx\n", base); | |
467 | show_value("total size", tsize); | |
468 | show_value("used size", usize); | |
469 | show_value("free", tsize - usize); | |
4aed2276 SG |
470 | } |
471 | ||
472 | void bloblist_show_list(void) | |
473 | { | |
474 | struct bloblist_hdr *hdr = gd->bloblist; | |
475 | struct bloblist_rec *rec; | |
476 | ||
f16ec777 | 477 | printf("%-8s %8s Tag Name\n", "Address", "Size"); |
4aed2276 SG |
478 | for (rec = bloblist_first_blob(hdr); rec; |
479 | rec = bloblist_next_blob(hdr, rec)) { | |
f16ec777 | 480 | printf("%08lx %8x %4x %s\n", |
1f06ed41 SG |
481 | (ulong)map_to_sysmem((void *)rec + rec_hdr_size(rec)), |
482 | rec->size, rec_tag(rec), | |
483 | bloblist_tag_name(rec_tag(rec))); | |
4aed2276 SG |
484 | } |
485 | } | |
486 | ||
1ef43f3b | 487 | int bloblist_reloc(void *to, uint to_size) |
9fe06464 SG |
488 | { |
489 | struct bloblist_hdr *hdr; | |
490 | ||
7d521f20 HM |
491 | if (!to_size) |
492 | return 0; | |
493 | ||
1ef43f3b RM |
494 | if (to_size < gd->bloblist->total_size) |
495 | return -ENOSPC; | |
496 | ||
497 | memcpy(to, gd->bloblist, gd->bloblist->total_size); | |
9fe06464 | 498 | hdr = to; |
b86b2d94 | 499 | hdr->total_size = to_size; |
1ef43f3b RM |
500 | gd->bloblist = to; |
501 | ||
502 | return 0; | |
9fe06464 SG |
503 | } |
504 | ||
66131310 RM |
505 | /* |
506 | * Weak default function for getting bloblist from boot args. | |
507 | */ | |
6799f090 | 508 | int __weak xferlist_from_boot_arg(ulong __always_unused *addr) |
66131310 RM |
509 | { |
510 | return -ENOENT; | |
511 | } | |
512 | ||
9f407d4e SG |
513 | int bloblist_init(void) |
514 | { | |
ce3e75dc | 515 | bool fixed = IS_ENABLED(CONFIG_BLOBLIST_FIXED); |
6799f090 | 516 | int ret = 0; |
b36f6294 | 517 | ulong addr = 0, size; |
66131310 | 518 | |
6799f090 RM |
519 | /* Check if a valid transfer list passed in */ |
520 | if (!xferlist_from_boot_arg(&addr)) { | |
521 | size = bloblist_get_total_size(); | |
522 | } else { | |
523 | /* | |
524 | * If U-Boot is not in the first phase, an existing bloblist must | |
525 | * be at a fixed address. | |
526 | */ | |
527 | bool from_addr = fixed && !xpl_is_first_phase(); | |
7d521f20 | 528 | |
03a76b1a RM |
529 | /* |
530 | * If Firmware Handoff is mandatory but no transfer list is | |
531 | * observed, report it as an error. | |
532 | */ | |
533 | if (IS_ENABLED(CONFIG_BLOBLIST_PASSAGE_MANDATORY)) | |
534 | return -ENOENT; | |
66131310 | 535 | |
6799f090 | 536 | ret = -ENOENT; |
7d521f20 | 537 | |
6799f090 RM |
538 | if (xpl_prev_phase() == PHASE_TPL && |
539 | !IS_ENABLED(CONFIG_TPL_BLOBLIST)) | |
540 | from_addr = false; | |
541 | if (fixed) | |
542 | addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, | |
543 | CONFIG_BLOBLIST_ADDR); | |
544 | size = CONFIG_BLOBLIST_SIZE; | |
66131310 | 545 | |
6799f090 RM |
546 | if (from_addr) |
547 | ret = bloblist_check(addr, size); | |
548 | ||
549 | if (ret) | |
550 | log_warning("Bloblist at %lx not found (err=%d)\n", | |
551 | addr, ret); | |
552 | else | |
553 | /* Get the real size */ | |
554 | size = gd->bloblist->total_size; | |
555 | } | |
66131310 | 556 | |
9f407d4e | 557 | if (ret) { |
66131310 RM |
558 | /* |
559 | * If we don't have a bloblist from a fixed address, or the one | |
560 | * in the fixed address is not valid. we must allocate the | |
561 | * memory for it now. | |
562 | */ | |
99047f5d SG |
563 | if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC)) { |
564 | void *ptr = memalign(BLOBLIST_ALIGN, size); | |
d5b6e91b SG |
565 | |
566 | if (!ptr) | |
567 | return log_msg_ret("alloc", -ENOMEM); | |
568 | addr = map_to_sysmem(ptr); | |
ce3e75dc | 569 | } else if (!fixed) { |
66131310 RM |
570 | return log_msg_ret("BLOBLIST_FIXED is not enabled", |
571 | ret); | |
d5b6e91b | 572 | } |
99047f5d SG |
573 | log_debug("Creating new bloblist size %lx at %lx\n", size, |
574 | addr); | |
7d790a80 | 575 | ret = bloblist_new(addr, size, 0, 0); |
9f407d4e | 576 | } else { |
99047f5d SG |
577 | log_debug("Found existing bloblist size %lx at %lx\n", size, |
578 | addr); | |
9f407d4e | 579 | } |
6799f090 | 580 | |
3d653180 SG |
581 | if (ret) |
582 | return log_msg_ret("ini", ret); | |
583 | gd->flags |= GD_FLG_BLOBLIST_READY; | |
584 | ||
66131310 RM |
585 | #ifdef DEBUG |
586 | bloblist_show_stats(); | |
587 | bloblist_show_list(); | |
588 | #endif | |
589 | ||
3d653180 SG |
590 | return 0; |
591 | } | |
9f407d4e | 592 | |
3d653180 SG |
593 | int bloblist_maybe_init(void) |
594 | { | |
595 | if (CONFIG_IS_ENABLED(BLOBLIST) && !(gd->flags & GD_FLG_BLOBLIST_READY)) | |
596 | return bloblist_init(); | |
597 | ||
598 | return 0; | |
9f407d4e | 599 | } |
1c4751fd | 600 | |
6799f090 | 601 | int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig, ulong xlist) |
1c4751fd | 602 | { |
99145eec | 603 | u64 version = BLOBLIST_REGCONV_VER; |
84ab75fb | 604 | ulong sigval; |
6799f090 | 605 | int ret; |
84ab75fb | 606 | |
99145eec AG |
607 | if ((IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_SPL_BUILD)) || |
608 | (IS_ENABLED(CONFIG_SPL_64BIT) && IS_ENABLED(CONFIG_SPL_BUILD))) { | |
609 | sigval = ((BLOBLIST_MAGIC & ((1ULL << BLOBLIST_REGCONV_SHIFT_64) - 1)) | | |
610 | ((version & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_64)); | |
611 | } else { | |
612 | sigval = ((BLOBLIST_MAGIC & ((1UL << BLOBLIST_REGCONV_SHIFT_32) - 1)) | | |
84ab75fb | 613 | ((version & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_32)); |
99145eec | 614 | } |
84ab75fb | 615 | |
6799f090 RM |
616 | if (rzero || rsig != sigval) |
617 | return -EIO; | |
618 | ||
619 | ret = bloblist_check(xlist, 0); | |
620 | if (ret) | |
621 | return ret; | |
622 | ||
623 | if (rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) { | |
1c4751fd RM |
624 | gd->bloblist = NULL; /* Reset the gd bloblist pointer */ |
625 | return -EIO; | |
626 | } | |
627 | ||
628 | return 0; | |
629 | } |