summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commonlib/cbfs.c48
-rw-r--r--src/commonlib/include/commonlib/cbfs.h17
-rw-r--r--src/commonlib/include/commonlib/cbfs_serialized.h49
3 files changed, 113 insertions, 1 deletions
diff --git a/src/commonlib/cbfs.c b/src/commonlib/cbfs.c
index 56faf286ef..1db8d31acf 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_full(&fh->metadata);
+ 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 c74dd708e3..5e511a7aea 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 c01ba1a020..1e394d280f 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