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 | |
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
-rw-r--r-- | bootloader/bootloader.make | 3 | ||||
-rw-r--r-- | bootloader/iaudio_coldfire.c | 16 | ||||
-rw-r--r-- | firmware/target/coldfire/crt0.S | 53 | ||||
-rw-r--r-- | firmware/target/coldfire/iaudio/boot.lds | 6 | ||||
-rw-r--r-- | rbutil/rbutilqt/base/bootloaderinstallhex.cpp | 2 | ||||
-rw-r--r-- | tools/mkboot.c | 172 | ||||
-rw-r--r-- | tools/mkboot.h | 3 |
7 files changed, 220 insertions, 35 deletions
diff --git a/bootloader/bootloader.make b/bootloader/bootloader.make index 0118235bb7..78b8b438c4 100644 --- a/bootloader/bootloader.make +++ b/bootloader/bootloader.make | |||
@@ -10,6 +10,7 @@ | |||
10 | INCLUDES += -I$(APPSDIR) | 10 | INCLUDES += -I$(APPSDIR) |
11 | SRC += $(call preprocess, $(APPSDIR)/SOURCES) | 11 | SRC += $(call preprocess, $(APPSDIR)/SOURCES) |
12 | 12 | ||
13 | CONFIGFILE := $(FIRMDIR)/export/config/$(MODELNAME).h | ||
13 | BOOTLDS := $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/boot.lds | 14 | BOOTLDS := $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/boot.lds |
14 | BOOTLINK := $(BUILDDIR)/boot.link | 15 | BOOTLINK := $(BUILDDIR)/boot.link |
15 | 16 | ||
@@ -17,7 +18,7 @@ CLEANOBJS += $(BUILDDIR)/bootloader.* | |||
17 | 18 | ||
18 | .SECONDEXPANSION: | 19 | .SECONDEXPANSION: |
19 | 20 | ||
20 | $(BOOTLINK): $(BOOTLDS) | 21 | $(BOOTLINK): $(BOOTLDS) $(CONFIGFILE) |
21 | $(call PRINTS,PP $(@F)) | 22 | $(call PRINTS,PP $(@F)) |
22 | $(call preprocess2file,$<,$@,-DLOADADDRESS=$(LOADADDRESS)) | 23 | $(call preprocess2file,$<,$@,-DLOADADDRESS=$(LOADADDRESS)) |
23 | 24 | ||
diff --git a/bootloader/iaudio_coldfire.c b/bootloader/iaudio_coldfire.c index 5639a0e59b..9c829c4a34 100644 --- a/bootloader/iaudio_coldfire.c +++ b/bootloader/iaudio_coldfire.c | |||
@@ -123,6 +123,10 @@ void check_battery(void) | |||
123 | } | 123 | } |
124 | } | 124 | } |
125 | 125 | ||
126 | #if defined(IAUDIO_M5) || defined(IAUDIO_X5) | ||
127 | int initial_gpio_read; | ||
128 | #endif | ||
129 | |||
126 | void main(void) | 130 | void main(void) |
127 | { | 131 | { |
128 | int i; | 132 | int i; |
@@ -144,17 +148,13 @@ void main(void) | |||
144 | if ((GPIO_READ & 0x80000000) == 0) | 148 | if ((GPIO_READ & 0x80000000) == 0) |
145 | rc_on_button = true; | 149 | rc_on_button = true; |
146 | #elif defined(IAUDIO_M5) || defined(IAUDIO_X5) | 150 | #elif defined(IAUDIO_M5) || defined(IAUDIO_X5) |
147 | int data; | ||
148 | |||
149 | or_l(0x0e000000, &GPIO_FUNCTION); /* main Hold & Power, remote Play */ | 151 | or_l(0x0e000000, &GPIO_FUNCTION); /* main Hold & Power, remote Play */ |
150 | and_l(~0x0e000000, &GPIO_ENABLE); | 152 | and_l(~0x0e000000, &GPIO_ENABLE); |
151 | 153 | ||
152 | data = GPIO_READ; | 154 | if ((initial_gpio_read & 0x04000000) == 0) |
153 | |||
154 | if ((data & 0x04000000) == 0) | ||
155 | on_button = true; | 155 | on_button = true; |
156 | 156 | ||
157 | if ((data & 0x02000000) == 0) | 157 | if ((initial_gpio_read & 0x02000000) == 0) |
158 | rc_on_button = true; | 158 | rc_on_button = true; |
159 | #endif | 159 | #endif |
160 | 160 | ||
diff --git a/firmware/target/coldfire/crt0.S b/firmware/target/coldfire/crt0.S index e6717710b1..881fcf908f 100644 --- a/firmware/target/coldfire/crt0.S +++ b/firmware/target/coldfire/crt0.S | |||
@@ -26,11 +26,51 @@ | |||
26 | .global start | 26 | .global start |
27 | start: | 27 | start: |
28 | 28 | ||
29 | #if defined(BOOTLOADER) && defined(HAVE_DUALBOOT) \ | ||
30 | && (defined(IAUDIO_X5) || defined(IAUDIO_M5)) | ||
31 | |||
32 | /* 8 byte dualboot signature */ | ||
33 | bra.b 1f /* 0x6006 */ | ||
34 | .short 0x4442 /* DB */ | ||
35 | #if defined(IAUDIO_X5) | ||
36 | .long 0x69617835 /* iax5 */ | ||
37 | #elif defined(IAUDIO_M5) | ||
38 | .long 0x69616d35 /* iam5 */ | ||
39 | #else | ||
40 | #error Dualboot signature not defined | ||
41 | #endif | ||
42 | 1: | ||
43 | /* As the control registers are write-only, we're relying on MBAR2 being */ | ||
44 | /* set up correctly by the preloader for button check */ | ||
45 | /* Only use scratch regs until we're sure that we will boot rockbox */ | ||
46 | lea MBAR2, %a1 | ||
47 | move.l (%a1), %a0 /* store GPIO_READ result for button check in main() */ | ||
48 | |||
49 | /* Wait ~3 seconds for ON-button release. We need roughly 300ns per | ||
50 | iteration, so we check 10000000 times to reach the desired delay */ | ||
51 | move.l #10000000, %d0 | ||
52 | .on_button_test: | ||
53 | move.l (%a1), %d1 /* GPIO_READ */ | ||
54 | and.l #0x06000000, %d1 /* Check main (bit 25=0) and remote (bit 26=0) */ | ||
55 | cmp.l #0x06000000, %d1 /* ON buttons simultaneously */ | ||
56 | beq.b .loadrockbox | ||
57 | subq.l #1, %d0 | ||
58 | bne.b .on_button_test | ||
59 | |||
60 | .loadoriginal: | ||
61 | jmp 0x10010 | ||
62 | |||
63 | .loadrockbox: | ||
64 | move.l %a0, %d7 /* keep initial GPIO_READ value in %d7 for now */ | ||
65 | |||
66 | #endif /* defined(BOOTLOADER && defined(HAVE_DUALBOOT) | ||
67 | && (defined(IAUDIO_X5) || defined(IAUDIO_M5)) */ | ||
68 | |||
29 | move.w #0x2700,%sr | 69 | move.w #0x2700,%sr |
30 | 70 | ||
31 | move.l #vectors,%d0 | 71 | move.l #vectors,%d0 |
32 | movec.l %d0,%vbr | 72 | movec.l %d0,%vbr |
33 | 73 | ||
34 | move.l #MBAR+1,%d0 | 74 | move.l #MBAR+1,%d0 |
35 | movec.l %d0,%mbar | 75 | movec.l %d0,%mbar |
36 | 76 | ||
@@ -39,7 +79,12 @@ start: | |||
39 | 79 | ||
40 | lea MBAR,%a0 | 80 | lea MBAR,%a0 |
41 | lea MBAR2,%a1 | 81 | lea MBAR2,%a1 |
42 | 82 | ||
83 | #if defined(BOOTLOADER) && !defined(HAVE_DUALBOOT) \ | ||
84 | && (defined(IAUDIO_X5) || defined(IAUDIO_M5)) | ||
85 | move.l (%a1), %d7 /* store GPIO_READ result for button check in main() */ | ||
86 | #endif | ||
87 | |||
43 | clr.l (0x180,%a1) /* PLLCR = 0 */ | 88 | clr.l (0x180,%a1) /* PLLCR = 0 */ |
44 | 89 | ||
45 | /* 64K DMA-capable SRAM at 0x10000000 | 90 | /* 64K DMA-capable SRAM at 0x10000000 |
@@ -318,6 +363,10 @@ start: | |||
318 | move.l %d0,(%a2)+ | 363 | move.l %d0,(%a2)+ |
319 | cmp.l %a2,%a4 | 364 | cmp.l %a2,%a4 |
320 | bhi.b .mungeloop | 365 | bhi.b .mungeloop |
366 | |||
367 | #if defined(BOOTLOADER) && (defined(IAUDIO_X5) || defined(IAUDIO_M5)) | ||
368 | move.l %d7, initial_gpio_read | ||
369 | #endif | ||
321 | 370 | ||
322 | jsr main | 371 | jsr main |
323 | .hoo: | 372 | .hoo: |
diff --git a/firmware/target/coldfire/iaudio/boot.lds b/firmware/target/coldfire/iaudio/boot.lds index 4cd0e8eaab..9288a6c18b 100644 --- a/firmware/target/coldfire/iaudio/boot.lds +++ b/firmware/target/coldfire/iaudio/boot.lds | |||
@@ -14,8 +14,12 @@ STARTUP(target/coldfire/crt0.o) | |||
14 | #define IRAMSIZE 0x18000 | 14 | #define IRAMSIZE 0x18000 |
15 | #endif | 15 | #endif |
16 | #define DRAMORIG 0x31000000 | 16 | #define DRAMORIG 0x31000000 |
17 | #ifdef HAVE_DUALBOOT | ||
18 | #define FLASHORIG 0x00150000 | ||
19 | #else | ||
17 | #define FLASHORIG 0x00010000 | 20 | #define FLASHORIG 0x00010000 |
18 | #define FLASHSIZE 4M | 21 | #endif |
22 | #define FLASHSIZE 4M - FLASHORIG | ||
19 | 23 | ||
20 | MEMORY | 24 | MEMORY |
21 | { | 25 | { |
diff --git a/rbutil/rbutilqt/base/bootloaderinstallhex.cpp b/rbutil/rbutilqt/base/bootloaderinstallhex.cpp index 84d60eda86..5118aab52c 100644 --- a/rbutil/rbutilqt/base/bootloaderinstallhex.cpp +++ b/rbutil/rbutilqt/base/bootloaderinstallhex.cpp | |||
@@ -162,7 +162,7 @@ void BootloaderInstallHex::installStage2(void) | |||
162 | 162 | ||
163 | // iriver decode already done in stage 1 | 163 | // iriver decode already done in stage 1 |
164 | int result; | 164 | int result; |
165 | if((result = mkboot(descrambledName.toLocal8Bit().constData(), | 165 | if((result = mkboot_iriver(descrambledName.toLocal8Bit().constData(), |
166 | tempfileName.toLocal8Bit().constData(), | 166 | tempfileName.toLocal8Bit().constData(), |
167 | tempbinName.toLocal8Bit().constData(), origin)) < 0) | 167 | tempbinName.toLocal8Bit().constData(), origin)) < 0) |
168 | { | 168 | { |
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 | } |