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 )