1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2003 by Jörg Hohensohn
12 * Autoring tool for the firmware image to be programmed into Flash ROM
13 * It composes the flash content with header, bootloader and image(s)
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
31 #define UINT8 unsigned char
32 #define UINT16 unsigned short
33 #define UINT32 unsigned long
38 // size of one flash sector, the granularity with which it can be erased
39 #define SECTORSIZE 4096
41 #define BOOTLOAD_DEST 0x0FFFF500 // for the "normal" one
42 #define FLASH_START 0x02000000
43 #define BOOTLOAD_SCR 0x02000100
44 #define ROCKBOX_DEST 0x09000000
45 #define ROCKBOX_EXEC 0x09000200
48 // place a 32 bit value into memory, big endian
49 void Write32(UINT8
* pByte
, UINT32 value
)
51 pByte
[0] = (UINT8
)(value
>> 24);
52 pByte
[1] = (UINT8
)(value
>> 16);
53 pByte
[2] = (UINT8
)(value
>> 8);
54 pByte
[3] = (UINT8
)(value
);
58 // read a 32 bit value from memory, big endian
59 UINT32
Read32(UINT8
* pByte
)
63 value
|= (UINT32
)pByte
[0] << 24;
64 value
|= (UINT32
)pByte
[1] << 16;
65 value
|= (UINT32
)pByte
[2] << 8;
66 value
|= (UINT32
)pByte
[3];
72 UINT32
CalcCRC32 (const UINT8
* buf
, UINT32 len
)
74 static const UINT32 crc_table
[256] =
75 { // CRC32 lookup table for polynomial 0x04C11DB7
76 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
77 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
78 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7,
79 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
80 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3,
81 0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
82 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF,
83 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
84 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB,
85 0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
86 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
87 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
88 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4,
89 0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
90 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08,
91 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
92 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC,
93 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
94 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050,
95 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
96 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
97 0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
98 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1,
99 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
100 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5,
101 0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
102 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9,
103 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
104 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD,
105 0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
106 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
107 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
108 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2,
109 0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
110 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E,
111 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
112 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A,
113 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
114 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676,
115 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
116 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
117 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
118 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
121 UINT32 crc
= 0xffffffff;
123 for (i
= 0; i
< len
; i
++)
124 crc
= (crc
<< 8) ^ crc_table
[((crc
>> 24) ^ *buf
++) & 0xFF];
130 UINT32
PlaceImage(char* filename
, UINT32 pos
, UINT8
* pFirmware
, UINT32 limit
)
136 UINT32 load_addr
= ROCKBOX_DEST
, exec_addr
= ROCKBOX_EXEC
; // defaults
138 // magic file header for compressed files
139 static const UINT8 magic
[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a };
140 UINT8 ucl_header
[26];
142 pFile
= fopen(filename
, "rb"); // open the current image
145 printf("Image file %s not found!\n", filename
);
149 fseek(pFile
, 0, SEEK_END
);
151 fseek(pFile
, 0, SEEK_SET
);
153 // determine if compressed
154 flags
= 0x00000000; // default: flags for uncompressed
155 fread(ucl_header
, 1, sizeof(ucl_header
), pFile
);
156 if (memcmp(magic
, ucl_header
, sizeof(magic
)) == 0)
158 if (ucl_header
[12] != 0x2E // check algorithm
159 && ucl_header
[12] != 0x2B) // or uncompressed
161 printf("UCL compressed files must use algorithm 2e, not %d\n", ucl_header
[12]);
162 printf("Generate with: uclpack --best --2e rockbox.bin %s\n", filename
);
166 size
= Read32(ucl_header
+ 22); // compressed size
167 if (Read32(ucl_header
+ 18) > size
) // compare with uncompressed size
169 flags
= 0x00000001; // flags for UCL compressed
172 if (ucl_header
[12] == 0x2B) // uncompressed means "ROMbox", for direct flash execution
176 fread(start_addr
, 1, sizeof(start_addr
), pFile
); // read the link address from image
177 fread(reset_vec
, 1, sizeof(reset_vec
), pFile
); // read the reset vector from image
178 fseek(pFile
, 0-sizeof(start_addr
)-sizeof(reset_vec
), SEEK_CUR
); // wind back
179 load_addr
= Read32(start_addr
);
180 if (load_addr
!= FLASH_START
+ pos
+ 16) // behind 16 byte header
182 printf("Error: Rombox .ucl file is linked to 0x%08X instead of 0x%08X\n", load_addr
, FLASH_START
+ pos
+ 16);
185 exec_addr
= Read32(reset_vec
);
190 fseek(pFile
, 0, SEEK_SET
); // go back
193 if (pos
+ 16 + size
> limit
) // enough space for all that?
195 printf("Exceeding maximum image size %d\n", limit
);
200 align
= (pos
+ 16 + size
+ SECTORSIZE
-1) & ~(SECTORSIZE
-1); // round up to next flash sector
201 Write32(pFirmware
+ pos
, load_addr
); // load address
202 Write32(pFirmware
+ pos
+ 4, align
- (pos
+ 16)); // image size
203 Write32(pFirmware
+ pos
+ 8, exec_addr
); // execution address
204 Write32(pFirmware
+ pos
+ 12, flags
); // compressed or not
208 read
= fread(pFirmware
+ pos
, 1, size
, pFile
);
211 printf("Read error, expecting %d bytes, got only %d\n", size
, read
);
222 int main(int argc
, char* argv
[])
224 static UINT8 aFirmware
[512*1024]; // maximum with exchanged chip
226 UINT32 size
; // size of loaded item
227 UINT32 pos
; // current position in firmware
228 UINT32 crc32
; // checksum of "payload"
229 BOOL hasBootRom
; // flag if regular boot ROM or directly starts from flash
230 UINT32 template_F8
, template_FC
; // my platform ID, mask and version
237 printf("make_firmware <output> <template.bin> <bootloader.ajz> <image1.ucl> {image2.ucl}\n");
238 printf("<template.bin> is the original firmware from your box\n");
239 printf("<bootloader.ajz> is the scrambled bootloader\n");
240 printf("<image1.ucl> is the first image, compressed (recommended) or uncompressed\n");
241 printf("<image1.ucl> is the second image, compressed (recommended) or uncompressed\n");
242 printf("More images may follow, but keep the flash size in mind!\n");
243 printf("Compression must be UCL, algorithm 2e.\n");
244 printf("Generated with: uclpack --best --2e rockbox.bin imageN.ucl\n");
248 memset(aFirmware
, 0xFF, sizeof(aFirmware
));
250 /******* process template *******/
252 pFile
= fopen(argv
[2], "rb"); // open the template
255 printf("Template file %s not found!\n", argv
[2]);
258 size
= fread(aFirmware
, 1, 256, pFile
); // need only the header
260 if (size
< 256) // need at least the firmware header
262 printf("Template file %s too small, need at least the header!\n", argv
[2]);
266 if (strncmp(aFirmware
, "ARCH", 4) == 0)
269 pos
= 256; // place bootloader after this "boot block"
271 else if (Read32(aFirmware
) == 0x0200)
274 pos
= 0; // directly start with the bootloader
275 template_F8
= Read32(aFirmware
+ 0xF8); // my platform ID and future info
276 template_FC
= Read32(aFirmware
+ 0xFC); // use mask+version from template
280 printf("Template file %s invalid!\n", argv
[2]);
284 /******* process bootloader *******/
286 pFile
= fopen(argv
[3], "rb"); // open the bootloader
289 printf("Bootloader file %s not found!\n", argv
[3]);
292 if (hasBootRom
&& fseek(pFile
, 6, SEEK_SET
)) // skip the ajz header
294 printf("Bootloader file %s too short!\n", argv
[3]);
298 // place bootloader after header
299 size
= fread(aFirmware
+ pos
, 1, sizeof(aFirmware
) - pos
, pFile
);
304 Write32(aFirmware
+ 4, BOOTLOAD_DEST
); // boot code destination address
306 for (i
=0x08; i
<=0x28; i
+=8)
308 Write32(aFirmware
+ i
, BOOTLOAD_SCR
); // boot code source address
309 Write32(aFirmware
+ i
+ 4, size
); // boot code size
314 Write32(aFirmware
+ 0xF8, template_F8
); // values from template
315 Write32(aFirmware
+ 0xFC, template_FC
); // mask and version
318 size
= (size
+ 3) & ~3; // make shure it's 32 bit aligned
319 pos
+= size
; // prepare position for first image
321 /******* process images *******/
322 for (i
= 4; i
< argc
; i
++)
324 pos
= PlaceImage(argv
[i
], pos
, aFirmware
, sizeof(aFirmware
));
327 { // not the last: round up to next flash sector
328 pos
= (pos
+ SECTORSIZE
-1) & ~(SECTORSIZE
-1);
333 /******* append CRC32 checksum *******/
334 crc32
= CalcCRC32(aFirmware
, pos
);
335 Write32(aFirmware
+ pos
, crc32
);
336 pos
+= sizeof(crc32
); // 4 bytes
339 /******* save result to output file *******/
341 pFile
= fopen(argv
[1], "wb"); // open the output file
344 printf("Output file %s cannot be created!\n", argv
[1]);
347 size
= fwrite(aFirmware
, 1, pos
, pFile
);
352 printf("Error writing %d bytes to output file %s!\n", pos
, argv
[1]);
356 printf("Firmware file generated with %d bytes.\n", pos
);