Commit 9f407d4ef092c2ce7ab0f4f366aee252611dab3c

Authored by Simon Glass
Committed by Tom Rini
1 parent 4d8d3056f8

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

... ... @@ -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"
... ... @@ -61,6 +61,7 @@
61 61 endif # !CONFIG_SPL_BUILD
62 62  
63 63 obj-$(CONFIG_$(SPL_TPL_)BOOTSTAGE) += bootstage.o
  64 +obj-$(CONFIG_$(SPL_TPL_)BLOBLIST) += bloblist.o
64 65  
65 66 ifdef CONFIG_SPL_BUILD
66 67 ifdef CONFIG_SPL_DFU_SUPPORT
  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 +}
  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 */
... ... @@ -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 */