11 /* LZMA filter choices. Must match those used by unlzma.S */
16 /* LZMA preset choice. This is a policy decision */
17 #define LZMA_PRESET ( LZMA_PRESET_DEFAULT | LZMA_PRESET_EXTREME )
50 struct zinfo_payload {
65 struct zinfo_common common;
66 struct zinfo_copy copy;
67 struct zinfo_pack pack;
68 struct zinfo_payload payload;
73 union zinfo_record *zinfo;
74 unsigned int num_entries;
77 static unsigned long align ( unsigned long value, unsigned long align ) {
78 return ( ( value + align - 1 ) & ~( align - 1 ) );
81 static int read_file ( const char *filename, void **buf, size_t *len ) {
85 file = fopen ( filename, "r" );
87 fprintf ( stderr, "Could not open %s: %s\n", filename,
92 if ( fstat ( fileno ( file ), &stat ) < 0 ) {
93 fprintf ( stderr, "Could not stat %s: %s\n", filename,
99 *buf = malloc ( *len );
101 fprintf ( stderr, "Could not malloc() %zd bytes for %s: %s\n",
102 *len, filename, strerror ( errno ) );
106 if ( fread ( *buf, 1, *len, file ) != *len ) {
107 fprintf ( stderr, "Could not read %zd bytes from %s: %s\n",
108 *len, filename, strerror ( errno ) );
121 static int read_input_file ( const char *filename,
122 struct input_file *input ) {
123 return read_file ( filename, &input->buf, &input->len );
126 static int read_zinfo_file ( const char *filename,
127 struct zinfo_file *zinfo ) {
131 if ( read_file ( filename, &buf, &len ) < 0 )
134 if ( ( len % sizeof ( *(zinfo->zinfo) ) ) != 0 ) {
135 fprintf ( stderr, ".zinfo file %s has invalid length %zd\n",
141 zinfo->num_entries = ( len / sizeof ( *(zinfo->zinfo) ) );
145 static int alloc_output_file ( size_t max_len, struct output_file *output ) {
147 output->max_len = ( max_len );
148 output->buf = malloc ( max_len );
149 if ( ! output->buf ) {
150 fprintf ( stderr, "Could not allocate %zd bytes for output\n",
154 memset ( output->buf, 0xff, max_len );
158 static int process_zinfo_copy ( struct input_file *input,
159 struct output_file *output,
160 union zinfo_record *zinfo ) {
161 struct zinfo_copy *copy = &zinfo->copy;
162 size_t offset = copy->offset;
163 size_t len = copy->len;
165 if ( ( offset + len ) > input->len ) {
166 fprintf ( stderr, "Input buffer overrun on copy\n" );
170 output->len = align ( output->len, copy->align );
171 if ( ( output->len + len ) > output->max_len ) {
172 fprintf ( stderr, "Output buffer overrun on copy\n" );
177 fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n",
178 offset, ( offset + len ), output->len,
179 ( output->len + len ) );
182 memcpy ( ( output->buf + output->len ),
183 ( input->buf + offset ), len );
188 #define OPCODE_CALL 0xe8
189 #define OPCODE_JMP 0xe9
191 static void bcj_filter ( void *data, size_t len ) {
195 } __attribute__ (( packed )) *jump;
196 ssize_t limit = ( len - sizeof ( *jump ) );
199 /* liblzma does include an x86 BCJ filter, but it's hideously
200 * convoluted and undocumented. This BCJ filter is
201 * substantially simpler and achieves the same compression (at
202 * the cost of requiring the decompressor to know the size of
203 * the decompressed data, which we already have in iPXE).
205 for ( offset = 0 ; offset <= limit ; offset++ ) {
206 jump = ( data + offset );
208 /* Skip instructions that are not followed by a rel32 address */
209 if ( ( jump->opcode != OPCODE_CALL ) &&
210 ( jump->opcode != OPCODE_JMP ) )
213 /* Convert rel32 address to an absolute address. To
214 * avoid false positives (which damage the compression
215 * ratio), we should check that the jump target is
216 * within the range [0,limit).
218 * Some output values would then end up being mapped
219 * from two distinct input values, making the
220 * transformation irreversible. To solve this, we
221 * transform such values back into the part of the
222 * range which would otherwise correspond to no input
225 if ( ( jump->target >= -offset ) &&
226 ( jump->target < ( limit - offset ) ) ) {
227 /* Convert relative addresses in the range
228 * [-offset,limit-offset) to absolute
229 * addresses in the range [0,limit).
231 jump->target += offset;
232 } else if ( ( jump->target >= ( limit - offset ) ) &&
233 ( jump->target < limit ) ) {
234 /* Convert positive numbers in the range
235 * [limit-offset,limit) to negative numbers in
236 * the range [-offset,0).
238 jump->target -= limit;
240 offset += sizeof ( jump->target );
244 static int process_zinfo_pack ( struct input_file *input,
245 struct output_file *output,
246 union zinfo_record *zinfo ) {
247 struct zinfo_pack *pack = &zinfo->pack;
248 size_t offset = pack->offset;
249 size_t len = pack->len;
250 size_t packed_len = 0;
251 size_t remaining = ( output->max_len - output->len );
252 lzma_options_lzma options;
253 const lzma_filter filters[] = {
254 { .id = LZMA_FILTER_LZMA1, .options = &options },
255 { .id = LZMA_VLI_UNKNOWN }
258 if ( ( offset + len ) > input->len ) {
259 fprintf ( stderr, "Input buffer overrun on pack\n" );
263 output->len = align ( output->len, pack->align );
264 if ( output->len > output->max_len ) {
265 fprintf ( stderr, "Output buffer overrun on pack\n" );
269 bcj_filter ( ( input->buf + offset ), len );
271 lzma_lzma_preset ( &options, LZMA_PRESET );
272 options.lc = LZMA_LC;
273 options.lp = LZMA_LP;
274 options.pb = LZMA_PB;
275 if ( lzma_raw_buffer_encode ( filters, NULL, ( input->buf + offset ),
276 len, ( output->buf + output->len ),
277 &packed_len, remaining ) != LZMA_OK ) {
278 fprintf ( stderr, "Compression failure\n" );
283 fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n",
284 offset, ( offset + len ), output->len,
285 ( output->len + packed_len ) );
288 output->len += packed_len;
289 if ( output->len > output->max_len ) {
290 fprintf ( stderr, "Output buffer overrun on pack\n" );
297 static int process_zinfo_payl ( struct input_file *input
298 __attribute__ (( unused )),
299 struct output_file *output,
300 union zinfo_record *zinfo ) {
301 struct zinfo_payload *payload = &zinfo->payload;
303 output->len = align ( output->len, payload->align );
304 output->hdr_len = output->len;
307 fprintf ( stderr, "PAYL at %#zx\n", output->hdr_len );
312 static int process_zinfo_add ( struct input_file *input
313 __attribute__ (( unused )),
314 struct output_file *output,
316 struct zinfo_add *add, size_t offset,
324 offset += add->offset;
325 if ( ( offset + datasize ) > output->len ) {
326 fprintf ( stderr, "Add at %#zx outside output buffer\n",
331 target = ( output->buf + offset );
332 size = ( align ( len, add->divisor ) / add->divisor );
334 switch ( datasize ) {
336 addend = *( ( int8_t * ) target );
339 addend = *( ( int16_t * ) target );
342 addend = *( ( int32_t * ) target );
345 fprintf ( stderr, "Unsupported add datasize %zd\n",
352 /* The result of 1UL << ( 8 * sizeof(unsigned long) ) is undefined */
353 mask = ( ( datasize < sizeof ( mask ) ) ?
354 ( ( 1UL << ( 8 * datasize ) ) - 1 ) : ~0UL );
357 fprintf ( stderr, "Add %s%#x+%#lx at %#zx %sflows field\n",
358 ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
359 offset, ( ( addend < 0 ) ? "under" : "over" ) );
364 fprintf ( stderr, "Add %s%#x+%#lx at %#zx overflows %zd-byte "
365 "field (%d bytes too big)\n",
366 ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
368 ( int )( ( val - mask - 1 ) * add->divisor ) );
372 switch ( datasize ) {
374 *( ( uint8_t * ) target ) = val;
377 *( ( uint16_t * ) target ) = val;
380 *( ( uint32_t * ) target ) = val;
385 fprintf ( stderr, "ADDx [%#zx,%#zx) (%s%#x+(%#zx/%#x)) = "
386 "%#lx\n", offset, ( offset + datasize ),
387 ( ( addend < 0 ) ? "-" : "" ), abs ( addend ),
388 len, add->divisor, val );
394 static int process_zinfo_addb ( struct input_file *input,
395 struct output_file *output,
396 union zinfo_record *zinfo ) {
397 return process_zinfo_add ( input, output, output->len,
401 static int process_zinfo_addw ( struct input_file *input,
402 struct output_file *output,
403 union zinfo_record *zinfo ) {
404 return process_zinfo_add ( input, output, output->len,
408 static int process_zinfo_addl ( struct input_file *input,
409 struct output_file *output,
410 union zinfo_record *zinfo ) {
411 return process_zinfo_add ( input, output, output->len,
415 static int process_zinfo_adhb ( struct input_file *input,
416 struct output_file *output,
417 union zinfo_record *zinfo ) {
418 return process_zinfo_add ( input, output, output->hdr_len,
422 static int process_zinfo_adhw ( struct input_file *input,
423 struct output_file *output,
424 union zinfo_record *zinfo ) {
425 return process_zinfo_add ( input, output, output->hdr_len,
429 static int process_zinfo_adhl ( struct input_file *input,
430 struct output_file *output,
431 union zinfo_record *zinfo ) {
432 return process_zinfo_add ( input, output, output->hdr_len,
436 static int process_zinfo_adpb ( struct input_file *input,
437 struct output_file *output,
438 union zinfo_record *zinfo ) {
439 return process_zinfo_add ( input, output,
440 ( output->len - output->hdr_len ),
444 static int process_zinfo_adpw ( struct input_file *input,
445 struct output_file *output,
446 union zinfo_record *zinfo ) {
447 return process_zinfo_add ( input, output,
448 ( output->len - output->hdr_len ),
452 static int process_zinfo_adpl ( struct input_file *input,
453 struct output_file *output,
454 union zinfo_record *zinfo ) {
455 return process_zinfo_add ( input, output,
456 ( output->len - output->hdr_len ),
460 static int process_zinfo_appb ( struct input_file *input,
461 struct output_file *output,
462 union zinfo_record *zinfo ) {
463 return process_zinfo_add ( input, output,
464 ( output->len - output->hdr_len ),
465 &zinfo->add, output->hdr_len, 1 );
468 static int process_zinfo_appw ( struct input_file *input,
469 struct output_file *output,
470 union zinfo_record *zinfo ) {
471 return process_zinfo_add ( input, output,
472 ( output->len - output->hdr_len ),
473 &zinfo->add, output->hdr_len, 2 );
476 static int process_zinfo_appl ( struct input_file *input,
477 struct output_file *output,
478 union zinfo_record *zinfo ) {
479 return process_zinfo_add ( input, output,
480 ( output->len - output->hdr_len ),
481 &zinfo->add, output->hdr_len, 4 );
484 struct zinfo_processor {
486 int ( * process ) ( struct input_file *input,
487 struct output_file *output,
488 union zinfo_record *zinfo );
491 static struct zinfo_processor zinfo_processors[] = {
492 { "COPY", process_zinfo_copy },
493 { "PACK", process_zinfo_pack },
494 { "PAYL", process_zinfo_payl },
495 { "ADDB", process_zinfo_addb },
496 { "ADDW", process_zinfo_addw },
497 { "ADDL", process_zinfo_addl },
498 { "ADHB", process_zinfo_adhb },
499 { "ADHW", process_zinfo_adhw },
500 { "ADHL", process_zinfo_adhl },
501 { "ADPB", process_zinfo_adpb },
502 { "ADPW", process_zinfo_adpw },
503 { "ADPL", process_zinfo_adpl },
504 { "APPB", process_zinfo_appb },
505 { "APPW", process_zinfo_appw },
506 { "APPL", process_zinfo_appl },
509 static int process_zinfo ( struct input_file *input,
510 struct output_file *output,
511 union zinfo_record *zinfo ) {
512 struct zinfo_common *common = &zinfo->common;
513 struct zinfo_processor *processor;
514 char type[ sizeof ( common->type ) + 1 ] = "";
517 strncat ( type, common->type, sizeof ( type ) - 1 );
518 for ( i = 0 ; i < ( sizeof ( zinfo_processors ) /
519 sizeof ( zinfo_processors[0] ) ) ; i++ ) {
520 processor = &zinfo_processors[i];
521 if ( strcmp ( processor->type, type ) == 0 )
522 return processor->process ( input, output, zinfo );
525 fprintf ( stderr, "Unknown zinfo record type \"%s\"\n", &type[0] );
529 static int write_output_file ( struct output_file *output ) {
530 if ( fwrite ( output->buf, 1, output->len, stdout ) != output->len ) {
531 fprintf ( stderr, "Could not write %zd bytes of output: %s\n",
532 output->len, strerror ( errno ) );
538 int main ( int argc, char **argv ) {
539 struct input_file input;
540 struct output_file output;
541 struct zinfo_file zinfo;
545 fprintf ( stderr, "Syntax: %s file.bin file.zinfo "
546 "> file.zbin\n", argv[0] );
550 if ( read_input_file ( argv[1], &input ) < 0 )
552 if ( read_zinfo_file ( argv[2], &zinfo ) < 0 )
554 if ( alloc_output_file ( ( input.len * 4 ), &output ) < 0 )
557 for ( i = 0 ; i < zinfo.num_entries ; i++ ) {
558 if ( process_zinfo ( &input, &output,
559 &zinfo.zinfo[i] ) < 0 )
563 if ( write_output_file ( &output ) < 0 )