You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

zbin.c 15KB

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