1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006-2007 Dave Chapman
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
26 #include <sys/types.h>
30 #include "sansapatcher.h"
33 #include "bootimg_c200.h"
34 #include "bootimg_e200.h"
36 /* The offset of the MI4 image header in the firmware partition */
37 #define PPMI_OFFSET 0x80000
38 #define NVPARAMS_OFFSET 0x780000
39 #define NVPARAMS_SIZE (0x80000-0x200)
43 /* Windows requires the buffer for disk I/O to be aligned in memory on a
44 multiple of the disk volume size - so we use a single global variable
45 and initialise it with sansa_alloc_buf() in main().
48 extern unsigned char* sectorbuf
;
50 static off_t
filesize(int fd
) {
53 if (fstat(fd
,&buf
) < 0) {
54 perror("[ERR] Checking filesize of input file");
61 /* Partition table parsing code taken from Rockbox */
63 #define MAX_SECTOR_SIZE 2048
64 #define SECTOR_SIZE 512
66 static inline int32_t le2int(unsigned char* buf
)
68 int32_t res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
73 static inline uint32_t le2uint(unsigned char* buf
)
75 uint32_t res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
80 static inline void int2le(unsigned int val
, unsigned char* addr
)
83 addr
[1] = (val
>> 8) & 0xff;
84 addr
[2] = (val
>> 16) & 0xff;
85 addr
[3] = (val
>> 24) & 0xff;
88 #define BYTES2INT32(array,pos)\
89 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
90 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
92 int sansa_read_partinfo(struct sansa_t
* sansa
, int silent
)
97 count
= sansa_read(sansa
,sectorbuf
, sansa
->sector_size
);
100 print_error(" Error reading from disk: ");
104 if ((sectorbuf
[510] == 0x55) && (sectorbuf
[511] == 0xaa)) {
105 /* parse partitions */
106 for ( i
= 0; i
< 4; i
++ ) {
107 unsigned char* ptr
= sectorbuf
+ 0x1be + 16*i
;
108 sansa
->pinfo
[i
].type
= ptr
[4];
109 sansa
->pinfo
[i
].start
= BYTES2INT32(ptr
, 8);
110 sansa
->pinfo
[i
].size
= BYTES2INT32(ptr
, 12);
113 if ( sansa
->pinfo
[i
].type
== 5 ) {
114 /* not handled yet */
117 } else if ((sectorbuf
[0] == 'E') && (sectorbuf
[1] == 'R')) {
118 if (!silent
) fprintf(stderr
,"[ERR] Bad boot sector signature\n");
122 /* Calculate the starting position of the firmware partition */
123 sansa
->start
= (loff_t
)sansa
->pinfo
[1].start
*(loff_t
)sansa
->sector_size
;
127 /* NOTE: memmem implementation copied from glibc-2.2.4 - it's a GNU
128 extension and is not universally. In addition, early versions of
129 memmem had a serious bug - the meaning of needle and haystack were
132 /* Copyright (C) 1991,92,93,94,96,97,98,2000 Free Software Foundation, Inc.
133 This file is part of the GNU C Library.
135 The GNU C Library is free software; you can redistribute it and/or
136 modify it under the terms of the GNU Lesser General Public
137 License as published by the Free Software Foundation; either
138 version 2.1 of the License, or (at your option) any later version.
140 The GNU C Library is distributed in the hope that it will be useful,
141 but WITHOUT ANY WARRANTY; without even the implied warranty of
142 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
143 Lesser General Public License for more details.
145 You should have received a copy of the GNU Lesser General Public
146 License along with the GNU C Library; if not, write to the Free
147 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
150 /* Return the first occurrence of NEEDLE in HAYSTACK. */
152 sansa_memmem (haystack
, haystack_len
, needle
, needle_len
)
153 const void *haystack
;
159 const char *const last_possible
160 = (const char *) haystack
+ haystack_len
- needle_len
;
163 /* The first occurrence of the empty string is deemed to occur at
164 the beginning of the string. */
165 return (void *) haystack
;
167 /* Sanity check, otherwise the loop might search through the whole
169 if (__builtin_expect (haystack_len
< needle_len
, 0))
172 for (begin
= (const char *) haystack
; begin
<= last_possible
; ++begin
)
173 if (begin
[0] == ((const char *) needle
)[0] &&
174 !memcmp ((const void *) &begin
[1],
175 (const void *) ((const char *) needle
+ 1),
177 return (void *) begin
;
183 * CRC32 implementation taken from:
185 * efone - Distributed internet phone system.
187 * (c) 1999,2000 Krzysztof Dabrowski
188 * (c) 1999,2000 ElysiuM deeZine
190 * This program is free software; you can redistribute it and/or
191 * modify it under the terms of the GNU General Public License
192 * as published by the Free Software Foundation; either version
193 * 2 of the License, or (at your option) any later version.
197 /* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
198 * so make sure, you call it before using the other
201 static unsigned int crc_tab
[256];
203 /* chksum_crc() -- to a given block, this one calculates the
204 * crc32-checksum until the length is
205 * reached. the crc32-checksum will be
208 static unsigned int chksum_crc32 (unsigned char *block
, unsigned int length
)
210 register unsigned long crc
;
214 for (i
= 0; i
< length
; i
++)
216 crc
= ((crc
>> 8) & 0x00FFFFFF) ^ crc_tab
[(crc
^ *block
++) & 0xFF];
221 /* chksum_crc32gentab() -- to a global crc_tab[256], this one will
222 * calculate the crcTable for crc32-checksums.
223 * it is generated to the polynom [..]
226 static void chksum_crc32gentab (void)
228 unsigned long crc
, poly
;
232 for (i
= 0; i
< 256; i
++)
235 for (j
= 8; j
> 0; j
--)
239 crc
= (crc
>> 1) ^ poly
;
250 /* Known keys for Sansa E200 and C200 firmwares: */
251 #define NUM_KEYS ((int)(sizeof(keys)/sizeof(keys[0])))
252 static uint32_t keys
[][4] = {
253 { 0xe494e96e, 0x3ee32966, 0x6f48512b, 0xa93fbb42 }, /* "sansa" */
254 { 0xd7b10538, 0xc662945b, 0x1b3fce68, 0xf389c0e6 }, /* "sansa_gh" */
255 { 0x1d29ddc0, 0x2579c2cd, 0xce339e1a, 0x75465dfe }, /* sansa 103 */
257 { 0xbf2d06fa, 0xf0e23d59, 0x29738132, 0xe2d04ca7 }, /* c200 */
258 { 0x2a7968de, 0x15127979, 0x142e60a7, 0xe49c1893 }, /* c200 1.00.03 */
259 { 0xa913d139, 0xf842f398, 0x3e03f1a6, 0x060ee012 }, /* c200 1.00.06 */
264 tea_decrypt() from http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
266 "Following is an adaptation of the reference encryption and decryption
267 routines in C, released into the public domain by David Wheeler and
272 /* NOTE: The mi4 version of TEA uses a different initial value to sum compared
273 to the reference implementation and the main loop is 8 iterations, not
277 void tea_decrypt(uint32_t* v0
, uint32_t* v1
, uint32_t* k
) {
278 uint32_t sum
=0xF1BBCDC8, i
; /* set up */
279 uint32_t delta
=0x9E3779B9; /* a key schedule constant */
280 uint32_t k0
=k
[0], k1
=k
[1], k2
=k
[2], k3
=k
[3]; /* cache key */
281 for(i
=0; i
<8; i
++) { /* basic cycle start */
282 *v1
-= ((*v0
<<4) + k2
) ^ (*v0
+ sum
) ^ ((*v0
>>5) + k3
);
283 *v0
-= ((*v1
<<4) + k0
) ^ (*v1
+ sum
) ^ ((*v1
>>5) + k1
);
284 sum
-= delta
; /* end cycle */
288 /* mi4 files are encrypted in 64-bit blocks (two little-endian 32-bit
289 integers) and the key is incremented after each block
292 void tea_decrypt_buf(unsigned char* src
, unsigned char* dest
, size_t n
, uint32_t * key
)
297 for (i
= 0; i
< (n
/ 8); i
++) {
301 tea_decrypt(&v0
, &v1
, key
);
309 /* Now increment the key */
323 static int get_mi4header(unsigned char* buf
,struct mi4header_t
* mi4header
)
325 if (memcmp(buf
,"PPOS",4)!=0)
328 mi4header
->version
= le2int(buf
+0x04);
329 mi4header
->length
= le2int(buf
+0x08);
330 mi4header
->crc32
= le2int(buf
+0x0c);
331 mi4header
->enctype
= le2int(buf
+0x10);
332 mi4header
->mi4size
= le2int(buf
+0x14);
333 mi4header
->plaintext
= le2int(buf
+0x18);
338 static int set_mi4header(unsigned char* buf
,struct mi4header_t
* mi4header
)
340 if (memcmp(buf
,"PPOS",4)!=0)
343 int2le(mi4header
->version
,buf
+0x04);
344 int2le(mi4header
->length
,buf
+0x08);
345 int2le(mi4header
->crc32
,buf
+0x0c);
346 int2le(mi4header
->enctype
,buf
+0x10);
347 int2le(mi4header
->mi4size
,buf
+0x14);
348 int2le(mi4header
->plaintext
,buf
+0x18);
350 /* Add a dummy DSA signature */
351 memset(buf
+0x1c,0,40);
357 static int sansa_seek_and_read(struct sansa_t
* sansa
, loff_t pos
, unsigned char* buf
, int nbytes
)
361 if (sansa_seek(sansa
, pos
) < 0) {
365 if ((n
= sansa_read(sansa
,buf
,nbytes
)) < 0) {
370 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n",
379 /* We identify an E200 based on the following criteria:
381 1) Exactly two partitions;
382 2) First partition is type "W95 FAT32" (0x0b or 0x0c);
383 3) Second partition is type "OS/2 hidden C: drive" (0x84);
384 4) The "PPBL" string appears at offset 0 in the 2nd partition;
385 5) The "PPMI" string appears at offset PPMI_OFFSET in the 2nd partition.
388 int is_sansa(struct sansa_t
* sansa
)
390 struct mi4header_t mi4header
;
394 /* Check partition layout */
396 if (((sansa
->pinfo
[0].type
!= 0x06) &&
397 (sansa
->pinfo
[0].type
!= 0x0b) &&
398 (sansa
->pinfo
[0].type
!= 0x0c) &&
399 (sansa
->pinfo
[0].type
!= 0x0e)) ||
400 (sansa
->pinfo
[1].type
!= 0x84) ||
401 (sansa
->pinfo
[2].type
!= 0x00) ||
402 (sansa
->pinfo
[3].type
!= 0x00)) {
403 /* Bad partition layout, abort */
407 /* Check Bootloader header */
408 if (sansa_seek_and_read(sansa
, sansa
->start
, sectorbuf
, 0x200) < 0) {
411 if (memcmp(sectorbuf
,"PPBL",4)!=0) {
412 /* No bootloader header, abort */
415 ppbl_length
= (le2int(sectorbuf
+4) + 0x1ff) & ~0x1ff;
417 /* Sanity/safety check - the bootloader can't be larger than PPMI_OFFSET */
418 if (ppbl_length
> PPMI_OFFSET
)
423 /* Load Sansa bootloader and check for "Sansa C200" magic string */
424 if (sansa_seek_and_read(sansa
, sansa
->start
+ 0x200, sectorbuf
, ppbl_length
) < 0) {
425 fprintf(stderr
,"[ERR] Seek and read to 0x%08llx in is_sansa failed.\n",
429 if (sansa_memmem(sectorbuf
, ppbl_length
, "Sansa C200", 10) != NULL
) {
431 sansa
->targetname
="c200";
434 sansa
->targetname
="e200";
437 /* Check Main firmware header */
438 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
, sectorbuf
, 0x200) < 0) {
439 fprintf(stderr
,"[ERR] Seek to 0x%08llx in is_sansa failed.\n",
440 sansa
->start
+PPMI_OFFSET
);
443 if (memcmp(sectorbuf
,"PPMI",4)!=0) {
444 /* No bootloader header, abort */
447 ppmi_length
= le2int(sectorbuf
+4);
449 /* Check main mi4 file header */
450 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
+0x200, sectorbuf
, 0x200) < 0) {
451 fprintf(stderr
,"[ERR] Seek to 0x%08llx in is_sansa failed.\n",
452 sansa
->start
+PPMI_OFFSET
+0x200);
456 if (get_mi4header(sectorbuf
,&mi4header
) < 0) {
457 fprintf(stderr
,"[ERR] Invalid mi4header\n");
461 /* Some sanity checks:
463 1) Main MI4 image without RBBL and < 100000 bytes -> old install
464 2) Main MI4 image with RBBL but no second image -> old install
467 sansa
->hasoldbootloader
= 0;
468 if (memcmp(sectorbuf
+0x1f8,"RBBL",4)==0) {
469 /* Look for an original firmware after the first image */
470 if (sansa_seek_and_read(sansa
,
471 sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
,
472 sectorbuf
, 512) < 0) {
476 if (get_mi4header(sectorbuf
,&mi4header
)!=0) {
477 fprintf(stderr
,"[ERR] No original firmware found\n");
478 sansa
->hasoldbootloader
= 1;
480 } else if (mi4header
.mi4size
< 100000) {
481 fprintf(stderr
,"[ERR] Old bootloader found\n");
482 sansa
->hasoldbootloader
= 1;
488 int sansa_scan(struct sansa_t
* sansa
)
492 char last_disk
[4096];
494 printf("[INFO] Scanning disk devices...\n");
496 for (i
= 0; i
<= 25 ; i
++) {
498 sprintf(sansa
->diskname
,"\\\\.\\PhysicalDrive%d",i
);
499 #elif defined(linux) || defined (__linux)
500 sprintf(sansa
->diskname
,"/dev/sd%c",'a'+i
);
501 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
502 || defined(__bsdi__) || defined(__DragonFly__)
503 sprintf(sansa
->diskname
,"/dev/da%d",i
);
504 #elif defined(__APPLE__) && defined(__MACH__)
505 sprintf(sansa
->diskname
,"/dev/disk%d",i
);
507 #error No disk paths defined for this platform
509 if (sansa_open(sansa
, 1) < 0) {
513 if (sansa_read_partinfo(sansa
,1) < 0) {
517 if (is_sansa(sansa
) < 0) {
522 printf("[INFO] %s found - disk device %d\n",sansa
->targetname
, i
);
524 printf("[INFO] %s found - %s\n",sansa
->targetname
, sansa
->diskname
);
527 strcpy(last_disk
,sansa
->diskname
);
532 /* Remember the disk name */
533 strcpy(sansa
->diskname
,last_disk
);
538 /* Prepare original firmware for writing to the firmware partition by decrypting
539 and updating the header */
540 static int prepare_original_firmware(unsigned char* buf
, struct mi4header_t
* mi4header
)
542 unsigned char* tmpbuf
;
546 get_mi4header(buf
,mi4header
);
549 printf("mi4header->version =0x%08x\n",mi4header
->version
);
550 printf("mi4header->length =0x%08x\n",mi4header
->length
);
551 printf("mi4header->crc32 =0x%08x\n",mi4header
->crc32
);
552 printf("mi4header->enctype =0x%08x\n",mi4header
->enctype
);
553 printf("mi4header->mi4size =0x%08x\n",mi4header
->mi4size
);
554 printf("mi4header->plaintext =0x%08x\n",mi4header
->plaintext
);
557 /* Decrypt anything that needs decrypting. */
558 if (mi4header
->plaintext
< mi4header
->mi4size
- 0x200) {
559 /* TODO: Check different keys */
560 tmpbuf
=malloc(mi4header
->mi4size
-(mi4header
->plaintext
+0x200));
562 fprintf(stderr
,"[ERR] Can not allocate memory\n");
567 for (i
=0; i
< NUM_KEYS
&& !key_found
; i
++) {
568 tea_decrypt_buf(buf
+(mi4header
->plaintext
+0x200),
570 mi4header
->mi4size
-(mi4header
->plaintext
+0x200),
572 key_found
= (le2uint(tmpbuf
+mi4header
->length
-mi4header
->plaintext
-4) == 0xaa55aa55);
576 memcpy(buf
+(mi4header
->plaintext
+0x200),tmpbuf
,mi4header
->mi4size
-(mi4header
->plaintext
+0x200));
579 fprintf(stderr
,"[ERR] Failed to decrypt image, aborting\n");
585 /* Increase plaintext value to full file */
586 mi4header
->plaintext
= mi4header
->mi4size
- 0x200;
588 /* Update CRC checksum */
589 chksum_crc32gentab ();
590 mi4header
->crc32
= chksum_crc32(buf
+0x200,mi4header
->mi4size
-0x200);
592 set_mi4header(buf
,mi4header
);
594 /* Add Rockbox-specific header */
595 memcpy(buf
+0x1f8,"RBOFe200",8);
600 static int load_original_firmware(struct sansa_t
* sansa
, unsigned char* buf
, struct mi4header_t
* mi4header
)
605 /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */
606 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
, buf
, 512) < 0) {
610 /* No need to check PPMI magic - it's done during init to confirm
612 ppmi_length
= le2int(buf
+4);
614 /* Firstly look for an original firmware after the first image */
615 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
, buf
, 512) < 0) {
619 if (get_mi4header(buf
,mi4header
)==0) {
620 /* We have a valid MI4 file after a bootloader, so we use this. */
621 if ((n
= sansa_seek_and_read(sansa
,
622 sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
,
623 buf
, mi4header
->mi4size
)) < 0) {
627 /* No valid MI4 file, so read the first image. */
628 if ((n
= sansa_seek_and_read(sansa
,
629 sansa
->start
+ PPMI_OFFSET
+ 0x200,
630 buf
, ppmi_length
)) < 0) {
634 return prepare_original_firmware(buf
, mi4header
);
637 int sansa_read_firmware(struct sansa_t
* sansa
, char* filename
)
641 struct mi4header_t mi4header
;
643 res
= load_original_firmware(sansa
,sectorbuf
,&mi4header
);
647 outfile
= open(filename
,O_CREAT
|O_TRUNC
|O_WRONLY
|O_BINARY
,0666);
649 fprintf(stderr
,"[ERR] Couldn't open file %s\n",filename
);
653 res
= write(outfile
,sectorbuf
,mi4header
.mi4size
);
654 if (res
!= (int)mi4header
.mi4size
) {
655 fprintf(stderr
,"[ERR] Write error - %d\n", res
);
664 int sansa_add_bootloader(struct sansa_t
* sansa
, char* filename
, int type
)
667 int infile
= -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
668 int bl_length
= 0; /* Keep gcc happy when building for rbutil */
669 struct mi4header_t mi4header
;
673 if (type
==FILETYPE_MI4
) {
674 /* Step 1 - read bootloader into RAM. */
675 infile
=open(filename
,O_RDONLY
|O_BINARY
);
677 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
681 bl_length
= filesize(infile
);
684 if (strcmp(sansa
->targetname
,"c200") == 0) {
685 bl_length
= LEN_bootimg_c200
;
687 bl_length
= LEN_bootimg_e200
;
692 /* Create PPMI header */
693 memset(sectorbuf
,0,0x200);
694 memcpy(sectorbuf
,"PPMI",4);
695 int2le(bl_length
, sectorbuf
+4);
696 int2le(0x00020000, sectorbuf
+8);
698 if (type
==FILETYPE_MI4
) {
699 /* Read bootloader into sectorbuf+0x200 */
700 n
= read(infile
,sectorbuf
+0x200,bl_length
);
703 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n"
708 if (memcmp(sectorbuf
+0x200+0x1f8,"RBBL",4)!=0) {
709 fprintf(stderr
,"[ERR] %s is not a Rockbox bootloader, aborting.\n",
715 if (strcmp(sansa
->targetname
,"c200") == 0) {
716 memcpy(sectorbuf
+0x200,bootimg_c200
,LEN_bootimg_c200
);
718 memcpy(sectorbuf
+0x200,bootimg_e200
,LEN_bootimg_e200
);
723 /* Load original firmware from Sansa to the space after the bootloader */
724 res
= load_original_firmware(sansa
,sectorbuf
+0x200+bl_length
,&mi4header
);
728 /* Now write the whole thing back to the Sansa */
730 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
) < 0) {
731 fprintf(stderr
,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
732 sansa
->start
+PPMI_OFFSET
);
736 length
= 0x200 + bl_length
+ mi4header
.mi4size
;
738 n
=sansa_write(sansa
, sectorbuf
, length
);
740 fprintf(stderr
,"[ERR] Short write in add_bootloader\n");
747 int sansa_delete_bootloader(struct sansa_t
* sansa
)
750 struct mi4header_t mi4header
;
754 /* Load original firmware from Sansa to sectorbuf+0x200 */
755 res
= load_original_firmware(sansa
,sectorbuf
+0x200,&mi4header
);
759 /* Create PPMI header */
760 memset(sectorbuf
,0,0x200);
761 memcpy(sectorbuf
,"PPMI",4);
762 int2le(mi4header
.mi4size
, sectorbuf
+4);
763 int2le(0x00020000, sectorbuf
+8);
765 /* Now write the whole thing back to the Sansa */
767 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
) < 0) {
768 fprintf(stderr
,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
769 sansa
->start
+PPMI_OFFSET
);
773 length
= 0x200 + mi4header
.mi4size
;
775 n
=sansa_write(sansa
, sectorbuf
, length
);
777 fprintf(stderr
,"[ERR] Short write in delete_bootloader\n");
784 void sansa_list_images(struct sansa_t
* sansa
)
786 struct mi4header_t mi4header
;
789 /* Check Main firmware header */
790 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
, sectorbuf
, 0x200) < 0) {
794 ppmi_length
= le2int(sectorbuf
+4);
796 printf("[INFO] Image 1 - %llu bytes\n",ppmi_length
);
798 /* Look for an original firmware after the first image */
799 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
, sectorbuf
, 512) < 0) {
803 if (get_mi4header(sectorbuf
,&mi4header
)==0) {
804 printf("[INFO] Image 2 - %d bytes\n",mi4header
.mi4size
);
808 int sansa_update_of(struct sansa_t
* sansa
, char* filename
)
811 int infile
= -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
812 int of_length
= 0; /* Keep gcc happy when building for rbutil */
814 struct mi4header_t mi4header
;
815 unsigned char buf
[512];
817 /* Step 1 - check we have an OF on the Sansa to upgrade. We expect the
818 Rockbox bootloader to be installed and the OF to be after it on disk. */
820 /* Read 512 bytes from PPMI_OFFSET - the PPMI header */
821 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
,
826 /* No need to check PPMI magic - it's done during init to confirm
828 ppmi_length
= le2int(buf
+4);
830 /* Look for an original firmware after the first image */
831 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
,
836 if (get_mi4header(buf
,&mi4header
)!=0) {
837 /* We don't have a valid MI4 file after a bootloader, so do nothing. */
838 fprintf(stderr
,"[ERR] No original firmware found at 0x%08llx\n",
839 sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
);
843 /* Step 2 - read OF into RAM. */
844 infile
=open(filename
,O_RDONLY
|O_BINARY
);
846 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
850 of_length
= filesize(infile
);
852 /* Load original firmware from file */
853 memset(sectorbuf
,0,0x200);
854 n
= read(infile
,sectorbuf
,of_length
);
857 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n"
862 /* Check we have a valid MI4 file. */
863 if (get_mi4header(sectorbuf
,&mi4header
)!=0) {
864 fprintf(stderr
,"[ERR] %s is not a valid mi4 file\n",filename
);
868 /* Decrypt and build the header */
869 if(prepare_original_firmware(sectorbuf
, &mi4header
)!=0){
870 fprintf(stderr
,"[ERR] Unable to build decrypted mi4 from %s\n"
875 /* Step 3 - write the OF to the Sansa */
876 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
) < 0) {
877 fprintf(stderr
,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
878 sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
);
882 n
=sansa_write(sansa
, sectorbuf
, of_length
);
884 fprintf(stderr
,"[ERR] Short write in sansa_update_of\n");
888 /* Step 4 - zero out the nvparams section - we have to do this or we end up
889 with multiple copies of the nvparams data and don't know which one to
890 work with for the database rebuild disabling trick in our bootloader */
891 if (strcmp(sansa
->targetname
,"e200") == 0) {
892 printf("[INFO] Resetting Original Firmware settings\n");
893 if (sansa_seek(sansa
, sansa
->start
+NVPARAMS_OFFSET
+0x200) < 0) {
894 fprintf(stderr
,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
895 sansa
->start
+NVPARAMS_OFFSET
+0x200);
899 memset(sectorbuf
,0,NVPARAMS_SIZE
);
900 n
=sansa_write(sansa
, sectorbuf
, NVPARAMS_SIZE
);
901 if (n
< NVPARAMS_SIZE
) {
902 fprintf(stderr
,"[ERR] Short write in sansa_update_of\n");
910 /* Update the PPBL (bootloader) image in the hidden firmware partition */
911 int sansa_update_ppbl(struct sansa_t
* sansa
, char* filename
)
914 int infile
= -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
915 int ppbl_length
= 0; /* Keep gcc happy when building for rbutil */
917 /* Step 1 - read bootloader into RAM. */
918 infile
=open(filename
,O_RDONLY
|O_BINARY
);
920 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
924 ppbl_length
= filesize(infile
);
926 n
= read(infile
,sectorbuf
+0x200,ppbl_length
);
928 if (n
< ppbl_length
) {
929 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n", ppbl_length
, n
);
933 /* Step 2 - Build the header */
934 memset(sectorbuf
,0,0x200);
935 memcpy(sectorbuf
,"PPBL",4);
936 int2le(ppbl_length
, sectorbuf
+4);
937 int2le(0x00010000, sectorbuf
+8);
939 /* Step 3 - write the bootloader to the Sansa */
940 if (sansa_seek(sansa
, sansa
->start
) < 0) {
941 fprintf(stderr
,"[ERR] Seek to 0x%08llx in sansa_update_ppbl failed.\n", sansa
->start
);
945 n
=sansa_write(sansa
, sectorbuf
, ppbl_length
+ 0x200);
946 if (n
< (ppbl_length
+0x200)) {
947 fprintf(stderr
,"[ERR] Short write in sansa_update_ppbl\n");