Marshall Dawson has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/33401
Change subject: util/amdfwtool: Add new BIOS compression tool ......................................................................
util/amdfwtool: Add new BIOS compression tool
Add a utility to generate a compressed BIOS image for AMD Family 17h.
If the input is an elf file, the utility extracts the program portion for compression. Otherwise the file is compressed as-is.
In modern AMD systems, the PSP brings up DRAM then uncompresses the BIOS image into memory prior to x86 beginning execution. The PSP supports a zlib engine, and interprets the first 256 bytes as a header, where offset 0x14 containing the uncompressed size. For further details, see AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h Processors (NDA only, #55758).
BUG=b:127766506 TEST=Use with WIP Picasso
Change-Id: Id1c54e0a6dae9e4a0362c6635fe8b8aa48a369d8 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M Makefile.inc M util/cbfstool/Makefile.inc A util/cbfstool/amdcompress.c 3 files changed, 349 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/33401/1
diff --git a/Makefile.inc b/Makefile.inc index 14cd50c..2c4680c 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -512,6 +512,7 @@ FMAPTOOL:=$(objutil)/cbfstool/fmaptool RMODTOOL:=$(objutil)/cbfstool/rmodtool IFWITOOL:=$(objutil)/cbfstool/ifwitool +AMDCOMPRESS:=$(objutil)/cbfstool/amdcompress
$(obj)/cbfstool: $(CBFSTOOL) cp $< $@ @@ -525,6 +526,9 @@ $(obj)/ifwitool: $(IFWITOOL) cp $< $@
+$(obj)/amdcompress: $(AMDCOMPRESS) + cp $< $@ + _WINCHECK=$(shell uname -o 2> /dev/null) STACK= ifeq ($(_WINCHECK),Msys) @@ -637,7 +641,7 @@ include util/crossgcc/Makefile.inc
.PHONY: tools -tools: $(objutil)/kconfig/conf $(CBFSTOOL) $(objutil)/cbfstool/cbfs-compression-tool $(FMAPTOOL) $(RMODTOOL) $(IFWITOOL) $(objutil)/nvramtool/nvramtool $(ROMCC_BIN) $(objutil)/sconfig/sconfig $(IFDTOOL) $(CBOOTIMAGE) $(AMDFWTOOL) $(FUTILITY) $(BINCFG) +tools: $(objutil)/kconfig/conf $(CBFSTOOL) $(objutil)/cbfstool/cbfs-compression-tool $(FMAPTOOL) $(RMODTOOL) $(IFWITOOL) $(objutil)/nvramtool/nvramtool $(ROMCC_BIN) $(objutil)/sconfig/sconfig $(IFDTOOL) $(CBOOTIMAGE) $(AMDFWTOOL) $(AMDCOMPRESS) $(FUTILITY) $(BINCFG)
########################################################################### # Common recipes for all stages diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc index 7928520..2f803b3 100644 --- a/util/cbfstool/Makefile.inc +++ b/util/cbfstool/Makefile.inc @@ -70,6 +70,12 @@ cbfscompobj += $(compressionobj) cbfscompobj += cbfscomptool.o
+amdcompobj := +amdcompobj += amdcompress.o +amdcompobj += elfheaders.o +amdcompobj += common.o +amdcompobj += xdr.o + TOOLCFLAGS ?= -Werror -Wall -Wextra TOOLCFLAGS += -Wcast-qual -Wmissing-prototypes -Wredundant-decls -Wshadow TOOLCFLAGS += -Wstrict-prototypes -Wwrite-strings @@ -153,6 +159,10 @@ printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n" $(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(cbfscompobj))
+$(objutil)/cbfstool/amdcompress: $(addprefix $(objutil)/cbfstool/,$(amdcompobj)) + printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n" + $(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(amdcompobj)) -lz + # Yacc source is superset of header $(objutil)/cbfstool/fmd.o: TOOLCFLAGS += -Wno-redundant-decls $(objutil)/cbfstool/fmd_parser.o: TOOLCFLAGS += -Wno-redundant-decls diff --git a/util/cbfstool/amdcompress.c b/util/cbfstool/amdcompress.c new file mode 100644 index 0000000..efa332f --- /dev/null +++ b/util/cbfstool/amdcompress.c @@ -0,0 +1,334 @@ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <getopt.h> +#include <elfparsing.h> +#include "zlib.h" + +#define DEBUG_FILE 0 + +#define HDR_SIZE 256 +#define UNCOMP_MAX 0x300000 + +#define DIR_UNDEF 0 +#define DIR_COMP 1 +#define DIR_UNCOMP 2 + +typedef struct _header { + uint32_t rsvd1[5]; + uint32_t size; + uint32_t rsvd2[58]; +} __attribute__((packed)) header; + +static const char *optstring = "i:o:cm:uh"; + +static struct option long_options[] = { + {"infile", required_argument, 0, 'i' }, + {"outfile", required_argument, 0, 'o' }, + {"compress", required_argument, 0, 'c' }, + {"maxsize", required_argument, 0, 'h' }, + {"uncompress", required_argument, 0, 'u' }, + {"help", no_argument, 0, 'h' }, +}; + +static void usage(void) +{ + printf("<name>: Extract or create a zlib compressed BIOS binary\n"); + printf(" image. A compressed image contains a 256 byte\n"); + printf(" header with a 32-bit size at 0x14.\n"); + printf("Usage: <name> -i in_file -o out_file -[c|u]\n"); + printf("-i | --infile <FILE> Input file\n"); + printf("-o | --outfile <FILE> Output file\n"); + printf("-c | --compress Compress\n"); + printf("-m | --maxsize <HEX_VAL> Maximum uncompressed size (optional)\n"); + printf(" * On compress: verify uncompressed size\n"); + printf(" will be less than or equal maxsize\n"); + printf(" * On uncompress: override default buffer size\n"); + printf(" allocation of 0x%x bytes\n", UNCOMP_MAX); + printf("-u | --uncompress Uncompress\n"); + printf("-h | --help Display this message\n"); + + exit(1); +} + +static int do_file(char *name, size_t *size, int oflag) +{ + struct stat fd_stat; + int fd; + + fd = open(name, oflag, 0666); + if (fd < 0) { + return -1; + } + + if (fstat(fd, &fd_stat)) { + close(fd); + return -1; + } + + if (size) + *size = fd_stat.st_size; + return fd; +} + +static int parse_elf_to_xip_ram(const struct buffer *input, + struct buffer *output) +{ + struct parsed_elf pelf; + + if (parse_elf(input, &pelf, ELF_PARSE_ALL)) + return 1; + if (buffer_create(output, pelf.phdr->p_filesz, "") != 0) + return 1; + + memcpy(output->data, input->data + pelf.phdr->p_offset, output->size); + + return 0; +} + +static int iself(const void *input) +{ + const Elf32_Ehdr *ehdr = input; + return !memcmp(ehdr->e_ident, ELFMAG, 4); +} + +/* todo: Consider using deflate() and inflate() instead of compress() and + * decompress(), especially if memory allocation somehow becomes a problem. + * Those two functions can operate on streams and process chunks of data. + */ + +static void do_compress(char *outf, char *inf, size_t max_size) +{ + int out_fd, in_fd; + char *in_buf, *out_buf; + struct buffer bios_buf; + size_t size_unc, size_comp; + size_t bytes; + int err; + + in_fd = do_file(inf, &size_unc, O_RDONLY); + if (in_fd < 0) { + printf("\tError opening input file %s\n", inf); + err = 1; + goto out; + } + + out_fd = do_file(outf, 0, O_CREAT | O_WRONLY); + if (out_fd < 0) { + printf("\tError opening output file %s\n", outf); + err = 1; + goto out_close_in; + } + + in_buf = malloc(size_unc); + if (!in_buf) { + printf("\tError allocating 0x%zx bytes for input buffer\n", + size_unc); + err = 1; + goto out_close_out; + } + + bytes = read(in_fd, in_buf, size_unc); + if (bytes != size_unc) { + printf("\tError reading input file %s\n", inf); + err = 1; + goto out_free_in; + } + + struct buffer inbf; + inbf.data = in_buf; + inbf.size = size_unc; + + if (iself(in_buf)) { + /* if elf, convert the in_buf to point to the progbits */ + err = parse_elf_to_xip_ram(&inbf, &bios_buf); + if (err) { + err = 1; + printf("\tError parsing ELF file %s\n", inf); + goto out_free_in; + } + free(in_buf); + in_buf = bios_buf.data; + size_unc = bios_buf.size; + } + + size_comp = size_unc; /* todo: tbd worst case? */ + if (max_size && size_unc > max_size) { + printf("\tError - size (%zx) exceeds specified max_size (%zx)\n", + size_unc, max_size); + err = 1; + goto out_free_in; + } + + out_buf = malloc(size_comp + sizeof(header)); + if (!out_buf) { + printf("\tError allocating 0x%zx bytes for output buffer\n", + size_comp + sizeof(header)); + err = 1; + goto out_free_in; + } + + err = compress((Bytef *)(out_buf + sizeof(header)), &size_comp, + (Bytef *)in_buf, size_unc); + if (err != Z_OK) { + printf("\tzlib compression error %d\n", err); + err = 1; + goto out_free_out; + } + + if (DEBUG_FILE) + printf("\tCompressed 0x%zx bytes into 0x%zx\n", + size_unc, size_comp); + + memset(out_buf, 0, sizeof(header)); + ((header *)out_buf)->size = size_comp; + + bytes = write(out_fd, out_buf, size_comp + sizeof(header)); + if (bytes != size_comp + sizeof(header)) { + printf("\tError writing to %s\n", outf); + err = 1; + /* fall through to out_free_out */ + } + +out_free_out: + free(out_buf); +out_free_in: + free(in_buf); +out_close_out: + close(out_fd); +out_close_in: + close(in_fd); +out: + if (err) + exit(err); +} + +static void do_uncompress(char *outf, char *inf, size_t max_size) +{ + int out_fd, in_fd; + char *in_buf, *out_buf; + size_t size_unc, size_comp; + size_t bytes; + int err; + + in_fd = do_file(inf, &size_comp, O_RDONLY); + if (in_fd < 0) { + printf("\tError opening input file %s\n", inf); + err = 1; + goto out; + } + + out_fd = do_file(outf, 0, O_CREAT | O_WRONLY); + if (out_fd < 0) { + printf("\tError opening output file %s\n", outf); + err = 1; + goto out_close_in; + } + + in_buf = malloc(size_comp); + if (!in_buf) { + printf("\tError allocating 0x%zx bytes for input buffer\n", + size_comp); + err = 1; + goto out_close_out; + } + + bytes = read(in_fd, in_buf, size_comp); + if (bytes != size_comp) { + printf("\tError reading input file %s\n", inf); + err = 1; + goto out_free_in; + } + + size_comp = ((header *)in_buf)->size; + + size_unc = max_size ? max_size : UNCOMP_MAX; + out_buf = malloc(size_unc); + if (!out_buf) { + printf("\tError allocating 0x%zx bytes for output buffer\n", + size_unc); + err = 1; + goto out_free_in; + } + + err = uncompress((Bytef *)out_buf, &size_unc, + (Bytef *)in_buf + sizeof(header), size_comp); + if (err != Z_OK) { + printf("\tzlib uncompression error %d\n", err); + err = 1; + goto out_free_out; + } + + if (DEBUG_FILE) + printf("Uncompressed 0x%zx bytes into 0x%zx\n", + size_comp, size_unc); + + bytes = write(out_fd, out_buf, size_unc); + if (bytes != size_unc) { + printf("\tError writing to %s\n", outf); + err = 1; + /* fall through to out_free_out */ + } + +out_free_out: + free(out_buf); +out_free_in: + free(in_buf); +out_close_out: + close(out_fd); +out_close_in: + close(in_fd); +out: + if (err) + exit(err); +} + +int main(int argc, char *argv[]) +{ + int c; + char *inf = 0, *outf = 0, *scratch; + int direction = DIR_UNDEF; + size_t max_size = 0; + + while (1) { + int optindex = 0; + + c = getopt_long(argc, argv, optstring, long_options, &optindex); + if (c == -1) + break; + + switch (c) { + case 'i': + inf = optarg; + break; + case 'o': + outf = optarg; + break; + case 'c': + if (direction != DIR_UNDEF) + usage(); + direction = DIR_COMP; + break; + case 'u': + if (direction != DIR_UNDEF) + usage(); + direction = DIR_UNCOMP; + break; + case 'm': + max_size = strtoull(optarg, &scratch, 16); + break; + case 'h': + usage(); + } + } + if (!inf || !outf || direction == DIR_UNDEF) + usage(); + + if (direction == DIR_COMP) + do_compress(outf, inf, max_size); + else + do_uncompress(outf, inf, max_size); + + return 0; +}
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/amdfwtool: Add new BIOS compression tool ......................................................................
Patch Set 1:
(7 comments)
https://review.coreboot.org/#/c/33401/1/util/cbfstool/amdcompress.c File util/cbfstool/amdcompress.c:
https://review.coreboot.org/#/c/33401/1/util/cbfstool/amdcompress.c@44 PS1, Line 44: printf("-m | --maxsize <HEX_VAL> Maximum uncompressed size (optional)\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/1/util/cbfstool/amdcompress.c@45 PS1, Line 45: printf(" * On compress: verify uncompressed size\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/1/util/cbfstool/amdcompress.c@46 PS1, Line 46: printf(" will be less than or equal maxsize\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/1/util/cbfstool/amdcompress.c@47 PS1, Line 47: printf(" * On uncompress: override default buffer size\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/1/util/cbfstool/amdcompress.c@48 PS1, Line 48: printf(" allocation of 0x%x bytes\n", UNCOMP_MAX); line over 80 characters
https://review.coreboot.org/#/c/33401/1/util/cbfstool/amdcompress.c@61 PS1, Line 61: if (fd < 0) { braces {} are not necessary for single statement blocks
https://review.coreboot.org/#/c/33401/1/util/cbfstool/amdcompress.c@158 PS1, Line 158: printf("\tError - size (%zx) exceeds specified max_size (%zx)\n", line over 80 characters
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33401
to look at the new patch set (#2).
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
util/cbfstool: Add AMD BIOS compression tool for PSP
Add a utility to generate a compressed BIOS image for AMD Family 17h.
If the input is an elf file, the utility extracts the program portion for compression. Otherwise the file is compressed as-is.
In modern AMD systems, the PSP brings up DRAM then uncompresses the BIOS image into memory prior to x86 beginning execution. The PSP supports a zlib engine, and interprets the first 256 bytes as a header, where offset 0x14 containing the uncompressed size. For further details, see AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h Processors (NDA only, #55758).
BUG=b:127766506 TEST=Use with WIP Picasso
Change-Id: Id1c54e0a6dae9e4a0362c6635fe8b8aa48a369d8 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M Makefile.inc M util/cbfstool/Makefile.inc A util/cbfstool/amdcompress.c 3 files changed, 348 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/33401/2
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 2:
(6 comments)
https://review.coreboot.org/#/c/33401/2/util/cbfstool/amdcompress.c File util/cbfstool/amdcompress.c:
https://review.coreboot.org/#/c/33401/2/util/cbfstool/amdcompress.c@44 PS2, Line 44: printf("-m | --maxsize <HEX_VAL> Maximum uncompressed size (optional)\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/2/util/cbfstool/amdcompress.c@45 PS2, Line 45: printf(" * On compress: verify uncompressed size\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/2/util/cbfstool/amdcompress.c@46 PS2, Line 46: printf(" will be less than or equal maxsize\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/2/util/cbfstool/amdcompress.c@47 PS2, Line 47: printf(" * On uncompress: override default buffer size\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/2/util/cbfstool/amdcompress.c@48 PS2, Line 48: printf(" allocation of 0x%x bytes\n", UNCOMP_MAX); line over 80 characters
https://review.coreboot.org/#/c/33401/2/util/cbfstool/amdcompress.c@157 PS2, Line 157: printf("\tError - size (%zx) exceeds specified max_size (%zx)\n", line over 80 characters
Martin Roth has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 2:
(2 comments)
https://review.coreboot.org/#/c/33401/2/Makefile.inc File Makefile.inc:
https://review.coreboot.org/#/c/33401/2/Makefile.inc@645 PS2, Line 645: Unrelated to this patch, I think we need to clean up this list of tools. amdfwtool and amdcompress should only be built by platforms that need them. The same goes for all of the other tools.
Specific to this patch, I worry about adding this because I'm afraid it's going to cause coreboot builds to fail if the user doesn't have the zlib library installed.
For now, let's just add the build for amdcompress into the picasso build when it comes along.
https://review.coreboot.org/#/c/33401/2/util/cbfstool/amdcompress.c File util/cbfstool/amdcompress.c:
PS2: Add a license header?
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 2:
(1 comment)
https://review.coreboot.org/#/c/33401/2/Makefile.inc File Makefile.inc:
https://review.coreboot.org/#/c/33401/2/Makefile.inc@645 PS2, Line 645:
...cause coreboot builds to fail if the user doesn't have the zlib library
Agree. I think I had that concern initially and you cited the lesson1 (I think) that installs it. Curious whether that changes your opinion at all? Granted we don't all stay up to date with the full list of requirements, and we deal with them individually as they arise. But your point is well-taken, someone may start failing due to an AMD tool when they're not on AMD.
For now, let's just add the build for amdcompress into the picasso build when it comes along.
I can do that easily enough. However, do we still build tools once for abuild? In other words, if Picasso isn't the first built, does that mean its build fails later because the utility isn't present? I think this is an example where you worked around a somewhat similar limitation before: https://review.coreboot.org/c/coreboot/+/17321 .
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33401
to look at the new patch set (#3).
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
util/cbfstool: Add AMD BIOS compression tool for PSP
Add a utility to generate a compressed BIOS image for AMD Family 17h.
If the input is an elf file, the utility extracts the program portion for compression. Otherwise the file is compressed as-is.
In modern AMD systems, the PSP brings up DRAM then uncompresses the BIOS image into memory prior to x86 beginning execution. The PSP supports a zlib engine, and interprets the first 256 bytes as a header, where offset 0x14 containing the uncompressed size. For further details, see AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h Processors (NDA only, #55758).
BUG=b:127766506 TEST=Use with WIP Picasso
Change-Id: Id1c54e0a6dae9e4a0362c6635fe8b8aa48a369d8 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M Makefile.inc M util/cbfstool/Makefile.inc A util/cbfstool/amdcompress.c 3 files changed, 365 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/33401/3
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 3:
(6 comments)
https://review.coreboot.org/#/c/33401/3/util/cbfstool/amdcompress.c File util/cbfstool/amdcompress.c:
https://review.coreboot.org/#/c/33401/3/util/cbfstool/amdcompress.c@59 PS3, Line 59: printf("-m | --maxsize <HEX_VAL> Maximum uncompressed size (optional)\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/3/util/cbfstool/amdcompress.c@60 PS3, Line 60: printf(" * On compress: verify uncompressed size\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/3/util/cbfstool/amdcompress.c@61 PS3, Line 61: printf(" will be less than or equal maxsize\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/3/util/cbfstool/amdcompress.c@62 PS3, Line 62: printf(" * On uncompress: override default buffer size\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/3/util/cbfstool/amdcompress.c@63 PS3, Line 63: printf(" allocation of 0x%x bytes\n", UNCOMP_MAX); line over 80 characters
https://review.coreboot.org/#/c/33401/3/util/cbfstool/amdcompress.c@172 PS3, Line 172: printf("\tError - size (%zx) exceeds specified max_size (%zx)\n", line over 80 characters
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 3:
(1 comment)
https://review.coreboot.org/#/c/33401/2/Makefile.inc File Makefile.inc:
https://review.coreboot.org/#/c/33401/2/Makefile.inc@645 PS2, Line 645:
However, do we still build tools once for abuild? In other words...
Well, I guess I have my answer. Looking at the best way to get around it now, but I'm open to suggestions for doing it correctly.
make[1]: *** No rule to make target '/cb-build/coreboot-gerrit.0/sharedutils/cbfstool/amdcompress', needed by 'tools'. Stop.
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 3:
(1 comment)
https://review.coreboot.org/#/c/33401/2/Makefile.inc File Makefile.inc:
https://review.coreboot.org/#/c/33401/2/Makefile.inc@645 PS2, Line 645:
However, do we still build tools once for abuild? In other words... […]
Martin, from what I can tell, the amdcompress utility never gets built unless somebody needs to use it. Seems I should just remove the ifeq()/endif and move on. I don't think anyone w/o zlib should be affected.
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33401
to look at the new patch set (#4).
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
util/cbfstool: Add AMD BIOS compression tool for PSP
Add a utility to generate a compressed BIOS image for AMD Family 17h.
If the input is an elf file, the utility extracts the program portion for compression. Otherwise the file is compressed as-is.
In modern AMD systems, the PSP brings up DRAM then uncompresses the BIOS image into memory prior to x86 beginning execution. The PSP supports a zlib engine, and interprets the first 256 bytes as a header, where offset 0x14 containing the uncompressed size. For further details, see AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h Processors (NDA only, #55758).
BUG=b:127766506 TEST=Use with WIP Picasso
Change-Id: Id1c54e0a6dae9e4a0362c6635fe8b8aa48a369d8 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M Makefile.inc M util/cbfstool/Makefile.inc A util/cbfstool/amdcompress.c 3 files changed, 363 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/33401/4
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 4:
(6 comments)
https://review.coreboot.org/#/c/33401/4/util/cbfstool/amdcompress.c File util/cbfstool/amdcompress.c:
https://review.coreboot.org/#/c/33401/4/util/cbfstool/amdcompress.c@59 PS4, Line 59: printf("-m | --maxsize <HEX_VAL> Maximum uncompressed size (optional)\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/4/util/cbfstool/amdcompress.c@60 PS4, Line 60: printf(" * On compress: verify uncompressed size\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/4/util/cbfstool/amdcompress.c@61 PS4, Line 61: printf(" will be less than or equal maxsize\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/4/util/cbfstool/amdcompress.c@62 PS4, Line 62: printf(" * On uncompress: override default buffer size\n"); line over 80 characters
https://review.coreboot.org/#/c/33401/4/util/cbfstool/amdcompress.c@63 PS4, Line 63: printf(" allocation of 0x%x bytes\n", UNCOMP_MAX); line over 80 characters
https://review.coreboot.org/#/c/33401/4/util/cbfstool/amdcompress.c@172 PS4, Line 172: printf("\tError - size (%zx) exceeds specified max_size (%zx)\n", line over 80 characters
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 4:
please add Documentation for the new compressed BIOS image, the different DRAM bring-up procedure, and the general bootflow compared to older x86 platforms.
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 4:
Patch Set 4:
please add Documentation for the new compressed BIOS image, the different DRAM bring-up procedure, and the general bootflow compared to older x86 platforms.
Nevermind. I found the existing documentation that describes the DRAM bring-up procedure.
Please document the compressed BIOS image layout required to boot the platform.
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 4:
Please document the compressed BIOS image layout required to boot the platform.
I've not seen any additional requirements on the BIOS layout for booting. Only that there should be a 256 byte header leading the image, where offset 0x14 contains the uncompressed size (as mentioned in the commit message and shown in the source).
Are you suggesting you'd like to see that detail in Documentation/soc/amd? That seems reasonable to me... As has been your experience, AMD still doesn't want to document the PSP information. That's the reason for showing minimal detail and citing the NDA doc for further reference.
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33401
to look at the new patch set (#5).
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
util/cbfstool: Add AMD BIOS compression tool for PSP
Add a utility to generate a compressed BIOS image for AMD Family 17h.
If the input is an elf file, the utility extracts the program portion for compression. Otherwise the file is compressed as-is.
In modern AMD systems, the PSP brings up DRAM then uncompresses the BIOS image into memory prior to x86 beginning execution. The PSP supports a zlib engine, and interprets the first 256 bytes as a header, where offset 0x14 containing the uncompressed size. For further details, see AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h Processors (NDA only, #55758).
BUG=b:127766506 TEST=Use with WIP Picasso
Change-Id: Id1c54e0a6dae9e4a0362c6635fe8b8aa48a369d8 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M Makefile.inc M util/cbfstool/Makefile.inc A util/cbfstool/amdcompress.c 3 files changed, 363 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/33401/5
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 5:
Marshall Dawson: Uploaded patch set 5.
Manual rebase.
Martin Roth has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 5: Code-Review+2
Please document the compressed BIOS image layout required to boot the platform.
Currently we're only compressing the romstage, which doesn't really require any additional documentation. Eventually we'll probably want to compress more, so at that point, when things are better defined, we'll create a document.
I've created a support issue for this: https://ticket.coreboot.org/issues/215 and it's being tracked in google's bugtracker as well.
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 5:
(23 comments)
Hi Marshall,
Please kindly see my suggests more for the sake of robustness here.
Thanks, Edward.
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c File util/cbfstool/amdcompress.c:
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@118 PS5, Line 118: char *in_buf, *out_buf; drop `char *in_buf`
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@124 PS5, Line 124: in_fd = do_file(inf, &size_unc, O_RDONLY); `in_fd = do_file(inf, &inbf.size, O_RDONLY);`
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@138 PS5, Line 138: in_buf = malloc(size_unc); `inbf.data = calloc(1, inbf.size);`
Use in general `s/malloc(/calloc(1, /` as calloc zero's the buffer at instantiation.
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@141 PS5, Line 141: size_unc); s/size_unc/inbf.size/
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@146 PS5, Line 146: bytes = read(in_fd, in_buf, size_unc); `if (read(in_fd, inbf.data, inbf.size) != inbf.size) {`
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@147 PS5, Line 147: if (bytes != size_unc) { remove
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@153 PS5, Line 153: struct buffer inbf; Move into function pre-amble.
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@154 PS5, Line 154: inbf.data = in_buf; remove
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@155 PS5, Line 155: inbf.size = size_unc; remove
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@157 PS5, Line 157: if (iself(in_buf)) { `if (iself(inbf.data)) {`
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@158 PS5, Line 158: /* if elf, convert the in_buf to point to the progbits */ s/in_buf/inbf.data/
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@165 PS5, Line 165: free(in_buf); ``` free(inbf.data); inbf.data = NULL; inbf.size = 0; ```
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@166 PS5, Line 166: in_buf = bios_buf.data; The `in_buf` reuse is a bit awkward. Please see my suggested rework above (can be in a follow up commit).
remove
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@167 PS5, Line 167: size_unc = bios_buf.size; remove
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@170 PS5, Line 170: size_comp = size_unc; /* todo: tbd worst case? */ s/size_unc/bios_buf.size/
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@171 PS5, Line 171: if (max_size && size_unc > max_size) { s/size_unc/bios_buf.size/
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@173 PS5, Line 173: size_unc, max_size); s/size_unc/bios_buf.size/
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@178 PS5, Line 178: out_buf = malloc(size_comp + sizeof(header)); s/malloc(/calloc(1, /
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@187 PS5, Line 187: (Bytef *)in_buf, size_unc); s/in_buf/bios_buf.data/ s/size_unc/bios_buf.size/
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@196 PS5, Line 196: size_unc, size_comp); s/size_unc/bios_buf.size/
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@211 PS5, Line 211: free(in_buf); `free(bios_buf.data);`
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@243 PS5, Line 243: in_buf = malloc(size_comp); s/malloc(/calloc(1, /
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@261 PS5, Line 261: out_buf = malloc(size_unc); s/malloc(/calloc(1, /
Martin Roth has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 5:
Marshall, how do you want to address Edward's comments? Do you want to address these in a follow-on or update this commit?
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 5:
Marshall, how do you want to address Edward's comments? Do you want to address these in a follow-on or update this commit?
Sorry for the delay. I have a change that I'm quite sure still functions but I'd really like to verify it on hardware before repushing. Running out of hours today so hopefully tomorrow afternoon.
Hello Edward O'Callaghan, build bot (Jenkins), Raul Rangel, Martin Roth, Furquan Shaikh,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33401
to look at the new patch set (#6).
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
util/cbfstool: Add AMD BIOS compression tool for PSP
Add a utility to generate a compressed BIOS image for AMD Family 17h.
If the input is an elf file, the utility extracts the program portion for compression. Otherwise the file is compressed as-is.
In modern AMD systems, the PSP brings up DRAM then uncompresses the BIOS image into memory prior to x86 beginning execution. The PSP supports a zlib engine, and interprets the first 256 bytes as a header, where offset 0x14 containing the uncompressed size. For further details, see AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h Processors (NDA only, #55758).
BUG=b:127766506 TEST=Use with WIP Picasso
Change-Id: Id1c54e0a6dae9e4a0362c6635fe8b8aa48a369d8 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M Makefile.inc M util/cbfstool/Makefile.inc A util/cbfstool/amdcompress.c 3 files changed, 379 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/33401/6
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 6:
(23 comments)
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c File util/cbfstool/amdcompress.c:
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@118 PS5, Line 118: char *in_buf, *out_buf;
drop `char *in_buf`
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@124 PS5, Line 124: in_fd = do_file(inf, &size_unc, O_RDONLY);
`in_fd = do_file(inf, &inbf. […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@138 PS5, Line 138: in_buf = malloc(size_unc);
`inbf.data = calloc(1, inbf.size);` […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@141 PS5, Line 141: size_unc);
s/size_unc/inbf. […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@146 PS5, Line 146: bytes = read(in_fd, in_buf, size_unc);
`if (read(in_fd, inbf.data, inbf.size) != inbf. […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@147 PS5, Line 147: if (bytes != size_unc) {
remove
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@153 PS5, Line 153: struct buffer inbf;
Move into function pre-amble.
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@154 PS5, Line 154: inbf.data = in_buf;
remove
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@155 PS5, Line 155: inbf.size = size_unc;
remove
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@157 PS5, Line 157: if (iself(in_buf)) {
`if (iself(inbf. […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@158 PS5, Line 158: /* if elf, convert the in_buf to point to the progbits */
s/in_buf/inbf. […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@165 PS5, Line 165: free(in_buf);
Relocated. See what you think.
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@166 PS5, Line 166: in_buf = bios_buf.data;
The `in_buf` reuse is a bit awkward. […]
Relocated to a separate function but still reusing. See what you think.
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@167 PS5, Line 167: size_unc = bios_buf.size;
remove
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@170 PS5, Line 170: size_comp = size_unc; /* todo: tbd worst case? */
s/size_unc/bios_buf. […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@171 PS5, Line 171: if (max_size && size_unc > max_size) {
s/size_unc/bios_buf. […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@173 PS5, Line 173: size_unc, max_size);
s/size_unc/bios_buf. […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@178 PS5, Line 178: out_buf = malloc(size_comp + sizeof(header));
s/malloc(/calloc(1, /
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@187 PS5, Line 187: (Bytef *)in_buf, size_unc);
s/in_buf/bios_buf.data/ […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@196 PS5, Line 196: size_unc, size_comp);
s/size_unc/bios_buf. […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@211 PS5, Line 211: free(in_buf);
`free(bios_buf. […]
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@243 PS5, Line 243: in_buf = malloc(size_comp);
s/malloc(/calloc(1, /
Done
https://review.coreboot.org/#/c/33401/5/util/cbfstool/amdcompress.c@261 PS5, Line 261: out_buf = malloc(size_unc);
s/malloc(/calloc(1, /
Done
Raul Rangel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 6: Code-Review+2
(2 comments)
https://review.coreboot.org/#/c/33401/6/util/cbfstool/amdcompress.c File util/cbfstool/amdcompress.c:
https://review.coreboot.org/#/c/33401/6/util/cbfstool/amdcompress.c@70 PS6, Line 70: char const char *name
https://review.coreboot.org/#/c/33401/6/util/cbfstool/amdcompress.c@127 PS6, Line 127: /* todo: Consider using deflate() and inflate() instead of compress() and Do we need to keep the todo?
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 6: Code-Review+2
I think we want all the error paths to probably go to stderr instead of stdout. However i'll probably just make a quick follow up to sort out those misc things.
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
Patch Set 6:
Raul, had hoped to get to your suggestions today, but now will plan follow-on changes instead.
Martin Roth has submitted this change and it was merged. ( https://review.coreboot.org/c/coreboot/+/33401 )
Change subject: util/cbfstool: Add AMD BIOS compression tool for PSP ......................................................................
util/cbfstool: Add AMD BIOS compression tool for PSP
Add a utility to generate a compressed BIOS image for AMD Family 17h.
If the input is an elf file, the utility extracts the program portion for compression. Otherwise the file is compressed as-is.
In modern AMD systems, the PSP brings up DRAM then uncompresses the BIOS image into memory prior to x86 beginning execution. The PSP supports a zlib engine, and interprets the first 256 bytes as a header, where offset 0x14 containing the uncompressed size. For further details, see AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h Processors (NDA only, #55758).
BUG=b:127766506 TEST=Use with WIP Picasso
Change-Id: Id1c54e0a6dae9e4a0362c6635fe8b8aa48a369d8 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com Reviewed-on: https://review.coreboot.org/c/coreboot/+/33401 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Raul Rangel rrangel@chromium.org Reviewed-by: Edward O'Callaghan quasisec@chromium.org --- M Makefile.inc M util/cbfstool/Makefile.inc A util/cbfstool/amdcompress.c 3 files changed, 379 insertions(+), 1 deletion(-)
Approvals: build bot (Jenkins): Verified Raul Rangel: Looks good to me, approved Edward O'Callaghan: Looks good to me, approved
diff --git a/Makefile.inc b/Makefile.inc index 362243e..28f1363 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -514,6 +514,7 @@ RMODTOOL:=$(objutil)/cbfstool/rmodtool IFWITOOL:=$(objutil)/cbfstool/ifwitool IFITTOOL:=$(objutil)/cbfstool/ifittool +AMDCOMPRESS:=$(objutil)/cbfstool/amdcompress
$(obj)/cbfstool: $(CBFSTOOL) cp $< $@ @@ -530,6 +531,9 @@ $(obj)/ifittool: $(IFITTOOL) cp $< $@
+$(obj)/amdcompress: $(AMDCOMPRESS) + cp $< $@ + _WINCHECK=$(shell uname -o 2> /dev/null) STACK= ifeq ($(_WINCHECK),Msys) @@ -642,7 +646,7 @@ include util/crossgcc/Makefile.inc
.PHONY: tools -tools: $(objutil)/kconfig/conf $(CBFSTOOL) $(objutil)/cbfstool/cbfs-compression-tool $(FMAPTOOL) $(RMODTOOL) $(IFWITOOL) $(objutil)/nvramtool/nvramtool $(ROMCC_BIN) $(objutil)/sconfig/sconfig $(IFDTOOL) $(CBOOTIMAGE) $(AMDFWTOOL) $(FUTILITY) $(BINCFG) $(IFITTOOL) +tools: $(objutil)/kconfig/conf $(CBFSTOOL) $(objutil)/cbfstool/cbfs-compression-tool $(FMAPTOOL) $(RMODTOOL) $(IFWITOOL) $(objutil)/nvramtool/nvramtool $(ROMCC_BIN) $(objutil)/sconfig/sconfig $(IFDTOOL) $(CBOOTIMAGE) $(AMDFWTOOL) $(AMDCOMPRESS) $(FUTILITY) $(BINCFG) $(IFITTOOL)
########################################################################### # Common recipes for all stages diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc index efc3dca..95372c2 100644 --- a/util/cbfstool/Makefile.inc +++ b/util/cbfstool/Makefile.inc @@ -98,6 +98,12 @@ cbfscompobj += $(compressionobj) cbfscompobj += cbfscomptool.o
+amdcompobj := +amdcompobj += amdcompress.o +amdcompobj += elfheaders.o +amdcompobj += common.o +amdcompobj += xdr.o + TOOLCFLAGS ?= -Werror -Wall -Wextra TOOLCFLAGS += -Wcast-qual -Wmissing-prototypes -Wredundant-decls -Wshadow TOOLCFLAGS += -Wstrict-prototypes -Wwrite-strings @@ -185,6 +191,10 @@ printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n" $(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(cbfscompobj))
+$(objutil)/cbfstool/amdcompress: $(addprefix $(objutil)/cbfstool/,$(amdcompobj)) + printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n" + $(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(amdcompobj)) -lz + # Yacc source is superset of header $(objutil)/cbfstool/fmd.o: TOOLCFLAGS += -Wno-redundant-decls $(objutil)/cbfstool/fmd_parser.o: TOOLCFLAGS += -Wno-redundant-decls diff --git a/util/cbfstool/amdcompress.c b/util/cbfstool/amdcompress.c new file mode 100644 index 0000000..641e1ea --- /dev/null +++ b/util/cbfstool/amdcompress.c @@ -0,0 +1,364 @@ +/* + * AMD Family 17h and later BIOS compressor + * + * Copyright (C) 2019 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <getopt.h> +#include <elfparsing.h> +#include "zlib.h" + +#define DEBUG_FILE 0 + +#define HDR_SIZE 256 +#define UNCOMP_MAX 0x300000 + +#define DIR_UNDEF 0 +#define DIR_COMP 1 +#define DIR_UNCOMP 2 + +typedef struct _header { + uint32_t rsvd1[5]; + uint32_t size; + uint32_t rsvd2[58]; +} __attribute__((packed)) header; + +static const char *optstring = "i:o:cm:uh"; + +static struct option long_options[] = { + {"infile", required_argument, 0, 'i' }, + {"outfile", required_argument, 0, 'o' }, + {"compress", required_argument, 0, 'c' }, + {"maxsize", required_argument, 0, 'h' }, + {"uncompress", required_argument, 0, 'u' }, + {"help", no_argument, 0, 'h' }, +}; + +static void usage(void) +{ + printf("<name>: Extract or create a zlib compressed BIOS binary\n"); + printf(" image. A compressed image contains a 256 byte\n"); + printf(" header with a 32-bit size at 0x14.\n"); + printf("Usage: <name> -i in_file -o out_file -[c|u]\n"); + printf("-i | --infile <FILE> Input file\n"); + printf("-o | --outfile <FILE> Output file\n"); + printf("-c | --compress Compress\n"); + printf("-m | --maxsize <HEX_VAL> Maximum uncompressed size (optional)\n"); + printf(" * On compress: verify uncompressed size\n"); + printf(" will be less than or equal maxsize\n"); + printf(" * On uncompress: override default buffer size\n"); + printf(" allocation of 0x%x bytes\n", UNCOMP_MAX); + printf("-u | --uncompress Uncompress\n"); + printf("-h | --help Display this message\n"); + + exit(1); +} + +static int do_file(char *name, size_t *size, int oflag) +{ + struct stat fd_stat; + int fd; + + fd = open(name, oflag, 0666); + if (fd < 0) + return -1; + + if (fstat(fd, &fd_stat)) { + close(fd); + return -1; + } + + if (size) + *size = fd_stat.st_size; + return fd; +} + +static int parse_elf_to_xip_ram(const struct buffer *input, + struct buffer *output) +{ + struct parsed_elf pelf; + + if (parse_elf(input, &pelf, ELF_PARSE_ALL)) + return 1; + if (buffer_create(output, pelf.phdr->p_filesz, "") != 0) + return 1; + + memcpy(output->data, input->data + pelf.phdr->p_offset, output->size); + + return 0; +} + +static int convert_elf(struct buffer *buf) +{ + struct buffer out; + + if (parse_elf_to_xip_ram(buf, &out)) { + printf("\tError parsing ELF file\n"); + return -1; + } + + /* Discard the elf file in buf and replace with the progbits */ + free(buf->data); + buf->data = out.data; + buf->size = out.size; + + return 0; +} + +static int iself(const void *input) +{ + const Elf32_Ehdr *ehdr = input; + return !memcmp(ehdr->e_ident, ELFMAG, 4); +} + +/* todo: Consider using deflate() and inflate() instead of compress() and + * decompress(), especially if memory allocation somehow becomes a problem. + * Those two functions can operate on streams and process chunks of data. + */ + +/* Build the required header and follow it with the compressed image. Detect + * whether the input is an elf image, and if so, compress only the progbits. + * + * header + * 0 +------+-------+-------+-------+ + * | | | | | + * +----------------------+-------+ + * | | size | | | + * +----------------------+-------+ + * | | | | | + * | | | ... | + * 256 +------------------------------+ + * |compressed image | + * | ... | + * | ... | + * | ... | + * n +------------------------------+ + */ +static void do_compress(char *outf, char *inf, size_t max_size) +{ + int out_fd, in_fd; + struct buffer inbf, outbf; + int err; + + in_fd = do_file(inf, &inbf.size, O_RDONLY); + if (in_fd < 0) { + printf("\tError opening input file %s\n", inf); + err = 1; + goto out; + } + + out_fd = do_file(outf, 0, O_CREAT | O_WRONLY); + if (out_fd < 0) { + printf("\tError opening output file %s\n", outf); + err = 1; + goto out_close_in; + } + + inbf.data = calloc(inbf.size, 1); + if (!inbf.data) { + printf("\tError allocating 0x%zx bytes for input buffer\n", inbf.size); + err = 1; + goto out_close_out; + } + + if (read(in_fd, inbf.data, inbf.size) != (ssize_t)inbf.size) { + printf("\tError reading input file %s\n", inf); + err = 1; + goto out_free_in; + } + + if (iself(inbf.data)) { + if (convert_elf(&inbf)) { + err = 1; + goto out_free_in; + } + } + + if (max_size && inbf.size > max_size) { + printf("\tError - size (%zx) exceeds specified max_size (%zx)\n", + inbf.size, max_size); + err = 1; + goto out_free_in; + } + + outbf.size = inbf.size; /* todo: tbd worst case? */ + outbf.size += sizeof(header); + outbf.data = calloc(outbf.size, 1); + if (!outbf.size) { + printf("\tError allocating 0x%zx bytes for output buffer\n", outbf.size); + err = 1; + goto out_free_in; + } + + err = compress((Bytef *)(outbf.data + sizeof(header)), &outbf.size, + (Bytef *)inbf.data, inbf.size); + if (err != Z_OK) { + printf("\tzlib compression error %d\n", err); + err = 1; + goto out_free_out; + } + + if (DEBUG_FILE) + printf("\tCompressed 0x%zx bytes into 0x%zx\n", inbf.size, + outbf.size - sizeof(header)); + + ((header *)outbf.data)->size = outbf.size; + + if (write(out_fd, outbf.data, outbf.size + sizeof(header)) + != (ssize_t)(outbf.size + sizeof(header))) { + printf("\tError writing to %s\n", outf); + err = 1; + /* fall through to out_free_out */ + } + +out_free_out: + free(outbf.data); +out_free_in: + free(inbf.data); +out_close_out: + close(out_fd); +out_close_in: + close(in_fd); +out: + if (err) + exit(err); +} + +static void do_uncompress(char *outf, char *inf, size_t max_size) +{ + int out_fd, in_fd; + char *in_buf, *out_buf; + size_t size_unc, size_comp; + size_t bytes; + int err; + + in_fd = do_file(inf, &size_comp, O_RDONLY); + if (in_fd < 0) { + printf("\tError opening input file %s\n", inf); + err = 1; + goto out; + } + + out_fd = do_file(outf, 0, O_CREAT | O_WRONLY); + if (out_fd < 0) { + printf("\tError opening output file %s\n", outf); + err = 1; + goto out_close_in; + } + + in_buf = calloc(size_comp, 1); + if (!in_buf) { + printf("\tError allocating 0x%zx bytes for input buffer\n", size_comp); + err = 1; + goto out_close_out; + } + + bytes = read(in_fd, in_buf, size_comp); + if (bytes != size_comp) { + printf("\tError reading input file %s\n", inf); + err = 1; + goto out_free_in; + } + + size_comp = ((header *)in_buf)->size; + + size_unc = max_size ? max_size : UNCOMP_MAX; + out_buf = calloc(size_unc, 1); + if (!out_buf) { + printf("\tError allocating 0x%zx bytes for output buffer\n", size_unc); + err = 1; + goto out_free_in; + } + + err = uncompress((Bytef *)out_buf, &size_unc, + (Bytef *)in_buf + sizeof(header), size_comp); + if (err != Z_OK) { + printf("\tzlib uncompression error %d\n", err); + err = 1; + goto out_free_out; + } + + if (DEBUG_FILE) + printf("Uncompressed 0x%zx bytes into 0x%zx\n", size_comp, size_unc); + + bytes = write(out_fd, out_buf, size_unc); + if (bytes != size_unc) { + printf("\tError writing to %s\n", outf); + err = 1; + /* fall through to out_free_out */ + } + +out_free_out: + free(out_buf); +out_free_in: + free(in_buf); +out_close_out: + close(out_fd); +out_close_in: + close(in_fd); +out: + if (err) + exit(err); +} + +int main(int argc, char *argv[]) +{ + int c; + char *inf = 0, *outf = 0, *scratch; + int direction = DIR_UNDEF; + size_t max_size = 0; + + while (1) { + int optindex = 0; + + c = getopt_long(argc, argv, optstring, long_options, &optindex); + if (c == -1) + break; + + switch (c) { + case 'i': + inf = optarg; + break; + case 'o': + outf = optarg; + break; + case 'c': + if (direction != DIR_UNDEF) + usage(); + direction = DIR_COMP; + break; + case 'u': + if (direction != DIR_UNDEF) + usage(); + direction = DIR_UNCOMP; + break; + case 'm': + max_size = strtoull(optarg, &scratch, 16); + break; + case 'h': + usage(); + } + } + if (!inf || !outf || direction == DIR_UNDEF) + usage(); + + if (direction == DIR_COMP) + do_compress(outf, inf, max_size); + else + do_uncompress(outf, inf, max_size); + + return 0; +}