/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * * Copyright (C) 2006 by Rani Hod * * 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 #define ROCKBOX_BOOTLOADER 0x00150000 #define BOOTLOADER_LIMIT 0x00170000 void usage() { printf("Usage: x5-patch \n"); } void do_patch(char *fbuf, const char *ibuf, size_t ilength) { unsigned char *p; /* change jsr 0x10010 to jsr DUAL_BOOTLOADER */ p = fbuf + 0x1030 + 2; *p++ = (ROCKBOX_BOOTLOADER >> 24) & 0xff; *p++ = (ROCKBOX_BOOTLOADER >> 16) & 0xff; *p++ = (ROCKBOX_BOOTLOADER >> 8) & 0xff; *p++ = (ROCKBOX_BOOTLOADER ) & 0xff; p = fbuf + 0x1030 + ROCKBOX_BOOTLOADER - 0x10000; memcpy(p, ibuf, ilength); } int main(int argc, char **argv) { size_t flength, ilength; unsigned char *ibuf, *fbuf; const unsigned char fsig[] = { /* jsr 10010 */ 0x4e, 0xb9, 0x00, 0x01, 0x00, 0x10 }; //const unsigned char isig[] = { /* move.w #$2700, sr */ // 0x46, 0xfc, 0x27, 0x00 }; FILE *ifile, *ofile, *ffile; unsigned char sum = 0; int i; if (argc != 3) { usage(); return 1; } if ((ifile = fopen(argv[1], "rb")) == NULL) { perror("Cannot open input file.\n"); return -1; } fseek(ifile, 0, SEEK_END); ilength = ftell(ifile); fseek(ifile, 0, SEEK_SET); if (ilength + ROCKBOX_BOOTLOADER >= BOOTLOADER_LIMIT) { perror("Rockbox bootloader is too big.\n"); return -1; } if ((ffile = fopen("x5_fw.bin", "rb")) == NULL) { perror("Cannot open original firmware file.\n"); return -1; } fseek(ffile, 0, SEEK_END); flength = ftell(ffile); fseek(ffile, 0, SEEK_SET); ibuf = malloc(ilength); fbuf = malloc(flength); if (!ibuf || !fbuf) { perror("Out of memory.\n"); return -1; } if (fread(ibuf, 1, ilength, ifile) < ilength || fread(fbuf, 1, flength, ffile) < flength) { perror("Read error.\n"); return -1; } fclose(ffile); fclose(ifile); /* verify format of input files */ //if (ilength < 0x10 || memcmp(ibuf, isig, sizeof(isig))) //{ // perror("Rockbox bootloader format error (is it bootloader.bin?).\n"); // return -1; //} if (flength < 0x1030-0x10000+BOOTLOADER_LIMIT || memcmp(fbuf+0x1030, fsig, sizeof(fsig))) { perror("Firmware format error.\n"); return -1; } /* verify firmware is not overrun */ for (i = ROCKBOX_BOOTLOADER; i < BOOTLOADER_LIMIT; i++) { if (fbuf[0x1030-0x10000+i] != 0xff) { perror("Firmware has changed too much.\n"); return -1; } } do_patch(fbuf, ibuf, ilength); /* recalc checksum */ for (i = 0x1030; i < flength; i++) sum += fbuf[i]; fbuf[0x102b] = sum; if ((ofile = fopen(argv[2], "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); }