Used commands: perl -i -p0e 's|\/\*[\s*]*.*is free software[:;][\s*]*you[\s*]*can[\s*]*redistribute[\s*]*it[\s*]*and\/or[\s*]*modify[\s*]*it[\s*]*under[\s*]*the[\s*]*terms[\s*]*of[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*as[\s*]*published[\s*]*by[\s*]*the[\s*]*Free[\s*]*Software[\s*]*Foundation[;,][\s*]*version[\s*]*2[\s*]*of[\s*]*the[\s*]*License.[\s*]*This[\s*]*program[\s*]*is[\s*]*distributed[\s*]*in[\s*]*the[\s*]*hope[\s*]*that[\s*]*it[\s*]*will[\s*]*be[\s*]*useful,[\s*]*but[\s*]*WITHOUT[\s*]*ANY[\s*]*WARRANTY;[\s*]*without[\s*]*even[\s*]*the[\s*]*implied[\s*]*warranty[\s*]*of[\s*]*MERCHANTABILITY[\s*]*or[\s*]*FITNESS[\s*]*FOR[\s*]*A[\s*]*PARTICULAR[\s*]*PURPOSE.[\s*]*See[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*for[\s*]*more[\s*]*details.[\s*]*\*\/|/* SPDX-License-Identifier: GPL-2.0-only */|' $(cat filelist) perl -i -p0e 's|This[\s*]*program[\s*]*is[\s*]*free[\s*]*software[:;][\s*]*you[\s*]*can[\s*]*redistribute[\s*]*it[\s*]*and/or[\s*]*modify[\s*]*it[\s*]*under[\s*]*the[\s*]*terms[\s*]*of[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*as[\s*]*published[\s*]*by[\s*]*the[\s*]*Free[\s*]*Software[\s*]*Foundation[;,][\s*]*either[\s*]*version[\s*]*2[\s*]*of[\s*]*the[\s*]*License,[\s*]*or[\s*]*.at[\s*]*your[\s*]*option.*[\s*]*any[\s*]*later[\s*]*version.[\s*]*This[\s*]*program[\s*]*is[\s*]*distributed[\s*]*in[\s*]*the[\s*]*hope[\s*]*that[\s*]*it[\s*]*will[\s*]*be[\s*]*useful,[\s*]*but[\s*]*WITHOUT[\s*]*ANY[\s*]*WARRANTY;[\s*]*without[\s*]*even[\s*]*the[\s*]*implied[\s*]*warranty[\s*]*of[\s*]*MERCHANTABILITY[\s*]*or[\s*]*FITNESS[\s*]*FOR[\s*]*A[\s*]*PARTICULAR[\s*]*PURPOSE.[\s*]*See[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*for[\s*]*more[\s*]*details.[\s*]*\*\/|/* SPDX-License-Identifier: GPL-2.0-or-later */|' $(cat filelist) perl -i -p0e 's|\/\*[\s*]*.*This[\s*#]*program[\s*#]*is[\s*#]*free[\s*#]*software[;:,][\s*#]*you[\s*#]*can[\s*#]*redistribute[\s*#]*it[\s*#]*and/or[\s*#]*modify[\s*#]*it[\s*#]*under[\s*#]*the[\s*#]*terms[\s*#]*of[\s*#]*the[\s*#]*GNU[\s*#]*General[\s*#]*Public[\s*#]*License[\s*#]*as[\s*#]*published[\s*#]*by[\s*#]*the[\s*#]*Free[\s*#]*Software[\s*#]*Foundation[;:,][\s*#]*either[\s*#]*version[\s*#]*3[\s*#]*of[\s*#]*the[\s*#]*License[;:,][\s*#]*or[\s*#]*.at[\s*#]*your[\s*#]*option.*[\s*#]*any[\s*#]*later[\s*#]*version.[\s*#]*This[\s*#]*program[\s*#]*is[\s*#]*distributed[\s*#]*in[\s*#]*the[\s*#]*hope[\s*#]*that[\s*#]*it[\s*#]*will[\s*#]*be[\s*#]*useful[;:,][\s*#]*but[\s*#]*WITHOUT[\s*#]*ANY[\s*#]*WARRANTY[;:,][\s*#]*without[\s*#]*even[\s*#]*the[\s*#]*implied[\s*#]*warranty[\s*#]*of[\s*#]*MERCHANTABILITY[\s*#]*or[\s*#]*FITNESS[\s*#]*FOR[\s*#]*A[\s*#]*PARTICULAR[\s*#]*PURPOSE.[\s*#]*See[\s*#]*the[\s*#]*GNU[\s*#]*General[\s*#]*Public[\s*#]*License[\s*#]*for[\s*#]*more[\s*#]*details.[\s*]*\*\/|/* SPDX-License-Identifier: GPL-3.0-or-later */|' $(cat filelist) perl -i -p0e 's|(\#\#*)[\w]*.*is free software[:;][\#\s]*you[\#\s]*can[\#\s]*redistribute[\#\s]*it[\#\s]*and\/or[\#\s]*modify[\#\s]*it[\s\#]*under[\s \#]*the[\s\#]*terms[\s\#]*of[\s\#]*the[\s\#]*GNU[\s\#]*General[\s\#]*Public[\s\#]*License[\s\#]*as[\s\#]*published[\s\#]*by[\s\#]*the[\s\#]*Free[\s\#]*Software[\s\#]*Foundation[;,][\s\#]*version[\s\#]*2[\s\#]*of[\s\#]*the[\s\#]*License.*[\s\#]*This[\s\#]*program[\s\#]*is[\s\#]*distributed[\s\#]*in[\s\#]*the[\s\#]*hope[\s\#]*that[\s\#]*it[\s\#]*will[\#\s]*be[\#\s]*useful,[\#\s]*but[\#\s]*WITHOUT[\#\s]*ANY[\#\s]*WARRANTY;[\#\s]*without[\#\s]*even[\#\s]*the[\#\s]*implied[\#\s]*warranty[\#\s]*of[\#\s]*MERCHANTABILITY[\#\s]*or[\#\s]*FITNESS[\#\s]*FOR[\#\s]*A[\#\s]*PARTICULAR[\#\s]*PURPOSE.[\#\s]*See[\#\s]*the[\#\s]*GNU[\#\s]*General[\#\s]*Public[\#\s]*License[\#\s]*for[\#\s]*more[\#\s]*details.\s(#* *\n)*|\1 SPDX-License-Identifier: GPL-2.0-only\n\n|' $(cat filelist) perl -i -p0e 's|(\#\#*)[\w*]*.*is free software[:;][\s*]*you[\s*]*can[\s*]*redistribute[\s*]*it[\s*]*and\/or[\s*]*modify[\s*]*it[\s*]*under[\s*]*the[\s*]*terms[\s*]*of[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*as[\s*]*published[\s*]*by[\s*]*the[\s*]*Free[\s*]*Software[\s*]*Foundation[;,][\s*]*version[\s*]*2[\s*]*of[\s*]*the[\s*]*License.[\s*]*This[\s*]*program[\s*]*is[\s*]*distributed[\s*]*in[\s*]*the[\s*]*hope[\s*]*that[\s*]*it[\s*]*will[\s*]*be[\s*]*useful,[\s*]*but[\s*]*WITHOUT[\s*]*ANY[\s*]*WARRANTY;[\s*]*without[\s*]*even[\s*]*the[\s*]*implied[\s*]*warranty[\s*]*of[\s*]*MERCHANTABILITY[\s*]*or[\s*]*FITNESS[\s*]*FOR[\s*]*A[\s*]*PARTICULAR[\s*]*PURPOSE.[\s*]*See[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*for[\s*]*more[\s*]*details.\s(#* *\n)*|\1 SPDX-License-Identifier: GPL-2.0-only\n\n|' $(cat filelist) Change-Id: I1008a63b804f355a916221ac994701d7584f60ff Signed-off-by: Patrick Georgi <pgeorgi@google.com> Signed-off-by: Elyes HAOUAS <ehaouas@noos.fr> Reviewed-on: https://review.coreboot.org/c/coreboot/+/41177 Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
		
			
				
	
	
		
			353 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			353 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* AMD Family 17h and later BIOS compressor */
 | |
| /* SPDX-License-Identifier: GPL-2.0-only */
 | |
| 
 | |
| #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;
 | |
| }
 |