1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-09-01 08:42:12 +02:00

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>
This commit is contained in:
Simon Glass
2018-11-15 18:43:50 -07:00
committed by Tom Rini
parent 4d8d3056f8
commit 9f407d4ef0
5 changed files with 484 additions and 0 deletions

View File

@@ -750,4 +750,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 if SANDBOX
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"

View File

@@ -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

239
common/bloblist.c Normal file
View File

@@ -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;
}