blob: 1ab6ebdd6f9196853b84b984491e4c144c279680 [file] [log] [blame]
Hristo Kovachev9dc0e622006-08-11 08:35:27 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Barry Wardell
11 *
12 * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
13 * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
14 *
15 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
Barry Wardell84b509d2007-01-28 18:42:11 +000022#include "common.h"
Hristo Kovachev9dc0e622006-08-11 08:35:27 +000023#include "cpu.h"
Hristo Kovachev9dc0e622006-08-11 08:35:27 +000024#include "file.h"
Barry Wardell84b509d2007-01-28 18:42:11 +000025#include "system.h"
26#include "kernel.h"
27#include "lcd.h"
28#include "font.h"
29#include "ata.h"
30#include "button.h"
31#include "disk.h"
Barry Wardell14ed3ca2007-03-16 14:28:00 +000032#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 */
58static 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 */
65unsigned 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
83static 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}
Barry Wardell23709982007-03-12 22:12:20 +0000106
107/* Button definitions */
108#if CONFIG_KEYPAD == IRIVER_H10_PAD
109#define BOOTLOADER_VERBOSE BUTTON_PLAY
110#define BOOTLOADER_BOOT_OF BUTTON_LEFT
111
112#elif CONFIG_KEYPAD == SANSA_E200_PAD
113#define BOOTLOADER_VERBOSE BUTTON_RIGHT
114#define BOOTLOADER_BOOT_OF BUTTON_LEFT
115
116#endif
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000117
Barry Wardell84b509d2007-01-28 18:42:11 +0000118/* Maximum allowed firmware image size. 10MB is more than enough */
Barry Wardell2f16d4f2006-12-19 11:33:53 +0000119#define MAX_LOADSIZE (10*1024*1024)
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000120
Barry Wardell84b509d2007-01-28 18:42:11 +0000121/* A buffer to load the original firmware or Rockbox into */
122unsigned char *loadbuffer = (unsigned char *)DRAM_START;
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000123
Barry Wardell84b509d2007-01-28 18:42:11 +0000124/* Bootloader version */
Barry Wardell1920df32006-08-28 08:11:32 +0000125char version[] = APPSVERSION;
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000126
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000127/* 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 */
133struct 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 */
148struct 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 */
155int 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
Barry Wardella91a35b2007-03-16 14:36:14 +0000211#ifdef SANSA_E200
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000212/* Load mi4 firmware from a hidden disk partition */
213int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, unsigned int buffer_size)
214{
215 struct mi4header_t mi4header;
216 struct ppmi_header_t ppmi_header;
217 unsigned long sum;
218
219 /* Read header to find out how long the mi4 file is. */
220 ata_read_sectors(pinfo->start + PPMI_OFFSET, PPMI_SIZE, &ppmi_header);
221
222 /* The first four characters at 0x80000 (sector 1024) should be PPMI*/
223 if( memcmp(ppmi_header.magic, "PPMI", 4) )
224 return EFILE_NOT_FOUND;
225
226 printf("BL mi4 size: %x", ppmi_header.length);
227
228 /* Read mi4 header of the OF */
229 ata_read_sectors(pinfo->start + PPMI_OFFSET + PPMI_SIZE
230 + (ppmi_header.length/512), MI4_HEADER_SIZE, &mi4header);
231
232 /* We don't support encrypted mi4 files yet */
233 if( (mi4header.plaintext + 0x200) != mi4header.mi4size)
234 return EINVALID_FORMAT;
235
236 /* MI4 file size */
237 printf("OF mi4 size: %x", mi4header.length);
238
239 if (mi4header.length > buffer_size)
240 return EFILE_TOO_BIG;
241
242 /* CRC32 */
243 printf("CRC32: %x", mi4header.crc32);
244
245 /* Rockbox model id */
246 printf("Model id: %4s", mi4header.model);
247
248 /* Read binary type (RBOS, RBBL) */
249 printf("Binary type: %4s", mi4header.type);
250
251 /* Load firmware */
252 ata_read_sectors(pinfo->start + PPMI_OFFSET + PPMI_SIZE
253 + (ppmi_header.length/512) + MI4_HEADER_SIZE,
254 (mi4header.length-0x200)/512, buf);
255
256 /* Check CRC32 to see if we have a valid file */
257 sum = chksum_crc32 (buf,mi4header.mi4size-0x200);
258
259 printf("Calculated CRC32: %x", sum);
260
261 if(sum != mi4header.crc32)
262 return EBAD_CHKSUM;
263
264 return EOK;
265}
Barry Wardella91a35b2007-03-16 14:36:14 +0000266#endif
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000267
Barry Wardell1920df32006-08-28 08:11:32 +0000268void* main(void)
269{
270 char buf[256];
271 int i;
Barry Wardell23709982007-03-12 22:12:20 +0000272 int btn;
Barry Wardell1920df32006-08-28 08:11:32 +0000273 int rc;
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000274 int num_partitions;
Barry Wardell1920df32006-08-28 08:11:32 +0000275 unsigned short* identify_info;
276 struct partinfo* pinfo;
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000277
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000278 chksum_crc32gentab ();
279
Barry Wardell1920df32006-08-28 08:11:32 +0000280 system_init();
281 kernel_init();
282 lcd_init();
283 font_init();
Barry Wardell2f16d4f2006-12-19 11:33:53 +0000284 button_init();
Barry Wardell1920df32006-08-28 08:11:32 +0000285
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000286 lcd_set_foreground(LCD_WHITE);
287 lcd_set_background(LCD_BLACK);
288 lcd_clear_display();
289
Barry Wardell23709982007-03-12 22:12:20 +0000290 btn = button_read_device();
291
292 /* Enable bootloader messages */
Barry Wardella42070d2007-03-15 22:32:58 +0000293 if (btn & BOOTLOADER_VERBOSE)
Barry Wardell23709982007-03-12 22:12:20 +0000294 verbose = true;
295
Barry Wardell1920df32006-08-28 08:11:32 +0000296 lcd_setfont(FONT_SYSFIXED);
297
Barry Wardellf4709d02007-01-17 12:20:38 +0000298 printf("Rockbox boot loader");
299 printf("Version: 20%s", version);
300 printf(MODEL_NAME);
Barry Wardell1920df32006-08-28 08:11:32 +0000301
302 i=ata_init();
303 if (i==0) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000304 identify_info=ata_get_identify();
305 /* Show model */
306 for (i=0; i < 20; i++) {
307 ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
308 }
309 buf[40]=0;
310 for (i=39; i && buf[i]==' '; i--) {
311 buf[i]=0;
312 }
313 printf(buf);
Barry Wardell1920df32006-08-28 08:11:32 +0000314 } else {
Barry Wardell23709982007-03-12 22:12:20 +0000315 error(EATA, i);
Barry Wardell1920df32006-08-28 08:11:32 +0000316 }
317
318 disk_init();
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000319 num_partitions = disk_mount_all();
320 if (num_partitions<=0)
Barry Wardell1920df32006-08-28 08:11:32 +0000321 {
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000322 error(EDISK,num_partitions);
Barry Wardell1920df32006-08-28 08:11:32 +0000323 }
324
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000325 /* Just list the first 2 partitions since we don't have any devices yet
326 that have more than that */
327 for(i=0; i<2; i++)
328 {
329 pinfo = disk_partinfo(i);
330 printf("Partition %d: 0x%02x %ld MB",
331 i, pinfo->type, pinfo->size / 2048);
332 }
Barry Wardell1920df32006-08-28 08:11:32 +0000333
Barry Wardella42070d2007-03-15 22:32:58 +0000334 if(btn & BOOTLOADER_BOOT_OF)
Barry Wardell1920df32006-08-28 08:11:32 +0000335 {
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000336 /* Load original mi4 firmware in to a memory buffer called loadbuffer.
337 The rest of the loading is done in crt0.S.
338 1) First try reading from the hidden partition (on Sansa only).
339 2) Next try a decrypted mi4 file in /System/OF.mi4
340 3) Finally, try a raw firmware binary in /System/OF.mi4. It should be
341 a mi4 firmware decrypted and header stripped using mi4code.
Barry Wardell84b509d2007-01-28 18:42:11 +0000342 */
Barry Wardellf4709d02007-01-17 12:20:38 +0000343 printf("Loading original firmware...");
Barry Wardella91a35b2007-03-16 14:36:14 +0000344
345#ifdef SANSA_E200
346 /* First try a (hidden) firmware partition */
347 printf("Trying firmware partition");
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000348 pinfo = disk_partinfo(1);
Barry Wardellb8a5adf2007-03-16 14:41:55 +0000349 if(pinfo->type == PARTITION_TYPE_OS2_HIDDEN_C_DRIVE)
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000350 {
351 rc = load_mi4_part(loadbuffer, pinfo, MAX_LOADSIZE);
352 if (rc < EOK) {
353 printf("Can't load from partition");
354 printf(strerror(rc));
355 } else {
356 return (void*)loadbuffer;
357 }
358 } else {
359 printf("No hidden partition found.");
360 }
Barry Wardella91a35b2007-03-16 14:36:14 +0000361#endif
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000362
363 printf("Trying /System/OF.mi4");
364 rc=load_mi4(loadbuffer, "/System/OF.mi4", MAX_LOADSIZE);
365 if (rc < EOK) {
366 printf("Can't load /System/OF.mi4");
367 printf(strerror(rc));
368 } else {
369 return (void*)loadbuffer;
370 }
371
372 printf("Trying /System/OF.bin");
Barry Wardell84b509d2007-01-28 18:42:11 +0000373 rc=load_raw_firmware(loadbuffer, "/System/OF.bin", MAX_LOADSIZE);
374 if (rc < EOK) {
Barry Wardell23709982007-03-12 22:12:20 +0000375 printf("Can't load /System/OF.bin");
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000376 printf(strerror(rc));
377 } else {
378 return (void*)loadbuffer;
Barry Wardell84b509d2007-01-28 18:42:11 +0000379 }
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000380
Barry Wardell1920df32006-08-28 08:11:32 +0000381 } else {
Barry Wardellf4709d02007-01-17 12:20:38 +0000382 printf("Loading Rockbox...");
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000383 rc=load_mi4(loadbuffer, BOOTFILE, MAX_LOADSIZE);
Barry Wardell84b509d2007-01-28 18:42:11 +0000384 if (rc < EOK) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000385 printf("Can't load %s:", BOOTFILE);
Barry Wardell23709982007-03-12 22:12:20 +0000386 error(EBOOTFILE, rc);
Barry Wardell84b509d2007-01-28 18:42:11 +0000387 }
Barry Wardell1920df32006-08-28 08:11:32 +0000388 }
Hristo Kovachev12041362006-08-11 09:51:04 +0000389
Barry Wardell84b509d2007-01-28 18:42:11 +0000390 return (void*)loadbuffer;
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000391}
392
393/* These functions are present in the firmware library, but we reimplement
394 them here because the originals do a lot more than we want */
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000395void usb_acknowledge(void)
396{
397}
398
399void usb_wait_for_disconnect(void)
400{
401}