1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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
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 ****************************************************************************/
42 #include <sys/types.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 */
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 */
109 /* Branch to Rockbox if hold is on */
110 0x159ff004, /* ldrne pc, [pc, #4] -> 0x89000000 */
112 /* Branch to Rockbox if hold is off */
113 0x059ff004, /* ldreq pc, [pc, #4] -> 0x89000000 */
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
) {
135 if (fstat(fd
,&buf
) < 0) {
136 perror("[ERR] Checking filesize of input file");
145 int mknkboot(const struct filebuf
*indata
, const struct filebuf
*bootdata
,
146 struct filebuf
*outdata
)
150 unsigned char* boot2
;
151 unsigned char* disable
;
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");
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
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 */
185 memcpy(boot
+ 12, bootdata
->buf
, bootdata
->len
);
187 /****** STEP 5 - Create header for bootloader record */
189 /* Calculate checksum */
191 for (i
= 0; i
< bootdata
->len
; 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 */
209 for (i
= 0; i
< (signed int)sizeof(dualboot
); i
++) {
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);
220 #if !defined(BEASTPATCHER)
221 static void usage(void)
223 printf("Usage: mknkboot <firmware file> <boot file> <output file>\n");
229 int main(int argc
, char* argv
[])
231 char *infile
, *bootfile
, *outfile
;
232 int fdin
= -1, fdboot
= -1, fdout
= -1;
234 struct filebuf indata
= {0, NULL
}, bootdata
= {0, NULL
}, outdata
= {0, NULL
};
245 fdin
= open(infile
, O_RDONLY
|O_BINARY
);
253 fdboot
= open(bootfile
, O_RDONLY
|O_BINARY
);
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");
272 n
= read(fdin
, indata
.buf
, indata
.len
);
275 printf("[ERR] Could not read from %s\n",infile
);
279 n
= read(fdboot
, bootdata
.buf
, bootdata
.len
);
280 if (n
!= bootdata
.len
)
282 printf("[ERR] Could not read from %s\n",bootfile
);
287 result
= mknkboot(&indata
, &bootdata
, &outdata
);
292 fdout
= open(outfile
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_BINARY
, 0644);
300 n
= write(fdout
, outdata
.buf
, outdata
.len
);
301 if (n
!= outdata
.len
)
303 printf("[ERR] Could not write output file %s\n",outfile
);