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)\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"))
260 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
263 /* we store a 4-letter model name too, for humans */
264 strcpy(modelname
, &argv
[1][5]);
265 chksum
= modelnum
; /* start checksum calcs with this */
268 else if(!strcmp(argv
[1], "-iriver")) {
269 /* iRiver code dealt with in the iriver.c code */
272 iriver_encode(iname
, oname
, FALSE
);
275 else if(!strcmp(argv
[1], "-gigabeat")) {
276 /* iRiver code dealt with in the iriver.c code */
279 gigabeat_code(iname
, oname
);
282 else if(!strcmp(argv
[1], "-gigabeats")) {
285 gigabeat_s_code(iname
, oname
);
288 else if(!strcmp(argv
[1], "-iaudiox5")) {
291 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
293 else if(!strcmp(argv
[1], "-iaudiox5v")) {
296 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
298 else if(!strcmp(argv
[1], "-iaudiom5")) {
301 return iaudio_encode(iname
, oname
, "COWON_M5_FW");
303 else if(!strcmp(argv
[1], "-ipod3g")) {
306 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
308 else if(!strcmp(argv
[1], "-ipod4g")) {
311 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
313 else if(!strcmp(argv
[1], "-ipod5g")) {
316 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
318 else if(!strcmp(argv
[1], "-zvm")) {
321 return zvm_encode(iname
, oname
);
323 else if(!strncmp(argv
[1], "-mi4", 4)) {
329 if(!strcmp(&argv
[1][4], "v2")) {
330 mi4magic
= MI4_MAGIC_DEFAULT
;
331 version
= 0x00010201;
333 else if(!strcmp(&argv
[1][4], "v3")) {
334 mi4magic
= MI4_MAGIC_DEFAULT
;
335 version
= 0x00010301;
337 else if(!strcmp(&argv
[1][4], "r")) {
338 mi4magic
= MI4_MAGIC_R
;
339 version
= 0x00010301;
342 printf( "Invalid mi4 version: %s\n", &argv
[1][4]);
349 if(!strncmp(argv
[2], "-model=", 7)) {
352 strncpy(model
, &argv
[2][7], 4);
354 if(!strncmp(argv
[3], "-type=", 6)) {
357 strncpy(type
, &argv
[3][6], 4);
361 return mi4_encode(iname
, oname
, version
, mi4magic
, model
, type
);
365 file
= fopen(iname
,"rb");
370 fseek(file
,0,SEEK_END
);
371 length
= ftell(file
);
372 length
= (length
+ 3) & ~3; /* Round up to nearest 4 byte boundary */
374 if ((method
== scramble
) &&
375 ((length
+ headerlen
) >= size_limit
[model_id
])) {
376 printf("error: firmware image is %d bytes while max size is %d!\n",
378 size_limit
[model_id
]);
383 fseek(file
,0,SEEK_SET
);
384 inbuf
= malloc(length
);
386 outbuf
= malloc(length
*2);
387 else if(method
== add
)
388 outbuf
= malloc(length
+ 8);
390 outbuf
= malloc(length
);
391 if ( !inbuf
|| !outbuf
) {
392 printf("out of memory!\n");
396 /* zero-fill the last 4 bytes to make sure there's no rubbish there
397 when we write the size-aligned file later */
398 memset(outbuf
+length
-4, 0, 4);
402 i
=fread(inbuf
,1,length
,file
);
412 for (i
= 0; i
< length
; i
++) {
413 /* add 8 unsigned bits but keep a 32 bit sum */
419 for (i
= 0; i
< length
; i
++) {
420 unsigned long addr
= (i
>> 2) + ((i
% 4) * slen
);
421 unsigned char data
= inbuf
[i
];
422 data
= ~((data
<< 1) | ((data
>> 7) & 1)); /* poor man's ROL */
430 for (i
=0; i
<length
; i
++) {
432 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
433 outbuf
[slen
++] = inbuf
[i
];
438 if((method
== none
) || (method
== scramble
) || (method
== xor)) {
439 /* calculate checksum */
440 for (i
=0;i
<length
;i
++)
444 memset(header
, 0, sizeof header
);
449 int2be(chksum
, header
); /* checksum, big-endian */
450 memcpy(&header
[4], modelname
, 4); /* 4 bytes model name */
451 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
457 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
458 telechips_encode_sum(outbuf
, length
);
462 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
463 telechips_encode_crc(outbuf
, length
);
467 if (headerlen
== 6) {
468 int2be(length
, header
);
469 header
[4] = (crc
>> 8) & 0xff;
470 header
[5] = crc
& 0xff;
476 header
[3] = 0xff; /* ??? */
478 header
[6] = (crc
>> 8) & 0xff;
479 header
[7] = crc
& 0xff;
481 header
[11] = version
;
483 header
[15] = headerlen
; /* really? */
485 int2be(length
, &header
[20]);
491 int xorlen
= strlen(xorstring
);
494 for (i
=0; i
<slen
; i
++)
495 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
497 /* calculate checksum */
498 for (i
=0; i
<slen
; i
++)
501 header
[0] = header
[2] = 'Z';
502 header
[1] = header
[3] = version
;
503 int2le(length
, &header
[4]);
504 int2le(slen
, &header
[8]);
505 int2le(crc
, &header
[12]);
510 #define MY_FIRMWARE_TYPE "Rockbox"
511 #define MY_HEADER_VERSION 1
513 strncpy((char *)header
, MY_FIRMWARE_TYPE
,9);
514 header
[9]='\0'; /*shouldn't have to, but to be SURE */
515 header
[10]=MY_HEADER_VERSION
&0xFF;
516 header
[11]=(crc
>>8)&0xFF;
518 int2be(sizeof(header
), &header
[12]);
523 file
= fopen(oname
,"wb");
529 if ( !fwrite(header
,headerlen
,1,file
) ) {
534 if ( !fwrite(outbuf
,length
,1,file
) ) {
546 int iaudio_encode(char *iname
, char *oname
, char *idstring
)
551 unsigned char *outbuf
;
553 unsigned char sum
= 0;
555 file
= fopen(iname
, "rb");
560 fseek(file
,0,SEEK_END
);
561 length
= ftell(file
);
563 fseek(file
,0,SEEK_SET
);
564 outbuf
= malloc(length
+0x1030);
567 printf("out of memory!\n");
571 len
= fread(outbuf
+0x1030, 1, length
, file
);
577 memset(outbuf
, 0, 0x1030);
578 strcpy((char *)outbuf
, idstring
);
580 for(i
= 0; i
< length
;i
++)
581 sum
+= outbuf
[0x1030 + i
];
583 int2be(length
, &outbuf
[0x1024]);
584 outbuf
[0x102b] = sum
;
588 file
= fopen(oname
, "wb");
594 len
= fwrite(outbuf
, 1, length
+0x1030, file
);
604 /* Create an ipod firmware partition image
606 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
608 This function doesn't yet handle the Broadcom resource image for the 5g,
609 so the resulting images won't be usable.
611 This has also only been tested on an ipod Photo
614 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
)
616 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
637 unsigned int sum
= 0;
638 unsigned int rsrcsum
= 0;
639 unsigned char *outbuf
;
643 file
= fopen(iname
, "rb");
648 fseek(file
,0,SEEK_END
);
649 length
= ftell(file
);
651 fseek(file
,0,SEEK_SET
);
653 bufsize
=(length
+0x4600);
655 bufsize
= (bufsize
+ 0x400) & ~0x200;
658 outbuf
= malloc(bufsize
);
661 printf("out of memory!\n");
665 len
= fread(outbuf
+0x4600, 1, length
, file
);
672 /* Calculate checksum for later use in header */
673 for(i
= 0x4600; i
< 0x4600+length
;i
++)
676 /* Clear the header area to zero */
677 memset(outbuf
, 0, 0x4600);
679 /* APPLE STOP SIGN */
680 strcpy((char *)outbuf
, apple_stop_sign
);
683 memcpy(&outbuf
[0x100],"]ih[",4); /* Magic */
684 int2le(0x4000, &outbuf
[0x104]); /* Firmware offset relative to 0x200 */
685 short2le(0x10c, &outbuf
[0x108]); /* Location of extended header */
686 short2le(fw_ver
, &outbuf
[0x10a]);
688 /* Firmware Directory - "osos" entry */
689 memcpy(&outbuf
[0x4200],"!ATAsoso",8); /* dev and type */
690 int2le(0, &outbuf
[0x4208]); /* id */
691 int2le(0x4400, &outbuf
[0x420c]); /* devOffset */
692 int2le(length
, &outbuf
[0x4210]); /* Length of firmware */
693 int2le(0x10000000, &outbuf
[0x4214]); /* Addr */
694 int2le(0, &outbuf
[0x4218]); /* Entry Offset */
695 int2le(sum
, &outbuf
[0x421c]); /* Checksum */
696 int2le(0x00006012, &outbuf
[0x4220]); /* vers - 0x6012 is a guess */
697 int2le(0xffffffff, &outbuf
[0x4224]); /* LoadAddr - for flash images */
699 /* "rsrc" entry (if applicable) */
701 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
705 memcpy(&outbuf
[0x4228],"!ATAcrsr",8); /* dev and type */
706 int2le(0, &outbuf
[0x4230]); /* id */
707 int2le(rsrcoffset
, &outbuf
[0x4234]); /* devOffset */
708 int2le(rsrclength
, &outbuf
[0x4238]); /* Length of firmware */
709 int2le(0x10000000, &outbuf
[0x423c]); /* Addr */
710 int2le(0, &outbuf
[0x4240]); /* Entry Offset */
711 int2le(rsrcsum
, &outbuf
[0x4244]); /* Checksum */
712 int2le(0x0000b000, &outbuf
[0x4248]); /* vers */
713 int2le(0xffffffff, &outbuf
[0x424c]); /* LoadAddr - for flash images */
716 file
= fopen(oname
, "wb");
722 len
= fwrite(outbuf
, 1, length
+0x4600, file
);
734 /* Create an Zen Vision:M FRESCUE structure file
737 int zvm_encode(char *iname
, char *oname
)
742 unsigned int sum
= 0;
743 unsigned char *outbuf
;
746 file
= fopen(iname
, "rb");
751 fseek(file
,0,SEEK_END
);
752 length
= ftell(file
);
754 fseek(file
,0,SEEK_SET
);
756 outbuf
= malloc(length
+0x18+0x10);
759 printf("out of memory!\n");
763 len
= fread(outbuf
+0x18, 1, length
, file
);
770 /* Calculate checksum for later use in header */
771 for(i
=0; i
<length
; i
+= 4)
772 sum
+= le2int(&outbuf
[0x18+i
]) + (le2int(&outbuf
[0x18+i
])>>16);
774 /* Clear the header area to zero */
775 memset(outbuf
, 0, 0x18);
778 memcpy((char*)outbuf
, "EDOC", 4);
780 int2le(length
+0x20, &outbuf
[0x4]);
781 /* 4 bytes of zero */
783 /* Address = 0x900000 */
784 int2le(0x900000, &outbuf
[0xC]);
786 int2le(length
, &outbuf
[0x10]);
788 int2le(sum
, &outbuf
[0x14]);
791 /* Data starts here... */
793 /* Second block starts here ... */
796 int2le(0x4, &outbuf
[0x18+length
+0x4]);
798 outbuf
[0x18+length
+0x8] = 0xB7;
799 outbuf
[0x18+length
+0x9] = 0xD5;
800 /* Data: LDR PC, =0x900000 */
801 outbuf
[0x18+length
+0xC] = 0x18;
802 outbuf
[0x18+length
+0xD] = 0xF0;
803 outbuf
[0x18+length
+0xE] = 0x9F;
804 outbuf
[0x18+length
+0xF] = 0xE5;
807 file
= fopen(oname
, "wb");
813 len
= fwrite(outbuf
, 1, length
+0x28, file
);
814 if(len
< length
+0x18) {