summaryrefslogtreecommitdiff
path: root/utils/imxtools/sb.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/imxtools/sb.c')
-rw-r--r--utils/imxtools/sb.c1181
1 files changed, 1181 insertions, 0 deletions
diff --git a/utils/imxtools/sb.c b/utils/imxtools/sb.c
new file mode 100644
index 0000000000..44db56b7d1
--- /dev/null
+++ b/utils/imxtools/sb.c
@@ -0,0 +1,1181 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <time.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include "misc.h"
26#include "crypto.h"
27#include "sb.h"
28
29static void fill_gaps(struct sb_file_t *sb)
30{
31 for(int i = 0; i < sb->nr_sections; i++)
32 {
33 struct sb_section_t *sec = &sb->sections[i];
34 for(int j = 0; j < sec->nr_insts; j++)
35 {
36 struct sb_inst_t *inst = &sec->insts[j];
37 if(inst->inst != SB_INST_LOAD)
38 continue;
39 inst->padding_size = ROUND_UP(inst->size, BLOCK_SIZE) - inst->size;
40 /* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */
41 inst->padding = xmalloc(15);
42 generate_random_data(inst->padding, 15);
43 }
44 }
45}
46
47static void compute_sb_offsets(struct sb_file_t *sb)
48{
49 sb->image_size = 0;
50 /* sb header */
51 sb->image_size += sizeof(struct sb_header_t) / BLOCK_SIZE;
52 /* sections headers */
53 sb->image_size += sb->nr_sections * sizeof(struct sb_section_header_t) / BLOCK_SIZE;
54 /* key dictionary */
55 sb->image_size += g_nr_keys * sizeof(struct sb_key_dictionary_entry_t) / BLOCK_SIZE;
56 /* sections */
57 for(int i = 0; i < sb->nr_sections; i++)
58 {
59 /* each section has a preliminary TAG command */
60 sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE;
61 /* we might need to pad the section so compute next alignment */
62 uint32_t alignment = BLOCK_SIZE;
63 if((i + 1) < sb->nr_sections)
64 alignment = sb->sections[i + 1].alignment;
65 alignment /= BLOCK_SIZE; /* alignment in block sizes */
66
67 struct sb_section_t *sec = &sb->sections[i];
68 sec->sec_size = 0;
69
70 if(g_debug)
71 {
72 printf("%s section 0x%08x", sec->is_data ? "Data" : "Boot",
73 sec->identifier);
74 if(sec->is_cleartext)
75 printf(" (cleartext)");
76 printf("\n");
77 }
78
79 sec->file_offset = sb->image_size;
80 for(int j = 0; j < sec->nr_insts; j++)
81 {
82 struct sb_inst_t *inst = &sec->insts[j];
83 if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP)
84 {
85 if(g_debug)
86 printf(" %s | addr=0x%08x | arg=0x%08x\n",
87 inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument);
88 sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
89 sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
90 }
91 else if(inst->inst == SB_INST_FILL)
92 {
93 if(g_debug)
94 printf(" FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n",
95 inst->addr, inst->size, inst->pattern);
96 sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
97 sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
98 }
99 else if(inst->inst == SB_INST_LOAD)
100 {
101 if(g_debug)
102 printf(" LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size);
103 /* load header */
104 sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
105 sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
106 /* data + alignment */
107 sb->image_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
108 sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
109 }
110 else if(inst->inst == SB_INST_MODE)
111 {
112 if(g_debug)
113 printf(" MODE | mod=0x%08x", inst->addr);
114 sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
115 sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
116 }
117 else if(inst->inst == SB_INST_DATA)
118 {
119 if(g_debug)
120 printf(" DATA | size=0x%08x\n", inst->size);
121 sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
122 sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
123 }
124 else
125 bug("die on inst %d\n", inst->inst);
126 }
127 /* we need to make sure next section starts on the right alignment.
128 * Since each section starts with a boot tag, we thus need to ensure
129 * that this sections ends at adress X such that X+BLOCK_SIZE is
130 * a multiple of the alignment.
131 * For data sections, we just add random data, otherwise we add nops */
132 uint32_t missing_sz = alignment - ((sb->image_size + 1) % alignment);
133 if(missing_sz != alignment)
134 {
135 struct sb_inst_t *aug_insts;
136 int nr_aug_insts = 0;
137
138 if(sb->sections[i].is_data)
139 {
140 nr_aug_insts = 1;
141 aug_insts = xmalloc(sizeof(struct sb_inst_t));
142 memset(aug_insts, 0, sizeof(struct sb_inst_t));
143 aug_insts[0].inst = SB_INST_DATA;
144 aug_insts[0].size = missing_sz * BLOCK_SIZE;
145 aug_insts[0].data = xmalloc(missing_sz * BLOCK_SIZE);
146 generate_random_data(aug_insts[0].data, missing_sz * BLOCK_SIZE);
147 if(g_debug)
148 printf(" DATA | size=0x%08x\n", aug_insts[0].size);
149 }
150 else
151 {
152 nr_aug_insts = missing_sz;
153 aug_insts = xmalloc(sizeof(struct sb_inst_t) * nr_aug_insts);
154 memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
155 for(int j = 0; j < nr_aug_insts; j++)
156 {
157 aug_insts[j].inst = SB_INST_NOP;
158 if(g_debug)
159 printf(" NOOP\n");
160 }
161 }
162
163 sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t),
164 sb->sections[i].nr_insts, aug_insts, nr_aug_insts);
165 sb->sections[i].nr_insts += nr_aug_insts;
166 free(aug_insts);
167
168 /* augment image and section size */
169 sb->image_size += missing_sz;
170 sec->sec_size += missing_sz;
171 }
172 }
173 /* final signature */
174 sb->image_size += 2;
175}
176
177static uint64_t generate_timestamp()
178{
179 struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
180 time_t t = time(NULL) - mktime(&tm_base);
181 return (uint64_t)t * 1000000L;
182}
183
184static uint16_t swap16(uint16_t t)
185{
186 return (t << 8) | (t >> 8);
187}
188
189static void fix_version(struct sb_version_t *ver)
190{
191 ver->major = swap16(ver->major);
192 ver->minor = swap16(ver->minor);
193 ver->revision = swap16(ver->revision);
194}
195
196static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr)
197{
198 struct sha_1_params_t sha_1_params;
199
200 sb_hdr->signature[0] = 'S';
201 sb_hdr->signature[1] = 'T';
202 sb_hdr->signature[2] = 'M';
203 sb_hdr->signature[3] = 'P';
204 sb_hdr->major_ver = IMAGE_MAJOR_VERSION;
205 sb_hdr->minor_ver = IMAGE_MINOR_VERSION;
206 sb_hdr->flags = 0;
207 sb_hdr->image_size = sb->image_size;
208 sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE;
209 sb_hdr->first_boot_sec_id = sb->first_boot_sec_id;
210 sb_hdr->nr_keys = g_nr_keys;
211 sb_hdr->nr_sections = sb->nr_sections;
212 sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE;
213 sb_hdr->key_dict_off = sb_hdr->header_size +
214 sb_hdr->sec_hdr_size * sb_hdr->nr_sections;
215 sb_hdr->first_boot_tag_off = sb_hdr->key_dict_off +
216 sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE;
217 generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0));
218 generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1));
219 /* Version 1.0 has 6 bytes of random padding,
220 * Version 1.1 requires the last 4 bytes to be 'sgtl' */
221 if(sb->minor_version >= 1)
222 memcpy(&sb_hdr->rand_pad0[2], "sgtl", 4);
223
224 sb_hdr->timestamp = generate_timestamp();
225 sb_hdr->product_ver = sb->product_ver;
226 fix_version(&sb_hdr->product_ver);
227 sb_hdr->component_ver = sb->component_ver;
228 fix_version(&sb_hdr->component_ver);
229 sb_hdr->drive_tag = sb->drive_tag;
230
231 sha_1_init(&sha_1_params);
232 sha_1_update(&sha_1_params, &sb_hdr->signature[0],
233 sizeof(struct sb_header_t) - sizeof(sb_hdr->sha1_header));
234 sha_1_finish(&sha_1_params);
235 sha_1_output(&sha_1_params, sb_hdr->sha1_header);
236}
237
238static void produce_sb_section_header(struct sb_section_t *sec,
239 struct sb_section_header_t *sec_hdr)
240{
241 sec_hdr->identifier = sec->identifier;
242 sec_hdr->offset = sec->file_offset;
243 sec_hdr->size = sec->sec_size;
244 sec_hdr->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
245 | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
246}
247
248static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
249{
250 uint8_t sum = 90;
251 byte *ptr = (byte *)hdr;
252 for(int i = 1; i < 16; i++)
253 sum += ptr[i];
254 return sum;
255}
256
257static void produce_section_tag_cmd(struct sb_section_t *sec,
258 struct sb_instruction_tag_t *tag, bool is_last)
259{
260 tag->hdr.opcode = SB_INST_TAG;
261 tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0;
262 tag->identifier = sec->identifier;
263 tag->len = sec->sec_size;
264 tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
265 | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
266 tag->hdr.checksum = instruction_checksum(&tag->hdr);
267}
268
269void produce_sb_instruction(struct sb_inst_t *inst,
270 struct sb_instruction_common_t *cmd)
271{
272 memset(cmd, 0, sizeof(struct sb_instruction_common_t));
273 cmd->hdr.opcode = inst->inst;
274 switch(inst->inst)
275 {
276 case SB_INST_CALL:
277 case SB_INST_JUMP:
278 cmd->addr = inst->addr;
279 cmd->data = inst->argument;
280 break;
281 case SB_INST_FILL:
282 cmd->addr = inst->addr;
283 cmd->len = inst->size;
284 cmd->data = inst->pattern;
285 break;
286 case SB_INST_LOAD:
287 cmd->addr = inst->addr;
288 cmd->len = inst->size;
289 cmd->data = crc_continue(crc(inst->data, inst->size),
290 inst->padding, inst->padding_size);
291 break;
292 case SB_INST_MODE:
293 cmd->data = inst->addr;
294 break;
295 case SB_INST_NOP:
296 break;
297 default:
298 bug("die\n");
299 }
300 cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
301}
302
303enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename)
304{
305 struct crypto_key_t real_key;
306 real_key.method = CRYPTO_KEY;
307 byte crypto_iv[16];
308 byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys);
309 /* init CBC-MACs */
310 for(int i = 0; i < g_nr_keys; i++)
311 memset(cbc_macs[i], 0, 16);
312
313 fill_gaps(sb);
314 compute_sb_offsets(sb);
315
316 generate_random_data(real_key.u.key, 16);
317
318 /* global SHA-1 */
319 struct sha_1_params_t file_sha1;
320 sha_1_init(&file_sha1);
321 /* produce and write header */
322 struct sb_header_t sb_hdr;
323 produce_sb_header(sb, &sb_hdr);
324 /* allocate image */
325 byte *buf = xmalloc(sb_hdr.image_size * BLOCK_SIZE);
326 byte *buf_p = buf;
327 #define write(p, sz) do { memcpy(buf_p, p, sz); buf_p += sz; } while(0)
328
329 sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
330 write(&sb_hdr, sizeof(sb_hdr));
331
332 memcpy(crypto_iv, &sb_hdr, 16);
333
334 /* update CBC-MACs */
335 for(int i = 0; i < g_nr_keys; i++)
336 crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i],
337 cbc_macs[i], &cbc_macs[i], 1);
338
339 /* produce and write section headers */
340 for(int i = 0; i < sb_hdr.nr_sections; i++)
341 {
342 struct sb_section_header_t sb_sec_hdr;
343 produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
344 sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
345 write(&sb_sec_hdr, sizeof(sb_sec_hdr));
346 /* update CBC-MACs */
347 for(int j = 0; j < g_nr_keys; j++)
348 crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
349 &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
350 }
351 /* produce key dictionary */
352 for(int i = 0; i < g_nr_keys; i++)
353 {
354 struct sb_key_dictionary_entry_t entry;
355 memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16);
356 crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
357 crypto_iv, NULL, 1);
358
359 write(&entry, sizeof(entry));
360 sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
361 }
362
363 free(cbc_macs);
364
365 /* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
366 /* Image crafting, don't use it unless you understand what you do */
367 if(sb->override_real_key)
368 memcpy(real_key.u.key, sb->real_key, 16);
369 if(sb->override_crypto_iv)
370 memcpy(crypto_iv, sb->crypto_iv, 16);
371 /* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
372 if(g_debug)
373 {
374 printf("Real key: ");
375 for(int j = 0; j < 16; j++)
376 printf("%02x", real_key.u.key[j]);
377 printf("\n");
378 printf("IV : ");
379 for(int j = 0; j < 16; j++)
380 printf("%02x", crypto_iv[j]);
381 printf("\n");
382 }
383 /* produce sections data */
384 for(int i = 0; i< sb_hdr.nr_sections; i++)
385 {
386 /* produce tag command */
387 struct sb_instruction_tag_t tag_cmd;
388 produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
389 if(g_nr_keys > 0)
390 crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
391 &real_key, crypto_iv, NULL, 1);
392 sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
393 write(&tag_cmd, sizeof(tag_cmd));
394 /* produce other commands */
395 byte cur_cbc_mac[16];
396 memcpy(cur_cbc_mac, crypto_iv, 16);
397 for(int j = 0; j < sb->sections[i].nr_insts; j++)
398 {
399 struct sb_inst_t *inst = &sb->sections[i].insts[j];
400 /* command */
401 if(inst->inst != SB_INST_DATA)
402 {
403 struct sb_instruction_common_t cmd;
404 produce_sb_instruction(inst, &cmd);
405 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
406 crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
407 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
408 sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
409 write(&cmd, sizeof(cmd));
410 }
411 /* data */
412 if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
413 {
414 uint32_t sz = inst->size + inst->padding_size;
415 byte *data = xmalloc(sz);
416 memcpy(data, inst->data, inst->size);
417 memcpy(data + inst->size, inst->padding, inst->padding_size);
418 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
419 crypto_cbc(data, data, sz / BLOCK_SIZE,
420 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
421 sha_1_update(&file_sha1, data, sz);
422 write(data, sz);
423 free(data);
424 }
425 }
426 }
427 /* write file SHA-1 */
428 byte final_sig[32];
429 sha_1_finish(&file_sha1);
430 sha_1_output(&file_sha1, final_sig);
431 generate_random_data(final_sig + 20, 12);
432 if(g_nr_keys > 0)
433 crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
434 write(final_sig, 32);
435
436 if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE)
437 bug("SB image buffer was not entirely filled !");
438
439 FILE *fd = fopen(filename, "wb");
440 if(fd == NULL)
441 return SB_OPEN_ERROR;
442 if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1)
443 {
444 free(buf);
445 return SB_WRITE_ERROR;
446 }
447 fclose(fd);
448 free(buf);
449
450 return SB_SUCCESS;
451}
452
453static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
454 int size, const char *indent, void *u, sb_color_printf cprintf, enum sb_error_t *err)
455{
456 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
457 #define fatal(e, ...) \
458 do { if(err) *err = e; \
459 cprintf(u, true, GREY, __VA_ARGS__); \
460 sb_free_section(*sec); \
461 free(sec); \
462 return NULL; } while(0)
463
464 struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t));
465 memset(sec, 0, sizeof(struct sb_section_t));
466 sec->identifier = id;
467 sec->is_data = data_sec;
468 sec->sec_size = ROUND_UP(size, BLOCK_SIZE) / BLOCK_SIZE;
469
470 if(data_sec)
471 {
472 sec->nr_insts = 1;
473 sec->insts = xmalloc(sizeof(struct sb_inst_t));
474 memset(sec->insts, 0, sizeof(struct sb_inst_t));
475 sec->insts->inst = SB_INST_DATA;
476 sec->insts->size = size;
477 sec->insts->data = memdup(buf, size);
478 return sec;
479 }
480
481 /* Pretty print the content */
482 int pos = 0;
483 while(pos < size)
484 {
485 struct sb_inst_t inst;
486 memset(&inst, 0, sizeof(inst));
487
488 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos];
489 inst.inst = hdr->opcode;
490
491 printf(OFF, "%s", indent);
492 uint8_t checksum = instruction_checksum(hdr);
493 if(checksum != hdr->checksum)
494 fatal(SB_CHECKSUM_ERROR, "Bad instruction checksum");
495 if(hdr->flags != 0)
496 {
497 printf(GREY, "[");
498 printf(BLUE, "f=%x", hdr->flags);
499 printf(GREY, "] ");
500 }
501 if(hdr->opcode == SB_INST_LOAD)
502 {
503 struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos];
504 inst.size = load->len;
505 inst.addr = load->addr;
506 inst.data = memdup(load + 1, load->len);
507
508 printf(RED, "LOAD");
509 printf(OFF, " | ");
510 printf(BLUE, "addr=0x%08x", load->addr);
511 printf(OFF, " | ");
512 printf(GREEN, "len=0x%08x", load->len);
513 printf(OFF, " | ");
514 printf(YELLOW, "crc=0x%08x", load->crc);
515 /* data is padded to 16-byte boundary with random data and crc'ed with it */
516 uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)],
517 ROUND_UP(load->len, 16));
518 if(load->crc == computed_crc)
519 printf(RED, " Ok\n");
520 else
521 {
522 printf(RED, " Failed (crc=0x%08x)\n", computed_crc);
523 fatal(SB_CHECKSUM_ERROR, "Instruction data crc error\n");
524 }
525
526 pos += load->len + sizeof(struct sb_instruction_load_t);
527 }
528 else if(hdr->opcode == SB_INST_FILL)
529 {
530 struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos];
531 inst.pattern = fill->pattern;
532 inst.size = fill->len;
533 inst.addr = fill->addr;
534
535 printf(RED, "FILL");
536 printf(OFF, " | ");
537 printf(BLUE, "addr=0x%08x", fill->addr);
538 printf(OFF, " | ");
539 printf(GREEN, "len=0x%08x", fill->len);
540 printf(OFF, " | ");
541 printf(YELLOW, "pattern=0x%08x\n", fill->pattern);
542
543 pos += sizeof(struct sb_instruction_fill_t);
544 }
545 else if(hdr->opcode == SB_INST_CALL ||
546 hdr->opcode == SB_INST_JUMP)
547 {
548 int is_call = (hdr->opcode == SB_INST_CALL);
549 struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos];
550 inst.addr = call->addr;
551 inst.argument = call->arg;
552
553 if(is_call)
554 printf(RED, "CALL");
555 else
556 printf(RED, "JUMP");
557 printf(OFF, " | ");
558 printf(BLUE, "addr=0x%08x", call->addr);
559 printf(OFF, " | ");
560 printf(GREEN, "arg=0x%08x\n", call->arg);
561
562 pos += sizeof(struct sb_instruction_call_t);
563 }
564 else if(hdr->opcode == SB_INST_MODE)
565 {
566 struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr;
567 inst.argument = mode->mode;
568
569 printf(RED, "MODE");
570 printf(OFF, " | ");
571 printf(BLUE, "mod=0x%08x\n", mode->mode);
572
573 pos += sizeof(struct sb_instruction_mode_t);
574 }
575 else if(hdr->opcode == SB_INST_NOP)
576 {
577 printf(RED, "NOOP\n");
578 pos += sizeof(struct sb_instruction_mode_t);
579 }
580 else
581 {
582 fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
583 break;
584 }
585
586 sec->insts = augment_array(sec->insts, sizeof(struct sb_inst_t), sec->nr_insts++, &inst, 1);
587 pos = ROUND_UP(pos, BLOCK_SIZE);
588 }
589
590 return sec;
591 #undef printf
592 #undef fatal
593}
594
595void sb_fill_section_name(char name[5], uint32_t identifier)
596{
597 name[0] = (identifier >> 24) & 0xff;
598 name[1] = (identifier >> 16) & 0xff;
599 name[2] = (identifier >> 8) & 0xff;
600 name[3] = identifier & 0xff;
601 for(int i = 0; i < 4; i++)
602 if(!isprint(name[i]))
603 name[i] = '_';
604 name[4] = 0;
605}
606
607static uint32_t guess_alignment(uint32_t off)
608{
609 /* find greatest power of two which divides the offset */
610 if(off == 0)
611 return 1;
612 uint32_t a = 1;
613 while(off % (2 * a) == 0)
614 a *= 2;
615 return a;
616}
617
618struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
619 sb_color_printf cprintf, enum sb_error_t *err)
620{
621 uint8_t *buf = NULL;
622 struct sb_file_t *sb_file = NULL;
623
624 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
625 #define fatal(e, ...) \
626 do { if(err) *err = e; \
627 cprintf(u, true, GREY, __VA_ARGS__); \
628 free(buf); \
629 sb_free(sb_file); \
630 return NULL; } while(0)
631 #define print_hex(c, p, len, nl) \
632 do { printf(c, ""); print_hex(p, len, nl); } while(0)
633
634 FILE *f = fopen(filename, "rb");
635 if(f == NULL)
636 fatal(SB_OPEN_ERROR, "Cannot open file for reading\n");
637 fseek(f, 0, SEEK_END);
638 long filesize = ftell(f);
639 fseek(f, 0, SEEK_SET);
640 buf = xmalloc(filesize);
641 if(fread(buf, filesize, 1, f) != 1)
642 {
643 fclose(f);
644 fatal(SB_READ_ERROR, "Cannot read file\n");
645 }
646 fclose(f);
647
648 struct sha_1_params_t sha_1_params;
649 sb_file = xmalloc(sizeof(struct sb_file_t));
650 memset(sb_file, 0, sizeof(struct sb_file_t));
651 struct sb_header_t *sb_header = (struct sb_header_t *)buf;
652
653 sb_file->image_size = sb_header->image_size;
654 sb_file->minor_version = sb_header->minor_ver;
655 sb_file->flags = sb_header->flags;
656 sb_file->drive_tag = sb_header->drive_tag;
657 sb_file->first_boot_sec_id = sb_header->first_boot_sec_id;
658
659 if(memcmp(sb_header->signature, "STMP", 4) != 0)
660 fatal(SB_FORMAT_ERROR, "Bad signature\n");
661 if(sb_header->image_size * BLOCK_SIZE > filesize)
662 fatal(SB_FORMAT_ERROR, "File too small");
663 if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
664 fatal(SB_FORMAT_ERROR, "Bad header size");
665 if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
666 fatal(SB_FORMAT_ERROR, "Bad section header size");
667
668 if(filesize > sb_header->image_size * BLOCK_SIZE)
669 {
670 printf(GREY, "[Restrict file size from %lu to %d bytes]\n", filesize,
671 sb_header->image_size * BLOCK_SIZE);
672 filesize = sb_header->image_size * BLOCK_SIZE;
673 }
674
675 printf(BLUE, "Basic info:\n");
676 printf(GREEN, " SB version: ");
677 printf(YELLOW, "%d.%d\n", sb_header->major_ver, sb_header->minor_ver);
678 printf(GREEN, " Header SHA-1: ");
679 byte *hdr_sha1 = sb_header->sha1_header;
680 print_hex(YELLOW, hdr_sha1, 20, false);
681 /* Check SHA1 sum */
682 byte computed_sha1[20];
683 sha_1_init(&sha_1_params);
684 sha_1_update(&sha_1_params, &sb_header->signature[0],
685 sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header));
686 sha_1_finish(&sha_1_params);
687 sha_1_output(&sha_1_params, computed_sha1);
688 if(memcmp(hdr_sha1, computed_sha1, 20) == 0)
689 printf(RED, " Ok\n");
690 else
691 printf(RED, " Failed\n");
692 printf(GREEN, " Flags: ");
693 printf(YELLOW, "%x\n", sb_header->flags);
694 printf(GREEN, " Total file size : ");
695 printf(YELLOW, "%ld\n", filesize);
696
697 /* Sizes and offsets */
698 printf(BLUE, "Sizes and offsets:\n");
699 printf(GREEN, " # of encryption keys = ");
700 printf(YELLOW, "%d\n", sb_header->nr_keys);
701 printf(GREEN, " # of sections = ");
702 printf(YELLOW, "%d\n", sb_header->nr_sections);
703
704 /* Versions */
705 printf(BLUE, "Versions\n");
706
707 printf(GREEN, " Random 1: ");
708 print_hex(YELLOW, sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true);
709 printf(GREEN, " Random 2: ");
710 print_hex(YELLOW, sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true);
711
712 uint64_t micros = sb_header->timestamp;
713 time_t seconds = (micros / (uint64_t)1000000L);
714 struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
715 seconds += mktime(&tm_base);
716 struct tm *time = gmtime(&seconds);
717 printf(GREEN, " Creation date/time = ");
718 printf(YELLOW, "%s", asctime(time));
719
720 struct sb_version_t product_ver = sb_header->product_ver;
721 fix_version(&product_ver);
722 struct sb_version_t component_ver = sb_header->component_ver;
723 fix_version(&component_ver);
724
725 memcpy(&sb_file->product_ver, &product_ver, sizeof(product_ver));
726 memcpy(&sb_file->component_ver, &component_ver, sizeof(component_ver));
727
728 printf(GREEN, " Product version = ");
729 printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision);
730 printf(GREEN, " Component version = ");
731 printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision);
732
733 printf(GREEN, " Drive tag = ");
734 printf(YELLOW, "%x\n", sb_header->drive_tag);
735 printf(GREEN, " First boot tag offset = ");
736 printf(YELLOW, "%x\n", sb_header->first_boot_tag_off);
737 printf(GREEN, " First boot section ID = ");
738 printf(YELLOW, "0x%08x\n", sb_header->first_boot_sec_id);
739
740 /* encryption cbc-mac */
741 byte real_key[16];
742 bool valid_key = false; /* false until a matching key was found */
743
744 if(sb_header->nr_keys > 0)
745 {
746 byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys);
747 printf(BLUE, "Encryption keys\n");
748 for(int i = 0; i < g_nr_keys; i++)
749 {
750 printf(RED, " Key %d: ", i);
751 printf(YELLOW, "");
752 print_key(&g_key_array[i], true);
753 printf(GREEN, " CBC-MAC: ");
754 /* check it */
755 byte zero[16];
756 memset(zero, 0, 16);
757 int ret = crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
758 &g_key_array[i], zero, &cbcmacs[i], 1);
759 if(ret != CRYPTO_ERROR_SUCCESS)
760 {
761 free(cbcmacs);
762 fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d", ret);
763 }
764 print_hex(YELLOW, cbcmacs[i], 16, true);
765 }
766
767 printf(BLUE, "DEK\n");
768 for(int i = 0; i < sb_header->nr_keys; i++)
769 {
770 printf(RED, " Entry %d\n", i);
771 uint32_t ofs = sizeof(struct sb_header_t)
772 + sizeof(struct sb_section_header_t) * sb_header->nr_sections
773 + sizeof(struct sb_key_dictionary_entry_t) * i;
774 struct sb_key_dictionary_entry_t *dict_entry =
775 (struct sb_key_dictionary_entry_t *)&buf[ofs];
776 /* cbc mac */
777 printf(GREEN, " Encrypted key: ");
778 print_hex(YELLOW, dict_entry->key, 16, true);
779 printf(GREEN, " CBC-MAC : ");
780 print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
781 /* check it */
782 int idx = 0;
783 while(idx < g_nr_keys && memcmp(dict_entry->hdr_cbc_mac, cbcmacs[idx], 16) != 0)
784 idx++;
785 if(idx != g_nr_keys)
786 {
787 printf(RED, " Match\n");
788 /* decrypt */
789 byte decrypted_key[16];
790 byte iv[16];
791 memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
792 int ret = crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[idx], iv, NULL, 0);
793 if(ret != CRYPTO_ERROR_SUCCESS)
794 {
795 free(cbcmacs);
796 fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d\n", ret);
797 }
798 printf(GREEN, " Decrypted key: ");
799 print_hex(YELLOW, decrypted_key, 16, false);
800 if(valid_key)
801 {
802 if(memcmp(real_key, decrypted_key, 16) == 0)
803 printf(RED, " Cross-Check Ok");
804 else
805 printf(RED, " Cross-Check Failed");
806 }
807 else
808 {
809 memcpy(real_key, decrypted_key, 16);
810 valid_key = true;
811 }
812 printf(OFF, "\n");
813 }
814 else
815 printf(RED, " Don't Match\n");
816 }
817
818 free(cbcmacs);
819
820 if(!valid_key)
821 fatal(SB_NO_VALID_KEY, "No valid key found\n");
822
823 if(getenv("SB_REAL_KEY") != 0)
824 {
825 struct crypto_key_t k;
826 char *env = getenv("SB_REAL_KEY");
827 if(!parse_key(&env, &k) || *env)
828 bug("Invalid SB_REAL_KEY\n");
829 memcpy(real_key, k.u.key, 16);
830 }
831
832 printf(RED, " Summary:\n");
833 printf(GREEN, " Real key: ");
834 print_hex(YELLOW, real_key, 16, true);
835 printf(GREEN, " IV : ");
836 print_hex(YELLOW, buf, 16, true);
837
838 sb_file->override_real_key = true;
839 memcpy(sb_file->real_key, real_key, 16);
840 sb_file->override_crypto_iv = true;
841 memcpy(sb_file->crypto_iv, buf, 16);
842 }
843
844 /* sections */
845 if(!raw_mode)
846 {
847 sb_file->nr_sections = sb_header->nr_sections;
848 sb_file->sections = xmalloc(sb_file->nr_sections * sizeof(struct sb_section_t));
849 memset(sb_file->sections, 0, sb_file->nr_sections * sizeof(struct sb_section_t));
850 printf(BLUE, "Sections\n");
851 for(int i = 0; i < sb_header->nr_sections; i++)
852 {
853 uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t);
854 struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&buf[ofs];
855
856 char name[5];
857 sb_fill_section_name(name, sec_hdr->identifier);
858 int pos = sec_hdr->offset * BLOCK_SIZE;
859 int size = sec_hdr->size * BLOCK_SIZE;
860 int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE);
861 int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
862
863 printf(GREEN, " Section ");
864 printf(YELLOW, "'%s'\n", name);
865 printf(GREEN, " pos = ");
866 printf(YELLOW, "%8x - %8x\n", pos, pos+size);
867 printf(GREEN, " len = ");
868 printf(YELLOW, "%8x\n", size);
869 printf(GREEN, " flags = ");
870 printf(YELLOW, "%8x", sec_hdr->flags);
871 if(data_sec)
872 printf(RED, " Data Section");
873 else
874 printf(RED, " Boot Section");
875 if(encrypted)
876 printf(RED, " (Encrypted)");
877 printf(OFF, "\n");
878
879 /* save it */
880 byte *sec = xmalloc(size);
881 if(encrypted)
882 cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0);
883 else
884 memcpy(sec, buf + pos, size);
885
886 struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier,
887 sec, size, " ", u, cprintf, err);
888 if(s)
889 {
890 s->is_cleartext = !encrypted;
891 s->alignment = guess_alignment(pos);
892 memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t));
893 free(s);
894 }
895 else
896 fatal(*err, "Error reading section\n");
897
898 free(sec);
899 }
900 }
901 else
902 {
903 /* advanced raw mode */
904 printf(BLUE, "Commands\n");
905 uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE;
906 byte iv[16];
907 const char *indent = " ";
908 while(true)
909 {
910 /* restart with IV */
911 memcpy(iv, buf, 16);
912 byte cmd[BLOCK_SIZE];
913 if(sb_header->nr_keys > 0)
914 cbc_mac(buf + offset, cmd, 1, real_key, iv, &iv, 0);
915 else
916 memcpy(cmd, buf + offset, BLOCK_SIZE);
917 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd;
918 printf(OFF, "%s", indent);
919 uint8_t checksum = instruction_checksum(hdr);
920 if(checksum != hdr->checksum)
921 printf(GREY, "[Bad checksum']");
922
923 if(hdr->opcode == SB_INST_NOP)
924 {
925 printf(RED, "NOOP\n");
926 offset += BLOCK_SIZE;
927 }
928 else if(hdr->opcode == SB_INST_TAG)
929 {
930 struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr;
931 printf(RED, "BTAG");
932 printf(OFF, " | ");
933 printf(BLUE, "sec=0x%08x", tag->identifier);
934 printf(OFF, " | ");
935 printf(GREEN, "cnt=0x%08x", tag->len);
936 printf(OFF, " | ");
937 printf(YELLOW, "flg=0x%08x", tag->flags);
938 if(tag->hdr.flags & SB_INST_LAST_TAG)
939 {
940 printf(OFF, " | ");
941 printf(RED, " Last section");
942 }
943 printf(OFF, "\n");
944 offset += sizeof(struct sb_instruction_tag_t);
945
946 char name[5];
947 sb_fill_section_name(name, tag->identifier);
948 int pos = offset;
949 int size = tag->len * BLOCK_SIZE;
950 int data_sec = !(tag->flags & SECTION_BOOTABLE);
951 int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
952
953 printf(GREEN, "%sSection ", indent);
954 printf(YELLOW, "'%s'\n", name);
955 printf(GREEN, "%s pos = ", indent);
956 printf(YELLOW, "%8x - %8x\n", pos, pos+size);
957 printf(GREEN, "%s len = ", indent);
958 printf(YELLOW, "%8x\n", size);
959 printf(GREEN, "%s flags = ", indent);
960 printf(YELLOW, "%8x", tag->flags);
961 if(data_sec)
962 printf(RED, " Data Section");
963 else
964 printf(RED, " Boot Section");
965 if(encrypted)
966 printf(RED, " (Encrypted)");
967 printf(OFF, "\n");
968
969 /* save it */
970 byte *sec = xmalloc(size);
971 if(encrypted)
972 cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0);
973 else
974 memcpy(sec, buf + pos, size);
975
976 struct sb_section_t *s = read_section(data_sec, tag->identifier,
977 sec, size, " ", u, cprintf, err);
978 if(s)
979 {
980 s->is_cleartext = !encrypted;
981 s->alignment = guess_alignment(pos);
982 sb_file->sections = augment_array(sb_file->sections,
983 sizeof(struct sb_section_t), sb_file->nr_sections++,
984 s, 1);
985 free(s);
986 }
987 else
988 fatal(*err, "Error reading section\n");
989 free(sec);
990
991 /* last one ? */
992 if(tag->hdr.flags & SB_INST_LAST_TAG)
993 break;
994 offset += size;
995 }
996 else
997 {
998 fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
999 break;
1000 }
1001 }
1002 }
1003
1004 /* final signature */
1005 printf(BLUE, "Final signature:\n");
1006 byte decrypted_block[32];
1007 if(sb_header->nr_keys > 0)
1008 {
1009 printf(GREEN, " Encrypted SHA-1:\n");
1010 byte *encrypted_block = &buf[filesize - 32];
1011 printf(OFF, " ");
1012 print_hex(YELLOW, encrypted_block, 16, true);
1013 printf(OFF, " ");
1014 print_hex(YELLOW, encrypted_block + 16, 16, true);
1015 /* decrypt it */
1016 cbc_mac(encrypted_block, decrypted_block, 2, real_key, buf, NULL, 0);
1017 }
1018 else
1019 memcpy(decrypted_block, &buf[filesize - 32], 32);
1020 printf(GREEN, " File SHA-1:\n ");
1021 print_hex(YELLOW, decrypted_block, 20, false);
1022 /* check it */
1023 sha_1_init(&sha_1_params);
1024 sha_1_update(&sha_1_params, buf, filesize - 32);
1025 sha_1_finish(&sha_1_params);
1026 sha_1_output(&sha_1_params, computed_sha1);
1027 if(memcmp(decrypted_block, computed_sha1, 20) == 0)
1028 printf(RED, " Ok\n");
1029 else
1030 {
1031 printf(RED, " Failed\n");
1032 fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n");
1033 }
1034 free(buf);
1035
1036 return sb_file;
1037 #undef printf
1038 #undef fatal
1039 #undef print_hex
1040}
1041
1042void sb_free_section(struct sb_section_t sec)
1043{
1044 for(int j = 0; j < sec.nr_insts; j++)
1045 {
1046 free(sec.insts[j].padding);
1047 free(sec.insts[j].data);
1048 }
1049 free(sec.insts);
1050}
1051
1052void sb_free(struct sb_file_t *file)
1053{
1054 if(!file) return;
1055
1056 for(int i = 0; i < file->nr_sections; i++)
1057 sb_free_section(file->sections[i]);
1058
1059 free(file->sections);
1060 free(file);
1061}
1062
1063void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
1064{
1065 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
1066 #define print_hex(c, p, len, nl) \
1067 do { printf(c, ""); print_hex(p, len, nl); } while(0)
1068
1069 #define TREE RED
1070 #define HEADER GREEN
1071 #define TEXT YELLOW
1072 #define TEXT2 BLUE
1073 #define SEP OFF
1074
1075 printf(HEADER, "SB File\n");
1076 printf(TREE, "+-");
1077 printf(HEADER, "Version: ");
1078 printf(TEXT, "1.%d\n", file->minor_version);
1079 printf(TREE, "+-");
1080 printf(HEADER, "Flags: ");
1081 printf(TEXT, "%x\n", file->flags);
1082 printf(TREE, "+-");
1083 printf(HEADER, "Drive Tag: ");
1084 printf(TEXT, "%x\n", file->drive_tag);
1085 printf(TREE, "+-");
1086 printf(HEADER, "First Boot Section ID: ");
1087 char name[5];
1088 sb_fill_section_name(name, file->first_boot_sec_id);
1089 printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name);
1090
1091 if(file->override_real_key)
1092 {
1093 printf(TREE, "+-");
1094 printf(HEADER, "Real key: ");
1095 print_hex(TEXT, file->real_key, 16, true);
1096 }
1097 if(file->override_crypto_iv)
1098 {
1099 printf(TREE, "+-");
1100 printf(HEADER, "IV : ");
1101 print_hex(TEXT, file->crypto_iv, 16, true);
1102 }
1103 printf(TREE, "+-");
1104 printf(HEADER, "Product Version: ");
1105 printf(TEXT, "%X.%X.%X\n", file->product_ver.major, file->product_ver.minor,
1106 file->product_ver.revision);
1107 printf(TREE, "+-");
1108 printf(HEADER, "Component Version: ");
1109 printf(TEXT, "%X.%X.%X\n", file->component_ver.major, file->component_ver.minor,
1110 file->component_ver.revision);
1111
1112 for(int i = 0; i < file->nr_sections; i++)
1113 {
1114 struct sb_section_t *sec = &file->sections[i];
1115 printf(TREE, "+-");
1116 printf(HEADER, "Section\n");
1117 printf(TREE,"| +-");
1118 printf(HEADER, "Identifier: ");
1119 sb_fill_section_name(name, sec->identifier);
1120 printf(TEXT, "%08x (%s)\n", sec->identifier, name);
1121 printf(TREE, "| +-");
1122 printf(HEADER, "Type: ");
1123 printf(TEXT, "%s (%s)\n", sec->is_data ? "Data Section" : "Boot Section",
1124 sec->is_cleartext ? "Cleartext" : "Encrypted");
1125 printf(TREE, "| +-");
1126 printf(HEADER, "Alignment: ");
1127 printf(TEXT, "%d (bytes)\n", sec->alignment);
1128 printf(TREE, "| +-");
1129 printf(HEADER, "Instructions\n");
1130 for(int j = 0; j < sec->nr_insts; j++)
1131 {
1132 struct sb_inst_t *inst = &sec->insts[j];
1133 printf(TREE, "| | +-");
1134 switch(inst->inst)
1135 {
1136 case SB_INST_DATA:
1137 printf(HEADER, "DATA");
1138 printf(SEP, " | ");
1139 printf(TEXT, "size=0x%08x\n", inst->size);
1140 break;
1141 case SB_INST_CALL:
1142 case SB_INST_JUMP:
1143 printf(HEADER, "%s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP");
1144 printf(SEP, " | ");
1145 printf(TEXT, "addr=0x%08x", inst->addr);
1146 printf(SEP, " | ");
1147 printf(TEXT2, "arg=0x%08x\n", inst->argument);
1148 break;
1149 case SB_INST_LOAD:
1150 printf(HEADER, "LOAD");
1151 printf(SEP, " | ");
1152 printf(TEXT, "addr=0x%08x", inst->addr);
1153 printf(SEP, " | ");
1154 printf(TEXT2, "len=0x%08x\n", inst->size);
1155 break;
1156 case SB_INST_FILL:
1157 printf(HEADER, "FILL");
1158 printf(SEP, " | ");
1159 printf(TEXT, "addr=0x%08x", inst->addr);
1160 printf(SEP, " | ");
1161 printf(TEXT2, "len=0x%08x", inst->size);
1162 printf(SEP, " | ");
1163 printf(TEXT2, "pattern=0x%08x\n", inst->pattern);
1164 break;
1165 case SB_INST_MODE:
1166 printf(HEADER, "MODE");
1167 printf(SEP, " | ");
1168 printf(TEXT, "mod=0x%08x\n", inst->addr);
1169 break;
1170 case SB_INST_NOP:
1171 printf(HEADER, "NOOP\n");
1172 break;
1173 default:
1174 printf(GREY, "[Unknown instruction %x]\n", inst->inst);
1175 }
1176 }
1177 }
1178
1179 #undef printf
1180 #undef print_hex
1181}