Prepare new, unofficial maemo release
[maemo-rb.git] / rbutil / sansapatcher / sansapatcher.c
blob9297f36e0201da45111282a7847b3d996657c25b
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 /* 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 unsigned char* sansa_sectorbuf = NULL;
48 static off_t filesize(int fd) {
49 struct stat buf;
51 if (fstat(fd,&buf) < 0) {
52 perror("[ERR] Checking filesize of input file");
53 return -1;
54 } else {
55 return(buf.st_size);
59 /* Partition table parsing code taken from Rockbox */
61 #define MAX_SECTOR_SIZE 2048
62 #define SECTOR_SIZE 512
64 static inline int32_t le2int(const unsigned char* buf)
66 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
68 return res;
71 static inline uint32_t le2uint(const unsigned char* buf)
73 uint32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
75 return res;
78 static inline void int2le(unsigned int val, unsigned char* addr)
80 addr[0] = val & 0xFF;
81 addr[1] = (val >> 8) & 0xff;
82 addr[2] = (val >> 16) & 0xff;
83 addr[3] = (val >> 24) & 0xff;
86 #define BYTES2INT32(array,pos)\
87 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
88 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
90 int sansa_read_partinfo(struct sansa_t* sansa, int silent)
92 int i;
93 unsigned long count;
95 count = sansa_read(sansa,sansa_sectorbuf, sansa->sector_size);
97 if (count <= 0) {
98 sansa_print_error(" Error reading from disk: ");
99 return -1;
102 if ((sansa_sectorbuf[510] == 0x55) && (sansa_sectorbuf[511] == 0xaa)) {
103 /* parse partitions */
104 for ( i = 0; i < 4; i++ ) {
105 unsigned char* ptr = sansa_sectorbuf + 0x1be + 16*i;
106 sansa->pinfo[i].type = ptr[4];
107 sansa->pinfo[i].start = BYTES2INT32(ptr, 8);
108 sansa->pinfo[i].size = BYTES2INT32(ptr, 12);
110 /* extended? */
111 if ( sansa->pinfo[i].type == 5 ) {
112 /* not handled yet */
115 } else if ((sansa_sectorbuf[0] == 'E') && (sansa_sectorbuf[1] == 'R')) {
116 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
117 return -1;
120 /* Calculate the starting position of the firmware partition */
121 sansa->start = (loff_t)sansa->pinfo[1].start*(loff_t)sansa->sector_size;
122 return 0;
125 /* NOTE: memmem implementation copied from glibc-2.2.4 - it's a GNU
126 extension and is not universally. In addition, early versions of
127 memmem had a serious bug - the meaning of needle and haystack were
128 reversed. */
130 /* Copyright (C) 1991,92,93,94,96,97,98,2000 Free Software Foundation, Inc.
131 This file is part of the GNU C Library.
133 The GNU C Library is free software; you can redistribute it and/or
134 modify it under the terms of the GNU Lesser General Public
135 License as published by the Free Software Foundation; either
136 version 2.1 of the License, or (at your option) any later version.
138 The GNU C Library is distributed in the hope that it will be useful,
139 but WITHOUT ANY WARRANTY; without even the implied warranty of
140 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
141 Lesser General Public License for more details.
143 You should have received a copy of the GNU Lesser General Public
144 License along with the GNU C Library; if not, write to the Free
145 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
146 02111-1307 USA. */
148 /* Return the first occurrence of NEEDLE in HAYSTACK. */
149 static void *
150 sansa_memmem (haystack, haystack_len, needle, needle_len)
151 const void *haystack;
152 size_t haystack_len;
153 const void *needle;
154 size_t needle_len;
156 const char *begin;
157 const char *const last_possible
158 = (const char *) haystack + haystack_len - needle_len;
160 if (needle_len == 0)
161 /* The first occurrence of the empty string is deemed to occur at
162 the beginning of the string. */
163 return (void *) haystack;
165 /* Sanity check, otherwise the loop might search through the whole
166 memory. */
167 if (__builtin_expect (haystack_len < needle_len, 0))
168 return NULL;
170 for (begin = (const char *) haystack; begin <= last_possible; ++begin)
171 if (begin[0] == ((const char *) needle)[0] &&
172 !memcmp ((const void *) &begin[1],
173 (const void *) ((const char *) needle + 1),
174 needle_len - 1))
175 return (void *) begin;
177 return NULL;
181 * CRC32 implementation taken from:
183 * efone - Distributed internet phone system.
185 * (c) 1999,2000 Krzysztof Dabrowski
186 * (c) 1999,2000 ElysiuM deeZine
188 * This program is free software; you can redistribute it and/or
189 * modify it under the terms of the GNU General Public License
190 * as published by the Free Software Foundation; either version
191 * 2 of the License, or (at your option) any later version.
195 /* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
196 * so make sure, you call it before using the other
197 * functions!
199 static unsigned int crc_tab[256];
201 /* chksum_crc() -- to a given block, this one calculates the
202 * crc32-checksum until the length is
203 * reached. the crc32-checksum will be
204 * the result.
206 static unsigned int chksum_crc32 (const unsigned char *block, unsigned int length)
208 register unsigned long crc;
209 unsigned long i;
211 crc = 0;
212 for (i = 0; i < length; i++)
214 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
216 return (crc);
219 /* chksum_crc32gentab() -- to a global crc_tab[256], this one will
220 * calculate the crcTable for crc32-checksums.
221 * it is generated to the polynom [..]
224 static void chksum_crc32gentab (void)
226 unsigned long crc, poly;
227 int i, j;
229 poly = 0xEDB88320L;
230 for (i = 0; i < 256; i++)
232 crc = i;
233 for (j = 8; j > 0; j--)
235 if (crc & 1)
237 crc = (crc >> 1) ^ poly;
239 else
241 crc >>= 1;
244 crc_tab[i] = crc;
248 /* Known keys for Sansa E200 and C200 firmwares: */
249 #define NUM_KEYS ((int)(sizeof(keys)/sizeof(keys[0])))
250 static const uint32_t keys[][4] = {
251 { 0xe494e96e, 0x3ee32966, 0x6f48512b, 0xa93fbb42 }, /* "sansa" */
252 { 0xd7b10538, 0xc662945b, 0x1b3fce68, 0xf389c0e6 }, /* "sansa_gh" */
253 { 0x1d29ddc0, 0x2579c2cd, 0xce339e1a, 0x75465dfe }, /* sansa 103 */
255 { 0x2a7968de, 0x15127979, 0x142e60a7, 0xe49c1893 }, /* c200 1.00.03 */
256 { 0xbf2d06fa, 0xf0e23d59, 0x29738132, 0xe2d04ca7 }, /* c200 1.00.04 and up*/
257 { 0xa913d139, 0xf842f398, 0x3e03f1a6, 0x060ee012 }, /* c200 1.01.05 and up*/
258 { 0x0fe92902, 0xe8cc0f89, 0x6ff568ba, 0x1eff5161 }, /* c200 1.01.07 */
263 tea_decrypt() from http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
265 "Following is an adaptation of the reference encryption and decryption
266 routines in C, released into the public domain by David Wheeler and
267 Roger Needham:"
271 /* NOTE: The mi4 version of TEA uses a different initial value to sum compared
272 to the reference implementation and the main loop is 8 iterations, not
276 static void tea_decrypt(uint32_t* v0, uint32_t* v1, const uint32_t* k) {
277 uint32_t sum=0xF1BBCDC8, i; /* set up */
278 uint32_t delta=0x9E3779B9; /* a key schedule constant */
279 uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
280 for(i=0; i<8; i++) { /* basic cycle start */
281 *v1 -= ((*v0<<4) + k2) ^ (*v0 + sum) ^ ((*v0>>5) + k3);
282 *v0 -= ((*v1<<4) + k0) ^ (*v1 + sum) ^ ((*v1>>5) + k1);
283 sum -= delta; /* end cycle */
287 /* mi4 files are encrypted in 64-bit blocks (two little-endian 32-bit
288 integers) and the key is incremented after each block
291 static void tea_decrypt_buf(const unsigned char* src, unsigned char* dest,
292 size_t n, const uint32_t * initial_key)
294 uint32_t v0, v1;
295 unsigned int i;
296 uint32_t key[4];
298 memcpy(key, initial_key, sizeof(key));
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(const 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,const 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 */
397 if (((sansa->pinfo[0].type != 0x06) &&
398 (sansa->pinfo[0].type != 0x0b) &&
399 (sansa->pinfo[0].type != 0x0c) &&
400 (sansa->pinfo[0].type != 0x0e)) ||
401 (sansa->pinfo[1].type != 0x84) ||
402 (sansa->pinfo[2].type != 0x00) ||
403 (sansa->pinfo[3].type != 0x00)) {
404 /* Bad partition layout, abort */
405 return -1;
408 /* Check Bootloader header */
409 if (sansa_seek_and_read(sansa, sansa->start, sansa_sectorbuf, 0x200) < 0) {
410 return -2;
412 if (memcmp(sansa_sectorbuf,"PPBL",4)!=0) {
413 /* No bootloader header, abort */
414 return -4;
416 ppbl_length = (le2int(sansa_sectorbuf+4) + 0x1ff) & ~0x1ff;
418 /* Sanity/safety check - the bootloader can't be larger than PPMI_OFFSET */
419 if (ppbl_length > PPMI_OFFSET)
421 return -5;
424 /* Load Sansa bootloader and check for "Sansa C200" magic string */
425 if (sansa_seek_and_read(sansa, sansa->start + 0x200, sansa_sectorbuf, ppbl_length) < 0) {
426 fprintf(stderr,"[ERR] Seek and read to 0x%08llx in is_sansa failed.\n",
427 sansa->start+0x200);
428 return -6;
430 if (sansa_memmem(sansa_sectorbuf, ppbl_length, "Sansa C200", 10) != NULL) {
431 /* C200 */
432 sansa->targetname="c200";
433 } else {
434 /* E200 */
435 sansa->targetname="e200";
438 /* Check Main firmware header */
439 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sansa_sectorbuf, 0x200) < 0) {
440 fprintf(stderr,"[ERR] Seek to 0x%08llx in is_sansa failed.\n",
441 sansa->start+PPMI_OFFSET);
442 return -5;
444 if (memcmp(sansa_sectorbuf,"PPMI",4)!=0) {
445 /* No bootloader header, abort */
446 return -7;
448 ppmi_length = le2int(sansa_sectorbuf+4);
450 /* Check main mi4 file header */
451 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET+0x200, sansa_sectorbuf, 0x200) < 0) {
452 fprintf(stderr,"[ERR] Seek to 0x%08llx in is_sansa failed.\n",
453 sansa->start+PPMI_OFFSET+0x200);
454 return -5;
457 if (get_mi4header(sansa_sectorbuf,&mi4header) < 0) {
458 fprintf(stderr,"[ERR] Invalid mi4header\n");
459 return -6;
462 /* Some sanity checks:
464 1) Main MI4 image without RBBL and < 100000 bytes -> old install
465 2) Main MI4 image with RBBL but no second image -> old install
468 sansa->hasoldbootloader = 0;
469 if (memcmp(sansa_sectorbuf+0x1f8,"RBBL",4)==0) {
470 /* Look for an original firmware after the first image */
471 if (sansa_seek_and_read(sansa,
472 sansa->start + PPMI_OFFSET + 0x200 + ppmi_length,
473 sansa_sectorbuf, 512) < 0) {
474 return -7;
477 if (get_mi4header(sansa_sectorbuf,&mi4header)!=0) {
478 fprintf(stderr,"[ERR] No original firmware found\n");
479 sansa->hasoldbootloader = 1;
481 } else if (mi4header.mi4size < 100000) {
482 fprintf(stderr,"[ERR] Old bootloader found\n");
483 sansa->hasoldbootloader = 1;
486 return 0;
489 int sansa_scan(struct sansa_t* sansa)
491 int i;
492 int n = 0;
493 char last_disk[4096];
494 int denied = 0;
495 int result;
497 printf("[INFO] Scanning disk devices...\n");
499 for (i = 0; i <= 25 ; i++) {
500 #ifdef __WIN32__
501 sprintf(sansa->diskname,"\\\\.\\PhysicalDrive%d",i);
502 #elif defined(linux) || defined (__linux)
503 sprintf(sansa->diskname,"/dev/sd%c",'a'+i);
504 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
505 || defined(__bsdi__) || defined(__DragonFly__)
506 sprintf(sansa->diskname,"/dev/da%d",i);
507 #elif defined(__APPLE__) && defined(__MACH__)
508 sprintf(sansa->diskname,"/dev/disk%d",i);
509 #else
510 #error No disk paths defined for this platform
511 #endif
512 if ((result = sansa_open(sansa, 1)) < 0) {
513 if(result == -2) {
514 denied++;
516 sansa_close(sansa);
517 continue;
520 if (sansa_read_partinfo(sansa,1) < 0) {
521 sansa_close(sansa);
522 continue;
525 if (is_sansa(sansa) < 0) {
526 sansa_close(sansa);
527 continue;
530 #ifdef __WIN32__
531 printf("[INFO] %s found - disk device %d\n",sansa->targetname, i);
532 #else
533 printf("[INFO] %s found - %s\n",sansa->targetname, sansa->diskname);
534 #endif
535 n++;
536 strcpy(last_disk,sansa->diskname);
537 sansa_close(sansa);
540 if (n==1) {
541 /* Remember the disk name */
542 strcpy(sansa->diskname,last_disk);
544 else if (n == 0 && denied) {
545 printf("[ERR] FATAL: Permission denied on %d device(s) and no sansa detected.\n", denied);
546 #ifdef __WIN32__
547 printf("[ERR] You need to run this program with administrator priviledges!\n");
548 #else
549 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
550 #endif
553 return (n == 0 && denied) ? -1 : n;
556 /* Prepare original firmware for writing to the firmware partition by decrypting
557 and updating the header */
558 static int prepare_original_firmware(struct sansa_t* sansa, unsigned char* buf, struct mi4header_t* mi4header)
560 unsigned char* tmpbuf;
561 int i;
562 int key_found;
564 get_mi4header(buf,mi4header);
566 #if 0
567 printf("mi4header->version =0x%08x\n",mi4header->version);
568 printf("mi4header->length =0x%08x\n",mi4header->length);
569 printf("mi4header->crc32 =0x%08x\n",mi4header->crc32);
570 printf("mi4header->enctype =0x%08x\n",mi4header->enctype);
571 printf("mi4header->mi4size =0x%08x\n",mi4header->mi4size);
572 printf("mi4header->plaintext =0x%08x\n",mi4header->plaintext);
573 #endif
575 /* Decrypt anything that needs decrypting. */
576 if (mi4header->plaintext < mi4header->mi4size - 0x200) {
577 /* TODO: Check different keys */
578 tmpbuf=malloc(mi4header->mi4size-(mi4header->plaintext+0x200));
579 if (tmpbuf==NULL) {
580 fprintf(stderr,"[ERR] Can not allocate memory\n");
581 return -1;
584 key_found=0;
585 for (i=0; i < NUM_KEYS && !key_found ; i++) {
586 tea_decrypt_buf(buf+(mi4header->plaintext+0x200),
587 tmpbuf,
588 mi4header->mi4size-(mi4header->plaintext+0x200),
589 keys[i]);
590 key_found = (le2uint(tmpbuf+mi4header->length-mi4header->plaintext-4) == 0xaa55aa55);
593 if (key_found) {
594 memcpy(buf+(mi4header->plaintext+0x200),tmpbuf,mi4header->mi4size-(mi4header->plaintext+0x200));
595 free(tmpbuf);
596 } else {
597 fprintf(stderr,"[ERR] Failed to decrypt image, aborting\n");
598 free(tmpbuf);
599 return -1;
603 /* Increase plaintext value to full file */
604 mi4header->plaintext = mi4header->mi4size - 0x200;
606 /* Update CRC checksum */
607 chksum_crc32gentab ();
608 mi4header->crc32 = chksum_crc32(buf+0x200,mi4header->mi4size-0x200);
610 set_mi4header(buf,mi4header);
612 /* Add Rockbox-specific header */
613 memcpy(buf+0x1f8,"RBOF",4);
614 memcpy(buf+0x1fc,sansa->targetname,4);
616 return 0;
619 static int load_original_firmware(struct sansa_t* sansa, unsigned char* buf, struct mi4header_t* mi4header)
621 int ppmi_length;
622 int n;
624 /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */
625 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET, buf, 512) < 0) {
626 return -1;
629 /* No need to check PPMI magic - it's done during init to confirm
630 this is an E200 */
631 ppmi_length = le2int(buf+4);
633 /* Firstly look for an original firmware after the first image */
634 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, buf, 512) < 0) {
635 return -1;
638 if (get_mi4header(buf,mi4header)==0) {
639 /* We have a valid MI4 file after a bootloader, so we use this. */
640 if ((n = sansa_seek_and_read(sansa,
641 sansa->start + PPMI_OFFSET + 0x200 + ppmi_length,
642 buf, mi4header->mi4size)) < 0) {
643 return -1;
645 } else {
646 /* No valid MI4 file, so read the first image. */
647 if ((n = sansa_seek_and_read(sansa,
648 sansa->start + PPMI_OFFSET + 0x200,
649 buf, ppmi_length)) < 0) {
650 return -1;
653 return prepare_original_firmware(sansa, buf, mi4header);
656 int sansa_read_firmware(struct sansa_t* sansa, const char* filename)
658 int res;
659 int outfile;
660 struct mi4header_t mi4header;
662 res = load_original_firmware(sansa,sansa_sectorbuf,&mi4header);
663 if (res < 0)
664 return res;
666 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
667 if (outfile < 0) {
668 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
669 return -1;
672 res = write(outfile,sansa_sectorbuf,mi4header.mi4size);
673 if (res != (int)mi4header.mi4size) {
674 fprintf(stderr,"[ERR] Write error - %d\n", res);
675 return -1;
677 close(outfile);
679 return 0;
682 unsigned int sansa_read_bootloader(struct sansa_t* sansa, const char* filename, unsigned char** bl_buffer)
684 /* Step 1 - read bootloader into RAM. */
685 int infile;
686 unsigned int n;
687 unsigned int len;
688 infile=open(filename,O_RDONLY|O_BINARY);
689 if (infile < 0) {
690 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
691 return 0;
694 len = filesize(infile);
696 unsigned char* b = malloc(len);
697 if (b == NULL) {
698 fprintf(stderr,"[ERR] Could not allocate memory for bootloader\n");
699 close(infile);
700 return 0;
703 n = read(infile,b,len);
704 close(infile);
705 if (n < len) {
706 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
707 ,len,n);
708 return 0;
711 if (memcmp(b+0x1f8,"RBBL",4)!=0) {
712 fprintf(stderr,"[ERR] %s is not a Rockbox bootloader, aborting.\n",
713 filename);
714 return 0;
716 if (memcmp(b+0x1fc,sansa->targetname,4)!=0) {
717 fprintf(stderr,"[ERR] %s is not a Rockbox bootloader for %s, aborting.\n",
718 filename, sansa->targetname);
719 return 0;
721 *bl_buffer = b;
722 return len;
725 int sansa_add_bootloader(struct sansa_t* sansa, const unsigned char* bootloader, const unsigned int bl_length)
727 int res;
728 struct mi4header_t mi4header;
729 int length;
730 int n;
732 /* Create PPMI header */
733 memset(sansa_sectorbuf,0,0x200);
734 memcpy(sansa_sectorbuf,"PPMI",4);
735 int2le(bl_length, sansa_sectorbuf+4);
736 int2le(0x00020000, sansa_sectorbuf+8);
738 /* copy bootloader to sansa_sectorbuf+0x200 */
739 memcpy(sansa_sectorbuf+0x200,bootloader,bl_length);
741 /* Load original firmware from Sansa to the space after the bootloader */
742 res = load_original_firmware(sansa,sansa_sectorbuf+0x200+bl_length,&mi4header);
743 if (res < 0)
744 return res;
746 /* Now write the whole thing back to the Sansa */
748 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET) < 0) {
749 fprintf(stderr,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
750 sansa->start+PPMI_OFFSET);
751 return -5;
754 length = 0x200 + bl_length + mi4header.mi4size;
756 n=sansa_write(sansa, sansa_sectorbuf, length);
757 if (n < length) {
758 fprintf(stderr,"[ERR] Short write in add_bootloader\n");
759 return -6;
762 return 0;
765 int sansa_delete_bootloader(struct sansa_t* sansa)
767 int res;
768 struct mi4header_t mi4header;
769 int n;
770 int length;
772 /* Load original firmware from Sansa to sansa_sectorbuf+0x200 */
773 res = load_original_firmware(sansa,sansa_sectorbuf+0x200,&mi4header);
774 if (res < 0)
775 return res;
777 /* Create PPMI header */
778 memset(sansa_sectorbuf,0,0x200);
779 memcpy(sansa_sectorbuf,"PPMI",4);
780 int2le(mi4header.mi4size, sansa_sectorbuf+4);
781 int2le(0x00020000, sansa_sectorbuf+8);
783 /* Now write the whole thing back to the Sansa */
785 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET) < 0) {
786 fprintf(stderr,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
787 sansa->start+PPMI_OFFSET);
788 return -5;
791 length = 0x200 + mi4header.mi4size;
793 n=sansa_write(sansa, sansa_sectorbuf, length);
794 if (n < length) {
795 fprintf(stderr,"[ERR] Short write in delete_bootloader\n");
796 return -6;
799 return 0;
802 /** List number of MI4 images on the player, return number.
804 int sansa_list_images(struct sansa_t* sansa)
806 struct mi4header_t mi4header;
807 loff_t ppmi_length;
808 int num = 0;
810 /* Check Main firmware header */
811 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sansa_sectorbuf, 0x200) < 0) {
812 return 0;
815 ppmi_length = le2int(sansa_sectorbuf+4);
817 printf("[INFO] Image 1 - %llu bytes\n",ppmi_length);
818 num = 1;
820 /* Look for an original firmware after the first image */
821 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, sansa_sectorbuf, 512) < 0) {
822 return 0;
825 if (get_mi4header(sansa_sectorbuf,&mi4header)==0) {
826 printf("[INFO] Image 2 - %d bytes\n",mi4header.mi4size);
827 num = 2;
829 return num;
832 int sansa_update_of(struct sansa_t* sansa, const char* filename)
834 int n;
835 int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
836 int of_length = 0; /* Keep gcc happy when building for rbutil */
837 int ppmi_length;
838 struct mi4header_t mi4header;
839 unsigned char buf[512];
841 /* Step 1 - check we have an OF on the Sansa to upgrade. We expect the
842 Rockbox bootloader to be installed and the OF to be after it on disk. */
844 /* Read 512 bytes from PPMI_OFFSET - the PPMI header */
845 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET,
846 buf, 512) < 0) {
847 return -1;
850 /* No need to check PPMI magic - it's done during init to confirm
851 this is an E200 */
852 ppmi_length = le2int(buf+4);
854 /* Look for an original firmware after the first image */
855 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET+0x200+ppmi_length,
856 buf, 512) < 0) {
857 return -1;
860 if (get_mi4header(buf,&mi4header)!=0) {
861 /* We don't have a valid MI4 file after a bootloader, so do nothing. */
862 fprintf(stderr,"[ERR] No original firmware found at 0x%08llx\n",
863 sansa->start+PPMI_OFFSET+0x200+ppmi_length);
864 return -1;
867 /* Step 2 - read OF into RAM. */
868 infile=open(filename,O_RDONLY|O_BINARY);
869 if (infile < 0) {
870 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
871 return -1;
874 of_length = filesize(infile);
876 /* Load original firmware from file */
877 memset(sansa_sectorbuf,0,0x200);
878 n = read(infile,sansa_sectorbuf,of_length);
879 close(infile);
880 if (n < of_length) {
881 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
882 , of_length, n);
883 return -1;
886 /* Check we have a valid MI4 file. */
887 if (get_mi4header(sansa_sectorbuf,&mi4header)!=0) {
888 fprintf(stderr,"[ERR] %s is not a valid mi4 file\n",filename);
889 return -1;
892 /* Decrypt and build the header */
893 if(prepare_original_firmware(sansa, sansa_sectorbuf, &mi4header)!=0){
894 fprintf(stderr,"[ERR] Unable to build decrypted mi4 from %s\n"
895 ,filename);
896 return -1;
899 /* Step 3 - write the OF to the Sansa */
900 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET+0x200+ppmi_length) < 0) {
901 fprintf(stderr,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
902 sansa->start+PPMI_OFFSET+0x200+ppmi_length);
903 return -1;
906 n=sansa_write(sansa, sansa_sectorbuf, of_length);
907 if (n < of_length) {
908 fprintf(stderr,"[ERR] Short write in sansa_update_of\n");
909 return -1;
912 /* Step 4 - zero out the nvparams section - we have to do this or we end up
913 with multiple copies of the nvparams data and don't know which one to
914 work with for the database rebuild disabling trick in our bootloader */
915 if (strcmp(sansa->targetname,"e200") == 0) {
916 printf("[INFO] Resetting Original Firmware settings\n");
917 if (sansa_seek(sansa, sansa->start+NVPARAMS_OFFSET+0x200) < 0) {
918 fprintf(stderr,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
919 sansa->start+NVPARAMS_OFFSET+0x200);
920 return -1;
923 memset(sansa_sectorbuf,0,NVPARAMS_SIZE);
924 n=sansa_write(sansa, sansa_sectorbuf, NVPARAMS_SIZE);
925 if (n < NVPARAMS_SIZE) {
926 fprintf(stderr,"[ERR] Short write in sansa_update_of\n");
927 return -1;
931 return 0;
934 /* Update the PPBL (bootloader) image in the hidden firmware partition */
935 int sansa_update_ppbl(struct sansa_t* sansa, const char* filename)
937 int n;
938 int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
939 int ppbl_length = 0; /* Keep gcc happy when building for rbutil */
941 /* Step 1 - read bootloader into RAM. */
942 infile=open(filename,O_RDONLY|O_BINARY);
943 if (infile < 0) {
944 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
945 return -1;
948 ppbl_length = filesize(infile);
950 n = read(infile,sansa_sectorbuf+0x200,ppbl_length);
951 close(infile);
952 if (n < ppbl_length) {
953 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", ppbl_length, n);
954 return -1;
957 /* Step 2 - Build the header */
958 memset(sansa_sectorbuf,0,0x200);
959 memcpy(sansa_sectorbuf,"PPBL",4);
960 int2le(ppbl_length, sansa_sectorbuf+4);
961 int2le(0x00010000, sansa_sectorbuf+8);
963 /* Step 3 - write the bootloader to the Sansa */
964 if (sansa_seek(sansa, sansa->start) < 0) {
965 fprintf(stderr,"[ERR] Seek to 0x%08llx in sansa_update_ppbl failed.\n", sansa->start);
966 return -1;
969 n=sansa_write(sansa, sansa_sectorbuf, ppbl_length + 0x200);
970 if (n < (ppbl_length+0x200)) {
971 fprintf(stderr,"[ERR] Short write in sansa_update_ppbl\n");
972 return -1;
975 return 0;