Fix another oops with defining IRAMORIG twice. :p
[Rockbox.git] / tools / mknkboot.c
blobdfb3c99767bfaa68aff7121df8798a5f1f339842
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 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <inttypes.h>
30 /* New entry point for nk.bin - where our dualboot code is inserted */
31 #define NK_ENTRY_POINT 0x88200000
33 /* Entry point (and load address) for the main Rockbox bootloader */
34 #define BL_ENTRY_POINT 0x8a000000
38 Description of nk.bin from
40 http://www.xs4all.nl/~itsme/projects/xda/wince-flashfile-formats.html
42 these files contain most information, several non-contigouos blocks
43 may be present and an entrypoint in the code.
45 1. a 7 character signature "B000FF\n" ( that is with 3 zeroes, and
46 ending in a linefeed )
47 2. DWORD for image start
48 3. DWORD for image length
49 4. followd by several records of this format:
50 1. DWORD with address where this block is to be flashed to
51 2. DWORD with the length of this block
52 3. DWORD with the 32 bit checksum of this block, in perl:
53 unpack("%32C*", $data);
54 4. followed by <length> bytes of data
55 5. the last record has address ZERO, in the length the entrypoint
56 into the rom, and ZERO as checksum.
59 NOTE: The Gigabeat-S nk.bin contains 171 records, plus the EOF record.
61 mknkboot.c appends two images:
63 1) A "Disable" image which overwrites a word in the EBoot image
64 2) Our bootloader image, which has the same load address as nk.exe
68 /* win32 compatibility */
70 #ifndef O_BINARY
71 #define O_BINARY 0
72 #endif
74 #define DISABLE_ADDR 0x88065A10 /* in EBoot */
75 #define DISABLE_INSN 0xe3a00001
76 #define DISABLE_SUM (0xe3+0xa0+0x00+0x01)
78 /* Code to dual-boot - this is inserted at NK_ENTRY_POINT */
79 static uint32_t dualboot[] =
81 0xe59f900c, /* ldr r9, [pc, #12] -> 0x53fa4000 */
82 0xe5999000, /* ldr r9, [r9] */
83 0xe3190010, /* tst r9, #16 ; 0x10 */
84 #if 1
85 /* Branch to Rockbox if hold is on */
86 0x159ff004, /* ldrne pc, [pc, #4] -> 0x89000000 */
87 #else
88 /* Branch to Rockbox if hold is off */
89 0x059ff004, /* ldreq pc, [pc, #4] -> 0x89000000 */
90 #endif
91 /* Branch to original firmware */
92 0xea0003fa, /* b 0x1000 */
94 0x53fa4000, /* GPIO3_DR */
95 BL_ENTRY_POINT /* RB bootloader load address/entry point */
98 static void put_uint32le(uint32_t x, unsigned char* p)
100 p[0] = x & 0xff;
101 p[1] = (x >> 8) & 0xff;
102 p[2] = (x >> 16) & 0xff;
103 p[3] = (x >> 24) & 0xff;
106 static void usage(void)
108 printf("Usage: mknkboot <firmware file> <boot file> <output file>\n");
110 exit(1);
113 static off_t filesize(int fd) {
114 struct stat buf;
116 if (fstat(fd,&buf) < 0) {
117 perror("[ERR] Checking filesize of input file");
118 return -1;
119 } else {
120 return(buf.st_size);
125 int main(int argc, char *argv[])
127 char *infile, *bootfile, *outfile;
128 int fdin, fdboot,fdout;
129 int i,n;
130 int inlength,bootlength,newlength;
131 unsigned char* buf;
132 unsigned char* boot;
133 unsigned char* boot2;
134 unsigned char* disable;
135 uint32_t sum;
137 if(argc < 3) {
138 usage();
141 infile = argv[1];
142 bootfile = argv[2];
143 outfile = argv[3];
145 fdin = open(infile, O_RDONLY|O_BINARY);
146 if (fdin < 0)
148 perror(infile);
151 fdboot = open(bootfile, O_RDONLY|O_BINARY);
152 if (fdboot < 0)
154 perror(bootfile);
157 inlength = filesize(fdin);
159 bootlength = filesize(fdboot);
161 /* Create buffer for original nk.bin, plus our bootloader (with 12
162 byte header), plus the 16-byte "disable record", plus our dual-boot code */
164 newlength = inlength + (bootlength + 12) + 16 + (12 + 28);
165 buf = malloc(newlength);
167 if (buf==NULL)
169 printf("[ERR] Could not allocate memory, aborting\n");
170 return 1;
173 /****** STEP 1 - Read original nk.bin into buffer */
175 n = read(fdin, buf, inlength);
176 if (n != inlength)
178 printf("[ERR] Could not read from %s\n",infile);
179 return 2;
182 /****** STEP 2 - Move EOF record to the new EOF */
183 memcpy(buf + newlength - 12, buf + inlength - 12, 12);
185 /* Overwrite default entry point with NK_ENTRY_POINT */
186 put_uint32le(NK_ENTRY_POINT, buf + newlength - 8);
188 /****** STEP 3 - Create a record to disable the firmware signature
189 check in EBoot */
190 disable = buf + inlength - 12;
192 put_uint32le(DISABLE_ADDR, disable);
193 put_uint32le(4, disable + 4);
194 put_uint32le(DISABLE_SUM, disable + 8);
195 put_uint32le(DISABLE_INSN, disable + 12);
197 /****** STEP 4 - Read the bootloader binary */
198 boot = disable + 16;
199 n = read(fdboot, boot + 12, bootlength);
200 if (n != bootlength)
202 printf("[ERR] Could not read from %s\n",bootfile);
203 return 3;
206 /****** STEP 5 - Create header for bootloader record */
208 /* Calculate checksum */
209 sum = 0;
210 for (i = 0; i < bootlength; i++) {
211 sum += boot[12 + i];
214 put_uint32le(BL_ENTRY_POINT, boot); /* Our entry point */
215 put_uint32le(bootlength, boot + 4);
216 put_uint32le(sum, boot + 8);
218 /****** STEP 6 - Insert our dual-boot code */
219 boot2 = boot + bootlength + 12;
221 /* Copy dual-boot code in an endian-safe way */
222 for (i = 0; i < sizeof(dualboot) / 4; i++) {
223 put_uint32le(dualboot[i], boot2 + 12 + i*4);
226 /* Calculate checksum */
227 sum = 0;
228 for (i = 0; i < sizeof(dualboot); i++) {
229 sum += boot2[i+12];
232 put_uint32le(NK_ENTRY_POINT, boot2); /* New entry point for our nk.bin */
233 put_uint32le(sizeof(dualboot), boot2 + 4);
234 put_uint32le(sum, boot2 + 8);
236 /****** STEP 7 - Now write the output file */
238 fdout = open(outfile, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
239 if (fdout < 0)
241 perror(outfile);
244 n = write(fdout, buf, newlength);
245 if (n != newlength)
247 printf("[ERR] Could not write output file %s\n",outfile);
248 return 3;
251 close(fdin);
252 close(fdboot);
253 close(fdout);
255 return 0;