1
0
Fork 0
forked from len0rd/rockbox

Enabled iriver flashing plugin with additional safety checks,

confirmation and ability to restore original firmware.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10547 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2006-08-12 14:00:41 +00:00
parent 0ed49044b0
commit 25425360b5
2 changed files with 267 additions and 77 deletions

View file

@ -111,6 +111,7 @@ splitedit.c
/* Platform-specific plugins */
#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
iriverify.c
iriver_flash.c
#endif
#endif /* iFP7xx */

View file

@ -58,7 +58,7 @@ static struct plugin_api* rb; /* here is a global api struct pointer */
#ifdef IRIVER_H100_SERIES
#define SEC_SIZE 4096
#define BOOTLOADER_ERASEGUARD (BOOTLOADER_ENTRYPOINT / SEC_SIZE - 1)
#define BOOTLOADER_ERASEGUARD (BOOTLOADER_ENTRYPOINT / SEC_SIZE)
static volatile uint16_t* FB = (uint16_t*)0x00000000; /* Flash base address */
#endif
@ -181,7 +181,7 @@ bool cfi_get_flash_info(struct flash_info* pInfo)
/* Tool function to calculate a CRC32 across some buffer */
/* third argument is either 0xFFFFFFFF to start or value from last piece */
unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32)
unsigned crc_32(const unsigned char* buf, unsigned len, unsigned crc32)
{
/* CCITT standard polynomial 0x04C11DB7 */
static const unsigned crc32_lookup[16] =
@ -217,7 +217,7 @@ unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32)
/***************** User Interface Functions *****************/
int WaitForButton(void)
int wait_for_button(void)
{
int button;
@ -262,6 +262,36 @@ void ShowFlashInfo(struct flash_info* pInfo)
rb->lcd_update();
}
bool show_info(void)
{
struct flash_info fi;
rb->lcd_clear_display();
cfi_get_flash_info(&fi);
ShowFlashInfo(&fi);
if (fi.size == 0) /* no valid chip */
{
rb->splash(HZ*3, true, "Sorry!");
return false; /* exit */
}
return true;
}
bool confirm(const char *msg)
{
char buf[128];
bool ret;
rb->snprintf(buf, sizeof buf, "%s ([PLAY] to CONFIRM)", msg);
rb->splash(0, true, buf);
ret = (wait_for_button() == BUTTON_ON);
show_info();
return ret;
}
int load_firmware_file(const char *filename, uint32_t *checksum)
{
int fd;
@ -308,6 +338,45 @@ int load_firmware_file(const char *filename, uint32_t *checksum)
return len;
}
bool detect_flashed_rockbox(void)
{
struct flash_header hdr;
uint8_t *src = (uint8_t *)FLASH_ENTRYPOINT;
rb->memcpy(&hdr, src, sizeof(struct flash_header));
if (hdr.magic != FLASH_MAGIC)
return false;
return true;
}
unsigned long valid_bootloaders[][2] =
{
{ 62332, 0x77395351 },
{ 0, 0 }
};
bool detect_valid_bootloader(const unsigned char *addr, int len)
{
int i;
unsigned long crc32;
/* Try to scan through all valid bootloaders. */
for (i = 0; valid_bootloaders[i][0]; i++)
{
if (len > 0 && len != (long)valid_bootloaders[i][0])
continue;
crc32 = crc_32(addr, valid_bootloaders[i][0], 0xffffffff);
if (crc32 == valid_bootloaders[i][1])
return true;
}
return false;
}
int flash_rockbox(const char *filename)
{
struct flash_header hdr;
@ -318,9 +387,27 @@ int flash_rockbox(const char *filename)
uint16_t *p16;
len = load_firmware_file(filename, &checksum);
if (len < 0)
if (len <= 0)
return len * 10;
p8 = (char *)BOOTLOADER_ENTRYPOINT;
if (!detect_valid_bootloader(p8, 0))
{
rb->splash(HZ*3, true, "Incompatible bootloader");
return -1;
}
if (detect_flashed_rockbox())
{
if (!confirm("Update Rockbox flash image?"))
return -2;
}
else
{
if (!confirm("Erase original firmware?"))
return -3;
}
/* Erase the program flash. */
for (i = 1; i < BOOTLOADER_ERASEGUARD && (i-1)*4096 < len + 32; i++)
{
@ -349,10 +436,14 @@ int flash_rockbox(const char *filename)
}
p16 = (uint16_t *)audiobuf;
for (i = 0; i < len/2 && pos < (BOOTLOADER_ENTRYPOINT/2); i++)
for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++)
cfi_program_word(FB + pos + i, p16[i]);
/* Verify */
rb->snprintf(buf, sizeof(buf), "Verifying");
rb->lcd_puts(0, 5, buf);
rb->lcd_update();
p8 = (char *)FLASH_ENTRYPOINT;
p8 += sizeof(struct flash_header);
sum = 0;
@ -368,6 +459,8 @@ int flash_rockbox(const char *filename)
return -5;
}
rb->splash(HZ*2, true, "Success");
return 0;
}
@ -383,13 +476,13 @@ int flash_bootloader(const char *filename)
{
char buf[32];
int pos, i, len, rc;
unsigned long checksum, sum, crc32;
unsigned long checksum, sum;
unsigned char *p8;
uint16_t *p16;
(void)buf;
len = load_firmware_file(filename, &checksum);
if (len < 0)
if (len <= 0)
return len * 10;
if (len > 0xFFFF)
@ -399,18 +492,16 @@ int flash_bootloader(const char *filename)
}
/* Verify the crc32 checksum also. */
crc32 = crc_32(audiobuf, len, 0xffffffff);
#if 0
rb->snprintf(buf, sizeof buf, "crc32 = 0x%08x", crc32);
rb->splash(HZ*10, true, buf);
#else
if (crc32 != 0x77395351)
if (!detect_valid_bootloader(audiobuf, len))
{
rb->splash(HZ*3, true, "Untested bootloader");
return -2;
rb->splash(HZ*3, true, "Incompatible/Untested bootloader");
return -1;
}
#endif
rb->lcd_puts(0, 3, "Processing critical sections...");
if (!confirm("Update bootloader?"))
return -2;
rb->lcd_puts(0, 3, "Flashing...");
rb->lcd_update();
/* Erase the boot sector and write a proper reset vector. */
@ -445,6 +536,70 @@ int flash_bootloader(const char *filename)
for (i = 0; i < 8; i++)
{
if (p8[i] != audiobuf[i])
{
rb->splash(HZ*3, true, "Bootvector corrupt!");
show_fatal_error();
return -6;
}
}
rb->splash(HZ*2, true, "Success");
return 0;
}
int flash_original_fw(int len)
{
unsigned char reset_vector[8];
char buf[32];
int pos, i, rc;
unsigned char *p8;
uint16_t *p16;
(void)buf;
rb->lcd_puts(0, 3, "Critical section...");
rb->lcd_update();
p8 = (char *)FB;
rb->memcpy(reset_vector, p8, sizeof reset_vector);
/* Erase the boot sector and write back the reset vector. */
cfi_erase_sector(FB);
p16 = (uint16_t *)reset_vector;
for (i = 0; i < (long)sizeof(reset_vector)/2; i++)
cfi_program_word(FB + i, p16[i]);
rb->lcd_puts(0, 4, "Flashing orig. FW");
rb->lcd_update();
/* Erase the program flash. */
for (i = 1; i < BOOTLOADER_ERASEGUARD && (i-1)*4096 < len; i++)
{
rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i);
rb->snprintf(buf, sizeof(buf), "Erase: 0x%03x (%d)", i, rc);
rb->lcd_puts(0, 5, buf);
rb->lcd_update();
}
rb->snprintf(buf, sizeof(buf), "Programming");
rb->lcd_puts(0, 6, buf);
rb->lcd_update();
pos = 0x00000008/2;
p16 = (uint16_t *)audiobuf;
for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++)
cfi_program_word(FB + pos + i, p16[i]);
rb->snprintf(buf, sizeof(buf), "Verifying");
rb->lcd_puts(0, 7, buf);
rb->lcd_update();
/* Verify reset vectors. */
p8 = (char *)FB;
for (i = 0; i < 8; i++)
{
if (p8[i] != reset_vector[i])
{
rb->splash(HZ*3, true, "Bootvector corrupt!");
show_fatal_error();
@ -452,15 +607,100 @@ int flash_bootloader(const char *filename)
}
}
/* Verify */
p8 = (char *)0x00000008;
for (i = 0; i < len; i++)
{
if (p8[i] != audiobuf[i])
{
rb->splash(HZ*3, true, "Verify failed!");
rb->snprintf(buf, sizeof buf, "at: 0x%08x", i);
rb->splash(HZ*10, true, buf);
return -5;
}
}
rb->splash(HZ*2, true, "Success");
return 0;
}
int load_original_bin(const char *filename)
{
unsigned long magic[2];
int len, rc;
int fd;
fd = rb->open(filename, O_RDONLY);
if (fd < 0)
return -1;
len = rb->filesize(fd) - 0x228;
rb->lseek(fd, 0x220, SEEK_SET);
rb->read(fd, magic, 8);
if (magic[1] != 0x00000008 || len <= 0 || len > audiobuf_size)
{
rb->splash(HZ*2, true, "Not an original firmware file");
rb->close(fd);
return -1;
}
rc = rb->read(fd, audiobuf, len);
rb->close(fd);
if (rc != len)
{
rb->splash(HZ*2, true, "Read error");
return -2;
}
if (len % 2)
len++;
if (!confirm("Restore original firmware (bootloader will be kept)?"))
return -2;
return flash_original_fw(len);
}
int load_romdump(const char *filename)
{
int len, rc;
int fd;
fd = rb->open(filename, O_RDONLY);
if (fd < 0)
return -1;
len = rb->filesize(fd) - 8;
if (len <= 0)
return -1;
rb->lseek(fd, 8, SEEK_SET);
rc = rb->read(fd, audiobuf, len);
rb->close(fd);
if (rc != len)
{
rb->splash(HZ*2, true, "Read error");
return -2;
}
if (len % 2)
len++;
if (len > BOOTLOADER_ENTRYPOINT - 8)
len = BOOTLOADER_ENTRYPOINT - 8;
if (!confirm("Restore firmware section (bootloader will be kept)?"))
return -2;
return flash_original_fw(len);
}
/* Kind of our main function, defines the application flow. */
void DoUserDialog(char* filename)
{
struct flash_info fi;
int rc; /* generic return code */
/* this can only work if Rockbox runs in DRAM, not flash ROM */
if ((uint16_t*)rb >= FB && (uint16_t*)rb < FB + 4096*1024) /* 4 MB max */
{ /* we're running from flash */
@ -476,64 +716,9 @@ void DoUserDialog(char* filename)
}
rb->lcd_setfont(FONT_SYSFIXED);
rc = cfi_get_flash_info(&fi);
ShowFlashInfo(&fi);
if (fi.size == 0) /* no valid chip */
{
rb->splash(HZ*3, true, "Sorry!");
return; /* exit */
}
/* Debug? */
#if 0
rb->memcpy(&hdr, (uint8_t *)(FLASH_ENTRYPOINT), sizeof(struct flash_header));
rb->snprintf(buf, sizeof(buf), "Magic: 0x%03x", hdr.magic);
rb->lcd_puts(0, 3, buf);
rb->snprintf(buf, sizeof(buf), "Size: 0x%03x", hdr.length);
rb->lcd_puts(0, 4, buf);
rb->lcd_update();
rb->sleep(HZ*10);
rb->memcpy(&hdr, (uint8_t *)(FLASH_ENTRYPOINT/2), sizeof(struct flash_header));
rb->snprintf(buf, sizeof(buf), "Magic: 0x%03x", hdr.magic);
rb->lcd_puts(0, 3, buf);
rb->snprintf(buf, sizeof(buf), "Size: 0x%03x", hdr.length);
rb->lcd_puts(0, 4, buf);
rb->lcd_update();
rb->sleep(HZ*10);
#endif
/* Restore? */
#if 0
fd = rb->open("/internal_rom_000000-1FFFFF.bin", O_RDONLY);
if (fd < 0)
if (!show_info())
return ;
len = rb->filesize(fd);
/* Erase the program flash. */
for (i = 1; i < 0x1EF; i++)
{
rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i);
rb->snprintf(buf, sizeof(buf), "Erase: 0x%03x (%d)", i, rc);
rb->lcd_puts(0, 3, buf);
rb->lcd_update();
}
i = FLASH_ENTRYPOINT/2;
rb->lseek(fd, i*2, SEEK_SET);
len -= i*2 - 0xffff;
for (; len > 0 && i < (0x1F0000/2); i++)
{
rb->read(fd, bytes, 2);
cfi_program_word(FB + i, (bytes[0] << 8) | bytes[1]);
len -= 2;
}
rb->close(fd);
return ;
#endif
if (filename == NULL)
{
rb->splash(HZ*3, true, "Please use this plugin with \"Open with...\"");
@ -546,6 +731,10 @@ void DoUserDialog(char* filename)
flash_rockbox(filename);
else if (rb->strcasestr(filename, "/bootloader.iriver"))
flash_bootloader(filename);
else if (rb->strcasestr(filename, "/ihp_120.bin"))
load_original_bin(filename);
else if (rb->strcasestr(filename, "/internal_rom_000000-1FFFFF.bin"))
load_romdump(filename);
else
rb->splash(HZ*3, true, "Unknown file type");
}