Show status about downloading build information in the status bar.
[kugel-rb.git] / tools / mknkboot.c
blob6ac26428bca7998a01ca48f46f3df36e2771df13
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 by Dave Chapman
12 * Based on merge0.cpp by James Espinoza, but completely rewritten.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met:
18 * * Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
21 * * Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials provided
24 * with the distribution.
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ****************************************************************************/
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #if defined(_MSC_VER)
46 #include "pstdint.h"
47 #else
48 #include <unistd.h>
49 #include <inttypes.h>
50 #endif
52 #include "mknkboot.h"
54 /* New entry point for nk.bin - where our dualboot code is inserted */
55 #define NK_ENTRY_POINT 0x88200000
57 /* Entry point (and load address) for the main Rockbox bootloader */
58 #define BL_ENTRY_POINT 0x8a000000
62 Description of nk.bin from
64 http://www.xs4all.nl/~itsme/projects/xda/wince-flashfile-formats.html
66 these files contain most information, several non-contigouos blocks
67 may be present and an entrypoint in the code.
69 1. a 7 character signature "B000FF\n" ( that is with 3 zeroes, and
70 ending in a linefeed )
71 2. DWORD for image start
72 3. DWORD for image length
73 4. followd by several records of this format:
74 1. DWORD with address where this block is to be flashed to
75 2. DWORD with the length of this block
76 3. DWORD with the 32 bit checksum of this block, in perl:
77 unpack("%32C*", $data);
78 4. followed by <length> bytes of data
79 5. the last record has address ZERO, in the length the entrypoint
80 into the rom, and ZERO as checksum.
83 NOTE: The Gigabeat-S nk.bin contains 171 records, plus the EOF record.
85 mknkboot.c appends two images:
87 1) A "Disable" image which overwrites a word in the EBoot image
88 2) Our bootloader image, which has the same load address as nk.exe
92 /* win32 compatibility */
94 #ifndef O_BINARY
95 #define O_BINARY 0
96 #endif
98 #define DISABLE_ADDR 0x88065A10 /* in EBoot */
99 #define DISABLE_INSN 0xe3a00001
100 #define DISABLE_SUM (0xe3+0xa0+0x00+0x01)
102 /* Code to dual-boot - this is inserted at NK_ENTRY_POINT */
103 static uint32_t dualboot[] =
105 0xe59f900c, /* ldr r9, [pc, #12] -> 0x53fa4000 */
106 0xe5999000, /* ldr r9, [r9] */
107 0xe3190010, /* tst r9, #16 ; 0x10 */
108 #if 0
109 /* Branch to Rockbox if hold is on */
110 0x159ff004, /* ldrne pc, [pc, #4] -> 0x89000000 */
111 #else
112 /* Branch to Rockbox if hold is off */
113 0x059ff004, /* ldreq pc, [pc, #4] -> 0x89000000 */
114 #endif
115 /* Branch to original firmware */
116 0xea0003fa, /* b 0x1000 */
118 0x53fa4000, /* GPIO3_DR */
119 BL_ENTRY_POINT /* RB bootloader load address/entry point */
123 static void put_uint32le(uint32_t x, unsigned char* p)
125 p[0] = (unsigned char)(x & 0xff);
126 p[1] = (unsigned char)((x >> 8) & 0xff);
127 p[2] = (unsigned char)((x >> 16) & 0xff);
128 p[3] = (unsigned char)((x >> 24) & 0xff);
131 #if !defined(BEASTPATCHER)
132 static off_t filesize(int fd) {
133 struct stat buf;
135 if (fstat(fd,&buf) < 0) {
136 perror("[ERR] Checking filesize of input file");
137 return -1;
138 } else {
139 return(buf.st_size);
142 #endif
145 int mknkboot(const struct filebuf *indata, const struct filebuf *bootdata,
146 struct filebuf *outdata)
148 int i;
149 unsigned char* boot;
150 unsigned char* boot2;
151 unsigned char* disable;
152 uint32_t sum;
154 /* Create buffer for original nk.bin, plus our bootloader (with 12
155 byte header), plus the 16-byte "disable record", plus our dual-boot code */
156 outdata->len = indata->len + (bootdata->len + 12) + 16 + (12 + 28);
157 outdata->buf = malloc(outdata->len);
159 if (outdata->buf==NULL)
161 printf("[ERR] Could not allocate memory, aborting\n");
162 return -1;
165 /****** STEP 1 - Read original nk.bin into buffer */
166 memcpy(outdata->buf, indata->buf, indata->len);
168 /****** STEP 2 - Move EOF record to the new EOF */
169 memcpy(outdata->buf + outdata->len - 12, outdata->buf + indata->len - 12, 12);
171 /* Overwrite default entry point with NK_ENTRY_POINT */
172 put_uint32le(NK_ENTRY_POINT, outdata->buf + outdata->len - 8);
174 /****** STEP 3 - Create a record to disable the firmware signature
175 check in EBoot */
176 disable = outdata->buf + indata->len - 12;
178 put_uint32le(DISABLE_ADDR, disable);
179 put_uint32le(4, disable + 4);
180 put_uint32le(DISABLE_SUM, disable + 8);
181 put_uint32le(DISABLE_INSN, disable + 12);
183 /****** STEP 4 - Append the bootloader binary */
184 boot = disable + 16;
185 memcpy(boot + 12, bootdata->buf, bootdata->len);
187 /****** STEP 5 - Create header for bootloader record */
189 /* Calculate checksum */
190 sum = 0;
191 for (i = 0; i < bootdata->len; i++) {
192 sum += boot[12 + i];
195 put_uint32le(BL_ENTRY_POINT, boot); /* Our entry point */
196 put_uint32le(bootdata->len, boot + 4);
197 put_uint32le(sum, boot + 8);
199 /****** STEP 6 - Insert our dual-boot code */
200 boot2 = boot + bootdata->len + 12;
202 /* Copy dual-boot code in an endian-safe way */
203 for (i = 0; i < (signed int)sizeof(dualboot) / 4; i++) {
204 put_uint32le(dualboot[i], boot2 + 12 + i*4);
207 /* Calculate checksum */
208 sum = 0;
209 for (i = 0; i < (signed int)sizeof(dualboot); i++) {
210 sum += boot2[i+12];
213 put_uint32le(NK_ENTRY_POINT, boot2); /* New entry point for our nk.bin */
214 put_uint32le(sizeof(dualboot), boot2 + 4);
215 put_uint32le(sum, boot2 + 8);
217 return 0;
220 #if !defined(BEASTPATCHER)
221 static void usage(void)
223 printf("Usage: mknkboot <firmware file> <boot file> <output file>\n");
225 exit(1);
229 int main(int argc, char* argv[])
231 char *infile, *bootfile, *outfile;
232 int fdin = -1, fdboot = -1, fdout = -1;
233 int n;
234 struct filebuf indata = {0, NULL}, bootdata = {0, NULL}, outdata = {0, NULL};
235 int result = 0;
237 if(argc < 4) {
238 usage();
241 infile = argv[1];
242 bootfile = argv[2];
243 outfile = argv[3];
245 fdin = open(infile, O_RDONLY|O_BINARY);
246 if (fdin < 0)
248 perror(infile);
249 result = 2;
250 goto quit;
253 fdboot = open(bootfile, O_RDONLY|O_BINARY);
254 if (fdboot < 0)
256 perror(bootfile);
257 close(fdin);
258 result = 3;
259 goto quit;
262 indata.len = filesize(fdin);
263 bootdata.len = filesize(fdboot);
264 indata.buf = (unsigned char*)malloc(indata.len);
265 bootdata.buf = (unsigned char*)malloc(bootdata.len);
266 if(indata.buf == NULL || bootdata.buf == NULL)
268 printf("[ERR] Could not allocate memory, aborting\n");
269 result = 4;
270 goto quit;
272 n = read(fdin, indata.buf, indata.len);
273 if (n != indata.len)
275 printf("[ERR] Could not read from %s\n",infile);
276 result = 5;
277 goto quit;
279 n = read(fdboot, bootdata.buf, bootdata.len);
280 if (n != bootdata.len)
282 printf("[ERR] Could not read from %s\n",bootfile);
283 result = 6;
284 goto quit;
287 result = mknkboot(&indata, &bootdata, &outdata);
288 if(result != 0)
290 goto quit;
292 fdout = open(outfile, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
293 if (fdout < 0)
295 perror(outfile);
296 result = 7;
297 goto quit;
300 n = write(fdout, outdata.buf, outdata.len);
301 if (n != outdata.len)
303 printf("[ERR] Could not write output file %s\n",outfile);
304 result = 8;
305 goto quit;
308 quit:
309 free(bootdata.buf);
310 free(indata.buf);
311 free(outdata.buf);
312 close(fdin);
313 close(fdboot);
314 close(fdout);
316 return result;
319 #endif