1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 - 2007 by Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
26 #include "gigabeats.h"
28 #include "telechips.h"
30 int iaudio_encode(char *iname
, char *oname
, char *idstring
);
31 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
);
35 ARCHOS_PLAYER
, /* and V1 recorder */
44 0x32000, /* ARCHOS_PLAYER */
45 0x64000, /* ARCHOS_V2RECORDER */
46 0x64000, /* ARCHOS_FMRECORDER */
47 0x64000, /* ARCHOS_ONDIO_SP */
48 0x64000 /* ARCHOS_ONDIO_FM */
51 void short2le(unsigned short val
, unsigned char* addr
)
54 addr
[1] = (val
>> 8) & 0xff;
57 unsigned int le2int(unsigned char* buf
)
59 unsigned int res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
64 void int2le(unsigned int val
, unsigned char* addr
)
67 addr
[1] = (val
>> 8) & 0xff;
68 addr
[2] = (val
>> 16) & 0xff;
69 addr
[3] = (val
>> 24) & 0xff;
72 void int2be(unsigned int val
, unsigned char* addr
)
74 addr
[0] = (val
>> 24) & 0xff;
75 addr
[1] = (val
>> 16) & 0xff;
76 addr
[2] = (val
>> 8) & 0xff;
82 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
84 "\t-fm Archos FM recorder format\n"
85 "\t-v2 Archos V2 recorder format\n"
86 "\t-ofm Archos Ondio FM recorder format\n"
87 "\t-osp Archos Ondio SP format\n"
88 "\t-neo SSI Neo format\n"
89 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
90 "\t-iriver iRiver format\n"
91 "\t-iaudiox5 iAudio X5 format\n"
92 "\t-iaudiox5v iAudio X5V format\n"
93 "\t-iaudiom5 iAudio M5 format\n"
94 "\t-ipod3g ipod firmware partition format (3rd Gen)\n"
95 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
96 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
97 "\t-zvm Zen Vision:M FRESCUE structure format\n"
98 "\t-gigabeat Toshiba Gigabeat F/X format\n"
99 "\t-gigabeats Toshiba Gigabeat S format\n"
100 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
101 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
102 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
103 "\t All mi4 options take two optional arguments:\n"
104 "\t -model=XXXX where XXXX is the model id string\n"
105 "\t -type=XXXX where XXXX is a string indicating the \n"
106 "\t type of binary, eg. RBOS, RBBL\n"
107 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
108 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
109 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
110 "\t ip3g, ip4g, mini, iax5, h10, h10_5gb, tpj2,\n"
111 "\t c200, e200, giga, gigs, m100, m500, d2)\n"
112 "\nNo option results in Archos standard player/recorder format.\n");
117 int main (int argc
, char** argv
)
119 unsigned long length
,i
,slen
;
120 unsigned char *inbuf
,*outbuf
;
121 unsigned short crc
=0;
122 unsigned long chksum
=0; /* 32 bit checksum */
123 unsigned char header
[24];
124 char *iname
= argv
[1];
125 char *oname
= argv
[2];
130 unsigned long modelnum
;
133 enum { none
, scramble
, xor, tcc_sum
, tcc_crc
, add
} method
= scramble
;
135 model_id
= ARCHOS_PLAYER
;
141 if(!strcmp(argv
[1], "-fm")) {
146 model_id
= ARCHOS_FMRECORDER
;
149 else if(!strcmp(argv
[1], "-v2")) {
154 model_id
= ARCHOS_V2RECORDER
;
157 else if(!strcmp(argv
[1], "-ofm")) {
162 model_id
= ARCHOS_ONDIO_FM
;
165 else if(!strcmp(argv
[1], "-osp")) {
170 model_id
= ARCHOS_ONDIO_SP
;
173 else if(!strcmp(argv
[1], "-neo")) {
179 else if(!strncmp(argv
[1], "-mm=", 4)) {
184 version
= argv
[1][4];
188 printf("Multimedia needs an xor string\n");
192 else if(!strncmp(argv
[1], "-tcc=", 4)) {
197 if(!strcmp(&argv
[1][5], "sum"))
199 else if(!strcmp(&argv
[1][5], "crc"))
202 fprintf(stderr
, "unsupported TCC method: %s\n", &argv
[1][5]);
206 else if(!strncmp(argv
[1], "-add=", 5)) {
211 if(!strcmp(&argv
[1][5], "h120"))
213 else if(!strcmp(&argv
[1][5], "h140"))
214 modelnum
= 0; /* the same as the h120 */
215 else if(!strcmp(&argv
[1][5], "h100"))
217 else if(!strcmp(&argv
[1][5], "h300"))
219 else if(!strcmp(&argv
[1][5], "ipco"))
221 else if(!strcmp(&argv
[1][5], "nano"))
223 else if(!strcmp(&argv
[1][5], "ipvd"))
225 else if(!strcmp(&argv
[1][5], "fp7x"))
227 else if(!strcmp(&argv
[1][5], "ip3g"))
229 else if(!strcmp(&argv
[1][5], "ip4g"))
231 else if(!strcmp(&argv
[1][5], "mini"))
233 else if(!strcmp(&argv
[1][5], "iax5"))
235 else if(!strcmp(&argv
[1][5], "mn2g"))
237 else if(!strcmp(&argv
[1][5], "h10"))
239 else if(!strcmp(&argv
[1][5], "h10_5gb"))
241 else if(!strcmp(&argv
[1][5], "tpj2"))
243 else if(!strcmp(&argv
[1][5], "e200"))
245 else if(!strcmp(&argv
[1][5], "iam5"))
247 else if(!strcmp(&argv
[1][5], "giga"))
249 else if(!strcmp(&argv
[1][5], "1g2g"))
251 else if(!strcmp(&argv
[1][5], "c200"))
253 else if(!strcmp(&argv
[1][5], "gigs"))
255 else if(!strcmp(&argv
[1][5], "m500"))
257 else if(!strcmp(&argv
[1][5], "m100"))
259 else if(!strcmp(&argv
[1][5], "d2"))
262 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
265 /* we store a 4-letter model name too, for humans */
266 strcpy(modelname
, &argv
[1][5]);
267 chksum
= modelnum
; /* start checksum calcs with this */
270 else if(!strcmp(argv
[1], "-iriver")) {
271 /* iRiver code dealt with in the iriver.c code */
274 iriver_encode(iname
, oname
, FALSE
);
277 else if(!strcmp(argv
[1], "-gigabeat")) {
278 /* iRiver code dealt with in the iriver.c code */
281 gigabeat_code(iname
, oname
);
284 else if(!strcmp(argv
[1], "-gigabeats")) {
287 gigabeat_s_code(iname
, oname
);
290 else if(!strcmp(argv
[1], "-iaudiox5")) {
293 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
295 else if(!strcmp(argv
[1], "-iaudiox5v")) {
298 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
300 else if(!strcmp(argv
[1], "-iaudiom5")) {
303 return iaudio_encode(iname
, oname
, "COWON_M5_FW");
305 else if(!strcmp(argv
[1], "-ipod3g")) {
308 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
310 else if(!strcmp(argv
[1], "-ipod4g")) {
313 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
315 else if(!strcmp(argv
[1], "-ipod5g")) {
318 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
320 else if(!strcmp(argv
[1], "-zvm")) {
323 return zvm_encode(iname
, oname
);
325 else if(!strncmp(argv
[1], "-mi4", 4)) {
331 if(!strcmp(&argv
[1][4], "v2")) {
332 mi4magic
= MI4_MAGIC_DEFAULT
;
333 version
= 0x00010201;
335 else if(!strcmp(&argv
[1][4], "v3")) {
336 mi4magic
= MI4_MAGIC_DEFAULT
;
337 version
= 0x00010301;
339 else if(!strcmp(&argv
[1][4], "r")) {
340 mi4magic
= MI4_MAGIC_R
;
341 version
= 0x00010301;
344 printf( "Invalid mi4 version: %s\n", &argv
[1][4]);
351 if(!strncmp(argv
[2], "-model=", 7)) {
354 strncpy(model
, &argv
[2][7], 4);
356 if(!strncmp(argv
[3], "-type=", 6)) {
359 strncpy(type
, &argv
[3][6], 4);
363 return mi4_encode(iname
, oname
, version
, mi4magic
, model
, type
);
367 file
= fopen(iname
,"rb");
372 fseek(file
,0,SEEK_END
);
373 length
= ftell(file
);
374 length
= (length
+ 3) & ~3; /* Round up to nearest 4 byte boundary */
376 if ((method
== scramble
) &&
377 ((length
+ headerlen
) >= size_limit
[model_id
])) {
378 printf("error: firmware image is %d bytes while max size is %d!\n",
380 size_limit
[model_id
]);
385 fseek(file
,0,SEEK_SET
);
386 inbuf
= malloc(length
);
388 outbuf
= malloc(length
*2);
389 else if(method
== add
)
390 outbuf
= malloc(length
+ 8);
392 outbuf
= malloc(length
);
393 if ( !inbuf
|| !outbuf
) {
394 printf("out of memory!\n");
398 /* zero-fill the last 4 bytes to make sure there's no rubbish there
399 when we write the size-aligned file later */
400 memset(outbuf
+length
-4, 0, 4);
404 i
=fread(inbuf
,1,length
,file
);
414 for (i
= 0; i
< length
; i
++) {
415 /* add 8 unsigned bits but keep a 32 bit sum */
421 for (i
= 0; i
< length
; i
++) {
422 unsigned long addr
= (i
>> 2) + ((i
% 4) * slen
);
423 unsigned char data
= inbuf
[i
];
424 data
= ~((data
<< 1) | ((data
>> 7) & 1)); /* poor man's ROL */
432 for (i
=0; i
<length
; i
++) {
434 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
435 outbuf
[slen
++] = inbuf
[i
];
440 if((method
== none
) || (method
== scramble
) || (method
== xor)) {
441 /* calculate checksum */
442 for (i
=0;i
<length
;i
++)
446 memset(header
, 0, sizeof header
);
451 int2be(chksum
, header
); /* checksum, big-endian */
452 memcpy(&header
[4], modelname
, 4); /* 4 bytes model name */
453 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
459 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
460 telechips_encode_sum(outbuf
, length
);
464 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
465 telechips_encode_crc(outbuf
, length
);
469 if (headerlen
== 6) {
470 int2be(length
, header
);
471 header
[4] = (crc
>> 8) & 0xff;
472 header
[5] = crc
& 0xff;
478 header
[3] = 0xff; /* ??? */
480 header
[6] = (crc
>> 8) & 0xff;
481 header
[7] = crc
& 0xff;
483 header
[11] = version
;
485 header
[15] = headerlen
; /* really? */
487 int2be(length
, &header
[20]);
493 int xorlen
= strlen(xorstring
);
496 for (i
=0; i
<slen
; i
++)
497 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
499 /* calculate checksum */
500 for (i
=0; i
<slen
; i
++)
503 header
[0] = header
[2] = 'Z';
504 header
[1] = header
[3] = version
;
505 int2le(length
, &header
[4]);
506 int2le(slen
, &header
[8]);
507 int2le(crc
, &header
[12]);
512 #define MY_FIRMWARE_TYPE "Rockbox"
513 #define MY_HEADER_VERSION 1
515 strncpy((char *)header
, MY_FIRMWARE_TYPE
,9);
516 header
[9]='\0'; /*shouldn't have to, but to be SURE */
517 header
[10]=MY_HEADER_VERSION
&0xFF;
518 header
[11]=(crc
>>8)&0xFF;
520 int2be(sizeof(header
), &header
[12]);
525 file
= fopen(oname
,"wb");
531 if ( !fwrite(header
,headerlen
,1,file
) ) {
536 if ( !fwrite(outbuf
,length
,1,file
) ) {
548 int iaudio_encode(char *iname
, char *oname
, char *idstring
)
553 unsigned char *outbuf
;
555 unsigned char sum
= 0;
557 file
= fopen(iname
, "rb");
562 fseek(file
,0,SEEK_END
);
563 length
= ftell(file
);
565 fseek(file
,0,SEEK_SET
);
566 outbuf
= malloc(length
+0x1030);
569 printf("out of memory!\n");
573 len
= fread(outbuf
+0x1030, 1, length
, file
);
579 memset(outbuf
, 0, 0x1030);
580 strcpy((char *)outbuf
, idstring
);
582 for(i
= 0; i
< length
;i
++)
583 sum
+= outbuf
[0x1030 + i
];
585 int2be(length
, &outbuf
[0x1024]);
586 outbuf
[0x102b] = sum
;
590 file
= fopen(oname
, "wb");
596 len
= fwrite(outbuf
, 1, length
+0x1030, file
);
606 /* Create an ipod firmware partition image
608 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
610 This function doesn't yet handle the Broadcom resource image for the 5g,
611 so the resulting images won't be usable.
613 This has also only been tested on an ipod Photo
616 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
)
618 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
639 unsigned int sum
= 0;
640 unsigned int rsrcsum
= 0;
641 unsigned char *outbuf
;
645 file
= fopen(iname
, "rb");
650 fseek(file
,0,SEEK_END
);
651 length
= ftell(file
);
653 fseek(file
,0,SEEK_SET
);
655 bufsize
=(length
+0x4600);
657 bufsize
= (bufsize
+ 0x400) & ~0x200;
660 outbuf
= malloc(bufsize
);
663 printf("out of memory!\n");
667 len
= fread(outbuf
+0x4600, 1, length
, file
);
674 /* Calculate checksum for later use in header */
675 for(i
= 0x4600; i
< 0x4600+length
;i
++)
678 /* Clear the header area to zero */
679 memset(outbuf
, 0, 0x4600);
681 /* APPLE STOP SIGN */
682 strcpy((char *)outbuf
, apple_stop_sign
);
685 memcpy(&outbuf
[0x100],"]ih[",4); /* Magic */
686 int2le(0x4000, &outbuf
[0x104]); /* Firmware offset relative to 0x200 */
687 short2le(0x10c, &outbuf
[0x108]); /* Location of extended header */
688 short2le(fw_ver
, &outbuf
[0x10a]);
690 /* Firmware Directory - "osos" entry */
691 memcpy(&outbuf
[0x4200],"!ATAsoso",8); /* dev and type */
692 int2le(0, &outbuf
[0x4208]); /* id */
693 int2le(0x4400, &outbuf
[0x420c]); /* devOffset */
694 int2le(length
, &outbuf
[0x4210]); /* Length of firmware */
695 int2le(0x10000000, &outbuf
[0x4214]); /* Addr */
696 int2le(0, &outbuf
[0x4218]); /* Entry Offset */
697 int2le(sum
, &outbuf
[0x421c]); /* Checksum */
698 int2le(0x00006012, &outbuf
[0x4220]); /* vers - 0x6012 is a guess */
699 int2le(0xffffffff, &outbuf
[0x4224]); /* LoadAddr - for flash images */
701 /* "rsrc" entry (if applicable) */
703 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
707 memcpy(&outbuf
[0x4228],"!ATAcrsr",8); /* dev and type */
708 int2le(0, &outbuf
[0x4230]); /* id */
709 int2le(rsrcoffset
, &outbuf
[0x4234]); /* devOffset */
710 int2le(rsrclength
, &outbuf
[0x4238]); /* Length of firmware */
711 int2le(0x10000000, &outbuf
[0x423c]); /* Addr */
712 int2le(0, &outbuf
[0x4240]); /* Entry Offset */
713 int2le(rsrcsum
, &outbuf
[0x4244]); /* Checksum */
714 int2le(0x0000b000, &outbuf
[0x4248]); /* vers */
715 int2le(0xffffffff, &outbuf
[0x424c]); /* LoadAddr - for flash images */
718 file
= fopen(oname
, "wb");
724 len
= fwrite(outbuf
, 1, length
+0x4600, file
);
736 /* Create an Zen Vision:M FRESCUE structure file
739 int zvm_encode(char *iname
, char *oname
)
744 unsigned int sum
= 0;
745 unsigned char *outbuf
;
748 file
= fopen(iname
, "rb");
753 fseek(file
,0,SEEK_END
);
754 length
= ftell(file
);
756 fseek(file
,0,SEEK_SET
);
758 outbuf
= malloc(length
+0x18+0x10);
761 printf("out of memory!\n");
765 len
= fread(outbuf
+0x18, 1, length
, file
);
772 /* Calculate checksum for later use in header */
773 for(i
=0; i
<length
; i
+= 4)
774 sum
+= le2int(&outbuf
[0x18+i
]) + (le2int(&outbuf
[0x18+i
])>>16);
776 /* Clear the header area to zero */
777 memset(outbuf
, 0, 0x18);
780 memcpy((char*)outbuf
, "EDOC", 4);
782 int2le(length
+0x20, &outbuf
[0x4]);
783 /* 4 bytes of zero */
785 /* Address = 0x900000 */
786 int2le(0x900000, &outbuf
[0xC]);
788 int2le(length
, &outbuf
[0x10]);
790 int2le(sum
, &outbuf
[0x14]);
793 /* Data starts here... */
795 /* Second block starts here ... */
798 int2le(0x4, &outbuf
[0x18+length
+0x4]);
800 outbuf
[0x18+length
+0x8] = 0xB7;
801 outbuf
[0x18+length
+0x9] = 0xD5;
802 /* Data: LDR PC, =0x900000 */
803 outbuf
[0x18+length
+0xC] = 0x18;
804 outbuf
[0x18+length
+0xD] = 0xF0;
805 outbuf
[0x18+length
+0xE] = 0x9F;
806 outbuf
[0x18+length
+0xF] = 0xE5;
809 file
= fopen(oname
, "wb");
815 len
= fwrite(outbuf
, 1, length
+0x28, file
);
816 if(len
< length
+0x18) {