]>
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 <[email protected]> | |
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) | |
225 | { | |
226 | struct bloblist_rec *rec; | |
227 | ||
228 | rec = bloblist_findrec(tag); | |
229 | if (!rec) | |
230 | return NULL; | |
231 | if (size && size != rec->size) | |
232 | return NULL; | |
233 | ||
1f06ed41 | 234 | return (void *)rec + rec_hdr_size(rec); |
9f407d4e SG |
235 | } |
236 | ||
1a2e02f9 | 237 | void *bloblist_add(uint tag, int size, int align_log2) |
9f407d4e SG |
238 | { |
239 | struct bloblist_rec *rec; | |
240 | ||
1a2e02f9 | 241 | if (bloblist_addrec(tag, size, align_log2, &rec)) |
9f407d4e SG |
242 | return NULL; |
243 | ||
1f06ed41 | 244 | return (void *)rec + rec_hdr_size(rec); |
9f407d4e SG |
245 | } |
246 | ||
1a2e02f9 | 247 | int bloblist_ensure_size(uint tag, int size, int align_log2, void **blobp) |
9f407d4e SG |
248 | { |
249 | struct bloblist_rec *rec; | |
250 | int ret; | |
251 | ||
1a2e02f9 | 252 | ret = bloblist_ensurerec(tag, &rec, size, align_log2); |
9f407d4e SG |
253 | if (ret) |
254 | return ret; | |
1f06ed41 | 255 | *blobp = (void *)rec + rec_hdr_size(rec); |
9f407d4e SG |
256 | |
257 | return 0; | |
258 | } | |
259 | ||
260 | void *bloblist_ensure(uint tag, int size) | |
261 | { | |
262 | struct bloblist_rec *rec; | |
263 | ||
4c1497e7 | 264 | if (bloblist_ensurerec(tag, &rec, size, 0)) |
9f407d4e SG |
265 | return NULL; |
266 | ||
1f06ed41 | 267 | return (void *)rec + rec_hdr_size(rec); |
9f407d4e SG |
268 | } |
269 | ||
5b044548 SG |
270 | int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp) |
271 | { | |
272 | struct bloblist_rec *rec; | |
273 | int ret; | |
274 | ||
4c1497e7 | 275 | ret = bloblist_ensurerec(tag, &rec, *sizep, 0); |
5b044548 SG |
276 | if (ret == -ESPIPE) |
277 | *sizep = rec->size; | |
278 | else if (ret) | |
279 | return ret; | |
1f06ed41 | 280 | *blobp = (void *)rec + rec_hdr_size(rec); |
5b044548 SG |
281 | |
282 | return 0; | |
283 | } | |
284 | ||
1fe59375 SG |
285 | static int bloblist_resize_rec(struct bloblist_hdr *hdr, |
286 | struct bloblist_rec *rec, | |
287 | int new_size) | |
288 | { | |
289 | int expand_by; /* Number of bytes to expand by (-ve to contract) */ | |
b86b2d94 | 290 | int new_alloced; |
1fe59375 SG |
291 | ulong next_ofs; /* Offset of the record after @rec */ |
292 | ||
b6e83826 | 293 | expand_by = ALIGN(new_size - rec->size, BLOBLIST_BLOB_ALIGN); |
b86b2d94 | 294 | new_alloced = ALIGN(hdr->used_size + expand_by, BLOBLIST_BLOB_ALIGN); |
1fe59375 | 295 | if (new_size < 0) { |
1d8bbd76 SG |
296 | log_debug("Attempt to shrink blob size below 0 (%x)\n", |
297 | new_size); | |
1fe59375 SG |
298 | return log_msg_ret("size", -EINVAL); |
299 | } | |
b86b2d94 SG |
300 | if (new_alloced > hdr->total_size) { |
301 | log_err("Failed to allocate %x bytes\n", new_size); | |
302 | log_err("Used size=%x, total size=%x\n", | |
303 | hdr->used_size, hdr->total_size); | |
1fe59375 SG |
304 | return log_msg_ret("alloc", -ENOSPC); |
305 | } | |
306 | ||
307 | /* Move the following blobs up or down, if this is not the last */ | |
308 | next_ofs = bloblist_blob_end_ofs(hdr, rec); | |
b86b2d94 | 309 | if (next_ofs != hdr->used_size) { |
1fe59375 SG |
310 | memmove((void *)hdr + next_ofs + expand_by, |
311 | (void *)hdr + next_ofs, new_alloced - next_ofs); | |
312 | } | |
b86b2d94 | 313 | hdr->used_size = new_alloced; |
1fe59375 SG |
314 | |
315 | /* Zero the new part of the blob */ | |
316 | if (expand_by > 0) { | |
1f06ed41 | 317 | memset((void *)rec + rec_hdr_size(rec) + rec->size, '\0', |
1fe59375 SG |
318 | new_size - rec->size); |
319 | } | |
320 | ||
321 | /* Update the size of this blob */ | |
322 | rec->size = new_size; | |
323 | ||
324 | return 0; | |
325 | } | |
326 | ||
327 | int bloblist_resize(uint tag, int new_size) | |
328 | { | |
329 | struct bloblist_hdr *hdr = gd->bloblist; | |
330 | struct bloblist_rec *rec; | |
331 | int ret; | |
332 | ||
333 | rec = bloblist_findrec(tag); | |
334 | if (!rec) | |
335 | return log_msg_ret("find", -ENOENT); | |
336 | ret = bloblist_resize_rec(hdr, rec, new_size); | |
337 | if (ret) | |
338 | return log_msg_ret("resize", ret); | |
339 | ||
340 | return 0; | |
341 | } | |
342 | ||
9f407d4e SG |
343 | static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr) |
344 | { | |
997dac6e | 345 | u8 chksum; |
9f407d4e | 346 | |
b86b2d94 | 347 | chksum = table_compute_checksum(hdr, hdr->used_size); |
997dac6e | 348 | chksum += hdr->chksum; |
9f407d4e SG |
349 | |
350 | return chksum; | |
351 | } | |
352 | ||
7d790a80 | 353 | int bloblist_new(ulong addr, uint size, uint flags, uint align_log2) |
9f407d4e SG |
354 | { |
355 | struct bloblist_hdr *hdr; | |
356 | ||
357 | if (size < sizeof(*hdr)) | |
358 | return log_ret(-ENOSPC); | |
359 | if (addr & (BLOBLIST_ALIGN - 1)) | |
360 | return log_ret(-EFAULT); | |
361 | hdr = map_sysmem(addr, size); | |
362 | memset(hdr, '\0', sizeof(*hdr)); | |
363 | hdr->version = BLOBLIST_VERSION; | |
364 | hdr->hdr_size = sizeof(*hdr); | |
365 | hdr->flags = flags; | |
366 | hdr->magic = BLOBLIST_MAGIC; | |
b86b2d94 SG |
367 | hdr->used_size = hdr->hdr_size; |
368 | hdr->total_size = size; | |
7d790a80 | 369 | hdr->align_log2 = align_log2 ? align_log2 : BLOBLIST_BLOB_ALIGN_LOG2; |
9f407d4e SG |
370 | hdr->chksum = 0; |
371 | gd->bloblist = hdr; | |
372 | ||
373 | return 0; | |
374 | } | |
375 | ||
376 | int bloblist_check(ulong addr, uint size) | |
377 | { | |
378 | struct bloblist_hdr *hdr; | |
379 | u32 chksum; | |
380 | ||
381 | hdr = map_sysmem(addr, sizeof(*hdr)); | |
382 | if (hdr->magic != BLOBLIST_MAGIC) | |
383 | return log_msg_ret("Bad magic", -ENOENT); | |
384 | if (hdr->version != BLOBLIST_VERSION) | |
385 | return log_msg_ret("Bad version", -EPROTONOSUPPORT); | |
67254214 | 386 | if (!hdr->total_size || (size && hdr->total_size > size)) |
b86b2d94 SG |
387 | return log_msg_ret("Bad total size", -EFBIG); |
388 | if (hdr->used_size > hdr->total_size) | |
389 | return log_msg_ret("Bad used size", -ENOENT); | |
390 | if (hdr->hdr_size != sizeof(struct bloblist_hdr)) | |
391 | return log_msg_ret("Bad header size", -ENOENT); | |
392 | ||
9f407d4e SG |
393 | chksum = bloblist_calc_chksum(hdr); |
394 | if (hdr->chksum != chksum) { | |
1d8bbd76 | 395 | log_err("Checksum %x != %x\n", hdr->chksum, chksum); |
9f407d4e SG |
396 | return log_msg_ret("Bad checksum", -EIO); |
397 | } | |
398 | gd->bloblist = hdr; | |
399 | ||
400 | return 0; | |
401 | } | |
402 | ||
403 | int bloblist_finish(void) | |
404 | { | |
405 | struct bloblist_hdr *hdr = gd->bloblist; | |
406 | ||
407 | hdr->chksum = bloblist_calc_chksum(hdr); | |
b86b2d94 | 408 | log_debug("Finished bloblist size %lx at %lx\n", (ulong)hdr->used_size, |
99047f5d | 409 | (ulong)map_to_sysmem(hdr)); |
9f407d4e SG |
410 | |
411 | return 0; | |
412 | } | |
413 | ||
e50a24a0 SG |
414 | ulong bloblist_get_base(void) |
415 | { | |
416 | return map_to_sysmem(gd->bloblist); | |
417 | } | |
418 | ||
419 | ulong bloblist_get_size(void) | |
420 | { | |
421 | struct bloblist_hdr *hdr = gd->bloblist; | |
422 | ||
b86b2d94 SG |
423 | return hdr->used_size; |
424 | } | |
425 | ||
426 | ulong bloblist_get_total_size(void) | |
427 | { | |
428 | struct bloblist_hdr *hdr = gd->bloblist; | |
429 | ||
430 | return hdr->total_size; | |
e50a24a0 SG |
431 | } |
432 | ||
b86b2d94 | 433 | void bloblist_get_stats(ulong *basep, ulong *tsizep, ulong *usizep) |
4aed2276 SG |
434 | { |
435 | struct bloblist_hdr *hdr = gd->bloblist; | |
436 | ||
437 | *basep = map_to_sysmem(gd->bloblist); | |
b86b2d94 SG |
438 | *tsizep = hdr->total_size; |
439 | *usizep = hdr->used_size; | |
4aed2276 SG |
440 | } |
441 | ||
442 | static void show_value(const char *prompt, ulong value) | |
443 | { | |
b86b2d94 | 444 | printf("%s:%*s %-5lx ", prompt, 10 - (int)strlen(prompt), "", value); |
4aed2276 SG |
445 | print_size(value, "\n"); |
446 | } | |
447 | ||
448 | void bloblist_show_stats(void) | |
449 | { | |
b86b2d94 | 450 | ulong base, tsize, usize; |
4aed2276 | 451 | |
b86b2d94 SG |
452 | bloblist_get_stats(&base, &tsize, &usize); |
453 | printf("base: %lx\n", base); | |
454 | show_value("total size", tsize); | |
455 | show_value("used size", usize); | |
456 | show_value("free", tsize - usize); | |
4aed2276 SG |
457 | } |
458 | ||
459 | void bloblist_show_list(void) | |
460 | { | |
461 | struct bloblist_hdr *hdr = gd->bloblist; | |
462 | struct bloblist_rec *rec; | |
463 | ||
f16ec777 | 464 | printf("%-8s %8s Tag Name\n", "Address", "Size"); |
4aed2276 SG |
465 | for (rec = bloblist_first_blob(hdr); rec; |
466 | rec = bloblist_next_blob(hdr, rec)) { | |
f16ec777 | 467 | printf("%08lx %8x %4x %s\n", |
1f06ed41 SG |
468 | (ulong)map_to_sysmem((void *)rec + rec_hdr_size(rec)), |
469 | rec->size, rec_tag(rec), | |
470 | bloblist_tag_name(rec_tag(rec))); | |
4aed2276 SG |
471 | } |
472 | } | |
473 | ||
1ef43f3b | 474 | int bloblist_reloc(void *to, uint to_size) |
9fe06464 SG |
475 | { |
476 | struct bloblist_hdr *hdr; | |
477 | ||
1ef43f3b RM |
478 | if (to_size < gd->bloblist->total_size) |
479 | return -ENOSPC; | |
480 | ||
481 | memcpy(to, gd->bloblist, gd->bloblist->total_size); | |
9fe06464 | 482 | hdr = to; |
b86b2d94 | 483 | hdr->total_size = to_size; |
1ef43f3b RM |
484 | gd->bloblist = to; |
485 | ||
486 | return 0; | |
9fe06464 SG |
487 | } |
488 | ||
66131310 RM |
489 | /* |
490 | * Weak default function for getting bloblist from boot args. | |
491 | */ | |
492 | int __weak xferlist_from_boot_arg(ulong __always_unused addr, | |
493 | ulong __always_unused size) | |
494 | { | |
495 | return -ENOENT; | |
496 | } | |
497 | ||
9f407d4e SG |
498 | int bloblist_init(void) |
499 | { | |
ce3e75dc | 500 | bool fixed = IS_ENABLED(CONFIG_BLOBLIST_FIXED); |
9f407d4e | 501 | int ret = -ENOENT; |
99047f5d | 502 | ulong addr, size; |
66131310 RM |
503 | /* |
504 | * If U-Boot is not in the first phase, an existing bloblist must be | |
505 | * at a fixed address. | |
506 | */ | |
713bfc58 | 507 | bool from_addr = fixed && !xpl_is_first_phase(); |
66131310 RM |
508 | /* |
509 | * If U-Boot is in the first phase that an arch custom routine should | |
510 | * install the bloblist passed from previous loader to this fixed | |
ce3e75dc | 511 | * address. |
9f407d4e | 512 | */ |
713bfc58 | 513 | bool from_boot_arg = fixed && xpl_is_first_phase(); |
66131310 | 514 | |
6c49fc58 | 515 | if (xpl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST)) |
66131310 | 516 | from_addr = false; |
ce3e75dc SG |
517 | if (fixed) |
518 | addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, | |
519 | CONFIG_BLOBLIST_ADDR); | |
99047f5d | 520 | size = CONFIG_BLOBLIST_SIZE; |
66131310 RM |
521 | |
522 | if (from_boot_arg) | |
523 | ret = xferlist_from_boot_arg(addr, size); | |
524 | else if (from_addr) | |
99047f5d | 525 | ret = bloblist_check(addr, size); |
66131310 RM |
526 | |
527 | if (ret) | |
528 | log_warning("Bloblist at %lx not found (err=%d)\n", | |
529 | addr, ret); | |
530 | else | |
531 | /* Get the real size */ | |
532 | size = gd->bloblist->total_size; | |
533 | ||
9f407d4e | 534 | if (ret) { |
66131310 RM |
535 | /* |
536 | * If we don't have a bloblist from a fixed address, or the one | |
537 | * in the fixed address is not valid. we must allocate the | |
538 | * memory for it now. | |
539 | */ | |
99047f5d SG |
540 | if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC)) { |
541 | void *ptr = memalign(BLOBLIST_ALIGN, size); | |
d5b6e91b SG |
542 | |
543 | if (!ptr) | |
544 | return log_msg_ret("alloc", -ENOMEM); | |
545 | addr = map_to_sysmem(ptr); | |
ce3e75dc | 546 | } else if (!fixed) { |
66131310 RM |
547 | return log_msg_ret("BLOBLIST_FIXED is not enabled", |
548 | ret); | |
d5b6e91b | 549 | } |
99047f5d SG |
550 | log_debug("Creating new bloblist size %lx at %lx\n", size, |
551 | addr); | |
7d790a80 | 552 | ret = bloblist_new(addr, size, 0, 0); |
9f407d4e | 553 | } else { |
99047f5d SG |
554 | log_debug("Found existing bloblist size %lx at %lx\n", size, |
555 | addr); | |
9f407d4e | 556 | } |
3d653180 SG |
557 | if (ret) |
558 | return log_msg_ret("ini", ret); | |
559 | gd->flags |= GD_FLG_BLOBLIST_READY; | |
560 | ||
66131310 RM |
561 | #ifdef DEBUG |
562 | bloblist_show_stats(); | |
563 | bloblist_show_list(); | |
564 | #endif | |
565 | ||
3d653180 SG |
566 | return 0; |
567 | } | |
9f407d4e | 568 | |
3d653180 SG |
569 | int bloblist_maybe_init(void) |
570 | { | |
571 | if (CONFIG_IS_ENABLED(BLOBLIST) && !(gd->flags & GD_FLG_BLOBLIST_READY)) | |
572 | return bloblist_init(); | |
573 | ||
574 | return 0; | |
9f407d4e | 575 | } |
1c4751fd RM |
576 | |
577 | int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig) | |
578 | { | |
84ab75fb LY |
579 | ulong version = BLOBLIST_REGCONV_VER; |
580 | ulong sigval; | |
581 | ||
582 | sigval = (IS_ENABLED(CONFIG_64BIT)) ? | |
583 | ((BLOBLIST_MAGIC & ((1UL << BLOBLIST_REGCONV_SHIFT_64) - 1)) | | |
584 | ((version & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_64)) : | |
585 | ((BLOBLIST_MAGIC & ((1UL << BLOBLIST_REGCONV_SHIFT_32) - 1)) | | |
586 | ((version & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_32)); | |
587 | ||
588 | if (rzero || rsig != sigval || | |
1c4751fd RM |
589 | rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) { |
590 | gd->bloblist = NULL; /* Reset the gd bloblist pointer */ | |
591 | return -EIO; | |
592 | } | |
593 | ||
594 | return 0; | |
595 | } |