diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2014-10-31 16:09:28 +0100 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2024-10-27 09:12:31 -0400 |
commit | b8d35c042de327a7ac5b35496283cdc2ab22d991 (patch) | |
tree | 120919cd0ac0372cc52a298e78920bc21c103e37 | |
parent | d22bb548b23c4281fc0fa0862333d912069752ae (diff) | |
download | rockbox-b8d35c042de327a7ac5b35496283cdc2ab22d991.tar.gz rockbox-b8d35c042de327a7ac5b35496283cdc2ab22d991.zip |
rknanotools: fix rknano stages processing
Change-Id: Ia88f5aa2a6c56b312f80b31afab41d1dc68b871b
-rw-r--r-- | utils/rknanoutils/rkboottool/elf.c | 73 | ||||
-rw-r--r-- | utils/rknanoutils/rkboottool/elf.h | 5 | ||||
-rw-r--r-- | utils/rknanoutils/rkboottool/rkboottool.c | 211 |
3 files changed, 210 insertions, 79 deletions
diff --git a/utils/rknanoutils/rkboottool/elf.c b/utils/rknanoutils/rkboottool/elf.c index 481ab98dd6..78b29506a2 100644 --- a/utils/rknanoutils/rkboottool/elf.c +++ b/utils/rknanoutils/rkboottool/elf.c | |||
@@ -21,6 +21,14 @@ | |||
21 | #include "elf.h" | 21 | #include "elf.h" |
22 | #include "misc.h" | 22 | #include "misc.h" |
23 | 23 | ||
24 | static char *strdup(const char *str) | ||
25 | { | ||
26 | int len = strlen(str); | ||
27 | char *s = malloc(len + 1); | ||
28 | memcpy(s, str, len + 1); | ||
29 | return s; | ||
30 | } | ||
31 | |||
24 | /** | 32 | /** |
25 | * Definitions | 33 | * Definitions |
26 | * taken from elf.h linux header | 34 | * taken from elf.h linux header |
@@ -189,43 +197,55 @@ static struct elf_segment_t *elf_add_segment(struct elf_params_t *params) | |||
189 | } | 197 | } |
190 | 198 | ||
191 | void elf_add_load_section(struct elf_params_t *params, | 199 | void elf_add_load_section(struct elf_params_t *params, |
192 | uint32_t load_addr, uint32_t size, const void *section) | 200 | uint32_t load_addr, uint32_t size, const void *section, const char *name) |
193 | { | 201 | { |
194 | struct elf_section_t *sec = elf_add_section(params); | 202 | struct elf_section_t *sec = elf_add_section(params); |
203 | char buffer[32]; | ||
204 | if(name == NULL) | ||
205 | { | ||
206 | sprintf(buffer, ".text%d", params->unique_index++); | ||
207 | name = buffer; | ||
208 | } | ||
195 | 209 | ||
196 | sec->type = EST_LOAD; | 210 | sec->type = EST_LOAD; |
197 | sec->addr = load_addr; | 211 | sec->addr = load_addr; |
198 | sec->size = size; | 212 | sec->size = size; |
199 | sec->section = xmalloc(size); | 213 | sec->section = xmalloc(size); |
214 | sec->name = strdup(name); | ||
200 | memcpy(sec->section, section, size); | 215 | memcpy(sec->section, section, size); |
201 | } | 216 | } |
202 | 217 | ||
203 | void elf_add_fill_section(struct elf_params_t *params, | 218 | void elf_add_fill_section(struct elf_params_t *params, |
204 | uint32_t fill_addr, uint32_t size, uint32_t pattern) | 219 | uint32_t fill_addr, uint32_t size, uint32_t pattern) |
205 | { | 220 | { |
221 | char buffer[32]; | ||
222 | sprintf(buffer, ".bss%d", params->unique_index++); | ||
223 | |||
206 | if(pattern != 0x00) | 224 | if(pattern != 0x00) |
207 | { | 225 | { |
208 | printf("oops, non-zero filling, ignore fill section\n"); | 226 | printf("oops, non-zero filling, ignore fill section\n"); |
209 | return; | 227 | return; |
210 | } | 228 | } |
211 | 229 | ||
212 | struct elf_section_t *sec = elf_add_section(params); | 230 | struct elf_section_t *sec = elf_add_section(params); |
213 | 231 | ||
214 | sec->type = EST_FILL; | 232 | sec->type = EST_FILL; |
215 | sec->addr = fill_addr; | 233 | sec->addr = fill_addr; |
216 | sec->size = size; | 234 | sec->size = size; |
217 | sec->pattern = pattern; | 235 | sec->pattern = pattern; |
236 | sec->name = strdup(buffer); | ||
218 | } | 237 | } |
219 | 238 | ||
220 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | 239 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, |
221 | elf_printf_fn_t printf, void *user) | 240 | elf_printf_fn_t printf, void *user) |
222 | { | 241 | { |
223 | (void) printf; | 242 | (void) printf; |
224 | 243 | ||
225 | Elf32_Ehdr ehdr; | 244 | Elf32_Ehdr ehdr; |
226 | uint32_t phnum = 0; | 245 | uint32_t phnum = 0; |
227 | struct elf_section_t *sec = params->first_section; | 246 | struct elf_section_t *sec = params->first_section; |
228 | uint32_t offset = 0; | 247 | uint32_t offset = 0; |
248 | uint32_t strtbl_size = 1; /* offset 0 is for the NULL name */ | ||
229 | Elf32_Phdr phdr; | 249 | Elf32_Phdr phdr; |
230 | Elf32_Shdr shdr; | 250 | Elf32_Shdr shdr; |
231 | memset(&ehdr, 0, EI_NIDENT); | 251 | memset(&ehdr, 0, EI_NIDENT); |
@@ -241,7 +261,9 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
241 | { | 261 | { |
242 | sec->offset = 0; | 262 | sec->offset = 0; |
243 | } | 263 | } |
244 | 264 | sec->name_offset = strtbl_size; | |
265 | strtbl_size += strlen(sec->name) + 1; | ||
266 | |||
245 | phnum++; | 267 | phnum++; |
246 | sec = sec->next; | 268 | sec = sec->next; |
247 | } | 269 | } |
@@ -275,16 +297,14 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
275 | 297 | ||
276 | write(user, 0, &ehdr, sizeof ehdr); | 298 | write(user, 0, &ehdr, sizeof ehdr); |
277 | 299 | ||
278 | /* allocate enough size to hold any combinaison of .text/.bss in the string table: | 300 | /* the last name offset gives the size of the section, we need to add a small |
279 | * - one empty name ("\0") | 301 | * amount of .shstrtab name */ |
280 | * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0" | 302 | uint32_t shstrtab_index = strtbl_size; |
281 | * - one name ".shstrtab\0" */ | 303 | strtbl_size += strlen(".shstrtab") + 1; |
282 | char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 + | 304 | char *strtbl_content = malloc(strtbl_size); |
283 | phnum * (strlen(".textXXXX") + 1)); | 305 | /* create NULL and shstrtab names */ |
284 | |||
285 | strtbl_content[0] = '\0'; | 306 | strtbl_content[0] = '\0'; |
286 | strcpy(&strtbl_content[1], ".shstrtab"); | 307 | strcpy(&strtbl_content[shstrtab_index], ".shstrtab"); |
287 | uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1; | ||
288 | 308 | ||
289 | uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + | 309 | uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + |
290 | ehdr.e_shnum * ehdr.e_shentsize; | 310 | ehdr.e_shnum * ehdr.e_shentsize; |
@@ -294,7 +314,8 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
294 | while(sec) | 314 | while(sec) |
295 | { | 315 | { |
296 | sec->offset += data_offset; | 316 | sec->offset += data_offset; |
297 | 317 | strcpy(&strtbl_content[sec->name_offset], sec->name); | |
318 | |||
298 | phdr.p_type = PT_LOAD; | 319 | phdr.p_type = PT_LOAD; |
299 | if(sec->type == EST_LOAD) | 320 | if(sec->type == EST_LOAD) |
300 | phdr.p_offset = sec->offset; | 321 | phdr.p_offset = sec->offset; |
@@ -336,21 +357,13 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
336 | offset += sizeof(Elf32_Shdr); | 357 | offset += sizeof(Elf32_Shdr); |
337 | } | 358 | } |
338 | 359 | ||
339 | uint32_t text_idx = 0; | ||
340 | uint32_t bss_idx = 0; | ||
341 | while(sec) | 360 | while(sec) |
342 | { | 361 | { |
343 | shdr.sh_name = strtbl_index; | 362 | shdr.sh_name = sec->name_offset; |
344 | if(sec->type == EST_LOAD) | 363 | if(sec->type == EST_LOAD) |
345 | { | ||
346 | strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++); | ||
347 | shdr.sh_type = SHT_PROGBITS; | 364 | shdr.sh_type = SHT_PROGBITS; |
348 | } | ||
349 | else | 365 | else |
350 | { | ||
351 | strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++); | ||
352 | shdr.sh_type = SHT_NOBITS; | 366 | shdr.sh_type = SHT_NOBITS; |
353 | } | ||
354 | shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; | 367 | shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; |
355 | shdr.sh_addr = sec->addr; | 368 | shdr.sh_addr = sec->addr; |
356 | shdr.sh_offset = sec->offset; | 369 | shdr.sh_offset = sec->offset; |
@@ -367,12 +380,12 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
367 | } | 380 | } |
368 | 381 | ||
369 | { | 382 | { |
370 | shdr.sh_name = 1; | 383 | shdr.sh_name = shstrtab_index; |
371 | shdr.sh_type = SHT_STRTAB; | 384 | shdr.sh_type = SHT_STRTAB; |
372 | shdr.sh_flags = 0; | 385 | shdr.sh_flags = 0; |
373 | shdr.sh_addr = 0; | 386 | shdr.sh_addr = 0; |
374 | shdr.sh_offset = strtbl_offset + data_offset; | 387 | shdr.sh_offset = strtbl_offset + data_offset; |
375 | shdr.sh_size = strtbl_index; | 388 | shdr.sh_size = strtbl_size; |
376 | shdr.sh_link = SHN_UNDEF; | 389 | shdr.sh_link = SHN_UNDEF; |
377 | shdr.sh_info = 0; | 390 | shdr.sh_info = 0; |
378 | shdr.sh_addralign = 1; | 391 | shdr.sh_addralign = 1; |
@@ -391,7 +404,7 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
391 | sec = sec->next; | 404 | sec = sec->next; |
392 | } | 405 | } |
393 | 406 | ||
394 | write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index); | 407 | write(user, strtbl_offset + data_offset, strtbl_content, strtbl_size); |
395 | free(strtbl_content); | 408 | free(strtbl_content); |
396 | } | 409 | } |
397 | 410 | ||
@@ -399,7 +412,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, | |||
399 | elf_printf_fn_t printf, void *user) | 412 | elf_printf_fn_t printf, void *user) |
400 | { | 413 | { |
401 | #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) | 414 | #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) |
402 | 415 | ||
403 | /* read header */ | 416 | /* read header */ |
404 | Elf32_Ehdr ehdr; | 417 | Elf32_Ehdr ehdr; |
405 | if(!read(user, 0, &ehdr, sizeof(ehdr))) | 418 | if(!read(user, 0, &ehdr, sizeof(ehdr))) |
@@ -459,7 +472,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, | |||
459 | void *data = xmalloc(shdr.sh_size); | 472 | void *data = xmalloc(shdr.sh_size); |
460 | if(!read(user, shdr.sh_offset, data, shdr.sh_size)) | 473 | if(!read(user, shdr.sh_offset, data, shdr.sh_size)) |
461 | error_printf("error read self section data\n"); | 474 | error_printf("error read self section data\n"); |
462 | elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); | 475 | elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data, NULL); |
463 | free(data); | 476 | free(data); |
464 | 477 | ||
465 | if(strtab) | 478 | if(strtab) |
@@ -476,7 +489,6 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, | |||
476 | if(strtab) | 489 | if(strtab) |
477 | printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); | 490 | printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); |
478 | } | 491 | } |
479 | |||
480 | } | 492 | } |
481 | free(strtab); | 493 | free(strtab); |
482 | /* run through segments */ | 494 | /* run through segments */ |
@@ -562,6 +574,7 @@ void elf_release(struct elf_params_t *params) | |||
562 | struct elf_section_t *next_sec = sec->next; | 574 | struct elf_section_t *next_sec = sec->next; |
563 | if(sec->type == EST_LOAD) | 575 | if(sec->type == EST_LOAD) |
564 | free(sec->section); | 576 | free(sec->section); |
577 | free(sec->name); | ||
565 | free(sec); | 578 | free(sec); |
566 | sec = next_sec; | 579 | sec = next_sec; |
567 | } | 580 | } |
diff --git a/utils/rknanoutils/rkboottool/elf.h b/utils/rknanoutils/rkboottool/elf.h index 2166833276..2408e0c588 100644 --- a/utils/rknanoutils/rkboottool/elf.h +++ b/utils/rknanoutils/rkboottool/elf.h | |||
@@ -42,6 +42,7 @@ struct elf_section_t | |||
42 | uint32_t addr; /* virtual address */ | 42 | uint32_t addr; /* virtual address */ |
43 | uint32_t size; /* virtual size */ | 43 | uint32_t size; /* virtual size */ |
44 | enum elf_section_type_t type; | 44 | enum elf_section_type_t type; |
45 | char *name; | ||
45 | /* <union> */ | 46 | /* <union> */ |
46 | void *section; /* data */ | 47 | void *section; /* data */ |
47 | uint32_t pattern; /* fill pattern */ | 48 | uint32_t pattern; /* fill pattern */ |
@@ -49,6 +50,7 @@ struct elf_section_t | |||
49 | struct elf_section_t *next; | 50 | struct elf_section_t *next; |
50 | /* Internal to elf_write_file */ | 51 | /* Internal to elf_write_file */ |
51 | uint32_t offset; | 52 | uint32_t offset; |
53 | uint32_t name_offset; | ||
52 | }; | 54 | }; |
53 | 55 | ||
54 | struct elf_segment_t | 56 | struct elf_segment_t |
@@ -68,6 +70,7 @@ struct elf_params_t | |||
68 | struct elf_section_t *last_section; | 70 | struct elf_section_t *last_section; |
69 | struct elf_segment_t *first_segment; | 71 | struct elf_segment_t *first_segment; |
70 | struct elf_segment_t *last_segment; | 72 | struct elf_segment_t *last_segment; |
73 | int unique_index; | ||
71 | }; | 74 | }; |
72 | 75 | ||
73 | typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count); | 76 | typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count); |
@@ -77,7 +80,7 @@ typedef void (*elf_printf_fn_t)(void *user, bool error, const char *fmt, ...); | |||
77 | 80 | ||
78 | void elf_init(struct elf_params_t *params); | 81 | void elf_init(struct elf_params_t *params); |
79 | void elf_add_load_section(struct elf_params_t *params, | 82 | void elf_add_load_section(struct elf_params_t *params, |
80 | uint32_t load_addr, uint32_t size, const void *section); | 83 | uint32_t load_addr, uint32_t size, const void *section, const char *name); |
81 | void elf_add_fill_section(struct elf_params_t *params, | 84 | void elf_add_fill_section(struct elf_params_t *params, |
82 | uint32_t fill_addr, uint32_t size, uint32_t pattern); | 85 | uint32_t fill_addr, uint32_t size, uint32_t pattern); |
83 | uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr); | 86 | uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr); |
diff --git a/utils/rknanoutils/rkboottool/rkboottool.c b/utils/rknanoutils/rkboottool/rkboottool.c index ee9b17e610..763751e41f 100644 --- a/utils/rknanoutils/rkboottool/rkboottool.c +++ b/utils/rknanoutils/rkboottool/rkboottool.c | |||
@@ -15,6 +15,11 @@ bool g_debug = false; | |||
15 | typedef uint8_t packed_bcd_uint8_t; | 15 | typedef uint8_t packed_bcd_uint8_t; |
16 | typedef uint16_t packed_bcd_uint16_t; | 16 | typedef uint16_t packed_bcd_uint16_t; |
17 | 17 | ||
18 | /** | ||
19 | * RKnanoFW | ||
20 | * contains resources and code stages | ||
21 | */ | ||
22 | |||
18 | struct rknano_date_t | 23 | struct rknano_date_t |
19 | { | 24 | { |
20 | packed_bcd_uint16_t year; | 25 | packed_bcd_uint16_t year; |
@@ -176,7 +181,7 @@ static void save_blob(const struct rknano_blob_t *b, void *buf, uint32_t size, | |||
176 | } | 181 | } |
177 | encode_page(buff_ptr, out_ptr, len); | 182 | encode_page(buff_ptr, out_ptr, len); |
178 | } | 183 | } |
179 | 184 | ||
180 | if(f) | 185 | if(f) |
181 | { | 186 | { |
182 | fwrite(ptr, b->size, 1, f); | 187 | fwrite(ptr, b->size, 1, f); |
@@ -276,6 +281,11 @@ static int do_nanofw_image(uint8_t *buf, unsigned long size) | |||
276 | return 0; | 281 | return 0; |
277 | } | 282 | } |
278 | 283 | ||
284 | /** | ||
285 | * RKNano stage | ||
286 | * contains code and memory mapping | ||
287 | */ | ||
288 | |||
279 | struct rknano_stage_header_t | 289 | struct rknano_stage_header_t |
280 | { | 290 | { |
281 | uint32_t addr; | 291 | uint32_t addr; |
@@ -283,21 +293,28 @@ struct rknano_stage_header_t | |||
283 | } __attribute__((packed)); | 293 | } __attribute__((packed)); |
284 | 294 | ||
285 | /* | 295 | /* |
286 | * The [code_pa,code_pa+code_sz[ and [data_pa,data_pa+data_sz[ ranges | 296 | * NOTE this theory has not been tested against actual code, it's still a guess |
287 | * are consistent: they never overlap and have no gaps and fill the | 297 | * The firmware is too big to fit in memory so it's split into sections, |
288 | * entire space. Furthermore they match the code sequences so it's | 298 | * each section having a "virtual address" and a "physical address". |
289 | * reasonable to assume these fields are correct. | 299 | * Except it gets tricky because the RKNano doesn't have a MMU but a MPU, |
290 | * The other fields are still quite unsure. */ | 300 | * so most probably the OF divides the memory into regions (8 would match |
301 | * hardware capabilities), each being able to contain one of the sections | ||
302 | * in the OF file. To gracefully handle jumps between sections, my guess is | ||
303 | * that the entire OF is linked as a flat image, cut into pieces and | ||
304 | * then each code section get relocated except for jump/calls outside of it: | ||
305 | * this will trigger an access fault when trying to access another section, which | ||
306 | * the OF can trap and then load the corresponding section. | ||
307 | */ | ||
291 | 308 | ||
292 | struct rknano_stage_section_t | 309 | struct rknano_stage_section_t |
293 | { | 310 | { |
294 | uint32_t code_pa; | ||
295 | uint32_t code_va; | 311 | uint32_t code_va; |
312 | uint32_t code_pa; | ||
296 | uint32_t code_sz; | 313 | uint32_t code_sz; |
297 | uint32_t data_pa; | ||
298 | uint32_t data_va; | 314 | uint32_t data_va; |
315 | uint32_t data_pa; | ||
299 | uint32_t data_sz; | 316 | uint32_t data_sz; |
300 | uint32_t bss_va; | 317 | uint32_t bss_pa; |
301 | uint32_t bss_sz; | 318 | uint32_t bss_sz; |
302 | } __attribute__((packed)); | 319 | } __attribute__((packed)); |
303 | 320 | ||
@@ -319,14 +336,14 @@ static void elf_write(void *user, uint32_t addr, const void *buf, size_t count) | |||
319 | fwrite(buf, count, 1, f); | 336 | fwrite(buf, count, 1, f); |
320 | } | 337 | } |
321 | 338 | ||
322 | static void extract_elf_section(struct elf_params_t *elf, int count) | 339 | static void extract_elf_section(struct elf_params_t *elf) |
323 | { | 340 | { |
324 | if(g_out_prefix == NULL) | 341 | if(g_out_prefix == NULL) |
325 | return; | 342 | return; |
326 | char *filename = xmalloc(strlen(g_out_prefix) + 32); | 343 | char *filename = xmalloc(strlen(g_out_prefix) + 32); |
327 | sprintf(filename, "%s%d.elf", g_out_prefix, count); | 344 | sprintf(filename, "%s.elf", g_out_prefix); |
328 | if(g_debug) | 345 | if(g_debug) |
329 | printf("Write entry %d to %s\n", count, filename); | 346 | printf("Write stage to %s\n", filename); |
330 | 347 | ||
331 | FILE *fd = fopen(filename, "wb"); | 348 | FILE *fd = fopen(filename, "wb"); |
332 | free(filename); | 349 | free(filename); |
@@ -337,67 +354,149 @@ static void extract_elf_section(struct elf_params_t *elf, int count) | |||
337 | fclose(fd); | 354 | fclose(fd); |
338 | } | 355 | } |
339 | 356 | ||
357 | struct range_t | ||
358 | { | ||
359 | unsigned long start, size; | ||
360 | int section; | ||
361 | int type; | ||
362 | }; | ||
363 | |||
364 | int range_cmp(const void *_a, const void *_b) | ||
365 | { | ||
366 | const struct range_t *a = _a, *b = _b; | ||
367 | if(a->start == b->start) | ||
368 | return a->size - b->size; | ||
369 | return a->start - b->start; | ||
370 | } | ||
371 | |||
372 | #define RANGE_TXT 0 | ||
373 | #define RANGE_DAT 1 | ||
374 | |||
340 | static int do_nanostage_image(uint8_t *buf, unsigned long size) | 375 | static int do_nanostage_image(uint8_t *buf, unsigned long size) |
341 | { | 376 | { |
342 | if(size < sizeof(struct rknano_stage_section_t)) | 377 | if(size < sizeof(struct rknano_stage_section_t)) |
343 | return 1; | 378 | return 1; |
344 | struct rknano_stage_header_t *hdr = (void *)buf; | 379 | struct rknano_stage_header_t *hdr = (void *)buf; |
380 | size_t hdr_size = sizeof(struct rknano_stage_header_t) + | ||
381 | hdr->count * sizeof(struct rknano_stage_section_t); | ||
382 | if(size < hdr_size) | ||
383 | return 1; | ||
345 | 384 | ||
346 | cprintf(BLUE, "Header\n"); | 385 | cprintf(BLUE, "Header\n"); |
347 | cprintf(GREEN, " Base Address: "); | 386 | cprintf(GREEN, " Base Address: "); |
348 | cprintf(YELLOW, "%#08x\n", hdr->addr); | 387 | cprintf(YELLOW, "%#08x\n", hdr->addr); |
349 | cprintf(GREEN, " Load count: "); | 388 | cprintf(GREEN, " Section count: "); |
350 | cprintf(YELLOW, "%d\n", hdr->count); | 389 | cprintf(YELLOW, "%d\n", hdr->count); |
351 | |||
352 | struct rknano_stage_section_t *sec = (void *)(hdr + 1); | ||
353 | 390 | ||
391 | struct rknano_stage_section_t *sec = (void *)(hdr + 1); | ||
392 | struct elf_params_t elf; | ||
393 | elf_init(&elf); | ||
394 | bool error = false; | ||
395 | /* track range for overlap */ | ||
396 | struct range_t *ranges = malloc(sizeof(struct range_t) * 2 * hdr->count); | ||
397 | int nr_ranges = 0; | ||
354 | for(unsigned i = 0; i < hdr->count; i++, sec++) | 398 | for(unsigned i = 0; i < hdr->count; i++, sec++) |
355 | { | 399 | { |
356 | cprintf(BLUE, "Section %d\n", i); | 400 | cprintf(BLUE, "Section %d\n", i); |
357 | cprintf(GREEN, " Code: "); | 401 | cprintf(GREEN, " Code: "); |
358 | cprintf(YELLOW, "0x%08x", sec->code_pa); | 402 | cprintf(YELLOW, "0x%08x", sec->code_va); |
359 | cprintf(RED, "-(txt)-"); | 403 | cprintf(RED, "-(txt)-"); |
360 | cprintf(YELLOW, "0x%08x", sec->code_pa + sec->code_sz); | 404 | cprintf(YELLOW, "0x%08x", sec->code_va + sec->code_sz); |
361 | cprintf(BLUE, " |--> "); | 405 | cprintf(BLUE, " |--> "); |
362 | cprintf(YELLOW, "0x%08x", sec->code_va); | 406 | cprintf(YELLOW, "0x%08x", sec->code_pa); |
363 | cprintf(RED, "-(txt)-"); | 407 | cprintf(RED, "-(txt)-"); |
364 | cprintf(YELLOW, "0x%08x\n", sec->code_va + sec->code_sz); | 408 | cprintf(YELLOW, "0x%08x\n", sec->code_pa + sec->code_sz); |
409 | |||
410 | /* add ranges */ | ||
411 | ranges[nr_ranges].start = sec->code_va; | ||
412 | ranges[nr_ranges].size = sec->code_sz; | ||
413 | ranges[nr_ranges].section = i; | ||
414 | ranges[nr_ranges].type = RANGE_TXT; | ||
415 | ranges[nr_ranges + 1].start = sec->data_va; | ||
416 | ranges[nr_ranges + 1].size = sec->data_sz; | ||
417 | ranges[nr_ranges + 1].section = i; | ||
418 | ranges[nr_ranges + 1].type = RANGE_DAT; | ||
419 | nr_ranges += 2; | ||
365 | 420 | ||
366 | cprintf(GREEN, " Data: "); | 421 | cprintf(GREEN, " Data: "); |
367 | cprintf(YELLOW, "0x%08x", sec->data_pa); | 422 | cprintf(YELLOW, "0x%08x", sec->data_va); |
368 | cprintf(RED, "-(dat)-"); | 423 | cprintf(RED, "-(dat)-"); |
369 | cprintf(YELLOW, "0x%08x", sec->data_pa + sec->data_sz); | 424 | cprintf(YELLOW, "0x%08x", sec->data_va + sec->data_sz); |
370 | cprintf(BLUE, " |--> "); | 425 | cprintf(BLUE, " |--> "); |
371 | cprintf(YELLOW, "0x%08x", sec->data_va); | 426 | cprintf(YELLOW, "0x%08x", sec->data_pa); |
372 | cprintf(RED, "-(dat)-"); | 427 | cprintf(RED, "-(dat)-"); |
373 | cprintf(YELLOW, "0x%08x\n", sec->data_va + sec->data_sz); | 428 | cprintf(YELLOW, "0x%08x\n", sec->data_pa + sec->data_sz); |
374 | 429 | ||
375 | cprintf(GREEN, " Data: "); | 430 | cprintf(GREEN, " Data: "); |
376 | cprintf(RED, " "); | 431 | cprintf(RED, " "); |
377 | cprintf(BLUE, " |--> "); | 432 | cprintf(BLUE, " |--> "); |
378 | cprintf(YELLOW, "0x%08x", sec->bss_va); | 433 | cprintf(YELLOW, "0x%08x", sec->bss_pa); |
379 | cprintf(RED, "-(bss)-"); | 434 | cprintf(RED, "-(bss)-"); |
380 | cprintf(YELLOW, "0x%08x\n", sec->bss_va + sec->bss_sz); | 435 | cprintf(YELLOW, "0x%08x\n", sec->bss_pa + sec->bss_sz); |
436 | |||
437 | #define check_range_(start,sz) \ | ||
438 | ((start) >= hdr_size && (start) + (sz) <= size) | ||
439 | #define check_range(start,sz) \ | ||
440 | ((start) >= hdr->addr && check_range_((start) - hdr->addr, sz)) | ||
441 | /* check ranges */ | ||
442 | if(sec->code_sz != 0 && !check_range(sec->code_va, sec->code_sz)) | ||
443 | { | ||
444 | cprintf(GREY, "Invalid stage: out of bound code\n"); | ||
445 | error = true; | ||
446 | break; | ||
447 | } | ||
448 | if(sec->data_sz != 0 && !check_range(sec->data_va, sec->data_sz)) | ||
449 | { | ||
450 | cprintf(GREY, "Invalid stage: out of bound data\n"); | ||
451 | error = true; | ||
452 | break; | ||
453 | } | ||
454 | #undef check_range_ | ||
455 | #undef check_range | ||
381 | 456 | ||
382 | #if 0 | 457 | char buffer[32]; |
383 | struct rknano_blob_t blob; | 458 | if(sec->code_sz != 0) |
384 | blob.offset = sec->code_pa - hdr->addr; | 459 | { |
385 | blob.size = sec->code_sz; | 460 | sprintf(buffer, ".text.%d", i); |
386 | save_blob(&blob, buf, size, "entry.", i, NO_ENC); | 461 | elf_add_load_section(&elf, sec->code_va, sec->code_sz, |
387 | #else | 462 | buf + sec->code_va - hdr->addr, buffer); |
388 | struct elf_params_t elf; | 463 | } |
389 | elf_init(&elf); | 464 | if(sec->data_sz != 0) |
390 | elf_add_load_section(&elf, sec->code_va, sec->code_sz, buf + sec->code_pa - hdr->addr); | 465 | { |
391 | elf_add_load_section(&elf, sec->data_va, sec->data_sz, buf + sec->data_pa - hdr->addr); | 466 | sprintf(buffer, ".data.%d", i); |
392 | elf_add_fill_section(&elf, sec->bss_va, sec->bss_sz, 0); | 467 | elf_add_load_section(&elf, sec->data_va, sec->data_sz, |
393 | extract_elf_section(&elf, i); | 468 | buf + sec->data_va - hdr->addr, buffer); |
394 | elf_release(&elf); | 469 | } |
395 | #endif | 470 | } |
471 | /* sort ranges and check overlap */ | ||
472 | qsort(ranges, nr_ranges, sizeof(struct range_t), range_cmp); | ||
473 | for(int i = 1; i < nr_ranges; i++) | ||
474 | { | ||
475 | if(ranges[i - 1].start + ranges[i - 1].size > ranges[i].start) | ||
476 | { | ||
477 | error = true; | ||
478 | static const char *type[] = {"txt", "dat"}; | ||
479 | cprintf(GREY, "Section overlap: section %d %s intersects section %d %s\n", | ||
480 | ranges[i - 1].section, type[ranges[i - 1].type], ranges[i].section, | ||
481 | type[ranges[i].type]); | ||
482 | break; | ||
483 | } | ||
396 | } | 484 | } |
485 | if(!error) | ||
486 | extract_elf_section(&elf); | ||
487 | /* FIXME for full information, we could add segments to the ELF file to | ||
488 | * keep the mapping, but it's unclear if that would do any good */ | ||
489 | elf_release(&elf); | ||
490 | free(ranges); | ||
397 | 491 | ||
398 | return 0; | 492 | return 0; |
399 | } | 493 | } |
400 | 494 | ||
495 | /** | ||
496 | * RKNano BOOT | ||
497 | * contains named bootloader stages | ||
498 | */ | ||
499 | |||
401 | #define MAGIC_BOOT "BOOT" | 500 | #define MAGIC_BOOT "BOOT" |
402 | #define MAGIC_BOOT_SIZE 4 | 501 | #define MAGIC_BOOT_SIZE 4 |
403 | 502 | ||
@@ -428,6 +527,8 @@ struct rknano_boot_header_t | |||
428 | uint32_t field_34; | 527 | uint32_t field_34; |
429 | } __attribute__((packed)); | 528 | } __attribute__((packed)); |
430 | 529 | ||
530 | #define BOOT_CHIP_RKNANO 0x30 | ||
531 | |||
431 | struct rknano_boot_entry_t | 532 | struct rknano_boot_entry_t |
432 | { | 533 | { |
433 | uint8_t entry_size; // unsure | 534 | uint8_t entry_size; // unsure |
@@ -588,7 +689,7 @@ static int do_boot_image(uint8_t *buf, unsigned long size) | |||
588 | cprintf(RED, "OK\n"); | 689 | cprintf(RED, "OK\n"); |
589 | else | 690 | else |
590 | cprintf(RED, "Mismatch\n"); | 691 | cprintf(RED, "Mismatch\n"); |
591 | 692 | ||
592 | #define print(str, name) cprintf(GREEN, " "str": ");cprintf(YELLOW, "%#x\n", (unsigned)hdr->name) | 693 | #define print(str, name) cprintf(GREEN, " "str": ");cprintf(YELLOW, "%#x\n", (unsigned)hdr->name) |
593 | #define print_arr(str, name, sz) \ | 694 | #define print_arr(str, name, sz) \ |
594 | cprintf(GREEN, " "str":");for(int i = 0; i < sz; i++)cprintf(YELLOW, " %#x", (unsigned)hdr->name[i]);printf("\n") | 695 | cprintf(GREEN, " "str":");for(int i = 0; i < sz; i++)cprintf(YELLOW, " %#x", (unsigned)hdr->name[i]);printf("\n") |
@@ -602,8 +703,12 @@ static int do_boot_image(uint8_t *buf, unsigned long size) | |||
602 | hdr->hour, hdr->minute, hdr->second); | 703 | hdr->hour, hdr->minute, hdr->second); |
603 | 704 | ||
604 | cprintf(GREEN, " Chip: "); | 705 | cprintf(GREEN, " Chip: "); |
605 | cprintf(YELLOW, "%#x\n", hdr->chip); | 706 | cprintf(YELLOW, "%#x ", hdr->chip); |
606 | 707 | if(hdr->chip == BOOT_CHIP_RKNANO) | |
708 | cprintf(RED, "(RKNANO)\n"); | ||
709 | else | ||
710 | cprintf(RED, "(unknown)\n"); | ||
711 | |||
607 | print_arr("field_2A", field_2B, 9); | 712 | print_arr("field_2A", field_2B, 9); |
608 | print("field_34", field_34); | 713 | print("field_34", field_34); |
609 | 714 | ||
@@ -625,10 +730,15 @@ static int do_boot_image(uint8_t *buf, unsigned long size) | |||
625 | cprintf(RED, "OK\n"); | 730 | cprintf(RED, "OK\n"); |
626 | else | 731 | else |
627 | cprintf(RED, "Mismatch\n"); | 732 | cprintf(RED, "Mismatch\n"); |
628 | 733 | ||
629 | return 0; | 734 | return 0; |
630 | } | 735 | } |
631 | 736 | ||
737 | /** | ||
738 | * RKFW | ||
739 | * contains bootloader and update | ||
740 | */ | ||
741 | |||
632 | typedef struct rknano_blob_t rkfw_blob_t; | 742 | typedef struct rknano_blob_t rkfw_blob_t; |
633 | 743 | ||
634 | #define MAGIC_RKFW "RKFW" | 744 | #define MAGIC_RKFW "RKFW" |
@@ -637,7 +747,7 @@ typedef struct rknano_blob_t rkfw_blob_t; | |||
637 | struct rkfw_header_t | 747 | struct rkfw_header_t |
638 | { | 748 | { |
639 | char magic[MAGIC_RKFW_SIZE]; | 749 | char magic[MAGIC_RKFW_SIZE]; |
640 | uint16_t hdr_size; // UNSURE | 750 | uint16_t hdr_size; |
641 | uint32_t version; | 751 | uint32_t version; |
642 | uint32_t code; | 752 | uint32_t code; |
643 | uint16_t year; | 753 | uint16_t year; |
@@ -652,6 +762,8 @@ struct rkfw_header_t | |||
652 | uint8_t pad[61]; | 762 | uint8_t pad[61]; |
653 | } __attribute__((packed)); | 763 | } __attribute__((packed)); |
654 | 764 | ||
765 | #define RKFW_CHIP_RKNANO 0x30 | ||
766 | |||
655 | static int do_rkfw_image(uint8_t *buf, unsigned long size) | 767 | static int do_rkfw_image(uint8_t *buf, unsigned long size) |
656 | { | 768 | { |
657 | if(size < sizeof(struct rkfw_header_t)) | 769 | if(size < sizeof(struct rkfw_header_t)) |
@@ -686,8 +798,12 @@ static int do_rkfw_image(uint8_t *buf, unsigned long size) | |||
686 | hdr->hour, hdr->minute, hdr->second); | 798 | hdr->hour, hdr->minute, hdr->second); |
687 | 799 | ||
688 | cprintf(GREEN, " Chip: "); | 800 | cprintf(GREEN, " Chip: "); |
689 | cprintf(YELLOW, "%#x\n", hdr->chip); | 801 | cprintf(YELLOW, "%#x ", hdr->chip); |
690 | 802 | if(hdr->chip == RKFW_CHIP_RKNANO) | |
803 | cprintf(RED, "(RKNANO)\n"); | ||
804 | else | ||
805 | cprintf(RED, "(unknown)\n"); | ||
806 | |||
691 | cprintf(GREEN, " Loader: "); | 807 | cprintf(GREEN, " Loader: "); |
692 | print_blob_interval(&hdr->loader); | 808 | print_blob_interval(&hdr->loader); |
693 | cprintf(OFF, "\n"); | 809 | cprintf(OFF, "\n"); |
@@ -852,7 +968,7 @@ int main(int argc, char **argv) | |||
852 | perror("Cannot read file"); | 968 | perror("Cannot read file"); |
853 | return 1; | 969 | return 1; |
854 | } | 970 | } |
855 | 971 | ||
856 | fclose(fin); | 972 | fclose(fin); |
857 | 973 | ||
858 | if(try_nanofw && !do_nanofw_image(buf, size)) | 974 | if(try_nanofw && !do_nanofw_image(buf, size)) |
@@ -873,4 +989,3 @@ int main(int argc, char **argv) | |||
873 | 989 | ||
874 | return 0; | 990 | return 0; |
875 | } | 991 | } |
876 | |||