[process] Include process name in debug messages
[ipxe.git] / src / util / zbin.c
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <sys/stat.h>
7 #include <lzma.h>
8
9 #define DEBUG 0
10
11 /* LZMA filter choices. Must match those used by unlzma.S */
12 #define LZMA_LC 2
13 #define LZMA_LP 0
14 #define LZMA_PB 0
15
16 /* LZMA preset choice. This is a policy decision */
17 #define LZMA_PRESET ( LZMA_PRESET_DEFAULT | LZMA_PRESET_EXTREME )
18
19 struct input_file {
20 void *buf;
21 size_t len;
22 };
23
24 struct output_file {
25 void *buf;
26 size_t len;
27 size_t hdr_len;
28 size_t max_len;
29 };
30
31 struct zinfo_common {
32 char type[4];
33 char pad[12];
34 };
35
36 struct zinfo_copy {
37 char type[4];
38 uint32_t offset;
39 uint32_t len;
40 uint32_t align;
41 };
42
43 struct zinfo_pack {
44 char type[4];
45 uint32_t offset;
46 uint32_t len;
47 uint32_t align;
48 };
49
50 struct zinfo_payload {
51 char type[4];
52 uint32_t pad1;
53 uint32_t pad2;
54 uint32_t align;
55 };
56
57 struct zinfo_add {
58 char type[4];
59 uint32_t offset;
60 uint32_t divisor;
61 uint32_t pad;
62 };
63
64 union zinfo_record {
65 struct zinfo_common common;
66 struct zinfo_copy copy;
67 struct zinfo_pack pack;
68 struct zinfo_payload payload;
69 struct zinfo_add add;
70 };
71
72 struct zinfo_file {
73 union zinfo_record *zinfo;
74 unsigned int num_entries;
75 };
76
77 static unsigned long align ( unsigned long value, unsigned long align ) {
78 return ( ( value + align - 1 ) & ~( align - 1 ) );
79 }
80
81 static int read_file ( const char *filename, void **buf, size_t *len ) {
82 FILE *file;
83 struct stat stat;
84
85 file = fopen ( filename, "r" );
86 if ( ! file ) {
87 fprintf ( stderr, "Could not open %s: %s\n", filename,
88 strerror ( errno ) );
89 goto err;
90 }
91
92 if ( fstat ( fileno ( file ), &stat ) < 0 ) {
93 fprintf ( stderr, "Could not stat %s: %s\n", filename,
94 strerror ( errno ) );
95 goto err;
96 }
97
98 *len = stat.st_size;
99 *buf = malloc ( *len );
100 if ( ! *buf ) {
101 fprintf ( stderr, "Could not malloc() %zd bytes for %s: %s\n",
102 *len, filename, strerror ( errno ) );
103 goto err;
104 }
105
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 ) );
109 goto err;
110 }
111
112 fclose ( file );
113 return 0;
114
115 err:
116 if ( file )
117 fclose ( file );
118 return -1;
119 }
120
121 static int read_input_file ( const char *filename,
122 struct input_file *input ) {
123 return read_file ( filename, &input->buf, &input->len );
124 }
125
126 static int read_zinfo_file ( const char *filename,
127 struct zinfo_file *zinfo ) {
128 void *buf;
129 size_t len;
130
131 if ( read_file ( filename, &buf, &len ) < 0 )
132 return -1;
133
134 if ( ( len % sizeof ( *(zinfo->zinfo) ) ) != 0 ) {
135 fprintf ( stderr, ".zinfo file %s has invalid length %zd\n",
136 filename, len );
137 return -1;
138 }
139
140 zinfo->zinfo = buf;
141 zinfo->num_entries = ( len / sizeof ( *(zinfo->zinfo) ) );
142 return 0;
143 }
144
145 static int alloc_output_file ( size_t max_len, struct output_file *output ) {
146 output->len = 0;
147 output->hdr_len = 0;
148 output->max_len = ( max_len );
149 output->buf = malloc ( max_len );
150 if ( ! output->buf ) {
151 fprintf ( stderr, "Could not allocate %zd bytes for output\n",
152 max_len );
153 return -1;
154 }
155 memset ( output->buf, 0xff, max_len );
156 return 0;
157 }
158
159 static int process_zinfo_copy ( struct input_file *input,
160 struct output_file *output,
161 union zinfo_record *zinfo ) {
162 struct zinfo_copy *copy = &zinfo->copy;
163 size_t offset = copy->offset;
164 size_t len = copy->len;
165
166 if ( ( offset + len ) > input->len ) {
167 fprintf ( stderr, "Input buffer overrun on copy\n" );
168 return -1;
169 }
170
171 output->len = align ( output->len, copy->align );
172 if ( ( output->len + len ) > output->max_len ) {
173 fprintf ( stderr, "Output buffer overrun on copy\n" );
174 return -1;
175 }
176
177 if ( DEBUG ) {
178 fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n",
179 offset, ( offset + len ), output->len,
180 ( output->len + len ) );
181 }
182
183 memcpy ( ( output->buf + output->len ),
184 ( input->buf + offset ), len );
185 output->len += len;
186 return 0;
187 }
188
189 #define OPCODE_CALL 0xe8
190 #define OPCODE_JMP 0xe9
191
192 static void bcj_filter ( void *data, size_t len ) {
193 struct {
194 uint8_t opcode;
195 int32_t target;
196 } __attribute__ (( packed )) *jump;
197 ssize_t limit = ( len - sizeof ( *jump ) );
198 ssize_t offset;
199
200 /* liblzma does include an x86 BCJ filter, but it's hideously
201 * convoluted and undocumented. This BCJ filter is
202 * substantially simpler and achieves the same compression (at
203 * the cost of requiring the decompressor to know the size of
204 * the decompressed data, which we already have in iPXE).
205 */
206 for ( offset = 0 ; offset <= limit ; offset++ ) {
207 jump = ( data + offset );
208
209 /* Skip instructions that are not followed by a rel32 address */
210 if ( ( jump->opcode != OPCODE_CALL ) &&
211 ( jump->opcode != OPCODE_JMP ) )
212 continue;
213
214 /* Convert rel32 address to an absolute address. To
215 * avoid false positives (which damage the compression
216 * ratio), we should check that the jump target is
217 * within the range [0,limit).
218 *
219 * Some output values would then end up being mapped
220 * from two distinct input values, making the
221 * transformation irreversible. To solve this, we
222 * transform such values back into the part of the
223 * range which would otherwise correspond to no input
224 * values.
225 */
226 if ( ( jump->target >= -offset ) &&
227 ( jump->target < ( limit - offset ) ) ) {
228 /* Convert relative addresses in the range
229 * [-offset,limit-offset) to absolute
230 * addresses in the range [0,limit).
231 */
232 jump->target += offset;
233 } else if ( ( jump->target >= ( limit - offset ) ) &&
234 ( jump->target < limit ) ) {
235 /* Convert positive numbers in the range
236 * [limit-offset,limit) to negative numbers in
237 * the range [-offset,0).
238 */
239 jump->target -= limit;
240 }
241 offset += sizeof ( jump->target );
242 };
243 }
244
245 #define CRCPOLY 0xedb88320
246 #define CRCSEED 0xffffffff
247
248 static uint32_t crc32_le ( uint32_t crc, const void *data, size_t len ) {
249 const uint8_t *src = data;
250 uint32_t mult;
251 unsigned int i;
252
253 while ( len-- ) {
254 crc ^= *(src++);
255 for ( i = 0 ; i < 8 ; i++ ) {
256 mult = ( ( crc & 1 ) ? CRCPOLY : 0 );
257 crc = ( ( crc >> 1 ) ^ mult );
258 }
259 }
260 return crc;
261 }
262
263 static int process_zinfo_pack ( struct input_file *input,
264 struct output_file *output,
265 union zinfo_record *zinfo ) {
266 struct zinfo_pack *pack = &zinfo->pack;
267 size_t offset = pack->offset;
268 size_t len = pack->len;
269 size_t start_len;
270 size_t packed_len = 0;
271 size_t remaining;
272 lzma_options_lzma options;
273 const lzma_filter filters[] = {
274 { .id = LZMA_FILTER_LZMA1, .options = &options },
275 { .id = LZMA_VLI_UNKNOWN }
276 };
277 void *packed;
278 uint32_t *len32;
279 uint32_t *crc32;
280
281 if ( ( offset + len ) > input->len ) {
282 fprintf ( stderr, "Input buffer overrun on pack\n" );
283 return -1;
284 }
285
286 output->len = align ( output->len, pack->align );
287 start_len = output->len;
288 len32 = ( output->buf + output->len );
289 output->len += sizeof ( *len32 );
290 if ( output->len > output->max_len ) {
291 fprintf ( stderr, "Output buffer overrun on pack\n" );
292 return -1;
293 }
294
295 bcj_filter ( ( input->buf + offset ), len );
296
297 packed = ( output->buf + output->len );
298 remaining = ( output->max_len - output->len );
299 lzma_lzma_preset ( &options, LZMA_PRESET );
300 options.lc = LZMA_LC;
301 options.lp = LZMA_LP;
302 options.pb = LZMA_PB;
303 if ( lzma_raw_buffer_encode ( filters, NULL, ( input->buf + offset ),
304 len, packed, &packed_len,
305 remaining ) != LZMA_OK ) {
306 fprintf ( stderr, "Compression failure\n" );
307 return -1;
308 }
309 output->len += packed_len;
310
311 crc32 = ( output->buf + output->len );
312 output->len += sizeof ( *crc32 );
313 if ( output->len > output->max_len ) {
314 fprintf ( stderr, "Output buffer overrun on pack\n" );
315 return -1;
316 }
317 *len32 = ( packed_len + sizeof ( *crc32 ) );
318 *crc32 = crc32_le ( CRCSEED, packed, packed_len );
319
320 if ( DEBUG ) {
321 fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx) crc %#08x\n",
322 offset, ( offset + len ), start_len, output->len,
323 *crc32 );
324 }
325
326 return 0;
327 }
328
329 static int process_zinfo_payl ( struct input_file *input
330 __attribute__ (( unused )),
331 struct output_file *output,
332 union zinfo_record *zinfo ) {
333 struct zinfo_payload *payload = &zinfo->payload;
334
335 output->len = align ( output->len, payload->align );
336 output->hdr_len = output->len;
337
338 if ( DEBUG ) {
339 fprintf ( stderr, "PAYL at %#zx\n", output->hdr_len );
340 }
341 return 0;
342 }
343
344 static int process_zinfo_add ( struct input_file *input
345 __attribute__ (( unused )),
346 struct output_file *output,
347 size_t len,
348 struct zinfo_add *add, size_t offset,
349 size_t datasize ) {
350 void *target;
351 signed long addend;
352 unsigned long size;
353 signed long val;
354 unsigned long mask;
355
356 offset += add->offset;
357 if ( ( offset + datasize ) > output->len ) {
358 fprintf ( stderr, "Add at %#zx outside output buffer\n",
359 offset );
360 return -1;
361 }
362
363 target = ( output->buf + offset );
364 size = ( align ( len, add->divisor ) / add->divisor );
365
366 switch ( datasize ) {
367 case 1:
368 addend = *( ( int8_t * ) target );
369 break;
370 case 2:
371 addend = *( ( int16_t * ) target );
372 break;
373 case 4:
374 addend = *( ( int32_t * ) target );
375 break;
376 default:
377 fprintf ( stderr, "Unsupported add datasize %zd\n",
378 datasize );
379 return -1;
380 }
381
382 val = size + addend;
383
384 /* The result of 1UL << ( 8 * sizeof(unsigned long) ) is undefined */
385 mask = ( ( datasize < sizeof ( mask ) ) ?
386 ( ( 1UL << ( 8 * datasize ) ) - 1 ) : ~0UL );
387
388 if ( val < 0 ) {
389 fprintf ( stderr, "Add %s%#x+%#lx at %#zx %sflows field\n",
390 ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
391 offset, ( ( addend < 0 ) ? "under" : "over" ) );
392 return -1;
393 }
394
395 if ( val & ~mask ) {
396 fprintf ( stderr, "Add %s%#x+%#lx at %#zx overflows %zd-byte "
397 "field (%d bytes too big)\n",
398 ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
399 offset, datasize,
400 ( int )( ( val - mask - 1 ) * add->divisor ) );
401 return -1;
402 }
403
404 switch ( datasize ) {
405 case 1:
406 *( ( uint8_t * ) target ) = val;
407 break;
408 case 2:
409 *( ( uint16_t * ) target ) = val;
410 break;
411 case 4:
412 *( ( uint32_t * ) target ) = val;
413 break;
414 }
415
416 if ( DEBUG ) {
417 fprintf ( stderr, "ADDx [%#zx,%#zx) (%s%#x+(%#zx/%#x)) = "
418 "%#lx\n", offset, ( offset + datasize ),
419 ( ( addend < 0 ) ? "-" : "" ), abs ( addend ),
420 len, add->divisor, val );
421 }
422
423 return 0;
424 }
425
426 static int process_zinfo_addb ( struct input_file *input,
427 struct output_file *output,
428 union zinfo_record *zinfo ) {
429 return process_zinfo_add ( input, output, output->len,
430 &zinfo->add, 0, 1 );
431 }
432
433 static int process_zinfo_addw ( struct input_file *input,
434 struct output_file *output,
435 union zinfo_record *zinfo ) {
436 return process_zinfo_add ( input, output, output->len,
437 &zinfo->add, 0, 2 );
438 }
439
440 static int process_zinfo_addl ( struct input_file *input,
441 struct output_file *output,
442 union zinfo_record *zinfo ) {
443 return process_zinfo_add ( input, output, output->len,
444 &zinfo->add, 0, 4 );
445 }
446
447 static int process_zinfo_adhb ( struct input_file *input,
448 struct output_file *output,
449 union zinfo_record *zinfo ) {
450 return process_zinfo_add ( input, output, output->hdr_len,
451 &zinfo->add, 0, 1 );
452 }
453
454 static int process_zinfo_adhw ( struct input_file *input,
455 struct output_file *output,
456 union zinfo_record *zinfo ) {
457 return process_zinfo_add ( input, output, output->hdr_len,
458 &zinfo->add, 0, 2 );
459 }
460
461 static int process_zinfo_adhl ( struct input_file *input,
462 struct output_file *output,
463 union zinfo_record *zinfo ) {
464 return process_zinfo_add ( input, output, output->hdr_len,
465 &zinfo->add, 0, 4 );
466 }
467
468 static int process_zinfo_adpb ( 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, 0, 1 );
474 }
475
476 static int process_zinfo_adpw ( 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, 0, 2 );
482 }
483
484 static int process_zinfo_adpl ( struct input_file *input,
485 struct output_file *output,
486 union zinfo_record *zinfo ) {
487 return process_zinfo_add ( input, output,
488 ( output->len - output->hdr_len ),
489 &zinfo->add, 0, 4 );
490 }
491
492 static int process_zinfo_appb ( struct input_file *input,
493 struct output_file *output,
494 union zinfo_record *zinfo ) {
495 return process_zinfo_add ( input, output,
496 ( output->len - output->hdr_len ),
497 &zinfo->add, output->hdr_len, 1 );
498 }
499
500 static int process_zinfo_appw ( struct input_file *input,
501 struct output_file *output,
502 union zinfo_record *zinfo ) {
503 return process_zinfo_add ( input, output,
504 ( output->len - output->hdr_len ),
505 &zinfo->add, output->hdr_len, 2 );
506 }
507
508 static int process_zinfo_appl ( struct input_file *input,
509 struct output_file *output,
510 union zinfo_record *zinfo ) {
511 return process_zinfo_add ( input, output,
512 ( output->len - output->hdr_len ),
513 &zinfo->add, output->hdr_len, 4 );
514 }
515
516 struct zinfo_processor {
517 char *type;
518 int ( * process ) ( struct input_file *input,
519 struct output_file *output,
520 union zinfo_record *zinfo );
521 };
522
523 static struct zinfo_processor zinfo_processors[] = {
524 { "COPY", process_zinfo_copy },
525 { "PACK", process_zinfo_pack },
526 { "PAYL", process_zinfo_payl },
527 { "ADDB", process_zinfo_addb },
528 { "ADDW", process_zinfo_addw },
529 { "ADDL", process_zinfo_addl },
530 { "ADHB", process_zinfo_adhb },
531 { "ADHW", process_zinfo_adhw },
532 { "ADHL", process_zinfo_adhl },
533 { "ADPB", process_zinfo_adpb },
534 { "ADPW", process_zinfo_adpw },
535 { "ADPL", process_zinfo_adpl },
536 { "APPB", process_zinfo_appb },
537 { "APPW", process_zinfo_appw },
538 { "APPL", process_zinfo_appl },
539 };
540
541 static int process_zinfo ( struct input_file *input,
542 struct output_file *output,
543 union zinfo_record *zinfo ) {
544 struct zinfo_common *common = &zinfo->common;
545 struct zinfo_processor *processor;
546 char type[ sizeof ( common->type ) + 1 ] = "";
547 unsigned int i;
548
549 strncat ( type, common->type, sizeof ( type ) - 1 );
550 for ( i = 0 ; i < ( sizeof ( zinfo_processors ) /
551 sizeof ( zinfo_processors[0] ) ) ; i++ ) {
552 processor = &zinfo_processors[i];
553 if ( strcmp ( processor->type, type ) == 0 )
554 return processor->process ( input, output, zinfo );
555 }
556
557 fprintf ( stderr, "Unknown zinfo record type \"%s\"\n", &type[0] );
558 return -1;
559 }
560
561 static int write_output_file ( struct output_file *output ) {
562 if ( fwrite ( output->buf, 1, output->len, stdout ) != output->len ) {
563 fprintf ( stderr, "Could not write %zd bytes of output: %s\n",
564 output->len, strerror ( errno ) );
565 return -1;
566 }
567 return 0;
568 }
569
570 int main ( int argc, char **argv ) {
571 struct input_file input;
572 struct output_file output;
573 struct zinfo_file zinfo;
574 unsigned int i;
575
576 if ( argc != 3 ) {
577 fprintf ( stderr, "Syntax: %s file.bin file.zinfo "
578 "> file.zbin\n", argv[0] );
579 exit ( 1 );
580 }
581
582 if ( read_input_file ( argv[1], &input ) < 0 )
583 exit ( 1 );
584 if ( read_zinfo_file ( argv[2], &zinfo ) < 0 )
585 exit ( 1 );
586 if ( alloc_output_file ( ( input.len * 4 ), &output ) < 0 )
587 exit ( 1 );
588
589 for ( i = 0 ; i < zinfo.num_entries ; i++ ) {
590 if ( process_zinfo ( &input, &output,
591 &zinfo.zinfo[i] ) < 0 )
592 exit ( 1 );
593 }
594
595 if ( write_output_file ( &output ) < 0 )
596 exit ( 1 );
597
598 return 0;
599 }