Move load_firmware() to separate file

The idea is to share loading code between bootloaders and rolo().

Change-Id: I1656ed91946d7a05cb7c9fa7a16793c3c862a5cd
Reviewed-on: http://gerrit.rockbox.org/190
Reviewed-by: Marcin Bukat <marcin.bukat@gmail.com>
This commit is contained in:
Marcin Bukat 2012-03-04 15:34:29 +01:00
parent 46ea8bfe7c
commit 0b29691324
29 changed files with 727 additions and 608 deletions

View file

@ -35,6 +35,14 @@
#include "string.h"
#include "usb.h"
#include "file.h"
#include "loader_strerror.h"
#if defined(MI4_FORMAT)
#include "mi4-loader.h"
#elif defined(RKW_FORMAT)
#include "rkw-loader.h"
#else
#include "rb-loader.h"
#endif
/* TODO: Other bootloaders need to be adjusted to set this variable to true
on a button press - currently only the ipod, H10, Vibe 500 and Sansa versions do. */
@ -94,31 +102,6 @@ int printf(const char *format, ...)
return len;
}
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";
case EINVALID_FORMAT:
return "Invalid file format";
default:
return "Unknown";
}
}
void error(int errortype, int error, bool shutdown)
{
switch(errortype)
@ -132,85 +115,17 @@ void error(int errortype, int error, bool shutdown)
break;
case EBOOTFILE:
printf(strerror(error));
printf(loader_strerror(error));
break;
}
lcd_update();
sleep(5*HZ);
if(shutdown)
power_off();
}
/* 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), BOOTDIR "/%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 EOK;
}
/* Load raw binary image. */
int load_raw_firmware(unsigned char* buf, char* firmware, int buffer_size)
{

View file

@ -21,16 +21,6 @@
#include <stdbool.h>
/* 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
#define EINVALID_FORMAT -7
/* Set this to true to enable lcd_update() in the printf function */
extern bool verbose;
@ -42,9 +32,7 @@ extern bool verbose;
/* Functions common to all bootloaders */
void reset_screen(void);
int printf(const char *format, ...);
char *strerror(int error);
void error(int errortype, int error, bool shutdown);
int load_firmware(unsigned char* buf, char* firmware, int buffer_size);
int load_raw_firmware(unsigned char* buf, char* firmware, int buffer_size);
#ifdef ROCKBOX_HAS_LOGF
void display_logf(void);

View file

@ -28,6 +28,8 @@
#include "backlight.h"
#include "button.h"
#include "common.h"
#include "loader_strerror.h"
#include "rb-loader.h"
#include "usb.h"
#include "version.h"
@ -104,15 +106,12 @@ void main(void)
buffer_size = (unsigned char*)0x01900000 - loadbuffer;
ret = load_firmware(loadbuffer, BOOTFILE, buffer_size);
if(ret < 0)
if(ret <= EFILE_EMPTY)
error(EBOOTFILE, ret, true);
else if(ret == EOK)
{
kernel_entry = (void*) loadbuffer;
ret = kernel_entry();
printf("FAILED!");
}
kernel_entry = (void*) loadbuffer;
ret = kernel_entry();
printf("FAILED!");
}
storage_sleepnow();

View file

@ -30,6 +30,8 @@
#include "dir.h"
#include "disk.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "power.h"
#include "backlight.h"
#include "usb.h"
@ -296,7 +298,7 @@ static void NORETURN_ATTR handle_firmware_load(void)
{
int rc = load_firmware(load_buf, BOOTFILE, load_buf_size);
if(rc < 0)
if(rc <= EFILE_EMPTY)
error(EBOOTFILE, rc, true);
/* Pause to look at messages */
@ -321,11 +323,8 @@ static void NORETURN_ATTR handle_firmware_load(void)
storage_close();
system_prepare_fw_start();
if (rc == EOK)
{
commit_discard_idcache();
asm volatile ("bx %0": : "r"(start_addr));
}
commit_discard_idcache();
asm volatile ("bx %0": : "r"(start_addr));
/* Halt */
while (1)

View file

@ -41,6 +41,8 @@
#include "power.h"
#include "file.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "rbunicode.h"
#include "usb.h"
#include "mmu-arm.h"
@ -201,18 +203,15 @@ void main(void)
buffer_size = (unsigned char*)0x31400000 - loadbuffer;
rc = load_firmware(loadbuffer, BOOTFILE, buffer_size);
if(rc < 0)
if(rc <= EFILE_EMPTY)
error(EBOOTFILE, rc, true);
storage_close();
system_prepare_fw_start();
if (rc == EOK)
{
commit_discard_idcache();
kernel_entry = (void*) loadbuffer;
rc = kernel_entry();
}
commit_discard_idcache();
kernel_entry = (void*) loadbuffer;
rc = kernel_entry();
#if 0
/* Halt */

View file

@ -43,6 +43,8 @@
#include "powermgmt.h"
#include "file.h"
#include "version.h"
#include "loader_strerror.h"
#include "rb-loader.h"
#include "pcf50606.h"
@ -129,7 +131,6 @@ int initial_gpio_read;
void main(void)
{
int i;
int rc;
bool rc_on_button = false;
bool on_button = false;
@ -194,35 +195,22 @@ void main(void)
rc = storage_init();
if(rc)
{
printf("ATA error: %d", rc);
sleep(HZ*5);
power_off();
}
error(EATA, rc, true);
disk_init();
rc = disk_mount_all();
if (rc<=0)
{
printf("No partition found");
sleep(HZ*5);
power_off();
}
error(EDISK, rc, true);
printf("Loading firmware");
i = load_firmware((unsigned char *)DRAM_START, BOOTFILE, MAX_LOADSIZE);
printf("Result: %s", strerror(i));
if (i < EOK) {
printf("Error!");
printf("Can't load " BOOTFILE ": ");
printf(strerror(rc));
sleep(HZ*3);
power_off();
} else {
start_firmware();
}
rc = load_firmware((unsigned char *)DRAM_START, BOOTFILE, MAX_LOADSIZE);
if (rc <= EFILE_EMPTY)
error(EBOOTFILE, rc, true);
start_firmware();
}
/* These functions are present in the firmware library, but we reimplement

View file

@ -31,6 +31,8 @@
#include "backlight.h"
#include "button-target.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "storage.h"
#include "disk.h"
#include "panic.h"
@ -180,7 +182,7 @@ void main(uint32_t arg, uint32_t addr)
loadbuffer = (unsigned char*)loadaddress;
buffer_size = (int)(loadaddressend - loadaddress);
while((ret = load_firmware(loadbuffer, BOOTFILE, buffer_size)) < 0)
while((ret = load_firmware(loadbuffer, BOOTFILE, buffer_size)) <= EFILE_EMPTY)
{
error(EBOOTFILE, ret, true);
}

View file

@ -42,6 +42,8 @@
#include "power.h"
#include "file.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "hwcompat.h"
#include "usb.h"
#include "version.h"
@ -376,7 +378,7 @@ void* main(void)
rc=load_firmware(loadbuffer, "apple_os.ipod", MAX_LOADSIZE);
if (rc == EOK) {
if (rc > 0) {
printf("apple_os.ipod loaded.");
return (void*)DRAM_START;
} else if (rc == EFILE_NOT_FOUND) {
@ -387,10 +389,10 @@ void* main(void)
/* We have a copy of the retailos in RAM, lets just run it. */
return (void*)DRAM_START;
}
} else if (rc < EFILE_NOT_FOUND) {
} else {
printf("Error!");
printf("Can't load apple_os.ipod:");
printf(strerror(rc));
printf(loader_strerror(rc));
}
/* Everything failed - just loop forever */
@ -399,17 +401,17 @@ void* main(void)
} else if (btn==BUTTON_PLAY) {
printf("Loading Linux...");
rc=load_raw_firmware(loadbuffer, "/linux.bin", MAX_LOADSIZE);
if (rc < EOK) {
if (rc <= EFILE_EMPTY) {
printf("Error!");
printf("Can't load linux.bin:");
printf(strerror(rc));
printf(loader_strerror(rc));
} else {
return (void*)DRAM_START;
}
} else {
printf("Loading Rockbox...");
rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
if (rc == EOK) {
if (rc > 0) {
printf("Rockbox loaded.");
return (void*)DRAM_START;
} else if (rc == EFILE_NOT_FOUND) {
@ -424,7 +426,7 @@ void* main(void)
printf("Error!");
printf("Can't load " BOOTFILE ": ");
printf(strerror(rc));
printf(loader_strerror(rc));
}
/* If we get to here, then we haven't been able to load any firmware */

View file

@ -44,6 +44,8 @@
#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.
@ -238,10 +240,10 @@ void main(void)
printf("Loading Rockbox...");
rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
if (rc != EOK) {
if (rc <= EFILE_EMPTY) {
printf("Error!");
printf("Can't load " BOOTFILE ": ");
printf(strerror(rc));
printf(loader_strerror(rc));
fatal_error();
}

View file

@ -46,6 +46,8 @@
#include "eeprom_settings.h"
#include "rbunicode.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "version.h"
#include <stdarg.h>
@ -608,9 +610,9 @@ void main(void)
printf("Loading firmware");
i = load_firmware((unsigned char *)DRAM_START, BOOTFILE, MAX_LOADSIZE);
if(i < 0)
printf("Error: %s", strerror(i));
printf("Error: %s", loader_strerror(i));
if (i == EOK)
if (i > 0)
start_firmware();
if (!detect_original_firmware())

View file

@ -45,6 +45,8 @@
#include "file.h"
#include "pcf50606.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "rbunicode.h"
#include "isp1362.h"
#include "version.h"
@ -361,10 +363,10 @@ void main(void)
printf("Loading firmware");
i = load_firmware((unsigned char *)DRAM_START, BOOTFILE, MAX_LOADSIZE);
if(i < 0)
printf("Error: %s", strerror(i));
if(i <= EFILE_EMPTY)
printf("Error: %s", loader_strerror(i));
if (i == EOK)
if (i > 0)
start_firmware();
if (!detect_original_firmware())

View file

@ -37,6 +37,8 @@
#include "button.h"
#include "disk.h"
#include "crc32-mi4.h"
#include "mi4-loader.h"
#include "loader_strerror.h"
#include <string.h>
#include "power.h"
#include "version.h"
@ -110,21 +112,6 @@ unsigned char *loadbuffer = (unsigned char *)DRAM_START;
#define MI4_HEADER_SIZE 0x200
/* mi4 header structure */
struct mi4header_t {
unsigned char magic[4];
uint32_t version;
uint32_t length;
uint32_t crc32;
uint32_t enctype;
uint32_t mi4size;
uint32_t plaintext;
uint32_t dsa_key[10];
uint32_t pad[109];
unsigned char type[4];
unsigned char model[4];
};
/* PPMI header structure */
struct ppmi_header_t {
unsigned char magic[4];
@ -132,236 +119,6 @@ struct ppmi_header_t {
uint32_t pad[126];
};
inline unsigned int le2int(unsigned char* buf)
{
int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
return res;
}
inline void int2le(unsigned int val, unsigned char* addr)
{
addr[0] = val & 0xFF;
addr[1] = (val >> 8) & 0xff;
addr[2] = (val >> 16) & 0xff;
addr[3] = (val >> 24) & 0xff;
}
struct tea_key {
const char * name;
uint32_t key[4];
};
#define NUM_KEYS (sizeof(tea_keytable)/sizeof(tea_keytable[0]))
struct tea_key tea_keytable[] = {
{ "default" , { 0x20d36cc0, 0x10e8c07d, 0xc0e7dcaa, 0x107eb080 } },
{ "sansa", { 0xe494e96e, 0x3ee32966, 0x6f48512b, 0xa93fbb42 } },
{ "sansa_gh", { 0xd7b10538, 0xc662945b, 0x1b3fce68, 0xf389c0e6 } },
{ "sansa_103", { 0x1d29ddc0, 0x2579c2cd, 0xce339e1a, 0x75465dfe } },
{ "rhapsody", { 0x7aa9c8dc, 0xbed0a82a, 0x16204cc7, 0x5904ef38 } },
{ "p610", { 0x950e83dc, 0xec4907f9, 0x023734b9, 0x10cfb7c7 } },
{ "p640", { 0x220c5f23, 0xd04df68e, 0x431b5e25, 0x4dcc1fa1 } },
{ "virgin", { 0xe83c29a1, 0x04862973, 0xa9b3f0d4, 0x38be2a9c } },
{ "20gc_eng", { 0x0240772c, 0x6f3329b5, 0x3ec9a6c5, 0xb0c9e493 } },
{ "20gc_fre", { 0xbede8817, 0xb23bfe4f, 0x80aa682d, 0xd13f598c } },
{ "elio_p722", { 0x6af3b9f8, 0x777483f5, 0xae8181cc, 0xfa6d8a84 } },
{ "c200", { 0xbf2d06fa, 0xf0e23d59, 0x29738132, 0xe2d04ca7 } },
{ "c200_103", { 0x2a7968de, 0x15127979, 0x142e60a7, 0xe49c1893 } },
{ "c200_106", { 0xa913d139, 0xf842f398, 0x3e03f1a6, 0x060ee012 } },
{ "view", { 0x70e19bda, 0x0c69ea7d, 0x2b8b1ad1, 0xe9767ced } },
{ "sa9200", { 0x33ea0236, 0x9247bdc5, 0xdfaedf9f, 0xd67c9d30 } },
{ "hdd1630/hdd63x0", { 0x04543ced, 0xcebfdbad, 0xf7477872, 0x0d12342e } },
{ "vibe500", { 0xe3a66156, 0x77c6b67a, 0xe821dca5, 0xca8ca37c } },
};
/*
tea_decrypt() from http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
"Following is an adaptation of the reference encryption and decryption
routines in C, released into the public domain by David Wheeler and
Roger Needham:"
*/
/* NOTE: The mi4 version of TEA uses a different initial value to sum compared
to the reference implementation and the main loop is 8 iterations, not
32.
*/
static void tea_decrypt(uint32_t* v0, uint32_t* v1, uint32_t* k) {
uint32_t sum=0xF1BBCDC8, i; /* set up */
uint32_t delta=0x9E3779B9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for(i=0; i<8; i++) { /* basic cycle start */
*v1 -= ((*v0<<4) + k2) ^ (*v0 + sum) ^ ((*v0>>5) + k3);
*v0 -= ((*v1<<4) + k0) ^ (*v1 + sum) ^ ((*v1>>5) + k1);
sum -= delta; /* end cycle */
}
}
/* mi4 files are encrypted in 64-bit blocks (two little-endian 32-bit
integers) and the key is incremented after each block
*/
static void tea_decrypt_buf(unsigned char* src, unsigned char* dest, size_t n, uint32_t * key)
{
uint32_t v0, v1;
unsigned int i;
for (i = 0; i < (n / 8); i++) {
v0 = le2int(src);
v1 = le2int(src+4);
tea_decrypt(&v0, &v1, key);
int2le(v0, dest);
int2le(v1, dest+4);
src += 8;
dest += 8;
/* Now increment the key */
key[0]++;
if (key[0]==0) {
key[1]++;
if (key[1]==0) {
key[2]++;
if (key[2]==0) {
key[3]++;
}
}
}
}
}
static int tea_find_key(struct mi4header_t *mi4header, unsigned char* buf)
{
unsigned int i;
uint32_t key[4];
uint32_t keyinc;
unsigned char magic_dec[8];
int key_found = -1;
unsigned int magic_location = mi4header->length-4;
int unaligned = 0;
if ( (magic_location % 8) != 0 )
{
unaligned = 1;
magic_location -= 4;
}
printf("Searching for key:");
for (i=0; i < NUM_KEYS && (key_found<0) ; i++) {
key[0] = tea_keytable[i].key[0];
key[1] = tea_keytable[i].key[1];
key[2] = tea_keytable[i].key[2];
key[3] = tea_keytable[i].key[3];
/* Now increment the key */
keyinc = (magic_location-mi4header->plaintext)/8;
if ((key[0]+keyinc) < key[0]) key[1]++;
key[0] += keyinc;
if (key[1]==0) key[2]++;
if (key[2]==0) key[3]++;
/* Decrypt putative magic */
tea_decrypt_buf(&buf[magic_location], magic_dec, 8, key);
if (le2int(&magic_dec[4*unaligned]) == 0xaa55aa55)
{
key_found = i;
printf("%s...found", tea_keytable[i].name);
} else {
/* printf("%s...failed", tea_keytable[i].name); */
}
}
return key_found;
}
/* Load mi4 format firmware image */
int load_mi4(unsigned char* buf, char* firmware, unsigned int buffer_size)
{
int fd;
struct mi4header_t mi4header;
int rc;
unsigned long sum;
char filename[MAX_PATH];
snprintf(filename,sizeof(filename), BOOTDIR "/%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;
}
read(fd, &mi4header, MI4_HEADER_SIZE);
/* MI4 file size */
printf("mi4 size: %x", mi4header.mi4size);
if ((mi4header.mi4size-MI4_HEADER_SIZE) > buffer_size)
{
close(fd);
return EFILE_TOO_BIG;
}
/* CRC32 */
printf("CRC32: %x", mi4header.crc32);
/* Rockbox model id */
printf("Model id: %.4s", mi4header.model);
/* Read binary type (RBOS, RBBL) */
printf("Binary type: %.4s", mi4header.type);
/* Load firmware file */
lseek(fd, MI4_HEADER_SIZE, SEEK_SET);
rc = read(fd, buf, mi4header.mi4size-MI4_HEADER_SIZE);
close(fd);
if(rc < (int)mi4header.mi4size-MI4_HEADER_SIZE)
return EREAD_IMAGE_FAILED;
/* Check CRC32 to see if we have a valid file */
sum = chksum_crc32 (buf, mi4header.mi4size - MI4_HEADER_SIZE);
printf("Calculated CRC32: %x", sum);
if(sum != mi4header.crc32)
return EBAD_CHKSUM;
if( (mi4header.plaintext + MI4_HEADER_SIZE) != mi4header.mi4size)
{
/* Load encrypted firmware */
int key_index = tea_find_key(&mi4header, buf);
if (key_index < 0)
return EINVALID_FORMAT;
/* Plaintext part is already loaded */
buf += mi4header.plaintext;
/* Decrypt in-place */
tea_decrypt_buf(buf, buf,
mi4header.mi4size-(mi4header.plaintext+MI4_HEADER_SIZE),
tea_keytable[key_index].key);
printf("%s key used", tea_keytable[key_index].name);
/* Check decryption was successfull */
if(le2int(&buf[mi4header.length-mi4header.plaintext-4]) != 0xaa55aa55)
return EREAD_IMAGE_FAILED;
}
return EOK;
}
#if (CONFIG_STORAGE & STORAGE_SD)
/* Load mi4 firmware from a hidden disk partition */
int load_mi4_part(unsigned char* buf, struct partinfo* pinfo,
@ -432,7 +189,7 @@ int load_mi4_part(unsigned char* buf, struct partinfo* pinfo,
(void) disable_rebuild;
#endif
return EOK;
return mi4header.mi4size-MI4_HEADER_SIZE;
}
#endif /* (CONFIG_STORAGE & STORAGE_SD) */
@ -528,6 +285,7 @@ static int handle_usb(int connect_timeout)
void* main(void)
{
char filename[MAX_PATH];
int i;
int btn;
int rc;
@ -642,13 +400,15 @@ void* main(void)
if((btn & BOOTLOADER_BOOT_OF) == 0)
{
printf("Loading Rockbox...");
rc = load_mi4(loadbuffer, BOOTFILE, MAX_LOADSIZE);
if (rc < EOK)
snprintf(filename,sizeof(filename), BOOTDIR "/%s", BOOTFILE);
rc = load_mi4(loadbuffer, filename, MAX_LOADSIZE);
if (rc <= EFILE_EMPTY)
{
bool old_verbose = verbose;
verbose = true;
printf("Can't load " BOOTFILE ": ");
printf(strerror(rc));
printf(loader_strerror(rc));
verbose = old_verbose;
btn |= BOOTLOADER_BOOT_OF;
sleep(5*HZ);
@ -676,9 +436,9 @@ void* main(void)
{
rc = load_mi4_part(loadbuffer, pinfo, MAX_LOADSIZE,
usb == USB_INSERTED);
if (rc < EOK) {
if (rc <= EFILE_EMPTY) {
printf("Can't load from partition");
printf(strerror(rc));
printf(loader_strerror(rc));
} else {
goto main_exit;
}
@ -690,9 +450,9 @@ void* main(void)
#if defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) || defined(PHILIPS_SA9200)
printf("Trying /System/OF.ebn");
rc=load_mi4(loadbuffer, "/System/OF.ebn", MAX_LOADSIZE);
if (rc < EOK) {
if (rc <= EFILE_EMPTY) {
printf("Can't load /System/OF.ebn");
printf(strerror(rc));
printf(loader_strerror(rc));
} else {
goto main_exit;
}
@ -700,9 +460,9 @@ void* main(void)
printf("Trying /System/OF.mi4");
rc=load_mi4(loadbuffer, "/System/OF.mi4", MAX_LOADSIZE);
if (rc < EOK) {
if (rc <= EFILE_EMPTY) {
printf("Can't load /System/OF.mi4");
printf(strerror(rc));
printf(loader_strerror(rc));
} else {
#if defined(SAMSUNG_YH925)
lcd_reset();
@ -712,9 +472,9 @@ void* main(void)
printf("Trying /System/OF.bin");
rc=load_raw_firmware(loadbuffer, "/System/OF.bin", MAX_LOADSIZE);
if (rc < EOK) {
if (rc <= EFILE_EMPTY) {
printf("Can't load /System/OF.bin");
printf(strerror(rc));
printf(loader_strerror(rc));
} else {
#if defined(SAMSUNG_YH925)
lcd_reset();

View file

@ -39,6 +39,8 @@
#include "power.h"
#include "file.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "sd.h"
#include "backlight-target.h"
#include "lcd-target.h"
@ -97,26 +99,23 @@ int main(void)
printf("Loading firmware");
/* Flush out anything pending first */
cpucache_invalidate();
commit_discard_idcache();
loadbuffer = (unsigned char*) 0x31000000;
buffer_size = (unsigned char*)0x31400000 - loadbuffer;
rc = load_firmware(loadbuffer, BOOTFILE, buffer_size);
if(rc < 0)
if(rc <= 0)
error(EBOOTFILE, rc, true);
printf("Loaded firmware %d\n", rc);
/* storage_close(); */
system_prepare_fw_start();
if (rc == EOK)
{
cpucache_invalidate();
kernel_entry = (void*) loadbuffer;
rc = kernel_entry();
}
commit_discard_idcache();
kernel_entry = (void*) loadbuffer;
rc = kernel_entry();
/* end stop - should not get here */
led_flash(LED_ALL, LED_NONE);

View file

@ -43,6 +43,8 @@
#include "file.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "version.h"
#include <stdarg.h>
@ -199,35 +201,21 @@ static void rb_boot(void)
rc = storage_init();
if(rc)
{
printf("ATA error: %d", rc);
sleep(HZ*5);
return;
}
error(EATA, rc, true);
disk_init();
rc = disk_mount_all();
if (rc<=0)
{
printf("No partition found");
sleep(HZ*5);
return;
}
if (rc <= 0)
error(EDISK, rc, true);
printf("Loading firmware");
rc = load_firmware((unsigned char *)DRAM_START,
BOOTFILE, MAX_LOADSIZE);
if (rc < EOK)
{
printf("Error!");
printf("Can't load " BOOTFILE ": ");
printf("Result: %s", strerror(rc));
sleep(HZ*5);
return;
}
if (rc <= EFILE_EMPTY)
error(EBOOTFILE, rc, true);
cpu_boost(false);
start_rockbox();

View file

@ -38,6 +38,8 @@
#include "power.h"
#include "file.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "rbunicode.h"
#include "usb.h"
#include "spi.h"
@ -138,12 +140,12 @@ void main(void)
buffer_size = (unsigned char*)0x01900000 - loadbuffer;
rc = load_firmware(loadbuffer, BOOTFILE, buffer_size);
if(rc < 0)
if(rc <= EFILE_EMPTY)
error(EBOOTFILE, rc, true);
if (rc == EOK)
{
kernel_entry = (void*) loadbuffer;
rc = kernel_entry();
}
kernel_entry = (void*) loadbuffer;
rc = kernel_entry();
/* Should not get here! */
return rc;
}

View file

@ -29,6 +29,8 @@
#include "system.h"
#include "button.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "storage.h"
#include "disk.h"
#include "string.h"
@ -148,7 +150,7 @@ static int boot_rockbox(void)
printf("Loading firmware...");
rc = load_firmware((unsigned char *)CONFIG_SDRAM_START, BOOTFILE, 0x400000);
if(rc < 0)
if(rc <= EFILE_EMPTY)
return rc;
else
{
@ -303,8 +305,8 @@ int main(void)
#endif
rc = boot_rockbox();
if(rc < 0)
printf("Error: %s", strerror(rc));
if(rc <= EFILE_EMPTY)
printf("Error: %s", loader_strerror(rc));
/* Halt */
while (1)

View file

@ -20,6 +20,7 @@
#include "rkw-loader.h"
#include "version.h"
#include "i2c-rk27xx.h"
#include "loader_strerror.h"
/* beginning of DRAM */
#define DRAM_ORIG 0x60000000
@ -161,11 +162,10 @@ void main(void)
printf("Loading: %s", filename);
ret = load_rkw(loadbuffer, filename, LOAD_SIZE);
if (ret < 0)
if (ret <= EFILE_EMPTY)
{
printf(rkw_strerror(ret));
lcd_update();
sleep(5*HZ);
error(EBOOTFILE, ret, false);
/* if we boot rockbox we shutdown on error
* if we boot OF we fall back to rkusb mode on error
@ -186,7 +186,7 @@ void main(void)
else
{
/* print 'Loading OK' */
printf(rkw_strerror(0));
printf("Loading OK");
sleep(HZ);
}

View file

@ -35,6 +35,8 @@
#include "backlight.h"
#include "button-target.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "storage.h"
#include "disk.h"
#include "panic.h"
@ -147,7 +149,7 @@ void main(void)
loadbuffer = (unsigned char*)DRAM_ORIG; /* DRAM */
buffer_size = (int)(loadbuffer + (DRAM_SIZE) - TTB_SIZE);
while((ret = load_firmware(loadbuffer, BOOTFILE, buffer_size)) < 0)
while((ret = load_firmware(loadbuffer, BOOTFILE, buffer_size)) <= EFILE_EMPTY)
{
#ifdef USE_ROCKBOX_USB
error(EBOOTFILE, ret, false);

View file

@ -27,6 +27,7 @@
#include "backlight.h"
#include "button.h"
#include "common.h"
#include "rb-loader.h"
#include "version.h"
#include "uart-target.h"
#include "power.h"
@ -115,11 +116,11 @@ void main(void)
ret = load_firmware(loadbuffer, BOOTFILE, buffer_size);
if(ret < 0)
if(ret <= EFILE_EMPTY)
{
error(EBOOTFILE, ret, true);
}
else if(ret == EOK)
else
{
system_prepare_fw_start();

View file

@ -43,6 +43,8 @@
#include "power.h"
#include "file.h"
#include "common.h"
#include "rb-loader.h"
#include "loader_strerror.h"
#include "version.h"
/* Show the Rockbox logo - in show_logo.c */
@ -170,11 +172,11 @@ void* main(void)
rc = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE);
if (rc < 0)
if (rc <= EFILE_EMPTY)
{
error(EBOOTFILE,rc, true);
}
else if (rc == EOK)
else
{
int(*kernel_entry)(void) = (void *) loadbuffer;

View file

@ -35,6 +35,9 @@ load_code.c
#ifdef RB_PROFILE
profile.c
#endif /* RB_PROFILE */
#if !defined(RKW_FORMAT) && !defined(MI4_FORMAT) && defined(MODEL_NUMBER)
common/rb-loader.c
#endif
#if !defined(BOOTLOADER) || defined(CPU_SH)
rolo.c
#endif /* !defined(BOOTLOADER) || defined(CPU_SH) */
@ -139,6 +142,9 @@ libc/gmtime.c
common/version.c
common/config.c
common/crc32.c
#ifdef MODEL_NUMBER
common/loader_strerror.c
#endif
#ifdef MI4_FORMAT
common/crc32-mi4.c
#endif
@ -594,6 +600,7 @@ target/arm/as3525/pcm-as3525.c
target/arm/pp/i2s-pp.c
target/arm/pp/kernel-pp.c
target/arm/pp/timer-pp.c
target/arm/pp/mi4-loader.c
# if CONFIG_STORAGE & STORAGE_SD
target/arm/pp/ata-sd-pp.c
# endif

View file

@ -0,0 +1,63 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2013 Marcin Bukat
*
* 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 "loader_strerror.h"
char *loader_strerror(enum error_t error)
{
switch(error)
{
case EFILE_EMPTY:
return "File empty";
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";
case EINVALID_FORMAT:
return "Invalid file format";
#if defined(MI4_FORMAT)
case EREAD_HEADER_FAILED:
return "Can't read mi4 header";
case EKEY_NOT_FOUND:
return "Can't find crypt key";
case EDECRYPT_FAILED:
return "Decryption failed";
#elif defined(RKW_FORMAT)
case EREAD_HEADER_FAILED:
return "Can't read RKW header";
case EBAD_HEADER_CHKSUM:
return "RKW header CRC error";
case EINVALID_LOAD_ADDR:
return "RKW Load address mismatch";
case EBAD_MODEL:
return "Bad model number";
#endif
default:
return "Unknown error";
}
}

115
firmware/common/rb-loader.c Normal file
View file

@ -0,0 +1,115 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2005 by Linus Nielsen Feltzing
*
* 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 1
* 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 <stdio.h>
#include "config.h"
#include "system.h"
#include "file.h"
#include "rb-loader.h"
#include "loader_strerror.h"
/* Load firmware image in a format created by add method of tools/scramble
* on success we return size loaded image
* on error we return negative value which can be deciphered by means
* of strerror() function
*/
int load_firmware(unsigned char* buf, const char* firmware, int buffer_size)
{
char filename[MAX_PATH];
int fd;
int rc;
int len;
int ret = 0;
unsigned long chksum;
unsigned long sum;
int i;
/* only filename passed */
if (firmware[0] != '/')
{
/* First check in BOOTDIR */
snprintf(filename, sizeof(filename), BOOTDIR "/%s",firmware);
fd = open(filename, O_RDONLY);
if(fd < 0)
{
/* Check in root dir */
snprintf(filename, sizeof(filename),"/%s",firmware);
fd = open(filename, O_RDONLY);
if (fd < 0)
return EFILE_NOT_FOUND;
}
}
else
{
/* full path passed */
fd = open(firmware, O_RDONLY);
if (fd < 0)
return EFILE_NOT_FOUND;
}
len = filesize(fd) - 8;
if (len > buffer_size)
{
ret = EFILE_TOO_BIG;
goto end;
}
lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET);
rc = read(fd, &chksum, 4);
chksum = betoh32(chksum); /* Rockbox checksums are big-endian */
if(rc < 4)
{
ret = EREAD_CHKSUM_FAILED;
goto end;
}
lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
rc = read(fd, buf, len);
if(rc < len)
{
ret = EREAD_IMAGE_FAILED;
goto end;
}
sum = MODEL_NUMBER;
for(i = 0;i < len;i++)
{
sum += buf[i];
}
if(sum != chksum)
{
ret = EBAD_CHKSUM;
goto end;
}
ret = len;
end:
close(fd);
return ret;
}

View file

@ -0,0 +1,51 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2006 by Barry Wardell
*
* Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
* and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
*
* 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 <stdint.h>
#define MI4_HEADER_SIZE 0x200
/* mi4 header structure */
struct mi4header_t {
unsigned char magic[4];
uint32_t version;
uint32_t length;
uint32_t crc32;
uint32_t enctype;
uint32_t mi4size;
uint32_t plaintext;
uint32_t dsa_key[10];
uint32_t pad[109];
unsigned char type[4];
unsigned char model[4];
};
struct tea_key {
const char * name;
uint32_t key[4];
};
#define NUM_KEYS (sizeof(tea_keytable)/sizeof(tea_keytable[0]))
int load_mi4(unsigned char* buf, const char* firmware, unsigned int buffer_size);
const char *mi4_strerror(int8_t errno);

View file

@ -0,0 +1,38 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2013 Marcin Bukat
*
* 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.
*
****************************************************************************/
enum error_t {
EFILE_EMPTY = 0,
EFILE_NOT_FOUND = -1,
EREAD_CHKSUM_FAILED = -2,
EREAD_MODEL_FAILED = -3,
EREAD_IMAGE_FAILED = -4,
EBAD_CHKSUM = -5,
EFILE_TOO_BIG = -6,
EINVALID_FORMAT = -7,
EKEY_NOT_FOUND = -8,
EDECRYPT_FAILED = -9,
EREAD_HEADER_FAILED = -10,
EBAD_HEADER_CHKSUM = -11,
EINVALID_LOAD_ADDR = -12,
EBAD_MODEL = -13
};
char *loader_strerror(enum error_t error);

View file

@ -0,0 +1,22 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2005 by Linus Nielsen Feltzing
*
* 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 1
* 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.
*
****************************************************************************/
const char *rb_strerror(int8_t errno);
int load_firmware(unsigned char* buf, const char* firmware, int buffer_size);

View file

@ -37,16 +37,17 @@
#include "storage.h"
#include "rolo.h"
#ifdef MI4_FORMAT
#include "loader_strerror.h"
#if defined(MI4_FORMAT)
#include "crc32-mi4.h"
#undef FIRMWARE_OFFSET_FILE_CRC
#undef FIRMWARE_OFFSET_FILE_DATA
#define FIRMWARE_OFFSET_FILE_CRC 0xC
#define FIRMWARE_OFFSET_FILE_DATA 0x200
#endif
#ifdef RKW_FORMAT
#include "mi4-loader.h"
#define LOAD_FIRMWARE(a,b,c) load_mi4(a,b,c)
#elif defined(RKW_FORMAT)
#include "rkw-loader.h"
#define LOAD_FIRMWARE(a,b,c) load_rkw(a,b,c)
#else
#include "rb-loader.h"
#define LOAD_FIRMWARE(a,b,c) load_firmware(a,b,c)
#endif
#if !defined(IRIVER_IFP7XX_SERIES)
@ -206,7 +207,7 @@ extern unsigned long loadaddress;
* Filename must be a fully defined filename including the path and extension
*
***************************************************************************/
#ifdef RKW_FORMAT
#if defined(CPU_COLDFIRE) || defined(CPU_ARM) || defined(CPU_MIPS)
int rolo_load(const char* filename)
{
unsigned char* ramstart = (void*)&loadaddress;
@ -232,15 +233,26 @@ int rolo_load(const char* filename)
rolo_handle = core_alloc_maximum("rolo", &filebuf_size, NULL);
filebuf = core_get_data(rolo_handle);
errno = load_rkw(filebuf, filename, filebuf_size);
if (errno < 0)
errno = LOAD_FIRMWARE(filebuf, filename, filebuf_size);
if (errno <= 0)
{
rolo_error(rkw_strerror(errno));
rolo_error(loader_strerror(errno));
return -1;
}
else
length = errno;
#if defined(CPU_PP) && NUM_CORES > 1
lcd_puts(0, 2, "Waiting for coprocessor...");
lcd_update();
rolo_restart_cop();
/* Wait for COP to be in safe code */
while(cpu_reply != 1);
lcd_puts(0, 2, " ");
lcd_update();
#endif
#ifdef HAVE_STORAGE_FLUSH
lcd_puts(0, 1, "Flushing storage buffers");
lcd_update();
@ -255,27 +267,29 @@ int rolo_load(const char* filename)
#endif
adc_close();
#if CONFIG_CPU != IMX31L /* We're not finished yet */
#ifdef CPU_ARM
/* Should do these together since some ARM version should never have
* FIQ disabled and not IRQ (imx31 errata). */
disable_interrupt(IRQ_FIQ_STATUS);
#else
/* Some targets have a higher disable level than HIGEST_IRQ_LEVEL */
set_irq_level(DISABLE_INTERRUPTS);
#endif
#endif /* CONFIG_CPU == IMX31L */
rolo_restart(filebuf, ramstart, length);
/* never reached */
return 0;
}
#else
#else /* defined(CPU_SH) */
int rolo_load(const char* filename)
{
int fd;
long length;
#if defined(CPU_COLDFIRE) || defined(CPU_ARM) || defined(CPU_MIPS)
#if !defined(MI4_FORMAT)
int i;
#endif
unsigned long checksum,file_checksum;
#else
long file_length;
unsigned short checksum,file_checksum;
#endif
unsigned char* ramstart = (void*)&loadaddress;
unsigned char* filebuf;
size_t filebuf_size;
@ -306,87 +320,6 @@ int rolo_load(const char* filename)
rolo_handle = core_alloc_maximum("rolo", &filebuf_size, NULL);
filebuf = core_get_data(rolo_handle);
#if CONFIG_CPU != SH7034
/* Read and save checksum */
lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET);
if (read(fd, &file_checksum, 4) != 4) {
rolo_error("Error Reading checksum");
return -1;
}
#if !defined(MI4_FORMAT)
/* Rockbox checksums are big-endian */
file_checksum = betoh32(file_checksum);
#endif
#if defined(CPU_PP) && NUM_CORES > 1
lcd_puts(0, 2, "Waiting for coprocessor...");
lcd_update();
rolo_restart_cop();
/* Wait for COP to be in safe code */
while(cpu_reply != 1);
lcd_puts(0, 2, " ");
lcd_update();
#endif
lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
/* this shouldn't happen, but well */
if ((long)filebuf_size < length)
{
rolo_error("File too big");
return -1;
}
if (read(fd, filebuf, length) != length) {
rolo_error("Error Reading File");
return -1;
}
#ifdef MI4_FORMAT
/* Check CRC32 to see if we have a valid file */
chksum_crc32gentab();
checksum = chksum_crc32 (filebuf, length);
#else
checksum = MODEL_NUMBER;
for(i = 0;i < length;i++) {
checksum += filebuf[i];
}
#endif
/* Verify checksum against file header */
if (checksum != file_checksum) {
rolo_error("Checksum Error");
return -1;
}
#ifdef HAVE_STORAGE_FLUSH
lcd_puts(0, 1, "Flushing storage buffers");
lcd_update();
storage_flush();
#endif
lcd_puts(0, 1, "Executing");
lcd_update();
#ifdef HAVE_REMOTE_LCD
lcd_remote_puts(0, 1, "Executing");
lcd_remote_update();
#endif
adc_close();
#if CONFIG_CPU != IMX31L /* We're not finished yet */
#ifdef CPU_ARM
/* Should do these together since some ARM version should never have
* FIQ disabled and not IRQ (imx31 errata). */
disable_interrupt(IRQ_FIQ_STATUS);
#else
/* Some targets have a higher disable level than HIGEST_IRQ_LEVEL */
set_irq_level(DISABLE_INTERRUPTS);
#endif
#endif /* CONFIG_CPU == IMX31L */
#else /* CONFIG_CPU == SH7034 */
/* Read file length from header and compare to real file length */
lseek(fd, FIRMWARE_OFFSET_FILE_LENGTH, SEEK_SET);
if(read(fd, &file_length, 4) != 4) {
@ -450,14 +383,13 @@ int rolo_load(const char* filename)
#if defined(ARCHOS_RECORDER) || defined(ARCHOS_RECORDERV2) || \
defined(ARCHOS_FMRECORDER)
PAIOR = 0x0FA0;
#endif
#endif
rolo_restart(filebuf, ramstart, length);
return 0; /* this is never reached */
(void)checksum; (void)file_checksum;
}
#endif /* ifdef RKW_FORMAT */
#endif /* */
#else /* !defined(IRIVER_IFP7XX_SERIES) */
int rolo_load(const char* filename)
{

View file

@ -0,0 +1,237 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2006 by Barry Wardell
*
* Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
* and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
*
* 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 <stdbool.h>
#include <stdio.h>
#include "config.h"
#include "mi4-loader.h"
#include "loader_strerror.h"
#include "crc32-mi4.h"
#include "file.h"
static inline unsigned int le2int(unsigned char* buf)
{
int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
return res;
}
static inline void int2le(unsigned int val, unsigned char* addr)
{
addr[0] = val & 0xFF;
addr[1] = (val >> 8) & 0xff;
addr[2] = (val >> 16) & 0xff;
addr[3] = (val >> 24) & 0xff;
}
static struct tea_key tea_keytable[] = {
{ "default" , { 0x20d36cc0, 0x10e8c07d, 0xc0e7dcaa, 0x107eb080 } },
{ "sansa", { 0xe494e96e, 0x3ee32966, 0x6f48512b, 0xa93fbb42 } },
{ "sansa_gh", { 0xd7b10538, 0xc662945b, 0x1b3fce68, 0xf389c0e6 } },
{ "sansa_103", { 0x1d29ddc0, 0x2579c2cd, 0xce339e1a, 0x75465dfe } },
{ "rhapsody", { 0x7aa9c8dc, 0xbed0a82a, 0x16204cc7, 0x5904ef38 } },
{ "p610", { 0x950e83dc, 0xec4907f9, 0x023734b9, 0x10cfb7c7 } },
{ "p640", { 0x220c5f23, 0xd04df68e, 0x431b5e25, 0x4dcc1fa1 } },
{ "virgin", { 0xe83c29a1, 0x04862973, 0xa9b3f0d4, 0x38be2a9c } },
{ "20gc_eng", { 0x0240772c, 0x6f3329b5, 0x3ec9a6c5, 0xb0c9e493 } },
{ "20gc_fre", { 0xbede8817, 0xb23bfe4f, 0x80aa682d, 0xd13f598c } },
{ "elio_p722", { 0x6af3b9f8, 0x777483f5, 0xae8181cc, 0xfa6d8a84 } },
{ "c200", { 0xbf2d06fa, 0xf0e23d59, 0x29738132, 0xe2d04ca7 } },
{ "c200_103", { 0x2a7968de, 0x15127979, 0x142e60a7, 0xe49c1893 } },
{ "c200_106", { 0xa913d139, 0xf842f398, 0x3e03f1a6, 0x060ee012 } },
{ "view", { 0x70e19bda, 0x0c69ea7d, 0x2b8b1ad1, 0xe9767ced } },
{ "sa9200", { 0x33ea0236, 0x9247bdc5, 0xdfaedf9f, 0xd67c9d30 } },
{ "hdd1630/hdd63x0", { 0x04543ced, 0xcebfdbad, 0xf7477872, 0x0d12342e } },
{ "vibe500", { 0xe3a66156, 0x77c6b67a, 0xe821dca5, 0xca8ca37c } },
};
/*
tea_decrypt() from http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
"Following is an adaptation of the reference encryption and decryption
routines in C, released into the public domain by David Wheeler and
Roger Needham:"
*/
/* NOTE: The mi4 version of TEA uses a different initial value to sum compared
to the reference implementation and the main loop is 8 iterations, not
32.
*/
static void tea_decrypt(uint32_t* v0, uint32_t* v1, uint32_t* k) {
uint32_t sum=0xF1BBCDC8, i; /* set up */
uint32_t delta=0x9E3779B9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for(i=0; i<8; i++) { /* basic cycle start */
*v1 -= ((*v0<<4) + k2) ^ (*v0 + sum) ^ ((*v0>>5) + k3);
*v0 -= ((*v1<<4) + k0) ^ (*v1 + sum) ^ ((*v1>>5) + k1);
sum -= delta; /* end cycle */
}
}
/* mi4 files are encrypted in 64-bit blocks (two little-endian 32-bit
integers) and the key is incremented after each block
*/
static void tea_decrypt_buf(unsigned char* src,
unsigned char* dest,
size_t n, uint32_t * key)
{
uint32_t v0, v1;
unsigned int i;
for (i = 0; i < (n / 8); i++) {
v0 = le2int(src);
v1 = le2int(src+4);
tea_decrypt(&v0, &v1, key);
int2le(v0, dest);
int2le(v1, dest+4);
src += 8;
dest += 8;
/* Now increment the key */
key[0]++;
if (key[0]==0) {
key[1]++;
if (key[1]==0) {
key[2]++;
if (key[2]==0) {
key[3]++;
}
}
}
}
}
static int tea_find_key(struct mi4header_t *mi4header, unsigned char* buf)
{
unsigned int i;
uint32_t key[4];
uint32_t keyinc;
unsigned char magic_dec[8];
int key_found = -1;
unsigned int magic_location = mi4header->length-4;
int unaligned = 0;
if ( (magic_location % 8) != 0 )
{
unaligned = 1;
magic_location -= 4;
}
for (i=0; i < NUM_KEYS && (key_found<0) ; i++) {
key[0] = tea_keytable[i].key[0];
key[1] = tea_keytable[i].key[1];
key[2] = tea_keytable[i].key[2];
key[3] = tea_keytable[i].key[3];
/* Now increment the key */
keyinc = (magic_location-mi4header->plaintext)/8;
if ((key[0]+keyinc) < key[0]) key[1]++;
key[0] += keyinc;
if (key[1]==0) key[2]++;
if (key[2]==0) key[3]++;
/* Decrypt putative magic */
tea_decrypt_buf(&buf[magic_location], magic_dec, 8, key);
if (le2int(&magic_dec[4*unaligned]) == 0xaa55aa55)
{
key_found = i;
}
}
return key_found;
}
/* Load mi4 format firmware image */
int load_mi4(unsigned char* buf,
const char* firmware,
unsigned int buffer_size)
{
int fd;
struct mi4header_t mi4header;
int rc;
unsigned long sum;
char filename[MAX_PATH];
snprintf(filename,sizeof(filename), BOOTDIR "/%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;
}
read(fd, &mi4header, MI4_HEADER_SIZE);
/* MI4 file size */
if ((mi4header.mi4size-MI4_HEADER_SIZE) > buffer_size)
{
close(fd);
return EFILE_TOO_BIG;
}
/* Load firmware file */
lseek(fd, MI4_HEADER_SIZE, SEEK_SET);
rc = read(fd, buf, mi4header.mi4size-MI4_HEADER_SIZE);
close(fd);
if(rc < (int)mi4header.mi4size-MI4_HEADER_SIZE)
return EREAD_IMAGE_FAILED;
/* Check CRC32 to see if we have a valid file */
sum = chksum_crc32 (buf, mi4header.mi4size - MI4_HEADER_SIZE);
if(sum != mi4header.crc32)
return EBAD_CHKSUM;
if( (mi4header.plaintext + MI4_HEADER_SIZE) != mi4header.mi4size)
{
/* Load encrypted firmware */
int key_index = tea_find_key(&mi4header, buf);
if (key_index < 0)
return EINVALID_FORMAT;
/* Plaintext part is already loaded */
buf += mi4header.plaintext;
/* Decrypt in-place */
tea_decrypt_buf(buf, buf,
mi4header.mi4size-(mi4header.plaintext+MI4_HEADER_SIZE),
tea_keytable[key_index].key);
/* Check decryption was successfull */
if(le2int(&buf[mi4header.length-mi4header.plaintext-4]) != 0xaa55aa55)
return EREAD_IMAGE_FAILED;
}
return mi4header.mi4size - MI4_HEADER_SIZE;
}

View file

@ -18,42 +18,22 @@
*
****************************************************************************/
#include <stdio.h>
#include "config.h"
#include "loader_strerror.h"
#include "rkw-loader.h"
#include "crc32-rkw.h"
#include "file.h"
#include "panic.h"
/* error strings sorted by number */
/* error 0 is empty */
static const char *err_str[] = {
"Loading OK",
"Can't open RKW file",
"Can't read RKW header",
"Invalid RKW magic number",
"RKW header CRC error",
"RKW file too big",
"RKW Load address mismatch",
"Bad model number",
"Error Reading File",
"RKW firmware CRC error"
};
const char *rkw_strerror(int8_t errno)
{
if ((uint8_t)-errno >= sizeof(err_str)/sizeof(err_str[0]) || errno > 0)
return "Unknown error";
return err_str[-errno];
}
/* loosely based on load_firmware()
* on success we return size loaded image
* on success we return size of loaded image
* on error we return negative value which can be deciphered by means
* of rkw_strerror() function
*/
int load_rkw(unsigned char* buf, const char* filename, int buffer_size)
int load_rkw(unsigned char* buf, const char* firmware, int buffer_size)
{
char filename[MAX_PATH];
int fd;
int rc;
int len;
@ -61,22 +41,42 @@ int load_rkw(unsigned char* buf, const char* filename, int buffer_size)
uint32_t crc, fw_crc;
struct rkw_header_t rkw_info;
fd = open(filename, O_RDONLY);
/* only filename passed */
if (firmware[0] != '/')
{
/* First check in BOOTDIR */
snprintf(filename, sizeof(filename), BOOTDIR "/%s",firmware);
if(fd < 0)
return -1;
fd = open(filename, O_RDONLY);
if(fd < 0)
{
/* Check in root dir */
snprintf(filename, sizeof(filename),"/%s",firmware);
fd = open(filename, O_RDONLY);
if (fd < 0)
return EFILE_NOT_FOUND;
}
}
else
{
/* full path passed */
fd = open(firmware, O_RDONLY);
if (fd < 0)
return EFILE_NOT_FOUND;
}
rc = read(fd, &rkw_info, sizeof(rkw_info));
if (rc < (int)sizeof(rkw_info))
{
ret = -2;
ret = EREAD_HEADER_FAILED;
goto end;
}
/* check if RKW is valid */
if (rkw_info.magic_number != RKLD_MAGIC)
{
ret = -3;
ret = EINVALID_FORMAT;
goto end;
}
@ -86,7 +86,7 @@ int load_rkw(unsigned char* buf, const char* filename, int buffer_size)
crc = crc32_rkw((uint8_t *)&rkw_info, sizeof(rkw_info)-sizeof(uint32_t));
if (rkw_info.crc != crc)
{
ret = -4;
ret = EBAD_HEADER_CHKSUM;
goto end;
}
}
@ -95,14 +95,14 @@ int load_rkw(unsigned char* buf, const char* filename, int buffer_size)
len = rkw_info.load_limit - rkw_info.load_address;
if (len > buffer_size)
{
ret = -5;
ret = EFILE_TOO_BIG;
goto end;
}
/* check load address - we support loading only at 0x60000000 */
if (rkw_info.load_address != 0x60000000)
{
ret = -6;
ret = EINVALID_LOAD_ADDR;
goto end;
}
@ -112,7 +112,7 @@ int load_rkw(unsigned char* buf, const char* filename, int buffer_size)
*/
if (rkw_info.reserved0 != 0 && rkw_info.reserved0 != MODEL_NUMBER)
{
ret = -7;
ret = EBAD_MODEL;
goto end;
}
@ -124,7 +124,7 @@ int load_rkw(unsigned char* buf, const char* filename, int buffer_size)
if(rc < len)
{
ret = -8;
ret = EREAD_IMAGE_FAILED;
goto end;
}
@ -136,7 +136,7 @@ int load_rkw(unsigned char* buf, const char* filename, int buffer_size)
if (fw_crc != crc)
{
ret = -9;
ret = EBAD_CHKSUM;
goto end;
}
}