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"
35 /* The offset of the MI4 image header in the firmware partition */
36 #define PPMI_OFFSET 0x80000
40 /* Windows requires the buffer for disk I/O to be aligned in memory on a
41 multiple of the disk volume size - so we use a single global variable
42 and initialise it with sansa_alloc_buf() in main().
45 extern unsigned char* sectorbuf
;
47 static off_t
filesize(int fd
) {
50 if (fstat(fd
,&buf
) < 0) {
51 perror("[ERR] Checking filesize of input file");
58 /* Partition table parsing code taken from Rockbox */
60 #define MAX_SECTOR_SIZE 2048
61 #define SECTOR_SIZE 512
63 static inline int32_t le2int(unsigned char* buf
)
65 int32_t res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
70 static inline uint32_t le2uint(unsigned char* buf
)
72 uint32_t res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
77 static inline void int2le(unsigned int val
, unsigned char* addr
)
80 addr
[1] = (val
>> 8) & 0xff;
81 addr
[2] = (val
>> 16) & 0xff;
82 addr
[3] = (val
>> 24) & 0xff;
85 #define BYTES2INT32(array,pos)\
86 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
87 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
89 int sansa_read_partinfo(struct sansa_t
* sansa
, int silent
)
94 count
= sansa_read(sansa
,sectorbuf
, sansa
->sector_size
);
97 print_error(" Error reading from disk: ");
101 if ((sectorbuf
[510] == 0x55) && (sectorbuf
[511] == 0xaa)) {
102 /* parse partitions */
103 for ( i
= 0; i
< 4; i
++ ) {
104 unsigned char* ptr
= sectorbuf
+ 0x1be + 16*i
;
105 sansa
->pinfo
[i
].type
= ptr
[4];
106 sansa
->pinfo
[i
].start
= BYTES2INT32(ptr
, 8);
107 sansa
->pinfo
[i
].size
= BYTES2INT32(ptr
, 12);
110 if ( sansa
->pinfo
[i
].type
== 5 ) {
111 /* not handled yet */
114 } else if ((sectorbuf
[0] == 'E') && (sectorbuf
[1] == 'R')) {
115 if (!silent
) fprintf(stderr
,"[ERR] Bad boot sector signature\n");
119 /* Calculate the starting position of the firmware partition */
120 sansa
->start
= (loff_t
)sansa
->pinfo
[1].start
*(loff_t
)sansa
->sector_size
;
126 * CRC32 implementation taken from:
128 * efone - Distributed internet phone system.
130 * (c) 1999,2000 Krzysztof Dabrowski
131 * (c) 1999,2000 ElysiuM deeZine
133 * This program is free software; you can redistribute it and/or
134 * modify it under the terms of the GNU General Public License
135 * as published by the Free Software Foundation; either version
136 * 2 of the License, or (at your option) any later version.
140 /* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
141 * so make sure, you call it before using the other
144 static unsigned int crc_tab
[256];
146 /* chksum_crc() -- to a given block, this one calculates the
147 * crc32-checksum until the length is
148 * reached. the crc32-checksum will be
151 static unsigned int chksum_crc32 (unsigned char *block
, unsigned int length
)
153 register unsigned long crc
;
157 for (i
= 0; i
< length
; i
++)
159 crc
= ((crc
>> 8) & 0x00FFFFFF) ^ crc_tab
[(crc
^ *block
++) & 0xFF];
164 /* chksum_crc32gentab() -- to a global crc_tab[256], this one will
165 * calculate the crcTable for crc32-checksums.
166 * it is generated to the polynom [..]
169 static void chksum_crc32gentab (void)
171 unsigned long crc
, poly
;
175 for (i
= 0; i
< 256; i
++)
178 for (j
= 8; j
> 0; j
--)
182 crc
= (crc
>> 1) ^ poly
;
193 /* Known keys for Sansa E200 firmwares: */
195 static uint32_t keys
[][4] = {
196 { 0xe494e96e, 0x3ee32966, 0x6f48512b, 0xa93fbb42 }, /* "sansa" */
197 { 0xd7b10538, 0xc662945b, 0x1b3fce68, 0xf389c0e6 }, /* "sansa_gh" */
202 tea_decrypt() from http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
204 "Following is an adaptation of the reference encryption and decryption
205 routines in C, released into the public domain by David Wheeler and
210 /* NOTE: The mi4 version of TEA uses a different initial value to sum compared
211 to the reference implementation and the main loop is 8 iterations, not
215 void tea_decrypt(uint32_t* v0
, uint32_t* v1
, uint32_t* k
) {
216 uint32_t sum
=0xF1BBCDC8, i
; /* set up */
217 uint32_t delta
=0x9E3779B9; /* a key schedule constant */
218 uint32_t k0
=k
[0], k1
=k
[1], k2
=k
[2], k3
=k
[3]; /* cache key */
219 for(i
=0; i
<8; i
++) { /* basic cycle start */
220 *v1
-= ((*v0
<<4) + k2
) ^ (*v0
+ sum
) ^ ((*v0
>>5) + k3
);
221 *v0
-= ((*v1
<<4) + k0
) ^ (*v1
+ sum
) ^ ((*v1
>>5) + k1
);
222 sum
-= delta
; /* end cycle */
226 /* mi4 files are encrypted in 64-bit blocks (two little-endian 32-bit
227 integers) and the key is incremented after each block
230 void tea_decrypt_buf(unsigned char* src
, unsigned char* dest
, size_t n
, uint32_t * key
)
235 for (i
= 0; i
< (n
/ 8); i
++) {
239 tea_decrypt(&v0
, &v1
, key
);
247 /* Now increment the key */
261 static int get_mi4header(unsigned char* buf
,struct mi4header_t
* mi4header
)
263 if (memcmp(buf
,"PPOS",4)!=0)
266 mi4header
->version
= le2int(buf
+0x04);
267 mi4header
->length
= le2int(buf
+0x08);
268 mi4header
->crc32
= le2int(buf
+0x0c);
269 mi4header
->enctype
= le2int(buf
+0x10);
270 mi4header
->mi4size
= le2int(buf
+0x14);
271 mi4header
->plaintext
= le2int(buf
+0x18);
276 static int set_mi4header(unsigned char* buf
,struct mi4header_t
* mi4header
)
278 if (memcmp(buf
,"PPOS",4)!=0)
281 int2le(mi4header
->version
,buf
+0x04);
282 int2le(mi4header
->length
,buf
+0x08);
283 int2le(mi4header
->crc32
,buf
+0x0c);
284 int2le(mi4header
->enctype
,buf
+0x10);
285 int2le(mi4header
->mi4size
,buf
+0x14);
286 int2le(mi4header
->plaintext
,buf
+0x18);
288 /* Add a dummy DSA signature */
289 memset(buf
+0x1c,0,40);
295 static int sansa_seek_and_read(struct sansa_t
* sansa
, loff_t pos
, unsigned char* buf
, int nbytes
)
299 if (sansa_seek(sansa
, pos
) < 0) {
303 if ((n
= sansa_read(sansa
,buf
,nbytes
)) < 0) {
308 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n",
317 /* We identify an E200 based on the following criteria:
319 1) Exactly two partitions;
320 2) First partition is type "W95 FAT32" (0x0b);
321 3) Second partition is type "OS/2 hidden C: drive" (0x84);
322 4) The "PPBL" string appears at offset 0 in the 2nd partition;
323 5) The "PPMI" string appears at offset PPMI_OFFSET in the 2nd partition.
326 int is_e200(struct sansa_t
* sansa
)
328 struct mi4header_t mi4header
;
331 /* Check partition layout */
333 if ((sansa
->pinfo
[0].type
!= 0x0b) || (sansa
->pinfo
[1].type
!= 0x84) ||
334 (sansa
->pinfo
[2].type
!= 0x00) || (sansa
->pinfo
[3].type
!= 0x00)) {
335 /* Bad partition layout, abort */
339 /* Check Bootloader header */
340 if (sansa_seek_and_read(sansa
, sansa
->start
, sectorbuf
, 0x200) < 0) {
343 if (memcmp(sectorbuf
,"PPBL",4)!=0) {
344 /* No bootloader header, abort */
348 /* Check Main firmware header */
349 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
, sectorbuf
, 0x200) < 0) {
350 fprintf(stderr
,"[ERR] Seek to 0x%08llx in is_e200 failed.\n",
351 sansa
->start
+PPMI_OFFSET
);
354 if (memcmp(sectorbuf
,"PPMI",4)!=0) {
355 /* No bootloader header, abort */
358 ppmi_length
= le2int(sectorbuf
+4);
360 /* Check main mi4 file header */
361 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
+0x200, sectorbuf
, 0x200) < 0) {
362 fprintf(stderr
,"[ERR] Seek to 0x%08llx in is_e200 failed.\n",
363 sansa
->start
+PPMI_OFFSET
+0x200);
367 if (get_mi4header(sectorbuf
,&mi4header
) < 0) {
368 fprintf(stderr
,"[ERR] Invalid mi4header\n");
372 /* Some sanity checks:
374 1) Main MI4 image without RBBL and < 100000 bytes -> old install
375 2) Main MI4 image with RBBL but no second image -> old install
378 sansa
->hasoldbootloader
= 0;
379 if (memcmp(sectorbuf
+0x1f8,"RBBL",4)==0) {
380 /* Look for an original firmware after the first image */
381 if (sansa_seek_and_read(sansa
,
382 sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
,
383 sectorbuf
, 512) < 0) {
387 if (get_mi4header(sectorbuf
,&mi4header
)!=0) {
388 fprintf(stderr
,"[ERR] No original firmware found\n");
389 sansa
->hasoldbootloader
= 1;
391 } else if (mi4header
.mi4size
< 100000) {
392 fprintf(stderr
,"[ERR] Old bootloader found\n");
393 sansa
->hasoldbootloader
= 1;
399 int sansa_scan(struct sansa_t
* sansa
)
403 char last_disk
[4096];
405 printf("[INFO] Scanning disk devices...\n");
407 for (i
= 0; i
<= 25 ; i
++) {
409 sprintf(sansa
->diskname
,"\\\\.\\PhysicalDrive%d",i
);
410 #elif defined(linux) || defined (__linux)
411 sprintf(sansa
->diskname
,"/dev/sd%c",'a'+i
);
412 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
413 || defined(__bsdi__) || defined(__DragonFly__)
414 sprintf(sansa
->diskname
,"/dev/da%d",i
);
415 #elif defined(__APPLE__) && defined(__MACH__)
416 sprintf(sansa
->diskname
,"/dev/disk%d",i
);
418 #error No disk paths defined for this platform
420 if (sansa_open(sansa
, 1) < 0) {
424 if (sansa_read_partinfo(sansa
,1) < 0) {
428 if (is_e200(sansa
) < 0) {
433 printf("[INFO] E200 found - disk device %d\n",i
);
435 printf("[INFO] E200 found - %s\n",sansa
->diskname
);
438 strcpy(last_disk
,sansa
->diskname
);
443 /* Remember the disk name */
444 strcpy(sansa
->diskname
,last_disk
);
449 /* Prepare original firmware for writing to the firmware partition by decrypting
450 and updating the header */
451 static int prepare_original_firmware(unsigned char* buf
, struct mi4header_t
* mi4header
)
453 unsigned char* tmpbuf
;
457 get_mi4header(buf
,mi4header
);
460 printf("mi4header->version =0x%08x\n",mi4header
->version
);
461 printf("mi4header->length =0x%08x\n",mi4header
->length
);
462 printf("mi4header->crc32 =0x%08x\n",mi4header
->crc32
);
463 printf("mi4header->enctype =0x%08x\n",mi4header
->enctype
);
464 printf("mi4header->mi4size =0x%08x\n",mi4header
->mi4size
);
465 printf("mi4header->plaintext =0x%08x\n",mi4header
->plaintext
);
468 /* Decrypt anything that needs decrypting. */
469 if (mi4header
->plaintext
< mi4header
->mi4size
- 0x200) {
470 /* TODO: Check different keys */
471 tmpbuf
=malloc(mi4header
->mi4size
-(mi4header
->plaintext
+0x200));
473 fprintf(stderr
,"[ERR] Can not allocate memory\n");
478 for (i
=0; i
< NUM_KEYS
&& !key_found
; i
++) {
479 tea_decrypt_buf(buf
+(mi4header
->plaintext
+0x200),
481 mi4header
->mi4size
-(mi4header
->plaintext
+0x200),
483 key_found
= (le2uint(tmpbuf
+mi4header
->length
-mi4header
->plaintext
-4) == 0xaa55aa55);
487 memcpy(buf
+(mi4header
->plaintext
+0x200),tmpbuf
,mi4header
->mi4size
-(mi4header
->plaintext
+0x200));
490 fprintf(stderr
,"[ERR] Failed to decrypt image, aborting\n");
496 /* Increase plaintext value to full file */
497 mi4header
->plaintext
= mi4header
->mi4size
- 0x200;
499 /* Update CRC checksum */
500 chksum_crc32gentab ();
501 mi4header
->crc32
= chksum_crc32(buf
+0x200,mi4header
->mi4size
-0x200);
503 set_mi4header(buf
,mi4header
);
505 /* Add Rockbox-specific header */
506 memcpy(buf
+0x1f8,"RBOFe200",8);
511 static int load_original_firmware(struct sansa_t
* sansa
, unsigned char* buf
, struct mi4header_t
* mi4header
)
516 /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */
517 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
, buf
, 512) < 0) {
521 /* No need to check PPMI magic - it's done during init to confirm
523 ppmi_length
= le2int(buf
+4);
525 /* Firstly look for an original firmware after the first image */
526 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
, buf
, 512) < 0) {
530 if (get_mi4header(buf
,mi4header
)==0) {
531 /* We have a valid MI4 file after a bootloader, so we use this. */
532 if ((n
= sansa_seek_and_read(sansa
,
533 sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
,
534 buf
, mi4header
->mi4size
)) < 0) {
538 /* No valid MI4 file, so read the first image. */
539 if ((n
= sansa_seek_and_read(sansa
,
540 sansa
->start
+ PPMI_OFFSET
+ 0x200,
541 buf
, ppmi_length
)) < 0) {
545 return prepare_original_firmware(buf
, mi4header
);
548 int sansa_read_firmware(struct sansa_t
* sansa
, char* filename
)
552 struct mi4header_t mi4header
;
554 res
= load_original_firmware(sansa
,sectorbuf
,&mi4header
);
558 outfile
= open(filename
,O_CREAT
|O_TRUNC
|O_WRONLY
|O_BINARY
,0666);
560 fprintf(stderr
,"[ERR] Couldn't open file %s\n",filename
);
564 res
= write(outfile
,sectorbuf
,mi4header
.mi4size
);
565 if (res
!= (int)mi4header
.mi4size
) {
566 fprintf(stderr
,"[ERR] Write error - %d\n", res
);
575 int sansa_add_bootloader(struct sansa_t
* sansa
, char* filename
, int type
)
578 int infile
= -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
579 int bl_length
= 0; /* Keep gcc happy when building for rbutil */
580 struct mi4header_t mi4header
;
584 if (type
==FILETYPE_MI4
) {
585 /* Step 1 - read bootloader into RAM. */
586 infile
=open(filename
,O_RDONLY
|O_BINARY
);
588 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
592 bl_length
= filesize(infile
);
595 bl_length
= LEN_bootimg
;
599 /* Create PPMI header */
600 memset(sectorbuf
,0,0x200);
601 memcpy(sectorbuf
,"PPMI",4);
602 int2le(bl_length
, sectorbuf
+4);
603 int2le(0x00020000, sectorbuf
+8);
605 if (type
==FILETYPE_MI4
) {
606 /* Read bootloader into sectorbuf+0x200 */
607 n
= read(infile
,sectorbuf
+0x200,bl_length
);
610 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n"
615 if (memcmp(sectorbuf
+0x200+0x1f8,"RBBL",4)!=0) {
616 fprintf(stderr
,"[ERR] %s is not a Rockbox bootloader, aborting.\n",
622 memcpy(sectorbuf
+0x200,bootimg
,LEN_bootimg
);
626 /* Load original firmware from Sansa to the space after the bootloader */
627 res
= load_original_firmware(sansa
,sectorbuf
+0x200+bl_length
,&mi4header
);
631 /* Now write the whole thing back to the Sansa */
633 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
) < 0) {
634 fprintf(stderr
,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
635 sansa
->start
+PPMI_OFFSET
);
639 length
= 0x200 + bl_length
+ mi4header
.mi4size
;
641 n
=sansa_write(sansa
, sectorbuf
, length
);
643 fprintf(stderr
,"[ERR] Short write in add_bootloader\n");
650 int sansa_delete_bootloader(struct sansa_t
* sansa
)
653 struct mi4header_t mi4header
;
657 /* Load original firmware from Sansa to sectorbuf+0x200 */
658 res
= load_original_firmware(sansa
,sectorbuf
+0x200,&mi4header
);
662 /* Create PPMI header */
663 memset(sectorbuf
,0,0x200);
664 memcpy(sectorbuf
,"PPMI",4);
665 int2le(mi4header
.mi4size
, sectorbuf
+4);
666 int2le(0x00020000, sectorbuf
+8);
668 /* Now write the whole thing back to the Sansa */
670 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
) < 0) {
671 fprintf(stderr
,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
672 sansa
->start
+PPMI_OFFSET
);
676 length
= 0x200 + mi4header
.mi4size
;
678 n
=sansa_write(sansa
, sectorbuf
, length
);
680 fprintf(stderr
,"[ERR] Short write in delete_bootloader\n");
687 void sansa_list_images(struct sansa_t
* sansa
)
689 struct mi4header_t mi4header
;
692 /* Check Main firmware header */
693 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
, sectorbuf
, 0x200) < 0) {
697 ppmi_length
= le2int(sectorbuf
+4);
699 printf("[INFO] Image 1 - %llu bytes\n",ppmi_length
);
701 /* Look for an original firmware after the first image */
702 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
, sectorbuf
, 512) < 0) {
706 if (get_mi4header(sectorbuf
,&mi4header
)==0) {
707 printf("[INFO] Image 2 - %d bytes\n",mi4header
.mi4size
);
711 int sansa_update_of(struct sansa_t
* sansa
, char* filename
)
714 int infile
= -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
715 int of_length
= 0; /* Keep gcc happy when building for rbutil */
717 struct mi4header_t mi4header
;
718 unsigned char buf
[512];
720 /* Step 1 - check we have an OF on the Sansa to upgrade. We expect the
721 Rockbox bootloader to be installed and the OF to be after it on disk. */
723 /* Read 512 bytes from PPMI_OFFSET - the PPMI header */
724 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
,
729 /* No need to check PPMI magic - it's done during init to confirm
731 ppmi_length
= le2int(buf
+4);
733 /* Look for an original firmware after the first image */
734 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
,
739 if (get_mi4header(buf
,&mi4header
)!=0) {
740 /* We don't have a valid MI4 file after a bootloader, so do nothing. */
741 fprintf(stderr
,"[ERR] No original firmware found at 0x%08llx\n",
742 sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
);
746 /* Step 2 - read OF into RAM. */
747 infile
=open(filename
,O_RDONLY
|O_BINARY
);
749 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
753 of_length
= filesize(infile
);
755 /* Load original firmware from file */
756 memset(sectorbuf
,0,0x200);
757 n
= read(infile
,sectorbuf
,of_length
);
760 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n"
765 /* Check we have a valid MI4 file. */
766 if (get_mi4header(sectorbuf
,&mi4header
)!=0) {
767 fprintf(stderr
,"[ERR] %s is not a valid mi4 file\n",filename
);
771 /* Decrypt and build the header */
772 if(prepare_original_firmware(sectorbuf
, &mi4header
)!=0){
773 fprintf(stderr
,"[ERR] Unable to build decrypted mi4 from %s\n"
778 /* Step 3 - write the OF to the Sansa */
779 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
) < 0) {
780 fprintf(stderr
,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
781 sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
);
785 n
=sansa_write(sansa
, sectorbuf
, of_length
);
787 fprintf(stderr
,"[ERR] Short write in sansa_update_of\n");