When autodetecting, don't segfault if no item was previously selected and a device...
[Rockbox.git] / flash / make_firmware / make_firmware.c
blob05cb3322ea0166279c0ec1b2f9ee54796db06ec5
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 * 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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <memory.h>
27 #include <string.h>
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
36 // size of one flash sector, the granularity with which it can be erased
37 #define SECTORSIZE 4096
39 #define BOOTLOAD_DEST 0x0FFFF500 // for the "normal" one
40 #define FLASH_START 0x02000000
41 #define BOOTLOAD_SCR 0x02000100
42 #define ROCKBOX_DEST 0x09000000
43 #define ROCKBOX_EXEC 0x09000200
46 // place a 32 bit value into memory, big endian
47 void Write32(UINT8* pByte, UINT32 value)
49 pByte[0] = (UINT8)(value >> 24);
50 pByte[1] = (UINT8)(value >> 16);
51 pByte[2] = (UINT8)(value >> 8);
52 pByte[3] = (UINT8)(value);
56 // read a 32 bit value from memory, big endian
57 UINT32 Read32(UINT8* pByte)
59 UINT32 value = 0;
61 value |= (UINT32)pByte[0] << 24;
62 value |= (UINT32)pByte[1] << 16;
63 value |= (UINT32)pByte[2] << 8;
64 value |= (UINT32)pByte[3];
66 return value;
70 UINT32 CalcCRC32 (const UINT8* buf, UINT32 len)
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
118 UINT32 i;
119 UINT32 crc = 0xffffffff;
121 for (i = 0; i < len; i++)
122 crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *buf++) & 0xFF];
124 return crc;
128 UINT32 PlaceImage(char* filename, UINT32 pos, UINT8* pFirmware, UINT32 limit)
130 UINT32 size, read;
131 FILE* pFile;
132 UINT32 align;
133 UINT32 flags;
134 UINT32 load_addr = ROCKBOX_DEST, exec_addr = ROCKBOX_EXEC; // defaults
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];
140 pFile = fopen(filename, "rb"); // open the current image
141 if (pFile == NULL)
143 printf("Image file %s not found!\n", filename);
144 exit(5);
147 fseek(pFile, 0, SEEK_END);
148 size = ftell(pFile);
149 fseek(pFile, 0, SEEK_SET);
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)
156 if (ucl_header[12] != 0x2E // check algorithm
157 && ucl_header[12] != 0x2B) // or uncompressed
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);
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
170 if (ucl_header[12] == 0x2B) // uncompressed means "ROMbox", for direct flash execution
172 UINT8 start_addr[4];
173 UINT8 reset_vec[4];
174 fread(start_addr, 1, sizeof(start_addr), pFile); // read the link address from image
175 fread(reset_vec, 1, sizeof(reset_vec), pFile); // read the reset vector from image
176 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
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);
183 exec_addr = Read32(reset_vec);
186 else
188 fseek(pFile, 0, SEEK_SET); // go back
191 if (pos + 16 + size > limit) // enough space for all that?
193 printf("Exceeding maximum image size %d\n", limit);
194 exit(7);
197 // write header
198 align = (pos + 16 + size + SECTORSIZE-1) & ~(SECTORSIZE-1); // round up to next flash sector
199 Write32(pFirmware + pos, load_addr); // load address
200 Write32(pFirmware + pos + 4, align - (pos + 16)); // image size
201 Write32(pFirmware + pos + 8, exec_addr); // execution address
202 Write32(pFirmware + pos + 12, flags); // compressed or not
203 pos += 16;
205 // load image
206 read = fread(pFirmware + pos, 1, size, pFile);
207 if (read != size)
209 printf("Read error, expecting %d bytes, got only %d\n", size, read);
210 exit(8);
212 fclose (pFile);
214 pos += size;
216 return pos;
220 int main(int argc, char* argv[])
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
230 int i;
232 if (argc <= 4)
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);
246 memset(aFirmware, 0xFF, sizeof(aFirmware));
248 /******* process template *******/
250 pFile = fopen(argv[2], "rb"); // open the template
251 if (pFile == NULL)
253 printf("Template file %s not found!\n", argv[2]);
254 exit(1);
256 size = fread(aFirmware, 1, 256, pFile); // need only the header
257 fclose(pFile);
258 if (size < 256) // need at least the firmware header
260 printf("Template file %s too small, need at least the header!\n", argv[2]);
261 exit(2);
264 if (strncmp(aFirmware, "ARCH", 4) == 0)
266 hasBootRom = TRUE;
267 pos = 256; // place bootloader after this "boot block"
269 else if (Read32(aFirmware) == 0x0200)
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
276 else
278 printf("Template file %s invalid!\n", argv[2]);
279 exit(3);
282 /******* process bootloader *******/
284 pFile = fopen(argv[3], "rb"); // open the bootloader
285 if (pFile == NULL)
287 printf("Bootloader file %s not found!\n", argv[3]);
288 exit(4);
290 if (hasBootRom && fseek(pFile, 6, SEEK_SET)) // skip the ajz header
292 printf("Bootloader file %s too short!\n", argv[3]);
293 exit(5);
296 // place bootloader after header
297 size = fread(aFirmware + pos, 1, sizeof(aFirmware) - pos, pFile);
298 fclose(pFile);
300 if (hasBootRom)
302 Write32(aFirmware + 4, BOOTLOAD_DEST); // boot code destination address
304 for (i=0x08; i<=0x28; i+=8)
306 Write32(aFirmware + i, BOOTLOAD_SCR); // boot code source address
307 Write32(aFirmware + i + 4, size); // boot code size
310 else
312 Write32(aFirmware + 0xF8, template_F8); // values from template
313 Write32(aFirmware + 0xFC, template_FC); // mask and version
316 size = (size + 3) & ~3; // make shure it's 32 bit aligned
317 pos += size; // prepare position for first image
319 /******* process images *******/
320 for (i = 4; i < argc; i++)
322 pos = PlaceImage(argv[i], pos, aFirmware, sizeof(aFirmware));
324 if (i < argc-1)
325 { // not the last: round up to next flash sector
326 pos = (pos + SECTORSIZE-1) & ~(SECTORSIZE-1);
331 /******* append CRC32 checksum *******/
332 crc32 = CalcCRC32(aFirmware, pos);
333 Write32(aFirmware + pos, crc32);
334 pos += sizeof(crc32); // 4 bytes
337 /******* save result to output file *******/
339 pFile = fopen(argv[1], "wb"); // open the output file
340 if (pFile == NULL)
342 printf("Output file %s cannot be created!\n", argv[1]);
343 exit(9);
345 size = fwrite(aFirmware, 1, pos, pFile);
346 fclose(pFile);
348 if (size != pos)
350 printf("Error writing %d bytes to output file %s!\n", pos, argv[1]);
351 exit(10);
354 printf("Firmware file generated with %d bytes.\n", pos);
356 return 0;