A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

rknanotools: fix rknano stages processing

Change-Id: Ia88f5aa2a6c56b312f80b31afab41d1dc68b871b

authored by

Amaury Pouly and committed by
Solomon Peachy
b8d35c04 d22bb548

+210 -79
+43 -30
utils/rknanoutils/rkboottool/elf.c
··· 21 21 #include "elf.h" 22 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 33 * Definitions 26 34 * taken from elf.h linux header ··· 189 197 } 190 198 191 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 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 210 sec->type = EST_LOAD; 197 211 sec->addr = load_addr; 198 212 sec->size = size; 199 213 sec->section = xmalloc(size); 214 + sec->name = strdup(name); 200 215 memcpy(sec->section, section, size); 201 216 } 202 217 203 218 void elf_add_fill_section(struct elf_params_t *params, 204 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 224 if(pattern != 0x00) 207 225 { 208 226 printf("oops, non-zero filling, ignore fill section\n"); 209 227 return; 210 228 } 211 - 229 + 212 230 struct elf_section_t *sec = elf_add_section(params); 213 - 231 + 214 232 sec->type = EST_FILL; 215 233 sec->addr = fill_addr; 216 234 sec->size = size; 217 235 sec->pattern = pattern; 236 + sec->name = strdup(buffer); 218 237 } 219 238 220 239 void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, 221 240 elf_printf_fn_t printf, void *user) 222 241 { 223 242 (void) printf; 224 - 243 + 225 244 Elf32_Ehdr ehdr; 226 245 uint32_t phnum = 0; 227 246 struct elf_section_t *sec = params->first_section; 228 247 uint32_t offset = 0; 248 + uint32_t strtbl_size = 1; /* offset 0 is for the NULL name */ 229 249 Elf32_Phdr phdr; 230 250 Elf32_Shdr shdr; 231 251 memset(&ehdr, 0, EI_NIDENT); ··· 241 261 { 242 262 sec->offset = 0; 243 263 } 244 - 264 + sec->name_offset = strtbl_size; 265 + strtbl_size += strlen(sec->name) + 1; 266 + 245 267 phnum++; 246 268 sec = sec->next; 247 269 } ··· 275 297 276 298 write(user, 0, &ehdr, sizeof ehdr); 277 299 278 - /* allocate enough size to hold any combinaison of .text/.bss in the string table: 279 - * - one empty name ("\0") 280 - * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0" 281 - * - one name ".shstrtab\0" */ 282 - char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 + 283 - phnum * (strlen(".textXXXX") + 1)); 284 - 300 + /* the last name offset gives the size of the section, we need to add a small 301 + * amount of .shstrtab name */ 302 + uint32_t shstrtab_index = strtbl_size; 303 + strtbl_size += strlen(".shstrtab") + 1; 304 + char *strtbl_content = malloc(strtbl_size); 305 + /* create NULL and shstrtab names */ 285 306 strtbl_content[0] = '\0'; 286 - strcpy(&strtbl_content[1], ".shstrtab"); 287 - uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1; 307 + strcpy(&strtbl_content[shstrtab_index], ".shstrtab"); 288 308 289 309 uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + 290 310 ehdr.e_shnum * ehdr.e_shentsize; ··· 294 314 while(sec) 295 315 { 296 316 sec->offset += data_offset; 297 - 317 + strcpy(&strtbl_content[sec->name_offset], sec->name); 318 + 298 319 phdr.p_type = PT_LOAD; 299 320 if(sec->type == EST_LOAD) 300 321 phdr.p_offset = sec->offset; ··· 336 357 offset += sizeof(Elf32_Shdr); 337 358 } 338 359 339 - uint32_t text_idx = 0; 340 - uint32_t bss_idx = 0; 341 360 while(sec) 342 361 { 343 - shdr.sh_name = strtbl_index; 362 + shdr.sh_name = sec->name_offset; 344 363 if(sec->type == EST_LOAD) 345 - { 346 - strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++); 347 364 shdr.sh_type = SHT_PROGBITS; 348 - } 349 365 else 350 - { 351 - strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++); 352 366 shdr.sh_type = SHT_NOBITS; 353 - } 354 367 shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; 355 368 shdr.sh_addr = sec->addr; 356 369 shdr.sh_offset = sec->offset; ··· 367 380 } 368 381 369 382 { 370 - shdr.sh_name = 1; 383 + shdr.sh_name = shstrtab_index; 371 384 shdr.sh_type = SHT_STRTAB; 372 385 shdr.sh_flags = 0; 373 386 shdr.sh_addr = 0; 374 387 shdr.sh_offset = strtbl_offset + data_offset; 375 - shdr.sh_size = strtbl_index; 388 + shdr.sh_size = strtbl_size; 376 389 shdr.sh_link = SHN_UNDEF; 377 390 shdr.sh_info = 0; 378 391 shdr.sh_addralign = 1; ··· 391 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 408 free(strtbl_content); 396 409 } 397 410 ··· 399 412 elf_printf_fn_t printf, void *user) 400 413 { 401 414 #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) 402 - 415 + 403 416 /* read header */ 404 417 Elf32_Ehdr ehdr; 405 418 if(!read(user, 0, &ehdr, sizeof(ehdr))) ··· 459 472 void *data = xmalloc(shdr.sh_size); 460 473 if(!read(user, shdr.sh_offset, data, shdr.sh_size)) 461 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 476 free(data); 464 477 465 478 if(strtab) ··· 476 489 if(strtab) 477 490 printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); 478 491 } 479 - 480 492 } 481 493 free(strtab); 482 494 /* run through segments */ ··· 562 574 struct elf_section_t *next_sec = sec->next; 563 575 if(sec->type == EST_LOAD) 564 576 free(sec->section); 577 + free(sec->name); 565 578 free(sec); 566 579 sec = next_sec; 567 580 }
+4 -1
utils/rknanoutils/rkboottool/elf.h
··· 42 42 uint32_t addr; /* virtual address */ 43 43 uint32_t size; /* virtual size */ 44 44 enum elf_section_type_t type; 45 + char *name; 45 46 /* <union> */ 46 47 void *section; /* data */ 47 48 uint32_t pattern; /* fill pattern */ ··· 49 50 struct elf_section_t *next; 50 51 /* Internal to elf_write_file */ 51 52 uint32_t offset; 53 + uint32_t name_offset; 52 54 }; 53 55 54 56 struct elf_segment_t ··· 68 70 struct elf_section_t *last_section; 69 71 struct elf_segment_t *first_segment; 70 72 struct elf_segment_t *last_segment; 73 + int unique_index; 71 74 }; 72 75 73 76 typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count); ··· 77 80 78 81 void elf_init(struct elf_params_t *params); 79 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 84 void elf_add_fill_section(struct elf_params_t *params, 82 85 uint32_t fill_addr, uint32_t size, uint32_t pattern); 83 86 uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr);
+163 -48
utils/rknanoutils/rkboottool/rkboottool.c
··· 15 15 typedef uint8_t packed_bcd_uint8_t; 16 16 typedef uint16_t packed_bcd_uint16_t; 17 17 18 + /** 19 + * RKnanoFW 20 + * contains resources and code stages 21 + */ 22 + 18 23 struct rknano_date_t 19 24 { 20 25 packed_bcd_uint16_t year; ··· 176 181 } 177 182 encode_page(buff_ptr, out_ptr, len); 178 183 } 179 - 184 + 180 185 if(f) 181 186 { 182 187 fwrite(ptr, b->size, 1, f); ··· 276 281 return 0; 277 282 } 278 283 284 + /** 285 + * RKNano stage 286 + * contains code and memory mapping 287 + */ 288 + 279 289 struct rknano_stage_header_t 280 290 { 281 291 uint32_t addr; ··· 283 293 } __attribute__((packed)); 284 294 285 295 /* 286 - * The [code_pa,code_pa+code_sz[ and [data_pa,data_pa+data_sz[ ranges 287 - * are consistent: they never overlap and have no gaps and fill the 288 - * entire space. Furthermore they match the code sequences so it's 289 - * reasonable to assume these fields are correct. 290 - * The other fields are still quite unsure. */ 296 + * NOTE this theory has not been tested against actual code, it's still a guess 297 + * The firmware is too big to fit in memory so it's split into sections, 298 + * each section having a "virtual address" and a "physical address". 299 + * Except it gets tricky because the RKNano doesn't have a MMU but a MPU, 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 309 struct rknano_stage_section_t 293 310 { 294 - uint32_t code_pa; 295 311 uint32_t code_va; 312 + uint32_t code_pa; 296 313 uint32_t code_sz; 297 - uint32_t data_pa; 298 314 uint32_t data_va; 315 + uint32_t data_pa; 299 316 uint32_t data_sz; 300 - uint32_t bss_va; 317 + uint32_t bss_pa; 301 318 uint32_t bss_sz; 302 319 } __attribute__((packed)); 303 320 ··· 319 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 341 if(g_out_prefix == NULL) 325 342 return; 326 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 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 348 FILE *fd = fopen(filename, "wb"); 332 349 free(filename); ··· 337 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 375 static int do_nanostage_image(uint8_t *buf, unsigned long size) 341 376 { 342 377 if(size < sizeof(struct rknano_stage_section_t)) 343 378 return 1; 344 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 385 cprintf(BLUE, "Header\n"); 347 386 cprintf(GREEN, " Base Address: "); 348 387 cprintf(YELLOW, "%#08x\n", hdr->addr); 349 - cprintf(GREEN, " Load count: "); 388 + cprintf(GREEN, " Section count: "); 350 389 cprintf(YELLOW, "%d\n", hdr->count); 351 - 390 + 352 391 struct rknano_stage_section_t *sec = (void *)(hdr + 1); 353 - 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 398 for(unsigned i = 0; i < hdr->count; i++, sec++) 355 399 { 356 400 cprintf(BLUE, "Section %d\n", i); 357 401 cprintf(GREEN, " Code: "); 358 - cprintf(YELLOW, "0x%08x", sec->code_pa); 402 + cprintf(YELLOW, "0x%08x", sec->code_va); 359 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 405 cprintf(BLUE, " |--> "); 362 - cprintf(YELLOW, "0x%08x", sec->code_va); 406 + cprintf(YELLOW, "0x%08x", sec->code_pa); 363 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 421 cprintf(GREEN, " Data: "); 367 - cprintf(YELLOW, "0x%08x", sec->data_pa); 422 + cprintf(YELLOW, "0x%08x", sec->data_va); 368 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 425 cprintf(BLUE, " |--> "); 371 - cprintf(YELLOW, "0x%08x", sec->data_va); 426 + cprintf(YELLOW, "0x%08x", sec->data_pa); 372 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 430 cprintf(GREEN, " Data: "); 376 431 cprintf(RED, " "); 377 432 cprintf(BLUE, " |--> "); 378 - cprintf(YELLOW, "0x%08x", sec->bss_va); 433 + cprintf(YELLOW, "0x%08x", sec->bss_pa); 379 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 383 - struct rknano_blob_t blob; 384 - blob.offset = sec->code_pa - hdr->addr; 385 - blob.size = sec->code_sz; 386 - save_blob(&blob, buf, size, "entry.", i, NO_ENC); 387 - #else 388 - struct elf_params_t elf; 389 - elf_init(&elf); 390 - elf_add_load_section(&elf, sec->code_va, sec->code_sz, buf + sec->code_pa - hdr->addr); 391 - elf_add_load_section(&elf, sec->data_va, sec->data_sz, buf + sec->data_pa - hdr->addr); 392 - elf_add_fill_section(&elf, sec->bss_va, sec->bss_sz, 0); 393 - extract_elf_section(&elf, i); 394 - elf_release(&elf); 395 - #endif 457 + char buffer[32]; 458 + if(sec->code_sz != 0) 459 + { 460 + sprintf(buffer, ".text.%d", i); 461 + elf_add_load_section(&elf, sec->code_va, sec->code_sz, 462 + buf + sec->code_va - hdr->addr, buffer); 463 + } 464 + if(sec->data_sz != 0) 465 + { 466 + sprintf(buffer, ".data.%d", i); 467 + elf_add_load_section(&elf, sec->data_va, sec->data_sz, 468 + buf + sec->data_va - hdr->addr, buffer); 469 + } 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 492 return 0; 399 493 } 494 + 495 + /** 496 + * RKNano BOOT 497 + * contains named bootloader stages 498 + */ 400 499 401 500 #define MAGIC_BOOT "BOOT" 402 501 #define MAGIC_BOOT_SIZE 4 ··· 427 526 uint8_t field_2B[9]; 428 527 uint32_t field_34; 429 528 } __attribute__((packed)); 529 + 530 + #define BOOT_CHIP_RKNANO 0x30 430 531 431 532 struct rknano_boot_entry_t 432 533 { ··· 588 689 cprintf(RED, "OK\n"); 589 690 else 590 691 cprintf(RED, "Mismatch\n"); 591 - 692 + 592 693 #define print(str, name) cprintf(GREEN, " "str": ");cprintf(YELLOW, "%#x\n", (unsigned)hdr->name) 593 694 #define print_arr(str, name, sz) \ 594 695 cprintf(GREEN, " "str":");for(int i = 0; i < sz; i++)cprintf(YELLOW, " %#x", (unsigned)hdr->name[i]);printf("\n") ··· 602 703 hdr->hour, hdr->minute, hdr->second); 603 704 604 705 cprintf(GREEN, " Chip: "); 605 - cprintf(YELLOW, "%#x\n", hdr->chip); 606 - 706 + cprintf(YELLOW, "%#x ", hdr->chip); 707 + if(hdr->chip == BOOT_CHIP_RKNANO) 708 + cprintf(RED, "(RKNANO)\n"); 709 + else 710 + cprintf(RED, "(unknown)\n"); 711 + 607 712 print_arr("field_2A", field_2B, 9); 608 713 print("field_34", field_34); 609 714 ··· 625 730 cprintf(RED, "OK\n"); 626 731 else 627 732 cprintf(RED, "Mismatch\n"); 628 - 733 + 629 734 return 0; 630 735 } 631 736 737 + /** 738 + * RKFW 739 + * contains bootloader and update 740 + */ 741 + 632 742 typedef struct rknano_blob_t rkfw_blob_t; 633 743 634 744 #define MAGIC_RKFW "RKFW" ··· 637 747 struct rkfw_header_t 638 748 { 639 749 char magic[MAGIC_RKFW_SIZE]; 640 - uint16_t hdr_size; // UNSURE 750 + uint16_t hdr_size; 641 751 uint32_t version; 642 752 uint32_t code; 643 753 uint16_t year; ··· 651 761 rkfw_blob_t update; 652 762 uint8_t pad[61]; 653 763 } __attribute__((packed)); 764 + 765 + #define RKFW_CHIP_RKNANO 0x30 654 766 655 767 static int do_rkfw_image(uint8_t *buf, unsigned long size) 656 768 { ··· 686 798 hdr->hour, hdr->minute, hdr->second); 687 799 688 800 cprintf(GREEN, " Chip: "); 689 - cprintf(YELLOW, "%#x\n", hdr->chip); 690 - 801 + cprintf(YELLOW, "%#x ", hdr->chip); 802 + if(hdr->chip == RKFW_CHIP_RKNANO) 803 + cprintf(RED, "(RKNANO)\n"); 804 + else 805 + cprintf(RED, "(unknown)\n"); 806 + 691 807 cprintf(GREEN, " Loader: "); 692 808 print_blob_interval(&hdr->loader); 693 809 cprintf(OFF, "\n"); ··· 852 968 perror("Cannot read file"); 853 969 return 1; 854 970 } 855 - 971 + 856 972 fclose(fin); 857 973 858 974 if(try_nanofw && !do_nanofw_image(buf, size)) ··· 873 989 874 990 return 0; 875 991 } 876 -