blob: 9ee3b84b8f334fef0a06e16f14b15ed4e24bb449 [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
Barry Wardell23709982007-03-12 22:12:20 +0000109#define BOOTLOADER_BOOT_OF BUTTON_LEFT
110
111#elif CONFIG_KEYPAD == SANSA_E200_PAD
Barry Wardell23709982007-03-12 22:12:20 +0000112#define BOOTLOADER_BOOT_OF BUTTON_LEFT
113
114#endif
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000115
Barry Wardell84b509d2007-01-28 18:42:11 +0000116/* Maximum allowed firmware image size. 10MB is more than enough */
Barry Wardell2f16d4f2006-12-19 11:33:53 +0000117#define MAX_LOADSIZE (10*1024*1024)
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000118
Barry Wardell84b509d2007-01-28 18:42:11 +0000119/* A buffer to load the original firmware or Rockbox into */
120unsigned char *loadbuffer = (unsigned char *)DRAM_START;
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000121
Barry Wardell84b509d2007-01-28 18:42:11 +0000122/* Bootloader version */
Barry Wardell1920df32006-08-28 08:11:32 +0000123char version[] = APPSVERSION;
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000124
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000125/* Locations and sizes in hidden partition on Sansa */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000126#define PPMI_SECTOR_OFFSET 1024
127#define PPMI_SECTORS 1
128#define MI4_HEADER_SECTORS 1
129#define MI4_HEADER_SIZE 0x200
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000130
131/* mi4 header structure */
132struct mi4header_t {
133 unsigned char magic[4];
134 uint32_t version;
135 uint32_t length;
136 uint32_t crc32;
137 uint32_t enctype;
138 uint32_t mi4size;
139 uint32_t plaintext;
140 uint32_t dsa_key[10];
141 uint32_t pad[109];
142 unsigned char type[4];
143 unsigned char model[4];
144};
145
146/* PPMI header structure */
147struct ppmi_header_t {
148 unsigned char magic[4];
149 uint32_t length;
150 uint32_t pad[126];
151};
152
153/* Load mi4 format firmware image */
154int load_mi4(unsigned char* buf, char* firmware, unsigned int buffer_size)
155{
156 int fd;
157 struct mi4header_t mi4header;
158 int rc;
159 unsigned long sum;
160 char filename[MAX_PATH];
161
162 snprintf(filename,sizeof(filename),"/.rockbox/%s",firmware);
163 fd = open(filename, O_RDONLY);
164 if(fd < 0)
165 {
166 snprintf(filename,sizeof(filename),"/%s",firmware);
167 fd = open(filename, O_RDONLY);
168 if(fd < 0)
169 return EFILE_NOT_FOUND;
170 }
171
Barry Wardelle293bbb2007-03-17 19:07:20 +0000172 read(fd, &mi4header, MI4_HEADER_SIZE);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000173
174 /* We don't support encrypted mi4 files yet */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000175 if( (mi4header.plaintext + MI4_HEADER_SIZE) != mi4header.mi4size)
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000176 return EINVALID_FORMAT;
177
178 /* MI4 file size */
179 printf("mi4 size: %x", mi4header.length);
180
181 if (mi4header.length > buffer_size)
182 return EFILE_TOO_BIG;
183
184 /* CRC32 */
185 printf("CRC32: %x", mi4header.crc32);
186
187 /* Rockbox model id */
Barry Wardellca8f7bf2007-03-19 11:20:22 +0000188 printf("Model id: %.4s", mi4header.model);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000189
190 /* Read binary type (RBOS, RBBL) */
Barry Wardellca8f7bf2007-03-19 11:20:22 +0000191 printf("Binary type: %.4s", mi4header.type);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000192
193 /* Load firmware */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000194 lseek(fd, MI4_HEADER_SIZE, SEEK_SET);
195 rc = read(fd, buf, mi4header.mi4size-MI4_HEADER_SIZE);
196 if(rc < (int)mi4header.mi4size-MI4_HEADER_SIZE)
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000197 return EREAD_IMAGE_FAILED;
198
199 /* Check CRC32 to see if we have a valid file */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000200 sum = chksum_crc32 (buf,mi4header.mi4size-MI4_HEADER_SIZE);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000201
202 printf("Calculated CRC32: %x", sum);
203
204 if(sum != mi4header.crc32)
205 return EBAD_CHKSUM;
206
207 return EOK;
208}
209
Barry Wardella91a35b2007-03-16 14:36:14 +0000210#ifdef SANSA_E200
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000211/* Load mi4 firmware from a hidden disk partition */
212int 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. */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000219 ata_read_sectors(pinfo->start + PPMI_SECTOR_OFFSET,
220 PPMI_SECTORS, &ppmi_header);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000221
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 */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000229 ata_read_sectors(pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS
230 + (ppmi_header.length/512), MI4_HEADER_SECTORS, &mi4header);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000231
232 /* We don't support encrypted mi4 files yet */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000233 if( (mi4header.plaintext + MI4_HEADER_SIZE) != mi4header.mi4size)
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000234 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 */
Barry Wardellca8f7bf2007-03-19 11:20:22 +0000246 printf("Model id: %.4s", mi4header.model);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000247
248 /* Read binary type (RBOS, RBBL) */
Barry Wardellca8f7bf2007-03-19 11:20:22 +0000249 printf("Binary type: %.4s", mi4header.type);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000250
251 /* Load firmware */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000252 ata_read_sectors(pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS
253 + (ppmi_header.length/512) + MI4_HEADER_SECTORS,
254 (mi4header.length-MI4_HEADER_SIZE)/512, buf);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000255
256 /* Check CRC32 to see if we have a valid file */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000257 sum = chksum_crc32 (buf,mi4header.mi4size-MI4_HEADER_SIZE);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000258
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
Barry Wardell0c1a3042007-03-20 10:36:26 +0000292 /* Enable bootloader messages if any button is pressed */
293 if (btn)
294 verbose = true;
Barry Wardell23709982007-03-12 22:12:20 +0000295
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");
Barry Wardellca8f7bf2007-03-19 11:20:22 +0000299 printf("Version: %s", version);
Barry Wardellf4709d02007-01-17 12:20:38 +0000300 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 Wardell0c1a3042007-03-20 10:36:26 +0000380
381 error(EBOOTFILE, rc);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000382
Barry Wardell1920df32006-08-28 08:11:32 +0000383 } else {
Barry Wardellf4709d02007-01-17 12:20:38 +0000384 printf("Loading Rockbox...");
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000385 rc=load_mi4(loadbuffer, BOOTFILE, MAX_LOADSIZE);
Barry Wardell84b509d2007-01-28 18:42:11 +0000386 if (rc < EOK) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000387 printf("Can't load %s:", BOOTFILE);
Barry Wardelle293bbb2007-03-17 19:07:20 +0000388 printf(strerror(rc));
389
390 /* Try loading rockbox from old rockbox.e200/rockbox.h10 format */
391 rc=load_firmware(loadbuffer, OLD_BOOTFILE, MAX_LOADSIZE);
392 if (rc < EOK) {
393 printf("Can't load %s:", OLD_BOOTFILE);
Barry Wardell0c1a3042007-03-20 10:36:26 +0000394 error(EBOOTFILE, rc);
Barry Wardelle293bbb2007-03-17 19:07:20 +0000395 }
Barry Wardell84b509d2007-01-28 18:42:11 +0000396 }
Barry Wardell1920df32006-08-28 08:11:32 +0000397 }
Hristo Kovachev12041362006-08-11 09:51:04 +0000398
Barry Wardell84b509d2007-01-28 18:42:11 +0000399 return (void*)loadbuffer;
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000400}
401
402/* These functions are present in the firmware library, but we reimplement
403 them here because the originals do a lot more than we want */
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000404void usb_acknowledge(void)
405{
406}
407
408void usb_wait_for_disconnect(void)
409{
410}