Index: rockbox-bleeding-20070914/firmware/boot.lds =================================================================== --- rockbox-bleeding-20070914.orig/firmware/boot.lds 2007-09-09 13:20:43.000000000 +0200 +++ rockbox-bleeding-20070914/firmware/boot.lds 2007-11-07 11:47:18.000000000 +0100 @@ -35,8 +35,8 @@ #define DRAMORIG 0x31000000 #define IRAMORIG 0x10000000 #define IRAMSIZE 0x20000 -#define FLASHORIG 0x00010000 -#define FLASHSIZE 4M +#define FLASHORIG 0x00150000 +#define FLASHSIZE 4M - FLASHORIG #elif CONFIG_CPU == PP5020 #define DRAMORIG 0x10000000 #define IRAMORIG 0x40000000 Index: rockbox-bleeding-20070914/firmware/target/coldfire/crt0.S =================================================================== --- rockbox-bleeding-20070914.orig/firmware/target/coldfire/crt0.S 2007-02-18 02:20:03.000000000 +0100 +++ rockbox-bleeding-20070914/firmware/target/coldfire/crt0.S 2007-11-07 14:03:35.000000000 +0100 @@ -24,6 +24,35 @@ .global start start: +#if (defined(IAUDIO_X5) || defined(IAUDIO_M5)) && defined(BOOTLOADER) && !defined(IAUDIO_NO_DUALBOOT) + /* iAudio X5/M5 dual boot support. + * Hold power on switch < 3s: Boot Rockbox + * Hold power on switch > 3s: Boot original Cowon Firmware + */ + tst.b 0x30000000 /* preloader sets this to 1 + if woke up due to RTC alarm */ + bne .loadoriginal + + /* Wait ~3 seconds for ON-button release. We need roughly 300ns per + iteration, so we check 10000000 times to reach the desired delay */ + move.l #10000000, %d0 +.on_button_test: + move.l (0x80000000), %d1 /* GPIO_READ */ + and.l #0x6000000, %d1 /* Check main (bit 25=0) and remote (bit 26=0) */ + cmp.l #0x6000000, %d1 /* ON buttons simultaneously */ + beq .loadrockbox + sub.l #1, %d0 + bne .on_button_test + +.loadoriginal: + jmp 0x10010 + +.loadrockbox: + jmp .actualcrt0 + +.actualcrt0: +#endif /* (IAUDIO_X5 || IAUDIO_M5) && BOOTLOADER && !IAUDIO_NO_DUALBOOT */ + move.w #0x2700,%sr move.l #vectors,%d0 Index: rockbox-bleeding-20070914/tools/mkboot.c =================================================================== --- rockbox-bleeding-20070914.orig/tools/mkboot.c 2007-01-09 00:44:31.000000000 +0100 +++ rockbox-bleeding-20070914/tools/mkboot.c 2007-11-12 13:45:53.000000000 +0100 @@ -22,41 +22,43 @@ void usage(void) { - printf("usage: mkboot [-h300] \n"); + printf("usage: mkboot <-iax5|-h100|-h300> \n"); exit(1); } -unsigned char image[0x400000 + 0x220 + 0x400000/0x200]; int main(int argc, char *argv[]) { - char *infile, *bootfile, *outfile; + if(argc != 5) + { + usage(); + return 1; + } + + if ( ! strcmp(argv[1], "-h100")) + return iriver_main(argv[2], argv[3], argv[4], 0x1f0000); + + if ( ! strcmp(argv[1], "-h300")) + return iriver_main(argv[2], argv[3], argv[4], 0x3f0000); + + if ( ! strcmp(argv[1], "-iax5")) + return iaudio_main(argv[2], argv[3], argv[4]); + + usage(); + return 1; +} + +unsigned char image[0x400000 + 0x220 + 0x400000/0x200]; + +int iriver_main(const char infile[], const char bootfile[], const char outfile[], int origin) +{ FILE *f; long pos; int i; int file_length; int len; int actual_length, total_length, binary_length, num_chksums; - int origin = 0x1f0000; /* H1x0 bootloader address */ - - if(argc < 3) { - usage(); - } - - if(!strcmp(argv[1], "-h300")) { - infile = argv[2]; - bootfile = argv[3]; - outfile = argv[4]; - - origin = 0x3f0000; /* H3x0 bootloader address */ - } - else - { - infile = argv[1]; - bootfile = argv[2]; - outfile = argv[3]; - } memset(image, 0xff, sizeof(image)); @@ -172,3 +174,141 @@ return 0; } + +/* iAudio firmware update file header size */ +#define HEADER_SIZE 0x1030 +/* Address of flash contents that get overwritten by a firmware update. + * Contents before this address contain the preloader and are not affected + * by a firmware update. + * -> Firmware update file contents starting at offset HEADER_SIZE end up + * in flash at address FLASH_START + */ +#define FLASH_START 0x00010000 +/* Start of unused space in original firmware (flash address, not file + * offset!) where we patch in the Rockbox loader */ +#define ROCKBOX_BOOTLOADER 0x00150000 +/* End of unused space in original firmware */ +#define BOOTLOADER_LIMIT 0x00170000 + +/* Patch the Rockbox bootloader into free space in the original firmware + * (starting at 0x150000). The preloader starts execution of the OF at + * 0x10000 which normally contains a jsr 0x10010. We also patch this to + * do a jsr 0x150000 to the Rockbox dual boot loader instead. If it then + * decides to start the OF instead of Rockbox, it simply does a jmp + * 0x10010 instead of loading Rockbox from disk. + */ +int iaudio_main(const char fname[], const char bname[], const char oname[]) +{ + size_t flength, blength; + unsigned char *bbuf, *fbuf, *p; + const unsigned char fsig[] = { + /* jsr 10010 */ + 0x4e, 0xb9, 0x00, 0x01, 0x00, 0x10 }; + const unsigned char bsig[] = { + /* tst.b 30000000 */ + 0x4a, 0x39, 0x30, 0x00, 0x00, 0x00 }; + FILE *ffile, *bfile, *ofile; + unsigned char sum = 0; + int i; + + /* read input files */ + if ((bfile = fopen(bname, "rb")) == NULL) + { + perror("Cannot open Rockbox bootloader file.\n"); + return 1; + } + + fseek(bfile, 0, SEEK_END); + blength = ftell(bfile); + fseek(bfile, 0, SEEK_SET); + + if (blength + ROCKBOX_BOOTLOADER >= BOOTLOADER_LIMIT) + { + fprintf(stderr, "Rockbox bootloader is too big.\n"); + return 1; + } + + if ((ffile = fopen(fname, "rb")) == NULL) + { + perror("Cannot open original firmware file."); + return 1; + } + + fseek(ffile, 0, SEEK_END); + flength = ftell(ffile); + fseek(ffile, 0, SEEK_SET); + + bbuf = malloc(blength); + fbuf = malloc(flength); + + if (!bbuf || !fbuf) + { + fprintf(stderr, "Out of memory.\n"); + return 1; + } + + if ( fread(bbuf, 1, blength, bfile) < blength + || fread(fbuf, 1, flength, ffile) < flength) + { + fprintf(stderr, "Read error.\n"); + return 1; + } + fclose(bfile); + fclose(ffile); + + /* verify format of input files */ + if (blength < 0x10 + || memcmp(bbuf, bsig, sizeof(bsig))) + { + fprintf(stderr, "Rockbox bootloader format error (is it bootloader.bin?).\n"); + return 1; + } + if (flength < HEADER_SIZE-FLASH_START+BOOTLOADER_LIMIT + || memcmp(fbuf+HEADER_SIZE, fsig, sizeof(fsig))) + { + fprintf(stderr, "Original firmware format error (is it x5_fw.bin?).\n"); + return 1; + } + + /* verify firmware is not overrun */ + for (i = ROCKBOX_BOOTLOADER; i < BOOTLOADER_LIMIT; i++) + { + if (fbuf[HEADER_SIZE-FLASH_START+i] != 0xff) + { + fprintf(stderr, "Original firmware has grown too much.\n"); + return 1; + } + } + + /* change jsr 0x10010 to jsr DUAL_BOOTLOADER */ + p = fbuf + HEADER_SIZE + 2; + *p++ = (ROCKBOX_BOOTLOADER >> 24) & 0xff; + *p++ = (ROCKBOX_BOOTLOADER >> 16) & 0xff; + *p++ = (ROCKBOX_BOOTLOADER >> 8) & 0xff; + *p++ = (ROCKBOX_BOOTLOADER ) & 0xff; + + p = fbuf + HEADER_SIZE + ROCKBOX_BOOTLOADER - FLASH_START; + memcpy(p, bbuf, blength); + + /* recalc checksum */ + for (i = HEADER_SIZE; i < flength; i++) + sum += fbuf[i]; + fbuf[0x102b] = sum; + + /* write output */ + if ((ofile = fopen(oname, "wb")) == NULL) + { + perror("Cannot open output file"); + return 1; + } + if (fwrite(fbuf, 1, flength, ofile) < flength) + { + fprintf(stderr, "Write error.\n"); + return 1; + } + fclose(ofile); + free(bbuf); + free(fbuf); + + return 0; +}