summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2017-01-01 20:46:16 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2017-01-16 19:49:07 +0100
commit2df6b1fc43ab3cc7b07688a7c8d18f377a754c82 (patch)
tree385ecac7957387e3fdedb50f1faf62b841631ec3
parent4f7fea2addf4a5bc7c301e78f53d9080eaf43fb6 (diff)
downloadrockbox-2df6b1fc43ab3cc7b07688a7c8d18f377a754c82.tar.gz
rockbox-2df6b1fc43ab3cc7b07688a7c8d18f377a754c82.zip
imxtools: rework sb file production
The old code had some annoying way of dealing with padding by adding explicit instructions to the stream, which is 1) ugly 2) not in par with freescale tools. The trick, which this new version implements, is to put the useful length of the section in the section header, and the actual (with padding) length in the boot tag. This way the tools can just ignore padding instruction by reading the section header, and the bootloader can still load the image because it uses the boot tags. Also correctly handle the case where the first section does not start right after the header (there is a bug in freescale tools for this case by the way). There is an ambiguity in the way the padding instructions should be encrypted: the bootloader should logically treat them as regular instruction of the section stream, but it appears the freescale tools do not generate them as part of the stream and instead encrypt them like boot tags, which is stupid because there is no way the bootloader could decrypt them, and anyway we don't care because the bootloader doesn't decrypt them at all. Change-Id: Iabdc1d1f9f82d374779bf03efb75c2c3998f5b5d
-rw-r--r--utils/imxtools/sbtools/sb.c151
-rw-r--r--utils/imxtools/sbtools/sb.h4
2 files changed, 82 insertions, 73 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
30static void fill_gaps(struct sb_file_t *sb) 33static 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
diff --git a/utils/imxtools/sbtools/sb.h b/utils/imxtools/sbtools/sb.h
index cf826362de..9ab7fe7aba 100644
--- a/utils/imxtools/sbtools/sb.h
+++ b/utils/imxtools/sbtools/sb.h
@@ -195,7 +195,8 @@ struct sb_section_t
195 struct sb_inst_t *insts; 195 struct sb_inst_t *insts;
196 /* for production use */ 196 /* for production use */
197 uint32_t file_offset; /* in blocks */ 197 uint32_t file_offset; /* in blocks */
198 uint32_t sec_size; /* in blocks */ 198 uint32_t sec_size; /* in blocks, without padding */
199 uint32_t pad_size; /* padding size after the section until next section */
199}; 200};
200 201
201struct sb_file_t 202struct sb_file_t
@@ -217,6 +218,7 @@ struct sb_file_t
217 struct sb_version_t product_ver; 218 struct sb_version_t product_ver;
218 struct sb_version_t component_ver; 219 struct sb_version_t component_ver;
219 /* for production use */ 220 /* for production use */
221 int first_boot_sec; /* index in sections[] */
220 uint32_t image_size; /* in blocks */ 222 uint32_t image_size; /* in blocks */
221}; 223};
222 224