Sansa C200 bootloader works fine, no need to be verbose anymore
[kugel-rb.git] / tools / fwpatcher / iriver.c
blobe24df8c768d5870d22da25a20d25ab47ff947502
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004 by Dave Hooper
12 * This particular source code file is licensed under the X11 license. See the
13 * bottom of the COPYING file for details on this license.
15 * Original code from http://www.beermex.com/@spc/ihpfirm.src.zip
16 * Details at http://www.rockbox.org/twiki/bin/view/Main/IriverToolsGuide
18 ****************************************************************************/
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include "iriver.h"
25 const unsigned char munge[] = {
26 0x7a, 0x36, 0xc4, 0x43, 0x49, 0x6b, 0x35, 0x4e, 0xa3, 0x46, 0x25, 0x84,
27 0x4d, 0x73, 0x74, 0x61
30 const unsigned char header_modify[] = "* IHPFIRM-DECODED ";
32 const char * const models[] = { "iHP-100", "iHP-120/iHP-140", "H300 series",
33 NULL };
35 /* aligns with models array; expected min firmware size */
36 const unsigned int firmware_minsize[] = { 0x100000, 0x100000, 0x200000 };
37 /* aligns with models array; expected max firmware size */
38 const unsigned int firmware_maxsize[] = { 0x200000, 0x200000, 0x400000 };
40 const unsigned char header[][16] = {
41 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
42 { 0x20, 0x03, 0x08, 0x27, 0x24, 0x00, 0x02, 0x30, 0x19, 0x17, 0x65, 0x73,
43 0x85, 0x32, 0x83, 0x22 },
44 { 0x20, 0x04, 0x03, 0x27, 0x20, 0x50, 0x01, 0x70, 0x80, 0x30, 0x80, 0x06,
45 0x30, 0x19, 0x17, 0x65 }
48 static int testheader( const unsigned char * const data )
50 const unsigned char * const d = data+16;
51 const char * const * m = models;
52 int index = 0;
53 while( *m )
55 if( memcmp( header[ index ], d, 16 ) == 0 )
56 return index;
57 index++;
58 m++;
60 return -1;
63 static void modifyheader( unsigned char * data )
65 const unsigned char * h = header_modify;
66 int i;
67 for( i=0; i<512; i++ )
69 if( *h == '\0' )
70 h = header_modify;
71 *data++ ^= *h++;
75 static FILE * openinfile( const TCHAR * filename )
77 FILE * F = _tfopen( filename, TEXT("rb") );
78 if( F == NULL )
80 fprintf( stderr, "Couldn't open input file %s\n", filename );
81 perror( "Error was " );
83 return F;
86 static FILE * openoutfile( const TCHAR * filename )
88 FILE * F = _tfopen( filename, TEXT("wb") );
89 if( F == NULL )
91 fprintf( stderr, "Couldn't open output file %s\n", filename );
92 perror( "Error was " );
94 return F;
97 int iriver_decode(TCHAR *infile_name, TCHAR *outfile_name, unsigned int modify,
98 enum striptype stripmode )
100 FILE * infile = NULL;
101 FILE * outfile = NULL;
102 int i = -1;
103 unsigned char headerdata[512];
104 unsigned long dwLength1, dwLength2, dwLength3, fp = 0;
105 unsigned char blockdata[16+16];
106 unsigned char out[16];
107 unsigned char newmunge;
108 signed long lenread;
109 int s = 0;
110 unsigned char * pChecksums, * ppChecksums = 0;
111 unsigned char ck;
113 infile = openinfile(infile_name);
114 outfile = openoutfile(outfile_name);
115 if (!infile || !outfile) return -1;
117 lenread = fread( headerdata, 1, 512, infile );
118 if( lenread != 512 )
120 fprintf( stderr, "This doesn't look like a valid encrypted iHP "
121 "firmware - reason: header length\n" );
122 goto error;
125 i = testheader( headerdata );
126 if( i == -1 )
128 fprintf( stderr, "This firmware is for an unknown model, or is not"
129 " a valid encrypted iHP firmware\n" );
130 goto error;
132 fprintf( stderr, "Model %s\n", models[ i ] );
134 dwLength1 = headerdata[0] | (headerdata[1]<<8) |
135 (headerdata[2]<<16) | (headerdata[3]<<24);
136 dwLength2 = headerdata[4] | (headerdata[5]<<8) |
137 (headerdata[6]<<16) | (headerdata[7]<<24);
138 dwLength3 = headerdata[8] | (headerdata[9]<<8) |
139 (headerdata[10]<<16) | (headerdata[11]<<24);
141 if( dwLength1 < firmware_minsize[ i ] ||
142 dwLength1 > firmware_maxsize[ i ] ||
143 dwLength2 < firmware_minsize[ i ] ||
144 dwLength2 > dwLength1 ||
145 dwLength3 > dwLength1 ||
146 dwLength2>>9 != dwLength3 ||
147 dwLength2+dwLength3+512 != dwLength1 )
149 fprintf( stderr, "This doesn't look like a valid encrypted "
150 "iHP firmware - reason: file 'length' data\n" );
151 goto error;
154 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) );
156 if( modify )
158 modifyheader( headerdata );
161 if( stripmode == STRIP_NONE )
162 fwrite( headerdata, 512, 1, outfile );
164 memset( blockdata, 0, 16 );
166 ck = 0;
167 while( ( fp < dwLength2 ) &&
168 ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 )
170 fp += 16;
172 for( i=0; i<16; ++i )
174 newmunge = blockdata[16+i] ^ munge[i];
175 out[i] = newmunge ^ blockdata[i];
176 blockdata[i] = newmunge;
177 ck += out[i];
180 if( fp > ESTF_SIZE || stripmode != STRIP_HEADER_CHECKSUM_ESTF )
182 fwrite( out+4, 1, 12, outfile );
183 fwrite( out, 1, 4, outfile );
185 else
187 if( ESTF_SIZE - fp < 16 )
189 memcpy( out+4, blockdata+16, 12 );
190 memcpy( out, blockdata+28, 4 );
191 fwrite( blockdata+16+ESTF_SIZE-fp, 1, ESTF_SIZE-fp, outfile );
196 if( s == 496 )
198 s = 0;
199 memset( blockdata, 0, 16 );
200 *ppChecksums++ = ck;
201 ck = 0;
203 else
204 s+=16;
207 if( fp != dwLength2 )
209 fprintf( stderr, "This doesn't look like a valid encrypted "
210 "iHP firmware - reason: 'length2' mismatch\n" );
211 goto error;
214 fp = 0;
215 ppChecksums = pChecksums;
216 while( ( fp < dwLength3 ) &&
217 ( lenread = fread( blockdata, 1, 32, infile ) ) > 0 )
219 fp += lenread;
220 if( stripmode == STRIP_NONE )
221 fwrite( blockdata, 1, lenread, outfile );
222 if( memcmp( ppChecksums, blockdata, lenread ) != 0 )
224 fprintf( stderr, "This doesn't look like a valid encrypted "
225 "iHP firmware - reason: Checksum mismatch!" );
226 goto error;
228 ppChecksums += lenread;
231 if( fp != dwLength3 )
233 fprintf( stderr, "This doesn't look like a valid encrypted "
234 "iHP firmware - reason: 'length3' mismatch\n" );
235 goto error;
239 fprintf( stderr, "File decoded correctly and all checksums matched!\n" );
240 switch( stripmode )
242 default:
243 case STRIP_NONE:
244 fprintf(stderr, "Output file contains all headers and "
245 "checksums\n");
246 break;
247 case STRIP_HEADER_CHECKSUM:
248 fprintf( stderr, "NB: output file contains only ESTFBINR header"
249 " and decoded firmware code\n" );
250 break;
251 case STRIP_HEADER_CHECKSUM_ESTF:
252 fprintf( stderr, "NB: output file contains only raw decoded "
253 "firmware code\n" );
254 break;
257 fclose(infile);
258 fclose(outfile);
259 return 0;
260 error:
261 fclose(infile);
262 fclose(outfile);
263 return -1;
266 int iriver_encode(TCHAR *infile_name, TCHAR *outfile_name, unsigned int modify )
268 FILE * infile = NULL;
269 FILE * outfile = NULL;
270 int i = -1;
271 unsigned char headerdata[512];
272 unsigned long dwLength1, dwLength2, dwLength3, fp = 0;
273 unsigned char blockdata[16+16];
274 unsigned char out[16];
275 unsigned char newmunge;
276 signed long lenread;
277 int s = 0;
278 unsigned char * pChecksums, * ppChecksums;
279 unsigned char ck;
281 enum striptype stripmode = STRIP_NONE;
283 infile = openinfile(infile_name);
284 outfile = openoutfile(outfile_name);
285 if (!infile || !outfile) return -1;
287 lenread = fread( headerdata, 1, 512, infile );
288 if( lenread != 512 )
290 fprintf( stderr, "This doesn't look like a valid decoded "
291 "iHP firmware - reason: header length\n" );
292 goto error;
295 if( modify )
297 modifyheader( headerdata ); /* reversible */
300 i = testheader( headerdata );
301 if( i == -1 )
303 fprintf( stderr, "This firmware is for an unknown model, or is not"
304 " a valid decoded iHP firmware\n" );
305 goto error;
307 fprintf( stderr, "Model %s\n", models[ i ] );
309 dwLength1 = headerdata[0] | (headerdata[1]<<8) |
310 (headerdata[2]<<16) | (headerdata[3]<<24);
311 dwLength2 = headerdata[4] | (headerdata[5]<<8) |
312 (headerdata[6]<<16) | (headerdata[7]<<24);
313 dwLength3 = headerdata[8] | (headerdata[9]<<8) |
314 (headerdata[10]<<16) | (headerdata[11]<<24);
316 if( dwLength1 < firmware_minsize[i] ||
317 dwLength1 > firmware_maxsize[i] ||
318 dwLength2 < firmware_minsize[i] ||
319 dwLength2 > dwLength1 ||
320 dwLength3 > dwLength1 ||
321 dwLength2+dwLength3+512 != dwLength1 )
323 fprintf( stderr, "This doesn't look like a valid decoded iHP"
324 " firmware - reason: file 'length' data\n" );
325 goto error;
328 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) );
330 fwrite( headerdata, 512, 1, outfile );
332 memset( blockdata, 0, 16 );
333 ck = 0;
334 while( ( fp < dwLength2 ) &&
335 ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 )
337 fp += 16;
338 for( i=0; i<16; ++i )
340 newmunge = blockdata[16+((12+i)&0xf)] ^ blockdata[i];
341 out[i] = newmunge ^ munge[i];
342 ck += blockdata[16+i];
343 blockdata[i] = newmunge;
345 fwrite( out, 1, 16, outfile );
347 if( s == 496 )
349 s = 0;
350 memset( blockdata, 0, 16 );
351 *ppChecksums++ = ck;
352 ck = 0;
354 else
355 s+=16;
358 if( fp != dwLength2 )
360 fprintf( stderr, "This doesn't look like a valid decoded "
361 "iHP firmware - reason: 'length1' mismatch\n" );
362 goto error;
365 /* write out remainder w/out applying descrambler */
366 fp = 0;
367 lenread = dwLength3;
368 ppChecksums = pChecksums;
369 while( ( fp < dwLength3) &&
370 ( lenread = fwrite( ppChecksums, 1, lenread, outfile ) ) > 0 )
372 fp += lenread;
373 ppChecksums += lenread;
374 lenread = dwLength3 - fp;
377 if( fp != dwLength3 )
379 fprintf( stderr, "This doesn't look like a valid decoded "
380 "iHP firmware - reason: 'length2' mismatch\n" );
381 goto error;
384 fprintf( stderr, "File encoded successfully and checksum table built!\n" );
386 fclose(infile);
387 fclose(outfile);
388 return 0;
389 error:
390 fclose(infile);
391 fclose(outfile);
392 return -1;