From 14ed3ca8d88a8f792e45b5453c9f089ffd8a975a Mon Sep 17 00:00:00 2001 From: Barry Wardell Date: Fri, 16 Mar 2007 14:28:00 +0000 Subject: In preparation for use with sansapatcher, change portalplayer bootloaders to read firmwares in mi4 format. When loading the OF: 1) first try to load from a hidden disk partition 2) try loading /System/OF.mi4 3) finally fall back to loading /System/OF.bin which is what the old bootloader used. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12802 a1c6a512-1295-4272-9138-f99709370657 --- bootloader/common.c | 2 + bootloader/common.h | 1 + bootloader/main-pp.c | 280 +++++++++++++++++++++++++++++++++++++-- firmware/export/config-e200.h | 12 +- firmware/export/config-h10.h | 12 +- firmware/export/config-h10_5gb.h | 12 +- firmware/export/disk.h | 1 + tools/configure | 58 ++++---- 8 files changed, 329 insertions(+), 49 deletions(-) diff --git a/bootloader/common.c b/bootloader/common.c index a382816791..51b751cbf9 100644 --- a/bootloader/common.c +++ b/bootloader/common.c @@ -97,6 +97,8 @@ char *strerror(int error) return "Bad checksum"; case EFILE_TOO_BIG: return "File too big"; + case EINVALID_FORMAT: + return "Invalid file format"; default: return "Unknown"; } diff --git a/bootloader/common.h b/bootloader/common.h index 3607dd0f68..c2690324e5 100644 --- a/bootloader/common.h +++ b/bootloader/common.h @@ -27,6 +27,7 @@ #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; diff --git a/bootloader/main-pp.c b/bootloader/main-pp.c index 960e570889..64f9e79a93 100644 --- a/bootloader/main-pp.c +++ b/bootloader/main-pp.c @@ -29,6 +29,80 @@ #include "ata.h" #include "button.h" #include "disk.h" +#include + +/* + * CRC32 implementation taken from: + * + * efone - Distributed internet phone system. + * + * (c) 1999,2000 Krzysztof Dabrowski + * (c) 1999,2000 ElysiuM deeZine + * + * 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. + * + */ + +/* based on implementation by Finn Yannick Jacobs */ + +#include +#include + +/* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab(). + * so make sure, you call it before using the other + * functions! + */ +static unsigned int crc_tab[256]; + +/* chksum_crc() -- to a given block, this one calculates the + * crc32-checksum until the length is + * reached. the crc32-checksum will be + * the result. + */ +unsigned int chksum_crc32 (unsigned char *block, unsigned int length) +{ + register unsigned long crc; + unsigned long i; + + crc = 0; + for (i = 0; i < length; i++) + { + crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF]; + } + return (crc); +} + +/* chksum_crc32gentab() -- to a global crc_tab[256], this one will + * calculate the crcTable for crc32-checksums. + * it is generated to the polynom [..] + */ + +static void chksum_crc32gentab (void) +{ + unsigned long crc, poly; + int i, j; + + poly = 0xEDB88320L; + for (i = 0; i < 256; i++) + { + crc = i; + for (j = 8; j > 0; j--) + { + if (crc & 1) + { + crc = (crc >> 1) ^ poly; + } + else + { + crc >>= 1; + } + } + crc_tab[i] = crc; + } +} /* Button definitions */ #if CONFIG_KEYPAD == IRIVER_H10_PAD @@ -50,21 +124,167 @@ unsigned char *loadbuffer = (unsigned char *)DRAM_START; /* Bootloader version */ char version[] = APPSVERSION; +/* Locations and sizes in hidden partition on Sansa */ +#define PPMI_OFFSET 1024 +#define PPMI_SIZE 1 +#define MI4_HEADER_SIZE 1 + +/* 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]; + uint32_t length; + uint32_t pad[126]; +}; + +/* 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),"/.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; + } + + read(fd, &mi4header, 0x200); + + /* We don't support encrypted mi4 files yet */ + if( (mi4header.plaintext + 0x200) != mi4header.mi4size) + return EINVALID_FORMAT; + + /* MI4 file size */ + printf("mi4 size: %x", mi4header.length); + + if (mi4header.length > buffer_size) + 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 */ + lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET); + rc = read(fd, buf, mi4header.mi4size-0x200); + if(rc < (int)mi4header.mi4size-0x200) + return EREAD_IMAGE_FAILED; + + /* Check CRC32 to see if we have a valid file */ + sum = chksum_crc32 (buf,mi4header.mi4size-0x200); + + printf("Calculated CRC32: %x", sum); + + if(sum != mi4header.crc32) + return EBAD_CHKSUM; + + return EOK; +} + +/* Load mi4 firmware from a hidden disk partition */ +int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, unsigned int buffer_size) +{ + struct mi4header_t mi4header; + struct ppmi_header_t ppmi_header; + unsigned long sum; + + /* Read header to find out how long the mi4 file is. */ + ata_read_sectors(pinfo->start + PPMI_OFFSET, PPMI_SIZE, &ppmi_header); + + /* The first four characters at 0x80000 (sector 1024) should be PPMI*/ + if( memcmp(ppmi_header.magic, "PPMI", 4) ) + return EFILE_NOT_FOUND; + + printf("BL mi4 size: %x", ppmi_header.length); + + /* Read mi4 header of the OF */ + ata_read_sectors(pinfo->start + PPMI_OFFSET + PPMI_SIZE + + (ppmi_header.length/512), MI4_HEADER_SIZE, &mi4header); + + /* We don't support encrypted mi4 files yet */ + if( (mi4header.plaintext + 0x200) != mi4header.mi4size) + return EINVALID_FORMAT; + + /* MI4 file size */ + printf("OF mi4 size: %x", mi4header.length); + + if (mi4header.length > buffer_size) + 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 */ + ata_read_sectors(pinfo->start + PPMI_OFFSET + PPMI_SIZE + + (ppmi_header.length/512) + MI4_HEADER_SIZE, + (mi4header.length-0x200)/512, buf); + + /* Check CRC32 to see if we have a valid file */ + sum = chksum_crc32 (buf,mi4header.mi4size-0x200); + + printf("Calculated CRC32: %x", sum); + + if(sum != mi4header.crc32) + return EBAD_CHKSUM; + + return EOK; +} + void* main(void) { char buf[256]; int i; int btn; int rc; + int num_partitions; unsigned short* identify_info; struct partinfo* pinfo; + chksum_crc32gentab (); + system_init(); kernel_init(); lcd_init(); font_init(); button_init(); + lcd_set_foreground(LCD_WHITE); + lcd_set_background(LCD_BLACK); + lcd_clear_display(); + btn = button_read_device(); /* Enable bootloader messages */ @@ -94,31 +314,69 @@ void* main(void) } disk_init(); - rc = disk_mount_all(); - if (rc<=0) + num_partitions = disk_mount_all(); + if (num_partitions<=0) { - error(EDISK,rc); + error(EDISK,num_partitions); } - pinfo = disk_partinfo(0); - printf("Partition 0: 0x%02x %ld MB", pinfo->type, pinfo->size / 2048); + /* Just list the first 2 partitions since we don't have any devices yet + that have more than that */ + for(i=0; i<2; i++) + { + pinfo = disk_partinfo(i); + printf("Partition %d: 0x%02x %ld MB", + i, pinfo->type, pinfo->size / 2048); + } if(btn & BOOTLOADER_BOOT_OF) { - /* 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 + /* Load original mi4 firmware in to a memory buffer called loadbuffer. + The rest of the loading is done in crt0.S. + 1) First try reading from the hidden partition (on Sansa only). + 2) Next try a decrypted mi4 file in /System/OF.mi4 + 3) Finally, try a raw firmware binary in /System/OF.mi4. It should be + a mi4 firmware decrypted and header stripped using mi4code. */ printf("Loading original firmware..."); + + /* First try a hidden partition */ + printf("Trying hidden partition"); + pinfo = disk_partinfo(1); + if(pinfo->type == PARTITION_TYPE_HIDDEN) + { + rc = load_mi4_part(loadbuffer, pinfo, MAX_LOADSIZE); + if (rc < EOK) { + printf("Can't load from partition"); + printf(strerror(rc)); + } else { + return (void*)loadbuffer; + } + } else { + printf("No hidden partition found."); + } + + printf("Trying /System/OF.mi4"); + rc=load_mi4(loadbuffer, "/System/OF.mi4", MAX_LOADSIZE); + if (rc < EOK) { + printf("Can't load /System/OF.mi4"); + printf(strerror(rc)); + } else { + return (void*)loadbuffer; + } + + printf("Trying /System/OF.bin"); rc=load_raw_firmware(loadbuffer, "/System/OF.bin", MAX_LOADSIZE); if (rc < EOK) { printf("Can't load /System/OF.bin"); - error(EBOOTFILE, rc); + printf(strerror(rc)); + } else { + return (void*)loadbuffer; } + } else { printf("Loading Rockbox..."); - rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE); + rc=load_mi4(loadbuffer, BOOTFILE, MAX_LOADSIZE); if (rc < EOK) { printf("Can't load %s:", BOOTFILE); error(EBOOTFILE, rc); diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h index 304c7062e5..0126cdf739 100644 --- a/firmware/export/config-e200.h +++ b/firmware/export/config-e200.h @@ -108,13 +108,19 @@ #define CONFIG_LCD LCD_X5 /* Offset ( in the firmware file's header ) to the file length */ -#define FIRMWARE_OFFSET_FILE_LENGTH 0 +#define FIRMWARE_OFFSET_FILE_LENGTH 0x8 /* Offset ( in the firmware file's header ) to the file CRC */ -#define FIRMWARE_OFFSET_FILE_CRC 0 +#define FIRMWARE_OFFSET_FILE_CRC 0x0c + +/* Offset ( in the firmware file's header ) to the file type */ +#define FIRMWARE_OFFSET_FILE_TYPE 0x1f8 + +/* Offset ( in the firmware file's header ) to the file model id */ +#define FIRMWARE_OFFSET_FILE_MODEL 0x1fc /* Offset ( in the firmware file's header ) to the real data */ -#define FIRMWARE_OFFSET_FILE_DATA 8 +#define FIRMWARE_OFFSET_FILE_DATA 0x200 /* #define USB_IPODSTYLE */ diff --git a/firmware/export/config-h10.h b/firmware/export/config-h10.h index a66a387f02..ec6f83fecb 100644 --- a/firmware/export/config-h10.h +++ b/firmware/export/config-h10.h @@ -138,13 +138,19 @@ #define HAVE_ATA_POWER_OFF /* Offset ( in the firmware file's header ) to the file length */ -#define FIRMWARE_OFFSET_FILE_LENGTH 0 +#define FIRMWARE_OFFSET_FILE_LENGTH 0x8 /* Offset ( in the firmware file's header ) to the file CRC */ -#define FIRMWARE_OFFSET_FILE_CRC 0 +#define FIRMWARE_OFFSET_FILE_CRC 0x0c + +/* Offset ( in the firmware file's header ) to the file type */ +#define FIRMWARE_OFFSET_FILE_TYPE 0x1f8 + +/* Offset ( in the firmware file's header ) to the file model id */ +#define FIRMWARE_OFFSET_FILE_MODEL 0x1fc /* Offset ( in the firmware file's header ) to the real data */ -#define FIRMWARE_OFFSET_FILE_DATA 8 +#define FIRMWARE_OFFSET_FILE_DATA 0x200 /* #define USB_IPODSTYLE */ diff --git a/firmware/export/config-h10_5gb.h b/firmware/export/config-h10_5gb.h index fa643b01b9..b809f3471c 100644 --- a/firmware/export/config-h10_5gb.h +++ b/firmware/export/config-h10_5gb.h @@ -118,13 +118,19 @@ #define HAVE_ATA_POWER_OFF /* Offset ( in the firmware file's header ) to the file length */ -#define FIRMWARE_OFFSET_FILE_LENGTH 0 +#define FIRMWARE_OFFSET_FILE_LENGTH 0x8 /* Offset ( in the firmware file's header ) to the file CRC */ -#define FIRMWARE_OFFSET_FILE_CRC 0 +#define FIRMWARE_OFFSET_FILE_CRC 0x0c + +/* Offset ( in the firmware file's header ) to the file type */ +#define FIRMWARE_OFFSET_FILE_TYPE 0x1f8 + +/* Offset ( in the firmware file's header ) to the file model id */ +#define FIRMWARE_OFFSET_FILE_MODEL 0x1fc /* Offset ( in the firmware file's header ) to the real data */ -#define FIRMWARE_OFFSET_FILE_DATA 8 +#define FIRMWARE_OFFSET_FILE_DATA 0x200 /* #define USB_IPODSTYLE */ diff --git a/firmware/export/disk.h b/firmware/export/disk.h index e10fe9e7dc..b9619be983 100644 --- a/firmware/export/disk.h +++ b/firmware/export/disk.h @@ -30,6 +30,7 @@ struct partinfo { #define PARTITION_TYPE_FAT32 0x0b #define PARTITION_TYPE_FAT32_LBA 0x0c #define PARTITION_TYPE_FAT16 0x06 +#define PARTITION_TYPE_HIDDEN 0x84 /* returns a pointer to an array of 8 partinfo structs */ struct partinfo* disk_init(IF_MV_NONVOID(int volume)); diff --git a/tools/configure b/tools/configure index 7fe1956efb..a691c98d7f 100755 --- a/tools/configure +++ b/tools/configure @@ -1173,7 +1173,7 @@ EOF flash="" plugins="yes" codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" - boottool="$rootdir/tools/scramble -mi4v3" + boottool="$rootdir/tools/scramble -mi4v3 -model=h10 -type=RBBL" bootoutput="H10_20GC.mi4" # toolset is the tools within the tools directory that we build for # this particular target. @@ -1184,6 +1184,32 @@ EOF t_model="h10" ;; + 15|h10_5gb) + target_id=24 + archos="h10_5gb" + target="-DIRIVER_H10_5GB" + memory=32 # always + arm7tdmicc + tool="$rootdir/tools/scramble -add=h10_5gb" + bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" + bmp2rb_native="$rootdir/tools/bmp2rb -f 5" + output="rockbox.h10" + appextra="recorder:gui" + archosrom="" + flash="" + plugins="yes" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + boottool="$rootdir/tools/scramble -mi4v2 -model=h105 -type=RBBL" + bootoutput="H10.mi4" + # toolset is the tools within the tools directory that we build for + # this particular target. + toolset="$genericbitmaptools scramble" + # architecture, manufacturer and model for the target-tree build + t_cpu="arm" + t_manufacturer="iriver" + t_model="h10" + ;; + 50|e200) target_id=23 archos="e200" @@ -1199,7 +1225,7 @@ EOF flash="" plugins="yes" codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" - boottool="$rootdir/tools/scramble -mi4v3" + boottool="$rootdir/tools/scramble -mi4v3 -model=e200 -type=RBBL" bootoutput="PP5022.mi4" # toolset is the tools within the tools directory that we build for # this particular target. @@ -1228,7 +1254,7 @@ EOF flash="" plugins="yes" codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" - boottool="$rootdir/tools/scramble -mi4r" + boottool="$rootdir/tools/scramble -mi4r -model=e20r -type=RBBL" bootoutput="pp5022.mi4" # toolset is the tools within the tools directory that we build for # this particular target. @@ -1239,32 +1265,6 @@ EOF t_model="sansa-e200" ;; - 15|h10_5gb) - target_id=24 - archos="h10_5gb" - target="-DIRIVER_H10_5GB" - memory=32 # always - arm7tdmicc - tool="$rootdir/tools/scramble -add=h10_5gb" - bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" - bmp2rb_native="$rootdir/tools/bmp2rb -f 5" - output="rockbox.h10" - appextra="recorder:gui" - archosrom="" - flash="" - plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" - boottool="$rootdir/tools/scramble -mi4v2" - bootoutput="H10.mi4" - # toolset is the tools within the tools directory that we build for - # this particular target. - toolset="$genericbitmaptools scramble" - # architecture, manufacturer and model for the target-tree build - t_cpu="arm" - t_manufacturer="iriver" - t_model="h10" - ;; - 60|tpj1022) target_id=25 archos="tpj1022" -- cgit v1.2.3