Commit 9f407d4ef092c2ce7ab0f4f366aee252611dab3c
Committed by
Tom Rini
1 parent
4d8d3056f8
Exists in
smarc_8mq_lf_v2020.04
and in
11 other branches
Add core support for a bloblist to convey data from SPL
At present there is no standard way in U-Boot to pass information from SPL to U-Boot proper. But sometimes SPL wants to convey information to U-Boot that U-Boot cannot easily figure out. For example, if SPL sets up SDRAM then it might want to pass the size of SDRAM, or the location of each bank, to U-Boot proper. Add a new 'bloblist' feature which provides this. A bloblist is set up in the first phase of U-Boot that runs (i.e. TPL or SPL). The location of this info may be in SRAM or CAR (x86 cache-as-RAM) or somewhere else. Information placed in this region is preserved (with a checksum) through TPL and SPL and ends up in U-Boot. At this point it is copied into SDRAM so it can be used after relocation. Reviewed-by: Tom Rini <trini@konsulko.com> Signed-off-by: Simon Glass <sjg@chromium.org> Acked-by: Andreas Dannenberg <dannenberg@ti.com>
Showing 5 changed files with 484 additions and 0 deletions Side-by-side Diff
common/Kconfig
... | ... | @@ -750,5 +750,53 @@ |
750 | 750 | |
751 | 751 | endmenu |
752 | 752 | |
753 | +menu "Blob list" | |
754 | + | |
755 | +config BLOBLIST | |
756 | + bool "Support for a bloblist" | |
757 | + help | |
758 | + This enables support for a bloblist in U-Boot, which can be passed | |
759 | + from TPL to SPL to U-Boot proper (and potentially to Linux). The | |
760 | + blob list supports multiple binary blobs of data, each with a tag, | |
761 | + so that different U-Boot components can store data which can survive | |
762 | + through to the next stage of the boot. | |
763 | + | |
764 | +config SPL_BLOBLIST | |
765 | + bool "Support for a bloblist in SPL" | |
766 | + depends on BLOBLIST | |
767 | + default y if SPL | |
768 | + help | |
769 | + This enables a bloblist in SPL. If this is the first part of U-Boot | |
770 | + to run, then the bloblist is set up in SPL and passed to U-Boot | |
771 | + proper. If TPL also has a bloblist, then SPL uses the one from there. | |
772 | + | |
773 | +config TPL_BLOBLIST | |
774 | + bool "Support for a bloblist in TPL" | |
775 | + depends on BLOBLIST | |
776 | + default y if TPL | |
777 | + help | |
778 | + This enables a bloblist in TPL. The bloblist is set up in TPL and | |
779 | + passed to SPL and U-Boot proper. | |
780 | + | |
781 | +config BLOBLIST_SIZE | |
782 | + hex "Size of bloblist" | |
783 | + depends on BLOBLIST | |
784 | + default 0x400 | |
785 | + help | |
786 | + Sets the size of the bloblist in bytes. This must include all | |
787 | + overhead (alignment, bloblist header, record header). The bloblist | |
788 | + is set up in the first part of U-Boot to run (TPL, SPL or U-Boot | |
789 | + proper), and this sane bloblist is used for subsequent stages. | |
790 | + | |
791 | +config BLOBLIST_ADDR | |
792 | + hex "Address of bloblist" | |
793 | + depends on BLOBLIST | |
794 | + default 0xe000 if SANDBOX | |
795 | + help | |
796 | + Sets the address of the bloblist, set up by the first part of U-Boot | |
797 | + which runs. Subsequent U-Boot stages typically use the same address. | |
798 | + | |
799 | +endmenu | |
800 | + | |
753 | 801 | source "common/spl/Kconfig" |
common/Makefile
common/bloblist.c
1 | +// SPDX-License-Identifier: GPL-2.0+ | |
2 | +/* | |
3 | + * Copyright 2018 Google, Inc | |
4 | + * Written by Simon Glass <sjg@chromium.org> | |
5 | + */ | |
6 | + | |
7 | +#include <common.h> | |
8 | +#include <bloblist.h> | |
9 | +#include <log.h> | |
10 | +#include <mapmem.h> | |
11 | +#include <spl.h> | |
12 | + | |
13 | +DECLARE_GLOBAL_DATA_PTR; | |
14 | + | |
15 | +struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr) | |
16 | +{ | |
17 | + if (hdr->alloced <= hdr->hdr_size) | |
18 | + return NULL; | |
19 | + return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size); | |
20 | +} | |
21 | + | |
22 | +struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr, | |
23 | + struct bloblist_rec *rec) | |
24 | +{ | |
25 | + ulong offset; | |
26 | + | |
27 | + offset = (void *)rec - (void *)hdr; | |
28 | + offset += rec->hdr_size + ALIGN(rec->size, BLOBLIST_ALIGN); | |
29 | + if (offset >= hdr->alloced) | |
30 | + return NULL; | |
31 | + return (struct bloblist_rec *)((void *)hdr + offset); | |
32 | +} | |
33 | + | |
34 | +#define foreach_rec(_rec, _hdr) \ | |
35 | + for (_rec = bloblist_first_blob(_hdr); \ | |
36 | + _rec; \ | |
37 | + _rec = bloblist_next_blob(_hdr, _rec)) | |
38 | + | |
39 | +static struct bloblist_rec *bloblist_findrec(uint tag) | |
40 | +{ | |
41 | + struct bloblist_hdr *hdr = gd->bloblist; | |
42 | + struct bloblist_rec *rec; | |
43 | + | |
44 | + if (!hdr) | |
45 | + return NULL; | |
46 | + | |
47 | + foreach_rec(rec, hdr) { | |
48 | + if (rec->tag == tag) | |
49 | + return rec; | |
50 | + } | |
51 | + | |
52 | + return NULL; | |
53 | +} | |
54 | + | |
55 | +static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp) | |
56 | +{ | |
57 | + struct bloblist_hdr *hdr = gd->bloblist; | |
58 | + struct bloblist_rec *rec; | |
59 | + int new_alloced; | |
60 | + | |
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); | |
68 | + } | |
69 | + rec = (void *)hdr + hdr->alloced; | |
70 | + hdr->alloced = new_alloced; | |
71 | + | |
72 | + rec->tag = tag; | |
73 | + rec->hdr_size = sizeof(*rec); | |
74 | + rec->size = size; | |
75 | + rec->spare = 0; | |
76 | + *recp = rec; | |
77 | + | |
78 | + return 0; | |
79 | +} | |
80 | + | |
81 | +static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size) | |
82 | +{ | |
83 | + struct bloblist_rec *rec; | |
84 | + | |
85 | + rec = bloblist_findrec(tag); | |
86 | + if (rec) { | |
87 | + if (size && size != rec->size) | |
88 | + return -ESPIPE; | |
89 | + } else { | |
90 | + int ret; | |
91 | + | |
92 | + ret = bloblist_addrec(tag, size, &rec); | |
93 | + if (ret) | |
94 | + return ret; | |
95 | + } | |
96 | + *recp = rec; | |
97 | + | |
98 | + return 0; | |
99 | +} | |
100 | + | |
101 | +void *bloblist_find(uint tag, int size) | |
102 | +{ | |
103 | + struct bloblist_rec *rec; | |
104 | + | |
105 | + rec = bloblist_findrec(tag); | |
106 | + if (!rec) | |
107 | + return NULL; | |
108 | + if (size && size != rec->size) | |
109 | + return NULL; | |
110 | + | |
111 | + return (void *)rec + rec->hdr_size; | |
112 | +} | |
113 | + | |
114 | +void *bloblist_add(uint tag, int size) | |
115 | +{ | |
116 | + struct bloblist_rec *rec; | |
117 | + | |
118 | + if (bloblist_addrec(tag, size, &rec)) | |
119 | + return NULL; | |
120 | + | |
121 | + return rec + 1; | |
122 | +} | |
123 | + | |
124 | +int bloblist_ensure_size(uint tag, int size, void **blobp) | |
125 | +{ | |
126 | + struct bloblist_rec *rec; | |
127 | + int ret; | |
128 | + | |
129 | + ret = bloblist_ensurerec(tag, &rec, size); | |
130 | + if (ret) | |
131 | + return ret; | |
132 | + *blobp = (void *)rec + rec->hdr_size; | |
133 | + | |
134 | + return 0; | |
135 | +} | |
136 | + | |
137 | +void *bloblist_ensure(uint tag, int size) | |
138 | +{ | |
139 | + struct bloblist_rec *rec; | |
140 | + | |
141 | + if (bloblist_ensurerec(tag, &rec, size)) | |
142 | + return NULL; | |
143 | + | |
144 | + return (void *)rec + rec->hdr_size; | |
145 | +} | |
146 | + | |
147 | +static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr) | |
148 | +{ | |
149 | + struct bloblist_rec *rec; | |
150 | + u32 chksum; | |
151 | + | |
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); | |
157 | + } | |
158 | + | |
159 | + return chksum; | |
160 | +} | |
161 | + | |
162 | +int bloblist_new(ulong addr, uint size, uint flags) | |
163 | +{ | |
164 | + struct bloblist_hdr *hdr; | |
165 | + | |
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); | |
174 | + hdr->flags = flags; | |
175 | + hdr->magic = BLOBLIST_MAGIC; | |
176 | + hdr->size = size; | |
177 | + hdr->alloced = hdr->hdr_size; | |
178 | + hdr->chksum = 0; | |
179 | + gd->bloblist = hdr; | |
180 | + | |
181 | + return 0; | |
182 | +} | |
183 | + | |
184 | +int bloblist_check(ulong addr, uint size) | |
185 | +{ | |
186 | + struct bloblist_hdr *hdr; | |
187 | + u32 chksum; | |
188 | + | |
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, | |
199 | + chksum); | |
200 | + return log_msg_ret("Bad checksum", -EIO); | |
201 | + } | |
202 | + gd->bloblist = hdr; | |
203 | + | |
204 | + return 0; | |
205 | +} | |
206 | + | |
207 | +int bloblist_finish(void) | |
208 | +{ | |
209 | + struct bloblist_hdr *hdr = gd->bloblist; | |
210 | + | |
211 | + hdr->chksum = bloblist_calc_chksum(hdr); | |
212 | + | |
213 | + return 0; | |
214 | +} | |
215 | + | |
216 | +int bloblist_init(void) | |
217 | +{ | |
218 | + bool expected; | |
219 | + int ret = -ENOENT; | |
220 | + | |
221 | + /** | |
222 | + * Wed expect to find an existing bloblist in the first phase of U-Boot | |
223 | + * that runs | |
224 | + */ | |
225 | + expected = !u_boot_first_phase(); | |
226 | + if (expected) | |
227 | + ret = bloblist_check(CONFIG_BLOBLIST_ADDR, | |
228 | + CONFIG_BLOBLIST_SIZE); | |
229 | + if (ret) { | |
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, | |
233 | + 0); | |
234 | + } else { | |
235 | + log(LOGC_BLOBLIST, LOGL_DEBUG, "Found existing bloblist\n"); | |
236 | + } | |
237 | + | |
238 | + return ret; | |
239 | +} |
include/bloblist.h
1 | +/* SPDX-License-Identifier: GPL-2.0+ */ | |
2 | +/* | |
3 | + * This provides a standard way of passing information between boot phases | |
4 | + * (TPL -> SPL -> U-Boot proper.) | |
5 | + * | |
6 | + * A list of blobs of data, tagged with their owner. The list resides in memory | |
7 | + * and can be updated by SPL, U-Boot, etc. | |
8 | + * | |
9 | + * Copyright 2018 Google, Inc | |
10 | + * Written by Simon Glass <sjg@chromium.org> | |
11 | + */ | |
12 | + | |
13 | +#ifndef __BLOBLIST_H | |
14 | +#define __BLOBLIST_H | |
15 | + | |
16 | +enum { | |
17 | + BLOBLIST_VERSION = 0, | |
18 | + BLOBLIST_MAGIC = 0xb00757a3, | |
19 | + BLOBLIST_ALIGN = 16, | |
20 | +}; | |
21 | + | |
22 | +enum bloblist_tag_t { | |
23 | + BLOBLISTT_NONE = 0, | |
24 | + | |
25 | + /* Vendor-specific tags are permitted here */ | |
26 | + BLOBLISTT_EC_HOSTEVENT, /* Chromium OS EC host-event mask */ | |
27 | + BLOBLISTT_SPL_HANDOFF, /* Hand-off info from SPL */ | |
28 | + BLOBLISTT_VBOOT_CTX, /* Chromium OS verified boot context */ | |
29 | + BLOBLISTT_VBOOT_HANDOFF, /* Chromium OS internal handoff info */ | |
30 | +}; | |
31 | + | |
32 | +/** | |
33 | + * struct bloblist_hdr - header for the bloblist | |
34 | + * | |
35 | + * This is stored at the start of the bloblist which is always on a 16-byte | |
36 | + * boundary. Records follow this header. The bloblist normally stays in the | |
37 | + * same place in memory as SPL and U-Boot execute, but it can be safely moved | |
38 | + * around. | |
39 | + * | |
40 | + * None of the bloblist structures contain pointers but it is possible to put | |
41 | + * pointers inside a bloblist record if desired. This is not encouraged, | |
42 | + * since it can make part of the bloblist inaccessible if the pointer is | |
43 | + * no-longer valid. It is better to just store all the data inside a bloblist | |
44 | + * record. | |
45 | + * | |
46 | + * Each bloblist record is aligned to a 16-byte boundary and follows immediately | |
47 | + * from the last. | |
48 | + * | |
49 | + * @version: BLOBLIST_VERSION | |
50 | + * @hdr_size: Size of this header, normally sizeof(struct bloblist_hdr). The | |
51 | + * first bloblist_rec starts at this offset from the start of the header | |
52 | + * @flags: Space for BLOBLISTF_... flags (none yet) | |
53 | + * @magic: BLOBLIST_MAGIC | |
54 | + * @size: Total size of all records (non-zero if valid) including this header. | |
55 | + * The bloblist extends for this many bytes from the start of this header. | |
56 | + * @alloced: Total size allocated for this bloblist. When adding new records, | |
57 | + * the bloblist can grow up to this size. This starts out as | |
58 | + * sizeof(bloblist_hdr) since we need at least that much space to store a | |
59 | + * valid bloblist | |
60 | + * @spare: Space space | |
61 | + * @chksum: CRC32 for the entire bloblist allocated area. Since any of the | |
62 | + * blobs can be altered after being created, this checksum is only valid | |
63 | + * when the bloblist is finalised before jumping to the next stage of boot. | |
64 | + * Note: @chksum is last to make it easier to exclude it from the checksum | |
65 | + * calculation. | |
66 | + */ | |
67 | +struct bloblist_hdr { | |
68 | + u32 version; | |
69 | + u32 hdr_size; | |
70 | + u32 flags; | |
71 | + u32 magic; | |
72 | + | |
73 | + u32 size; | |
74 | + u32 alloced; | |
75 | + u32 spare; | |
76 | + u32 chksum; | |
77 | +}; | |
78 | + | |
79 | +/** | |
80 | + * struct bloblist_rec - record for the bloblist | |
81 | + * | |
82 | + * NOTE: Only exported for testing purposes. Do not use this struct. | |
83 | + * | |
84 | + * The bloblist contains a number of records each consisting of this record | |
85 | + * structure followed by the data contained. Each records is 16-byte aligned. | |
86 | + * | |
87 | + * @tag: Tag indicating what the record contains | |
88 | + * @hdr_size: Size of this header, normally sizeof(struct bloblist_rec). The | |
89 | + * record's data starts at this offset from the start of the record | |
90 | + * @size: Size of record in bytes, excluding the header size. This does not | |
91 | + * need to be aligned (e.g. 3 is OK). | |
92 | + * @spare: Spare space for other things | |
93 | + */ | |
94 | +struct bloblist_rec { | |
95 | + u32 tag; | |
96 | + u32 hdr_size; | |
97 | + u32 size; | |
98 | + u32 spare; | |
99 | +}; | |
100 | + | |
101 | +/** | |
102 | + * bloblist_find() - Find a blob | |
103 | + * | |
104 | + * Searches the bloblist and returns the blob with the matching tag | |
105 | + * | |
106 | + * @tag: Tag to search for (enum bloblist_tag_t) | |
107 | + * @size: Expected size of the blob | |
108 | + * @return pointer to blob if found, or NULL if not found, or a blob was found | |
109 | + * but it is the wrong size | |
110 | + */ | |
111 | +void *bloblist_find(uint tag, int size); | |
112 | + | |
113 | +/** | |
114 | + * bloblist_add() - Add a new blob | |
115 | + * | |
116 | + * Add a new blob to the bloblist | |
117 | + * | |
118 | + * This should only be called if you konw there is no existing blob for a | |
119 | + * particular tag. It is typically safe to call in the first phase of U-Boot | |
120 | + * (e.g. TPL or SPL). After that, bloblist_ensure() should be used instead. | |
121 | + * | |
122 | + * @tag: Tag to add (enum bloblist_tag_t) | |
123 | + * @size: Size of the blob | |
124 | + * @return pointer to the newly added block, or NULL if there is not enough | |
125 | + * space for the blob | |
126 | + */ | |
127 | +void *bloblist_add(uint tag, int size); | |
128 | + | |
129 | +/** | |
130 | + * bloblist_ensure_size() - Find or add a blob | |
131 | + * | |
132 | + * Find an existing blob, or add a new one if not found | |
133 | + * | |
134 | + * @tag: Tag to add (enum bloblist_tag_t) | |
135 | + * @size: Size of the blob | |
136 | + * @blobp: Returns a pointer to blob on success | |
137 | + * @return 0 if OK, -ENOSPC if it is missing and could not be added due to lack | |
138 | + * of space, or -ESPIPE it exists but has the wrong size | |
139 | + */ | |
140 | +int bloblist_ensure_size(uint tag, int size, void **blobp); | |
141 | + | |
142 | +/** | |
143 | + * bloblist_ensure() - Find or add a blob | |
144 | + * | |
145 | + * Find an existing blob, or add a new one if not found | |
146 | + * | |
147 | + * @tag: Tag to add (enum bloblist_tag_t) | |
148 | + * @size: Size of the blob | |
149 | + * @return pointer to blob, or NULL if it is missing and could not be added due | |
150 | + * to lack of space, or it exists but has the wrong size | |
151 | + */ | |
152 | +void *bloblist_ensure(uint tag, int size); | |
153 | + | |
154 | +/** | |
155 | + * bloblist_new() - Create a new, empty bloblist of a given size | |
156 | + * | |
157 | + * @addr: Address of bloblist | |
158 | + * @size: Initial size for bloblist | |
159 | + * @flags: Flags to use for bloblist | |
160 | + * @return 0 if OK, -EFAULT if addr is not aligned correctly, -ENOSPC is the | |
161 | + * area is not large enough | |
162 | + */ | |
163 | +int bloblist_new(ulong addr, uint size, uint flags); | |
164 | + | |
165 | +/** | |
166 | + * bloblist_check() - Check if a bloblist exists | |
167 | + * | |
168 | + * @addr: Address of bloblist | |
169 | + * @size: Expected size of blobsize, or 0 to detect the size | |
170 | + * @return 0 if OK, -ENOENT if the magic number doesn't match (indicating that | |
171 | + * there problem is no bloblist at the given address), -EPROTONOSUPPORT | |
172 | + * if the version does not match, -EIO if the checksum does not match, | |
173 | + * -EFBIG if the expected size does not match the detected size | |
174 | + */ | |
175 | +int bloblist_check(ulong addr, uint size); | |
176 | + | |
177 | +/** | |
178 | + * bloblist_finish() - Set up the bloblist for the next U-Boot part | |
179 | + * | |
180 | + * This sets the correct checksum for the bloblist. This ensures that the | |
181 | + * bloblist will be detected correctly by the next phase of U-Boot. | |
182 | + * | |
183 | + * @return 0 | |
184 | + */ | |
185 | +int bloblist_finish(void); | |
186 | + | |
187 | +/** | |
188 | + * bloblist_init() - Init the bloblist system with a single bloblist | |
189 | + * | |
190 | + * This uses CONFIG_BLOBLIST_ADDR and CONFIG_BLOBLIST_SIZE to set up a bloblist | |
191 | + * for use by U-Boot. | |
192 | + */ | |
193 | +int bloblist_init(void); | |
194 | + | |
195 | +#endif /* __BLOBLIST_H */ |
include/log.h
... | ... | @@ -48,6 +48,7 @@ |
48 | 48 | LOGC_EFI, /* EFI implementation */ |
49 | 49 | LOGC_ALLOC, /* Memory allocation */ |
50 | 50 | LOGC_SANDBOX, /* Related to the sandbox board */ |
51 | + LOGC_BLOBLIST, /* Bloblist */ | |
51 | 52 | |
52 | 53 | LOGC_COUNT, /* Number of log categories */ |
53 | 54 | LOGC_END, /* Sentinel value for a list of log categories */ |