
Hi Kever,
On 7 October 2018 at 20:42, Kever Yang kever.yang@rock-chips.com wrote:
Hi Simon,
I didn't notice you already have a V2 for this patch set just now
and have send a reply to V1.
My question is: Is it possible to use ATAGs instead of a new 'bloblist'?
I thought that was a way of passing things to the kernel, and was dropped in favour of device tree? Also, it is ARM only, right?
Regards, Simon
Thanks,
- Kever
On 10/02/2018 07:22 PM, Simon Glass wrote:
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.
Signed-off-by: Simon Glass sjg@chromium.org Acked-by: Andreas Dannenberg dannenberg@ti.com
Changes in v2:
- Fix several typos
common/Kconfig | 48 +++++++++ common/Makefile | 1 + common/bloblist.c | 239 +++++++++++++++++++++++++++++++++++++++++++++ include/bloblist.h | 195 ++++++++++++++++++++++++++++++++++++ include/log.h | 1 + 5 files changed, 484 insertions(+) create mode 100644 common/bloblist.c create mode 100644 include/bloblist.h
diff --git a/common/Kconfig b/common/Kconfig index 3bb9571b710..2e72b3c83c6 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -715,4 +715,52 @@ config UPDATE_TFTP_MSEC_MAX
endmenu
+menu "Blob list"
+config BLOBLIST
bool "Support for a bloblist"
help
This enables support for a bloblist in U-Boot, which can be
passed
from TPL to SPL to U-Boot proper (and potentially to Linux). The
blob list supports multiple binary blobs of data, each with a
tag,
so that different U-Boot components can store data which can
survive
through to the next stage of the boot.
+config SPL_BLOBLIST
bool "Support for a bloblist in SPL"
depends on BLOBLIST
default y if SPL
help
This enables a bloblist in SPL. If this is the first part of
U-Boot
to run, then the bloblist is set up in SPL and passed to U-Boot
proper. If TPL also has a bloblist, then SPL uses the one from
there.
+config TPL_BLOBLIST
bool "Support for a bloblist in TPL"
depends on BLOBLIST
default y if TPL
help
This enables a bloblist in TPL. The bloblist is set up in TPL and
passed to SPL and U-Boot proper.
+config BLOBLIST_SIZE
hex "Size of bloblist"
depends on BLOBLIST
default 0x400
help
Sets the size of the bloblist in bytes. This must include all
overhead (alignment, bloblist header, record header). The
bloblist
is set up in the first part of U-Boot to run (TPL, SPL or U-Boot
proper), and this sane bloblist is used for subsequent stages.
+config BLOBLIST_ADDR
hex "Address of bloblist"
depends on BLOBLIST
default 0xe000
help
Sets the address of the bloblist, set up by the first part of
U-Boot
which runs. Subsequent U-Boot stages typically use the same
address.
+endmenu
source "common/spl/Kconfig" diff --git a/common/Makefile b/common/Makefile index cbca4ff2da6..6aff2b1a6e3 100644 --- a/common/Makefile +++ b/common/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_CMDLINE) += cli_readline.o cli_simple.o endif # !CONFIG_SPL_BUILD
obj-$(CONFIG_$(SPL_TPL_)BOOTSTAGE) += bootstage.o +obj-$(CONFIG_$(SPL_TPL_)BLOBLIST) += bloblist.o
ifdef CONFIG_SPL_BUILD ifdef CONFIG_SPL_DFU_SUPPORT diff --git a/common/bloblist.c b/common/bloblist.c new file mode 100644 index 00000000000..b4cf169b05a --- /dev/null +++ b/common/bloblist.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright 2018 Google, Inc
- Written by Simon Glass sjg@chromium.org
- */
+#include <common.h> +#include <bloblist.h> +#include <log.h> +#include <mapmem.h> +#include <spl.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr) +{
if (hdr->alloced <= hdr->hdr_size)
return NULL;
return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size);
+}
+struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
struct bloblist_rec *rec)
+{
ulong offset;
offset = (void *)rec - (void *)hdr;
offset += rec->hdr_size + ALIGN(rec->size, BLOBLIST_ALIGN);
if (offset >= hdr->alloced)
return NULL;
return (struct bloblist_rec *)((void *)hdr + offset);
+}
+#define foreach_rec(_rec, _hdr) \
for (_rec = bloblist_first_blob(_hdr); \
_rec; \
_rec = bloblist_next_blob(_hdr, _rec))
+static struct bloblist_rec *bloblist_findrec(uint tag) +{
struct bloblist_hdr *hdr = gd->bloblist;
struct bloblist_rec *rec;
if (!hdr)
return NULL;
foreach_rec(rec, hdr) {
if (rec->tag == tag)
return rec;
}
return NULL;
+}
+static int bloblist_addrec(uint tag, int size, struct bloblist_rec
**recp)
+{
struct bloblist_hdr *hdr = gd->bloblist;
struct bloblist_rec *rec;
int new_alloced;
new_alloced = hdr->alloced + sizeof(*rec) +
ALIGN(size, BLOBLIST_ALIGN);
if (new_alloced >= hdr->size) {
log(LOGC_BLOBLIST, LOGL_ERR,
"Failed to allocate %x bytes size=%x, need size>=%x\n",
size, hdr->size, new_alloced);
return log_msg_ret("bloblist add", -ENOSPC);
}
rec = (void *)hdr + hdr->alloced;
hdr->alloced = new_alloced;
rec->tag = tag;
rec->hdr_size = sizeof(*rec);
rec->size = size;
rec->spare = 0;
*recp = rec;
return 0;
+}
+static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int
size)
+{
struct bloblist_rec *rec;
rec = bloblist_findrec(tag);
if (rec) {
if (size && size != rec->size)
return -ESPIPE;
} else {
int ret;
ret = bloblist_addrec(tag, size, &rec);
if (ret)
return ret;
}
*recp = rec;
return 0;
+}
+void *bloblist_find(uint tag, int size) +{
struct bloblist_rec *rec;
rec = bloblist_findrec(tag);
if (!rec)
return NULL;
if (size && size != rec->size)
return NULL;
return (void *)rec + rec->hdr_size;
+}
+void *bloblist_add(uint tag, int size) +{
struct bloblist_rec *rec;
if (bloblist_addrec(tag, size, &rec))
return NULL;
return rec + 1;
+}
+int bloblist_ensure_size(uint tag, int size, void **blobp) +{
struct bloblist_rec *rec;
int ret;
ret = bloblist_ensurerec(tag, &rec, size);
if (ret)
return ret;
*blobp = (void *)rec + rec->hdr_size;
return 0;
+}
+void *bloblist_ensure(uint tag, int size) +{
struct bloblist_rec *rec;
if (bloblist_ensurerec(tag, &rec, size))
return NULL;
return (void *)rec + rec->hdr_size;
+}
+static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr) +{
struct bloblist_rec *rec;
u32 chksum;
chksum = crc32(0, (unsigned char *)hdr,
offsetof(struct bloblist_hdr, chksum));
foreach_rec(rec, hdr) {
chksum = crc32(chksum, (void *)rec, rec->hdr_size);
chksum = crc32(chksum, (void *)rec + rec->hdr_size,
rec->size);
}
return chksum;
+}
+int bloblist_new(ulong addr, uint size, uint flags) +{
struct bloblist_hdr *hdr;
if (size < sizeof(*hdr))
return log_ret(-ENOSPC);
if (addr & (BLOBLIST_ALIGN - 1))
return log_ret(-EFAULT);
hdr = map_sysmem(addr, size);
memset(hdr, '\0', sizeof(*hdr));
hdr->version = BLOBLIST_VERSION;
hdr->hdr_size = sizeof(*hdr);
hdr->flags = flags;
hdr->magic = BLOBLIST_MAGIC;
hdr->size = size;
hdr->alloced = hdr->hdr_size;
hdr->chksum = 0;
gd->bloblist = hdr;
return 0;
+}
+int bloblist_check(ulong addr, uint size) +{
struct bloblist_hdr *hdr;
u32 chksum;
hdr = map_sysmem(addr, sizeof(*hdr));
if (hdr->magic != BLOBLIST_MAGIC)
return log_msg_ret("Bad magic", -ENOENT);
if (hdr->version != BLOBLIST_VERSION)
return log_msg_ret("Bad version", -EPROTONOSUPPORT);
if (size && hdr->size != size)
return log_msg_ret("Bad size", -EFBIG);
chksum = bloblist_calc_chksum(hdr);
if (hdr->chksum != chksum) {
log(LOGC_BLOBLIST, LOGL_ERR, "Checksum %x != %x\n",
hdr->chksum,
chksum);
return log_msg_ret("Bad checksum", -EIO);
}
gd->bloblist = hdr;
return 0;
+}
+int bloblist_finish(void) +{
struct bloblist_hdr *hdr = gd->bloblist;
hdr->chksum = bloblist_calc_chksum(hdr);
return 0;
+}
+int bloblist_init(void) +{
bool expected;
int ret = -ENOENT;
/**
* Wed expect to find an existing bloblist in the first phase of
U-Boot
* that runs
*/
expected = !u_boot_first_phase();
if (expected)
ret = bloblist_check(CONFIG_BLOBLIST_ADDR,
CONFIG_BLOBLIST_SIZE);
if (ret) {
log(LOGC_BLOBLIST, expected ? LOGL_WARNING : LOGL_DEBUG,
"Existing bloblist not found: creating new
bloblist\n");
ret = bloblist_new(CONFIG_BLOBLIST_ADDR,
CONFIG_BLOBLIST_SIZE,
0);
} else {
log(LOGC_BLOBLIST, LOGL_DEBUG, "Found existing
bloblist\n");
}
return ret;
+} diff --git a/include/bloblist.h b/include/bloblist.h new file mode 100644 index 00000000000..413736a9080 --- /dev/null +++ b/include/bloblist.h @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- This provides a standard way of passing information between boot
phases
- (TPL -> SPL -> U-Boot proper.)
- A list of blobs of data, tagged with their owner. The list resides
in memory
- and can be updated by SPL, U-Boot, etc.
- Copyright 2018 Google, Inc
- Written by Simon Glass sjg@chromium.org
- */
+#ifndef __BLOBLIST_H +#define __BLOBLIST_H
+enum {
BLOBLIST_VERSION = 0,
BLOBLIST_MAGIC = 0xb00757a3,
BLOBLIST_ALIGN = 16,
+};
+enum bloblist_tag_t {
BLOBLISTT_NONE = 0,
/* Vendor-specific tags are permitted here */
BLOBLISTT_EC_HOSTEVENT, /* Chromium OS EC host-event mask
*/
BLOBLISTT_SPL_HANDOFF, /* Hand-off info from SPL */
BLOBLISTT_VBOOT_CTX, /* Chromium OS verified boot
context */
BLOBLISTT_VBOOT_HANDOFF, /* Chromium OS internal handoff
info */
+};
+/**
- struct bloblist_hdr - header for the bloblist
- This is stored at the start of the bloblist which is always on a
16-byte
- boundary. Records follow this header. The bloblist normally stays in
the
- same place in memory as SPL and U-Boot execute, but it can be safely
moved
- around.
- None of the bloblist structures contain pointers but it is possible
to put
- pointers inside a bloblist record if desired. This is not encouraged,
- since it can make part of the bloblist inaccessible if the pointer is
- no-longer valid. It is better to just store all the data inside a
bloblist
- record.
- Each bloblist record is aligned to a 16-byte boundary and follows
immediately
- from the last.
- @version: BLOBLIST_VERSION
- @hdr_size: Size of this header, normally sizeof(struct
bloblist_hdr). The
- first bloblist_rec starts at this offset from the start of the
header
- @flags: Space for BLOBLISTF_... flags (none yet)
- @magic: BLOBLIST_MAGIC
- @size: Total size of all records (non-zero if valid) including this
header.
- The bloblist extends for this many bytes from the start of this
header.
- @alloced: Total size allocated for this bloblist. When adding new
records,
- the bloblist can grow up to this size. This starts out as
- sizeof(bloblist_hdr) since we need at least that much space to
store a
- valid bloblist
- @spare: Space space
- @chksum: CRC32 for the entire bloblist allocated area. Since any of
the
- blobs can be altered after being created, this checksum is only
valid
- when the bloblist is finalised before jumping to the next stage of
boot.
- Note: @chksum is last to make it easier to exclude it from the
checksum
- calculation.
- */
+struct bloblist_hdr {
u32 version;
u32 hdr_size;
u32 flags;
u32 magic;
u32 size;
u32 alloced;
u32 spare;
u32 chksum;
+};
+/**
- struct bloblist_rec - record for the bloblist
- NOTE: Only exported for testing purposes. Do not use this struct.
- The bloblist contains a number of records each consisting of this
record
- structure followed by the data contained. Each records is 16-byte
aligned.
- @tag: Tag indicating what the record contains
- @hdr_size: Size of this header, normally sizeof(struct
bloblist_rec). The
- record's data starts at this offset from the start of the record
- @size: Size of record in bytes, excluding the header size. This does
not
- need to be aligned (e.g. 3 is OK).
- @spare: Spare space for other things
- */
+struct bloblist_rec {
u32 tag;
u32 hdr_size;
u32 size;
u32 spare;
+};
+/**
- bloblist_find() - Find a blob
- Searches the bloblist and returns the blob with the matching tag
- @tag: Tag to search for (enum bloblist_tag_t)
- @size: Expected size of the blob
- @return pointer to blob if found, or NULL if not found, or a blob
was found
- but it is the wrong size
- */
+void *bloblist_find(uint tag, int size);
+/**
- bloblist_add() - Add a new blob
- Add a new blob to the bloblist
- This should only be called if you konw there is no existing blob for
a
- particular tag. It is typically safe to call in the first phase of
U-Boot
- (e.g. TPL or SPL). After that, bloblist_ensure() should be used
instead.
- @tag: Tag to add (enum bloblist_tag_t)
- @size: Size of the blob
- @return pointer to the newly added block, or NULL if there is not
enough
- space for the blob
- */
+void *bloblist_add(uint tag, int size);
+/**
- bloblist_ensure_size() - Find or add a blob
- Find an existing blob, or add a new one if not found
- @tag: Tag to add (enum bloblist_tag_t)
- @size: Size of the blob
- @blobp: Returns a pointer to blob on success
- @return 0 if OK, -ENOSPC if it is missing and could not be added due
to lack
- of space, or -ESPIPE it exists but has the wrong size
- */
+int bloblist_ensure_size(uint tag, int size, void **blobp);
+/**
- bloblist_ensure() - Find or add a blob
- Find an existing blob, or add a new one if not found
- @tag: Tag to add (enum bloblist_tag_t)
- @size: Size of the blob
- @return pointer to blob, or NULL if it is missing and could not be
added due
- to lack of space, or it exists but has the wrong size
- */
+void *bloblist_ensure(uint tag, int size);
+/**
- bloblist_new() - Create a new, empty bloblist of a given size
- @addr: Address of bloblist
- @size: Initial size for bloblist
- @flags: Flags to use for bloblist
- @return 0 if OK, -EFAULT if addr is not aligned correctly, -ENOSPC
is the
- area is not large enough
- */
+int bloblist_new(ulong addr, uint size, uint flags);
+/**
- bloblist_check() - Check if a bloblist exists
- @addr: Address of bloblist
- @size: Expected size of blobsize, or 0 to detect the size
- @return 0 if OK, -ENOENT if the magic number doesn't match
(indicating that
- there problem is no bloblist at the given address),
-EPROTONOSUPPORT
- if the version does not match, -EIO if the checksum does not match,
- -EFBIG if the expected size does not match the detected size
- */
+int bloblist_check(ulong addr, uint size);
+/**
- bloblist_finish() - Set up the bloblist for the next U-Boot part
- This sets the correct checksum for the bloblist. This ensures that
the
- bloblist will be detected correctly by the next phase of U-Boot.
- @return 0
- */
+int bloblist_finish(void);
+/**
- bloblist_init() - Init the bloblist system with a single bloblist
- This uses CONFIG_BLOBLIST_ADDR and CONFIG_BLOBLIST_SIZE to set up a
bloblist
- for use by U-Boot.
- */
+int bloblist_init(void);
+#endif /* __BLOBLIST_H */ diff --git a/include/log.h b/include/log.h index 1146f423a7a..61411b72eac 100644 --- a/include/log.h +++ b/include/log.h @@ -46,6 +46,7 @@ enum log_category_t { LOGC_DM, /* Core driver-model */ LOGC_DT, /* Device-tree */ LOGC_EFI, /* EFI implementation */
LOGC_BLOBLIST, /* Bloblist */ LOGC_COUNT, LOGC_END,