blob: d0a8e0206c3381d678253fdd9cfd44045bebce80 [file] [log] [blame]
Dave Chapmanafe43d32009-07-12 22:16:51 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Dave Chapman0270e4c2009-07-16 00:57:02 +000010 * Copyright (C) 2009 by Dave Chapman
Dave Chapmanafe43d32009-07-12 22:16:51 +000011 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <stdarg.h>
25#include <string.h>
26
27#include "config.h"
28
29#include "inttypes.h"
30#include "cpu.h"
31#include "system.h"
32#include "lcd.h"
Dave Chapman38650352009-07-18 11:31:19 +000033#include "i2c-s5l8700.h"
Michael Sevakis4ea4cdf2014-08-08 02:28:11 -040034#include "../kernel-internal.h"
Michael Sevakis7d1a47c2013-08-05 22:02:45 -040035#include "file_internal.h"
Dave Chapmanafe43d32009-07-12 22:16:51 +000036#include "storage.h"
37#include "fat.h"
38#include "disk.h"
39#include "font.h"
40#include "backlight.h"
41#include "backlight-target.h"
42#include "button.h"
43#include "panic.h"
44#include "power.h"
45#include "file.h"
46#include "common.h"
Marcin Bukat0b296912012-03-04 15:34:29 +010047#include "rb-loader.h"
48#include "loader_strerror.h"
Rafaël Carré5d236b22010-05-27 09:41:46 +000049#include "version.h"
Dave Chapmanafe43d32009-07-12 22:16:51 +000050
Dave Chapmanb04a7a82009-10-11 01:37:12 +000051/* Safety measure - maximum allowed firmware image size.
52 The largest known current (October 2009) firmware is about 6.2MB so
53 we set this to 8MB.
54*/
55#define MAX_LOADSIZE (8*1024*1024)
56
Dave Chapmana70c7bf2009-10-12 19:46:45 +000057/* The buffer to load the firmware into - use an uncached alias of 0x08000000 */
58unsigned char *loadbuffer = (unsigned char *)0x48000000;
Dave Chapmanb04a7a82009-10-11 01:37:12 +000059
Dave Chapman38650352009-07-18 11:31:19 +000060extern int line;
61
Dave Chapmanb04a7a82009-10-11 01:37:12 +000062void fatal_error(void)
63{
64 extern int line;
65 bool holdstatus=false;
66
67 /* System font is 6 pixels wide */
68 printf("Hold MENU+SELECT to");
69 printf("reboot then SELECT+PLAY");
70 printf("for disk mode");
71 lcd_update();
72
73 while (1) {
74 if (button_hold() != holdstatus) {
75 if (button_hold()) {
76 holdstatus=true;
77 lcd_puts(0, line, "Hold switch on!");
78 } else {
79 holdstatus=false;
80 lcd_puts(0, line, " ");
81 }
82 lcd_update();
83 }
84 }
85}
86
Dave Chapmanf2bf4632009-10-12 00:57:07 +000087static void aes_decrypt(void* data, uint32_t size)
88{
89 uint32_t ptr, i;
90 uint32_t go = 1;
91
92 PWRCONEXT &= ~0x400;
93 AESTYPE = 1;
94 AESUNKREG0 = 1;
95 AESUNKREG0 = 0;
96 AESCONTROL = 1;
97 AESKEYLEN = 8;
98 AESOUTSIZE = size;
99 AESAUXSIZE = 0x10;
100 AESINSIZE = 0x10;
101 AESSIZE3 = 0x10;
102 for (ptr = (size >> 2) - 4; ; ptr -= 4)
103 {
104 AESOUTADDR = (uint32_t)data + (ptr << 2);
105 AESINADDR = (uint32_t)data + (ptr << 2);
106 AESAUXADDR = (uint32_t)data + (ptr << 2);
107 AESSTATUS = 6;
108 AESGO = go;
109 go = 3;
110 while ((AESSTATUS & 6) == 0);
111 if (ptr == 0) break;
112 for (i = 0; i < 4; i++)
113 ((uint32_t*)data)[ptr + i] ^= ((uint32_t*)data)[ptr + i - 4];
114 }
115 AESCONTROL = 0;
116 PWRCONEXT |= 0x400;
117}
118
119static int readfw(char* filename, void* address, int* size)
120{
121 int i;
122 uint32_t startsector = 0;
123 uint32_t buffer[0x200];
124
125 if (nand_read_sectors(0, 1, buffer) != 0)
126 return -1;
127
128 if (*((uint16_t*)((uint32_t)buffer + 0x1FE)) != 0xAA55)
129 return -2;
130
131 for (i = 0x1C2; i < 0x200; i += 0x10) {
132 if (((uint8_t*)buffer)[i] == 0) {
133 startsector = *((uint16_t*)((uint32_t)buffer + i + 4))
134 | (*((uint16_t*)((uint32_t)buffer + i + 6)) << 16);
135 break;
136 }
137 }
138
139 if (startsector == 0)
140 return -3;
141
142 if (nand_read_sectors(startsector, 1, buffer) != 0)
143 return -4;
144
145 if (buffer[0x40] != 0x5B68695D)
146 return -5;
147
148 if (nand_read_sectors(startsector + 1 + (buffer[0x41] >> 11), 1, buffer) != 0)
149 return -6;
150
151 for (i = 0; i < 0x1FE; i += 10) {
152 if (memcmp(&buffer[i], filename, 8) == 0) {
153 uint32_t filesector = startsector + 1 + (buffer[i + 3] >> 11);
154 *size = buffer[i + 4];
155
156 if (nand_read_sectors(filesector, ((*size + 0x7FF) >> 11), address) != 0)
157 return -7;
158
159 /* Success! */
160 return 0;
161 }
162 }
163
164 /* Nothing found */
165 return -8;
166}
167
Dave Chapmanafe43d32009-07-12 22:16:51 +0000168void main(void)
169{
Dave Chapman38650352009-07-18 11:31:19 +0000170 int i;
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000171 int btn;
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000172 int size;
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000173 int rc;
174 bool button_was_held;
175
176 /* Check the button hold status as soon as possible - to
177 give the user maximum chance to turn it on in order to
178 reset the settings in rockbox. */
179 button_was_held = button_hold();
Dave Chapman38650352009-07-18 11:31:19 +0000180
181 system_init();
Dave Chapman38650352009-07-18 11:31:19 +0000182 kernel_init();
183
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000184 i2c_init();
185
Dave Chapman38650352009-07-18 11:31:19 +0000186 enable_irq();
187
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000188 backlight_init(); /* Turns on the backlight */
189
Dave Chapman0270e4c2009-07-16 00:57:02 +0000190 lcd_init();
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000191 font_init();
Dave Chapman0270e4c2009-07-16 00:57:02 +0000192
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000193 lcd_set_foreground(LCD_WHITE);
194 lcd_set_background(LCD_BLACK);
195 lcd_clear_display();
Dave Chapman0270e4c2009-07-16 00:57:02 +0000196
Michael Sparmannc599da32010-10-10 20:52:46 +0000197 button_init();
Dave Chapman38650352009-07-18 11:31:19 +0000198
Michael Sparmannc599da32010-10-10 20:52:46 +0000199 btn = button_status();
Dave Chapman38650352009-07-18 11:31:19 +0000200
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000201 /* Enable bootloader messages */
202 if (btn==BUTTON_RIGHT)
203 verbose = true;
204
205 lcd_setfont(FONT_SYSFIXED);
206
207 printf("Rockbox boot loader");
Michael Sevakis95a4c3a2014-08-28 10:26:45 -0400208 printf("Version: %s", rbversion);
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000209
210 i = storage_init();
211
212 if (i != 0) {
213 printf("ATA error: %d", i);
214 fatal_error();
Dave Chapman38650352009-07-18 11:31:19 +0000215 }
216
Michael Sevakis7d1a47c2013-08-05 22:02:45 -0400217 filesystem_init();
218
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000219 rc = disk_mount_all();
220 if (rc<=0)
221 {
222 printf("No partition found");
223 fatal_error();
224 }
225
226 if (button_was_held || (btn==BUTTON_MENU)) {
227 /* If either the hold switch was on, or the Menu button was held, then
228 try the Apple firmware */
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000229 printf("Loading original firmware...");
230
Dave Chapmana70c7bf2009-10-12 19:46:45 +0000231 if ((rc = readfw("DNANkbso", loadbuffer, &size)) < 0) {
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000232 printf("readfw error %d",rc);
233 fatal_error();
234 }
235
236 /* Now we need to decrypt it */
237 printf("Decrypting %d bytes...",size);
238
Dave Chapmana70c7bf2009-10-12 19:46:45 +0000239 aes_decrypt(loadbuffer, size);
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000240 } else {
241 printf("Loading Rockbox...");
242 rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
243
Marcin Bukat0b296912012-03-04 15:34:29 +0100244 if (rc <= EFILE_EMPTY) {
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000245 printf("Error!");
246 printf("Can't load " BOOTFILE ": ");
Marcin Bukat0b296912012-03-04 15:34:29 +0100247 printf(loader_strerror(rc));
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000248 fatal_error();
249 }
250
251 printf("Rockbox loaded.");
252 }
253
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000254
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000255 /* If we get here, we have a new firmware image at 0x08000000, run it */
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000256 printf("Executing...");
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000257
Dave Chapman38650352009-07-18 11:31:19 +0000258 disable_irq();
259
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000260 /* Remap the bootrom back to zero - that's how the NOR bootloader leaves
261 it.
262 */
Dave Chapmana70c7bf2009-10-12 19:46:45 +0000263 MIUCON &= ~1;
264
265 /* Disable caches and protection unit */
266 asm volatile(
267 "mrc 15, 0, r0, c1, c0, 0 \n"
268 "bic r0, r0, #0x1000 \n"
269 "bic r0, r0, #0x5 \n"
270 "mcr 15, 0, r0, c1, c0, 0 \n"
271 );
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000272
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000273 /* Branch to start of DRAM */
274 asm volatile("ldr pc, =0x08000000");
Dave Chapmanafe43d32009-07-12 22:16:51 +0000275}