blob: e598a29fa0d2677757e2f8788ef9d48619122742 [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 */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000128#define PPMI_SECTOR_OFFSET 1024
129#define PPMI_SECTORS 1
130#define MI4_HEADER_SECTORS 1
131#define MI4_HEADER_SIZE 0x200
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000132
133/* mi4 header structure */
134struct mi4header_t {
135 unsigned char magic[4];
136 uint32_t version;
137 uint32_t length;
138 uint32_t crc32;
139 uint32_t enctype;
140 uint32_t mi4size;
141 uint32_t plaintext;
142 uint32_t dsa_key[10];
143 uint32_t pad[109];
144 unsigned char type[4];
145 unsigned char model[4];
146};
147
148/* PPMI header structure */
149struct ppmi_header_t {
150 unsigned char magic[4];
151 uint32_t length;
152 uint32_t pad[126];
153};
154
155/* Load mi4 format firmware image */
156int load_mi4(unsigned char* buf, char* firmware, unsigned int buffer_size)
157{
158 int fd;
159 struct mi4header_t mi4header;
160 int rc;
161 unsigned long sum;
162 char filename[MAX_PATH];
163
164 snprintf(filename,sizeof(filename),"/.rockbox/%s",firmware);
165 fd = open(filename, O_RDONLY);
166 if(fd < 0)
167 {
168 snprintf(filename,sizeof(filename),"/%s",firmware);
169 fd = open(filename, O_RDONLY);
170 if(fd < 0)
171 return EFILE_NOT_FOUND;
172 }
173
Barry Wardelle293bbb2007-03-17 19:07:20 +0000174 read(fd, &mi4header, MI4_HEADER_SIZE);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000175
176 /* We don't support encrypted mi4 files yet */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000177 if( (mi4header.plaintext + MI4_HEADER_SIZE) != mi4header.mi4size)
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000178 return EINVALID_FORMAT;
179
180 /* MI4 file size */
181 printf("mi4 size: %x", mi4header.length);
182
183 if (mi4header.length > buffer_size)
184 return EFILE_TOO_BIG;
185
186 /* CRC32 */
187 printf("CRC32: %x", mi4header.crc32);
188
189 /* Rockbox model id */
190 printf("Model id: %4s", mi4header.model);
191
192 /* Read binary type (RBOS, RBBL) */
193 printf("Binary type: %4s", mi4header.type);
194
195 /* Load firmware */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000196 lseek(fd, MI4_HEADER_SIZE, SEEK_SET);
197 rc = read(fd, buf, mi4header.mi4size-MI4_HEADER_SIZE);
198 if(rc < (int)mi4header.mi4size-MI4_HEADER_SIZE)
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000199 return EREAD_IMAGE_FAILED;
200
201 /* Check CRC32 to see if we have a valid file */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000202 sum = chksum_crc32 (buf,mi4header.mi4size-MI4_HEADER_SIZE);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000203
204 printf("Calculated CRC32: %x", sum);
205
206 if(sum != mi4header.crc32)
207 return EBAD_CHKSUM;
208
209 return EOK;
210}
211
Barry Wardella91a35b2007-03-16 14:36:14 +0000212#ifdef SANSA_E200
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000213/* Load mi4 firmware from a hidden disk partition */
214int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, unsigned int buffer_size)
215{
216 struct mi4header_t mi4header;
217 struct ppmi_header_t ppmi_header;
218 unsigned long sum;
219
220 /* Read header to find out how long the mi4 file is. */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000221 ata_read_sectors(pinfo->start + PPMI_SECTOR_OFFSET,
222 PPMI_SECTORS, &ppmi_header);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000223
224 /* The first four characters at 0x80000 (sector 1024) should be PPMI*/
225 if( memcmp(ppmi_header.magic, "PPMI", 4) )
226 return EFILE_NOT_FOUND;
227
228 printf("BL mi4 size: %x", ppmi_header.length);
229
230 /* Read mi4 header of the OF */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000231 ata_read_sectors(pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS
232 + (ppmi_header.length/512), MI4_HEADER_SECTORS, &mi4header);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000233
234 /* We don't support encrypted mi4 files yet */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000235 if( (mi4header.plaintext + MI4_HEADER_SIZE) != mi4header.mi4size)
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000236 return EINVALID_FORMAT;
237
238 /* MI4 file size */
239 printf("OF mi4 size: %x", mi4header.length);
240
241 if (mi4header.length > buffer_size)
242 return EFILE_TOO_BIG;
243
244 /* CRC32 */
245 printf("CRC32: %x", mi4header.crc32);
246
247 /* Rockbox model id */
248 printf("Model id: %4s", mi4header.model);
249
250 /* Read binary type (RBOS, RBBL) */
251 printf("Binary type: %4s", mi4header.type);
252
253 /* Load firmware */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000254 ata_read_sectors(pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS
255 + (ppmi_header.length/512) + MI4_HEADER_SECTORS,
256 (mi4header.length-MI4_HEADER_SIZE)/512, buf);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000257
258 /* Check CRC32 to see if we have a valid file */
Barry Wardelle293bbb2007-03-17 19:07:20 +0000259 sum = chksum_crc32 (buf,mi4header.mi4size-MI4_HEADER_SIZE);
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000260
261 printf("Calculated CRC32: %x", sum);
262
263 if(sum != mi4header.crc32)
264 return EBAD_CHKSUM;
265
266 return EOK;
267}
Barry Wardella91a35b2007-03-16 14:36:14 +0000268#endif
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000269
Barry Wardell1920df32006-08-28 08:11:32 +0000270void* main(void)
271{
272 char buf[256];
273 int i;
Barry Wardell23709982007-03-12 22:12:20 +0000274 int btn;
Barry Wardell1920df32006-08-28 08:11:32 +0000275 int rc;
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000276 int num_partitions;
Barry Wardell1920df32006-08-28 08:11:32 +0000277 unsigned short* identify_info;
278 struct partinfo* pinfo;
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000279
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000280 chksum_crc32gentab ();
281
Barry Wardell1920df32006-08-28 08:11:32 +0000282 system_init();
283 kernel_init();
284 lcd_init();
285 font_init();
Barry Wardell2f16d4f2006-12-19 11:33:53 +0000286 button_init();
Barry Wardell1920df32006-08-28 08:11:32 +0000287
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000288 lcd_set_foreground(LCD_WHITE);
289 lcd_set_background(LCD_BLACK);
290 lcd_clear_display();
291
Barry Wardell23709982007-03-12 22:12:20 +0000292 btn = button_read_device();
293
294 /* Enable bootloader messages */
Barry Wardella42070d2007-03-15 22:32:58 +0000295 if (btn & BOOTLOADER_VERBOSE)
Barry Wardell23709982007-03-12 22:12:20 +0000296 verbose = true;
297
Barry Wardell1920df32006-08-28 08:11:32 +0000298 lcd_setfont(FONT_SYSFIXED);
299
Barry Wardellf4709d02007-01-17 12:20:38 +0000300 printf("Rockbox boot loader");
301 printf("Version: 20%s", version);
302 printf(MODEL_NAME);
Barry Wardell1920df32006-08-28 08:11:32 +0000303
304 i=ata_init();
305 if (i==0) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000306 identify_info=ata_get_identify();
307 /* Show model */
308 for (i=0; i < 20; i++) {
309 ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
310 }
311 buf[40]=0;
312 for (i=39; i && buf[i]==' '; i--) {
313 buf[i]=0;
314 }
315 printf(buf);
Barry Wardell1920df32006-08-28 08:11:32 +0000316 } else {
Barry Wardell23709982007-03-12 22:12:20 +0000317 error(EATA, i);
Barry Wardell1920df32006-08-28 08:11:32 +0000318 }
319
320 disk_init();
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000321 num_partitions = disk_mount_all();
322 if (num_partitions<=0)
Barry Wardell1920df32006-08-28 08:11:32 +0000323 {
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000324 error(EDISK,num_partitions);
Barry Wardell1920df32006-08-28 08:11:32 +0000325 }
326
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000327 /* Just list the first 2 partitions since we don't have any devices yet
328 that have more than that */
329 for(i=0; i<2; i++)
330 {
331 pinfo = disk_partinfo(i);
332 printf("Partition %d: 0x%02x %ld MB",
333 i, pinfo->type, pinfo->size / 2048);
334 }
Barry Wardell1920df32006-08-28 08:11:32 +0000335
Barry Wardella42070d2007-03-15 22:32:58 +0000336 if(btn & BOOTLOADER_BOOT_OF)
Barry Wardell1920df32006-08-28 08:11:32 +0000337 {
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000338 /* Load original mi4 firmware in to a memory buffer called loadbuffer.
339 The rest of the loading is done in crt0.S.
340 1) First try reading from the hidden partition (on Sansa only).
341 2) Next try a decrypted mi4 file in /System/OF.mi4
342 3) Finally, try a raw firmware binary in /System/OF.mi4. It should be
343 a mi4 firmware decrypted and header stripped using mi4code.
Barry Wardell84b509d2007-01-28 18:42:11 +0000344 */
Barry Wardellf4709d02007-01-17 12:20:38 +0000345 printf("Loading original firmware...");
Barry Wardella91a35b2007-03-16 14:36:14 +0000346
347#ifdef SANSA_E200
348 /* First try a (hidden) firmware partition */
349 printf("Trying firmware partition");
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000350 pinfo = disk_partinfo(1);
Barry Wardellb8a5adf2007-03-16 14:41:55 +0000351 if(pinfo->type == PARTITION_TYPE_OS2_HIDDEN_C_DRIVE)
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000352 {
353 rc = load_mi4_part(loadbuffer, pinfo, MAX_LOADSIZE);
354 if (rc < EOK) {
355 printf("Can't load from partition");
356 printf(strerror(rc));
357 } else {
358 return (void*)loadbuffer;
359 }
360 } else {
361 printf("No hidden partition found.");
362 }
Barry Wardella91a35b2007-03-16 14:36:14 +0000363#endif
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000364
365 printf("Trying /System/OF.mi4");
366 rc=load_mi4(loadbuffer, "/System/OF.mi4", MAX_LOADSIZE);
367 if (rc < EOK) {
368 printf("Can't load /System/OF.mi4");
369 printf(strerror(rc));
370 } else {
371 return (void*)loadbuffer;
372 }
373
374 printf("Trying /System/OF.bin");
Barry Wardell84b509d2007-01-28 18:42:11 +0000375 rc=load_raw_firmware(loadbuffer, "/System/OF.bin", MAX_LOADSIZE);
376 if (rc < EOK) {
Barry Wardell23709982007-03-12 22:12:20 +0000377 printf("Can't load /System/OF.bin");
Barry Wardell14ed3ca2007-03-16 14:28:00 +0000378 printf(strerror(rc));
379 } else {
380 return (void*)loadbuffer;
Barry Wardell84b509d2007-01-28 18:42:11 +0000381 }
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);
394 printf(strerror(rc));
395 }
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}