summaryrefslogtreecommitdiff
path: root/utils/AMS/hacking/mkamsboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/AMS/hacking/mkamsboot.c')
-rw-r--r--utils/AMS/hacking/mkamsboot.c341
1 files changed, 0 insertions, 341 deletions
diff --git a/utils/AMS/hacking/mkamsboot.c b/utils/AMS/hacking/mkamsboot.c
deleted file mode 100644
index 52ead58b69..0000000000
--- a/utils/AMS/hacking/mkamsboot.c
+++ /dev/null
@@ -1,341 +0,0 @@
1/*
2
3mkamsboot.c - a tool for merging bootloader code into an Sansa V2
4 (AMS) firmware file
5
6Copyright (C) Dave Chapman 2008
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
21
22*/
23
24
25/*
26
27Insert a Rockbox bootloader into an AMS original firmware file.
28
29We replace the main firmware block (bytes 0x400..0x400+firmware_size)
30as follows:
31
32
33 --------------------- 0x0
34| |
35| Rockbox bootloader |
36| |
37|---------------------|
38| EMPTY SPACE |
39|---------------------|
40| ucl unpack function |
41|---------------------|
42| |
43| compressed OF image |
44| |
45| |
46 ---------------------
47
48This entire block fits into the space previously occupied by the main
49firmware block, and gives about 40KB of space to store the Rockbox
50bootloader. This could be increased if we also UCL compress the
51Rockbox bootloader.
52
53mkamsboot then corrects the checksums and writes a new legal firmware
54file which can be installed on the device.
55
56Our bootloader first checks for the "dual-boot" keypress, and then either:
57
58a) Copies the ucl unpack function and compressed OF image to an unused
59 part of RAM and then branches to the ucl_unpack function, which
60 will then branch to 0x0 after decompressing the OF to that location.
61
62b) Continues running with our test code
63
64*/
65
66
67#include <stdio.h>
68#include <stdlib.h>
69#include <stdint.h>
70#include <sys/types.h>
71#include <sys/stat.h>
72#include <fcntl.h>
73#include <unistd.h>
74#include <string.h>
75
76
77/* Win32 compatibility */
78#ifndef O_BINARY
79#define O_BINARY 0
80#endif
81
82
83#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
84
85
86/* This magic should appear at the start of any UCL file */
87static const unsigned char uclmagic[] = {
88 0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a
89};
90
91
92static off_t filesize(int fd) {
93 struct stat buf;
94
95 if (fstat(fd,&buf) < 0) {
96 perror("[ERR] Checking filesize of input file");
97 return -1;
98 } else {
99 return(buf.st_size);
100 }
101}
102
103static uint32_t get_uint32le(unsigned char* p)
104{
105 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
106}
107
108static uint32_t get_uint32be(unsigned char* p)
109{
110 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
111
112}
113
114static void put_uint32le(unsigned char* p, uint32_t x)
115{
116 p[0] = x & 0xff;
117 p[1] = (x >> 8) & 0xff;
118 p[2] = (x >> 16) & 0xff;
119 p[3] = (x >> 24) & 0xff;
120}
121
122static int calc_checksum(unsigned char* buf, uint32_t n)
123{
124 uint32_t sum = 0;
125 uint32_t i;
126
127 for (i=0;i<n;i+=4)
128 sum += get_uint32le(buf + i);
129
130 return sum;
131}
132
133void usage(void)
134{
135 printf("Usage: mkamsboot <firmware file> <ucl image> <boot file> <ucl unpack file> <output file>\n");
136
137 exit(1);
138}
139
140int main(int argc, char* argv[])
141{
142 char *infile, *uclfile, *bootfile, *uclunpackfile, *outfile;
143 int fdin, fducl, fdboot, fduclunpack, fdout;
144 off_t len;
145 unsigned char uclheader[26];
146 uint32_t n;
147 unsigned char* buf;
148 uint32_t firmware_size;
149 uint32_t firmware_paddedsize;
150 uint32_t bootloader_size;
151 uint32_t ucl_size;
152 uint32_t ucl_paddedsize;
153 uint32_t uclunpack_size;
154 uint32_t sum,filesum;
155 uint32_t i;
156
157 if(argc != 6) {
158 usage();
159 }
160
161 infile = argv[1];
162 uclfile = argv[2];
163 bootfile = argv[3];
164 uclunpackfile = argv[4];
165 outfile = argv[5];
166
167 /* Open the bootloader file */
168 fdboot = open(bootfile, O_RDONLY|O_BINARY);
169 if (fdboot < 0)
170 {
171 fprintf(stderr,"[ERR] Could not open %s for reading\n",bootfile);
172 return 1;
173 }
174
175 bootloader_size = filesize(fdboot);
176
177
178 /* Open the UCL-compressed image of the firmware block */
179 fduclunpack = open(uclunpackfile, O_RDONLY|O_BINARY);
180 if (fduclunpack < 0)
181 {
182 fprintf(stderr,"[ERR] Could not open %s for reading\n",uclunpackfile);
183 return 1;
184 }
185
186 uclunpack_size = filesize(fduclunpack);
187
188
189 /* Open the UCL-compressed image of the firmware block */
190 fducl = open(uclfile, O_RDONLY|O_BINARY);
191 if (fducl < 0)
192 {
193 fprintf(stderr,"[ERR] Could not open %s for reading\n",uclfile);
194 return 1;
195 }
196
197 /* Some UCL file sanity checks */
198 n = read(fducl, uclheader, sizeof(uclheader));
199
200 if (n != sizeof(uclheader)) {
201 fprintf(stderr,"[ERR] Could not read header from UCL file\n");
202 return 1;
203 }
204
205 if (memcmp(uclmagic, uclheader, sizeof(uclmagic))!=0) {
206 fprintf(stderr,"[ERR] Invalid UCL file\n");
207 return 1;
208 }
209
210 if (uclheader[12] != 0x2e) {
211 fprintf(stderr,"[ERR] Unsupported UCL compression format (0x%02x) - only 0x2e supported.\n",uclheader[12]);
212 return 1;
213 }
214 ucl_size = get_uint32be(&uclheader[22]) + 8;
215 ucl_paddedsize = (ucl_size + 3) & ~0x3;
216
217 if (ucl_size + 26 > (unsigned)filesize(fducl)) {
218 fprintf(stderr, "[ERR] Size mismatch in UCL file\n");
219 return 1;
220 }
221
222 /* Open the firmware file */
223 fdin = open(infile,O_RDONLY|O_BINARY);
224
225 if (fdin < 0) {
226 fprintf(stderr,"[ERR] Could not open %s for reading\n",infile);
227 return 1;
228 }
229
230 if ((len = filesize(fdin)) < 0)
231 return 1;
232
233 /* Allocate memory for the OF image - we don't change the size */
234 if ((buf = malloc(len)) == NULL) {
235 fprintf(stderr,"[ERR] Could not allocate buffer for input file (%d bytes)\n",(int)len);
236 return 1;
237 }
238
239 n = read(fdin, buf, len);
240
241 if (n != (uint32_t)len) {
242 fprintf(stderr,"[ERR] Could not read firmware file\n");
243 return 1;
244 }
245
246 close(fdin);
247
248 /* Get the firmware size */
249 firmware_size = get_uint32le(&buf[0x0c]);
250
251 /* Round size up to next multiple of 0x200 */
252
253 firmware_paddedsize = PAD_TO_BOUNDARY(firmware_size);
254
255 fprintf(stderr,"Original firmware size - %d bytes\n",firmware_size);
256 fprintf(stderr,"Padded firmware size - %d bytes\n",firmware_paddedsize);
257 fprintf(stderr,"Bootloader size - %d bytes\n",bootloader_size);
258 fprintf(stderr,"UCL image size - %d bytes (%d bytes padded)\n",ucl_size,ucl_paddedsize);
259 fprintf(stderr,"UCL unpack function size - %d bytes\n",uclunpack_size);
260 fprintf(stderr,"Original total size of firmware - %d bytes\n",(int)len);
261
262 /* Check we have room for our bootloader - in the future, we could UCL
263 pack this image as well if we need to. */
264 if (bootloader_size > (firmware_size - ucl_paddedsize - uclunpack_size)) {
265 fprintf(stderr,"[ERR] Bootloader too large (%d bytes, %d available)\n",
266 bootloader_size, firmware_size - ucl_paddedsize - uclunpack_size);
267 return 1;
268 }
269
270 /* Zero the original firmware area - not needed, but helps debugging */
271 memset(buf + 0x400, 0, firmware_size);
272
273 /* Locate our bootloader code at the start of the firmware block */
274 n = read(fdboot, buf + 0x400, bootloader_size);
275
276 if (n != bootloader_size) {
277 fprintf(stderr,"[ERR] Could not load bootloader file\n");
278 return 1;
279 }
280 close(fdboot);
281
282 /* Locate the compressed image of the original firmware block at the end
283 of the firmware block */
284 n = read(fducl, buf + 0x400 + firmware_size - ucl_paddedsize, ucl_size);
285
286 if (n != ucl_size) {
287 fprintf(stderr,"[ERR] Could not load ucl file\n");
288 return 1;
289 }
290 close(fducl);
291
292
293 /* Locate our UCL unpack function before copy of the compressed firmware */
294 n = read(fduclunpack, buf + 0x400 + firmware_size - ucl_paddedsize - uclunpack_size, uclunpack_size);
295
296 if (n != uclunpack_size) {
297 fprintf(stderr,"[ERR] Could not load uclunpack file\n");
298 return 1;
299 }
300 close(fduclunpack);
301
302 put_uint32le(&buf[0x420], 0x40000 - ucl_paddedsize - uclunpack_size + 1); /* UCL unpack entry point */
303 put_uint32le(&buf[0x424], 0x40000 - ucl_paddedsize); /* Location of OF */
304 put_uint32le(&buf[0x428], ucl_size); /* Size of UCL image */
305 put_uint32le(&buf[0x42c], firmware_size - uclunpack_size - ucl_paddedsize); /* Start of data to copy */
306 put_uint32le(&buf[0x430], uclunpack_size + ucl_paddedsize); /* Size of data to copy */
307
308 /* Update checksum */
309 sum = calc_checksum(buf + 0x400,firmware_size);
310
311 put_uint32le(&buf[0x04], sum);
312 put_uint32le(&buf[0x204], sum);
313
314 /* Update the whole-file checksum */
315 filesum = 0;
316 for (i=0;i < (unsigned)len - 4; i+=4)
317 filesum += get_uint32le(&buf[i]);
318
319 put_uint32le(buf + len - 4, filesum);
320
321
322 /* Write the new firmware */
323 fdout = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
324
325 if (fdout < 0) {
326 fprintf(stderr,"[ERR] Could not open %s for writing\n",outfile);
327 return 1;
328 }
329
330 n = write(fdout, buf, len);
331
332 if (n != (unsigned)len) {
333 fprintf(stderr,"[ERR] Could not write firmware file\n");
334 return 1;
335 }
336
337 close(fdout);
338
339 return 0;
340
341}