mirror of
				https://github.com/Rockbox/rockbox.git
				synced 2025-10-29 00:36:22 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			274 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
	
		
			6.8 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 "file_internal.h"
 | |
| #include "storage.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();
 | |
| 
 | |
|     lcd_init();
 | |
|     font_init();
 | |
| 
 | |
|     backlight_init(); /* Turns on backlight -- BUGFIX backlight_init MUST BE AFTER lcd_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: %s", rbversion);
 | |
| 
 | |
|     i = storage_init();
 | |
| 
 | |
|     if (i != 0) {
 | |
|         printf("ATA error: %d", i);
 | |
|         fatal_error();
 | |
|     }
 | |
| 
 | |
|     filesystem_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");
 | |
| }
 |