4ea4cdfc11
They need to include kernel-internal.h in order to perform inits. Change-Id: I5b0f155e4ff49a065c6cb97691ecd4396a199979
273 lines
6.7 KiB
C
273 lines
6.7 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2009 by Dave Chapman
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include "config.h"
|
|
|
|
#include "inttypes.h"
|
|
#include "cpu.h"
|
|
#include "system.h"
|
|
#include "lcd.h"
|
|
#include "i2c-s5l8700.h"
|
|
#include "../kernel-internal.h"
|
|
#include "storage.h"
|
|
#include "fat.h"
|
|
#include "disk.h"
|
|
#include "font.h"
|
|
#include "backlight.h"
|
|
#include "backlight-target.h"
|
|
#include "button.h"
|
|
#include "panic.h"
|
|
#include "power.h"
|
|
#include "file.h"
|
|
#include "common.h"
|
|
#include "rb-loader.h"
|
|
#include "loader_strerror.h"
|
|
#include "version.h"
|
|
|
|
/* Safety measure - maximum allowed firmware image size.
|
|
The largest known current (October 2009) firmware is about 6.2MB so
|
|
we set this to 8MB.
|
|
*/
|
|
#define MAX_LOADSIZE (8*1024*1024)
|
|
|
|
/* The buffer to load the firmware into - use an uncached alias of 0x08000000 */
|
|
unsigned char *loadbuffer = (unsigned char *)0x48000000;
|
|
|
|
extern int line;
|
|
|
|
void fatal_error(void)
|
|
{
|
|
extern int line;
|
|
bool holdstatus=false;
|
|
|
|
/* System font is 6 pixels wide */
|
|
printf("Hold MENU+SELECT to");
|
|
printf("reboot then SELECT+PLAY");
|
|
printf("for disk mode");
|
|
lcd_update();
|
|
|
|
while (1) {
|
|
if (button_hold() != holdstatus) {
|
|
if (button_hold()) {
|
|
holdstatus=true;
|
|
lcd_puts(0, line, "Hold switch on!");
|
|
} else {
|
|
holdstatus=false;
|
|
lcd_puts(0, line, " ");
|
|
}
|
|
lcd_update();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void aes_decrypt(void* data, uint32_t size)
|
|
{
|
|
uint32_t ptr, i;
|
|
uint32_t go = 1;
|
|
|
|
PWRCONEXT &= ~0x400;
|
|
AESTYPE = 1;
|
|
AESUNKREG0 = 1;
|
|
AESUNKREG0 = 0;
|
|
AESCONTROL = 1;
|
|
AESKEYLEN = 8;
|
|
AESOUTSIZE = size;
|
|
AESAUXSIZE = 0x10;
|
|
AESINSIZE = 0x10;
|
|
AESSIZE3 = 0x10;
|
|
for (ptr = (size >> 2) - 4; ; ptr -= 4)
|
|
{
|
|
AESOUTADDR = (uint32_t)data + (ptr << 2);
|
|
AESINADDR = (uint32_t)data + (ptr << 2);
|
|
AESAUXADDR = (uint32_t)data + (ptr << 2);
|
|
AESSTATUS = 6;
|
|
AESGO = go;
|
|
go = 3;
|
|
while ((AESSTATUS & 6) == 0);
|
|
if (ptr == 0) break;
|
|
for (i = 0; i < 4; i++)
|
|
((uint32_t*)data)[ptr + i] ^= ((uint32_t*)data)[ptr + i - 4];
|
|
}
|
|
AESCONTROL = 0;
|
|
PWRCONEXT |= 0x400;
|
|
}
|
|
|
|
static int readfw(char* filename, void* address, int* size)
|
|
{
|
|
int i;
|
|
uint32_t startsector = 0;
|
|
uint32_t buffer[0x200];
|
|
|
|
if (nand_read_sectors(0, 1, buffer) != 0)
|
|
return -1;
|
|
|
|
if (*((uint16_t*)((uint32_t)buffer + 0x1FE)) != 0xAA55)
|
|
return -2;
|
|
|
|
for (i = 0x1C2; i < 0x200; i += 0x10) {
|
|
if (((uint8_t*)buffer)[i] == 0) {
|
|
startsector = *((uint16_t*)((uint32_t)buffer + i + 4))
|
|
| (*((uint16_t*)((uint32_t)buffer + i + 6)) << 16);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (startsector == 0)
|
|
return -3;
|
|
|
|
if (nand_read_sectors(startsector, 1, buffer) != 0)
|
|
return -4;
|
|
|
|
if (buffer[0x40] != 0x5B68695D)
|
|
return -5;
|
|
|
|
if (nand_read_sectors(startsector + 1 + (buffer[0x41] >> 11), 1, buffer) != 0)
|
|
return -6;
|
|
|
|
for (i = 0; i < 0x1FE; i += 10) {
|
|
if (memcmp(&buffer[i], filename, 8) == 0) {
|
|
uint32_t filesector = startsector + 1 + (buffer[i + 3] >> 11);
|
|
*size = buffer[i + 4];
|
|
|
|
if (nand_read_sectors(filesector, ((*size + 0x7FF) >> 11), address) != 0)
|
|
return -7;
|
|
|
|
/* Success! */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Nothing found */
|
|
return -8;
|
|
}
|
|
|
|
void main(void)
|
|
{
|
|
int i;
|
|
int btn;
|
|
int size;
|
|
int rc;
|
|
bool button_was_held;
|
|
|
|
/* Check the button hold status as soon as possible - to
|
|
give the user maximum chance to turn it on in order to
|
|
reset the settings in rockbox. */
|
|
button_was_held = button_hold();
|
|
|
|
system_init();
|
|
kernel_init();
|
|
|
|
i2c_init();
|
|
|
|
enable_irq();
|
|
|
|
backlight_init(); /* Turns on the backlight */
|
|
|
|
lcd_init();
|
|
font_init();
|
|
|
|
lcd_set_foreground(LCD_WHITE);
|
|
lcd_set_background(LCD_BLACK);
|
|
lcd_clear_display();
|
|
|
|
button_init();
|
|
|
|
btn = button_status();
|
|
|
|
/* Enable bootloader messages */
|
|
if (btn==BUTTON_RIGHT)
|
|
verbose = true;
|
|
|
|
lcd_setfont(FONT_SYSFIXED);
|
|
|
|
printf("Rockbox boot loader");
|
|
printf("Version: " RBVERSION);
|
|
|
|
i = storage_init();
|
|
|
|
if (i != 0) {
|
|
printf("ATA error: %d", i);
|
|
fatal_error();
|
|
}
|
|
|
|
disk_init();
|
|
rc = disk_mount_all();
|
|
if (rc<=0)
|
|
{
|
|
printf("No partition found");
|
|
fatal_error();
|
|
}
|
|
|
|
if (button_was_held || (btn==BUTTON_MENU)) {
|
|
/* If either the hold switch was on, or the Menu button was held, then
|
|
try the Apple firmware */
|
|
printf("Loading original firmware...");
|
|
|
|
if ((rc = readfw("DNANkbso", loadbuffer, &size)) < 0) {
|
|
printf("readfw error %d",rc);
|
|
fatal_error();
|
|
}
|
|
|
|
/* Now we need to decrypt it */
|
|
printf("Decrypting %d bytes...",size);
|
|
|
|
aes_decrypt(loadbuffer, size);
|
|
} else {
|
|
printf("Loading Rockbox...");
|
|
rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
|
|
|
|
if (rc <= EFILE_EMPTY) {
|
|
printf("Error!");
|
|
printf("Can't load " BOOTFILE ": ");
|
|
printf(loader_strerror(rc));
|
|
fatal_error();
|
|
}
|
|
|
|
printf("Rockbox loaded.");
|
|
}
|
|
|
|
|
|
/* If we get here, we have a new firmware image at 0x08000000, run it */
|
|
printf("Executing...");
|
|
|
|
disable_irq();
|
|
|
|
/* Remap the bootrom back to zero - that's how the NOR bootloader leaves
|
|
it.
|
|
*/
|
|
MIUCON &= ~1;
|
|
|
|
/* Disable caches and protection unit */
|
|
asm volatile(
|
|
"mrc 15, 0, r0, c1, c0, 0 \n"
|
|
"bic r0, r0, #0x1000 \n"
|
|
"bic r0, r0, #0x5 \n"
|
|
"mcr 15, 0, r0, c1, c0, 0 \n"
|
|
);
|
|
|
|
/* Branch to start of DRAM */
|
|
asm volatile("ldr pc, =0x08000000");
|
|
}
|