summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/cbfstool/cbfs.h11
-rw-r--r--util/cbfstool/cbfs_image.c87
-rw-r--r--util/cbfstool/cbfs_image.h14
3 files changed, 107 insertions, 5 deletions
diff --git a/util/cbfstool/cbfs.h b/util/cbfstool/cbfs.h
index 3f80a046f4..185bddebf6 100644
--- a/util/cbfstool/cbfs.h
+++ b/util/cbfstool/cbfs.h
@@ -21,6 +21,10 @@
#include <stdint.h>
+/* cbfstool will fail when trying to build a cbfs_file header that's larger
+ * than MAX_CBFS_FILE_HEADER_BUFFER. 1K should give plenty of room. */
+#define MAX_CBFS_FILE_HEADER_BUFFER 1024
+
/* create a magic number in host-byte order.
* b3 is the high order byte.
* in the coreboot tools, we go with the 32-bit
@@ -77,6 +81,7 @@ struct cbfs_file {
/* length of file data */
uint32_t len;
uint32_t type;
+ /* offset to struct cbfs_file_attribute or 0 */
uint32_t attributes_offset;
/* length of header incl. variable data */
uint32_t offset;
@@ -95,6 +100,11 @@ struct cbfs_file_attribute {
uint8_t data[0];
} __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
+
struct cbfs_stage {
uint32_t compression;
uint64_t entry;
@@ -155,6 +165,7 @@ struct cbfs_payload {
#define CBFS_COMPONENT_NULL 0xFFFFFFFF
#define CBFS_SUBHEADER(_p) ( (void *) ((((uint8_t *) (_p)) + ntohl((_p)->offset))) )
+
/* cbfs_image.c */
uint32_t get_cbfs_entry_type(const char *name, uint32_t default_value);
uint32_t get_cbfs_compression(const char *name, uint32_t unknown);
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index e71d598a7b..d295058ea1 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -997,11 +997,8 @@ int cbfs_is_valid_entry(struct cbfs_image *image, struct cbfs_file *entry)
struct cbfs_file *cbfs_create_file_header(int type,
size_t len, const char *name)
{
- // assume that there won't be file names of ~1000 bytes
- const int bufsize = 1024;
-
- struct cbfs_file *entry = malloc(bufsize);
- memset(entry, CBFS_CONTENT_DEFAULT_VALUE, bufsize);
+ struct cbfs_file *entry = malloc(MAX_CBFS_FILE_HEADER_BUFFER);
+ memset(entry, CBFS_CONTENT_DEFAULT_VALUE, MAX_CBFS_FILE_HEADER_BUFFER);
memcpy(entry->magic, CBFS_FILE_MAGIC, sizeof(entry->magic));
entry->type = htonl(type);
entry->len = htonl(len);
@@ -1022,6 +1019,86 @@ int cbfs_create_empty_entry(struct cbfs_file *entry, int type,
return 0;
}
+struct cbfs_file_attribute *cbfs_file_first_attr(struct cbfs_file *file)
+{
+ /* attributes_offset should be 0 when there is no attribute, but all
+ * values that point into the cbfs_file header are invalid, too. */
+ if (ntohl(file->attributes_offset) <= sizeof(*file))
+ return NULL;
+
+ /* There needs to be enough space for the file header and one
+ * attribute header for this to make sense. */
+ if (ntohl(file->offset) <=
+ sizeof(*file) + sizeof(struct cbfs_file_attribute))
+ return NULL;
+
+ return (struct cbfs_file_attribute *)
+ (((uint8_t *)file) + ntohl(file->attributes_offset));
+}
+
+struct cbfs_file_attribute *cbfs_file_next_attr(struct cbfs_file *file,
+ struct cbfs_file_attribute *attr)
+{
+ /* ex falso sequitur quodlibet */
+ if (attr == NULL)
+ return NULL;
+
+ /* Is there enough space for another attribute? */
+ if ((uint8_t *)attr + ntohl(attr->len) +
+ sizeof(struct cbfs_file_attribute) >=
+ (uint8_t *)file + ntohl(file->offset))
+ return NULL;
+
+ struct cbfs_file_attribute *next = (struct cbfs_file_attribute *)
+ (((uint8_t *)attr) + ntohl(attr->len));
+ /* If any, "unused" attributes must come last. */
+ if (ntohl(next->tag) == CBFS_FILE_ATTR_TAG_UNUSED)
+ return NULL;
+ if (ntohl(next->tag) == CBFS_FILE_ATTR_TAG_UNUSED2)
+ return NULL;
+
+ return next;
+}
+
+struct cbfs_file_attribute *cbfs_add_file_attr(struct cbfs_file *header,
+ uint32_t tag,
+ uint32_t size)
+{
+ struct cbfs_file_attribute *attr, *next;
+ next = cbfs_file_first_attr(header);
+ do {
+ attr = next;
+ next = cbfs_file_next_attr(header, attr);
+ } while (next != NULL);
+ uint32_t header_size = ntohl(header->offset) + size;
+ if (header_size > MAX_CBFS_FILE_HEADER_BUFFER) {
+ DEBUG("exceeding allocated space for cbfs_file headers");
+ return NULL;
+ }
+ /* attr points to the last valid attribute now.
+ * If NULL, we have to create the first one. */
+ if (attr == NULL) {
+ /* New attributes start where the header ends.
+ * header->offset is later set to accomodate the
+ * additional structure.
+ * No endianess translation necessary here, because both
+ * fields are encoded the same way. */
+ header->attributes_offset = header->offset;
+ attr = (struct cbfs_file_attribute *)
+ (((uint8_t *)header) +
+ ntohl(header->attributes_offset));
+ } else {
+ attr = (struct cbfs_file_attribute *)
+ (((uint8_t *)attr) +
+ ntohl(attr->len));
+ }
+ header->offset = htonl(header_size);
+ memset(attr, CBFS_CONTENT_DEFAULT_VALUE, size);
+ attr->tag = htonl(tag);
+ attr->len = htonl(size);
+ return attr;
+}
+
/* Finds a place to hold whole data in same memory page. */
static int is_in_same_page(uint32_t start, uint32_t size, uint32_t page)
{
diff --git a/util/cbfstool/cbfs_image.h b/util/cbfstool/cbfs_image.h
index 7a9b48402f..aea826053a 100644
--- a/util/cbfstool/cbfs_image.h
+++ b/util/cbfstool/cbfs_image.h
@@ -170,4 +170,18 @@ int cbfs_merge_empty_entry(struct cbfs_image *image, struct cbfs_file *entry,
/* Returns the size of a cbfs file header with no extensions */
size_t cbfs_calculate_file_header_size(const char *name);
+
+/* Given a cbfs_file, return the first file attribute, or NULL. */
+struct cbfs_file_attribute *cbfs_file_first_attr(struct cbfs_file *file);
+
+/* Given a cbfs_file and a cbfs_file_attribute, return the attribute that
+ * follows it, or NULL. */
+struct cbfs_file_attribute *cbfs_file_next_attr(struct cbfs_file *file,
+ struct cbfs_file_attribute *attr);
+
+/* Adds to header a new extended attribute tagged 'tag', sized 'size'.
+ * Returns pointer to the new attribute, or NULL on error. */
+struct cbfs_file_attribute *cbfs_add_file_attr(struct cbfs_file *header,
+ uint32_t tag,
+ uint32_t size);
#endif