diff options
Diffstat (limited to 'bootloader/main-pp.c')
-rw-r--r-- | bootloader/main-pp.c | 280 |
1 files changed, 269 insertions, 11 deletions
diff --git a/bootloader/main-pp.c b/bootloader/main-pp.c index 960e570889..64f9e79a93 100644 --- a/bootloader/main-pp.c +++ b/bootloader/main-pp.c | |||
@@ -29,6 +29,80 @@ | |||
29 | #include "ata.h" | 29 | #include "ata.h" |
30 | #include "button.h" | 30 | #include "button.h" |
31 | #include "disk.h" | 31 | #include "disk.h" |
32 | #include <string.h> | ||
33 | |||
34 | /* | ||
35 | * CRC32 implementation taken from: | ||
36 | * | ||
37 | * efone - Distributed internet phone system. | ||
38 | * | ||
39 | * (c) 1999,2000 Krzysztof Dabrowski | ||
40 | * (c) 1999,2000 ElysiuM deeZine | ||
41 | * | ||
42 | * This program is free software; you can redistribute it and/or | ||
43 | * modify it under the terms of the GNU General Public License | ||
44 | * as published by the Free Software Foundation; either version | ||
45 | * 2 of the License, or (at your option) any later version. | ||
46 | * | ||
47 | */ | ||
48 | |||
49 | /* based on implementation by Finn Yannick Jacobs */ | ||
50 | |||
51 | #include <stdio.h> | ||
52 | #include <stdlib.h> | ||
53 | |||
54 | /* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab(). | ||
55 | * so make sure, you call it before using the other | ||
56 | * functions! | ||
57 | */ | ||
58 | static unsigned int crc_tab[256]; | ||
59 | |||
60 | /* chksum_crc() -- to a given block, this one calculates the | ||
61 | * crc32-checksum until the length is | ||
62 | * reached. the crc32-checksum will be | ||
63 | * the result. | ||
64 | */ | ||
65 | unsigned int chksum_crc32 (unsigned char *block, unsigned int length) | ||
66 | { | ||
67 | register unsigned long crc; | ||
68 | unsigned long i; | ||
69 | |||
70 | crc = 0; | ||
71 | for (i = 0; i < length; i++) | ||
72 | { | ||
73 | crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF]; | ||
74 | } | ||
75 | return (crc); | ||
76 | } | ||
77 | |||
78 | /* chksum_crc32gentab() -- to a global crc_tab[256], this one will | ||
79 | * calculate the crcTable for crc32-checksums. | ||
80 | * it is generated to the polynom [..] | ||
81 | */ | ||
82 | |||
83 | static void chksum_crc32gentab (void) | ||
84 | { | ||
85 | unsigned long crc, poly; | ||
86 | int i, j; | ||
87 | |||
88 | poly = 0xEDB88320L; | ||
89 | for (i = 0; i < 256; i++) | ||
90 | { | ||
91 | crc = i; | ||
92 | for (j = 8; j > 0; j--) | ||
93 | { | ||
94 | if (crc & 1) | ||
95 | { | ||
96 | crc = (crc >> 1) ^ poly; | ||
97 | } | ||
98 | else | ||
99 | { | ||
100 | crc >>= 1; | ||
101 | } | ||
102 | } | ||
103 | crc_tab[i] = crc; | ||
104 | } | ||
105 | } | ||
32 | 106 | ||
33 | /* Button definitions */ | 107 | /* Button definitions */ |
34 | #if CONFIG_KEYPAD == IRIVER_H10_PAD | 108 | #if CONFIG_KEYPAD == IRIVER_H10_PAD |
@@ -50,21 +124,167 @@ unsigned char *loadbuffer = (unsigned char *)DRAM_START; | |||
50 | /* Bootloader version */ | 124 | /* Bootloader version */ |
51 | char version[] = APPSVERSION; | 125 | char version[] = APPSVERSION; |
52 | 126 | ||
127 | /* Locations and sizes in hidden partition on Sansa */ | ||
128 | #define PPMI_OFFSET 1024 | ||
129 | #define PPMI_SIZE 1 | ||
130 | #define MI4_HEADER_SIZE 1 | ||
131 | |||
132 | /* mi4 header structure */ | ||
133 | struct mi4header_t { | ||
134 | unsigned char magic[4]; | ||
135 | uint32_t version; | ||
136 | uint32_t length; | ||
137 | uint32_t crc32; | ||
138 | uint32_t enctype; | ||
139 | uint32_t mi4size; | ||
140 | uint32_t plaintext; | ||
141 | uint32_t dsa_key[10]; | ||
142 | uint32_t pad[109]; | ||
143 | unsigned char type[4]; | ||
144 | unsigned char model[4]; | ||
145 | }; | ||
146 | |||
147 | /* PPMI header structure */ | ||
148 | struct ppmi_header_t { | ||
149 | unsigned char magic[4]; | ||
150 | uint32_t length; | ||
151 | uint32_t pad[126]; | ||
152 | }; | ||
153 | |||
154 | /* Load mi4 format firmware image */ | ||
155 | int load_mi4(unsigned char* buf, char* firmware, unsigned int buffer_size) | ||
156 | { | ||
157 | int fd; | ||
158 | struct mi4header_t mi4header; | ||
159 | int rc; | ||
160 | unsigned long sum; | ||
161 | char filename[MAX_PATH]; | ||
162 | |||
163 | snprintf(filename,sizeof(filename),"/.rockbox/%s",firmware); | ||
164 | fd = open(filename, O_RDONLY); | ||
165 | if(fd < 0) | ||
166 | { | ||
167 | snprintf(filename,sizeof(filename),"/%s",firmware); | ||
168 | fd = open(filename, O_RDONLY); | ||
169 | if(fd < 0) | ||
170 | return EFILE_NOT_FOUND; | ||
171 | } | ||
172 | |||
173 | read(fd, &mi4header, 0x200); | ||
174 | |||
175 | /* We don't support encrypted mi4 files yet */ | ||
176 | if( (mi4header.plaintext + 0x200) != mi4header.mi4size) | ||
177 | return EINVALID_FORMAT; | ||
178 | |||
179 | /* MI4 file size */ | ||
180 | printf("mi4 size: %x", mi4header.length); | ||
181 | |||
182 | if (mi4header.length > buffer_size) | ||
183 | return EFILE_TOO_BIG; | ||
184 | |||
185 | /* CRC32 */ | ||
186 | printf("CRC32: %x", mi4header.crc32); | ||
187 | |||
188 | /* Rockbox model id */ | ||
189 | printf("Model id: %4s", mi4header.model); | ||
190 | |||
191 | /* Read binary type (RBOS, RBBL) */ | ||
192 | printf("Binary type: %4s", mi4header.type); | ||
193 | |||
194 | /* Load firmware */ | ||
195 | lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET); | ||
196 | rc = read(fd, buf, mi4header.mi4size-0x200); | ||
197 | if(rc < (int)mi4header.mi4size-0x200) | ||
198 | return EREAD_IMAGE_FAILED; | ||
199 | |||
200 | /* Check CRC32 to see if we have a valid file */ | ||
201 | sum = chksum_crc32 (buf,mi4header.mi4size-0x200); | ||
202 | |||
203 | printf("Calculated CRC32: %x", sum); | ||
204 | |||
205 | if(sum != mi4header.crc32) | ||
206 | return EBAD_CHKSUM; | ||
207 | |||
208 | return EOK; | ||
209 | } | ||
210 | |||
211 | /* Load mi4 firmware from a hidden disk partition */ | ||
212 | int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, unsigned int buffer_size) | ||
213 | { | ||
214 | struct mi4header_t mi4header; | ||
215 | struct ppmi_header_t ppmi_header; | ||
216 | unsigned long sum; | ||
217 | |||
218 | /* Read header to find out how long the mi4 file is. */ | ||
219 | ata_read_sectors(pinfo->start + PPMI_OFFSET, PPMI_SIZE, &ppmi_header); | ||
220 | |||
221 | /* The first four characters at 0x80000 (sector 1024) should be PPMI*/ | ||
222 | if( memcmp(ppmi_header.magic, "PPMI", 4) ) | ||
223 | return EFILE_NOT_FOUND; | ||
224 | |||
225 | printf("BL mi4 size: %x", ppmi_header.length); | ||
226 | |||
227 | /* Read mi4 header of the OF */ | ||
228 | ata_read_sectors(pinfo->start + PPMI_OFFSET + PPMI_SIZE | ||
229 | + (ppmi_header.length/512), MI4_HEADER_SIZE, &mi4header); | ||
230 | |||
231 | /* We don't support encrypted mi4 files yet */ | ||
232 | if( (mi4header.plaintext + 0x200) != mi4header.mi4size) | ||
233 | return EINVALID_FORMAT; | ||
234 | |||
235 | /* MI4 file size */ | ||
236 | printf("OF mi4 size: %x", mi4header.length); | ||
237 | |||
238 | if (mi4header.length > buffer_size) | ||
239 | return EFILE_TOO_BIG; | ||
240 | |||
241 | /* CRC32 */ | ||
242 | printf("CRC32: %x", mi4header.crc32); | ||
243 | |||
244 | /* Rockbox model id */ | ||
245 | printf("Model id: %4s", mi4header.model); | ||
246 | |||
247 | /* Read binary type (RBOS, RBBL) */ | ||
248 | printf("Binary type: %4s", mi4header.type); | ||
249 | |||
250 | /* Load firmware */ | ||
251 | ata_read_sectors(pinfo->start + PPMI_OFFSET + PPMI_SIZE | ||
252 | + (ppmi_header.length/512) + MI4_HEADER_SIZE, | ||
253 | (mi4header.length-0x200)/512, buf); | ||
254 | |||
255 | /* Check CRC32 to see if we have a valid file */ | ||
256 | sum = chksum_crc32 (buf,mi4header.mi4size-0x200); | ||
257 | |||
258 | printf("Calculated CRC32: %x", sum); | ||
259 | |||
260 | if(sum != mi4header.crc32) | ||
261 | return EBAD_CHKSUM; | ||
262 | |||
263 | return EOK; | ||
264 | } | ||
265 | |||
53 | void* main(void) | 266 | void* main(void) |
54 | { | 267 | { |
55 | char buf[256]; | 268 | char buf[256]; |
56 | int i; | 269 | int i; |
57 | int btn; | 270 | int btn; |
58 | int rc; | 271 | int rc; |
272 | int num_partitions; | ||
59 | unsigned short* identify_info; | 273 | unsigned short* identify_info; |
60 | struct partinfo* pinfo; | 274 | struct partinfo* pinfo; |
61 | 275 | ||
276 | chksum_crc32gentab (); | ||
277 | |||
62 | system_init(); | 278 | system_init(); |
63 | kernel_init(); | 279 | kernel_init(); |
64 | lcd_init(); | 280 | lcd_init(); |
65 | font_init(); | 281 | font_init(); |
66 | button_init(); | 282 | button_init(); |
67 | 283 | ||
284 | lcd_set_foreground(LCD_WHITE); | ||
285 | lcd_set_background(LCD_BLACK); | ||
286 | lcd_clear_display(); | ||
287 | |||
68 | btn = button_read_device(); | 288 | btn = button_read_device(); |
69 | 289 | ||
70 | /* Enable bootloader messages */ | 290 | /* Enable bootloader messages */ |
@@ -94,31 +314,69 @@ void* main(void) | |||
94 | } | 314 | } |
95 | 315 | ||
96 | disk_init(); | 316 | disk_init(); |
97 | rc = disk_mount_all(); | 317 | num_partitions = disk_mount_all(); |
98 | if (rc<=0) | 318 | if (num_partitions<=0) |
99 | { | 319 | { |
100 | error(EDISK,rc); | 320 | error(EDISK,num_partitions); |
101 | } | 321 | } |
102 | 322 | ||
103 | pinfo = disk_partinfo(0); | 323 | /* Just list the first 2 partitions since we don't have any devices yet |
104 | printf("Partition 0: 0x%02x %ld MB", pinfo->type, pinfo->size / 2048); | 324 | that have more than that */ |
325 | for(i=0; i<2; i++) | ||
326 | { | ||
327 | pinfo = disk_partinfo(i); | ||
328 | printf("Partition %d: 0x%02x %ld MB", | ||
329 | i, pinfo->type, pinfo->size / 2048); | ||
330 | } | ||
105 | 331 | ||
106 | if(btn & BOOTLOADER_BOOT_OF) | 332 | if(btn & BOOTLOADER_BOOT_OF) |
107 | { | 333 | { |
108 | /* Load original mi4 firmware. This expects a file called | 334 | /* Load original mi4 firmware in to a memory buffer called loadbuffer. |
109 | "/System/OF.bin" on the player. It should be a mi4 firmware decrypted | 335 | The rest of the loading is done in crt0.S. |
110 | and header stripped using mi4code. It reads the file in to a memory | 336 | 1) First try reading from the hidden partition (on Sansa only). |
111 | buffer called loadbuffer. The rest of the loading is done in crt0.S | 337 | 2) Next try a decrypted mi4 file in /System/OF.mi4 |
338 | 3) Finally, try a raw firmware binary in /System/OF.mi4. It should be | ||
339 | a mi4 firmware decrypted and header stripped using mi4code. | ||
112 | */ | 340 | */ |
113 | printf("Loading original firmware..."); | 341 | printf("Loading original firmware..."); |
342 | |||
343 | /* First try a hidden partition */ | ||
344 | printf("Trying hidden partition"); | ||
345 | pinfo = disk_partinfo(1); | ||
346 | if(pinfo->type == PARTITION_TYPE_HIDDEN) | ||
347 | { | ||
348 | rc = load_mi4_part(loadbuffer, pinfo, MAX_LOADSIZE); | ||
349 | if (rc < EOK) { | ||
350 | printf("Can't load from partition"); | ||
351 | printf(strerror(rc)); | ||
352 | } else { | ||
353 | return (void*)loadbuffer; | ||
354 | } | ||
355 | } else { | ||
356 | printf("No hidden partition found."); | ||
357 | } | ||
358 | |||
359 | printf("Trying /System/OF.mi4"); | ||
360 | rc=load_mi4(loadbuffer, "/System/OF.mi4", MAX_LOADSIZE); | ||
361 | if (rc < EOK) { | ||
362 | printf("Can't load /System/OF.mi4"); | ||
363 | printf(strerror(rc)); | ||
364 | } else { | ||
365 | return (void*)loadbuffer; | ||
366 | } | ||
367 | |||
368 | printf("Trying /System/OF.bin"); | ||
114 | rc=load_raw_firmware(loadbuffer, "/System/OF.bin", MAX_LOADSIZE); | 369 | rc=load_raw_firmware(loadbuffer, "/System/OF.bin", MAX_LOADSIZE); |
115 | if (rc < EOK) { | 370 | if (rc < EOK) { |
116 | printf("Can't load /System/OF.bin"); | 371 | printf("Can't load /System/OF.bin"); |
117 | error(EBOOTFILE, rc); | 372 | printf(strerror(rc)); |
373 | } else { | ||
374 | return (void*)loadbuffer; | ||
118 | } | 375 | } |
376 | |||
119 | } else { | 377 | } else { |
120 | printf("Loading Rockbox..."); | 378 | printf("Loading Rockbox..."); |
121 | rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE); | 379 | rc=load_mi4(loadbuffer, BOOTFILE, MAX_LOADSIZE); |
122 | if (rc < EOK) { | 380 | if (rc < EOK) { |
123 | printf("Can't load %s:", BOOTFILE); | 381 | printf("Can't load %s:", BOOTFILE); |
124 | error(EBOOTFILE, rc); | 382 | error(EBOOTFILE, rc); |