summaryrefslogtreecommitdiff
path: root/apps/plugins/iriver_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/iriver_flash.c')
-rw-r--r--apps/plugins/iriver_flash.c343
1 files changed, 266 insertions, 77 deletions
diff --git a/apps/plugins/iriver_flash.c b/apps/plugins/iriver_flash.c
index f919a0d25c..1cae1767a9 100644
--- a/apps/plugins/iriver_flash.c
+++ b/apps/plugins/iriver_flash.c
@@ -58,7 +58,7 @@ static struct plugin_api* rb; /* here is a global api struct pointer */
58 58
59#ifdef IRIVER_H100_SERIES 59#ifdef IRIVER_H100_SERIES
60#define SEC_SIZE 4096 60#define SEC_SIZE 4096
61#define BOOTLOADER_ERASEGUARD (BOOTLOADER_ENTRYPOINT / SEC_SIZE - 1) 61#define BOOTLOADER_ERASEGUARD (BOOTLOADER_ENTRYPOINT / SEC_SIZE)
62 62
63static volatile uint16_t* FB = (uint16_t*)0x00000000; /* Flash base address */ 63static volatile uint16_t* FB = (uint16_t*)0x00000000; /* Flash base address */
64#endif 64#endif
@@ -181,7 +181,7 @@ bool cfi_get_flash_info(struct flash_info* pInfo)
181 181
182/* Tool function to calculate a CRC32 across some buffer */ 182/* Tool function to calculate a CRC32 across some buffer */
183/* third argument is either 0xFFFFFFFF to start or value from last piece */ 183/* third argument is either 0xFFFFFFFF to start or value from last piece */
184unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32) 184unsigned crc_32(const unsigned char* buf, unsigned len, unsigned crc32)
185{ 185{
186 /* CCITT standard polynomial 0x04C11DB7 */ 186 /* CCITT standard polynomial 0x04C11DB7 */
187 static const unsigned crc32_lookup[16] = 187 static const unsigned crc32_lookup[16] =
@@ -217,7 +217,7 @@ unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32)
217 217
218 218
219/***************** User Interface Functions *****************/ 219/***************** User Interface Functions *****************/
220int WaitForButton(void) 220int wait_for_button(void)
221{ 221{
222 int button; 222 int button;
223 223
@@ -262,6 +262,36 @@ void ShowFlashInfo(struct flash_info* pInfo)
262 rb->lcd_update(); 262 rb->lcd_update();
263} 263}
264 264
265bool show_info(void)
266{
267 struct flash_info fi;
268
269 rb->lcd_clear_display();
270 cfi_get_flash_info(&fi);
271 ShowFlashInfo(&fi);
272 if (fi.size == 0) /* no valid chip */
273 {
274 rb->splash(HZ*3, true, "Sorry!");
275 return false; /* exit */
276 }
277
278 return true;
279}
280
281bool confirm(const char *msg)
282{
283 char buf[128];
284 bool ret;
285
286 rb->snprintf(buf, sizeof buf, "%s ([PLAY] to CONFIRM)", msg);
287 rb->splash(0, true, buf);
288
289 ret = (wait_for_button() == BUTTON_ON);
290 show_info();
291
292 return ret;
293}
294
265int load_firmware_file(const char *filename, uint32_t *checksum) 295int load_firmware_file(const char *filename, uint32_t *checksum)
266{ 296{
267 int fd; 297 int fd;
@@ -308,6 +338,45 @@ int load_firmware_file(const char *filename, uint32_t *checksum)
308 return len; 338 return len;
309} 339}
310 340
341bool detect_flashed_rockbox(void)
342{
343 struct flash_header hdr;
344 uint8_t *src = (uint8_t *)FLASH_ENTRYPOINT;
345
346 rb->memcpy(&hdr, src, sizeof(struct flash_header));
347
348 if (hdr.magic != FLASH_MAGIC)
349 return false;
350
351 return true;
352}
353
354unsigned long valid_bootloaders[][2] =
355 {
356 { 62332, 0x77395351 },
357 { 0, 0 }
358 };
359
360
361bool detect_valid_bootloader(const unsigned char *addr, int len)
362{
363 int i;
364 unsigned long crc32;
365
366 /* Try to scan through all valid bootloaders. */
367 for (i = 0; valid_bootloaders[i][0]; i++)
368 {
369 if (len > 0 && len != (long)valid_bootloaders[i][0])
370 continue;
371
372 crc32 = crc_32(addr, valid_bootloaders[i][0], 0xffffffff);
373 if (crc32 == valid_bootloaders[i][1])
374 return true;
375 }
376
377 return false;
378}
379
311int flash_rockbox(const char *filename) 380int flash_rockbox(const char *filename)
312{ 381{
313 struct flash_header hdr; 382 struct flash_header hdr;
@@ -318,9 +387,27 @@ int flash_rockbox(const char *filename)
318 uint16_t *p16; 387 uint16_t *p16;
319 388
320 len = load_firmware_file(filename, &checksum); 389 len = load_firmware_file(filename, &checksum);
321 if (len < 0) 390 if (len <= 0)
322 return len * 10; 391 return len * 10;
323 392
393 p8 = (char *)BOOTLOADER_ENTRYPOINT;
394 if (!detect_valid_bootloader(p8, 0))
395 {
396 rb->splash(HZ*3, true, "Incompatible bootloader");
397 return -1;
398 }
399
400 if (detect_flashed_rockbox())
401 {
402 if (!confirm("Update Rockbox flash image?"))
403 return -2;
404 }
405 else
406 {
407 if (!confirm("Erase original firmware?"))
408 return -3;
409 }
410
324 /* Erase the program flash. */ 411 /* Erase the program flash. */
325 for (i = 1; i < BOOTLOADER_ERASEGUARD && (i-1)*4096 < len + 32; i++) 412 for (i = 1; i < BOOTLOADER_ERASEGUARD && (i-1)*4096 < len + 32; i++)
326 { 413 {
@@ -349,10 +436,14 @@ int flash_rockbox(const char *filename)
349 } 436 }
350 437
351 p16 = (uint16_t *)audiobuf; 438 p16 = (uint16_t *)audiobuf;
352 for (i = 0; i < len/2 && pos < (BOOTLOADER_ENTRYPOINT/2); i++) 439 for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++)
353 cfi_program_word(FB + pos + i, p16[i]); 440 cfi_program_word(FB + pos + i, p16[i]);
354 441
355 /* Verify */ 442 /* Verify */
443 rb->snprintf(buf, sizeof(buf), "Verifying");
444 rb->lcd_puts(0, 5, buf);
445 rb->lcd_update();
446
356 p8 = (char *)FLASH_ENTRYPOINT; 447 p8 = (char *)FLASH_ENTRYPOINT;
357 p8 += sizeof(struct flash_header); 448 p8 += sizeof(struct flash_header);
358 sum = 0; 449 sum = 0;
@@ -368,6 +459,8 @@ int flash_rockbox(const char *filename)
368 return -5; 459 return -5;
369 } 460 }
370 461
462 rb->splash(HZ*2, true, "Success");
463
371 return 0; 464 return 0;
372} 465}
373 466
@@ -383,13 +476,13 @@ int flash_bootloader(const char *filename)
383{ 476{
384 char buf[32]; 477 char buf[32];
385 int pos, i, len, rc; 478 int pos, i, len, rc;
386 unsigned long checksum, sum, crc32; 479 unsigned long checksum, sum;
387 unsigned char *p8; 480 unsigned char *p8;
388 uint16_t *p16; 481 uint16_t *p16;
389 482
390 (void)buf; 483 (void)buf;
391 len = load_firmware_file(filename, &checksum); 484 len = load_firmware_file(filename, &checksum);
392 if (len < 0) 485 if (len <= 0)
393 return len * 10; 486 return len * 10;
394 487
395 if (len > 0xFFFF) 488 if (len > 0xFFFF)
@@ -399,18 +492,16 @@ int flash_bootloader(const char *filename)
399 } 492 }
400 493
401 /* Verify the crc32 checksum also. */ 494 /* Verify the crc32 checksum also. */
402 crc32 = crc_32(audiobuf, len, 0xffffffff); 495 if (!detect_valid_bootloader(audiobuf, len))
403#if 0
404 rb->snprintf(buf, sizeof buf, "crc32 = 0x%08x", crc32);
405 rb->splash(HZ*10, true, buf);
406#else
407 if (crc32 != 0x77395351)
408 { 496 {
409 rb->splash(HZ*3, true, "Untested bootloader"); 497 rb->splash(HZ*3, true, "Incompatible/Untested bootloader");
410 return -2; 498 return -1;
411 } 499 }
412#endif 500
413 rb->lcd_puts(0, 3, "Processing critical sections..."); 501 if (!confirm("Update bootloader?"))
502 return -2;
503
504 rb->lcd_puts(0, 3, "Flashing...");
414 rb->lcd_update(); 505 rb->lcd_update();
415 506
416 /* Erase the boot sector and write a proper reset vector. */ 507 /* Erase the boot sector and write a proper reset vector. */
@@ -448,92 +539,186 @@ int flash_bootloader(const char *filename)
448 { 539 {
449 rb->splash(HZ*3, true, "Bootvector corrupt!"); 540 rb->splash(HZ*3, true, "Bootvector corrupt!");
450 show_fatal_error(); 541 show_fatal_error();
451 break; 542 return -6;
452 } 543 }
453 } 544 }
454 545
546 rb->splash(HZ*2, true, "Success");
547
455 return 0; 548 return 0;
456} 549}
457 550
458/* Kind of our main function, defines the application flow. */ 551int flash_original_fw(int len)
459void DoUserDialog(char* filename)
460{ 552{
461 struct flash_info fi; 553 unsigned char reset_vector[8];
462 int rc; /* generic return code */ 554 char buf[32];
555 int pos, i, rc;
556 unsigned char *p8;
557 uint16_t *p16;
558
559 (void)buf;
560
561 rb->lcd_puts(0, 3, "Critical section...");
562 rb->lcd_update();
463 563
464 /* this can only work if Rockbox runs in DRAM, not flash ROM */ 564 p8 = (char *)FB;
465 if ((uint16_t*)rb >= FB && (uint16_t*)rb < FB + 4096*1024) /* 4 MB max */ 565 rb->memcpy(reset_vector, p8, sizeof reset_vector);
466 { /* we're running from flash */ 566
467 rb->splash(HZ*3, true, "Not from ROM"); 567 /* Erase the boot sector and write back the reset vector. */
468 return; /* exit */ 568 cfi_erase_sector(FB);
569 p16 = (uint16_t *)reset_vector;
570 for (i = 0; i < (long)sizeof(reset_vector)/2; i++)
571 cfi_program_word(FB + i, p16[i]);
572
573 rb->lcd_puts(0, 4, "Flashing orig. FW");
574 rb->lcd_update();
575
576 /* Erase the program flash. */
577 for (i = 1; i < BOOTLOADER_ERASEGUARD && (i-1)*4096 < len; i++)
578 {
579 rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i);
580 rb->snprintf(buf, sizeof(buf), "Erase: 0x%03x (%d)", i, rc);
581 rb->lcd_puts(0, 5, buf);
582 rb->lcd_update();
469 } 583 }
470 584
471 /* refuse to work if the power may fail meanwhile */ 585 rb->snprintf(buf, sizeof(buf), "Programming");
472 if (!rb->battery_level_safe()) 586 rb->lcd_puts(0, 6, buf);
587 rb->lcd_update();
588
589 pos = 0x00000008/2;
590 p16 = (uint16_t *)audiobuf;
591 for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++)
592 cfi_program_word(FB + pos + i, p16[i]);
593
594 rb->snprintf(buf, sizeof(buf), "Verifying");
595 rb->lcd_puts(0, 7, buf);
596 rb->lcd_update();
597
598 /* Verify reset vectors. */
599 p8 = (char *)FB;
600 for (i = 0; i < 8; i++)
473 { 601 {
474 rb->splash(HZ*3, true, "Battery too low!"); 602 if (p8[i] != reset_vector[i])
475 return; /* exit */ 603 {
604 rb->splash(HZ*3, true, "Bootvector corrupt!");
605 show_fatal_error();
606 break;
607 }
476 } 608 }
477 609
478 rb->lcd_setfont(FONT_SYSFIXED); 610 /* Verify */
479 611 p8 = (char *)0x00000008;
480 rc = cfi_get_flash_info(&fi); 612 for (i = 0; i < len; i++)
481 ShowFlashInfo(&fi);
482 if (fi.size == 0) /* no valid chip */
483 { 613 {
484 rb->splash(HZ*3, true, "Sorry!"); 614 if (p8[i] != audiobuf[i])
485 return; /* exit */ 615 {
616 rb->splash(HZ*3, true, "Verify failed!");
617 rb->snprintf(buf, sizeof buf, "at: 0x%08x", i);
618 rb->splash(HZ*10, true, buf);
619 return -5;
620 }
486 } 621 }
487
488 /* Debug? */
489#if 0
490 rb->memcpy(&hdr, (uint8_t *)(FLASH_ENTRYPOINT), sizeof(struct flash_header));
491 rb->snprintf(buf, sizeof(buf), "Magic: 0x%03x", hdr.magic);
492 rb->lcd_puts(0, 3, buf);
493 rb->snprintf(buf, sizeof(buf), "Size: 0x%03x", hdr.length);
494 rb->lcd_puts(0, 4, buf);
495 rb->lcd_update();
496 rb->sleep(HZ*10);
497 622
498 rb->memcpy(&hdr, (uint8_t *)(FLASH_ENTRYPOINT/2), sizeof(struct flash_header)); 623 rb->splash(HZ*2, true, "Success");
499 rb->snprintf(buf, sizeof(buf), "Magic: 0x%03x", hdr.magic); 624
500 rb->lcd_puts(0, 3, buf); 625 return 0;
501 rb->snprintf(buf, sizeof(buf), "Size: 0x%03x", hdr.length); 626}
502 rb->lcd_puts(0, 4, buf); 627
503 rb->lcd_update(); 628int load_original_bin(const char *filename)
504 rb->sleep(HZ*10); 629{
505#endif 630 unsigned long magic[2];
631 int len, rc;
632 int fd;
506 633
507 /* Restore? */ 634 fd = rb->open(filename, O_RDONLY);
508#if 0
509 fd = rb->open("/internal_rom_000000-1FFFFF.bin", O_RDONLY);
510 if (fd < 0) 635 if (fd < 0)
511 return ; 636 return -1;
512 len = rb->filesize(fd);
513 637
514 /* Erase the program flash. */ 638 len = rb->filesize(fd) - 0x228;
515 for (i = 1; i < 0x1EF; i++) 639 rb->lseek(fd, 0x220, SEEK_SET);
640 rb->read(fd, magic, 8);
641 if (magic[1] != 0x00000008 || len <= 0 || len > audiobuf_size)
516 { 642 {
517 rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i); 643 rb->splash(HZ*2, true, "Not an original firmware file");
518 rb->snprintf(buf, sizeof(buf), "Erase: 0x%03x (%d)", i, rc); 644 rb->close(fd);
519 rb->lcd_puts(0, 3, buf); 645 return -1;
520 rb->lcd_update();
521 } 646 }
522 647
523 i = FLASH_ENTRYPOINT/2; 648 rc = rb->read(fd, audiobuf, len);
524 rb->lseek(fd, i*2, SEEK_SET); 649 rb->close(fd);
525 len -= i*2 - 0xffff; 650
526 for (; len > 0 && i < (0x1F0000/2); i++) 651 if (rc != len)
527 { 652 {
528 rb->read(fd, bytes, 2); 653 rb->splash(HZ*2, true, "Read error");
529 cfi_program_word(FB + i, (bytes[0] << 8) | bytes[1]); 654 return -2;
530 len -= 2;
531 } 655 }
532 656
657 if (len % 2)
658 len++;
659
660 if (!confirm("Restore original firmware (bootloader will be kept)?"))
661 return -2;
662
663 return flash_original_fw(len);
664}
665
666int load_romdump(const char *filename)
667{
668 int len, rc;
669 int fd;
670
671 fd = rb->open(filename, O_RDONLY);
672 if (fd < 0)
673 return -1;
674
675 len = rb->filesize(fd) - 8;
676 if (len <= 0)
677 return -1;
678
679 rb->lseek(fd, 8, SEEK_SET);
680 rc = rb->read(fd, audiobuf, len);
533 rb->close(fd); 681 rb->close(fd);
534 return ;
535#endif
536 682
683 if (rc != len)
684 {
685 rb->splash(HZ*2, true, "Read error");
686 return -2;
687 }
688
689 if (len % 2)
690 len++;
691
692 if (len > BOOTLOADER_ENTRYPOINT - 8)
693 len = BOOTLOADER_ENTRYPOINT - 8;
694
695 if (!confirm("Restore firmware section (bootloader will be kept)?"))
696 return -2;
697
698 return flash_original_fw(len);
699}
700
701/* Kind of our main function, defines the application flow. */
702void DoUserDialog(char* filename)
703{
704 /* this can only work if Rockbox runs in DRAM, not flash ROM */
705 if ((uint16_t*)rb >= FB && (uint16_t*)rb < FB + 4096*1024) /* 4 MB max */
706 { /* we're running from flash */
707 rb->splash(HZ*3, true, "Not from ROM");
708 return; /* exit */
709 }
710
711 /* refuse to work if the power may fail meanwhile */
712 if (!rb->battery_level_safe())
713 {
714 rb->splash(HZ*3, true, "Battery too low!");
715 return; /* exit */
716 }
717
718 rb->lcd_setfont(FONT_SYSFIXED);
719 if (!show_info())
720 return ;
721
537 if (filename == NULL) 722 if (filename == NULL)
538 { 723 {
539 rb->splash(HZ*3, true, "Please use this plugin with \"Open with...\""); 724 rb->splash(HZ*3, true, "Please use this plugin with \"Open with...\"");
@@ -546,6 +731,10 @@ void DoUserDialog(char* filename)
546 flash_rockbox(filename); 731 flash_rockbox(filename);
547 else if (rb->strcasestr(filename, "/bootloader.iriver")) 732 else if (rb->strcasestr(filename, "/bootloader.iriver"))
548 flash_bootloader(filename); 733 flash_bootloader(filename);
734 else if (rb->strcasestr(filename, "/ihp_120.bin"))
735 load_original_bin(filename);
736 else if (rb->strcasestr(filename, "/internal_rom_000000-1FFFFF.bin"))
737 load_romdump(filename);
549 else 738 else
550 rb->splash(HZ*3, true, "Unknown file type"); 739 rb->splash(HZ*3, true, "Unknown file type");
551} 740}