FS#6554. Move bootloader code into a common file. Only PortalPlayer devices (iPods, H10, Sansa) are affected for the moment. Someone with access to (and no fear of bricking) an X5, H100, H300 and Gigabeat should try to adapt those bootloaders to also use the code in common.c. The (non-working) patch in the tracker would be a good place to start with this.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12136 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Barry Wardell 2007-01-28 18:42:11 +00:00
parent 6c3a446435
commit 84b509dc43
7 changed files with 364 additions and 421 deletions

View file

@ -1,8 +1,10 @@
#if defined(IPOD_ARCH)
common.c
ipod.c
#elif defined(GIGABEAT_F)
gigabeat.c
#elif defined(IRIVER_H10) || defined(IRIVER_H10_5GB) || defined(SANSA_E200)
common.c
main-pp.c
#elif defined(ELIO_TPJ1022)
tpj1022.c

205
bootloader/common.c Normal file
View file

@ -0,0 +1,205 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id: main.c 11997 2007-01-13 09:08:18Z miipekk $
*
* Copyright (C) 2005 by Linus Nielsen Feltzing
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "lcd.h"
#include "lcd-remote.h"
#include "font.h"
#include "system.h"
#include <stdarg.h>
#include <stdio.h>
#include "cpu.h"
#include "common.h"
int line = 0;
#ifdef HAVE_REMOTE_LCD
int remote_line = 0;
#endif
char printfbuf[256];
void reset_screen(void)
{
lcd_clear_display();
line = 0;
#ifdef HAVE_REMOTE_LCD
lcd_remote_clear_display();
remote_line = 0;
#endif
}
void printf(const char *format, ...)
{
int len;
unsigned char *ptr;
va_list ap;
va_start(ap, format);
ptr = printfbuf;
len = vsnprintf(ptr, sizeof(printfbuf), format, ap);
va_end(ap);
lcd_puts(0, line++, ptr);
lcd_update();
if(line >= LCD_HEIGHT/SYSFONT_HEIGHT)
line = 0;
#ifdef HAVE_REMOTE_LCD
lcd_remote_puts(0, remote_line++, ptr);
lcd_remote_update();
if(remote_line >= LCD_REMOTE_HEIGHT/SYSFONT_HEIGHT)
remote_line = 0;
#endif
}
char *strerror(int error)
{
switch(error)
{
case EOK:
return "OK";
case EFILE_NOT_FOUND:
return "File not found";
case EREAD_CHKSUM_FAILED:
return "Read failed (chksum)";
case EREAD_MODEL_FAILED:
return "Read failed (model)";
case EREAD_IMAGE_FAILED:
return "Read failed (image)";
case EBAD_CHKSUM:
return "Bad checksum";
case EFILE_TOO_BIG:
return "File too big";
default:
return "Unknown";
}
}
/* Load firmware image in a format created by tools/scramble */
int load_firmware(unsigned char* buf, char* firmware, int buffer_size)
{
int fd;
int rc;
int len;
unsigned long chksum;
char model[5];
unsigned long sum;
int i;
char filename[MAX_PATH];
snprintf(filename,sizeof(filename),"/.rockbox/%s",firmware);
fd = open(filename, O_RDONLY);
if(fd < 0)
{
snprintf(filename,sizeof(filename),"/%s",firmware);
fd = open(filename, O_RDONLY);
if(fd < 0)
return EFILE_NOT_FOUND;
}
len = filesize(fd) - 8;
printf("Length: %x", len);
if (len > buffer_size)
return EFILE_TOO_BIG;
lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET);
rc = read(fd, &chksum, 4);
chksum=betoh32(chksum); /* Rockbox checksums are big-endian */
if(rc < 4)
return EREAD_CHKSUM_FAILED;
printf("Checksum: %x", chksum);
rc = read(fd, model, 4);
if(rc < 4)
return EREAD_MODEL_FAILED;
model[4] = 0;
printf("Model name: %s", model);
printf("Loading %s", firmware);
lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
rc = read(fd, buf, len);
if(rc < len)
return EREAD_IMAGE_FAILED;
close(fd);
sum = MODEL_NUMBER;
for(i = 0;i < len;i++) {
sum += buf[i];
}
printf("Sum: %x", sum);
if(sum != chksum)
return EBAD_CHKSUM;
return len;
}
/* Load raw binary image. */
int load_raw_firmware(unsigned char* buf, char* firmware, int buffer_size)
{
int fd;
int rc;
int len;
char filename[MAX_PATH];
snprintf(filename,sizeof(filename),"%s",firmware);
fd = open(filename, O_RDONLY);
if(fd < 0)
{
return EFILE_NOT_FOUND;
}
len = filesize(fd);
if (len > buffer_size)
return EFILE_TOO_BIG;
rc = read(fd, buf, len);
if(rc < len)
return EREAD_IMAGE_FAILED;
close(fd);
return len;
}
/* These functions are present in the firmware library, but we reimplement
them here because the originals do a lot more than we want */
void reset_poweroff_timer(void)
{
}
int dbg_ports(void)
{
return 0;
}
void mpeg_stop(void)
{
}
void sys_poweroff(void)
{
}

34
bootloader/common.h Normal file
View file

@ -0,0 +1,34 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id: main.c 11997 2007-01-13 09:08:18Z miipekk $
*
* Copyright (C) 2005 by Linus Nielsen Feltzing
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
/* Error codes */
#define EOK 0
#define EFILE_NOT_FOUND -1
#define EREAD_CHKSUM_FAILED -2
#define EREAD_MODEL_FAILED -3
#define EREAD_IMAGE_FAILED -4
#define EBAD_CHKSUM -5
#define EFILE_TOO_BIG -6
/* Functions common to all bootloaders */
void reset_screen(void);
void printf(const char *format, ...);
char *strerror(int error);
int load_firmware(unsigned char* buf, char* firmware, int buffer_size);
int load_raw_firmware(unsigned char* buf, char* firmware, int buffer_size);

View file

@ -39,16 +39,22 @@
#include "panic.h"
#include "power.h"
#include "file.h"
#include "common.h"
#define XSC(X) #X
#define SC(X) XSC(X)
#if (CONFIG_CPU == PP5020)
#define DRAM_START 0x10000000
#else
#define IPOD_LCD_BASE 0xc0001000
#define DRAM_START 0x28000000
#endif
/* Maximum allowed firmware image size. The largest known current
(December 2006) firmware is about 7.5MB (Apple's firmware for the ipod video)
so we set this to 8MB. */
#define MAX_LOADSIZE (8*1024*1024)
/* A buffer to load the Linux kernel or Rockbox into */
unsigned char *loadbuffer = (unsigned char *)DRAM_START;
/* Bootloader version */
char version[] = APPSVERSION;
#define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084)))
/* We copy the hardware revision to the last four bytes of SDRAM and then
@ -61,17 +67,6 @@
#define BUTTON_PLAY 4
#define BUTTON_HOLD 5
/* Size of the buffer to store the loaded Rockbox/Linux/AppleOS image */
/* The largest known current (December 2006) firmware is about 7.5MB
(Apple's firmware for the ipod video) so we set this to 8MB. */
#define MAX_LOADSIZE (8*1024*1024)
char version[] = APPSVERSION;
int line=0;
#if CONFIG_KEYPAD == IPOD_4G_PAD && !defined(IPOD_MINI)
/* check if number of seconds has past */
int timer_check(int clock_start, unsigned int usecs)
@ -157,54 +152,6 @@ int opto_keypad_read(void)
}
#endif
char *strerror(int error)
{
switch(error)
{
case 0:
return "OK";
case -1:
return "File not found";
case -2:
return "Read failed (chksum)";
case -3:
return "Read failed (model)";
case -4:
return "Read failed (image)";
case -5:
return "Bad checksum";
case -6:
return "File too big";
default:
return "Unknown";
}
}
char printfbuf[256];
void reset_screen(void)
{
lcd_clear_display();
line = 0;
}
void printf(const char *format, ...)
{
int len;
unsigned char *ptr;
va_list ap;
va_start(ap, format);
ptr = printfbuf;
len = vsnprintf(ptr, sizeof(printfbuf), format, ap);
va_end(ap);
lcd_puts(0, line++, ptr);
lcd_update();
if(line >= (LCD_HEIGHT/SYSFONT_HEIGHT))
line = 0;
}
static int key_pressed(void)
{
unsigned char state;
@ -240,101 +187,9 @@ bool button_hold(void)
return (GPIOA_INPUT_VAL & 0x20)?false:true;
}
int load_rockbox(unsigned char* buf, char* firmware)
{
int fd;
int rc;
int len;
unsigned long chksum;
char model[5];
unsigned long sum;
int i;
char filename[MAX_PATH];
snprintf(filename,sizeof(filename),"/.rockbox/%s",firmware);
fd = open(filename, O_RDONLY);
if(fd < 0)
{
snprintf(filename,sizeof(filename),"/%s",firmware);
fd = open(filename, O_RDONLY);
if(fd < 0)
return -1;
}
len = filesize(fd) - 8;
if (len > MAX_LOADSIZE)
return -6;
lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET);
rc = read(fd, &chksum, 4);
chksum=betoh32(chksum); /* Rockbox checksums are big-endian */
if(rc < 4)
return -2;
rc = read(fd, model, 4);
if(rc < 4)
return -3;
model[4] = 0;
printf("Model: %s", model);
printf("Checksum: %x", chksum);
printf("Loading %s", firmware);
lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
rc = read(fd, buf, len);
if(rc < len)
return -4;
close(fd);
sum = MODEL_NUMBER;
for(i = 0;i < len;i++) {
sum += buf[i];
}
printf("Sum: %x", sum);
if(sum != chksum)
return -5;
return len;
}
int load_linux(unsigned char* buf) {
int fd;
int rc;
int len;
fd=open("/linux.bin",O_RDONLY);
if (fd < 0)
return -1;
len=filesize(fd);
if (len > MAX_LOADSIZE)
return -6;
rc=read(fd,buf,len);
if (rc < len)
return -4;
printf("Loaded Linux: %d bytes", len);
return len;
}
/* A buffer to load the Linux kernel or Rockbox into */
unsigned char loadbuffer[MAX_LOADSIZE];
void fatal_error(void)
{
extern int line;
bool holdstatus=false;
/* System font is 6 pixels wide */
@ -423,7 +278,6 @@ void* main(void)
button_init();
#endif
line=0;
lcd_setfont(FONT_SYSFIXED);
@ -459,95 +313,74 @@ void* main(void)
printf("Partition 1: 0x%02x %ld MB",
pinfo->type, pinfo->size / 2048);
/* See if there is an Apple firmware image in RAM */
haveretailos = (memcmp((void*)(DRAM_START+0x20),"portalplayer",12)==0);
/* Check for a keypress */
i=key_pressed();
/* We don't load Rockbox if the hold button is enabled. */
if (!button_was_held) {
/* Check for a keypress */
i=key_pressed();
if (button_was_held || (i==BUTTON_MENU)) {
/* If either the hold switch was on, or the Menu button was held, then
try the Apple firmware */
if ((i!=BUTTON_MENU) && (i!=BUTTON_PLAY)) {
printf("Loading Rockbox...");
rc=load_rockbox(loadbuffer, BOOTFILE);
if (rc < 0) {
printf("Error!");
printf("Can't load rockbox.ipod:");
printf(strerror(rc));
} else {
printf("Rockbox loaded.");
memcpy((void*)DRAM_START,loadbuffer,rc);
printf("Loading original firmware...");
/* First try an apple_os.ipod file on the FAT32 partition
(either in .rockbox or the root)
*/
rc=load_firmware(loadbuffer, "apple_os.ipod", MAX_LOADSIZE);
if(rc==EFILE_NOT_FOUND) {
/* If apple_os.ipod doesn't exist, then check if there is an Apple
firmware image in RAM */
haveretailos = (memcmp((void*)(DRAM_START+0x20),"portalplayer",12)==0);
if (haveretailos) {
/* We have a copy of the retailos in RAM, lets just run it. */
return (void*)DRAM_START;
}
} else if (rc < EFILE_NOT_FOUND) {
printf("Error!");
printf("Can't load apple_os.ipod:");
printf(strerror(rc));
} else if (rc > 0) {
printf("apple_os.ipod loaded.");
return (void*)DRAM_START;
}
if (i==BUTTON_PLAY) {
printf("Loading Linux...");
rc=load_linux(loadbuffer);
if (rc < 0) {
printf("Error!");
printf("Can't load linux.bin:");
printf(strerror(rc));
} else {
memcpy((void*)DRAM_START,loadbuffer,rc);
return (void*)DRAM_START;
}
/* Everything failed - just loop forever */
printf("No RetailOS detected");
} else if (i==BUTTON_PLAY) {
printf("Loading Linux...");
rc=load_raw_firmware(loadbuffer, "/linux.bin", MAX_LOADSIZE);
if (rc < EOK) {
printf("Error!");
printf("Can't load linux.bin:");
printf(strerror(rc));
} else {
return (void*)DRAM_START;
}
} else {
printf("Loading Rockbox...");
rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
if (rc < EOK) {
printf("Error!");
printf("Can't load rockbox.ipod:");
printf(strerror(rc));
} else {
printf("Rockbox loaded.");
return (void*)DRAM_START;
}
}
/* If either the hold switch was on, or loading Rockbox/IPL
failed, then try the Apple firmware */
printf("Loading original firmware...");
/* First try an apple_os.ipod file on the FAT32 partition
(either in .rockbox or the root)
*/
rc=load_rockbox(loadbuffer, "apple_os.ipod");
/* Only report errors if the file was found */
if (rc < -1) {
printf("Error!");
printf("Can't load apple_os.ipod:");
printf(strerror(rc));
} else if (rc > 0) {
printf("apple_os.ipod loaded.");
memcpy((void*)DRAM_START,loadbuffer,rc);
return (void*)DRAM_START;
}
if (haveretailos) {
/* We have a copy of the retailos in RAM, lets just run it. */
return (void*)DRAM_START;
}
/* Everything failed - just loop forever */
printf("No RetailOS detected");
/* If we get to here, then we haven't been able to load any firmware */
fatal_error();
/* We never get here, but keep gcc happy */
return (void*)0;
}
/* These functions are present in the firmware library, but we reimplement
them here because the originals do a lot more than we want */
void reset_poweroff_timer(void)
{
}
int dbg_ports(void)
{
return 0;
}
void mpeg_stop(void)
{
}
void usb_acknowledge(void)
{
}
@ -555,7 +388,3 @@ void usb_acknowledge(void)
void usb_wait_for_disconnect(void)
{
}
void sys_poweroff(void)
{
}

View file

@ -19,156 +19,27 @@
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "common.h"
#include "cpu.h"
#include "system.h"
#include "lcd.h"
#include "kernel.h"
#include "thread.h"
#include "ata.h"
#include "fat.h"
#include "disk.h"
#include "font.h"
#include "adc.h"
#include "backlight.h"
#include "button.h"
#include "panic.h"
#include "power.h"
#include "file.h"
#include "system.h"
#include "kernel.h"
#include "lcd.h"
#include "font.h"
#include "ata.h"
#include "button.h"
#include "disk.h"
#include "power.h"
/* Size of the buffer to store the loaded firmware image */
/* Maximum allowed firmware image size. 10MB is more than enough */
#define MAX_LOADSIZE (10*1024*1024)
/* A buffer to load the iriver firmware or Rockbox into */
unsigned char loadbuffer[MAX_LOADSIZE];
/* A buffer to load the original firmware or Rockbox into */
unsigned char *loadbuffer = (unsigned char *)DRAM_START;
/* Bootloader version */
char version[] = APPSVERSION;
#define DRAM_START 0x10000000
int line=0;
char printfbuf[256];
void reset_screen(void)
{
lcd_clear_display();
line = 0;
}
void printf(const char *format, ...)
{
int len;
unsigned char *ptr;
va_list ap;
va_start(ap, format);
ptr = printfbuf;
len = vsnprintf(ptr, sizeof(printfbuf), format, ap);
va_end(ap);
lcd_puts(0, line++, ptr);
lcd_update();
if(line >= (LCD_HEIGHT/SYSFONT_HEIGHT))
line = 0;
}
/* Load original mi4 firmware. This function expects a file called
"/System/OF.bin" on the player. It should be a mi4 firmware decrypted
and header stripped using mi4code. It reads the file in to a memory
buffer called buf. The rest of the loading is done in main() and crt0.S
*/
int load_original_firmware(unsigned char* buf)
{
int fd;
int rc;
int len;
fd = open("/System/OF.bin", O_RDONLY);
len = filesize(fd);
if (len > MAX_LOADSIZE)
return -6;
rc = read(fd, buf, len);
if(rc < len)
return -4;
close(fd);
return len;
}
/* Load Rockbox firmware (rockbox.*) */
int load_rockbox(unsigned char* buf)
{
int fd;
int rc;
int len;
unsigned long chksum;
char model[5];
unsigned long sum;
int i;
fd = open("/.rockbox/" BOOTFILE, O_RDONLY);
if(fd < 0)
{
fd = open("/" BOOTFILE, O_RDONLY);
if(fd < 0)
return -1;
}
len = filesize(fd) - 8;
printf("Length: %x", len);
if (len > MAX_LOADSIZE)
return -6;
lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET);
rc = read(fd, &chksum, 4);
chksum=betoh32(chksum); /* Rockbox checksums are big-endian */
if(rc < 4)
return -2;
printf("Checksum: %x", chksum);
rc = read(fd, model, 4);
if(rc < 4)
return -3;
model[4] = 0;
printf("Model name: %s", model);
lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
rc = read(fd, buf, len);
if(rc < len)
return -4;
close(fd);
sum = MODEL_NUMBER;
for(i = 0;i < len;i++) {
sum += buf[i];
}
printf("Sum: %x", sum);
if(sum != chksum)
return -5;
return len;
}
void* main(void)
{
char buf[256];
@ -183,8 +54,6 @@ void* main(void)
font_init();
button_init();
line=0;
lcd_setfont(FONT_SYSFIXED);
printf("Rockbox boot loader");
@ -193,18 +62,20 @@ void* main(void)
i=ata_init();
if (i==0) {
identify_info=ata_get_identify();
/* Show model */
for (i=0; i < 20; i++) {
((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
}
buf[40]=0;
for (i=39; i && buf[i]==' '; i--) {
buf[i]=0;
}
printf(buf);
identify_info=ata_get_identify();
/* Show model */
for (i=0; i < 20; i++) {
((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
}
buf[40]=0;
for (i=39; i && buf[i]==' '; i--) {
buf[i]=0;
}
printf(buf);
} else {
printf("ATA: %d", i);
printf("ATA error: %d", i);
sleep(HZ*5);
power_off();
}
disk_init();
@ -212,6 +83,8 @@ void* main(void)
if (rc<=0)
{
printf("No partition found");
sleep(HZ*5);
power_off();
}
pinfo = disk_partinfo(0);
@ -220,39 +93,37 @@ void* main(void)
i=button_read_device();
if(i==BUTTON_LEFT)
{
/* Load original mi4 firmware. This expects a file called
"/System/OF.bin" on the player. It should be a mi4 firmware decrypted
and header stripped using mi4code. It reads the file in to a memory
buffer called loadbuffer. The rest of the loading is done in crt0.S
*/
printf("Loading original firmware...");
rc=load_original_firmware(loadbuffer);
rc=load_raw_firmware(loadbuffer, "/System/OF.bin", MAX_LOADSIZE);
if (rc < EOK) {
printf("Error!");
printf("Can't load /System/OF.bin:");
printf(strerror(rc));
sleep(HZ*5);
power_off();
}
} else {
printf("Loading Rockbox...");
rc=load_rockbox(loadbuffer);
}
if (rc < 0) {
printf("Rockbox error: %d",rc);
while(1) {}
rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
if (rc < EOK) {
printf("Error!");
printf("Can't load %s:", BOOTFILE);
printf(strerror(rc));
sleep(HZ*5);
power_off();
}
}
memcpy((void*)DRAM_START,loadbuffer,rc);
return (void*)DRAM_START;
return (void*)loadbuffer;
}
/* These functions are present in the firmware library, but we reimplement
them here because the originals do a lot more than we want */
void reset_poweroff_timer(void)
{
}
int dbg_ports(void)
{
return 0;
}
void mpeg_stop(void)
{
}
void usb_acknowledge(void)
{
}
@ -260,7 +131,3 @@ void usb_acknowledge(void)
void usb_wait_for_disconnect(void)
{
}
void sys_poweroff(void)
{
}

View file

@ -20,6 +20,10 @@
#define __PP5002_H__
/* All info gleaned and/or copied from the iPodLinux project. */
#define DRAM_START 0x28000000
#define IPOD_LCD_BASE 0xc0001000
#define CPU_CTL (*(volatile unsigned char *)(0xcf004054))
#define COP_CTL (*(volatile unsigned char *)(0xcf004058))

View file

@ -20,6 +20,8 @@
#define __PP5020_H__
/* All info gleaned and/or copied from the iPodLinux project. */
#define DRAM_START 0x10000000
#define CPU_CTL (*(volatile unsigned long *)(0x60007000))
#define COP_CTL (*(volatile unsigned long *)(0x60007004))