diff options
author | Jens Arnold <amiconn@rockbox.org> | 2011-06-19 17:23:18 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2011-06-19 17:23:18 +0000 |
commit | 91ce4b2a60c4cbe8e3568f79c3a73572461ff40d (patch) | |
tree | 863cf4142841fee4dd53e2849d060d2c559cca55 /tools | |
parent | e9e0cf59085cb3b3d77c8a2962fd8b80ac4d0c9d (diff) | |
download | rockbox-91ce4b2a60c4cbe8e3568f79c3a73572461ff40d.tar.gz rockbox-91ce4b2a60c4cbe8e3568f79c3a73572461ff40d.zip |
Optional dual-boot support in iAudio X5 and M5 bootloader, based on FS#5289.
In order to enable it, #define HAVE_DUALBOOT when building the bootloader.
Do not use the automatically created x5_fw.bin or m5_fw.bin, but use mkboot
to create a new firmware file from an OF x5_fw.bin resp. m5_fw.bin and
bootloader.bin.
The dual-boot bootloader boots the OF when pressing Play (main or remote) for
more than 3 seconds. Hold it a bit longer because the OF also checks buttons.
Short press boots rockbox.
As a bonus, the Play button read (for hold check) is done a bit earlier for
single-boot mode as well.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30018 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'tools')
-rw-r--r-- | tools/mkboot.c | 172 | ||||
-rw-r--r-- | tools/mkboot.h | 3 |
2 files changed, 153 insertions, 22 deletions
diff --git a/tools/mkboot.c b/tools/mkboot.c index 49d6452b4a..f7c7b4668d 100644 --- a/tools/mkboot.c +++ b/tools/mkboot.c | |||
@@ -26,42 +26,46 @@ | |||
26 | #ifndef RBUTIL | 26 | #ifndef RBUTIL |
27 | static void usage(void) | 27 | static void usage(void) |
28 | { | 28 | { |
29 | printf("usage: mkboot [-h300] <firmware file> <boot file> <output file>\n"); | 29 | printf("usage: mkboot <target> <firmware file> <boot file> <output file>\n"); |
30 | printf("available targets:\n" | ||
31 | "\t-h100 Iriver H1x0\n" | ||
32 | "\t-h300 Iriver H3x0\n" | ||
33 | "\t-iax5 iAudio X5\n" | ||
34 | "\t-iam5 iAudio M5\n"); | ||
30 | 35 | ||
31 | exit(1); | 36 | exit(1); |
32 | } | 37 | } |
33 | #endif | 38 | #endif |
34 | 39 | ||
35 | static unsigned char image[0x400000 + 0x220 + 0x400000/0x200]; | ||
36 | |||
37 | #ifndef RBUTIL | 40 | #ifndef RBUTIL |
38 | int main(int argc, char *argv[]) | 41 | int main(int argc, char *argv[]) |
39 | { | 42 | { |
40 | char *infile, *bootfile, *outfile; | 43 | if(argc != 5) |
41 | int origin = 0x1f0000; /* H1x0 bootloader address */ | 44 | { |
42 | |||
43 | if(argc < 3) { | ||
44 | usage(); | 45 | usage(); |
46 | return 1; | ||
45 | } | 47 | } |
46 | 48 | ||
47 | if(!strcmp(argv[1], "-h300")) { | 49 | if ( ! strcmp(argv[1], "-h100")) |
48 | infile = argv[2]; | 50 | return mkboot_iriver(argv[2], argv[3], argv[4], 0x1f0000); |
49 | bootfile = argv[3]; | 51 | |
50 | outfile = argv[4]; | 52 | if ( ! strcmp(argv[1], "-h300")) |
53 | return mkboot_iriver(argv[2], argv[3], argv[4], 0x3f0000); | ||
54 | |||
55 | if ( ! strcmp(argv[1], "-iax5")) | ||
56 | return mkboot_iaudio(argv[2], argv[3], argv[4], 0); | ||
57 | |||
58 | if ( ! strcmp(argv[1], "-iam5")) | ||
59 | return mkboot_iaudio(argv[2], argv[3], argv[4], 1); | ||
51 | 60 | ||
52 | origin = 0x3f0000; /* H3x0 bootloader address */ | 61 | usage(); |
53 | } | 62 | return 1; |
54 | else | ||
55 | { | ||
56 | infile = argv[1]; | ||
57 | bootfile = argv[2]; | ||
58 | outfile = argv[3]; | ||
59 | } | ||
60 | return mkboot(infile, bootfile, outfile, origin); | ||
61 | } | 63 | } |
62 | #endif | 64 | #endif |
63 | 65 | ||
64 | int mkboot(const char* infile, const char* bootfile, const char* outfile, int origin) | 66 | static unsigned char image[0x400000 + 0x220 + 0x400000/0x200]; |
67 | |||
68 | int mkboot_iriver(const char* infile, const char* bootfile, const char* outfile, int origin) | ||
65 | { | 69 | { |
66 | FILE *f; | 70 | FILE *f; |
67 | int i; | 71 | int i; |
@@ -187,3 +191,129 @@ int mkboot(const char* infile, const char* bootfile, const char* outfile, int or | |||
187 | 191 | ||
188 | return 0; | 192 | return 0; |
189 | } | 193 | } |
194 | |||
195 | /* iAudio firmware update file header size */ | ||
196 | #define HEADER_SIZE 0x1030 | ||
197 | /* Address of flash contents that get overwritten by a firmware update. | ||
198 | * Contents before this address contain the preloader and are not affected | ||
199 | * by a firmware update. | ||
200 | * -> Firmware update file contents starting at offset HEADER_SIZE end up | ||
201 | * in flash at address FLASH_START | ||
202 | */ | ||
203 | #define FLASH_START 0x00010000 | ||
204 | /* Start of unused space in original firmware (flash address, not file | ||
205 | * offset!) where we patch in the Rockbox loader */ | ||
206 | #define ROCKBOX_BOOTLOADER 0x00150000 | ||
207 | /* End of unused space in original firmware */ | ||
208 | #define BOOTLOADER_LIMIT 0x00170000 | ||
209 | |||
210 | /* Patch the Rockbox bootloader into free space in the original firmware | ||
211 | * (starting at 0x150000). The preloader starts execution of the OF at | ||
212 | * 0x10000 which normally contains a jsr 0x10010. We also patch this to | ||
213 | * do a jsr 0x150000 to the Rockbox dual boot loader instead. If it then | ||
214 | * decides to start the OF instead of Rockbox, it simply does a jmp | ||
215 | * 0x10010 instead of loading Rockbox from disk. | ||
216 | */ | ||
217 | int mkboot_iaudio(const char* infile, const char* bootfile, const char* outfile, int model_nr) | ||
218 | { | ||
219 | size_t flength, blength; | ||
220 | unsigned char *bbuf, *fbuf, *p; | ||
221 | const unsigned char fsig[] = { | ||
222 | 0x4e, 0xb9, 0x00, 0x01, 0x00, 0x10 }; /* jsr 0x10010 */ | ||
223 | unsigned char bsig[2][8] = { | ||
224 | /* dualboot signatures */ | ||
225 | { 0x60, 0x06, 0x44, 0x42, 0x69, 0x61, 0x78, 0x35 }, /* X5 */ | ||
226 | { 0x60, 0x06, 0x44, 0x42, 0x69, 0x61, 0x6d, 0x35 }, /* M5 */ }; | ||
227 | FILE *ffile, *bfile, *ofile; | ||
228 | unsigned char sum = 0; | ||
229 | int i; | ||
230 | |||
231 | /* read input files */ | ||
232 | if ((bfile = fopen(bootfile, "rb")) == NULL) { | ||
233 | perror("Cannot open Rockbox bootloader file.\n"); | ||
234 | return 1; | ||
235 | } | ||
236 | |||
237 | fseek(bfile, 0, SEEK_END); | ||
238 | blength = ftell(bfile); | ||
239 | fseek(bfile, 0, SEEK_SET); | ||
240 | |||
241 | if (blength + ROCKBOX_BOOTLOADER >= BOOTLOADER_LIMIT) { | ||
242 | fprintf(stderr, "Rockbox bootloader is too big.\n"); | ||
243 | return 1; | ||
244 | } | ||
245 | |||
246 | if ((ffile = fopen(infile, "rb")) == NULL) { | ||
247 | perror("Cannot open original firmware file."); | ||
248 | return 1; | ||
249 | } | ||
250 | |||
251 | fseek(ffile, 0, SEEK_END); | ||
252 | flength = ftell(ffile); | ||
253 | fseek(ffile, 0, SEEK_SET); | ||
254 | |||
255 | bbuf = malloc(blength); | ||
256 | fbuf = malloc(flength); | ||
257 | |||
258 | if (!bbuf || !fbuf) { | ||
259 | fprintf(stderr, "Out of memory.\n"); | ||
260 | return 1; | ||
261 | } | ||
262 | |||
263 | if ( fread(bbuf, 1, blength, bfile) < blength | ||
264 | || fread(fbuf, 1, flength, ffile) < flength) { | ||
265 | fprintf(stderr, "Read error.\n"); | ||
266 | return 1; | ||
267 | } | ||
268 | fclose(bfile); | ||
269 | fclose(ffile); | ||
270 | |||
271 | /* verify format of input files */ | ||
272 | if (blength < 0x10 || memcmp(bbuf, bsig[model_nr], sizeof(bsig[0]))) { | ||
273 | fprintf(stderr, "Rockbox bootloader format error (is it bootloader.bin?).\n"); | ||
274 | return 1; | ||
275 | } | ||
276 | if (flength < HEADER_SIZE-FLASH_START+BOOTLOADER_LIMIT | ||
277 | || memcmp(fbuf+HEADER_SIZE, fsig, sizeof(fsig))) { | ||
278 | fprintf(stderr, "Original firmware format error.\n"); | ||
279 | return 1; | ||
280 | } | ||
281 | |||
282 | /* verify firmware is not overrun */ | ||
283 | for (i = ROCKBOX_BOOTLOADER; i < BOOTLOADER_LIMIT; i++) { | ||
284 | if (fbuf[HEADER_SIZE-FLASH_START+i] != 0xff) { | ||
285 | fprintf(stderr, "Original firmware has grown too much.\n"); | ||
286 | return 1; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | /* change jsr 0x10010 to jsr DUAL_BOOTLOADER */ | ||
291 | p = fbuf + HEADER_SIZE + 2; | ||
292 | *p++ = (ROCKBOX_BOOTLOADER >> 24) & 0xff; | ||
293 | *p++ = (ROCKBOX_BOOTLOADER >> 16) & 0xff; | ||
294 | *p++ = (ROCKBOX_BOOTLOADER >> 8) & 0xff; | ||
295 | *p++ = (ROCKBOX_BOOTLOADER ) & 0xff; | ||
296 | |||
297 | p = fbuf + HEADER_SIZE + ROCKBOX_BOOTLOADER - FLASH_START; | ||
298 | memcpy(p, bbuf, blength); | ||
299 | |||
300 | /* recalc checksum */ | ||
301 | for (i = HEADER_SIZE; (size_t)i < flength; i++) | ||
302 | sum += fbuf[i]; | ||
303 | fbuf[0x102b] = sum; | ||
304 | |||
305 | /* write output */ | ||
306 | if ((ofile = fopen(outfile, "wb")) == NULL) { | ||
307 | perror("Cannot open output file"); | ||
308 | return 1; | ||
309 | } | ||
310 | if (fwrite(fbuf, 1, flength, ofile) < flength) { | ||
311 | fprintf(stderr, "Write error.\n"); | ||
312 | return 1; | ||
313 | } | ||
314 | fclose(ofile); | ||
315 | free(bbuf); | ||
316 | free(fbuf); | ||
317 | |||
318 | return 0; | ||
319 | } \ No newline at end of file | ||
diff --git a/tools/mkboot.h b/tools/mkboot.h index 980e469b87..ba12d1b473 100644 --- a/tools/mkboot.h +++ b/tools/mkboot.h | |||
@@ -26,7 +26,8 @@ | |||
26 | extern "C" { | 26 | extern "C" { |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | int mkboot(const char* infile, const char* bootfile, const char* outfile, int origin); | 29 | int mkboot_iriver(const char* infile, const char* bootfile, const char* outfile, int origin); |
30 | int mkboot_iaudio(const char* infile, const char* bootfile, const char* outfile, int model_nr); | ||
30 | 31 | ||
31 | #ifdef __cplusplus | 32 | #ifdef __cplusplus |
32 | } | 33 | } |