From 6a0ec8bfa86e7fcf02a9179dc8adbf2f0e25e6e7 Mon Sep 17 00:00:00 2001 From: Barry Wardell Date: Thu, 2 Aug 2007 11:39:43 +0000 Subject: Add --update-original-firmware (or -of) option to sansapatcher. This allows for changing the original firmware version when the rockbox bootloader is also present. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14138 a1c6a512-1295-4272-9138-f99709370657 --- rbutil/sansapatcher/main.c | 25 +++++- rbutil/sansapatcher/sansapatcher.c | 157 +++++++++++++++++++++++++++++-------- rbutil/sansapatcher/sansapatcher.h | 1 + 3 files changed, 147 insertions(+), 36 deletions(-) diff --git a/rbutil/sansapatcher/main.c b/rbutil/sansapatcher/main.c index 4f2a5fe226..a675cd80b6 100644 --- a/rbutil/sansapatcher/main.c +++ b/rbutil/sansapatcher/main.c @@ -47,7 +47,8 @@ enum { READ_FIRMWARE, WRITE_FIRMWARE, READ_PARTITION, - WRITE_PARTITION + WRITE_PARTITION, + UPDATE_OF }; void print_usage(void) @@ -62,9 +63,10 @@ void print_usage(void) fprintf(stderr,"Where [action] is one of the following options:\n"); fprintf(stderr," --install\n"); fprintf(stderr," -l, --list\n"); - fprintf(stderr," -rf, --read-firmware filename.mi4\n"); - fprintf(stderr," -a, --add-bootloader filename.mi4\n"); + fprintf(stderr," -rf, --read-firmware filename.mi4\n"); + fprintf(stderr," -a, --add-bootloader filename.mi4\n"); fprintf(stderr," -d, --delete-bootloader\n"); + fprintf(stderr," -of --update-original-firmware filename.mi4\n"); fprintf(stderr,"\n"); #ifdef __WIN32__ @@ -216,6 +218,13 @@ int main(int argc, char* argv[]) if (i == argc) { print_usage(); return 1; } filename=argv[i]; i++; + } else if ((strcmp(argv[i],"-of")==0) || + (strcmp(argv[i],"--update-original-firmware")==0)) { + action = UPDATE_OF; + i++; + if (i == argc) { print_usage(); return 1; } + filename=argv[i]; + i++; } else if ((strcmp(argv[i],"-rf")==0) || (strcmp(argv[i],"--read-firmware")==0)) { action = READ_FIRMWARE; @@ -326,6 +335,16 @@ int main(int argc, char* argv[]) } else { fprintf(stderr,"[ERR] --delete-bootloader failed.\n"); } + } else if (action==UPDATE_OF) { + if (sansa_reopen_rw(&sansa) < 0) { + return 5; + } + + if (sansa_update_of(&sansa, filename)==0) { + fprintf(stderr,"[INFO] OF updated successfully.\n"); + } else { + fprintf(stderr,"[ERR] --update-original-firmware failed.\n"); + } } } diff --git a/rbutil/sansapatcher/sansapatcher.c b/rbutil/sansapatcher/sansapatcher.c index 9b52196a7b..c9f047f472 100644 --- a/rbutil/sansapatcher/sansapatcher.c +++ b/rbutil/sansapatcher/sansapatcher.c @@ -446,44 +446,14 @@ int sansa_scan(struct sansa_t* sansa) return n; } -static int load_original_firmware(struct sansa_t* sansa, unsigned char* buf, struct mi4header_t* mi4header) +/* Prepare original firmware for writing to the firmware partition by decrypting + and updating the header */ +static int prepare_original_firmware(unsigned char* buf, struct mi4header_t* mi4header) { - int ppmi_length; - int n; unsigned char* tmpbuf; int i; int key_found; - /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */ - if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET, buf, 512) < 0) { - return -1; - } - - /* No need to check PPMI magic - it's done during init to confirm - this is an E200 */ - ppmi_length = le2int(buf+4); - - /* Firstly look for an original firmware after the first image */ - if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, buf, 512) < 0) { - return -1; - } - - if (get_mi4header(buf,mi4header)==0) { - /* We have a valid MI4 file after a bootloader, so we use this. */ - if ((n = sansa_seek_and_read(sansa, - sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, - buf, mi4header->mi4size)) < 0) { - return -1; - } - } else { - /* No valid MI4 file, so read the first image. */ - if ((n = sansa_seek_and_read(sansa, - sansa->start + PPMI_OFFSET + 0x200, - buf, ppmi_length)) < 0) { - return -1; - } - } - get_mi4header(buf,mi4header); #if 0 @@ -538,6 +508,43 @@ static int load_original_firmware(struct sansa_t* sansa, unsigned char* buf, str return 0; } +static int load_original_firmware(struct sansa_t* sansa, unsigned char* buf, struct mi4header_t* mi4header) +{ + int ppmi_length; + int n; + + /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */ + if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET, buf, 512) < 0) { + return -1; + } + + /* No need to check PPMI magic - it's done during init to confirm + this is an E200 */ + ppmi_length = le2int(buf+4); + + /* Firstly look for an original firmware after the first image */ + if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, buf, 512) < 0) { + return -1; + } + + if (get_mi4header(buf,mi4header)==0) { + /* We have a valid MI4 file after a bootloader, so we use this. */ + if ((n = sansa_seek_and_read(sansa, + sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, + buf, mi4header->mi4size)) < 0) { + return -1; + } + } else { + /* No valid MI4 file, so read the first image. */ + if ((n = sansa_seek_and_read(sansa, + sansa->start + PPMI_OFFSET + 0x200, + buf, ppmi_length)) < 0) { + return -1; + } + } + return prepare_original_firmware(buf, mi4header); +} + int sansa_read_firmware(struct sansa_t* sansa, char* filename) { int res; @@ -700,3 +707,87 @@ void sansa_list_images(struct sansa_t* sansa) printf("[INFO] Image 2 - %d bytes\n",mi4header.mi4size); } } + +int sansa_update_of(struct sansa_t* sansa, char* filename) +{ + int n; + int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */ + int of_length = 0; /* Keep gcc happy when building for rbutil */ + int ppmi_length; + struct mi4header_t mi4header; + char buf[512]; + + /* Step 1 - check we have an OF on the Sansa to upgrade. We expect the + Rockbox bootloader to be installed and the OF to be after it on disk. */ + + /* Read 512 bytes from PPMI_OFFSET - the PPMI header */ + if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET, + buf, 512) < 0) { + return -1; + } + + /* No need to check PPMI magic - it's done during init to confirm + this is an E200 */ + ppmi_length = le2int(buf+4); + + /* Look for an original firmware after the first image */ + if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET+0x200+ppmi_length, + buf, 512) < 0) { + return -1; + } + + if (get_mi4header(buf,&mi4header)!=0) { + /* We don't have a valid MI4 file after a bootloader, so do nothing. */ + fprintf(stderr,"[ERR] No original firmware found at 0x%08llx\n", + (loff_t)(sansa->start+PPMI_OFFSET+0x200+ppmi_length)); + return -1; + } + + /* Step 2 - read OF into RAM. */ + infile=open(filename,O_RDONLY|O_BINARY); + if (infile < 0) { + fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename); + return -1; + } + + of_length = filesize(infile); + + /* Load original firmware from file */ + memset(sectorbuf,0,0x200); + n = read(infile,sectorbuf,of_length); + close(infile); + if (n < of_length) { + fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n" + , of_length, n); + return -1; + } + + /* Check we have a valid MI4 file. */ + if (get_mi4header(sectorbuf,&mi4header)!=0) { + fprintf(stderr,"[ERR] %s is not a valid mi4 file\n",filename); + return -1; + } + + /* Decrypt and build the header */ + if(prepare_original_firmware(sectorbuf, &mi4header)!=0){ + fprintf(stderr,"[ERR] Unable to build decrypted mi4 from %s\n" + ,filename); + return -1; + } + + /* Step 3 - write the OF to the Sansa */ + if (sansa_seek(sansa, sansa->start+PPMI_OFFSET+0x200+ppmi_length) < 0) { + fprintf(stderr,"[ERR] Seek to 0x%08x in sansa_update_of failed.\n", + (unsigned int)(sansa->start+PPMI_OFFSET+0x200+ppmi_length)); + return -1; + } + + n=sansa_write(sansa, sectorbuf, of_length); + if (n < of_length) { + fprintf(stderr,"[ERR] Short write in sansa_update_of\n"); + return -1; + } + + return 0; +} + diff --git a/rbutil/sansapatcher/sansapatcher.h b/rbutil/sansapatcher/sansapatcher.h index a393a86576..52c72f834c 100644 --- a/rbutil/sansapatcher/sansapatcher.h +++ b/rbutil/sansapatcher/sansapatcher.h @@ -36,6 +36,7 @@ int sansa_scan(struct sansa_t* sansa); int sansa_read_firmware(struct sansa_t* sansa, char* filename); int sansa_add_bootloader(struct sansa_t* sansa, char* filename, int type); int sansa_delete_bootloader(struct sansa_t* sansa); +int sansa_update_of(struct sansa_t* sansa,char* filename); void sansa_list_images(struct sansa_t* sansa); #endif -- cgit v1.2.3