blob: 85bb2df86d0af4583428e69ebc694c8439ba4e15 [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"
Dave Chapmanafe43d32009-07-12 22:16:51 +000037#include "disk.h"
38#include "font.h"
39#include "backlight.h"
40#include "backlight-target.h"
41#include "button.h"
42#include "panic.h"
43#include "power.h"
44#include "file.h"
45#include "common.h"
Marcin Bukat0b296912012-03-04 15:34:29 +010046#include "rb-loader.h"
47#include "loader_strerror.h"
Rafaël Carré5d236b22010-05-27 09:41:46 +000048#include "version.h"
Dave Chapmanafe43d32009-07-12 22:16:51 +000049
Dave Chapmanb04a7a82009-10-11 01:37:12 +000050/* Safety measure - maximum allowed firmware image size.
51 The largest known current (October 2009) firmware is about 6.2MB so
52 we set this to 8MB.
53*/
54#define MAX_LOADSIZE (8*1024*1024)
55
Dave Chapmana70c7bf2009-10-12 19:46:45 +000056/* The buffer to load the firmware into - use an uncached alias of 0x08000000 */
57unsigned char *loadbuffer = (unsigned char *)0x48000000;
Dave Chapmanb04a7a82009-10-11 01:37:12 +000058
Dave Chapman38650352009-07-18 11:31:19 +000059extern int line;
60
Dave Chapmanb04a7a82009-10-11 01:37:12 +000061void fatal_error(void)
62{
63 extern int line;
64 bool holdstatus=false;
65
66 /* System font is 6 pixels wide */
67 printf("Hold MENU+SELECT to");
68 printf("reboot then SELECT+PLAY");
69 printf("for disk mode");
70 lcd_update();
71
72 while (1) {
73 if (button_hold() != holdstatus) {
74 if (button_hold()) {
75 holdstatus=true;
76 lcd_puts(0, line, "Hold switch on!");
77 } else {
78 holdstatus=false;
79 lcd_puts(0, line, " ");
80 }
81 lcd_update();
82 }
83 }
84}
85
Dave Chapmanf2bf4632009-10-12 00:57:07 +000086static void aes_decrypt(void* data, uint32_t size)
87{
88 uint32_t ptr, i;
89 uint32_t go = 1;
90
91 PWRCONEXT &= ~0x400;
92 AESTYPE = 1;
93 AESUNKREG0 = 1;
94 AESUNKREG0 = 0;
95 AESCONTROL = 1;
96 AESKEYLEN = 8;
97 AESOUTSIZE = size;
98 AESAUXSIZE = 0x10;
99 AESINSIZE = 0x10;
100 AESSIZE3 = 0x10;
101 for (ptr = (size >> 2) - 4; ; ptr -= 4)
102 {
103 AESOUTADDR = (uint32_t)data + (ptr << 2);
104 AESINADDR = (uint32_t)data + (ptr << 2);
105 AESAUXADDR = (uint32_t)data + (ptr << 2);
106 AESSTATUS = 6;
107 AESGO = go;
108 go = 3;
109 while ((AESSTATUS & 6) == 0);
110 if (ptr == 0) break;
111 for (i = 0; i < 4; i++)
112 ((uint32_t*)data)[ptr + i] ^= ((uint32_t*)data)[ptr + i - 4];
113 }
114 AESCONTROL = 0;
115 PWRCONEXT |= 0x400;
116}
117
118static int readfw(char* filename, void* address, int* size)
119{
120 int i;
121 uint32_t startsector = 0;
122 uint32_t buffer[0x200];
123
124 if (nand_read_sectors(0, 1, buffer) != 0)
125 return -1;
126
127 if (*((uint16_t*)((uint32_t)buffer + 0x1FE)) != 0xAA55)
128 return -2;
129
130 for (i = 0x1C2; i < 0x200; i += 0x10) {
131 if (((uint8_t*)buffer)[i] == 0) {
132 startsector = *((uint16_t*)((uint32_t)buffer + i + 4))
133 | (*((uint16_t*)((uint32_t)buffer + i + 6)) << 16);
134 break;
135 }
136 }
137
138 if (startsector == 0)
139 return -3;
140
141 if (nand_read_sectors(startsector, 1, buffer) != 0)
142 return -4;
143
144 if (buffer[0x40] != 0x5B68695D)
145 return -5;
146
147 if (nand_read_sectors(startsector + 1 + (buffer[0x41] >> 11), 1, buffer) != 0)
148 return -6;
149
150 for (i = 0; i < 0x1FE; i += 10) {
151 if (memcmp(&buffer[i], filename, 8) == 0) {
152 uint32_t filesector = startsector + 1 + (buffer[i + 3] >> 11);
153 *size = buffer[i + 4];
154
155 if (nand_read_sectors(filesector, ((*size + 0x7FF) >> 11), address) != 0)
156 return -7;
157
158 /* Success! */
159 return 0;
160 }
161 }
162
163 /* Nothing found */
164 return -8;
165}
166
Dave Chapmanafe43d32009-07-12 22:16:51 +0000167void main(void)
168{
Dave Chapman38650352009-07-18 11:31:19 +0000169 int i;
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000170 int btn;
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000171 int size;
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000172 int rc;
173 bool button_was_held;
174
175 /* Check the button hold status as soon as possible - to
176 give the user maximum chance to turn it on in order to
177 reset the settings in rockbox. */
178 button_was_held = button_hold();
Dave Chapman38650352009-07-18 11:31:19 +0000179
180 system_init();
Dave Chapman38650352009-07-18 11:31:19 +0000181 kernel_init();
182
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000183 i2c_init();
184
Dave Chapman38650352009-07-18 11:31:19 +0000185 enable_irq();
186
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000187 backlight_init(); /* Turns on the backlight */
188
Dave Chapman0270e4c2009-07-16 00:57:02 +0000189 lcd_init();
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000190 font_init();
Dave Chapman0270e4c2009-07-16 00:57:02 +0000191
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000192 lcd_set_foreground(LCD_WHITE);
193 lcd_set_background(LCD_BLACK);
194 lcd_clear_display();
Dave Chapman0270e4c2009-07-16 00:57:02 +0000195
Michael Sparmannc599da32010-10-10 20:52:46 +0000196 button_init();
Dave Chapman38650352009-07-18 11:31:19 +0000197
Michael Sparmannc599da32010-10-10 20:52:46 +0000198 btn = button_status();
Dave Chapman38650352009-07-18 11:31:19 +0000199
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000200 /* Enable bootloader messages */
201 if (btn==BUTTON_RIGHT)
202 verbose = true;
203
204 lcd_setfont(FONT_SYSFIXED);
205
206 printf("Rockbox boot loader");
Michael Sevakis95a4c3a2014-08-28 10:26:45 -0400207 printf("Version: %s", rbversion);
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000208
209 i = storage_init();
210
211 if (i != 0) {
212 printf("ATA error: %d", i);
213 fatal_error();
Dave Chapman38650352009-07-18 11:31:19 +0000214 }
215
Michael Sevakis7d1a47c2013-08-05 22:02:45 -0400216 filesystem_init();
217
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000218 rc = disk_mount_all();
219 if (rc<=0)
220 {
221 printf("No partition found");
222 fatal_error();
223 }
224
225 if (button_was_held || (btn==BUTTON_MENU)) {
226 /* If either the hold switch was on, or the Menu button was held, then
227 try the Apple firmware */
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000228 printf("Loading original firmware...");
229
Dave Chapmana70c7bf2009-10-12 19:46:45 +0000230 if ((rc = readfw("DNANkbso", loadbuffer, &size)) < 0) {
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000231 printf("readfw error %d",rc);
232 fatal_error();
233 }
234
235 /* Now we need to decrypt it */
236 printf("Decrypting %d bytes...",size);
237
Dave Chapmana70c7bf2009-10-12 19:46:45 +0000238 aes_decrypt(loadbuffer, size);
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000239 } else {
240 printf("Loading Rockbox...");
241 rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
242
Marcin Bukat0b296912012-03-04 15:34:29 +0100243 if (rc <= EFILE_EMPTY) {
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000244 printf("Error!");
245 printf("Can't load " BOOTFILE ": ");
Marcin Bukat0b296912012-03-04 15:34:29 +0100246 printf(loader_strerror(rc));
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000247 fatal_error();
248 }
249
250 printf("Rockbox loaded.");
251 }
252
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000253
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000254 /* If we get here, we have a new firmware image at 0x08000000, run it */
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000255 printf("Executing...");
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000256
Dave Chapman38650352009-07-18 11:31:19 +0000257 disable_irq();
258
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000259 /* Remap the bootrom back to zero - that's how the NOR bootloader leaves
260 it.
261 */
Dave Chapmana70c7bf2009-10-12 19:46:45 +0000262 MIUCON &= ~1;
263
264 /* Disable caches and protection unit */
265 asm volatile(
266 "mrc 15, 0, r0, c1, c0, 0 \n"
267 "bic r0, r0, #0x1000 \n"
268 "bic r0, r0, #0x5 \n"
269 "mcr 15, 0, r0, c1, c0, 0 \n"
270 );
Dave Chapmanf2bf4632009-10-12 00:57:07 +0000271
Dave Chapmanb04a7a82009-10-11 01:37:12 +0000272 /* Branch to start of DRAM */
273 asm volatile("ldr pc, =0x08000000");
Dave Chapmanafe43d32009-07-12 22:16:51 +0000274}