1 /* AMD Family 17h and later BIOS compressor */
2 /* SPDX-License-Identifier: GPL-2.0-only */
9 #include <elfparsing.h>
15 #define UNCOMP_MAX 0x300000
21 typedef struct _header
{
25 } __attribute__((packed
)) header
;
27 static const char *optstring
= "i:o:cm:uh";
29 static struct option long_options
[] = {
30 {"infile", required_argument
, 0, 'i' },
31 {"outfile", required_argument
, 0, 'o' },
32 {"compress", no_argument
, 0, 'c' },
33 {"maxsize", required_argument
, 0, 'm' },
34 {"uncompress", no_argument
, 0, 'u' },
35 {"help", no_argument
, 0, 'h' },
38 static void usage(void)
40 printf("<name>: Extract or create a zlib compressed BIOS binary\n");
41 printf(" image. A compressed image contains a 256 byte\n");
42 printf(" header with a 32-bit size at 0x14.\n");
43 printf("Usage: <name> -i in_file -o out_file -[c|u]\n");
44 printf("-i | --infile <FILE> Input file\n");
45 printf("-o | --outfile <FILE> Output file\n");
46 printf("-c | --compress Compress\n");
47 printf("-m | --maxsize <HEX_VAL> Maximum uncompressed size (optional)\n");
48 printf(" * On compress: verify uncompressed size\n");
49 printf(" will be less than or equal maxsize\n");
50 printf(" * On uncompress: override default buffer size\n");
51 printf(" allocation of 0x%x bytes\n", UNCOMP_MAX
);
52 printf("-u | --uncompress Uncompress\n");
53 printf("-h | --help Display this message\n");
58 static int do_file(char *name
, size_t *size
, int oflag
)
63 fd
= open(name
, oflag
, 0666);
67 if (fstat(fd
, &fd_stat
)) {
73 *size
= fd_stat
.st_size
;
77 static int parse_elf_to_xip_ram(const struct buffer
*input
,
78 struct buffer
*output
)
80 struct parsed_elf pelf
;
82 if (parse_elf(input
, &pelf
, ELF_PARSE_ALL
))
84 if (buffer_create(output
, pelf
.phdr
->p_filesz
, "") != 0)
87 memcpy(output
->data
, input
->data
+ pelf
.phdr
->p_offset
, output
->size
);
92 static int convert_elf(struct buffer
*buf
)
96 if (parse_elf_to_xip_ram(buf
, &out
)) {
97 printf("\tError parsing ELF file\n");
101 /* Discard the elf file in buf and replace with the progbits */
103 buf
->data
= out
.data
;
104 buf
->size
= out
.size
;
109 static int iself(const void *input
)
111 const Elf32_Ehdr
*ehdr
= input
;
112 return !memcmp(ehdr
->e_ident
, ELFMAG
, 4);
115 /* todo: Consider using deflate() and inflate() instead of compress() and
116 * decompress(), especially if memory allocation somehow becomes a problem.
117 * Those two functions can operate on streams and process chunks of data.
120 /* Build the required header and follow it with the compressed image. Detect
121 * whether the input is an elf image, and if so, compress only the progbits.
124 * 0 +------+-------+-------+-------+
126 * +----------------------+-------+
128 * +----------------------+-------+
131 * 256 +------------------------------+
132 * |compressed image |
136 * n +------------------------------+
138 static void do_compress(char *outf
, char *inf
, size_t max_size
)
141 struct buffer inbf
, outbf
;
144 in_fd
= do_file(inf
, &inbf
.size
, O_RDONLY
);
146 printf("\tError opening input file %s\n", inf
);
151 out_fd
= do_file(outf
, 0, O_CREAT
| O_WRONLY
);
153 printf("\tError opening output file %s\n", outf
);
158 inbf
.data
= calloc(inbf
.size
, 1);
160 printf("\tError allocating 0x%zx bytes for input buffer\n", inbf
.size
);
165 if (read(in_fd
, inbf
.data
, inbf
.size
) != (ssize_t
)inbf
.size
) {
166 printf("\tError reading input file %s\n", inf
);
171 if (iself(inbf
.data
)) {
172 if (convert_elf(&inbf
)) {
178 if (max_size
&& inbf
.size
> max_size
) {
179 printf("\tError - size (%zx) exceeds specified max_size (%zx)\n",
180 inbf
.size
, max_size
);
185 outbf
.size
= inbf
.size
; /* todo: tbd worst case? */
186 outbf
.size
+= sizeof(header
);
187 outbf
.data
= calloc(outbf
.size
, 1);
189 printf("\tError allocating 0x%zx bytes for output buffer\n", outbf
.size
);
194 err
= compress((Bytef
*)(outbf
.data
+ sizeof(header
)), &outbf
.size
,
195 (Bytef
*)inbf
.data
, inbf
.size
);
197 printf("\tzlib compression error %d\n", err
);
203 printf("\tCompressed 0x%zx bytes into 0x%zx\n", inbf
.size
,
204 outbf
.size
- sizeof(header
));
206 ((header
*)outbf
.data
)->size
= outbf
.size
;
208 if (write(out_fd
, outbf
.data
, outbf
.size
+ sizeof(header
))
209 != (ssize_t
)(outbf
.size
+ sizeof(header
))) {
210 printf("\tError writing to %s\n", outf
);
212 /* fall through to out_free_out */
228 static void do_uncompress(char *outf
, char *inf
, size_t max_size
)
231 char *in_buf
, *out_buf
;
232 size_t size_unc
, size_comp
;
236 in_fd
= do_file(inf
, &size_comp
, O_RDONLY
);
238 printf("\tError opening input file %s\n", inf
);
243 out_fd
= do_file(outf
, 0, O_CREAT
| O_WRONLY
);
245 printf("\tError opening output file %s\n", outf
);
250 in_buf
= calloc(size_comp
, 1);
252 printf("\tError allocating 0x%zx bytes for input buffer\n", size_comp
);
257 bytes
= read(in_fd
, in_buf
, size_comp
);
258 if (bytes
!= size_comp
) {
259 printf("\tError reading input file %s\n", inf
);
264 size_comp
= ((header
*)in_buf
)->size
;
266 size_unc
= max_size
? max_size
: UNCOMP_MAX
;
267 out_buf
= calloc(size_unc
, 1);
269 printf("\tError allocating 0x%zx bytes for output buffer\n", size_unc
);
274 err
= uncompress((Bytef
*)out_buf
, &size_unc
,
275 (Bytef
*)in_buf
+ sizeof(header
), size_comp
);
277 printf("\tzlib uncompression error %d\n", err
);
283 printf("Uncompressed 0x%zx bytes into 0x%zx\n", size_comp
, size_unc
);
285 bytes
= write(out_fd
, out_buf
, size_unc
);
286 if (bytes
!= size_unc
) {
287 printf("\tError writing to %s\n", outf
);
289 /* fall through to out_free_out */
305 int main(int argc
, char *argv
[])
308 char *inf
= 0, *outf
= 0, *scratch
;
309 int direction
= DIR_UNDEF
;
315 c
= getopt_long(argc
, argv
, optstring
, long_options
, &optindex
);
327 if (direction
!= DIR_UNDEF
)
329 direction
= DIR_COMP
;
332 if (direction
!= DIR_UNDEF
)
334 direction
= DIR_UNCOMP
;
337 max_size
= strtoull(optarg
, &scratch
, 16);
343 if (!inf
|| !outf
|| direction
== DIR_UNDEF
)
346 if (direction
== DIR_COMP
)
347 do_compress(outf
, inf
, max_size
);
349 do_uncompress(outf
, inf
, max_size
);