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"
29 #include "iaudio_bl_flash.h"
31 int iaudio_encode(char *iname
, char *oname
, char *idstring
);
32 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
);
36 ARCHOS_PLAYER
, /* and V1 recorder */
45 0x32000, /* ARCHOS_PLAYER */
46 0x64000, /* ARCHOS_V2RECORDER */
47 0x64000, /* ARCHOS_FMRECORDER */
48 0x64000, /* ARCHOS_ONDIO_SP */
49 0x64000 /* ARCHOS_ONDIO_FM */
52 void short2le(unsigned short val
, unsigned char* addr
)
55 addr
[1] = (val
>> 8) & 0xff;
58 unsigned int le2int(unsigned char* buf
)
60 unsigned int res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
65 void int2le(unsigned int val
, unsigned char* addr
)
68 addr
[1] = (val
>> 8) & 0xff;
69 addr
[2] = (val
>> 16) & 0xff;
70 addr
[3] = (val
>> 24) & 0xff;
73 void int2be(unsigned int val
, unsigned char* addr
)
75 addr
[0] = (val
>> 24) & 0xff;
76 addr
[1] = (val
>> 16) & 0xff;
77 addr
[2] = (val
>> 8) & 0xff;
81 void short2be(unsigned short val
, unsigned char* addr
)
83 addr
[0] = (val
>> 8) & 0xff;
89 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
91 "\t-fm Archos FM recorder format\n"
92 "\t-v2 Archos V2 recorder format\n"
93 "\t-ofm Archos Ondio FM recorder format\n"
94 "\t-osp Archos Ondio SP format\n"
95 "\t-neo SSI Neo format\n"
96 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
97 "\t-iriver iRiver format\n"
98 "\t-iaudiox5 iAudio X5 format\n"
99 "\t-iaudiox5v iAudio X5V format\n"
100 "\t-iaudiom5 iAudio M5 format\n"
101 "\t-iaudiom3 iAudio M3 format\n"
102 "\t-ipod3g ipod firmware partition format (3rd Gen)\n"
103 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
104 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
105 "\t-zvm Zen Vision:M FRESCUE structure format\n"
106 "\t-gigabeat Toshiba Gigabeat F/X format\n"
107 "\t-gigabeats Toshiba Gigabeat S format\n"
108 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
109 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
110 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
111 "\t All mi4 options take two optional arguments:\n"
112 "\t -model=XXXX where XXXX is the model id string\n"
113 "\t -type=XXXX where XXXX is a string indicating the \n"
114 "\t type of binary, eg. RBOS, RBBL\n"
115 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
116 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
117 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
118 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
119 "\t tpj2, c200, e200, giga, gigs, m100, m500, d2)\n"
120 "\nNo option results in Archos standard player/recorder format.\n");
125 int main (int argc
, char** argv
)
127 unsigned long length
,i
,slen
;
128 unsigned char *inbuf
,*outbuf
;
129 unsigned short crc
=0;
130 unsigned long chksum
=0; /* 32 bit checksum */
131 unsigned char header
[24];
132 char *iname
= argv
[1];
133 char *oname
= argv
[2];
138 unsigned long modelnum
;
141 enum { none
, scramble
, xor, tcc_sum
, tcc_crc
, add
} method
= scramble
;
143 model_id
= ARCHOS_PLAYER
;
149 if(!strcmp(argv
[1], "-fm")) {
154 model_id
= ARCHOS_FMRECORDER
;
157 else if(!strcmp(argv
[1], "-v2")) {
162 model_id
= ARCHOS_V2RECORDER
;
165 else if(!strcmp(argv
[1], "-ofm")) {
170 model_id
= ARCHOS_ONDIO_FM
;
173 else if(!strcmp(argv
[1], "-osp")) {
178 model_id
= ARCHOS_ONDIO_SP
;
181 else if(!strcmp(argv
[1], "-neo")) {
187 else if(!strncmp(argv
[1], "-mm=", 4)) {
192 version
= argv
[1][4];
196 printf("Multimedia needs an xor string\n");
200 else if(!strncmp(argv
[1], "-tcc=", 4)) {
205 if(!strcmp(&argv
[1][5], "sum"))
207 else if(!strcmp(&argv
[1][5], "crc"))
210 fprintf(stderr
, "unsupported TCC method: %s\n", &argv
[1][5]);
214 else if(!strncmp(argv
[1], "-add=", 5)) {
219 if(!strcmp(&argv
[1][5], "h120"))
221 else if(!strcmp(&argv
[1][5], "h140"))
222 modelnum
= 0; /* the same as the h120 */
223 else if(!strcmp(&argv
[1][5], "h100"))
225 else if(!strcmp(&argv
[1][5], "h300"))
227 else if(!strcmp(&argv
[1][5], "ipco"))
229 else if(!strcmp(&argv
[1][5], "nano"))
231 else if(!strcmp(&argv
[1][5], "ipvd"))
233 else if(!strcmp(&argv
[1][5], "fp7x"))
235 else if(!strcmp(&argv
[1][5], "ip3g"))
237 else if(!strcmp(&argv
[1][5], "ip4g"))
239 else if(!strcmp(&argv
[1][5], "mini"))
241 else if(!strcmp(&argv
[1][5], "iax5"))
243 else if(!strcmp(&argv
[1][5], "mn2g"))
245 else if(!strcmp(&argv
[1][5], "h10"))
247 else if(!strcmp(&argv
[1][5], "h10_5gb"))
249 else if(!strcmp(&argv
[1][5], "tpj2"))
251 else if(!strcmp(&argv
[1][5], "e200"))
253 else if(!strcmp(&argv
[1][5], "iam5"))
255 else if(!strcmp(&argv
[1][5], "giga"))
257 else if(!strcmp(&argv
[1][5], "1g2g"))
259 else if(!strcmp(&argv
[1][5], "c200"))
261 else if(!strcmp(&argv
[1][5], "gigs"))
263 else if(!strcmp(&argv
[1][5], "m500"))
265 else if(!strcmp(&argv
[1][5], "m100"))
267 else if(!strcmp(&argv
[1][5], "d2"))
269 else if(!strcmp(&argv
[1][5], "iam3"))
272 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
275 /* we store a 4-letter model name too, for humans */
276 strcpy(modelname
, &argv
[1][5]);
277 chksum
= modelnum
; /* start checksum calcs with this */
280 else if(!strcmp(argv
[1], "-iriver")) {
281 /* iRiver code dealt with in the iriver.c code */
284 iriver_encode(iname
, oname
, FALSE
);
287 else if(!strcmp(argv
[1], "-gigabeat")) {
288 /* iRiver code dealt with in the iriver.c code */
291 gigabeat_code(iname
, oname
);
294 else if(!strcmp(argv
[1], "-gigabeats")) {
297 gigabeat_s_code(iname
, oname
);
300 else if(!strcmp(argv
[1], "-iaudiox5")) {
303 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
305 else if(!strcmp(argv
[1], "-iaudiox5v")) {
308 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
310 else if(!strcmp(argv
[1], "-iaudiom5")) {
313 return iaudio_encode(iname
, oname
, "COWON_M5_FW");
315 else if(!strcmp(argv
[1], "-iaudiom3")) {
318 return iaudio_encode(iname
, oname
, "COWON_M3_FW");
320 else if(!strcmp(argv
[1], "-ipod3g")) {
323 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
325 else if(!strcmp(argv
[1], "-ipod4g")) {
328 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
330 else if(!strcmp(argv
[1], "-ipod5g")) {
333 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
335 else if(!strcmp(argv
[1], "-zvm")) {
338 return zvm_encode(iname
, oname
);
340 else if(!strncmp(argv
[1], "-mi4", 4)) {
346 if(!strcmp(&argv
[1][4], "v2")) {
347 mi4magic
= MI4_MAGIC_DEFAULT
;
348 version
= 0x00010201;
350 else if(!strcmp(&argv
[1][4], "v3")) {
351 mi4magic
= MI4_MAGIC_DEFAULT
;
352 version
= 0x00010301;
354 else if(!strcmp(&argv
[1][4], "r")) {
355 mi4magic
= MI4_MAGIC_R
;
356 version
= 0x00010301;
359 printf( "Invalid mi4 version: %s\n", &argv
[1][4]);
366 if(!strncmp(argv
[2], "-model=", 7)) {
369 strncpy(model
, &argv
[2][7], 4);
371 if(!strncmp(argv
[3], "-type=", 6)) {
374 strncpy(type
, &argv
[3][6], 4);
378 return mi4_encode(iname
, oname
, version
, mi4magic
, model
, type
);
382 file
= fopen(iname
,"rb");
387 fseek(file
,0,SEEK_END
);
388 length
= ftell(file
);
389 length
= (length
+ 3) & ~3; /* Round up to nearest 4 byte boundary */
391 if ((method
== scramble
) &&
392 ((length
+ headerlen
) >= size_limit
[model_id
])) {
393 printf("error: firmware image is %d bytes while max size is %d!\n",
395 size_limit
[model_id
]);
400 fseek(file
,0,SEEK_SET
);
401 inbuf
= malloc(length
);
403 outbuf
= malloc(length
*2);
404 else if(method
== add
)
405 outbuf
= malloc(length
+ 8);
407 outbuf
= malloc(length
);
408 if ( !inbuf
|| !outbuf
) {
409 printf("out of memory!\n");
413 /* zero-fill the last 4 bytes to make sure there's no rubbish there
414 when we write the size-aligned file later */
415 memset(outbuf
+length
-4, 0, 4);
419 i
=fread(inbuf
,1,length
,file
);
429 for (i
= 0; i
< length
; i
++) {
430 /* add 8 unsigned bits but keep a 32 bit sum */
436 for (i
= 0; i
< length
; i
++) {
437 unsigned long addr
= (i
>> 2) + ((i
% 4) * slen
);
438 unsigned char data
= inbuf
[i
];
439 data
= ~((data
<< 1) | ((data
>> 7) & 1)); /* poor man's ROL */
447 for (i
=0; i
<length
; i
++) {
449 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
450 outbuf
[slen
++] = inbuf
[i
];
455 if((method
== none
) || (method
== scramble
) || (method
== xor)) {
456 /* calculate checksum */
457 for (i
=0;i
<length
;i
++)
461 memset(header
, 0, sizeof header
);
466 int2be(chksum
, header
); /* checksum, big-endian */
467 memcpy(&header
[4], modelname
, 4); /* 4 bytes model name */
468 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
474 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
475 telechips_encode_sum(outbuf
, length
);
479 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
480 telechips_encode_crc(outbuf
, length
);
484 if (headerlen
== 6) {
485 int2be(length
, header
);
486 header
[4] = (crc
>> 8) & 0xff;
487 header
[5] = crc
& 0xff;
493 header
[3] = 0xff; /* ??? */
495 header
[6] = (crc
>> 8) & 0xff;
496 header
[7] = crc
& 0xff;
498 header
[11] = version
;
500 header
[15] = headerlen
; /* really? */
502 int2be(length
, &header
[20]);
508 int xorlen
= strlen(xorstring
);
511 for (i
=0; i
<slen
; i
++)
512 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
514 /* calculate checksum */
515 for (i
=0; i
<slen
; i
++)
518 header
[0] = header
[2] = 'Z';
519 header
[1] = header
[3] = version
;
520 int2le(length
, &header
[4]);
521 int2le(slen
, &header
[8]);
522 int2le(crc
, &header
[12]);
527 #define MY_FIRMWARE_TYPE "Rockbox"
528 #define MY_HEADER_VERSION 1
530 strncpy((char *)header
, MY_FIRMWARE_TYPE
,9);
531 header
[9]='\0'; /*shouldn't have to, but to be SURE */
532 header
[10]=MY_HEADER_VERSION
&0xFF;
533 header
[11]=(crc
>>8)&0xFF;
535 int2be(sizeof(header
), &header
[12]);
540 file
= fopen(oname
,"wb");
546 if ( !fwrite(header
,headerlen
,1,file
) ) {
551 if ( !fwrite(outbuf
,length
,1,file
) ) {
563 int iaudio_encode(char *iname
, char *oname
, char *idstring
)
568 unsigned char *outbuf
;
570 unsigned char sum
= 0;
572 file
= fopen(iname
, "rb");
577 fseek(file
,0,SEEK_END
);
578 length
= ftell(file
);
580 fseek(file
,0,SEEK_SET
);
581 outbuf
= malloc(length
+0x1030);
584 printf("out of memory!\n");
588 len
= fread(outbuf
+0x1030, 1, length
, file
);
594 memset(outbuf
, 0, 0x1030);
595 strcpy((char *)outbuf
, idstring
);
596 memcpy(outbuf
+0x20, iaudio_bl_flash
,
597 BMPWIDTH_iaudio_bl_flash
* (BMPHEIGHT_iaudio_bl_flash
/8) * 2);
598 short2be(BMPWIDTH_iaudio_bl_flash
, &outbuf
[0x10]);
599 short2be((BMPHEIGHT_iaudio_bl_flash
/8), &outbuf
[0x12]);
602 for(i
= 0; i
< length
;i
++)
603 sum
+= outbuf
[0x1030 + i
];
605 int2be(length
, &outbuf
[0x1024]);
606 outbuf
[0x102b] = sum
;
610 file
= fopen(oname
, "wb");
616 len
= fwrite(outbuf
, 1, length
+0x1030, file
);
626 /* Create an ipod firmware partition image
628 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
630 This function doesn't yet handle the Broadcom resource image for the 5g,
631 so the resulting images won't be usable.
633 This has also only been tested on an ipod Photo
636 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
)
638 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
659 unsigned int sum
= 0;
660 unsigned int rsrcsum
= 0;
661 unsigned char *outbuf
;
665 file
= fopen(iname
, "rb");
670 fseek(file
,0,SEEK_END
);
671 length
= ftell(file
);
673 fseek(file
,0,SEEK_SET
);
675 bufsize
=(length
+0x4600);
677 bufsize
= (bufsize
+ 0x400) & ~0x200;
680 outbuf
= malloc(bufsize
);
683 printf("out of memory!\n");
687 len
= fread(outbuf
+0x4600, 1, length
, file
);
694 /* Calculate checksum for later use in header */
695 for(i
= 0x4600; i
< 0x4600+length
;i
++)
698 /* Clear the header area to zero */
699 memset(outbuf
, 0, 0x4600);
701 /* APPLE STOP SIGN */
702 strcpy((char *)outbuf
, apple_stop_sign
);
705 memcpy(&outbuf
[0x100],"]ih[",4); /* Magic */
706 int2le(0x4000, &outbuf
[0x104]); /* Firmware offset relative to 0x200 */
707 short2le(0x10c, &outbuf
[0x108]); /* Location of extended header */
708 short2le(fw_ver
, &outbuf
[0x10a]);
710 /* Firmware Directory - "osos" entry */
711 memcpy(&outbuf
[0x4200],"!ATAsoso",8); /* dev and type */
712 int2le(0, &outbuf
[0x4208]); /* id */
713 int2le(0x4400, &outbuf
[0x420c]); /* devOffset */
714 int2le(length
, &outbuf
[0x4210]); /* Length of firmware */
715 int2le(0x10000000, &outbuf
[0x4214]); /* Addr */
716 int2le(0, &outbuf
[0x4218]); /* Entry Offset */
717 int2le(sum
, &outbuf
[0x421c]); /* Checksum */
718 int2le(0x00006012, &outbuf
[0x4220]); /* vers - 0x6012 is a guess */
719 int2le(0xffffffff, &outbuf
[0x4224]); /* LoadAddr - for flash images */
721 /* "rsrc" entry (if applicable) */
723 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
727 memcpy(&outbuf
[0x4228],"!ATAcrsr",8); /* dev and type */
728 int2le(0, &outbuf
[0x4230]); /* id */
729 int2le(rsrcoffset
, &outbuf
[0x4234]); /* devOffset */
730 int2le(rsrclength
, &outbuf
[0x4238]); /* Length of firmware */
731 int2le(0x10000000, &outbuf
[0x423c]); /* Addr */
732 int2le(0, &outbuf
[0x4240]); /* Entry Offset */
733 int2le(rsrcsum
, &outbuf
[0x4244]); /* Checksum */
734 int2le(0x0000b000, &outbuf
[0x4248]); /* vers */
735 int2le(0xffffffff, &outbuf
[0x424c]); /* LoadAddr - for flash images */
738 file
= fopen(oname
, "wb");
744 len
= fwrite(outbuf
, 1, length
+0x4600, file
);
756 /* Create an Zen Vision:M FRESCUE structure file
759 int zvm_encode(char *iname
, char *oname
)
764 unsigned int sum
= 0;
765 unsigned char *outbuf
;
768 file
= fopen(iname
, "rb");
773 fseek(file
,0,SEEK_END
);
774 length
= ftell(file
);
776 fseek(file
,0,SEEK_SET
);
778 outbuf
= malloc(length
+0x18+0x10);
781 printf("out of memory!\n");
785 len
= fread(outbuf
+0x18, 1, length
, file
);
792 /* Calculate checksum for later use in header */
793 for(i
=0; i
<length
; i
+= 4)
794 sum
+= le2int(&outbuf
[0x18+i
]) + (le2int(&outbuf
[0x18+i
])>>16);
796 /* Clear the header area to zero */
797 memset(outbuf
, 0, 0x18);
800 memcpy((char*)outbuf
, "EDOC", 4);
802 int2le(length
+0x20, &outbuf
[0x4]);
803 /* 4 bytes of zero */
805 /* Address = 0x900000 */
806 int2le(0x900000, &outbuf
[0xC]);
808 int2le(length
, &outbuf
[0x10]);
810 int2le(sum
, &outbuf
[0x14]);
813 /* Data starts here... */
815 /* Second block starts here ... */
818 int2le(0x4, &outbuf
[0x18+length
+0x4]);
820 outbuf
[0x18+length
+0x8] = 0xB7;
821 outbuf
[0x18+length
+0x9] = 0xD5;
822 /* Data: LDR PC, =0x900000 */
823 outbuf
[0x18+length
+0xC] = 0x18;
824 outbuf
[0x18+length
+0xD] = 0xF0;
825 outbuf
[0x18+length
+0xE] = 0x9F;
826 outbuf
[0x18+length
+0xF] = 0xE5;
829 file
= fopen(oname
, "wb");
835 len
= fwrite(outbuf
, 1, length
+0x28, file
);
836 if(len
< length
+0x18) {