[coreboot-gerrit] Patch set updated for coreboot: libpayload: allow compression at file header level

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Wed Sep 16 22:05:48 CET 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10938

-gerrit

commit b35818a4082e32b93e77d5112b82e42b96129924
Author: Daisuke Nojiri <dnojiri at chromium.org>
Date:   Thu Jul 9 15:07:45 2015 -0700

    libpayload: allow compression at file header level
    
    Sample call sequence for loading a compressed file is as follows:
    
    [pg: the following example isn't correct right now, but
     cbfs_get_file_content's interface will change once again before this
     gets merged.]
    	const char *name = "foo.bmp";
    	struct cbfs_file *file = cbfs_get_file(media, name);
    	struct cbfs_file_attributes *attr = CBFS_FILE_ATTRIBUTES(file);
    	if (attr) {
    		void *dst = malloc(ntohl(attr->uncompressed_size));
    		dst = cbfs_get_file_content(media, name, type, NULL, file, dst);
    	}
    
    cbfs_stage and cbfs_payload_segment continue to support compression at
    subheader level because stages and payloads have to be decompressed to the load
    address, which is stored in the subheader. For these, file level compression
    should be turned off.
    
    Change-Id: If959e3dff9b93c6ae45ec7358afcc7840bc17218
    Signed-off-by: Daisuke Nojiri <dnojiri at chromium.org>
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
---
 payloads/libpayload/include/cbfs_core.h | 26 +++++++++++--
 payloads/libpayload/libcbfs/cbfs.c      | 14 ++++---
 payloads/libpayload/libcbfs/cbfs_core.c | 65 +++++++++++++++++++++++----------
 3 files changed, 77 insertions(+), 28 deletions(-)

diff --git a/payloads/libpayload/include/cbfs_core.h b/payloads/libpayload/include/cbfs_core.h
index a2ee744..66307c1 100644
--- a/payloads/libpayload/include/cbfs_core.h
+++ b/payloads/libpayload/include/cbfs_core.h
@@ -141,6 +141,7 @@ struct cbfs_file {
  * 0xff. Support both. */
 #define CBFS_FILE_ATTR_TAG_UNUSED 0
 #define CBFS_FILE_ATTR_TAG_UNUSED2 0xffffffff
+#define CBFS_FILE_ATTR_TAG_COMPRESSION 0x42435a4c
 
 /* The common fields of extended cbfs file attributes.
    Attributes are expected to start with tag/len, then append their
@@ -152,6 +153,14 @@ struct cbfs_file_attribute {
 	uint8_t data[0];
 } __attribute__((packed));
 
+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));
+
 /* Given a cbfs_file, return the first file attribute, or NULL. */
 struct cbfs_file_attribute *cbfs_file_first_attr(struct cbfs_file *file);
 
@@ -237,12 +246,23 @@ struct cbfs_media {
 	int (*close)(struct cbfs_media *media);
 };
 
-/* returns pointer to a file entry inside CBFS or NULL */
+/* returns pointer to a file entry inside CBFS or NULL on error */
 struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name);
 
-/* returns pointer to file content inside CBFS after if type is correct */
+/*
+ * returns pointer to file content inside CBFS after if type is correct
+ * or NULL on error.
+ *
+ * if the file is compressed, it's decompressed and copied to dst allocated by
+ * the caller.
+ *
+ * it can be invoked using previously mapped file content pointed by *file.
+ * if *file is not NULL, loading file will be skipped, assuming the file has
+ * not been unmapped.
+ */
 void *cbfs_get_file_content(struct cbfs_media *media, const char *name,
-			    int type, size_t *sz);
+			    int type, size_t *sz,
+			    struct cbfs_file *file, void *dst);
 
 /* returns decompressed size on success, 0 on failure */
 int cbfs_decompress(int algo, void *src, void *dst, int len);
diff --git a/payloads/libpayload/libcbfs/cbfs.c b/payloads/libpayload/libcbfs/cbfs.c
index 3e614b6..c619075 100644
--- a/payloads/libpayload/libcbfs/cbfs.c
+++ b/payloads/libpayload/libcbfs/cbfs.c
@@ -89,7 +89,8 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
 	tohex16(device, name+8);
 
 	orom = (struct cbfs_optionrom *)
-		cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM, NULL);
+		cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM,
+			NULL, NULL, NULL);
 
 	if (orom == NULL)
 		return NULL;
@@ -119,7 +120,8 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
 void * cbfs_load_stage(struct cbfs_media *media, const char *name)
 {
 	struct cbfs_stage *stage = (struct cbfs_stage *)
-		cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL);
+		cbfs_get_file_content(media, name, CBFS_TYPE_STAGE,
+			NULL, NULL, NULL);
 	/* this is a mess. There is no ntohll. */
 	/* for now, assume compatible byte order until we solve this. */
 	uintptr_t entry;
@@ -155,7 +157,8 @@ void * cbfs_load_stage(struct cbfs_media *media, const char *name)
 int cbfs_execute_stage(struct cbfs_media *media, const char *name)
 {
 	struct cbfs_stage *stage = (struct cbfs_stage *)
-		cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL);
+		cbfs_get_file_content(media, name, CBFS_TYPE_STAGE,
+			NULL, NULL, NULL);
 
 	if (stage == NULL)
 		return 1;
@@ -173,7 +176,7 @@ int cbfs_execute_stage(struct cbfs_media *media, const char *name)
 void *cbfs_load_payload(struct cbfs_media *media, const char *name)
 {
 	return (struct cbfs_payload *)cbfs_get_file_content(
-		media, name, CBFS_TYPE_PAYLOAD, NULL);
+		media, name, CBFS_TYPE_PAYLOAD, NULL, NULL, NULL);
 }
 
 struct cbfs_file *cbfs_find(const char *name) {
@@ -181,7 +184,8 @@ struct cbfs_file *cbfs_find(const char *name) {
 }
 
 void *cbfs_find_file(const char *name, int type) {
-	return cbfs_get_file_content(CBFS_DEFAULT_MEDIA, name, type, NULL);
+	return cbfs_get_file_content(CBFS_DEFAULT_MEDIA, name, type,
+		NULL, NULL, NULL);
 }
 
 const struct cbfs_header *get_cbfs_header(void) {
diff --git a/payloads/libpayload/libcbfs/cbfs_core.c b/payloads/libpayload/libcbfs/cbfs_core.c
index 6a19b26..90aa9ad 100644
--- a/payloads/libpayload/libcbfs/cbfs_core.c
+++ b/payloads/libpayload/libcbfs/cbfs_core.c
@@ -97,8 +97,8 @@ const struct cbfs_header *cbfs_get_header(struct cbfs_media *media)
 /* public API starts here*/
 struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name)
 {
-	const char *file_name;
-	uint32_t offset, romsize, name_len;
+	const char *vardata;
+	uint32_t offset, romsize, vardata_len;
 	const struct cbfs_header *header;
 	struct cbfs_file file, *file_ptr;
 	struct cbfs_media default_media;
@@ -153,29 +153,29 @@ struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name)
 			offset += new_align;
 			continue;
 		}
-		name_len = ntohl(file.offset) - sizeof(file);
-		DEBUG(" - load entry 0x%x file name (%d bytes)...\n", offset,
-		      name_len);
+		vardata_len = ntohl(file.offset) - sizeof(file);
+		DEBUG(" - load entry 0x%x variable data (%d bytes)...\n",
+			offset, vardata_len);
 
 		// load file name (arbitrary length).
-		file_name = (const char*)media->map(
-				media, offset + sizeof(file), name_len);
-		if (file_name == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
+		vardata = (const char*)media->map(
+				media, offset + sizeof(file), vardata_len);
+		if (vardata == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
 			ERROR("ERROR: Failed to get filename: 0x%x.\n", offset);
-		} else if (strcmp(file_name, name) == 0) {
+		} else if (strcmp(vardata, name) == 0) {
 			int file_offset = ntohl(file.offset),
 			    file_len = ntohl(file.len);
 			DEBUG("Found file (offset=0x%x, len=%d).\n",
 			    offset + file_offset, file_len);
-			media->unmap(media, file_name);
+			media->unmap(media, vardata);
 			file_ptr = media->map(media, offset,
 					      file_offset + file_len);
 			media->close(media);
 			return file_ptr;
 		} else {
 			DEBUG(" (unmatched file @0x%x: %s)\n", offset,
-			      file_name);
-			media->unmap(media, file_name);
+			      vardata);
+			media->unmap(media, vardata);
 		}
 
 		// Move to next file.
@@ -189,18 +189,20 @@ struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name)
 }
 
 void *cbfs_get_file_content(struct cbfs_media *media, const char *name,
-			    int type, size_t *sz)
+			    int type, size_t *sz, struct cbfs_file *file,
+			    void *dst)
 {
-	struct cbfs_file *file = cbfs_get_file(media, name);
+	if (file == NULL) {
+		file = cbfs_get_file(media, name);
+		if (file == NULL) {
+			ERROR("Could not find file '%s'.\n", name);
+			return NULL;
+		}
+	}
 
 	if (sz)
 		*sz = 0;
 
-	if (file == NULL) {
-		ERROR("Could not find file '%s'.\n", name);
-		return NULL;
-	}
-
 	if (ntohl(file->type) != type) {
 		ERROR("File '%s' is of type %x, but we requested %x.\n", name,
 		      ntohl(file->type), type);
@@ -210,7 +212,30 @@ void *cbfs_get_file_content(struct cbfs_media *media, const char *name,
 	if (sz)
 		*sz = ntohl(file->len);
 
-	return (void *)CBFS_SUBHEADER(file);
+	void *file_content = (void *)CBFS_SUBHEADER(file);
+
+	struct cbfs_file_attribute *attr = cbfs_file_first_attr(file);
+	while (attr) {
+		if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_COMPRESSION)
+			break;
+		attr = cbfs_file_next_attr(file, attr);
+	}
+	if (attr) {
+		struct cbfs_file_attr_compression *comp =
+			(struct cbfs_file_attr_compression *)attr;
+		uint32_t alg = ntohl(comp->compression);
+		DEBUG("File '%s' is compressed (alg=%d)\n", alg);
+		if (!dst) {
+			ERROR("Memory for decompressed data not provided\n");
+			return NULL;
+		}
+		if (cbfs_decompress(alg, file_content, dst,
+				    ntohl(comp->decompressed_size)))
+			return NULL;
+		file_content = dst;
+	}
+
+	return file_content;
 }
 
 struct cbfs_file_attribute *cbfs_file_first_attr(struct cbfs_file *file)



More information about the coreboot-gerrit mailing list