Julius Werner (jwerner(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16271
-gerrit
commit 82a286b17f636317fd7f356f39cf84c588825887
Author: Julius Werner <jwerner(a)chromium.org>
Date: Fri Aug 19 15:24:54 2016 -0700
commonlib: cbfs: Add CBFS attribute support
This patch adds support for the CBFS attributes that were already
introduced in cbfstool and libpayload. I'm only copy&pasting the header
definitions needed for this once more. Really, we should be unifying the
definitions (and possibly part of the code) from cbfstool with
commonlib, but apparently that hadn't been done when this feature was
introduced and I don't really have time to do it cleanly now.
Also add a function to extract info from the compression attribute,
which can then be used to run cbfs_load_and_decompress() on the file.
Change-Id: I7b6463597757122cfe84f006c946a1658bb3acc6
Signed-off-by: Julius Werner <jwerner(a)chromium.org>
---
src/commonlib/cbfs.c | 48 ++++++++++++++++++++++
src/commonlib/include/commonlib/cbfs.h | 17 ++++++++
src/commonlib/include/commonlib/cbfs_serialized.h | 49 ++++++++++++++++++++++-
3 files changed, 113 insertions(+), 1 deletion(-)
diff --git a/src/commonlib/cbfs.c b/src/commonlib/cbfs.c
index 56faf28..8e83101 100644
--- a/src/commonlib/cbfs.c
+++ b/src/commonlib/cbfs.c
@@ -108,6 +108,54 @@ int cbfs_for_each_file(const struct region_device *cbfs,
return -1;
}
+size_t cbfs_for_each_attr(void *metadata, size_t metadata_size,
+ size_t last_offset)
+{
+ struct cbfs_file_attribute *attr;
+
+ if (!last_offset) {
+ struct cbfs_file *file = metadata;
+ size_t start_offset = read_be32(&file->attributes_offset);
+ if (start_offset <= sizeof(struct cbfs_file) ||
+ start_offset + sizeof(*attr) > metadata_size)
+ return 0;
+ return start_offset;
+ }
+
+ attr = metadata + last_offset;
+ size_t next_offset = last_offset + read_be32(&attr->len);
+
+ if (next_offset + sizeof(*attr) > metadata_size)
+ return 0;
+ return next_offset;
+}
+
+int cbfsf_decompression_info(struct cbfsf *fh, uint32_t *algo, size_t *size)
+{
+ size_t metadata_size = region_device_sz(&fh->metadata);
+ void *metadata = rdev_mmap(&fh->metadata, 0, metadata_size);
+ size_t offs = 0;
+
+ if (!metadata)
+ return -1;
+
+ while ((offs = cbfs_for_each_attr(metadata, metadata_size, offs))) {
+ struct cbfs_file_attr_compression *attr = metadata + offs;
+ if (read_be32(&attr->tag) != CBFS_FILE_ATTR_TAG_COMPRESSION)
+ continue;
+
+ *algo = read_be32(&attr->compression);
+ *size = read_be32(&attr->decompressed_size);
+ rdev_munmap(&fh->metadata, metadata);
+ return 0;
+ }
+
+ *algo = CBFS_COMPRESS_NONE;
+ *size = region_device_sz(&fh->data);
+ rdev_munmap(&fh->metadata, metadata);
+ return 0;
+}
+
static int cbfsf_file_type(struct cbfsf *fh, uint32_t *ftype)
{
const size_t sz = sizeof(*ftype);
diff --git a/src/commonlib/include/commonlib/cbfs.h b/src/commonlib/include/commonlib/cbfs.h
index c74dd70..5e511a7 100644
--- a/src/commonlib/include/commonlib/cbfs.h
+++ b/src/commonlib/include/commonlib/cbfs.h
@@ -56,6 +56,23 @@ int cbfs_for_each_file(const struct region_device *cbfs,
const struct cbfsf *prev, struct cbfsf *fh);
/*
+ * Return the offset for each CBFS attribute in a CBFS file metadata region.
+ * The metadata must already be fully mapped by the caller. Will return the
+ * offset (relative to the start of the metadata) or 0 when there are no
+ * further attributes. Should be called with 0 to begin, then always with
+ * the previously returned value until it returns 0.
+ */
+size_t cbfs_for_each_attr(void *metadata, size_t metadata_size,
+ size_t last_offset);
+
+/*
+ * Find out the decompression algorithm and decompressed size of a non-stage
+ * CBFS file (by parsing its metadata attributes), and return them with
+ * out-parameters. Returns 0 on success and < 0 on error.
+ */
+int cbfsf_decompression_info(struct cbfsf *fh, uint32_t *algo, size_t *size);
+
+/*
* Perform the vb2 hash over the CBFS region skipping empty file contents.
* Caller is responsible for providing the hash algorithm as well as storage
* for the final digest. Return 0 on success or non-zero on error.
diff --git a/src/commonlib/include/commonlib/cbfs_serialized.h b/src/commonlib/include/commonlib/cbfs_serialized.h
index c01ba1a..1e394d2 100644
--- a/src/commonlib/include/commonlib/cbfs_serialized.h
+++ b/src/commonlib/include/commonlib/cbfs_serialized.h
@@ -133,10 +133,57 @@ struct cbfs_file {
char magic[8];
uint32_t len;
uint32_t type;
- uint32_t checksum;
+ uint32_t attributes_offset;
uint32_t offset;
} __attribute__((packed));
+/* The common fields of extended cbfs file attributes.
+ Attributes are expected to start with tag/len, then append their
+ specific fields. */
+struct cbfs_file_attribute {
+ uint32_t tag;
+ /* len covers the whole structure, incl. tag and len */
+ uint32_t len;
+ uint8_t data[0];
+} __attribute__((packed));
+
+/* Depending on how the header was initialized, it may be backed with 0x00 or
+ * 0xff. Support both. */
+#define CBFS_FILE_ATTR_TAG_UNUSED 0
+#define CBFS_FILE_ATTR_TAG_UNUSED2 0xffffffff
+#define CBFS_FILE_ATTR_TAG_COMPRESSION 0x42435a4c
+#define CBFS_FILE_ATTR_TAG_HASH 0x68736148
+#define CBFS_FILE_ATTR_TAG_POSITION 0x42435350 /* PSCB */
+#define CBFS_FILE_ATTR_TAG_ALIGNMENT 0x42434c41 /* ALCB */
+
+struct cbfs_file_attr_compression {
+ uint32_t tag;
+ uint32_t len;
+ /* whole file compression format. 0 if no compression. */
+ uint32_t compression;
+ uint32_t decompressed_size;
+} __attribute__((packed));
+
+struct cbfs_file_attr_hash {
+ uint32_t tag;
+ uint32_t len;
+ uint32_t hash_type;
+ /* hash_data is len - sizeof(struct) bytes */
+ uint8_t hash_data[];
+} __attribute__((packed));
+
+struct cbfs_file_attr_position {
+ uint32_t tag;
+ uint32_t len;
+ uint32_t position;
+} __attribute__((packed));
+
+struct cbfs_file_attr_align {
+ uint32_t tag;
+ uint32_t len;
+ uint32_t alignment;
+} __attribute__((packed));
+
/*
* ROMCC does not understand uint64_t, so we hide future definitions as they are
* unlikely to be ever needed from ROMCC
Julius Werner (jwerner(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16272
-gerrit
commit 89e0a8bd5ef13c7a8d57f88b7c0d86d9415ee7f0
Author: Julius Werner <jwerner(a)chromium.org>
Date: Fri Aug 19 15:43:06 2016 -0700
cbfs: Add "struct" file type and associated helpers
This patch adds functionality to compile a C data structure into a raw
binary file, add it to CBFS and allow coreboot to load it at runtime.
This is useful in all cases where we need to be able to have several
larger data sets available in an image, but will only require a small
subset of them at boot (a classic example would be DRAM parameters) or
only require it in certain boot modes. This allows us to load less data
from flash and increase boot speed compared to solutions that compile
all data sets into a stage.
Each structure has to be defined in a separate .c file which contains no
functions and only a single global variable. The data type must be
serialization safe (composed of only fixed-width types, paying attention
to padding). It must be added to CBFS in a Makefile with the 'struct'
file processor.
Change-Id: Iab65c0b6ebea235089f741eaa8098743e54d6ccc
Signed-off-by: Julius Werner <jwerner(a)chromium.org>
---
Makefile.inc | 12 ++++++++++++
payloads/libpayload/include/cbfs_core.h | 1 +
src/commonlib/include/commonlib/cbfs_serialized.h | 1 +
src/include/cbfs.h | 4 ++++
src/lib/cbfs.c | 21 +++++++++++++++++++++
util/cbfstool/cbfs.h | 2 ++
6 files changed, 41 insertions(+)
diff --git a/Makefile.inc b/Makefile.inc
index ff77747..6225152 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -278,6 +278,18 @@ cbfs-files-processor-defconfig= \
\mv -f $(2).tmp $(2))
#######################################################################
+# Compile a C file with a bare struct definition into binary
+# arg1: C source file
+# arg2: binary file
+cbfs-files-processor-struct= \
+ $(eval $(2): $(1) $(obj)/build.h $(KCONFIG_AUTOHEADER); \
+ printf " CC+STRIP $(@)\n"; \
+ $(CC_ramstage) -MMD $(CPPFLAGS_ramstage) $(CFLAGS_ramstage) $(ramstage-c-ccopts) -include $(KCONFIG_AUTOHEADER) -MT $(2) -o $(2).tmp -c $(1) && \
+ $(OBJCOPY_ramstage) -O binary $(2).tmp $(2); \
+ rm -f $(2).tmp) \
+ $(eval DEPENDENCIES += $(2).d)
+
+#######################################################################
# Add handler for arbitrary files in CBFS
$(call add-special-class,cbfs-files)
cbfs-files-handler= \
diff --git a/payloads/libpayload/include/cbfs_core.h b/payloads/libpayload/include/cbfs_core.h
index f94056d..f45139e 100644
--- a/payloads/libpayload/include/cbfs_core.h
+++ b/payloads/libpayload/include/cbfs_core.h
@@ -73,6 +73,7 @@
#define CBFS_TYPE_VSA 0x51
#define CBFS_TYPE_MBI 0x52
#define CBFS_TYPE_MICROCODE 0x53
+#define CBFS_TYPE_STRUCT 0x70
#define CBFS_COMPONENT_CMOS_DEFAULT 0xaa
#define CBFS_COMPONENT_CMOS_LAYOUT 0x01aa
diff --git a/src/commonlib/include/commonlib/cbfs_serialized.h b/src/commonlib/include/commonlib/cbfs_serialized.h
index 1e394d2..706f175 100644
--- a/src/commonlib/include/commonlib/cbfs_serialized.h
+++ b/src/commonlib/include/commonlib/cbfs_serialized.h
@@ -77,6 +77,7 @@
#define CBFS_TYPE_MRC 0x61
#define CBFS_TYPE_MMA 0x62
#define CBFS_TYPE_EFI 0x63
+#define CBFS_TYPE_STRUCT 0x70
#define CBFS_COMPONENT_CMOS_DEFAULT 0xaa
#define CBFS_TYPE_SPD 0xab
#define CBFS_TYPE_MRC_CACHE 0xac
diff --git a/src/include/cbfs.h b/src/include/cbfs.h
index 6d9dd42..6063dd6 100644
--- a/src/include/cbfs.h
+++ b/src/include/cbfs.h
@@ -34,6 +34,10 @@ int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type);
* leaking mappings are a no-op. Returns NULL on error, else returns
* the mapping and sets the size of the file. */
void *cbfs_boot_map_with_leak(const char *name, uint32_t type, size_t *size);
+/* Load a struct file from CBFS into a buffer. Returns amount of loaded
+ * bytes on success or 0 on error. File will get decompressed as necessary.
+ * Same decompression requirements as cbfs_load_and_decompress(). */
+size_t cbfs_boot_load_struct(const char *name, void *buf, size_t buf_size);
/* Load |in_size| bytes from |rdev| at |offset| to the |buffer_size| bytes
* large |buffer|, decompressing it according to |compression| in the process.
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index 7318c87..5a2f63f 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -79,6 +79,8 @@ size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset,
switch (compression) {
case CBFS_COMPRESS_NONE:
+ if (buffer_size < in_size)
+ return 0;
if (rdev_readat(rdev, buffer, offset, in_size) != in_size)
return 0;
return in_size;
@@ -166,6 +168,25 @@ void *cbfs_boot_load_stage_by_name(const char *name)
return prog_entry(&stage);
}
+size_t cbfs_boot_load_struct(const char *name, void *buf, size_t buf_size)
+{
+ struct cbfsf fh;
+ uint32_t compression_algo;
+ size_t decompressed_size;
+ uint32_t type = CBFS_TYPE_STRUCT;
+
+ if (cbfs_boot_locate(&fh, name, &type) < 0)
+ return 0;
+
+ if (cbfsf_decompression_info(&fh, &compression_algo,
+ &decompressed_size) < 0
+ || decompressed_size > buf_size)
+ return 0;
+
+ return cbfs_load_and_decompress(&fh.data, 0, region_device_sz(&fh.data),
+ buf, buf_size, compression_algo);
+}
+
int cbfs_prog_stage_load(struct prog *pstage)
{
struct cbfs_stage stage;
diff --git a/util/cbfstool/cbfs.h b/util/cbfstool/cbfs.h
index 36b9fc0..f1ae09d 100644
--- a/util/cbfstool/cbfs.h
+++ b/util/cbfstool/cbfs.h
@@ -186,6 +186,7 @@ struct cbfs_payload {
#define CBFS_COMPONENT_MRC 0x61
#define CBFS_COMPONENT_MMA 0x62
#define CBFS_COMPONENT_EFI 0x63
+#define CBFS_COMPONENT_STRUCT 0x70
#define CBFS_COMPONENT_CMOS_DEFAULT 0xaa
#define CBFS_COMPONENT_SPD 0xab
#define CBFS_COMPONENT_MRC_CACHE 0xac
@@ -227,6 +228,7 @@ static struct typedesc_t filetypes[] unused = {
{CBFS_COMPONENT_MRC_CACHE, "mrc_cache"},
{CBFS_COMPONENT_MMA, "mma"},
{CBFS_COMPONENT_EFI, "efi"},
+ {CBFS_COMPONENT_STRUCT, "struct"},
{CBFS_COMPONENT_DELETED, "deleted"},
{CBFS_COMPONENT_NULL, "null"}
};
Julius Werner (jwerner(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16273
-gerrit
commit 136a14b075db3694564ebf4d9609cff9cd370cdf
Author: Julius Werner <jwerner(a)chromium.org>
Date: Fri Aug 19 16:20:40 2016 -0700
cbmem: Always maintain backing store struct in a global on non-x86
The current CBMEM code contains an optimization that maintains the
structure with information about the CBMEM backing store in a global
variable, so that we don't have to recover it from cbmem_top() again
every single time we access CBMEM. However, due to the problems with
using globals in x86 romstage, this optimization has only been enabled
in ramstage.
However, all non-x86 platforms are SRAM-based (at least for now) and
can use globals perfectly fine in earlier stages. Therefore, this patch
extends the optimization on those platforms to all stages. This also
allows us to remove the requirement that cbmem_top() needs to return
NULL before its backing store has been initialized from those boards,
since the CBMEM code can now keep track of whether it has been
initialized by itself.
Change-Id: Ia6c1db00ae01dee485d5e96e4315cb399dc63696
Signed-off-by: Julius Werner <jwerner(a)chromium.org>
---
src/include/cbmem.h | 5 ++---
src/lib/imd_cbmem.c | 16 ++++++++++------
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/src/include/cbmem.h b/src/include/cbmem.h
index 5b75db0..6a41ec7 100644
--- a/src/include/cbmem.h
+++ b/src/include/cbmem.h
@@ -67,9 +67,8 @@ void cbmem_initialize_empty_id_size(u32 id, u64 size);
/* Return the top address for dynamic cbmem. The address returned needs to
* be consistent across romstage and ramstage, and it is required to be
* below 4GiB.
- * Board or chipset should return NULL if any interface that might rely on cbmem
- * (e.g. cbfs, vboot) is used before the cbmem backing store has been
- * initialized. */
+ * x86 boards or chipsets must return NULL before the cbmem backing store has
+ * been initialized. */
void *cbmem_top(void);
/* Add a cbmem entry of a given size and id. These return NULL on failure. The
diff --git a/src/lib/imd_cbmem.c b/src/lib/imd_cbmem.c
index 3e3e2b0..c31b59b 100644
--- a/src/lib/imd_cbmem.c
+++ b/src/lib/imd_cbmem.c
@@ -26,10 +26,17 @@
#include <arch/acpi.h>
#endif
+/* We need special handling on x86 before ramstage because we cannot use global
+ * variables (we're executing in-place from flash so we don't have a writable
+ * data segment, and we cannot use CAR_GLOBAL here since that mechanism itself
+ * is dependent on CBMEM). Therefore, we have to always try to partially recover
+ * CBMEM from cbmem_top() whenever we try to access it. In other environments
+ * we're not so constrained and just keep the backing imd struct in a global. */
+#define CAN_USE_GLOBALS (!IS_ENABLED(CONFIG_ARCH_X86) || ENV_RAMSTAGE)
+
static inline struct imd *cbmem_get_imd(void)
{
- /* Only supply a backing store for imd in ramstage. */
- if (ENV_RAMSTAGE) {
+ if (CAN_USE_GLOBALS) {
static struct imd imd_cbmem;
return &imd_cbmem;
}
@@ -77,11 +84,8 @@ static struct imd *imd_init_backing_with_recover(struct imd *backing)
struct imd *imd;
imd = imd_init_backing(backing);
- if (!ENV_RAMSTAGE) {
+ if (!CAN_USE_GLOBALS) {
imd_handle_init(imd, cbmem_top());
-
- /* Need to partially recover all the time outside of ramstage
- * because there's object storage outside of the stack. */
imd_handle_init_partial_recovery(imd);
}