Redo r18136 a little cleaner
[kugel-rb.git] / rbutil / sansapatcher / sansapatcher.c
blobeb6f7d12a57ed114b9eff18f955988dd72fcf4e4
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(const 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(const 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 (const 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 const 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 { 0x2a7968de, 0x15127979, 0x142e60a7, 0xe49c1893 }, /* c200 1.00.03 */
260 { 0xbf2d06fa, 0xf0e23d59, 0x29738132, 0xe2d04ca7 }, /* c200 1.00.04 and up*/
261 { 0xa913d139, 0xf842f398, 0x3e03f1a6, 0x060ee012 }, /* c200 1.01.05 and up*/
262 { 0x0fe92902, 0xe8cc0f89, 0x6ff568ba, 0x1eff5161 }, /* c200 1.01.07 */
267 tea_decrypt() from http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
269 "Following is an adaptation of the reference encryption and decryption
270 routines in C, released into the public domain by David Wheeler and
271 Roger Needham:"
275 /* NOTE: The mi4 version of TEA uses a different initial value to sum compared
276 to the reference implementation and the main loop is 8 iterations, not
280 static void tea_decrypt(uint32_t* v0, uint32_t* v1, const uint32_t* k) {
281 uint32_t sum=0xF1BBCDC8, i; /* set up */
282 uint32_t delta=0x9E3779B9; /* a key schedule constant */
283 uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
284 for(i=0; i<8; i++) { /* basic cycle start */
285 *v1 -= ((*v0<<4) + k2) ^ (*v0 + sum) ^ ((*v0>>5) + k3);
286 *v0 -= ((*v1<<4) + k0) ^ (*v1 + sum) ^ ((*v1>>5) + k1);
287 sum -= delta; /* end cycle */
291 /* mi4 files are encrypted in 64-bit blocks (two little-endian 32-bit
292 integers) and the key is incremented after each block
295 static void tea_decrypt_buf(const unsigned char* src, unsigned char* dest,
296 size_t n, const uint32_t * initial_key)
298 uint32_t v0, v1;
299 unsigned int i;
300 uint32_t key[4];
302 memcpy(key, initial_key, sizeof(key));
303 for (i = 0; i < (n / 8); i++) {
304 v0 = le2int(src);
305 v1 = le2int(src+4);
307 tea_decrypt(&v0, &v1, key);
309 int2le(v0, dest);
310 int2le(v1, dest+4);
312 src += 8;
313 dest += 8;
315 /* Now increment the key */
316 key[0]++;
317 if (key[0]==0) {
318 key[1]++;
319 if (key[1]==0) {
320 key[2]++;
321 if (key[2]==0) {
322 key[3]++;
329 static int get_mi4header(const unsigned char* buf,struct mi4header_t* mi4header)
331 if (memcmp(buf,"PPOS",4)!=0)
332 return -1;
334 mi4header->version = le2int(buf+0x04);
335 mi4header->length = le2int(buf+0x08);
336 mi4header->crc32 = le2int(buf+0x0c);
337 mi4header->enctype = le2int(buf+0x10);
338 mi4header->mi4size = le2int(buf+0x14);
339 mi4header->plaintext = le2int(buf+0x18);
341 return 0;
344 static int set_mi4header(unsigned char* buf,const struct mi4header_t* mi4header)
346 if (memcmp(buf,"PPOS",4)!=0)
347 return -1;
349 int2le(mi4header->version ,buf+0x04);
350 int2le(mi4header->length ,buf+0x08);
351 int2le(mi4header->crc32 ,buf+0x0c);
352 int2le(mi4header->enctype ,buf+0x10);
353 int2le(mi4header->mi4size ,buf+0x14);
354 int2le(mi4header->plaintext ,buf+0x18);
356 /* Add a dummy DSA signature */
357 memset(buf+0x1c,0,40);
358 buf[0x2f] = 1;
360 return 0;
363 static int sansa_seek_and_read(struct sansa_t* sansa, loff_t pos, unsigned char* buf, int nbytes)
365 int n;
367 if (sansa_seek(sansa, pos) < 0) {
368 return -1;
371 if ((n = sansa_read(sansa,buf,nbytes)) < 0) {
372 return -1;
375 if (n < nbytes) {
376 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
377 nbytes,n);
378 return -1;
381 return 0;
385 /* We identify an E200 based on the following criteria:
387 1) Exactly two partitions;
388 2) First partition is type "W95 FAT32" (0x0b or 0x0c);
389 3) Second partition is type "OS/2 hidden C: drive" (0x84);
390 4) The "PPBL" string appears at offset 0 in the 2nd partition;
391 5) The "PPMI" string appears at offset PPMI_OFFSET in the 2nd partition.
394 int is_sansa(struct sansa_t* sansa)
396 struct mi4header_t mi4header;
397 int ppmi_length;
398 int ppbl_length;
400 /* Check partition layout */
401 if (((sansa->pinfo[0].type != 0x06) &&
402 (sansa->pinfo[0].type != 0x0b) &&
403 (sansa->pinfo[0].type != 0x0c) &&
404 (sansa->pinfo[0].type != 0x0e)) ||
405 (sansa->pinfo[1].type != 0x84) ||
406 (sansa->pinfo[2].type != 0x00) ||
407 (sansa->pinfo[3].type != 0x00)) {
408 /* Bad partition layout, abort */
409 return -1;
412 /* Check Bootloader header */
413 if (sansa_seek_and_read(sansa, sansa->start, sansa_sectorbuf, 0x200) < 0) {
414 return -2;
416 if (memcmp(sansa_sectorbuf,"PPBL",4)!=0) {
417 /* No bootloader header, abort */
418 return -4;
420 ppbl_length = (le2int(sansa_sectorbuf+4) + 0x1ff) & ~0x1ff;
422 /* Sanity/safety check - the bootloader can't be larger than PPMI_OFFSET */
423 if (ppbl_length > PPMI_OFFSET)
425 return -5;
428 /* Load Sansa bootloader and check for "Sansa C200" magic string */
429 if (sansa_seek_and_read(sansa, sansa->start + 0x200, sansa_sectorbuf, ppbl_length) < 0) {
430 fprintf(stderr,"[ERR] Seek and read to 0x%08llx in is_sansa failed.\n",
431 sansa->start+0x200);
432 return -6;
434 if (sansa_memmem(sansa_sectorbuf, ppbl_length, "Sansa C200", 10) != NULL) {
435 /* C200 */
436 sansa->targetname="c200";
437 } else {
438 /* E200 */
439 sansa->targetname="e200";
442 /* Check Main firmware header */
443 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sansa_sectorbuf, 0x200) < 0) {
444 fprintf(stderr,"[ERR] Seek to 0x%08llx in is_sansa failed.\n",
445 sansa->start+PPMI_OFFSET);
446 return -5;
448 if (memcmp(sansa_sectorbuf,"PPMI",4)!=0) {
449 /* No bootloader header, abort */
450 return -7;
452 ppmi_length = le2int(sansa_sectorbuf+4);
454 /* Check main mi4 file header */
455 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET+0x200, sansa_sectorbuf, 0x200) < 0) {
456 fprintf(stderr,"[ERR] Seek to 0x%08llx in is_sansa failed.\n",
457 sansa->start+PPMI_OFFSET+0x200);
458 return -5;
461 if (get_mi4header(sansa_sectorbuf,&mi4header) < 0) {
462 fprintf(stderr,"[ERR] Invalid mi4header\n");
463 return -6;
466 /* Some sanity checks:
468 1) Main MI4 image without RBBL and < 100000 bytes -> old install
469 2) Main MI4 image with RBBL but no second image -> old install
472 sansa->hasoldbootloader = 0;
473 if (memcmp(sansa_sectorbuf+0x1f8,"RBBL",4)==0) {
474 /* Look for an original firmware after the first image */
475 if (sansa_seek_and_read(sansa,
476 sansa->start + PPMI_OFFSET + 0x200 + ppmi_length,
477 sansa_sectorbuf, 512) < 0) {
478 return -7;
481 if (get_mi4header(sansa_sectorbuf,&mi4header)!=0) {
482 fprintf(stderr,"[ERR] No original firmware found\n");
483 sansa->hasoldbootloader = 1;
485 } else if (mi4header.mi4size < 100000) {
486 fprintf(stderr,"[ERR] Old bootloader found\n");
487 sansa->hasoldbootloader = 1;
490 return 0;
493 int sansa_scan(struct sansa_t* sansa)
495 int i;
496 int n = 0;
497 char last_disk[4096];
498 int denied = 0;
499 int result;
501 printf("[INFO] Scanning disk devices...\n");
503 for (i = 0; i <= 25 ; i++) {
504 #ifdef __WIN32__
505 sprintf(sansa->diskname,"\\\\.\\PhysicalDrive%d",i);
506 #elif defined(linux) || defined (__linux)
507 sprintf(sansa->diskname,"/dev/sd%c",'a'+i);
508 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
509 || defined(__bsdi__) || defined(__DragonFly__)
510 sprintf(sansa->diskname,"/dev/da%d",i);
511 #elif defined(__APPLE__) && defined(__MACH__)
512 sprintf(sansa->diskname,"/dev/disk%d",i);
513 #else
514 #error No disk paths defined for this platform
515 #endif
516 if ((result = sansa_open(sansa, 1)) < 0) {
517 if(result == -2) {
518 denied++;
520 sansa_close(sansa);
521 continue;
524 if (sansa_read_partinfo(sansa,1) < 0) {
525 sansa_close(sansa);
526 continue;
529 if (is_sansa(sansa) < 0) {
530 continue;
531 sansa_close(sansa);
534 #ifdef __WIN32__
535 printf("[INFO] %s found - disk device %d\n",sansa->targetname, i);
536 #else
537 printf("[INFO] %s found - %s\n",sansa->targetname, sansa->diskname);
538 #endif
539 n++;
540 strcpy(last_disk,sansa->diskname);
541 sansa_close(sansa);
544 if (n==1) {
545 /* Remember the disk name */
546 strcpy(sansa->diskname,last_disk);
548 else if (n == 0 && denied) {
549 printf("[ERR] FATAL: Permission denied on %d device(s) and no sansa detected.\n", denied);
550 #ifdef __WIN32__
551 printf("[ERR] You need to run this program with administrator priviledges!\n");
552 #else
553 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
554 #endif
557 return (n == 0 && denied) ? -1 : n;
560 /* Prepare original firmware for writing to the firmware partition by decrypting
561 and updating the header */
562 static int prepare_original_firmware(struct sansa_t* sansa, unsigned char* buf, struct mi4header_t* mi4header)
564 unsigned char* tmpbuf;
565 int i;
566 int key_found;
568 get_mi4header(buf,mi4header);
570 #if 0
571 printf("mi4header->version =0x%08x\n",mi4header->version);
572 printf("mi4header->length =0x%08x\n",mi4header->length);
573 printf("mi4header->crc32 =0x%08x\n",mi4header->crc32);
574 printf("mi4header->enctype =0x%08x\n",mi4header->enctype);
575 printf("mi4header->mi4size =0x%08x\n",mi4header->mi4size);
576 printf("mi4header->plaintext =0x%08x\n",mi4header->plaintext);
577 #endif
579 /* Decrypt anything that needs decrypting. */
580 if (mi4header->plaintext < mi4header->mi4size - 0x200) {
581 /* TODO: Check different keys */
582 tmpbuf=malloc(mi4header->mi4size-(mi4header->plaintext+0x200));
583 if (tmpbuf==NULL) {
584 fprintf(stderr,"[ERR] Can not allocate memory\n");
585 return -1;
588 key_found=0;
589 for (i=0; i < NUM_KEYS && !key_found ; i++) {
590 tea_decrypt_buf(buf+(mi4header->plaintext+0x200),
591 tmpbuf,
592 mi4header->mi4size-(mi4header->plaintext+0x200),
593 keys[i]);
594 key_found = (le2uint(tmpbuf+mi4header->length-mi4header->plaintext-4) == 0xaa55aa55);
597 if (key_found) {
598 memcpy(buf+(mi4header->plaintext+0x200),tmpbuf,mi4header->mi4size-(mi4header->plaintext+0x200));
599 free(tmpbuf);
600 } else {
601 fprintf(stderr,"[ERR] Failed to decrypt image, aborting\n");
602 free(tmpbuf);
603 return -1;
607 /* Increase plaintext value to full file */
608 mi4header->plaintext = mi4header->mi4size - 0x200;
610 /* Update CRC checksum */
611 chksum_crc32gentab ();
612 mi4header->crc32 = chksum_crc32(buf+0x200,mi4header->mi4size-0x200);
614 set_mi4header(buf,mi4header);
616 /* Add Rockbox-specific header */
617 memcpy(buf+0x1f8,"RBOF",4);
618 memcpy(buf+0x1fc,sansa->targetname,4);
620 return 0;
623 static int load_original_firmware(struct sansa_t* sansa, unsigned char* buf, struct mi4header_t* mi4header)
625 int ppmi_length;
626 int n;
628 /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */
629 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET, buf, 512) < 0) {
630 return -1;
633 /* No need to check PPMI magic - it's done during init to confirm
634 this is an E200 */
635 ppmi_length = le2int(buf+4);
637 /* Firstly look for an original firmware after the first image */
638 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, buf, 512) < 0) {
639 return -1;
642 if (get_mi4header(buf,mi4header)==0) {
643 /* We have a valid MI4 file after a bootloader, so we use this. */
644 if ((n = sansa_seek_and_read(sansa,
645 sansa->start + PPMI_OFFSET + 0x200 + ppmi_length,
646 buf, mi4header->mi4size)) < 0) {
647 return -1;
649 } else {
650 /* No valid MI4 file, so read the first image. */
651 if ((n = sansa_seek_and_read(sansa,
652 sansa->start + PPMI_OFFSET + 0x200,
653 buf, ppmi_length)) < 0) {
654 return -1;
657 return prepare_original_firmware(sansa, buf, mi4header);
660 int sansa_read_firmware(struct sansa_t* sansa, const char* filename)
662 int res;
663 int outfile;
664 struct mi4header_t mi4header;
666 res = load_original_firmware(sansa,sansa_sectorbuf,&mi4header);
667 if (res < 0)
668 return res;
670 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
671 if (outfile < 0) {
672 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
673 return -1;
676 res = write(outfile,sansa_sectorbuf,mi4header.mi4size);
677 if (res != (int)mi4header.mi4size) {
678 fprintf(stderr,"[ERR] Write error - %d\n", res);
679 return -1;
681 close(outfile);
683 return 0;
687 int sansa_add_bootloader(struct sansa_t* sansa, const char* filename, int type)
689 int res;
690 int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
691 int bl_length = 0; /* Keep gcc happy when building for rbutil */
692 struct mi4header_t mi4header;
693 int n;
694 int length;
696 if (type==FILETYPE_MI4) {
697 /* Step 1 - read bootloader into RAM. */
698 infile=open(filename,O_RDONLY|O_BINARY);
699 if (infile < 0) {
700 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
701 return -1;
704 bl_length = filesize(infile);
705 } else {
706 #ifndef RBUTIL
707 if (strcmp(sansa->targetname,"c200") == 0) {
708 bl_length = LEN_bootimg_c200;
709 } else {
710 bl_length = LEN_bootimg_e200;
712 #endif
715 /* Create PPMI header */
716 memset(sansa_sectorbuf,0,0x200);
717 memcpy(sansa_sectorbuf,"PPMI",4);
718 int2le(bl_length, sansa_sectorbuf+4);
719 int2le(0x00020000, sansa_sectorbuf+8);
721 if (type==FILETYPE_MI4) {
722 /* Read bootloader into sansa_sectorbuf+0x200 */
723 n = read(infile,sansa_sectorbuf+0x200,bl_length);
724 close(infile);
725 if (n < bl_length) {
726 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
727 ,bl_length,n);
728 return -1;
731 if (memcmp(sansa_sectorbuf+0x200+0x1f8,"RBBL",4)!=0) {
732 fprintf(stderr,"[ERR] %s is not a Rockbox bootloader, aborting.\n",
733 filename);
734 return -1;
736 } else {
737 #ifndef RBUTIL
738 if (strcmp(sansa->targetname,"c200") == 0) {
739 memcpy(sansa_sectorbuf+0x200,bootimg_c200,LEN_bootimg_c200);
740 } else {
741 memcpy(sansa_sectorbuf+0x200,bootimg_e200,LEN_bootimg_e200);
743 #endif
746 /* Load original firmware from Sansa to the space after the bootloader */
747 res = load_original_firmware(sansa,sansa_sectorbuf+0x200+bl_length,&mi4header);
748 if (res < 0)
749 return res;
751 /* Now write the whole thing back to the Sansa */
753 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET) < 0) {
754 fprintf(stderr,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
755 sansa->start+PPMI_OFFSET);
756 return -5;
759 length = 0x200 + bl_length + mi4header.mi4size;
761 n=sansa_write(sansa, sansa_sectorbuf, length);
762 if (n < length) {
763 fprintf(stderr,"[ERR] Short write in add_bootloader\n");
764 return -6;
767 return 0;
770 int sansa_delete_bootloader(struct sansa_t* sansa)
772 int res;
773 struct mi4header_t mi4header;
774 int n;
775 int length;
777 /* Load original firmware from Sansa to sansa_sectorbuf+0x200 */
778 res = load_original_firmware(sansa,sansa_sectorbuf+0x200,&mi4header);
779 if (res < 0)
780 return res;
782 /* Create PPMI header */
783 memset(sansa_sectorbuf,0,0x200);
784 memcpy(sansa_sectorbuf,"PPMI",4);
785 int2le(mi4header.mi4size, sansa_sectorbuf+4);
786 int2le(0x00020000, sansa_sectorbuf+8);
788 /* Now write the whole thing back to the Sansa */
790 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET) < 0) {
791 fprintf(stderr,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
792 sansa->start+PPMI_OFFSET);
793 return -5;
796 length = 0x200 + mi4header.mi4size;
798 n=sansa_write(sansa, sansa_sectorbuf, length);
799 if (n < length) {
800 fprintf(stderr,"[ERR] Short write in delete_bootloader\n");
801 return -6;
804 return 0;
807 /** List number of MI4 images on the player, return number.
809 int sansa_list_images(struct sansa_t* sansa)
811 struct mi4header_t mi4header;
812 loff_t ppmi_length;
813 int num = 0;
815 /* Check Main firmware header */
816 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sansa_sectorbuf, 0x200) < 0) {
817 return 0;
820 ppmi_length = le2int(sansa_sectorbuf+4);
822 printf("[INFO] Image 1 - %llu bytes\n",ppmi_length);
823 num = 1;
825 /* Look for an original firmware after the first image */
826 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, sansa_sectorbuf, 512) < 0) {
827 return 0;
830 if (get_mi4header(sansa_sectorbuf,&mi4header)==0) {
831 printf("[INFO] Image 2 - %d bytes\n",mi4header.mi4size);
832 num = 2;
834 return num;
837 int sansa_update_of(struct sansa_t* sansa, const char* filename)
839 int n;
840 int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
841 int of_length = 0; /* Keep gcc happy when building for rbutil */
842 int ppmi_length;
843 struct mi4header_t mi4header;
844 unsigned char buf[512];
846 /* Step 1 - check we have an OF on the Sansa to upgrade. We expect the
847 Rockbox bootloader to be installed and the OF to be after it on disk. */
849 /* Read 512 bytes from PPMI_OFFSET - the PPMI header */
850 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET,
851 buf, 512) < 0) {
852 return -1;
855 /* No need to check PPMI magic - it's done during init to confirm
856 this is an E200 */
857 ppmi_length = le2int(buf+4);
859 /* Look for an original firmware after the first image */
860 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET+0x200+ppmi_length,
861 buf, 512) < 0) {
862 return -1;
865 if (get_mi4header(buf,&mi4header)!=0) {
866 /* We don't have a valid MI4 file after a bootloader, so do nothing. */
867 fprintf(stderr,"[ERR] No original firmware found at 0x%08llx\n",
868 sansa->start+PPMI_OFFSET+0x200+ppmi_length);
869 return -1;
872 /* Step 2 - read OF into RAM. */
873 infile=open(filename,O_RDONLY|O_BINARY);
874 if (infile < 0) {
875 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
876 return -1;
879 of_length = filesize(infile);
881 /* Load original firmware from file */
882 memset(sansa_sectorbuf,0,0x200);
883 n = read(infile,sansa_sectorbuf,of_length);
884 close(infile);
885 if (n < of_length) {
886 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
887 , of_length, n);
888 return -1;
891 /* Check we have a valid MI4 file. */
892 if (get_mi4header(sansa_sectorbuf,&mi4header)!=0) {
893 fprintf(stderr,"[ERR] %s is not a valid mi4 file\n",filename);
894 return -1;
897 /* Decrypt and build the header */
898 if(prepare_original_firmware(sansa, sansa_sectorbuf, &mi4header)!=0){
899 fprintf(stderr,"[ERR] Unable to build decrypted mi4 from %s\n"
900 ,filename);
901 return -1;
904 /* Step 3 - write the OF to the Sansa */
905 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET+0x200+ppmi_length) < 0) {
906 fprintf(stderr,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
907 sansa->start+PPMI_OFFSET+0x200+ppmi_length);
908 return -1;
911 n=sansa_write(sansa, sansa_sectorbuf, of_length);
912 if (n < of_length) {
913 fprintf(stderr,"[ERR] Short write in sansa_update_of\n");
914 return -1;
917 /* Step 4 - zero out the nvparams section - we have to do this or we end up
918 with multiple copies of the nvparams data and don't know which one to
919 work with for the database rebuild disabling trick in our bootloader */
920 if (strcmp(sansa->targetname,"e200") == 0) {
921 printf("[INFO] Resetting Original Firmware settings\n");
922 if (sansa_seek(sansa, sansa->start+NVPARAMS_OFFSET+0x200) < 0) {
923 fprintf(stderr,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
924 sansa->start+NVPARAMS_OFFSET+0x200);
925 return -1;
928 memset(sansa_sectorbuf,0,NVPARAMS_SIZE);
929 n=sansa_write(sansa, sansa_sectorbuf, NVPARAMS_SIZE);
930 if (n < NVPARAMS_SIZE) {
931 fprintf(stderr,"[ERR] Short write in sansa_update_of\n");
932 return -1;
936 return 0;
939 /* Update the PPBL (bootloader) image in the hidden firmware partition */
940 int sansa_update_ppbl(struct sansa_t* sansa, const char* filename)
942 int n;
943 int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
944 int ppbl_length = 0; /* Keep gcc happy when building for rbutil */
946 /* Step 1 - read bootloader into RAM. */
947 infile=open(filename,O_RDONLY|O_BINARY);
948 if (infile < 0) {
949 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
950 return -1;
953 ppbl_length = filesize(infile);
955 n = read(infile,sansa_sectorbuf+0x200,ppbl_length);
956 close(infile);
957 if (n < ppbl_length) {
958 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", ppbl_length, n);
959 return -1;
962 /* Step 2 - Build the header */
963 memset(sansa_sectorbuf,0,0x200);
964 memcpy(sansa_sectorbuf,"PPBL",4);
965 int2le(ppbl_length, sansa_sectorbuf+4);
966 int2le(0x00010000, sansa_sectorbuf+8);
968 /* Step 3 - write the bootloader to the Sansa */
969 if (sansa_seek(sansa, sansa->start) < 0) {
970 fprintf(stderr,"[ERR] Seek to 0x%08llx in sansa_update_ppbl failed.\n", sansa->start);
971 return -1;
974 n=sansa_write(sansa, sansa_sectorbuf, ppbl_length + 0x200);
975 if (n < (ppbl_length+0x200)) {
976 fprintf(stderr,"[ERR] Short write in sansa_update_ppbl\n");
977 return -1;
980 return 0;