blob: bd838bf3bf13e4f5a3f48e63992ecc37df434ce8 [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 *
Nicolas Pennequin357ffb32008-05-05 10:32:46 +000010 * Copyright (C) 2003 by Jörg Hohensohn
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +000011 *
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 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000015 * 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.
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +000019 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25
26#include <stdio.h>
27#include <stdlib.h>
Thomas Martitz87409a22010-08-12 13:55:01 +000028#include <inttypes.h>
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +000029#include <string.h>
30
31#define UINT8 unsigned char
32#define UINT16 unsigned short
33#define UINT32 unsigned long
34#define BOOL int
35#define TRUE 1
36#define FALSE 0
37
38// size of one flash sector, the granularity with which it can be erased
39#define SECTORSIZE 4096
40
41#define BOOTLOAD_DEST 0x0FFFF500 // for the "normal" one
Jörg Hohensohn431be7f2004-12-23 20:15:13 +000042#define FLASH_START 0x02000000
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +000043#define BOOTLOAD_SCR 0x02000100
44#define ROCKBOX_DEST 0x09000000
45#define ROCKBOX_EXEC 0x09000200
46
47
48// place a 32 bit value into memory, big endian
49void Write32(UINT8* pByte, UINT32 value)
50{
51 pByte[0] = (UINT8)(value >> 24);
52 pByte[1] = (UINT8)(value >> 16);
53 pByte[2] = (UINT8)(value >> 8);
54 pByte[3] = (UINT8)(value);
55}
56
57
58// read a 32 bit value from memory, big endian
59UINT32 Read32(UINT8* pByte)
60{
61 UINT32 value = 0;
62
63 value |= (UINT32)pByte[0] << 24;
64 value |= (UINT32)pByte[1] << 16;
65 value |= (UINT32)pByte[2] << 8;
66 value |= (UINT32)pByte[3];
67
68 return value;
69}
70
71
Thomas Jaroschfdd4aef2015-01-05 18:44:36 +010072static UINT32 CalcCRC32 (const UINT8* buf, UINT32 len)
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +000073{
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
119 };
120 UINT32 i;
121 UINT32 crc = 0xffffffff;
122
123 for (i = 0; i < len; i++)
124 crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *buf++) & 0xFF];
125
126 return crc;
127}
128
129
Thomas Jaroschfdd4aef2015-01-05 18:44:36 +0100130static UINT32 PlaceImage(char* filename, UINT32 pos, UINT8* pFirmware, UINT32 limit)
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000131{
132 UINT32 size, read;
133 FILE* pFile;
134 UINT32 align;
135 UINT32 flags;
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000136 UINT32 load_addr = ROCKBOX_DEST, exec_addr = ROCKBOX_EXEC; // defaults
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000137
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];
141
142 pFile = fopen(filename, "rb"); // open the current image
143 if (pFile == NULL)
144 {
145 printf("Image file %s not found!\n", filename);
146 exit(5);
147 }
148
149 fseek(pFile, 0, SEEK_END);
150 size = ftell(pFile);
151 fseek(pFile, 0, SEEK_SET);
152
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)
157 {
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000158 if (ucl_header[12] != 0x2E // check algorithm
159 && ucl_header[12] != 0x2B) // or uncompressed
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000160 {
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);
163 exit(6);
164 }
165
166 size = Read32(ucl_header + 22); // compressed size
167 if (Read32(ucl_header + 18) > size) // compare with uncompressed size
168 { // normal case
169 flags = 0x00000001; // flags for UCL compressed
170 }
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000171
172 if (ucl_header[12] == 0x2B) // uncompressed means "ROMbox", for direct flash execution
173 {
Jörg Hohensohn977aa612005-08-31 23:50:40 +0000174 UINT8 start_addr[4];
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000175 UINT8 reset_vec[4];
Jörg Hohensohn977aa612005-08-31 23:50:40 +0000176 fread(start_addr, 1, sizeof(start_addr), pFile); // read the link address from image
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000177 fread(reset_vec, 1, sizeof(reset_vec), pFile); // read the reset vector from image
Jörg Hohensohn977aa612005-08-31 23:50:40 +0000178 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
181 {
182 printf("Error: Rombox .ucl file is linked to 0x%08X instead of 0x%08X\n", load_addr, FLASH_START + pos + 16);
183 exit(11);
184 }
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000185 exec_addr = Read32(reset_vec);
186 }
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000187 }
188 else
189 {
190 fseek(pFile, 0, SEEK_SET); // go back
191 }
192
193 if (pos + 16 + size > limit) // enough space for all that?
194 {
195 printf("Exceeding maximum image size %d\n", limit);
196 exit(7);
197 }
198
199 // write header
200 align = (pos + 16 + size + SECTORSIZE-1) & ~(SECTORSIZE-1); // round up to next flash sector
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000201 Write32(pFirmware + pos, load_addr); // load address
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000202 Write32(pFirmware + pos + 4, align - (pos + 16)); // image size
Jörg Hohensohn431be7f2004-12-23 20:15:13 +0000203 Write32(pFirmware + pos + 8, exec_addr); // execution address
Jörg Hohensohn6a4e4c82003-11-30 11:37:43 +0000204 Write32(pFirmware + pos + 12, flags); // compressed or not
205 pos += 16;
206
207 // load image
208 read = fread(pFirmware + pos, 1, size, pFile);
209 if (read != size)
210 {
211 printf("Read error, expecting %d bytes, got only %d\n", size, read);
212 exit(8);
213 }
214 fclose (pFile);
215
216 pos += size;
217
218 return pos;
219}
220
221
222int main(int argc, char* argv[])
223{
224 static UINT8 aFirmware[512*1024]; // maximum with exchanged chip
225 FILE* pFile;
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
231
232 int i;
233
234 if (argc <= 4)
235 {
236 printf("Usage:\n");
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");
245 exit(0);
246 }
247
248 memset(aFirmware, 0xFF, sizeof(aFirmware));
249
250 /******* process template *******/
251
252 pFile = fopen(argv[2], "rb"); // open the template
253 if (pFile == NULL)
254 {
255 printf("Template file %s not found!\n", argv[2]);
256 exit(1);
257 }
258 size = fread(aFirmware, 1, 256, pFile); // need only the header
259 fclose(pFile);
260 if (size < 256) // need at least the firmware header
261 {
262 printf("Template file %s too small, need at least the header!\n", argv[2]);
263 exit(2);
264 }
265
266 if (strncmp(aFirmware, "ARCH", 4) == 0)
267 {
268 hasBootRom = TRUE;
269 pos = 256; // place bootloader after this "boot block"
270 }
271 else if (Read32(aFirmware) == 0x0200)
272 {
273 hasBootRom = FALSE;
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
277 }
278 else
279 {
280 printf("Template file %s invalid!\n", argv[2]);
281 exit(3);
282 }
283
284 /******* process bootloader *******/
285
286 pFile = fopen(argv[3], "rb"); // open the bootloader
287 if (pFile == NULL)
288 {
289 printf("Bootloader file %s not found!\n", argv[3]);
290 exit(4);
291 }
292 if (hasBootRom && fseek(pFile, 6, SEEK_SET)) // skip the ajz header
293 {
294 printf("Bootloader file %s too short!\n", argv[3]);
295 exit(5);
296 }
297
298 // place bootloader after header
299 size = fread(aFirmware + pos, 1, sizeof(aFirmware) - pos, pFile);
300 fclose(pFile);
301
302 if (hasBootRom)
303 {
304 Write32(aFirmware + 4, BOOTLOAD_DEST); // boot code destination address
305
306 for (i=0x08; i<=0x28; i+=8)
307 {
308 Write32(aFirmware + i, BOOTLOAD_SCR); // boot code source address
309 Write32(aFirmware + i + 4, size); // boot code size
310 }
311 }
312 else
313 {
314 Write32(aFirmware + 0xF8, template_F8); // values from template
315 Write32(aFirmware + 0xFC, template_FC); // mask and version
316 }
317
318 size = (size + 3) & ~3; // make shure it's 32 bit aligned
319 pos += size; // prepare position for first image
320
321 /******* process images *******/
322 for (i = 4; i < argc; i++)
323 {
324 pos = PlaceImage(argv[i], pos, aFirmware, sizeof(aFirmware));
325
326 if (i < argc-1)
327 { // not the last: round up to next flash sector
328 pos = (pos + SECTORSIZE-1) & ~(SECTORSIZE-1);
329 }
330 }
331
332
333 /******* append CRC32 checksum *******/
334 crc32 = CalcCRC32(aFirmware, pos);
335 Write32(aFirmware + pos, crc32);
336 pos += sizeof(crc32); // 4 bytes
337
338
339 /******* save result to output file *******/
340
341 pFile = fopen(argv[1], "wb"); // open the output file
342 if (pFile == NULL)
343 {
344 printf("Output file %s cannot be created!\n", argv[1]);
345 exit(9);
346 }
347 size = fwrite(aFirmware, 1, pos, pFile);
348 fclose(pFile);
349
350 if (size != pos)
351 {
352 printf("Error writing %d bytes to output file %s!\n", pos, argv[1]);
353 exit(10);
354 }
355
356 printf("Firmware file generated with %d bytes.\n", pos);
357
358 return 0;
359}