From 2c61506630b8e76bed93b3a5ac0ab2089376f548 Mon Sep 17 00:00:00 2001 From: Patrick Georgi Date: Wed, 15 Jul 2015 20:49:00 +0200 Subject: cbfstool: add extended file attributes for cbfs_file cbfs_file_first_attr(struct cbfs_file *) and cbfs_file_next_attr(struct cbfs_file *, struct cbfs_file_attribute *) help navigate through extended attributes. cbfs_add_file_attr(header, tag, size) adds a new file attribute to header. Change-Id: I325965286c44f31abd95df684d340cebb0e68b75 Signed-off-by: Patrick Georgi Reviewed-on: http://review.coreboot.org/10934 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- util/cbfstool/cbfs.h | 11 ++++++ util/cbfstool/cbfs_image.c | 87 +++++++++++++++++++++++++++++++++++++++++++--- util/cbfstool/cbfs_image.h | 14 ++++++++ 3 files changed, 107 insertions(+), 5 deletions(-) (limited to 'util/cbfstool') 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 +/* 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 -- cgit v1.2.3