1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006-2007 Dave Chapman
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
28 #include <sys/types.h>
32 #include "sansapatcher.h"
34 /* The offset of the MI4 image header in the firmware partition */
35 #define PPMI_OFFSET 0x80000
36 #define NVPARAMS_OFFSET 0x780000
37 #define NVPARAMS_SIZE (0x80000-0x200)
39 int sansa_verbose
= 0;
41 /* Windows requires the buffer for disk I/O to be aligned in memory on a
42 multiple of the disk volume size - so we use a single global variable
43 and initialise it with sansa_alloc_buf() in main().
46 static off_t
filesize(int fd
) {
49 if (fstat(fd
,&buf
) < 0) {
50 perror("[ERR] Checking filesize of input file");
57 /* Partition table parsing code taken from Rockbox */
59 #define MAX_SECTOR_SIZE 2048
60 #define SECTOR_SIZE 512
62 static inline int32_t le2int(const unsigned char* buf
)
64 int32_t res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
69 static inline uint32_t le2uint(const unsigned char* buf
)
71 uint32_t res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
76 static inline void int2le(unsigned int val
, unsigned char* addr
)
79 addr
[1] = (val
>> 8) & 0xff;
80 addr
[2] = (val
>> 16) & 0xff;
81 addr
[3] = (val
>> 24) & 0xff;
84 #define BYTES2INT32(array,pos)\
85 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
86 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
88 int sansa_read_partinfo(struct sansa_t
* sansa
, int silent
)
93 count
= sansa_read(sansa
,sansa
->sectorbuf
, sansa
->sector_size
);
96 sansa_print_error(" Error reading from disk: ");
100 if ((sansa
->sectorbuf
[510] == 0x55) && (sansa
->sectorbuf
[511] == 0xaa)) {
101 /* parse partitions */
102 for ( i
= 0; i
< 4; i
++ ) {
103 unsigned char* ptr
= sansa
->sectorbuf
+ 0x1be + 16*i
;
104 sansa
->pinfo
[i
].type
= ptr
[4];
105 sansa
->pinfo
[i
].start
= BYTES2INT32(ptr
, 8);
106 sansa
->pinfo
[i
].size
= BYTES2INT32(ptr
, 12);
109 if ( sansa
->pinfo
[i
].type
== 5 ) {
110 /* not handled yet */
113 } else if ((sansa
->sectorbuf
[0] == 'E') && (sansa
->sectorbuf
[1] == 'R')) {
114 if (!silent
) fprintf(stderr
,"[ERR] Bad boot sector signature\n");
118 /* Calculate the starting position of the firmware partition */
119 sansa
->start
= (loff_t
)sansa
->pinfo
[1].start
*(loff_t
)sansa
->sector_size
;
123 /* NOTE: memmem implementation copied from glibc-2.2.4 - it's a GNU
124 extension and is not universally. In addition, early versions of
125 memmem had a serious bug - the meaning of needle and haystack were
128 /* Copyright (C) 1991,92,93,94,96,97,98,2000 Free Software Foundation, Inc.
129 This file is part of the GNU C Library.
131 The GNU C Library is free software; you can redistribute it and/or
132 modify it under the terms of the GNU Lesser General Public
133 License as published by the Free Software Foundation; either
134 version 2.1 of the License, or (at your option) any later version.
136 The GNU C Library is distributed in the hope that it will be useful,
137 but WITHOUT ANY WARRANTY; without even the implied warranty of
138 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
139 Lesser General Public License for more details.
141 You should have received a copy of the GNU Lesser General Public
142 License along with the GNU C Library; if not, write to the Free
143 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
146 /* Return the first occurrence of NEEDLE in HAYSTACK. */
148 sansa_memmem (haystack
, haystack_len
, needle
, needle_len
)
149 const void *haystack
;
155 const char *const last_possible
156 = (const char *) haystack
+ haystack_len
- needle_len
;
159 /* The first occurrence of the empty string is deemed to occur at
160 the beginning of the string. */
161 return (void *) haystack
;
163 /* Sanity check, otherwise the loop might search through the whole
165 if (__builtin_expect (haystack_len
< needle_len
, 0))
168 for (begin
= (const char *) haystack
; begin
<= last_possible
; ++begin
)
169 if (begin
[0] == ((const char *) needle
)[0] &&
170 !memcmp ((const void *) &begin
[1],
171 (const void *) ((const char *) needle
+ 1),
173 return (void *) begin
;
179 * CRC32 implementation taken from:
181 * efone - Distributed internet phone system.
183 * (c) 1999,2000 Krzysztof Dabrowski
184 * (c) 1999,2000 ElysiuM deeZine
186 * This program is free software; you can redistribute it and/or
187 * modify it under the terms of the GNU General Public License
188 * as published by the Free Software Foundation; either version
189 * 2 of the License, or (at your option) any later version.
193 /* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
194 * so make sure, you call it before using the other
197 static unsigned int crc_tab
[256];
199 /* chksum_crc() -- to a given block, this one calculates the
200 * crc32-checksum until the length is
201 * reached. the crc32-checksum will be
204 static unsigned int chksum_crc32 (const unsigned char *block
, unsigned int length
)
206 register unsigned long crc
;
210 for (i
= 0; i
< length
; i
++)
212 crc
= ((crc
>> 8) & 0x00FFFFFF) ^ crc_tab
[(crc
^ *block
++) & 0xFF];
217 /* chksum_crc32gentab() -- to a global crc_tab[256], this one will
218 * calculate the crcTable for crc32-checksums.
219 * it is generated to the polynom [..]
222 static void chksum_crc32gentab (void)
224 unsigned long crc
, poly
;
228 for (i
= 0; i
< 256; i
++)
231 for (j
= 8; j
> 0; j
--)
235 crc
= (crc
>> 1) ^ poly
;
246 /* Known keys for Sansa E200 and C200 firmwares: */
247 #define NUM_KEYS ((int)(sizeof(keys)/sizeof(keys[0])))
248 static const uint32_t keys
[][4] = {
249 { 0xe494e96e, 0x3ee32966, 0x6f48512b, 0xa93fbb42 }, /* "sansa" */
250 { 0xd7b10538, 0xc662945b, 0x1b3fce68, 0xf389c0e6 }, /* "sansa_gh" */
251 { 0x1d29ddc0, 0x2579c2cd, 0xce339e1a, 0x75465dfe }, /* sansa 103 */
253 { 0x2a7968de, 0x15127979, 0x142e60a7, 0xe49c1893 }, /* c200 1.00.03 */
254 { 0xbf2d06fa, 0xf0e23d59, 0x29738132, 0xe2d04ca7 }, /* c200 1.00.04 and up*/
255 { 0xa913d139, 0xf842f398, 0x3e03f1a6, 0x060ee012 }, /* c200 1.01.05 and up*/
256 { 0x0fe92902, 0xe8cc0f89, 0x6ff568ba, 0x1eff5161 }, /* c200 1.01.07 */
261 tea_decrypt() from http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
263 "Following is an adaptation of the reference encryption and decryption
264 routines in C, released into the public domain by David Wheeler and
269 /* NOTE: The mi4 version of TEA uses a different initial value to sum compared
270 to the reference implementation and the main loop is 8 iterations, not
274 static void tea_decrypt(uint32_t* v0
, uint32_t* v1
, const uint32_t* k
) {
275 uint32_t sum
=0xF1BBCDC8, i
; /* set up */
276 uint32_t delta
=0x9E3779B9; /* a key schedule constant */
277 uint32_t k0
=k
[0], k1
=k
[1], k2
=k
[2], k3
=k
[3]; /* cache key */
278 for(i
=0; i
<8; i
++) { /* basic cycle start */
279 *v1
-= ((*v0
<<4) + k2
) ^ (*v0
+ sum
) ^ ((*v0
>>5) + k3
);
280 *v0
-= ((*v1
<<4) + k0
) ^ (*v1
+ sum
) ^ ((*v1
>>5) + k1
);
281 sum
-= delta
; /* end cycle */
285 /* mi4 files are encrypted in 64-bit blocks (two little-endian 32-bit
286 integers) and the key is incremented after each block
289 static void tea_decrypt_buf(const unsigned char* src
, unsigned char* dest
,
290 size_t n
, const uint32_t * initial_key
)
296 memcpy(key
, initial_key
, sizeof(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(const 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
,const 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 */
395 if (((sansa
->pinfo
[0].type
!= 0x06) &&
396 (sansa
->pinfo
[0].type
!= 0x0b) &&
397 (sansa
->pinfo
[0].type
!= 0x0c) &&
398 (sansa
->pinfo
[0].type
!= 0x0e)) ||
399 (sansa
->pinfo
[1].type
!= 0x84) ||
400 (sansa
->pinfo
[2].type
!= 0x00) ||
401 (sansa
->pinfo
[3].type
!= 0x00)) {
402 /* Bad partition layout, abort */
406 /* Check Bootloader header */
407 if (sansa_seek_and_read(sansa
, sansa
->start
, sansa
->sectorbuf
, 0x200) < 0) {
410 if (memcmp(sansa
->sectorbuf
,"PPBL",4)!=0) {
411 /* No bootloader header, abort */
414 ppbl_length
= (le2int(sansa
->sectorbuf
+4) + 0x1ff) & ~0x1ff;
416 /* Sanity/safety check - the bootloader can't be larger than PPMI_OFFSET */
417 if (ppbl_length
> PPMI_OFFSET
)
422 /* Load Sansa bootloader and check for "Sansa C200" magic string */
423 if (sansa_seek_and_read(sansa
, sansa
->start
+ 0x200, sansa
->sectorbuf
, ppbl_length
) < 0) {
424 fprintf(stderr
,"[ERR] Seek and read to 0x%08"PRIx64
" in is_sansa failed.\n",
428 if (sansa_memmem(sansa
->sectorbuf
, ppbl_length
, "Sansa C200", 10) != NULL
) {
430 sansa
->targetname
="c200";
433 sansa
->targetname
="e200";
436 /* Check Main firmware header */
437 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
, sansa
->sectorbuf
, 0x200) < 0) {
438 fprintf(stderr
,"[ERR] Seek to 0x%"PRIx64
" in is_sansa failed.\n",
439 sansa
->start
+PPMI_OFFSET
);
442 if (memcmp(sansa
->sectorbuf
,"PPMI",4)!=0) {
443 /* No bootloader header, abort */
446 ppmi_length
= le2int(sansa
->sectorbuf
+4);
448 /* Check main mi4 file header */
449 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
+0x200, sansa
->sectorbuf
, 0x200) < 0) {
450 fprintf(stderr
,"[ERR] Seek to 0x%"PRIx64
" in is_sansa failed.\n",
451 sansa
->start
+PPMI_OFFSET
+0x200);
455 if (get_mi4header(sansa
->sectorbuf
,&mi4header
) < 0) {
456 fprintf(stderr
,"[ERR] Invalid mi4header\n");
460 /* Some sanity checks:
462 1) Main MI4 image without RBBL and < 100000 bytes -> old install
463 2) Main MI4 image with RBBL but no second image -> old install
466 sansa
->hasoldbootloader
= 0;
467 if (memcmp(sansa
->sectorbuf
+0x1f8,"RBBL",4)==0) {
468 /* Look for an original firmware after the first image */
469 if (sansa_seek_and_read(sansa
,
470 sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
,
471 sansa
->sectorbuf
, 512) < 0) {
475 if (get_mi4header(sansa
->sectorbuf
,&mi4header
)!=0) {
476 fprintf(stderr
,"[ERR] No original firmware found\n");
477 sansa
->hasoldbootloader
= 1;
479 } else if (mi4header
.mi4size
< 100000) {
480 fprintf(stderr
,"[ERR] Old bootloader found\n");
481 sansa
->hasoldbootloader
= 1;
487 int sansa_scan(struct sansa_t
* sansa
)
491 char last_disk
[4096];
495 printf("[INFO] Scanning disk devices...\n");
497 for (i
= 0; i
<= 25 ; i
++) {
499 sprintf(sansa
->diskname
,"\\\\.\\PhysicalDrive%d",i
);
500 #elif defined(linux) || defined (__linux)
501 sprintf(sansa
->diskname
,"/dev/sd%c",'a'+i
);
502 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
503 || defined(__bsdi__) || defined(__DragonFly__)
504 sprintf(sansa
->diskname
,"/dev/da%d",i
);
505 #elif defined(__APPLE__) && defined(__MACH__)
506 sprintf(sansa
->diskname
,"/dev/disk%d",i
);
508 #error No disk paths defined for this platform
510 if ((result
= sansa_open(sansa
, 1)) < 0) {
518 if (sansa_read_partinfo(sansa
,1) < 0) {
523 if (is_sansa(sansa
) < 0) {
529 printf("[INFO] %s found - disk device %d\n",sansa
->targetname
, i
);
531 printf("[INFO] %s found - %s\n",sansa
->targetname
, sansa
->diskname
);
534 strcpy(last_disk
,sansa
->diskname
);
539 /* Remember the disk name */
540 strcpy(sansa
->diskname
,last_disk
);
542 else if (n
== 0 && denied
) {
543 printf("[ERR] FATAL: Permission denied on %d device(s) and no sansa detected.\n", denied
);
545 printf("[ERR] You need to run this program with administrator priviledges!\n");
547 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
551 return (n
== 0 && denied
) ? -1 : n
;
554 /* Prepare original firmware for writing to the firmware partition by decrypting
555 and updating the header */
556 static int prepare_original_firmware(struct sansa_t
* sansa
, unsigned char* buf
, struct mi4header_t
* mi4header
)
558 unsigned char* tmpbuf
;
562 get_mi4header(buf
,mi4header
);
565 printf("mi4header->version =0x%08x\n",mi4header
->version
);
566 printf("mi4header->length =0x%08x\n",mi4header
->length
);
567 printf("mi4header->crc32 =0x%08x\n",mi4header
->crc32
);
568 printf("mi4header->enctype =0x%08x\n",mi4header
->enctype
);
569 printf("mi4header->mi4size =0x%08x\n",mi4header
->mi4size
);
570 printf("mi4header->plaintext =0x%08x\n",mi4header
->plaintext
);
573 /* Decrypt anything that needs decrypting. */
574 if (mi4header
->plaintext
< mi4header
->mi4size
- 0x200) {
575 /* TODO: Check different keys */
576 tmpbuf
=malloc(mi4header
->mi4size
-(mi4header
->plaintext
+0x200));
578 fprintf(stderr
,"[ERR] Can not allocate memory\n");
583 for (i
=0; i
< NUM_KEYS
&& !key_found
; i
++) {
584 tea_decrypt_buf(buf
+(mi4header
->plaintext
+0x200),
586 mi4header
->mi4size
-(mi4header
->plaintext
+0x200),
588 key_found
= (le2uint(tmpbuf
+mi4header
->length
-mi4header
->plaintext
-4) == 0xaa55aa55);
592 memcpy(buf
+(mi4header
->plaintext
+0x200),tmpbuf
,mi4header
->mi4size
-(mi4header
->plaintext
+0x200));
595 fprintf(stderr
,"[ERR] Failed to decrypt image, aborting\n");
601 /* Increase plaintext value to full file */
602 mi4header
->plaintext
= mi4header
->mi4size
- 0x200;
604 /* Update CRC checksum */
605 chksum_crc32gentab ();
606 mi4header
->crc32
= chksum_crc32(buf
+0x200,mi4header
->mi4size
-0x200);
608 set_mi4header(buf
,mi4header
);
610 /* Add Rockbox-specific header */
611 memcpy(buf
+0x1f8,"RBOF",4);
612 memcpy(buf
+0x1fc,sansa
->targetname
,4);
617 static int load_original_firmware(struct sansa_t
* sansa
, unsigned char* buf
, struct mi4header_t
* mi4header
)
622 /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */
623 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
, buf
, 512) < 0) {
627 /* No need to check PPMI magic - it's done during init to confirm
629 ppmi_length
= le2int(buf
+4);
631 /* Firstly look for an original firmware after the first image */
632 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
, buf
, 512) < 0) {
636 if (get_mi4header(buf
,mi4header
)==0) {
637 /* We have a valid MI4 file after a bootloader, so we use this. */
638 if ((n
= sansa_seek_and_read(sansa
,
639 sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
,
640 buf
, mi4header
->mi4size
)) < 0) {
644 /* No valid MI4 file, so read the first image. */
645 if ((n
= sansa_seek_and_read(sansa
,
646 sansa
->start
+ PPMI_OFFSET
+ 0x200,
647 buf
, ppmi_length
)) < 0) {
651 return prepare_original_firmware(sansa
, buf
, mi4header
);
654 int sansa_read_firmware(struct sansa_t
* sansa
, const char* filename
)
658 struct mi4header_t mi4header
;
660 res
= load_original_firmware(sansa
,sansa
->sectorbuf
,&mi4header
);
664 outfile
= open(filename
,O_CREAT
|O_TRUNC
|O_WRONLY
|O_BINARY
,0666);
666 fprintf(stderr
,"[ERR] Couldn't open file %s\n",filename
);
670 res
= write(outfile
,sansa
->sectorbuf
,mi4header
.mi4size
);
671 if (res
!= (int)mi4header
.mi4size
) {
672 fprintf(stderr
,"[ERR] Write error - %d\n", res
);
680 unsigned int sansa_read_bootloader(struct sansa_t
* sansa
, const char* filename
, unsigned char** bl_buffer
)
682 /* Step 1 - read bootloader into RAM. */
686 infile
=open(filename
,O_RDONLY
|O_BINARY
);
688 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
692 len
= filesize(infile
);
694 unsigned char* b
= malloc(len
);
696 fprintf(stderr
,"[ERR] Could not allocate memory for bootloader\n");
701 n
= read(infile
,b
,len
);
704 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n"
709 if (memcmp(b
+0x1f8,"RBBL",4)!=0) {
710 fprintf(stderr
,"[ERR] %s is not a Rockbox bootloader, aborting.\n",
714 if (memcmp(b
+0x1fc,sansa
->targetname
,4)!=0) {
715 fprintf(stderr
,"[ERR] %s is not a Rockbox bootloader for %s, aborting.\n",
716 filename
, sansa
->targetname
);
723 int sansa_add_bootloader(struct sansa_t
* sansa
, const unsigned char* bootloader
, const unsigned int bl_length
)
726 struct mi4header_t mi4header
;
730 /* Create PPMI header */
731 memset(sansa
->sectorbuf
,0,0x200);
732 memcpy(sansa
->sectorbuf
,"PPMI",4);
733 int2le(bl_length
, sansa
->sectorbuf
+4);
734 int2le(0x00020000, sansa
->sectorbuf
+8);
736 /* copy bootloader to sansa->sectorbuf+0x200 */
737 memcpy(sansa
->sectorbuf
+0x200,bootloader
,bl_length
);
739 /* Load original firmware from Sansa to the space after the bootloader */
740 res
= load_original_firmware(sansa
,sansa
->sectorbuf
+0x200+bl_length
,&mi4header
);
744 /* Now write the whole thing back to the Sansa */
746 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
) < 0) {
747 fprintf(stderr
,"[ERR] Seek to 0x%08"PRIx64
" in add_bootloader failed.\n",
748 sansa
->start
+PPMI_OFFSET
);
752 length
= 0x200 + bl_length
+ mi4header
.mi4size
;
754 n
=sansa_write(sansa
, length
);
756 fprintf(stderr
,"[ERR] Short write in add_bootloader\n");
763 int sansa_delete_bootloader(struct sansa_t
* sansa
)
766 struct mi4header_t mi4header
;
770 /* Load original firmware from Sansa to sansa->sectorbuf+0x200 */
771 res
= load_original_firmware(sansa
,sansa
->sectorbuf
+0x200,&mi4header
);
775 /* Create PPMI header */
776 memset(sansa
->sectorbuf
,0,0x200);
777 memcpy(sansa
->sectorbuf
,"PPMI",4);
778 int2le(mi4header
.mi4size
, sansa
->sectorbuf
+4);
779 int2le(0x00020000, sansa
->sectorbuf
+8);
781 /* Now write the whole thing back to the Sansa */
783 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
) < 0) {
784 fprintf(stderr
,"[ERR] Seek to 0x%08"PRIx64
" in add_bootloader failed.\n",
785 sansa
->start
+PPMI_OFFSET
);
789 length
= 0x200 + mi4header
.mi4size
;
791 n
=sansa_write(sansa
, length
);
793 fprintf(stderr
,"[ERR] Short write in delete_bootloader\n");
800 /** List number of MI4 images on the player, return number.
802 int sansa_list_images(struct sansa_t
* sansa
)
804 struct mi4header_t mi4header
;
808 /* Check Main firmware header */
809 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
, sansa
->sectorbuf
, 0x200) < 0) {
813 ppmi_length
= le2int(sansa
->sectorbuf
+4);
815 printf("[INFO] Image 1 - %"PRIu64
" bytes\n",ppmi_length
);
818 /* Look for an original firmware after the first image */
819 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
+ 0x200 + ppmi_length
, sansa
->sectorbuf
, 512) < 0) {
823 if (get_mi4header(sansa
->sectorbuf
,&mi4header
)==0) {
824 printf("[INFO] Image 2 - %d bytes\n",mi4header
.mi4size
);
830 int sansa_update_of(struct sansa_t
* sansa
, const char* filename
)
833 int infile
= -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
834 int of_length
= 0; /* Keep gcc happy when building for rbutil */
836 struct mi4header_t mi4header
;
837 unsigned char buf
[512];
839 /* Step 1 - check we have an OF on the Sansa to upgrade. We expect the
840 Rockbox bootloader to be installed and the OF to be after it on disk. */
842 /* Read 512 bytes from PPMI_OFFSET - the PPMI header */
843 if (sansa_seek_and_read(sansa
, sansa
->start
+ PPMI_OFFSET
,
848 /* No need to check PPMI magic - it's done during init to confirm
850 ppmi_length
= le2int(buf
+4);
852 /* Look for an original firmware after the first image */
853 if (sansa_seek_and_read(sansa
, sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
,
858 if (get_mi4header(buf
,&mi4header
)!=0) {
859 /* We don't have a valid MI4 file after a bootloader, so do nothing. */
860 fprintf(stderr
,"[ERR] No original firmware found at 0x%08"PRIx64
"\n",
861 sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
);
865 /* Step 2 - read OF into RAM. */
866 infile
=open(filename
,O_RDONLY
|O_BINARY
);
868 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
872 of_length
= filesize(infile
);
874 /* Load original firmware from file */
875 memset(sansa
->sectorbuf
,0,0x200);
876 n
= read(infile
,sansa
->sectorbuf
,of_length
);
879 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n"
884 /* Check we have a valid MI4 file. */
885 if (get_mi4header(sansa
->sectorbuf
,&mi4header
)!=0) {
886 fprintf(stderr
,"[ERR] %s is not a valid mi4 file\n",filename
);
890 /* Decrypt and build the header */
891 if(prepare_original_firmware(sansa
, sansa
->sectorbuf
, &mi4header
)!=0){
892 fprintf(stderr
,"[ERR] Unable to build decrypted mi4 from %s\n"
897 /* Step 3 - write the OF to the Sansa */
898 if (sansa_seek(sansa
, sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
) < 0) {
899 fprintf(stderr
,"[ERR] Seek to 0x%08"PRIx64
" in sansa_update_of failed.\n",
900 sansa
->start
+PPMI_OFFSET
+0x200+ppmi_length
);
904 n
=sansa_write(sansa
, of_length
);
906 fprintf(stderr
,"[ERR] Short write in sansa_update_of\n");
910 /* Step 4 - zero out the nvparams section - we have to do this or we end up
911 with multiple copies of the nvparams data and don't know which one to
912 work with for the database rebuild disabling trick in our bootloader */
913 if (strcmp(sansa
->targetname
,"e200") == 0) {
914 printf("[INFO] Resetting Original Firmware settings\n");
915 if (sansa_seek(sansa
, sansa
->start
+NVPARAMS_OFFSET
+0x200) < 0) {
916 fprintf(stderr
,"[ERR] Seek to 0x%08"PRIx64
" in sansa_update_of failed.\n",
917 sansa
->start
+NVPARAMS_OFFSET
+0x200);
921 memset(sansa
->sectorbuf
,0,NVPARAMS_SIZE
);
922 n
=sansa_write(sansa
, NVPARAMS_SIZE
);
923 if (n
< NVPARAMS_SIZE
) {
924 fprintf(stderr
,"[ERR] Short write in sansa_update_of\n");
932 /* Update the PPBL (bootloader) image in the hidden firmware partition */
933 int sansa_update_ppbl(struct sansa_t
* sansa
, const char* filename
)
936 int infile
= -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
937 int ppbl_length
= 0; /* Keep gcc happy when building for rbutil */
939 /* Step 1 - read bootloader into RAM. */
940 infile
=open(filename
,O_RDONLY
|O_BINARY
);
942 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
946 ppbl_length
= filesize(infile
);
948 n
= read(infile
,sansa
->sectorbuf
+0x200,ppbl_length
);
950 if (n
< ppbl_length
) {
951 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n", ppbl_length
, n
);
955 /* Step 2 - Build the header */
956 memset(sansa
->sectorbuf
,0,0x200);
957 memcpy(sansa
->sectorbuf
,"PPBL",4);
958 int2le(ppbl_length
, sansa
->sectorbuf
+4);
959 int2le(0x00010000, sansa
->sectorbuf
+8);
961 /* Step 3 - write the bootloader to the Sansa */
962 if (sansa_seek(sansa
, sansa
->start
) < 0) {
963 fprintf(stderr
,"[ERR] Seek to 0x%08"PRIx64
" in sansa_update_ppbl failed.\n", sansa
->start
);
967 n
=sansa_write(sansa
, ppbl_length
+ 0x200);
968 if (n
< (ppbl_length
+0x200)) {
969 fprintf(stderr
,"[ERR] Short write in sansa_update_ppbl\n");