diff options
Diffstat (limited to 'utils/imxtools/sbtools/sb.c')
-rw-r--r-- | utils/imxtools/sbtools/sb.c | 151 |
1 files changed, 79 insertions, 72 deletions
diff --git a/utils/imxtools/sbtools/sb.c b/utils/imxtools/sbtools/sb.c index 385c5e5ded..183434efad 100644 --- a/utils/imxtools/sbtools/sb.c +++ b/utils/imxtools/sbtools/sb.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #include "crypto.h" | 27 | #include "crypto.h" |
28 | #include "sb.h" | 28 | #include "sb.h" |
29 | 29 | ||
30 | #define ALIGN_DOWN(n, a) (((n)/(a))*(a)) | ||
31 | #define ALIGN_UP(n, a) ALIGN_DOWN((n)+((a)-1),a) | ||
32 | |||
30 | static void fill_gaps(struct sb_file_t *sb) | 33 | static void fill_gaps(struct sb_file_t *sb) |
31 | { | 34 | { |
32 | for(int i = 0; i < sb->nr_sections; i++) | 35 | for(int i = 0; i < sb->nr_sections; i++) |
@@ -58,27 +61,33 @@ static void compute_sb_offsets(struct sb_file_t *sb, void *u, generic_printf_t c | |||
58 | /* sections */ | 61 | /* sections */ |
59 | for(int i = 0; i < sb->nr_sections; i++) | 62 | for(int i = 0; i < sb->nr_sections; i++) |
60 | { | 63 | { |
61 | /* each section has a preliminary TAG command */ | ||
62 | sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE; | ||
63 | /* we might need to pad the section so compute next alignment */ | ||
64 | uint32_t alignment = BLOCK_SIZE; | ||
65 | if((i + 1) < sb->nr_sections) | ||
66 | alignment = sb->sections[i + 1].alignment; | ||
67 | alignment /= BLOCK_SIZE; /* alignment in block sizes */ | ||
68 | |||
69 | struct sb_section_t *sec = &sb->sections[i]; | 64 | struct sb_section_t *sec = &sb->sections[i]; |
65 | /* we need to make sure section starts on the right alignment, | ||
66 | * and since each section starts with a boot tag, we need to ensure | ||
67 | * that the boot tag is at address X such that X+BLOCK_SIZE is a | ||
68 | * multiple of the alignment */ | ||
69 | uint32_t alignment = sb->sections[i].alignment / BLOCK_SIZE; | ||
70 | sb->image_size = ALIGN_UP(sb->image_size + 1, alignment) - 1; | ||
71 | /* update padding of previous section */ | ||
72 | if(i > 0) | ||
73 | sb->sections[i - 1].pad_size = sb->image_size - | ||
74 | sb->sections[i - 1].file_offset - sb->sections[i - 1].sec_size; | ||
75 | /* each section has a preliminary TAG command */ | ||
76 | sb->image_size += 1; | ||
77 | sec->file_offset = sb->image_size; | ||
78 | /* compute section size */ | ||
70 | sec->sec_size = 0; | 79 | sec->sec_size = 0; |
80 | sec->pad_size = 0; | ||
71 | 81 | ||
72 | char name[5]; | 82 | char name[5]; |
73 | sb_fill_section_name(name, sec->identifier); | 83 | sb_fill_section_name(name, sec->identifier); |
74 | printf(BLUE, "%s", sec->is_data ? "Data" : "Boot"); | 84 | printf(BLUE, "%s", sec->is_data ? "Data" : "Boot"); |
75 | printf(GREEN, " Section"); | 85 | printf(GREEN, " Section "); |
76 | printf(YELLOW, "'%s'", name); | 86 | printf(YELLOW, "'%s'", name); |
77 | if(sec->is_cleartext) | 87 | if(sec->is_cleartext) |
78 | printf(RED, " (cleartext)"); | 88 | printf(RED, " (cleartext)"); |
79 | printf(OFF, "\n"); | 89 | printf(OFF, "\n"); |
80 | 90 | ||
81 | sec->file_offset = sb->image_size; | ||
82 | for(int j = 0; j < sec->nr_insts; j++) | 91 | for(int j = 0; j < sec->nr_insts; j++) |
83 | { | 92 | { |
84 | struct sb_inst_t *inst = &sec->insts[j]; | 93 | struct sb_inst_t *inst = &sec->insts[j]; |
@@ -87,7 +96,6 @@ static void compute_sb_offsets(struct sb_file_t *sb, void *u, generic_printf_t c | |||
87 | printf(RED, " %s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP"); | 96 | printf(RED, " %s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP"); |
88 | printf(OFF, " | "); printf(BLUE, "addr=0x%08x", inst->addr); | 97 | printf(OFF, " | "); printf(BLUE, "addr=0x%08x", inst->addr); |
89 | printf(OFF, " | "); printf(GREEN, "arg=0x%08x\n", inst->argument); | 98 | printf(OFF, " | "); printf(GREEN, "arg=0x%08x\n", inst->argument); |
90 | sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; | ||
91 | sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; | 99 | sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; |
92 | } | 100 | } |
93 | else if(inst->inst == SB_INST_FILL) | 101 | else if(inst->inst == SB_INST_FILL) |
@@ -96,7 +104,6 @@ static void compute_sb_offsets(struct sb_file_t *sb, void *u, generic_printf_t c | |||
96 | printf(OFF, " | "); printf(BLUE, "addr=0x%08x", inst->addr); | 104 | printf(OFF, " | "); printf(BLUE, "addr=0x%08x", inst->addr); |
97 | printf(OFF, " | "); printf(GREEN, "len=0x%08x", inst->size); | 105 | printf(OFF, " | "); printf(GREEN, "len=0x%08x", inst->size); |
98 | printf(OFF, " | "); printf(YELLOW, "pattern=0x%08x\n", inst->pattern); | 106 | printf(OFF, " | "); printf(YELLOW, "pattern=0x%08x\n", inst->pattern); |
99 | sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; | ||
100 | sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; | 107 | sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; |
101 | } | 108 | } |
102 | else if(inst->inst == SB_INST_LOAD) | 109 | else if(inst->inst == SB_INST_LOAD) |
@@ -105,30 +112,25 @@ static void compute_sb_offsets(struct sb_file_t *sb, void *u, generic_printf_t c | |||
105 | printf(OFF, " | "); printf(BLUE, "addr=0x%08x", inst->addr); | 112 | printf(OFF, " | "); printf(BLUE, "addr=0x%08x", inst->addr); |
106 | printf(OFF, " | "); printf(GREEN, "len=0x%08x\n", inst->size); | 113 | printf(OFF, " | "); printf(GREEN, "len=0x%08x\n", inst->size); |
107 | /* load header */ | 114 | /* load header */ |
108 | sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; | ||
109 | sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; | 115 | sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; |
110 | /* data + alignment */ | 116 | /* data + alignment */ |
111 | sb->image_size += (inst->size + inst->padding_size) / BLOCK_SIZE; | ||
112 | sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE; | 117 | sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE; |
113 | } | 118 | } |
114 | else if(inst->inst == SB_INST_MODE) | 119 | else if(inst->inst == SB_INST_MODE) |
115 | { | 120 | { |
116 | printf(RED, " MODE"); | 121 | printf(RED, " MODE"); |
117 | printf(OFF, " | "); printf(BLUE, "mod=0x%08x\n", inst->addr); | 122 | printf(OFF, " | "); printf(BLUE, "mod=0x%08x\n", inst->addr); |
118 | sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; | ||
119 | sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; | 123 | sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; |
120 | } | 124 | } |
121 | else if(inst->inst == SB_INST_DATA) | 125 | else if(inst->inst == SB_INST_DATA) |
122 | { | 126 | { |
123 | printf(RED, " DATA"); | 127 | printf(RED, " DATA"); |
124 | printf(OFF, " | "); printf(BLUE, "size=0x%08x\n", inst->size); | 128 | printf(OFF, " | "); printf(BLUE, "size=0x%08x\n", inst->size); |
125 | sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; | ||
126 | sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; | 129 | sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; |
127 | } | 130 | } |
128 | else if(inst->inst == SB_INST_NOP) | 131 | else if(inst->inst == SB_INST_NOP) |
129 | { | 132 | { |
130 | printf(RED, " NOOP\n"); | 133 | printf(RED, " NOOP\n"); |
131 | sb->image_size += sizeof(struct sb_instruction_nop_t) / BLOCK_SIZE; | ||
132 | sec->sec_size += sizeof(struct sb_instruction_nop_t) / BLOCK_SIZE; | 134 | sec->sec_size += sizeof(struct sb_instruction_nop_t) / BLOCK_SIZE; |
133 | } | 135 | } |
134 | else | 136 | else |
@@ -136,50 +138,7 @@ static void compute_sb_offsets(struct sb_file_t *sb, void *u, generic_printf_t c | |||
136 | cprintf(u, true, GREY, "die on inst %d\n", inst->inst); | 138 | cprintf(u, true, GREY, "die on inst %d\n", inst->inst); |
137 | } | 139 | } |
138 | } | 140 | } |
139 | /* we need to make sure next section starts on the right alignment. | 141 | sb->image_size += sec->sec_size; |
140 | * Since each section starts with a boot tag, we thus need to ensure | ||
141 | * that this sections ends at adress X such that X+BLOCK_SIZE is | ||
142 | * a multiple of the alignment. | ||
143 | * For data sections, we just add random data, otherwise we add nops */ | ||
144 | uint32_t missing_sz = alignment - ((sb->image_size + 1) % alignment); | ||
145 | if(missing_sz != alignment) | ||
146 | { | ||
147 | struct sb_inst_t *aug_insts; | ||
148 | int nr_aug_insts = 0; | ||
149 | |||
150 | if(sb->sections[i].is_data) | ||
151 | { | ||
152 | nr_aug_insts = 1; | ||
153 | aug_insts = xmalloc(sizeof(struct sb_inst_t)); | ||
154 | memset(aug_insts, 0, sizeof(struct sb_inst_t)); | ||
155 | aug_insts[0].inst = SB_INST_DATA; | ||
156 | aug_insts[0].size = missing_sz * BLOCK_SIZE; | ||
157 | aug_insts[0].data = xmalloc(missing_sz * BLOCK_SIZE); | ||
158 | generate_random_data(aug_insts[0].data, missing_sz * BLOCK_SIZE); | ||
159 | printf(RED, " DATA"); | ||
160 | printf(OFF, " | "); printf(BLUE, "size=0x%08x\n", aug_insts[0].size); | ||
161 | } | ||
162 | else | ||
163 | { | ||
164 | nr_aug_insts = missing_sz; | ||
165 | aug_insts = xmalloc(sizeof(struct sb_inst_t) * nr_aug_insts); | ||
166 | memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts); | ||
167 | for(int j = 0; j < nr_aug_insts; j++) | ||
168 | { | ||
169 | aug_insts[j].inst = SB_INST_NOP; | ||
170 | printf(RED, " NOOP\n"); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t), | ||
175 | sb->sections[i].nr_insts, aug_insts, nr_aug_insts); | ||
176 | sb->sections[i].nr_insts += nr_aug_insts; | ||
177 | free(aug_insts); | ||
178 | |||
179 | /* augment image and section size */ | ||
180 | sb->image_size += missing_sz; | ||
181 | sec->sec_size += missing_sz; | ||
182 | } | ||
183 | } | 142 | } |
184 | /* final signature */ | 143 | /* final signature */ |
185 | sb->image_size += 2; | 144 | sb->image_size += 2; |
@@ -222,14 +181,13 @@ static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr) | |||
222 | sb_hdr->flags = sb->flags; | 181 | sb_hdr->flags = sb->flags; |
223 | sb_hdr->image_size = sb->image_size; | 182 | sb_hdr->image_size = sb->image_size; |
224 | sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE; | 183 | sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE; |
225 | sb_hdr->first_boot_sec_id = sb->sections[0].identifier; | 184 | sb_hdr->first_boot_sec_id = sb->sections[sb->first_boot_sec].identifier; |
226 | sb_hdr->nr_keys = g_nr_keys; | 185 | sb_hdr->nr_keys = g_nr_keys; |
227 | sb_hdr->nr_sections = sb->nr_sections; | 186 | sb_hdr->nr_sections = sb->nr_sections; |
228 | sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE; | 187 | sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE; |
229 | sb_hdr->key_dict_off = sb_hdr->header_size + | 188 | sb_hdr->key_dict_off = sb_hdr->header_size + |
230 | sb_hdr->sec_hdr_size * sb_hdr->nr_sections; | 189 | sb_hdr->sec_hdr_size * sb_hdr->nr_sections; |
231 | sb_hdr->first_boot_tag_off = sb_hdr->key_dict_off + | 190 | sb_hdr->first_boot_tag_off = sb->sections[sb->first_boot_sec].file_offset - 1; |
232 | sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE; | ||
233 | generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0)); | 191 | generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0)); |
234 | generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1)); | 192 | generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1)); |
235 | /* Version 1.0 has 6 bytes of random padding, | 193 | /* Version 1.0 has 6 bytes of random padding, |
@@ -277,7 +235,11 @@ static void produce_section_tag_cmd(struct sb_section_t *sec, | |||
277 | tag->hdr.opcode = SB_INST_TAG; | 235 | tag->hdr.opcode = SB_INST_TAG; |
278 | tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0; | 236 | tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0; |
279 | tag->identifier = sec->identifier; | 237 | tag->identifier = sec->identifier; |
280 | tag->len = sec->sec_size; | 238 | /* there is a catch here: in the section header at the beginning of the SB |
239 | * file, we put the *useful* length of the section (without padding) but | ||
240 | * the bootloader will not use those and only use the TAG commande which | ||
241 | * need to give the *actual* length (with padding) */ | ||
242 | tag->len = sec->sec_size + sec->pad_size; | ||
281 | tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE) | 243 | tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE) |
282 | | (sec->is_cleartext ? SECTION_CLEARTEXT : 0) | 244 | | (sec->is_cleartext ? SECTION_CLEARTEXT : 0) |
283 | | sec->other_flags; | 245 | | sec->other_flags; |
@@ -330,15 +292,24 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void * | |||
330 | /* init CBC-MACs */ | 292 | /* init CBC-MACs */ |
331 | for(int i = 0; i < g_nr_keys; i++) | 293 | for(int i = 0; i < g_nr_keys; i++) |
332 | memset(cbc_macs[i], 0, 16); | 294 | memset(cbc_macs[i], 0, 16); |
333 | 295 | /* fill gaps */ | |
334 | fill_gaps(sb); | 296 | fill_gaps(sb); |
335 | if(sb->nr_sections == 0 || sb->sections[0].is_data) | 297 | /* find first bootable section */ |
298 | sb->first_boot_sec = -1; | ||
299 | for(int i = 0; i < sb->nr_sections; i++) | ||
300 | if(!sb->sections[i].is_data) | ||
301 | { | ||
302 | sb->first_boot_sec = i; | ||
303 | break; | ||
304 | } | ||
305 | if(sb->first_boot_sec == -1) | ||
336 | { | 306 | { |
337 | cprintf(u, true, GREY, "First section of the image is not bootable, I cannot handle that.\n"); | 307 | cprintf(u, true, GREY, "Image contains no bootable section, I cannot handle that.\n"); |
338 | return SB_ERROR; | 308 | return SB_ERROR; |
339 | } | 309 | } |
310 | /* compute section offsets */ | ||
340 | compute_sb_offsets(sb, u, cprintf); | 311 | compute_sb_offsets(sb, u, cprintf); |
341 | 312 | /* generate random real key */ | |
342 | generate_random_data(real_key.u.key, 16); | 313 | generate_random_data(real_key.u.key, 16); |
343 | 314 | ||
344 | /* global SHA-1 */ | 315 | /* global SHA-1 */ |
@@ -406,6 +377,17 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void * | |||
406 | printf(YELLOW, "%02x", crypto_iv[j]); | 377 | printf(YELLOW, "%02x", crypto_iv[j]); |
407 | printf(OFF, "\n"); | 378 | printf(OFF, "\n"); |
408 | } | 379 | } |
380 | /* the first section might not start right after the header, pad with | ||
381 | * random data */ | ||
382 | unsigned init_gap = (sb->sections[0].file_offset - 1) * BLOCK_SIZE - (buf_p - buf); | ||
383 | if(init_gap > 0) | ||
384 | { | ||
385 | byte *data = xmalloc(init_gap); | ||
386 | generate_random_data(data, init_gap); | ||
387 | sha_1_update(&file_sha1, data, init_gap); | ||
388 | write(data, init_gap); | ||
389 | free(data); | ||
390 | } | ||
409 | /* produce sections data */ | 391 | /* produce sections data */ |
410 | for(int i = 0; i< sb_hdr.nr_sections; i++) | 392 | for(int i = 0; i< sb_hdr.nr_sections; i++) |
411 | { | 393 | { |
@@ -449,6 +431,31 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void * | |||
449 | free(data); | 431 | free(data); |
450 | } | 432 | } |
451 | } | 433 | } |
434 | /* pad section with random data or NOP */ | ||
435 | uint32_t pad_size = sb->sections[i].pad_size; | ||
436 | if(sb->sections[i].is_data) | ||
437 | { | ||
438 | byte *data = xmalloc(pad_size * BLOCK_SIZE); | ||
439 | generate_random_data(data, pad_size * BLOCK_SIZE); | ||
440 | sha_1_update(&file_sha1, data, pad_size * BLOCK_SIZE); | ||
441 | write(data, pad_size * BLOCK_SIZE); | ||
442 | free(data); | ||
443 | } | ||
444 | else | ||
445 | { | ||
446 | for(unsigned j = 0; j < pad_size; j++) | ||
447 | { | ||
448 | struct sb_instruction_nop_t cmd; | ||
449 | memset(&cmd, 0, sizeof(cmd)); | ||
450 | cmd.hdr.opcode = SB_INST_NOP; | ||
451 | cmd.hdr.checksum = instruction_checksum(&cmd.hdr); | ||
452 | if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) | ||
453 | crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE, | ||
454 | &real_key, cur_cbc_mac, &cur_cbc_mac, 1); | ||
455 | sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd)); | ||
456 | write(&cmd, sizeof(cmd)); | ||
457 | } | ||
458 | } | ||
452 | } | 459 | } |
453 | /* write file SHA-1 */ | 460 | /* write file SHA-1 */ |
454 | byte final_sig[32]; | 461 | byte final_sig[32]; |
@@ -458,11 +465,11 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void * | |||
458 | if(g_nr_keys > 0) | 465 | if(g_nr_keys > 0) |
459 | crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1); | 466 | crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1); |
460 | write(final_sig, 32); | 467 | write(final_sig, 32); |
461 | |||
462 | if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE) | 468 | if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE) |
463 | { | 469 | { |
464 | if(g_debug) | 470 | printf(GREY, "[ERROR][INTERNAL] SB image buffer was not entirely filled !\n"); |
465 | printf(GREY, u, true, "SB image buffer was not entirely filled !\n"); | 471 | printf(GREY, "[ERROR][INTERNAL] expected %u blocks, got %u\n", |
472 | (buf_p - buf) / BLOCK_SIZE, sb_hdr.image_size); | ||
466 | return SB_ERROR; | 473 | return SB_ERROR; |
467 | } | 474 | } |
468 | 475 | ||