Add a note about Rockbox not running on Sansas v2 (FS#8477 by Marc Guay).
[Rockbox.git] / rbutil / sansapatcher / sansapatcher.c
blobbc0310893085c98bbe9401ffe5dc2e30012497f2
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <inttypes.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
29 #include "sansaio.h"
30 #include "sansapatcher.h"
32 #ifndef RBUTIL
33 #include "bootimg_c200.h"
34 #include "bootimg_e200.h"
35 #endif
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)
41 extern int verbose;
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) {
51 struct stat buf;
53 if (fstat(fd,&buf) < 0) {
54 perror("[ERR] Checking filesize of input file");
55 return -1;
56 } else {
57 return(buf.st_size);
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];
70 return res;
73 static inline uint32_t le2uint(unsigned char* buf)
75 uint32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
77 return res;
80 static inline void int2le(unsigned int val, unsigned char* addr)
82 addr[0] = val & 0xFF;
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)
94 int i;
95 unsigned long count;
97 count = sansa_read(sansa,sectorbuf, sansa->sector_size);
99 if (count <= 0) {
100 print_error(" Error reading from disk: ");
101 return -1;
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);
112 /* extended? */
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");
119 return -1;
122 /* Calculate the starting position of the firmware partition */
123 sansa->start = (loff_t)sansa->pinfo[1].start*(loff_t)sansa->sector_size;
124 return 0;
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
130 reversed. */
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
148 02111-1307 USA. */
150 /* Return the first occurrence of NEEDLE in HAYSTACK. */
151 static void *
152 sansa_memmem (haystack, haystack_len, needle, needle_len)
153 const void *haystack;
154 size_t haystack_len;
155 const void *needle;
156 size_t needle_len;
158 const char *begin;
159 const char *const last_possible
160 = (const char *) haystack + haystack_len - needle_len;
162 if (needle_len == 0)
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
168 memory. */
169 if (__builtin_expect (haystack_len < needle_len, 0))
170 return NULL;
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),
176 needle_len - 1))
177 return (void *) begin;
179 return NULL;
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
199 * functions!
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
206 * the result.
208 static unsigned int chksum_crc32 (unsigned char *block, unsigned int length)
210 register unsigned long crc;
211 unsigned long i;
213 crc = 0;
214 for (i = 0; i < length; i++)
216 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
218 return (crc);
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;
229 int i, j;
231 poly = 0xEDB88320L;
232 for (i = 0; i < 256; i++)
234 crc = i;
235 for (j = 8; j > 0; j--)
237 if (crc & 1)
239 crc = (crc >> 1) ^ poly;
241 else
243 crc >>= 1;
246 crc_tab[i] = crc;
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
268 Roger Needham:"
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)
294 uint32_t v0, v1;
295 unsigned int i;
297 for (i = 0; i < (n / 8); i++) {
298 v0 = le2int(src);
299 v1 = le2int(src+4);
301 tea_decrypt(&v0, &v1, key);
303 int2le(v0, dest);
304 int2le(v1, dest+4);
306 src += 8;
307 dest += 8;
309 /* Now increment the key */
310 key[0]++;
311 if (key[0]==0) {
312 key[1]++;
313 if (key[1]==0) {
314 key[2]++;
315 if (key[2]==0) {
316 key[3]++;
323 static int get_mi4header(unsigned char* buf,struct mi4header_t* mi4header)
325 if (memcmp(buf,"PPOS",4)!=0)
326 return -1;
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);
335 return 0;
338 static int set_mi4header(unsigned char* buf,struct mi4header_t* mi4header)
340 if (memcmp(buf,"PPOS",4)!=0)
341 return -1;
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);
352 buf[0x2f] = 1;
354 return 0;
357 static int sansa_seek_and_read(struct sansa_t* sansa, loff_t pos, unsigned char* buf, int nbytes)
359 int n;
361 if (sansa_seek(sansa, pos) < 0) {
362 return -1;
365 if ((n = sansa_read(sansa,buf,nbytes)) < 0) {
366 return -1;
369 if (n < nbytes) {
370 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
371 nbytes,n);
372 return -1;
375 return 0;
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;
391 int ppmi_length;
392 int ppbl_length;
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 */
404 return -1;
407 /* Check Bootloader header */
408 if (sansa_seek_and_read(sansa, sansa->start, sectorbuf, 0x200) < 0) {
409 return -2;
411 if (memcmp(sectorbuf,"PPBL",4)!=0) {
412 /* No bootloader header, abort */
413 return -4;
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)
420 return -5;
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",
426 sansa->start+0x200);
427 return -6;
429 if (sansa_memmem(sectorbuf, ppbl_length, "Sansa C200", 10) != NULL) {
430 /* C200 */
431 sansa->targetname="c200";
432 } else {
433 /* E200 */
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);
441 return -5;
443 if (memcmp(sectorbuf,"PPMI",4)!=0) {
444 /* No bootloader header, abort */
445 return -7;
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);
453 return -5;
456 if (get_mi4header(sectorbuf,&mi4header) < 0) {
457 fprintf(stderr,"[ERR] Invalid mi4header\n");
458 return -6;
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) {
473 return -7;
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;
485 return 0;
488 int sansa_scan(struct sansa_t* sansa)
490 int i;
491 int n = 0;
492 char last_disk[4096];
494 printf("[INFO] Scanning disk devices...\n");
496 for (i = 0; i <= 25 ; i++) {
497 #ifdef __WIN32__
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);
506 #else
507 #error No disk paths defined for this platform
508 #endif
509 if (sansa_open(sansa, 1) < 0) {
510 continue;
513 if (sansa_read_partinfo(sansa,1) < 0) {
514 continue;
517 if (is_sansa(sansa) < 0) {
518 continue;
521 #ifdef __WIN32__
522 printf("[INFO] %s found - disk device %d\n",sansa->targetname, i);
523 #else
524 printf("[INFO] %s found - %s\n",sansa->targetname, sansa->diskname);
525 #endif
526 n++;
527 strcpy(last_disk,sansa->diskname);
528 sansa_close(sansa);
531 if (n==1) {
532 /* Remember the disk name */
533 strcpy(sansa->diskname,last_disk);
535 return n;
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;
543 int i;
544 int key_found;
546 get_mi4header(buf,mi4header);
548 #if 0
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);
555 #endif
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));
561 if (tmpbuf==NULL) {
562 fprintf(stderr,"[ERR] Can not allocate memory\n");
563 return -1;
566 key_found=0;
567 for (i=0; i < NUM_KEYS && !key_found ; i++) {
568 tea_decrypt_buf(buf+(mi4header->plaintext+0x200),
569 tmpbuf,
570 mi4header->mi4size-(mi4header->plaintext+0x200),
571 keys[i]);
572 key_found = (le2uint(tmpbuf+mi4header->length-mi4header->plaintext-4) == 0xaa55aa55);
575 if (key_found) {
576 memcpy(buf+(mi4header->plaintext+0x200),tmpbuf,mi4header->mi4size-(mi4header->plaintext+0x200));
577 free(tmpbuf);
578 } else {
579 fprintf(stderr,"[ERR] Failed to decrypt image, aborting\n");
580 free(tmpbuf);
581 return -1;
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);
597 return 0;
600 static int load_original_firmware(struct sansa_t* sansa, unsigned char* buf, struct mi4header_t* mi4header)
602 int ppmi_length;
603 int n;
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) {
607 return -1;
610 /* No need to check PPMI magic - it's done during init to confirm
611 this is an E200 */
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) {
616 return -1;
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) {
624 return -1;
626 } else {
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) {
631 return -1;
634 return prepare_original_firmware(buf, mi4header);
637 int sansa_read_firmware(struct sansa_t* sansa, char* filename)
639 int res;
640 int outfile;
641 struct mi4header_t mi4header;
643 res = load_original_firmware(sansa,sectorbuf,&mi4header);
644 if (res < 0)
645 return res;
647 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
648 if (outfile < 0) {
649 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
650 return -1;
653 res = write(outfile,sectorbuf,mi4header.mi4size);
654 if (res != (int)mi4header.mi4size) {
655 fprintf(stderr,"[ERR] Write error - %d\n", res);
656 return -1;
658 close(outfile);
660 return 0;
664 int sansa_add_bootloader(struct sansa_t* sansa, char* filename, int type)
666 int res;
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;
670 int n;
671 int length;
673 if (type==FILETYPE_MI4) {
674 /* Step 1 - read bootloader into RAM. */
675 infile=open(filename,O_RDONLY|O_BINARY);
676 if (infile < 0) {
677 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
678 return -1;
681 bl_length = filesize(infile);
682 } else {
683 #ifndef RBUTIL
684 if (strcmp(sansa->targetname,"c200") == 0) {
685 bl_length = LEN_bootimg_c200;
686 } else {
687 bl_length = LEN_bootimg_e200;
689 #endif
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);
701 close(infile);
702 if (n < bl_length) {
703 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
704 ,bl_length,n);
705 return -1;
708 if (memcmp(sectorbuf+0x200+0x1f8,"RBBL",4)!=0) {
709 fprintf(stderr,"[ERR] %s is not a Rockbox bootloader, aborting.\n",
710 filename);
711 return -1;
713 } else {
714 #ifndef RBUTIL
715 if (strcmp(sansa->targetname,"c200") == 0) {
716 memcpy(sectorbuf+0x200,bootimg_c200,LEN_bootimg_c200);
717 } else {
718 memcpy(sectorbuf+0x200,bootimg_e200,LEN_bootimg_e200);
720 #endif
723 /* Load original firmware from Sansa to the space after the bootloader */
724 res = load_original_firmware(sansa,sectorbuf+0x200+bl_length,&mi4header);
725 if (res < 0)
726 return res;
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);
733 return -5;
736 length = 0x200 + bl_length + mi4header.mi4size;
738 n=sansa_write(sansa, sectorbuf, length);
739 if (n < length) {
740 fprintf(stderr,"[ERR] Short write in add_bootloader\n");
741 return -6;
744 return 0;
747 int sansa_delete_bootloader(struct sansa_t* sansa)
749 int res;
750 struct mi4header_t mi4header;
751 int n;
752 int length;
754 /* Load original firmware from Sansa to sectorbuf+0x200 */
755 res = load_original_firmware(sansa,sectorbuf+0x200,&mi4header);
756 if (res < 0)
757 return res;
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);
770 return -5;
773 length = 0x200 + mi4header.mi4size;
775 n=sansa_write(sansa, sectorbuf, length);
776 if (n < length) {
777 fprintf(stderr,"[ERR] Short write in delete_bootloader\n");
778 return -6;
781 return 0;
784 void sansa_list_images(struct sansa_t* sansa)
786 struct mi4header_t mi4header;
787 loff_t ppmi_length;
789 /* Check Main firmware header */
790 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sectorbuf, 0x200) < 0) {
791 return;
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) {
800 return;
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)
810 int n;
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 */
813 int ppmi_length;
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,
822 buf, 512) < 0) {
823 return -1;
826 /* No need to check PPMI magic - it's done during init to confirm
827 this is an E200 */
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,
832 buf, 512) < 0) {
833 return -1;
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);
840 return -1;
843 /* Step 2 - read OF into RAM. */
844 infile=open(filename,O_RDONLY|O_BINARY);
845 if (infile < 0) {
846 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
847 return -1;
850 of_length = filesize(infile);
852 /* Load original firmware from file */
853 memset(sectorbuf,0,0x200);
854 n = read(infile,sectorbuf,of_length);
855 close(infile);
856 if (n < of_length) {
857 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
858 , of_length, n);
859 return -1;
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);
865 return -1;
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"
871 ,filename);
872 return -1;
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);
879 return -1;
882 n=sansa_write(sansa, sectorbuf, of_length);
883 if (n < of_length) {
884 fprintf(stderr,"[ERR] Short write in sansa_update_of\n");
885 return -1;
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);
896 return -1;
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");
903 return -1;
907 return 0;
910 /* Update the PPBL (bootloader) image in the hidden firmware partition */
911 int sansa_update_ppbl(struct sansa_t* sansa, char* filename)
913 int n;
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);
919 if (infile < 0) {
920 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
921 return -1;
924 ppbl_length = filesize(infile);
926 n = read(infile,sectorbuf+0x200,ppbl_length);
927 close(infile);
928 if (n < ppbl_length) {
929 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", ppbl_length, n);
930 return -1;
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);
942 return -1;
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");
948 return -1;
951 return 0;