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