Patrick Georgi (pgeorgi@google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10938
-gerrit
commit 7284d14edd5b4b5c65c641be7a29b93a55e6d3fb Author: Daisuke Nojiri dnojiri@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:
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@chromium.org Signed-off-by: Patrick Georgi pgeorgi@chromium.org --- payloads/libpayload/include/cbfs_core.h | 19 +++++++++++++++--- payloads/libpayload/libcbfs/cbfs.c | 14 +++++++++----- payloads/libpayload/libcbfs/cbfs_core.c | 34 +++++++++++++++++++++++++-------- 3 files changed, 51 insertions(+), 16 deletions(-)
diff --git a/payloads/libpayload/include/cbfs_core.h b/payloads/libpayload/include/cbfs_core.h index 26730c9..eee587e 100644 --- a/payloads/libpayload/include/cbfs_core.h +++ b/payloads/libpayload/include/cbfs_core.h @@ -138,6 +138,8 @@ struct cbfs_file {
struct cbfs_file_attributes { uint32_t len; + uint32_t compression; + uint32_t decompressed_size; } __attribute__((packed));
#define CBFS_FILE_ATTRIBUTES(_p) (((_p)->attributes == 0) ? NULL : \ @@ -220,12 +222,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 9d7d2f1..6b0e11c 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 7926d9d..eec244a 100644 --- a/payloads/libpayload/libcbfs/cbfs_core.c +++ b/payloads/libpayload/libcbfs/cbfs_core.c @@ -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,23 @@ 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_attributes *attr = CBFS_FILE_ATTRIBUTES(file); + if (attr && attr->compression) { + uint32_t alg = ntohl(attr->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(attr->decompressed_size))) + return NULL; + file_content = dst; + } + + return file_content; }
int cbfs_decompress(int algo, void *src, void *dst, int len)