/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: mkboot.c,v 1.4 2005-11-18 23:00:40 linus Exp $ * * 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 #include #include void usage(void) { printf("usage: mkboot <-iax5|-h100|-h300> \n"); exit(1); } int main(int argc, char *argv[]) { if(argc != 5) { usage(); return 0; } 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 0; } 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; memset(image, 0xff, sizeof(image)); /* First, read the iriver original firmware into the image */ f = fopen(infile, "rb"); if(!f) { perror(infile); exit(1); } i = fread(image, 1, 16, f); if(i < 16) { perror(infile); exit(1); } /* This is the length of the binary image without the scrambling overhead (but including the ESTFBINR header) */ binary_length = image[4] + (image[5] << 8) + (image[6] << 16) + (image[7] << 24); /* Read the rest of the binary data, but not the checksum block */ len = binary_length+0x200-16; i = fread(image+16, 1, len, f); if(i < len) { perror(infile); exit(1); } fclose(f); /* Now, read the boot loader into the image */ f = fopen(bootfile, "rb"); if(!f) { perror(bootfile); exit(1); } fseek(f, 0, SEEK_END); len = ftell(f); fseek(f, 0, SEEK_SET); i = fread(image+0x220 + origin, 1, len, f); if(i < len) { perror(bootfile); exit(1); } fclose(f); f = fopen(outfile, "wb"); if(!f) { perror(outfile); exit(1); } /* Patch the reset vector to start the boot loader */ image[0x220 + 4] = image[origin + 0x220 + 4]; image[0x220 + 5] = image[origin + 0x220 + 5]; image[0x220 + 6] = image[origin + 0x220 + 6]; image[0x220 + 7] = image[origin + 0x220 + 7]; /* This is the actual length of the binary, excluding all headers */ actual_length = origin + len; /* Patch the ESTFBINR header */ image[0x20c] = (actual_length >> 24) & 0xff; image[0x20d] = (actual_length >> 16) & 0xff; image[0x20e] = (actual_length >> 8) & 0xff; image[0x20f] = actual_length & 0xff; image[0x21c] = (actual_length >> 24) & 0xff; image[0x21d] = (actual_length >> 16) & 0xff; image[0x21e] = (actual_length >> 8) & 0xff; image[0x21f] = actual_length & 0xff; /* This is the length of the binary, including the ESTFBINR header and rounded up to the nearest 0x200 boundary */ binary_length = (actual_length + 0x20 + 0x1ff) & 0xfffffe00; /* The number of checksums, i.e number of 0x200 byte blocks */ num_chksums = binary_length / 0x200; /* The total file length, including all headers and checksums */ total_length = binary_length + num_chksums + 0x200; /* Patch the scrambler header with the new length info */ image[0] = total_length & 0xff; image[1] = (total_length >> 8) & 0xff; image[2] = (total_length >> 16) & 0xff; image[3] = (total_length >> 24) & 0xff; image[4] = binary_length & 0xff; image[5] = (binary_length >> 8) & 0xff; image[6] = (binary_length >> 16) & 0xff; image[7] = (binary_length >> 24) & 0xff; image[8] = num_chksums & 0xff; image[9] = (num_chksums >> 8) & 0xff; image[10] = (num_chksums >> 16) & 0xff; image[11] = (num_chksums >> 24) & 0xff; i = fwrite(image, 1, total_length, f); if(i < total_length) { perror(outfile); exit(1); } printf("Wrote 0x%x bytes in %s\n", total_length, outfile); fclose(f); return 0; } #define HEADER_SIZE 0x1030 #define FLASH_START 0x00010000 #define ROCKBOX_BOOTLOADER 0x00150000 #define BOOTLOADER_LIMIT 0x00170000 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) { perror("Rockbox bootloader is too big.\n"); return -1; } if ((ffile = fopen(fname, "rb")) == NULL) { perror("Cannot open original firmware file.\n"); return -1; } fseek(ffile, 0, SEEK_END); flength = ftell(ffile); fseek(ffile, 0, SEEK_SET); bbuf = malloc(blength); fbuf = malloc(flength); if (!bbuf || !fbuf) { perror("Out of memory.\n"); return -1; } if ( fread(bbuf, 1, blength, bfile) < blength || fread(fbuf, 1, flength, ffile) < flength) { perror("Read error.\n"); return -1; } fclose(bfile); fclose(ffile); /* verify format of input files */ if (blength < 0x10 || memcmp(bbuf, bsig, sizeof(bsig))) { perror("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))) { perror("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) { perror("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.\n"); return -1; } if (fwrite(fbuf, 1, flength, ofile) < flength) { perror("Write error.\n"); return -1; } fclose(ofile); free(bbuf); free(fbuf); return 0; }