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