diff options
Diffstat (limited to 'bootloader')
-rw-r--r-- | bootloader/gigabeat.c | 367 |
1 files changed, 359 insertions, 8 deletions
diff --git a/bootloader/gigabeat.c b/bootloader/gigabeat.c index c04042cead..62c31310ae 100644 --- a/bootloader/gigabeat.c +++ b/bootloader/gigabeat.c | |||
@@ -17,12 +17,133 @@ | |||
17 | #include "panic.h" | 17 | #include "panic.h" |
18 | #include "power.h" | 18 | #include "power.h" |
19 | #include "file.h" | 19 | #include "file.h" |
20 | #include "button-target.h" | ||
21 | |||
22 | void map_memory(void); | ||
23 | |||
24 | int line = 0; | ||
20 | 25 | ||
21 | char version[] = APPSVERSION; | 26 | char version[] = APPSVERSION; |
22 | 27 | ||
23 | void go_usb_mode(void) { | 28 | /* This section allows you to toggle bits of any memory location */ |
29 | /* Touchpad to move around the bits. Select to toggle the red bit */ | ||
30 | typedef struct { | ||
31 | unsigned int address; | ||
32 | char *desc; | ||
33 | } memlocation_struct; | ||
34 | |||
35 | /* Just add any address and descriptions here */ | ||
36 | /* Must finish with 0xFFFFFFFF */ | ||
37 | const memlocation_struct memlocations[] = { | ||
38 | /* Address Description */ | ||
39 | { 0x56000000, "GPACON" }, | ||
40 | { 0x56000004, "GPADAT" }, | ||
41 | { 0x56000010, "GPBCON" }, | ||
42 | { 0x56000014, "GPBDAT" }, | ||
43 | { 0x56000020, "GPCCON" }, | ||
44 | { 0x56000024, "GPCDAT" }, | ||
45 | { 0x56000030, "GPDCON" }, | ||
46 | { 0x56000034, "GPDDAT" }, | ||
47 | { 0x56000040, "GPECON" }, | ||
48 | { 0x56000044, "GPEDAT" }, | ||
49 | { 0x56000050, "GPFCON" }, | ||
50 | { 0x56000054, "GPFDAT" }, | ||
51 | { 0x56000060, "GPGCON" }, | ||
52 | { 0x56000064, "GPGDAT" }, | ||
53 | { 0x56000070, "GPHCON" }, | ||
54 | { 0x56000074, "GPHDAT" }, | ||
55 | { 0xFFFFFFFF, 0 } | ||
56 | }; | ||
57 | |||
58 | void memdump(void) | ||
59 | { | ||
60 | int i, j; | ||
61 | int current=0, bit=0; | ||
62 | char * bitval; | ||
63 | int data; | ||
64 | char tmp[40]; | ||
65 | |||
66 | while(1) { | ||
67 | i = 0; | ||
68 | |||
69 | while(memlocations[i].address != 0xFFFFFFFF) { | ||
70 | |||
71 | data = *(volatile int *)memlocations[i].address; | ||
72 | |||
73 | snprintf(tmp, sizeof(tmp), "%s %s 0x%08X", | ||
74 | (i==current) ? "*" : " ", | ||
75 | memlocations[i].desc, | ||
76 | data); | ||
77 | lcd_puts(0, i*2+5, tmp); | ||
78 | |||
79 | /* print out in binary, current bit in red */ | ||
80 | for (j=31; j>=0; j--) { | ||
81 | if ((bit == j) && (current == i)) | ||
82 | lcd_set_foreground(LCD_RGBPACK(255,0,0)); | ||
83 | lcd_puts((31-j) + ((31-j) / 8), i*2+6, (data & (1 << j)) ? "1" : "0" ); | ||
84 | lcd_set_foreground(LCD_RGBPACK(0,0,0)); | ||
85 | } | ||
86 | |||
87 | i++; | ||
88 | } | ||
89 | |||
90 | data = *(volatile int *)memlocations[current].address; | ||
91 | bitval = (data & (1 << bit)) ? "1" : "0"; | ||
92 | snprintf(tmp, sizeof(tmp), "%s bit %ld = %s", memlocations[current].desc, bit, bitval); | ||
93 | lcd_puts(0, (i*2)+7, tmp); | ||
94 | |||
95 | lcd_update(); | ||
96 | |||
97 | /* touchpad controls */ | ||
98 | |||
99 | /* Up */ | ||
100 | if (GPJDAT & 0x01) { | ||
101 | if (current > 0) | ||
102 | current--; | ||
103 | while(GPJDAT & 0x01); | ||
104 | } | ||
105 | |||
106 | /* Down */ | ||
107 | if (GPJDAT & 0x40) { | ||
108 | if (current < (i-1)) | ||
109 | current++; | ||
110 | while(GPJDAT & 0x40); | ||
111 | } | ||
112 | |||
113 | /* Left */ | ||
114 | if (GPJDAT & 0x80) { | ||
115 | if (bit < 31) | ||
116 | bit++; | ||
117 | while(GPJDAT & 0x80); | ||
118 | } | ||
119 | |||
120 | /* Right */ | ||
121 | if (GPJDAT & 0x1000) { | ||
122 | if (bit > 0) | ||
123 | bit--; | ||
124 | while(GPJDAT & 0x1000); | ||
125 | } | ||
126 | |||
127 | /* Centre - Toggle Bit */ | ||
128 | if (GPJDAT & 0x08) { | ||
129 | data = *(volatile int *)memlocations[current].address; | ||
130 | data = data ^ (1 << bit); | ||
131 | *(volatile int *)memlocations[current].address = data; | ||
132 | while(GPJDAT & 0x08); | ||
133 | } | ||
134 | |||
135 | /* Bail out if the power button is pressed */ | ||
136 | if (GPGDAT & 1) { | ||
137 | break; | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | |||
142 | |||
143 | static void go_usb_mode(void) { | ||
24 | /* Drop into USB mode. This does not check for disconnection. */ | 144 | /* Drop into USB mode. This does not check for disconnection. */ |
25 | 145 | ||
146 | |||
26 | int i; | 147 | int i; |
27 | 148 | ||
28 | GPBDAT &= 0x7EF; | 149 | GPBDAT &= 0x7EF; |
@@ -34,17 +155,160 @@ void go_usb_mode(void) { | |||
34 | for (i = 0; i < 10000000; i++) {continue;} | 155 | for (i = 0; i < 10000000; i++) {continue;} |
35 | 156 | ||
36 | GPBCON &= 0x2FFCFF; | 157 | GPBCON &= 0x2FFCFF; |
37 | GPBDAT |= 1<<5; | 158 | GPBDAT |= 1<<5; |
38 | GPBDAT |= 1<<6; | 159 | GPBDAT |= 1<<6; |
39 | } | 160 | } |
40 | 161 | ||
162 | |||
163 | /* Restores a factory kernel/bootloader from a known location */ | ||
164 | /* Restores the FWIMG01.DAT file back in the case of a bootloader failure */ | ||
165 | /* The factory or "good" bootloader must be in /GBSYSTEM/FWIMG/FWIMG01.DAT.ORIG */ | ||
166 | /* Returns non-zero on failure */ | ||
167 | int restore_fwimg01dat(void) | ||
168 | { | ||
169 | int orig_file = 0, dest_file = 0; | ||
170 | int size = 0, size_read; | ||
171 | char buf[256]; | ||
172 | char lcd_buf[64]; | ||
173 | |||
174 | orig_file = open("/GBSYSTEM/FWIMG/FWIMG01.DAT.ORIG", O_RDONLY); | ||
175 | if (orig_file < 0) { | ||
176 | /* Couldn't open source file */ | ||
177 | lcd_puts(0, line++, "Couldn't open FWIMG01.DAT.ORIG for reading"); | ||
178 | lcd_update(); | ||
179 | return(1); | ||
180 | } | ||
181 | |||
182 | lcd_puts(0, line++, "FWIMG01.DAT.ORIG opened for reading"); | ||
183 | lcd_update(); | ||
184 | |||
185 | dest_file = open("/GBSYSTEM/FWIMG/FWIMG01.DAT", O_RDWR); | ||
186 | if (dest_file < 0) { | ||
187 | /* Couldn't open destination file */ | ||
188 | lcd_puts(0, line++, "Couldn't open FWIMG01.DAT.ORIG for writing"); | ||
189 | lcd_update(); | ||
190 | close(orig_file); | ||
191 | return(2); | ||
192 | } | ||
193 | |||
194 | lcd_puts(0, line++, "FWIMG01.DAT opened for writing"); | ||
195 | lcd_update(); | ||
196 | |||
197 | do { | ||
198 | /* Copy in chunks */ | ||
199 | size_read = read(orig_file, buf, sizeof(buf)); | ||
200 | if (size_read != write(dest_file, buf, size_read)) { | ||
201 | close(orig_file); | ||
202 | close(dest_file); | ||
203 | return(3); | ||
204 | } | ||
205 | size += size_read; | ||
206 | |||
207 | } while (size_read > 0); | ||
208 | |||
209 | close(orig_file); | ||
210 | close(dest_file); | ||
211 | |||
212 | snprintf(lcd_buf, sizeof(lcd_buf), "Finished copying %ld bytes from", size); | ||
213 | lcd_puts(0, line++, lcd_buf); | ||
214 | lcd_puts(0, line++, "FWIMG01.DAT.ORIG to FWIMG01.DAT"); | ||
215 | |||
216 | return(0); | ||
217 | } | ||
218 | |||
219 | |||
220 | int load_rockbox(const char* file_name, unsigned char* buf, int buffer_size) | ||
221 | { | ||
222 | int fd; | ||
223 | int rc; | ||
224 | int len; | ||
225 | char str[256]; | ||
226 | //unsigned long chksum; | ||
227 | //char model[5]; | ||
228 | //unsigned long sum; | ||
229 | //int i; | ||
230 | //char str[80]; | ||
231 | |||
232 | fd = open("/.rockbox/" BOOTFILE, O_RDONLY); | ||
233 | if(fd < 0) | ||
234 | { | ||
235 | fd = open("/" BOOTFILE, O_RDONLY); | ||
236 | if(fd < 0) | ||
237 | return -1; | ||
238 | } | ||
239 | fd = open(file_name, O_RDONLY); | ||
240 | if(fd < 0) | ||
241 | return -2; | ||
242 | |||
243 | len = filesize(fd); | ||
244 | |||
245 | if (len > buffer_size) { | ||
246 | snprintf(str, sizeof(str), "len: %d buf: %d", len, buffer_size); | ||
247 | lcd_puts(0, line++, str); | ||
248 | lcd_update(); | ||
249 | return -6; | ||
250 | } | ||
251 | |||
252 | /*lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET); | ||
253 | |||
254 | rc = read(fd, &chksum, 4); | ||
255 | chksum=betoh32(chksum);*/ /* Rockbox checksums are big-endian */ | ||
256 | /*if(rc < 4) | ||
257 | return -2; | ||
258 | |||
259 | rc = read(fd, model, 4); | ||
260 | if(rc < 4) | ||
261 | return -3; | ||
262 | |||
263 | model[4] = 0; | ||
264 | |||
265 | snprintf(str, 80, "Model: %s", model); | ||
266 | lcd_puts(0, line++, str); | ||
267 | snprintf(str, 80, "Checksum: %x", chksum); | ||
268 | lcd_puts(0, line++, str); | ||
269 | lcd_update(); | ||
270 | |||
271 | lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET); | ||
272 | */ | ||
273 | |||
274 | rc = read(fd, buf, len); | ||
275 | if(rc < len) { | ||
276 | snprintf(str, sizeof(str), "len: %d rc: %d", len, rc); | ||
277 | lcd_puts(0, line++, str); | ||
278 | lcd_update(); | ||
279 | return -4; | ||
280 | } | ||
281 | |||
282 | close(fd); | ||
283 | |||
284 | /*sum = MODEL_NUMBER; | ||
285 | |||
286 | for(i = 0;i < len;i++) { | ||
287 | sum += buf[i]; | ||
288 | } | ||
289 | |||
290 | snprintf(str, 80, "Sum: %x", sum); | ||
291 | lcd_puts(0, line++, str); | ||
292 | lcd_update(); | ||
293 | |||
294 | if(sum != chksum) | ||
295 | return -5;*/ | ||
296 | |||
297 | return len; | ||
298 | } | ||
299 | |||
41 | void * main(void) | 300 | void * main(void) |
42 | { | 301 | { |
43 | int line = 0, i; | 302 | int i; |
44 | char buf[256]; | 303 | char buf[256]; |
45 | struct partinfo* pinfo; | 304 | struct partinfo* pinfo; |
46 | unsigned short* identify_info; | 305 | unsigned short* identify_info; |
47 | int testfile; | 306 | //int testfile; |
307 | unsigned char* loadbuffer; | ||
308 | int buffer_size; | ||
309 | bool load_original = false; | ||
310 | int rc; | ||
311 | int(*kernel_entry)(void); | ||
48 | 312 | ||
49 | lcd_init(); | 313 | lcd_init(); |
50 | lcd_setfont(FONT_SYSFIXED); | 314 | lcd_setfont(FONT_SYSFIXED); |
@@ -57,7 +321,10 @@ void * main(void) | |||
57 | */ | 321 | */ |
58 | 322 | ||
59 | lcd_puts(0, line++, "Hold MENU when booting for rescue mode."); | 323 | lcd_puts(0, line++, "Hold MENU when booting for rescue mode."); |
324 | lcd_puts(0, line++, " \"VOL+\" button to restore original kernel"); | ||
325 | lcd_puts(0, line++, " \"A\" button to load original firmware"); | ||
60 | lcd_update(); | 326 | lcd_update(); |
327 | sleep(1*HZ); | ||
61 | 328 | ||
62 | /* hold MENU to enter rescue mode */ | 329 | /* hold MENU to enter rescue mode */ |
63 | if (GPGDAT & 2) { | 330 | if (GPGDAT & 2) { |
@@ -67,12 +334,44 @@ void * main(void) | |||
67 | while(1); | 334 | while(1); |
68 | } | 335 | } |
69 | 336 | ||
337 | sleep(5*HZ); | ||
338 | |||
339 | if(GPGDAT & 0x10) { | ||
340 | load_original = true; | ||
341 | lcd_puts(0, line++, "Loading original firmware..."); | ||
342 | lcd_update(); | ||
343 | } | ||
344 | |||
70 | i = ata_init(); | 345 | i = ata_init(); |
71 | i = disk_mount_all(); | 346 | i = disk_mount_all(); |
72 | 347 | ||
73 | snprintf(buf, sizeof(buf), "disk_mount_all: %d", i); | 348 | snprintf(buf, sizeof(buf), "disk_mount_all: %d", i); |
74 | lcd_puts(0, line++, buf); | 349 | lcd_puts(0, line++, buf); |
75 | 350 | ||
351 | /* hold VOL+ to enter rescue mode to copy old image */ | ||
352 | /* needs to be after ata_init and disk_mount_all */ | ||
353 | if (GPGDAT & 4) { | ||
354 | |||
355 | /* Try to restore the original kernel/bootloader if a copy is found */ | ||
356 | lcd_puts(0, line++, "Restoring FWIMG01.DAT..."); | ||
357 | lcd_update(); | ||
358 | |||
359 | if (!restore_fwimg01dat()) { | ||
360 | lcd_puts(0, line++, "Restoring FWIMG01.DAT successful."); | ||
361 | } else { | ||
362 | lcd_puts(0, line++, "Restoring FWIMG01.DAT failed."); | ||
363 | } | ||
364 | |||
365 | lcd_puts(0, line++, "Now power cycle to boot original"); | ||
366 | lcd_update(); | ||
367 | while(1); | ||
368 | } | ||
369 | |||
370 | /* Memory dump mode if Vol- pressed */ | ||
371 | if (GPGDAT & 8) { | ||
372 | memdump(); | ||
373 | } | ||
374 | |||
76 | identify_info = ata_get_identify(); | 375 | identify_info = ata_get_identify(); |
77 | 376 | ||
78 | for (i=0; i < 20; i++) | 377 | for (i=0; i < 20; i++) |
@@ -96,16 +395,68 @@ void * main(void) | |||
96 | lcd_puts(0, line++, buf); | 395 | lcd_puts(0, line++, buf); |
97 | 396 | ||
98 | pinfo = disk_partinfo(0); | 397 | pinfo = disk_partinfo(0); |
99 | snprintf(buf, sizeof(buf), "Partition 0: 0x%02x %ld MB", | 398 | snprintf(buf, sizeof(buf), "Partition 0: 0x%02x %ld MB", |
100 | pinfo->type, pinfo->size / 2048); | 399 | pinfo->type, pinfo->size / 2048); |
101 | lcd_puts(0, line++, buf); | 400 | lcd_puts(0, line++, buf); |
401 | lcd_update(); | ||
402 | |||
403 | /* Load original firmware */ | ||
404 | if(load_original) { | ||
405 | loadbuffer = (unsigned char*)0x30008000; | ||
406 | buffer_size =(unsigned char*)0x31000000 - loadbuffer; | ||
407 | rc = load_rockbox("/rockbox.gigabeat", loadbuffer, buffer_size); | ||
408 | if (rc < 0) { | ||
409 | lcd_puts(0, line++, "failed to load original firmware. Loading rockbox"); | ||
410 | lcd_update(); | ||
411 | sleep(2*HZ); | ||
412 | goto load_rockbox; | ||
413 | } | ||
102 | 414 | ||
103 | testfile = open("/boottest.txt", O_WRONLY|O_CREAT|O_TRUNC); | 415 | snprintf(buf, sizeof(buf), "Loaded: %d", rc); |
104 | write(testfile, "It works!", 9); | 416 | lcd_puts(0, line++, buf); |
105 | close(testfile); | 417 | lcd_update(); |
418 | sleep(2*HZ); | ||
419 | |||
420 | |||
421 | (*((int*)0x7000000)) = 333; | ||
422 | rc = *((int*)0x7000000+0x8000000); | ||
423 | snprintf(buf, sizeof(buf), "Bank0 mem test: %d", rc); | ||
424 | lcd_puts(0, line++, buf); | ||
425 | lcd_update(); | ||
426 | sleep(3*HZ); | ||
427 | |||
428 | lcd_puts(0, line++, "Woops, should not return from firmware!"); | ||
429 | lcd_update(); | ||
430 | goto usb; | ||
431 | } | ||
106 | 432 | ||
433 | load_rockbox: | ||
434 | map_memory(); | ||
435 | lcd_puts(0, line, "Loading Rockbox..."); | ||
107 | lcd_update(); | 436 | lcd_update(); |
437 | sleep(HZ*4); | ||
438 | |||
439 | // TODO: read those values from somwhere | ||
440 | loadbuffer = (unsigned char*) 0x100; | ||
441 | buffer_size = (unsigned char*)0x400000 - loadbuffer; | ||
442 | rc=load_rockbox("/rockbox.gigabeat", loadbuffer, buffer_size); | ||
443 | if (rc < 0) { | ||
444 | snprintf(buf, sizeof(buf), "Rockbox error: %d",rc); | ||
445 | lcd_puts(0, line++, buf); | ||
446 | lcd_update(); | ||
447 | } else { | ||
448 | lcd_puts(0, line++, "Rockbox loaded."); | ||
449 | lcd_update(); | ||
450 | kernel_entry = (void*)0x100; | ||
451 | rc = kernel_entry(); | ||
452 | snprintf(buf, sizeof(buf), "Woops, should not return from firmware: %d", rc); | ||
453 | lcd_puts(0, line++, buf); | ||
454 | lcd_update(); | ||
455 | goto usb; | ||
456 | } | ||
457 | |||
108 | 458 | ||
459 | usb: | ||
109 | /* now wait in USB mode so the bootloader can be updated */ | 460 | /* now wait in USB mode so the bootloader can be updated */ |
110 | go_usb_mode(); | 461 | go_usb_mode(); |
111 | while(1); | 462 | while(1); |