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];
496 printf("[INFO] Scanning disk devices...\n");
498 for (i
= 0; i
<= 25 ; i
++) {
500 sprintf(sansa
->diskname
,"\\\\.\\PhysicalDrive%d",i
);
501 #elif defined(linux) || defined (__linux)
502 sprintf(sansa
->diskname
,"/dev/sd%c",'a'+i
);
503 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
504 || defined(__bsdi__) || defined(__DragonFly__)
505 sprintf(sansa
->diskname
,"/dev/da%d",i
);
506 #elif defined(__APPLE__) && defined(__MACH__)
507 sprintf(sansa
->diskname
,"/dev/disk%d",i
);
509 #error No disk paths defined for this platform
511 if ((result
= sansa_open(sansa
, 1)) < 0) {
518 if (sansa_read_partinfo(sansa
,1) < 0) {
522 if (is_sansa(sansa
) < 0) {
527 printf("[INFO] %s found - disk device %d\n",sansa
->targetname
, i
);
529 printf("[INFO] %s found - %s\n",sansa
->targetname
, sansa
->diskname
);
532 strcpy(last_disk
,sansa
->diskname
);
537 /* Remember the disk name */
538 strcpy(sansa
->diskname
,last_disk
);
540 else if (n
== 0 && denied
) {
541 printf("[ERR] FATAL: Permission denied on %d device(s) and no sansa detected.\n", denied
);
543 printf("[ERR] You need to run this program with administrator priviledges!\n");
545 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
549 return (n
== 0 && denied
) ? -1 : n
;
552 /* Prepare original firmware for writing to the firmware partition by decrypting
553 and updating the header */
554 static int prepare_original_firmware(unsigned char* buf
, struct mi4header_t
* mi4header
)
556 unsigned char* tmpbuf
;
560 get_mi4header(buf
,mi4header
);
563 printf("mi4header->version =0x%08x\n",mi4header
->version
);
564 printf("mi4header->length =0x%08x\n",mi4header
->length
);
565 printf("mi4header->crc32 =0x%08x\n",mi4header
->crc32
);
566 printf("mi4header->enctype =0x%08x\n",mi4header
->enctype
);
567 printf("mi4header->mi4size =0x%08x\n",mi4header
->mi4size
);
568 printf("mi4header->plaintext =0x%08x\n",mi4header
->plaintext
);
571 /* Decrypt anything that needs decrypting. */
572 if (mi4header
->plaintext
< mi4header
->mi4size
- 0x200) {
573 /* TODO: Check different keys */
574 tmpbuf
=malloc(mi4header
->mi4size
-(mi4header
->plaintext
+0x200));
576 fprintf(stderr
,"[ERR] Can not allocate memory\n");
581 for (i
=0; i
< NUM_KEYS
&& !key_found
; i
++) {
582 tea_decrypt_buf(buf
+(mi4header
->plaintext
+0x200),
584 mi4header
->mi4size
-(mi4header
->plaintext
+0x200),
586 key_found
= (le2uint(tmpbuf
+mi4header
->length
-mi4header
->plaintext
-4) == 0xaa55aa55);
590 memcpy(buf
+(mi4header
->plaintext
+0x200),tmpbuf
,mi4header
->mi4size
-(mi4header
->plaintext
+0x200));
593 fprintf(stderr
,"[ERR] Failed to decrypt image, aborting\n");
599 /* Increase plaintext value to full file */
600 mi4header
->plaintext
= mi4header
->mi4size
- 0x200;
602 /* Update CRC checksum */
603 chksum_crc32gentab ();
604 mi4header
->crc32
= chksum_crc32(buf
+0x200,mi4header
->mi4size
-0x200);
606 set_mi4header(buf
,mi4header
);
608 /* Add Rockbox-specific header */
609 memcpy(buf
+0x1f8,"RBOFe200",8);
614 static int load_original_firmware(struct sansa_t
* sansa
, unsigned char* buf
, struct mi4header_t
* mi4header
)
619 /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */
620 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
, buf
, 512) < 0) {
624 /* No need to check PPMI magic - it's done during init to confirm
626 ppmi_length
= le2int(buf
+4);
628 /* Firstly look for an original firmware after the first image */
629 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
, buf
, 512) < 0) {
633 if (get_mi4header(buf
,mi4header
)==0) {
634 /* We have a valid MI4 file after a bootloader, so we use this. */
635 if ((n
= sansa_seek_and_read(sansa
,
636 sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
,
637 buf
, mi4header
->mi4size
)) < 0) {
641 /* No valid MI4 file, so read the first image. */
642 if ((n
= sansa_seek_and_read(sansa
,
643 sansa
->start
+ PPMI_OFFSET
+ 0x200,
644 buf
, ppmi_length
)) < 0) {
648 return prepare_original_firmware(buf
, mi4header
);
651 int sansa_read_firmware(struct sansa_t
* sansa
, char* filename
)
655 struct mi4header_t mi4header
;
657 res
= load_original_firmware(sansa
,sectorbuf
,&mi4header
);
661 outfile
= open(filename
,O_CREAT
|O_TRUNC
|O_WRONLY
|O_BINARY
,0666);
663 fprintf(stderr
,"[ERR] Couldn't open file %s\n",filename
);
667 res
= write(outfile
,sectorbuf
,mi4header
.mi4size
);
668 if (res
!= (int)mi4header
.mi4size
) {
669 fprintf(stderr
,"[ERR] Write error - %d\n", res
);
678 int sansa_add_bootloader(struct sansa_t
* sansa
, char* filename
, int type
)
681 int infile
= -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
682 int bl_length
= 0; /* Keep gcc happy when building for rbutil */
683 struct mi4header_t mi4header
;
687 if (type
==FILETYPE_MI4
) {
688 /* Step 1 - read bootloader into RAM. */
689 infile
=open(filename
,O_RDONLY
|O_BINARY
);
691 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
695 bl_length
= filesize(infile
);
698 if (strcmp(sansa
->targetname
,"c200") == 0) {
699 bl_length
= LEN_bootimg_c200
;
701 bl_length
= LEN_bootimg_e200
;
706 /* Create PPMI header */
707 memset(sectorbuf
,0,0x200);
708 memcpy(sectorbuf
,"PPMI",4);
709 int2le(bl_length
, sectorbuf
+4);
710 int2le(0x00020000, sectorbuf
+8);
712 if (type
==FILETYPE_MI4
) {
713 /* Read bootloader into sectorbuf+0x200 */
714 n
= read(infile
,sectorbuf
+0x200,bl_length
);
717 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n"
722 if (memcmp(sectorbuf
+0x200+0x1f8,"RBBL",4)!=0) {
723 fprintf(stderr
,"[ERR] %s is not a Rockbox bootloader, aborting.\n",
729 if (strcmp(sansa
->targetname
,"c200") == 0) {
730 memcpy(sectorbuf
+0x200,bootimg_c200
,LEN_bootimg_c200
);
732 memcpy(sectorbuf
+0x200,bootimg_e200
,LEN_bootimg_e200
);
737 /* Load original firmware from Sansa to the space after the bootloader */
738 res
= load_original_firmware(sansa
,sectorbuf
+0x200+bl_length
,&mi4header
);
742 /* Now write the whole thing back to the Sansa */
744 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
) < 0) {
745 fprintf(stderr
,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
746 sansa
->start
+PPMI_OFFSET
);
750 length
= 0x200 + bl_length
+ mi4header
.mi4size
;
752 n
=sansa_write(sansa
, sectorbuf
, length
);
754 fprintf(stderr
,"[ERR] Short write in add_bootloader\n");
761 int sansa_delete_bootloader(struct sansa_t
* sansa
)
764 struct mi4header_t mi4header
;
768 /* Load original firmware from Sansa to sectorbuf+0x200 */
769 res
= load_original_firmware(sansa
,sectorbuf
+0x200,&mi4header
);
773 /* Create PPMI header */
774 memset(sectorbuf
,0,0x200);
775 memcpy(sectorbuf
,"PPMI",4);
776 int2le(mi4header
.mi4size
, sectorbuf
+4);
777 int2le(0x00020000, sectorbuf
+8);
779 /* Now write the whole thing back to the Sansa */
781 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
) < 0) {
782 fprintf(stderr
,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
783 sansa
->start
+PPMI_OFFSET
);
787 length
= 0x200 + mi4header
.mi4size
;
789 n
=sansa_write(sansa
, sectorbuf
, length
);
791 fprintf(stderr
,"[ERR] Short write in delete_bootloader\n");
798 void sansa_list_images(struct sansa_t
* sansa
)
800 struct mi4header_t mi4header
;
803 /* Check Main firmware header */
804 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
, sectorbuf
, 0x200) < 0) {
808 ppmi_length
= le2int(sectorbuf
+4);
810 printf("[INFO] Image 1 - %llu bytes\n",ppmi_length
);
812 /* Look for an original firmware after the first image */
813 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
, sectorbuf
, 512) < 0) {
817 if (get_mi4header(sectorbuf
,&mi4header
)==0) {
818 printf("[INFO] Image 2 - %d bytes\n",mi4header
.mi4size
);
822 int sansa_update_of(struct sansa_t
* sansa
, char* filename
)
825 int infile
= -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
826 int of_length
= 0; /* Keep gcc happy when building for rbutil */
828 struct mi4header_t mi4header
;
829 unsigned char buf
[512];
831 /* Step 1 - check we have an OF on the Sansa to upgrade. We expect the
832 Rockbox bootloader to be installed and the OF to be after it on disk. */
834 /* Read 512 bytes from PPMI_OFFSET - the PPMI header */
835 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
,
840 /* No need to check PPMI magic - it's done during init to confirm
842 ppmi_length
= le2int(buf
+4);
844 /* Look for an original firmware after the first image */
845 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
,
850 if (get_mi4header(buf
,&mi4header
)!=0) {
851 /* We don't have a valid MI4 file after a bootloader, so do nothing. */
852 fprintf(stderr
,"[ERR] No original firmware found at 0x%08llx\n",
853 sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
);
857 /* Step 2 - read OF into RAM. */
858 infile
=open(filename
,O_RDONLY
|O_BINARY
);
860 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
864 of_length
= filesize(infile
);
866 /* Load original firmware from file */
867 memset(sectorbuf
,0,0x200);
868 n
= read(infile
,sectorbuf
,of_length
);
871 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n"
876 /* Check we have a valid MI4 file. */
877 if (get_mi4header(sectorbuf
,&mi4header
)!=0) {
878 fprintf(stderr
,"[ERR] %s is not a valid mi4 file\n",filename
);
882 /* Decrypt and build the header */
883 if(prepare_original_firmware(sectorbuf
, &mi4header
)!=0){
884 fprintf(stderr
,"[ERR] Unable to build decrypted mi4 from %s\n"
889 /* Step 3 - write the OF to the Sansa */
890 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
) < 0) {
891 fprintf(stderr
,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
892 sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
);
896 n
=sansa_write(sansa
, sectorbuf
, of_length
);
898 fprintf(stderr
,"[ERR] Short write in sansa_update_of\n");
902 /* Step 4 - zero out the nvparams section - we have to do this or we end up
903 with multiple copies of the nvparams data and don't know which one to
904 work with for the database rebuild disabling trick in our bootloader */
905 if (strcmp(sansa
->targetname
,"e200") == 0) {
906 printf("[INFO] Resetting Original Firmware settings\n");
907 if (sansa_seek(sansa
, sansa
->start
+NVPARAMS_OFFSET
+0x200) < 0) {
908 fprintf(stderr
,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
909 sansa
->start
+NVPARAMS_OFFSET
+0x200);
913 memset(sectorbuf
,0,NVPARAMS_SIZE
);
914 n
=sansa_write(sansa
, sectorbuf
, NVPARAMS_SIZE
);
915 if (n
< NVPARAMS_SIZE
) {
916 fprintf(stderr
,"[ERR] Short write in sansa_update_of\n");
924 /* Update the PPBL (bootloader) image in the hidden firmware partition */
925 int sansa_update_ppbl(struct sansa_t
* sansa
, char* filename
)
928 int infile
= -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
929 int ppbl_length
= 0; /* Keep gcc happy when building for rbutil */
931 /* Step 1 - read bootloader into RAM. */
932 infile
=open(filename
,O_RDONLY
|O_BINARY
);
934 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
938 ppbl_length
= filesize(infile
);
940 n
= read(infile
,sectorbuf
+0x200,ppbl_length
);
942 if (n
< ppbl_length
) {
943 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n", ppbl_length
, n
);
947 /* Step 2 - Build the header */
948 memset(sectorbuf
,0,0x200);
949 memcpy(sectorbuf
,"PPBL",4);
950 int2le(ppbl_length
, sectorbuf
+4);
951 int2le(0x00010000, sectorbuf
+8);
953 /* Step 3 - write the bootloader to the Sansa */
954 if (sansa_seek(sansa
, sansa
->start
) < 0) {
955 fprintf(stderr
,"[ERR] Seek to 0x%08llx in sansa_update_ppbl failed.\n", sansa
->start
);
959 n
=sansa_write(sansa
, sectorbuf
, ppbl_length
+ 0x200);
960 if (n
< (ppbl_length
+0x200)) {
961 fprintf(stderr
,"[ERR] Short write in sansa_update_ppbl\n");