Colour targets: Revert an optimisation from almost 18 months ago that actually turned...
[Rockbox.git] / rbutil / sansapatcher / sansapatcher.c
blob30433e282e7d5144bf6538cfbb9b074078d9b62a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <inttypes.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
31 #include "sansaio.h"
32 #include "sansapatcher.h"
34 #ifndef RBUTIL
35 #include "bootimg_c200.h"
36 #include "bootimg_e200.h"
37 #endif
38 /* The offset of the MI4 image header in the firmware partition */
39 #define PPMI_OFFSET 0x80000
40 #define NVPARAMS_OFFSET 0x780000
41 #define NVPARAMS_SIZE (0x80000-0x200)
43 int sansa_verbose = 0;
45 /* Windows requires the buffer for disk I/O to be aligned in memory on a
46 multiple of the disk volume size - so we use a single global variable
47 and initialise it with sansa_alloc_buf() in main().
50 unsigned char* sansa_sectorbuf;
52 static off_t filesize(int fd) {
53 struct stat buf;
55 if (fstat(fd,&buf) < 0) {
56 perror("[ERR] Checking filesize of input file");
57 return -1;
58 } else {
59 return(buf.st_size);
63 /* Partition table parsing code taken from Rockbox */
65 #define MAX_SECTOR_SIZE 2048
66 #define SECTOR_SIZE 512
68 static inline int32_t le2int(unsigned char* buf)
70 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
72 return res;
75 static inline uint32_t le2uint(unsigned char* buf)
77 uint32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
79 return res;
82 static inline void int2le(unsigned int val, unsigned char* addr)
84 addr[0] = val & 0xFF;
85 addr[1] = (val >> 8) & 0xff;
86 addr[2] = (val >> 16) & 0xff;
87 addr[3] = (val >> 24) & 0xff;
90 #define BYTES2INT32(array,pos)\
91 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
92 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
94 int sansa_read_partinfo(struct sansa_t* sansa, int silent)
96 int i;
97 unsigned long count;
99 count = sansa_read(sansa,sansa_sectorbuf, sansa->sector_size);
101 if (count <= 0) {
102 print_error(" Error reading from disk: ");
103 return -1;
106 if ((sansa_sectorbuf[510] == 0x55) && (sansa_sectorbuf[511] == 0xaa)) {
107 /* parse partitions */
108 for ( i = 0; i < 4; i++ ) {
109 unsigned char* ptr = sansa_sectorbuf + 0x1be + 16*i;
110 sansa->pinfo[i].type = ptr[4];
111 sansa->pinfo[i].start = BYTES2INT32(ptr, 8);
112 sansa->pinfo[i].size = BYTES2INT32(ptr, 12);
114 /* extended? */
115 if ( sansa->pinfo[i].type == 5 ) {
116 /* not handled yet */
119 } else if ((sansa_sectorbuf[0] == 'E') && (sansa_sectorbuf[1] == 'R')) {
120 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
121 return -1;
124 /* Calculate the starting position of the firmware partition */
125 sansa->start = (loff_t)sansa->pinfo[1].start*(loff_t)sansa->sector_size;
126 return 0;
129 /* NOTE: memmem implementation copied from glibc-2.2.4 - it's a GNU
130 extension and is not universally. In addition, early versions of
131 memmem had a serious bug - the meaning of needle and haystack were
132 reversed. */
134 /* Copyright (C) 1991,92,93,94,96,97,98,2000 Free Software Foundation, Inc.
135 This file is part of the GNU C Library.
137 The GNU C Library is free software; you can redistribute it and/or
138 modify it under the terms of the GNU Lesser General Public
139 License as published by the Free Software Foundation; either
140 version 2.1 of the License, or (at your option) any later version.
142 The GNU C Library is distributed in the hope that it will be useful,
143 but WITHOUT ANY WARRANTY; without even the implied warranty of
144 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
145 Lesser General Public License for more details.
147 You should have received a copy of the GNU Lesser General Public
148 License along with the GNU C Library; if not, write to the Free
149 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
150 02111-1307 USA. */
152 /* Return the first occurrence of NEEDLE in HAYSTACK. */
153 static void *
154 sansa_memmem (haystack, haystack_len, needle, needle_len)
155 const void *haystack;
156 size_t haystack_len;
157 const void *needle;
158 size_t needle_len;
160 const char *begin;
161 const char *const last_possible
162 = (const char *) haystack + haystack_len - needle_len;
164 if (needle_len == 0)
165 /* The first occurrence of the empty string is deemed to occur at
166 the beginning of the string. */
167 return (void *) haystack;
169 /* Sanity check, otherwise the loop might search through the whole
170 memory. */
171 if (__builtin_expect (haystack_len < needle_len, 0))
172 return NULL;
174 for (begin = (const char *) haystack; begin <= last_possible; ++begin)
175 if (begin[0] == ((const char *) needle)[0] &&
176 !memcmp ((const void *) &begin[1],
177 (const void *) ((const char *) needle + 1),
178 needle_len - 1))
179 return (void *) begin;
181 return NULL;
185 * CRC32 implementation taken from:
187 * efone - Distributed internet phone system.
189 * (c) 1999,2000 Krzysztof Dabrowski
190 * (c) 1999,2000 ElysiuM deeZine
192 * This program is free software; you can redistribute it and/or
193 * modify it under the terms of the GNU General Public License
194 * as published by the Free Software Foundation; either version
195 * 2 of the License, or (at your option) any later version.
199 /* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
200 * so make sure, you call it before using the other
201 * functions!
203 static unsigned int crc_tab[256];
205 /* chksum_crc() -- to a given block, this one calculates the
206 * crc32-checksum until the length is
207 * reached. the crc32-checksum will be
208 * the result.
210 static unsigned int chksum_crc32 (unsigned char *block, unsigned int length)
212 register unsigned long crc;
213 unsigned long i;
215 crc = 0;
216 for (i = 0; i < length; i++)
218 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
220 return (crc);
223 /* chksum_crc32gentab() -- to a global crc_tab[256], this one will
224 * calculate the crcTable for crc32-checksums.
225 * it is generated to the polynom [..]
228 static void chksum_crc32gentab (void)
230 unsigned long crc, poly;
231 int i, j;
233 poly = 0xEDB88320L;
234 for (i = 0; i < 256; i++)
236 crc = i;
237 for (j = 8; j > 0; j--)
239 if (crc & 1)
241 crc = (crc >> 1) ^ poly;
243 else
245 crc >>= 1;
248 crc_tab[i] = crc;
252 /* Known keys for Sansa E200 and C200 firmwares: */
253 #define NUM_KEYS ((int)(sizeof(keys)/sizeof(keys[0])))
254 static uint32_t keys[][4] = {
255 { 0xe494e96e, 0x3ee32966, 0x6f48512b, 0xa93fbb42 }, /* "sansa" */
256 { 0xd7b10538, 0xc662945b, 0x1b3fce68, 0xf389c0e6 }, /* "sansa_gh" */
257 { 0x1d29ddc0, 0x2579c2cd, 0xce339e1a, 0x75465dfe }, /* sansa 103 */
259 { 0xbf2d06fa, 0xf0e23d59, 0x29738132, 0xe2d04ca7 }, /* c200 */
260 { 0x2a7968de, 0x15127979, 0x142e60a7, 0xe49c1893 }, /* c200 1.00.03 */
261 { 0xa913d139, 0xf842f398, 0x3e03f1a6, 0x060ee012 }, /* c200 1.00.06 */
266 tea_decrypt() from http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
268 "Following is an adaptation of the reference encryption and decryption
269 routines in C, released into the public domain by David Wheeler and
270 Roger Needham:"
274 /* NOTE: The mi4 version of TEA uses a different initial value to sum compared
275 to the reference implementation and the main loop is 8 iterations, not
279 void tea_decrypt(uint32_t* v0, uint32_t* v1, uint32_t* k) {
280 uint32_t sum=0xF1BBCDC8, i; /* set up */
281 uint32_t delta=0x9E3779B9; /* a key schedule constant */
282 uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
283 for(i=0; i<8; i++) { /* basic cycle start */
284 *v1 -= ((*v0<<4) + k2) ^ (*v0 + sum) ^ ((*v0>>5) + k3);
285 *v0 -= ((*v1<<4) + k0) ^ (*v1 + sum) ^ ((*v1>>5) + k1);
286 sum -= delta; /* end cycle */
290 /* mi4 files are encrypted in 64-bit blocks (two little-endian 32-bit
291 integers) and the key is incremented after each block
294 void tea_decrypt_buf(unsigned char* src, unsigned char* dest, size_t n, uint32_t * key)
296 uint32_t v0, v1;
297 unsigned int i;
299 for (i = 0; i < (n / 8); i++) {
300 v0 = le2int(src);
301 v1 = le2int(src+4);
303 tea_decrypt(&v0, &v1, key);
305 int2le(v0, dest);
306 int2le(v1, dest+4);
308 src += 8;
309 dest += 8;
311 /* Now increment the key */
312 key[0]++;
313 if (key[0]==0) {
314 key[1]++;
315 if (key[1]==0) {
316 key[2]++;
317 if (key[2]==0) {
318 key[3]++;
325 static int get_mi4header(unsigned char* buf,struct mi4header_t* mi4header)
327 if (memcmp(buf,"PPOS",4)!=0)
328 return -1;
330 mi4header->version = le2int(buf+0x04);
331 mi4header->length = le2int(buf+0x08);
332 mi4header->crc32 = le2int(buf+0x0c);
333 mi4header->enctype = le2int(buf+0x10);
334 mi4header->mi4size = le2int(buf+0x14);
335 mi4header->plaintext = le2int(buf+0x18);
337 return 0;
340 static int set_mi4header(unsigned char* buf,struct mi4header_t* mi4header)
342 if (memcmp(buf,"PPOS",4)!=0)
343 return -1;
345 int2le(mi4header->version ,buf+0x04);
346 int2le(mi4header->length ,buf+0x08);
347 int2le(mi4header->crc32 ,buf+0x0c);
348 int2le(mi4header->enctype ,buf+0x10);
349 int2le(mi4header->mi4size ,buf+0x14);
350 int2le(mi4header->plaintext ,buf+0x18);
352 /* Add a dummy DSA signature */
353 memset(buf+0x1c,0,40);
354 buf[0x2f] = 1;
356 return 0;
359 static int sansa_seek_and_read(struct sansa_t* sansa, loff_t pos, unsigned char* buf, int nbytes)
361 int n;
363 if (sansa_seek(sansa, pos) < 0) {
364 return -1;
367 if ((n = sansa_read(sansa,buf,nbytes)) < 0) {
368 return -1;
371 if (n < nbytes) {
372 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
373 nbytes,n);
374 return -1;
377 return 0;
381 /* We identify an E200 based on the following criteria:
383 1) Exactly two partitions;
384 2) First partition is type "W95 FAT32" (0x0b or 0x0c);
385 3) Second partition is type "OS/2 hidden C: drive" (0x84);
386 4) The "PPBL" string appears at offset 0 in the 2nd partition;
387 5) The "PPMI" string appears at offset PPMI_OFFSET in the 2nd partition.
390 int is_sansa(struct sansa_t* sansa)
392 struct mi4header_t mi4header;
393 int ppmi_length;
394 int ppbl_length;
396 /* Check partition layout */
398 if (((sansa->pinfo[0].type != 0x06) &&
399 (sansa->pinfo[0].type != 0x0b) &&
400 (sansa->pinfo[0].type != 0x0c) &&
401 (sansa->pinfo[0].type != 0x0e)) ||
402 (sansa->pinfo[1].type != 0x84) ||
403 (sansa->pinfo[2].type != 0x00) ||
404 (sansa->pinfo[3].type != 0x00)) {
405 /* Bad partition layout, abort */
406 return -1;
409 /* Check Bootloader header */
410 if (sansa_seek_and_read(sansa, sansa->start, sansa_sectorbuf, 0x200) < 0) {
411 return -2;
413 if (memcmp(sansa_sectorbuf,"PPBL",4)!=0) {
414 /* No bootloader header, abort */
415 return -4;
417 ppbl_length = (le2int(sansa_sectorbuf+4) + 0x1ff) & ~0x1ff;
419 /* Sanity/safety check - the bootloader can't be larger than PPMI_OFFSET */
420 if (ppbl_length > PPMI_OFFSET)
422 return -5;
425 /* Load Sansa bootloader and check for "Sansa C200" magic string */
426 if (sansa_seek_and_read(sansa, sansa->start + 0x200, sansa_sectorbuf, ppbl_length) < 0) {
427 fprintf(stderr,"[ERR] Seek and read to 0x%08llx in is_sansa failed.\n",
428 sansa->start+0x200);
429 return -6;
431 if (sansa_memmem(sansa_sectorbuf, ppbl_length, "Sansa C200", 10) != NULL) {
432 /* C200 */
433 sansa->targetname="c200";
434 } else {
435 /* E200 */
436 sansa->targetname="e200";
439 /* Check Main firmware header */
440 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sansa_sectorbuf, 0x200) < 0) {
441 fprintf(stderr,"[ERR] Seek to 0x%08llx in is_sansa failed.\n",
442 sansa->start+PPMI_OFFSET);
443 return -5;
445 if (memcmp(sansa_sectorbuf,"PPMI",4)!=0) {
446 /* No bootloader header, abort */
447 return -7;
449 ppmi_length = le2int(sansa_sectorbuf+4);
451 /* Check main mi4 file header */
452 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET+0x200, sansa_sectorbuf, 0x200) < 0) {
453 fprintf(stderr,"[ERR] Seek to 0x%08llx in is_sansa failed.\n",
454 sansa->start+PPMI_OFFSET+0x200);
455 return -5;
458 if (get_mi4header(sansa_sectorbuf,&mi4header) < 0) {
459 fprintf(stderr,"[ERR] Invalid mi4header\n");
460 return -6;
463 /* Some sanity checks:
465 1) Main MI4 image without RBBL and < 100000 bytes -> old install
466 2) Main MI4 image with RBBL but no second image -> old install
469 sansa->hasoldbootloader = 0;
470 if (memcmp(sansa_sectorbuf+0x1f8,"RBBL",4)==0) {
471 /* Look for an original firmware after the first image */
472 if (sansa_seek_and_read(sansa,
473 sansa->start + PPMI_OFFSET + 0x200 + ppmi_length,
474 sansa_sectorbuf, 512) < 0) {
475 return -7;
478 if (get_mi4header(sansa_sectorbuf,&mi4header)!=0) {
479 fprintf(stderr,"[ERR] No original firmware found\n");
480 sansa->hasoldbootloader = 1;
482 } else if (mi4header.mi4size < 100000) {
483 fprintf(stderr,"[ERR] Old bootloader found\n");
484 sansa->hasoldbootloader = 1;
487 return 0;
490 int sansa_scan(struct sansa_t* sansa)
492 int i;
493 int n = 0;
494 char last_disk[4096];
495 int denied = 0;
496 int result;
498 printf("[INFO] Scanning disk devices...\n");
500 for (i = 0; i <= 25 ; i++) {
501 #ifdef __WIN32__
502 sprintf(sansa->diskname,"\\\\.\\PhysicalDrive%d",i);
503 #elif defined(linux) || defined (__linux)
504 sprintf(sansa->diskname,"/dev/sd%c",'a'+i);
505 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
506 || defined(__bsdi__) || defined(__DragonFly__)
507 sprintf(sansa->diskname,"/dev/da%d",i);
508 #elif defined(__APPLE__) && defined(__MACH__)
509 sprintf(sansa->diskname,"/dev/disk%d",i);
510 #else
511 #error No disk paths defined for this platform
512 #endif
513 if ((result = sansa_open(sansa, 1)) < 0) {
514 if(result == -2) {
515 denied++;
517 continue;
520 if (sansa_read_partinfo(sansa,1) < 0) {
521 continue;
524 if (is_sansa(sansa) < 0) {
525 continue;
528 #ifdef __WIN32__
529 printf("[INFO] %s found - disk device %d\n",sansa->targetname, i);
530 #else
531 printf("[INFO] %s found - %s\n",sansa->targetname, sansa->diskname);
532 #endif
533 n++;
534 strcpy(last_disk,sansa->diskname);
535 sansa_close(sansa);
538 if (n==1) {
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);
544 #ifdef __WIN32__
545 printf("[ERR] You need to run this program with administrator priviledges!\n");
546 #else
547 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
548 #endif
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(unsigned char* buf, struct mi4header_t* mi4header)
558 unsigned char* tmpbuf;
559 int i;
560 int key_found;
562 get_mi4header(buf,mi4header);
564 #if 0
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);
571 #endif
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));
577 if (tmpbuf==NULL) {
578 fprintf(stderr,"[ERR] Can not allocate memory\n");
579 return -1;
582 key_found=0;
583 for (i=0; i < NUM_KEYS && !key_found ; i++) {
584 tea_decrypt_buf(buf+(mi4header->plaintext+0x200),
585 tmpbuf,
586 mi4header->mi4size-(mi4header->plaintext+0x200),
587 keys[i]);
588 key_found = (le2uint(tmpbuf+mi4header->length-mi4header->plaintext-4) == 0xaa55aa55);
591 if (key_found) {
592 memcpy(buf+(mi4header->plaintext+0x200),tmpbuf,mi4header->mi4size-(mi4header->plaintext+0x200));
593 free(tmpbuf);
594 } else {
595 fprintf(stderr,"[ERR] Failed to decrypt image, aborting\n");
596 free(tmpbuf);
597 return -1;
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,"RBOFe200",8);
613 return 0;
616 static int load_original_firmware(struct sansa_t* sansa, unsigned char* buf, struct mi4header_t* mi4header)
618 int ppmi_length;
619 int n;
621 /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */
622 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET, buf, 512) < 0) {
623 return -1;
626 /* No need to check PPMI magic - it's done during init to confirm
627 this is an E200 */
628 ppmi_length = le2int(buf+4);
630 /* Firstly look for an original firmware after the first image */
631 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, buf, 512) < 0) {
632 return -1;
635 if (get_mi4header(buf,mi4header)==0) {
636 /* We have a valid MI4 file after a bootloader, so we use this. */
637 if ((n = sansa_seek_and_read(sansa,
638 sansa->start + PPMI_OFFSET + 0x200 + ppmi_length,
639 buf, mi4header->mi4size)) < 0) {
640 return -1;
642 } else {
643 /* No valid MI4 file, so read the first image. */
644 if ((n = sansa_seek_and_read(sansa,
645 sansa->start + PPMI_OFFSET + 0x200,
646 buf, ppmi_length)) < 0) {
647 return -1;
650 return prepare_original_firmware(buf, mi4header);
653 int sansa_read_firmware(struct sansa_t* sansa, char* filename)
655 int res;
656 int outfile;
657 struct mi4header_t mi4header;
659 res = load_original_firmware(sansa,sansa_sectorbuf,&mi4header);
660 if (res < 0)
661 return res;
663 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
664 if (outfile < 0) {
665 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
666 return -1;
669 res = write(outfile,sansa_sectorbuf,mi4header.mi4size);
670 if (res != (int)mi4header.mi4size) {
671 fprintf(stderr,"[ERR] Write error - %d\n", res);
672 return -1;
674 close(outfile);
676 return 0;
680 int sansa_add_bootloader(struct sansa_t* sansa, char* filename, int type)
682 int res;
683 int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
684 int bl_length = 0; /* Keep gcc happy when building for rbutil */
685 struct mi4header_t mi4header;
686 int n;
687 int length;
689 if (type==FILETYPE_MI4) {
690 /* Step 1 - read bootloader into RAM. */
691 infile=open(filename,O_RDONLY|O_BINARY);
692 if (infile < 0) {
693 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
694 return -1;
697 bl_length = filesize(infile);
698 } else {
699 #ifndef RBUTIL
700 if (strcmp(sansa->targetname,"c200") == 0) {
701 bl_length = LEN_bootimg_c200;
702 } else {
703 bl_length = LEN_bootimg_e200;
705 #endif
708 /* Create PPMI header */
709 memset(sansa_sectorbuf,0,0x200);
710 memcpy(sansa_sectorbuf,"PPMI",4);
711 int2le(bl_length, sansa_sectorbuf+4);
712 int2le(0x00020000, sansa_sectorbuf+8);
714 if (type==FILETYPE_MI4) {
715 /* Read bootloader into sansa_sectorbuf+0x200 */
716 n = read(infile,sansa_sectorbuf+0x200,bl_length);
717 close(infile);
718 if (n < bl_length) {
719 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
720 ,bl_length,n);
721 return -1;
724 if (memcmp(sansa_sectorbuf+0x200+0x1f8,"RBBL",4)!=0) {
725 fprintf(stderr,"[ERR] %s is not a Rockbox bootloader, aborting.\n",
726 filename);
727 return -1;
729 } else {
730 #ifndef RBUTIL
731 if (strcmp(sansa->targetname,"c200") == 0) {
732 memcpy(sansa_sectorbuf+0x200,bootimg_c200,LEN_bootimg_c200);
733 } else {
734 memcpy(sansa_sectorbuf+0x200,bootimg_e200,LEN_bootimg_e200);
736 #endif
739 /* Load original firmware from Sansa to the space after the bootloader */
740 res = load_original_firmware(sansa,sansa_sectorbuf+0x200+bl_length,&mi4header);
741 if (res < 0)
742 return res;
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%08llx in add_bootloader failed.\n",
748 sansa->start+PPMI_OFFSET);
749 return -5;
752 length = 0x200 + bl_length + mi4header.mi4size;
754 n=sansa_write(sansa, sansa_sectorbuf, length);
755 if (n < length) {
756 fprintf(stderr,"[ERR] Short write in add_bootloader\n");
757 return -6;
760 return 0;
763 int sansa_delete_bootloader(struct sansa_t* sansa)
765 int res;
766 struct mi4header_t mi4header;
767 int n;
768 int length;
770 /* Load original firmware from Sansa to sansa_sectorbuf+0x200 */
771 res = load_original_firmware(sansa,sansa_sectorbuf+0x200,&mi4header);
772 if (res < 0)
773 return res;
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%08llx in add_bootloader failed.\n",
785 sansa->start+PPMI_OFFSET);
786 return -5;
789 length = 0x200 + mi4header.mi4size;
791 n=sansa_write(sansa, sansa_sectorbuf, length);
792 if (n < length) {
793 fprintf(stderr,"[ERR] Short write in delete_bootloader\n");
794 return -6;
797 return 0;
800 void sansa_list_images(struct sansa_t* sansa)
802 struct mi4header_t mi4header;
803 loff_t ppmi_length;
805 /* Check Main firmware header */
806 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sansa_sectorbuf, 0x200) < 0) {
807 return;
810 ppmi_length = le2int(sansa_sectorbuf+4);
812 printf("[INFO] Image 1 - %llu bytes\n",ppmi_length);
814 /* Look for an original firmware after the first image */
815 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, sansa_sectorbuf, 512) < 0) {
816 return;
819 if (get_mi4header(sansa_sectorbuf,&mi4header)==0) {
820 printf("[INFO] Image 2 - %d bytes\n",mi4header.mi4size);
824 int sansa_update_of(struct sansa_t* sansa, char* filename)
826 int n;
827 int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
828 int of_length = 0; /* Keep gcc happy when building for rbutil */
829 int ppmi_length;
830 struct mi4header_t mi4header;
831 unsigned char buf[512];
833 /* Step 1 - check we have an OF on the Sansa to upgrade. We expect the
834 Rockbox bootloader to be installed and the OF to be after it on disk. */
836 /* Read 512 bytes from PPMI_OFFSET - the PPMI header */
837 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET,
838 buf, 512) < 0) {
839 return -1;
842 /* No need to check PPMI magic - it's done during init to confirm
843 this is an E200 */
844 ppmi_length = le2int(buf+4);
846 /* Look for an original firmware after the first image */
847 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET+0x200+ppmi_length,
848 buf, 512) < 0) {
849 return -1;
852 if (get_mi4header(buf,&mi4header)!=0) {
853 /* We don't have a valid MI4 file after a bootloader, so do nothing. */
854 fprintf(stderr,"[ERR] No original firmware found at 0x%08llx\n",
855 sansa->start+PPMI_OFFSET+0x200+ppmi_length);
856 return -1;
859 /* Step 2 - read OF into RAM. */
860 infile=open(filename,O_RDONLY|O_BINARY);
861 if (infile < 0) {
862 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
863 return -1;
866 of_length = filesize(infile);
868 /* Load original firmware from file */
869 memset(sansa_sectorbuf,0,0x200);
870 n = read(infile,sansa_sectorbuf,of_length);
871 close(infile);
872 if (n < of_length) {
873 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
874 , of_length, n);
875 return -1;
878 /* Check we have a valid MI4 file. */
879 if (get_mi4header(sansa_sectorbuf,&mi4header)!=0) {
880 fprintf(stderr,"[ERR] %s is not a valid mi4 file\n",filename);
881 return -1;
884 /* Decrypt and build the header */
885 if(prepare_original_firmware(sansa_sectorbuf, &mi4header)!=0){
886 fprintf(stderr,"[ERR] Unable to build decrypted mi4 from %s\n"
887 ,filename);
888 return -1;
891 /* Step 3 - write the OF to the Sansa */
892 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET+0x200+ppmi_length) < 0) {
893 fprintf(stderr,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
894 sansa->start+PPMI_OFFSET+0x200+ppmi_length);
895 return -1;
898 n=sansa_write(sansa, sansa_sectorbuf, of_length);
899 if (n < of_length) {
900 fprintf(stderr,"[ERR] Short write in sansa_update_of\n");
901 return -1;
904 /* Step 4 - zero out the nvparams section - we have to do this or we end up
905 with multiple copies of the nvparams data and don't know which one to
906 work with for the database rebuild disabling trick in our bootloader */
907 if (strcmp(sansa->targetname,"e200") == 0) {
908 printf("[INFO] Resetting Original Firmware settings\n");
909 if (sansa_seek(sansa, sansa->start+NVPARAMS_OFFSET+0x200) < 0) {
910 fprintf(stderr,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
911 sansa->start+NVPARAMS_OFFSET+0x200);
912 return -1;
915 memset(sansa_sectorbuf,0,NVPARAMS_SIZE);
916 n=sansa_write(sansa, sansa_sectorbuf, NVPARAMS_SIZE);
917 if (n < NVPARAMS_SIZE) {
918 fprintf(stderr,"[ERR] Short write in sansa_update_of\n");
919 return -1;
923 return 0;
926 /* Update the PPBL (bootloader) image in the hidden firmware partition */
927 int sansa_update_ppbl(struct sansa_t* sansa, char* filename)
929 int n;
930 int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
931 int ppbl_length = 0; /* Keep gcc happy when building for rbutil */
933 /* Step 1 - read bootloader into RAM. */
934 infile=open(filename,O_RDONLY|O_BINARY);
935 if (infile < 0) {
936 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
937 return -1;
940 ppbl_length = filesize(infile);
942 n = read(infile,sansa_sectorbuf+0x200,ppbl_length);
943 close(infile);
944 if (n < ppbl_length) {
945 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", ppbl_length, n);
946 return -1;
949 /* Step 2 - Build the header */
950 memset(sansa_sectorbuf,0,0x200);
951 memcpy(sansa_sectorbuf,"PPBL",4);
952 int2le(ppbl_length, sansa_sectorbuf+4);
953 int2le(0x00010000, sansa_sectorbuf+8);
955 /* Step 3 - write the bootloader to the Sansa */
956 if (sansa_seek(sansa, sansa->start) < 0) {
957 fprintf(stderr,"[ERR] Seek to 0x%08llx in sansa_update_ppbl failed.\n", sansa->start);
958 return -1;
961 n=sansa_write(sansa, sansa_sectorbuf, ppbl_length + 0x200);
962 if (n < (ppbl_length+0x200)) {
963 fprintf(stderr,"[ERR] Short write in sansa_update_ppbl\n");
964 return -1;
967 return 0;