blob: 05cb3322ea0166279c0ec1b2f9ee54796db06ec5 [file] [log] [blame]
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2003 by Jörg Hohensohn
11 *
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)
14 *
15 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <memory.h>
27#include <string.h>
28
29#define UINT8 unsigned char
30#define UINT16 unsigned short
31#define UINT32 unsigned long
32#define BOOL int
33#define TRUE 1
34#define FALSE 0
35
36// size of one flash sector, the granularity with which it can be erased
37#define SECTORSIZE 4096
38
39#define BOOTLOAD_DEST 0x0FFFF500 // for the "normal" one
Jörg Hohensohn431be7f2004-12-23 20:15:13 +000040#define FLASH_START 0x02000000
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +000041#define BOOTLOAD_SCR 0x02000100
42#define ROCKBOX_DEST 0x09000000
43#define ROCKBOX_EXEC 0x09000200
44
45
46// place a 32 bit value into memory, big endian
47void Write32(UINT8* pByte, UINT32 value)
48{
49 pByte[0] = (UINT8)(value >> 24);
50 pByte[1] = (UINT8)(value >> 16);
51 pByte[2] = (UINT8)(value >> 8);
52 pByte[3] = (UINT8)(value);
53}
54
55
56// read a 32 bit value from memory, big endian
57UINT32 Read32(UINT8* pByte)
58{
59 UINT32 value = 0;
60
61 value |= (UINT32)pByte[0] << 24;
62 value |= (UINT32)pByte[1] << 16;
63 value |= (UINT32)pByte[2] << 8;
64 value |= (UINT32)pByte[3];
65
66 return value;
67}
68
69
70UINT32 CalcCRC32 (const UINT8* buf, UINT32 len)
71{
72 static const UINT32 crc_table[256] =
73 { // CRC32 lookup table for polynomial 0x04C11DB7
74 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
75 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
76 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7,
77 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
78 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3,
79 0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
80 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF,
81 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
82 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB,
83 0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
84 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
85 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
86 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4,
87 0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
88 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08,
89 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
90 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC,
91 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
92 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050,
93 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
94 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
95 0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
96 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1,
97 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
98 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5,
99 0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
100 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9,
101 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
102 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD,
103 0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
104 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
105 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
106 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2,
107 0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
108 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E,
109 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
110 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A,
111 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
112 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676,
113 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
114 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
115 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
116 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
117 };
118 UINT32 i;
119 UINT32 crc = 0xffffffff;
120
121 for (i = 0; i < len; i++)
122 crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *buf++) & 0xFF];
123
124 return crc;
125}
126
127
128UINT32 PlaceImage(char* filename, UINT32 pos, UINT8* pFirmware, UINT32 limit)
129{
130 UINT32 size, read;
131 FILE* pFile;
132 UINT32 align;
133 UINT32 flags;
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000134 UINT32 load_addr = ROCKBOX_DEST, exec_addr = ROCKBOX_EXEC; // defaults
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000135
136 // magic file header for compressed files
137 static const UINT8 magic[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a };
138 UINT8 ucl_header[26];
139
140 pFile = fopen(filename, "rb"); // open the current image
141 if (pFile == NULL)
142 {
143 printf("Image file %s not found!\n", filename);
144 exit(5);
145 }
146
147 fseek(pFile, 0, SEEK_END);
148 size = ftell(pFile);
149 fseek(pFile, 0, SEEK_SET);
150
151 // determine if compressed
152 flags = 0x00000000; // default: flags for uncompressed
153 fread(ucl_header, 1, sizeof(ucl_header), pFile);
154 if (memcmp(magic, ucl_header, sizeof(magic)) == 0)
155 {
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000156 if (ucl_header[12] != 0x2E // check algorithm
157 && ucl_header[12] != 0x2B) // or uncompressed
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000158 {
159 printf("UCL compressed files must use algorithm 2e, not %d\n", ucl_header[12]);
160 printf("Generate with: uclpack --best --2e rockbox.bin %s\n", filename);
161 exit(6);
162 }
163
164 size = Read32(ucl_header + 22); // compressed size
165 if (Read32(ucl_header + 18) > size) // compare with uncompressed size
166 { // normal case
167 flags = 0x00000001; // flags for UCL compressed
168 }
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000169
170 if (ucl_header[12] == 0x2B) // uncompressed means "ROMbox", for direct flash execution
171 {
Jörg Hohensohn977aa612005-08-31 23:50:40 +0000172 UINT8 start_addr[4];
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000173 UINT8 reset_vec[4];
Jörg Hohensohn977aa612005-08-31 23:50:40 +0000174 fread(start_addr, 1, sizeof(start_addr), pFile); // read the link address from image
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000175 fread(reset_vec, 1, sizeof(reset_vec), pFile); // read the reset vector from image
Jörg Hohensohn977aa612005-08-31 23:50:40 +0000176 fseek(pFile, 0-sizeof(start_addr)-sizeof(reset_vec), SEEK_CUR); // wind back
177 load_addr = Read32(start_addr);
178 if (load_addr != FLASH_START + pos + 16) // behind 16 byte header
179 {
180 printf("Error: Rombox .ucl file is linked to 0x%08X instead of 0x%08X\n", load_addr, FLASH_START + pos + 16);
181 exit(11);
182 }
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000183 exec_addr = Read32(reset_vec);
184 }
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000185 }
186 else
187 {
188 fseek(pFile, 0, SEEK_SET); // go back
189 }
190
191 if (pos + 16 + size > limit) // enough space for all that?
192 {
193 printf("Exceeding maximum image size %d\n", limit);
194 exit(7);
195 }
196
197 // write header
198 align = (pos + 16 + size + SECTORSIZE-1) & ~(SECTORSIZE-1); // round up to next flash sector
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000199 Write32(pFirmware + pos, load_addr); // load address
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000200 Write32(pFirmware + pos + 4, align - (pos + 16)); // image size
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000201 Write32(pFirmware + pos + 8, exec_addr); // execution address
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000202 Write32(pFirmware + pos + 12, flags); // compressed or not
203 pos += 16;
204
205 // load image
206 read = fread(pFirmware + pos, 1, size, pFile);
207 if (read != size)
208 {
209 printf("Read error, expecting %d bytes, got only %d\n", size, read);
210 exit(8);
211 }
212 fclose (pFile);
213
214 pos += size;
215
216 return pos;
217}
218
219
220int main(int argc, char* argv[])
221{
222 static UINT8 aFirmware[512*1024]; // maximum with exchanged chip
223 FILE* pFile;
224 UINT32 size; // size of loaded item
225 UINT32 pos; // current position in firmware
226 UINT32 crc32; // checksum of "payload"
227 BOOL hasBootRom; // flag if regular boot ROM or directly starts from flash
228 UINT32 template_F8, template_FC; // my platform ID, mask and version
229
230 int i;
231
232 if (argc <= 4)
233 {
234 printf("Usage:\n");
235 printf("make_firmware <output> <template.bin> <bootloader.ajz> <image1.ucl> {image2.ucl}\n");
236 printf("<template.bin> is the original firmware from your box\n");
237 printf("<bootloader.ajz> is the scrambled bootloader\n");
238 printf("<image1.ucl> is the first image, compressed (recommended) or uncompressed\n");
239 printf("<image1.ucl> is the second image, compressed (recommended) or uncompressed\n");
240 printf("More images may follow, but keep the flash size in mind!\n");
241 printf("Compression must be UCL, algorithm 2e.\n");
242 printf("Generated with: uclpack --best --2e rockbox.bin imageN.ucl\n");
243 exit(0);
244 }
245
246 memset(aFirmware, 0xFF, sizeof(aFirmware));
247
248 /******* process template *******/
249
250 pFile = fopen(argv[2], "rb"); // open the template
251 if (pFile == NULL)
252 {
253 printf("Template file %s not found!\n", argv[2]);
254 exit(1);
255 }
256 size = fread(aFirmware, 1, 256, pFile); // need only the header
257 fclose(pFile);
258 if (size < 256) // need at least the firmware header
259 {
260 printf("Template file %s too small, need at least the header!\n", argv[2]);
261 exit(2);
262 }
263
264 if (strncmp(aFirmware, "ARCH", 4) == 0)
265 {
266 hasBootRom = TRUE;
267 pos = 256; // place bootloader after this "boot block"
268 }
269 else if (Read32(aFirmware) == 0x0200)
270 {
271 hasBootRom = FALSE;
272 pos = 0; // directly start with the bootloader
273 template_F8 = Read32(aFirmware + 0xF8); // my platform ID and future info
274 template_FC = Read32(aFirmware + 0xFC); // use mask+version from template
275 }
276 else
277 {
278 printf("Template file %s invalid!\n", argv[2]);
279 exit(3);
280 }
281
282 /******* process bootloader *******/
283
284 pFile = fopen(argv[3], "rb"); // open the bootloader
285 if (pFile == NULL)
286 {
287 printf("Bootloader file %s not found!\n", argv[3]);
288 exit(4);
289 }
290 if (hasBootRom && fseek(pFile, 6, SEEK_SET)) // skip the ajz header
291 {
292 printf("Bootloader file %s too short!\n", argv[3]);
293 exit(5);
294 }
295
296 // place bootloader after header
297 size = fread(aFirmware + pos, 1, sizeof(aFirmware) - pos, pFile);
298 fclose(pFile);
299
300 if (hasBootRom)
301 {
302 Write32(aFirmware + 4, BOOTLOAD_DEST); // boot code destination address
303
304 for (i=0x08; i<=0x28; i+=8)
305 {
306 Write32(aFirmware + i, BOOTLOAD_SCR); // boot code source address
307 Write32(aFirmware + i + 4, size); // boot code size
308 }
309 }
310 else
311 {
312 Write32(aFirmware + 0xF8, template_F8); // values from template
313 Write32(aFirmware + 0xFC, template_FC); // mask and version
314 }
315
316 size = (size + 3) & ~3; // make shure it's 32 bit aligned
317 pos += size; // prepare position for first image
318
319 /******* process images *******/
320 for (i = 4; i < argc; i++)
321 {
322 pos = PlaceImage(argv[i], pos, aFirmware, sizeof(aFirmware));
323
324 if (i < argc-1)
325 { // not the last: round up to next flash sector
326 pos = (pos + SECTORSIZE-1) & ~(SECTORSIZE-1);
327 }
328 }
329
330
331 /******* append CRC32 checksum *******/
332 crc32 = CalcCRC32(aFirmware, pos);
333 Write32(aFirmware + pos, crc32);
334 pos += sizeof(crc32); // 4 bytes
335
336
337 /******* save result to output file *******/
338
339 pFile = fopen(argv[1], "wb"); // open the output file
340 if (pFile == NULL)
341 {
342 printf("Output file %s cannot be created!\n", argv[1]);
343 exit(9);
344 }
345 size = fwrite(aFirmware, 1, pos, pFile);
346 fclose(pFile);
347
348 if (size != pos)
349 {
350 printf("Error writing %d bytes to output file %s!\n", pos, argv[1]);
351 exit(10);
352 }
353
354 printf("Firmware file generated with %d bytes.\n", pos);
355
356 return 0;
357}