Julius Werner (jwerner@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@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@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