summaryrefslogtreecommitdiff
path: root/tools/fwpatcher/iriver.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/fwpatcher/iriver.c')
-rw-r--r--tools/fwpatcher/iriver.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/tools/fwpatcher/iriver.c b/tools/fwpatcher/iriver.c
new file mode 100644
index 0000000000..e24df8c768
--- /dev/null
+++ b/tools/fwpatcher/iriver.c
@@ -0,0 +1,393 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 by Dave Hooper
11 *
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.
14 *
15 * Original code from http://www.beermex.com/@spc/ihpfirm.src.zip
16 * Details at http://www.rockbox.org/twiki/bin/view/Main/IriverToolsGuide
17 *
18 ****************************************************************************/
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "iriver.h"
24
25const unsigned char munge[] = {
26 0x7a, 0x36, 0xc4, 0x43, 0x49, 0x6b, 0x35, 0x4e, 0xa3, 0x46, 0x25, 0x84,
27 0x4d, 0x73, 0x74, 0x61
28};
29
30const unsigned char header_modify[] = "* IHPFIRM-DECODED ";
31
32const char * const models[] = { "iHP-100", "iHP-120/iHP-140", "H300 series",
33 NULL };
34
35/* aligns with models array; expected min firmware size */
36const unsigned int firmware_minsize[] = { 0x100000, 0x100000, 0x200000 };
37/* aligns with models array; expected max firmware size */
38const unsigned int firmware_maxsize[] = { 0x200000, 0x200000, 0x400000 };
39
40const 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 }
46};
47
48static int testheader( const unsigned char * const data )
49{
50 const unsigned char * const d = data+16;
51 const char * const * m = models;
52 int index = 0;
53 while( *m )
54 {
55 if( memcmp( header[ index ], d, 16 ) == 0 )
56 return index;
57 index++;
58 m++;
59 };
60 return -1;
61};
62
63static void modifyheader( unsigned char * data )
64{
65 const unsigned char * h = header_modify;
66 int i;
67 for( i=0; i<512; i++ )
68 {
69 if( *h == '\0' )
70 h = header_modify;
71 *data++ ^= *h++;
72 };
73};
74
75static FILE * openinfile( const TCHAR * filename )
76{
77 FILE * F = _tfopen( filename, TEXT("rb") );
78 if( F == NULL )
79 {
80 fprintf( stderr, "Couldn't open input file %s\n", filename );
81 perror( "Error was " );
82 };
83 return F;
84};
85
86static FILE * openoutfile( const TCHAR * filename )
87{
88 FILE * F = _tfopen( filename, TEXT("wb") );
89 if( F == NULL )
90 {
91 fprintf( stderr, "Couldn't open output file %s\n", filename );
92 perror( "Error was " );
93 };
94 return F;
95};
96
97int iriver_decode(TCHAR *infile_name, TCHAR *outfile_name, unsigned int modify,
98 enum striptype stripmode )
99{
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;
112
113 infile = openinfile(infile_name);
114 outfile = openoutfile(outfile_name);
115 if (!infile || !outfile) return -1;
116
117 lenread = fread( headerdata, 1, 512, infile );
118 if( lenread != 512 )
119 {
120 fprintf( stderr, "This doesn't look like a valid encrypted iHP "
121 "firmware - reason: header length\n" );
122 goto error;
123 };
124
125 i = testheader( headerdata );
126 if( i == -1 )
127 {
128 fprintf( stderr, "This firmware is for an unknown model, or is not"
129 " a valid encrypted iHP firmware\n" );
130 goto error;
131 };
132 fprintf( stderr, "Model %s\n", models[ i ] );
133
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);
140
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 )
148 {
149 fprintf( stderr, "This doesn't look like a valid encrypted "
150 "iHP firmware - reason: file 'length' data\n" );
151 goto error;
152 };
153
154 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) );
155
156 if( modify )
157 {
158 modifyheader( headerdata );
159 };
160
161 if( stripmode == STRIP_NONE )
162 fwrite( headerdata, 512, 1, outfile );
163
164 memset( blockdata, 0, 16 );
165
166 ck = 0;
167 while( ( fp < dwLength2 ) &&
168 ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 )
169 {
170 fp += 16;
171
172 for( i=0; i<16; ++i )
173 {
174 newmunge = blockdata[16+i] ^ munge[i];
175 out[i] = newmunge ^ blockdata[i];
176 blockdata[i] = newmunge;
177 ck += out[i];
178 }
179
180 if( fp > ESTF_SIZE || stripmode != STRIP_HEADER_CHECKSUM_ESTF )
181 {
182 fwrite( out+4, 1, 12, outfile );
183 fwrite( out, 1, 4, outfile );
184 }
185 else
186 {
187 if( ESTF_SIZE - fp < 16 )
188 {
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 );
192 }
193 }
194
195
196 if( s == 496 )
197 {
198 s = 0;
199 memset( blockdata, 0, 16 );
200 *ppChecksums++ = ck;
201 ck = 0;
202 }
203 else
204 s+=16;
205 };
206
207 if( fp != dwLength2 )
208 {
209 fprintf( stderr, "This doesn't look like a valid encrypted "
210 "iHP firmware - reason: 'length2' mismatch\n" );
211 goto error;
212 };
213
214 fp = 0;
215 ppChecksums = pChecksums;
216 while( ( fp < dwLength3 ) &&
217 ( lenread = fread( blockdata, 1, 32, infile ) ) > 0 )
218 {
219 fp += lenread;
220 if( stripmode == STRIP_NONE )
221 fwrite( blockdata, 1, lenread, outfile );
222 if( memcmp( ppChecksums, blockdata, lenread ) != 0 )
223 {
224 fprintf( stderr, "This doesn't look like a valid encrypted "
225 "iHP firmware - reason: Checksum mismatch!" );
226 goto error;
227 };
228 ppChecksums += lenread;
229 };
230
231 if( fp != dwLength3 )
232 {
233 fprintf( stderr, "This doesn't look like a valid encrypted "
234 "iHP firmware - reason: 'length3' mismatch\n" );
235 goto error;
236 };
237
238
239 fprintf( stderr, "File decoded correctly and all checksums matched!\n" );
240 switch( stripmode )
241 {
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;
255 };
256
257 fclose(infile);
258 fclose(outfile);
259 return 0;
260error:
261 fclose(infile);
262 fclose(outfile);
263 return -1;
264};
265
266int iriver_encode(TCHAR *infile_name, TCHAR *outfile_name, unsigned int modify )
267{
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;
280
281 enum striptype stripmode = STRIP_NONE;
282
283 infile = openinfile(infile_name);
284 outfile = openoutfile(outfile_name);
285 if (!infile || !outfile) return -1;
286
287 lenread = fread( headerdata, 1, 512, infile );
288 if( lenread != 512 )
289 {
290 fprintf( stderr, "This doesn't look like a valid decoded "
291 "iHP firmware - reason: header length\n" );
292 goto error;
293 };
294
295 if( modify )
296 {
297 modifyheader( headerdata ); /* reversible */
298 };
299
300 i = testheader( headerdata );
301 if( i == -1 )
302 {
303 fprintf( stderr, "This firmware is for an unknown model, or is not"
304 " a valid decoded iHP firmware\n" );
305 goto error;
306 };
307 fprintf( stderr, "Model %s\n", models[ i ] );
308
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);
315
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 )
322 {
323 fprintf( stderr, "This doesn't look like a valid decoded iHP"
324 " firmware - reason: file 'length' data\n" );
325 goto error;
326 };
327
328 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) );
329
330 fwrite( headerdata, 512, 1, outfile );
331
332 memset( blockdata, 0, 16 );
333 ck = 0;
334 while( ( fp < dwLength2 ) &&
335 ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 )
336 {
337 fp += 16;
338 for( i=0; i<16; ++i )
339 {
340 newmunge = blockdata[16+((12+i)&0xf)] ^ blockdata[i];
341 out[i] = newmunge ^ munge[i];
342 ck += blockdata[16+i];
343 blockdata[i] = newmunge;
344 };
345 fwrite( out, 1, 16, outfile );
346
347 if( s == 496 )
348 {
349 s = 0;
350 memset( blockdata, 0, 16 );
351 *ppChecksums++ = ck;
352 ck = 0;
353 }
354 else
355 s+=16;
356 };
357
358 if( fp != dwLength2 )
359 {
360 fprintf( stderr, "This doesn't look like a valid decoded "
361 "iHP firmware - reason: 'length1' mismatch\n" );
362 goto error;
363 };
364
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 )
371 {
372 fp += lenread;
373 ppChecksums += lenread;
374 lenread = dwLength3 - fp;
375 };
376
377 if( fp != dwLength3 )
378 {
379 fprintf( stderr, "This doesn't look like a valid decoded "
380 "iHP firmware - reason: 'length2' mismatch\n" );
381 goto error;
382 };
383
384 fprintf( stderr, "File encoded successfully and checksum table built!\n" );
385
386 fclose(infile);
387 fclose(outfile);
388 return 0;
389error:
390 fclose(infile);
391 fclose(outfile);
392 return -1;
393};