/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * * $Id$ * * Copyright (c) 2009, Dave Chapman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ #include #if !defined(_MSC_VER) #include #include #endif #include #include #if !defined(_MSC_VER) #include #else #include "pstdint.h" #endif #include #include #include "mtp_common.h" #include "bootimg.h" #include "mknkboot.h" /* Code to create a single-boot bootloader. Based on tools/gigabeats.c by Will Robertson. */ /* Entry point (and load address) for the main Rockbox bootloader */ #define BL_ENTRY_POINT 0x8a000000 static void put_uint32le(uint32_t x, unsigned char* p) { p[0] = (unsigned char)(x & 0xff); p[1] = (unsigned char)((x >> 8) & 0xff); p[2] = (unsigned char)((x >> 16) & 0xff); p[3] = (unsigned char)((x >> 24) & 0xff); } static uint32_t calc_csum(const unsigned char* pb, int cb) { uint32_t l = 0; while (cb--) l += *pb++; return l; } static void create_single_boot(unsigned char* boot, int bootlen, unsigned char** fwbuf, off_t* fwsize) { unsigned char* buf; /* 15 bytes for header, 16 for signature bypass, * 12 for record header, size of bootloader, 12 for footer */ *fwsize = 15 + 16 + 12 + bootlen + 12; *fwbuf = malloc(*fwsize); if(fwbuf == NULL) { fprintf(stderr, "[ERR] Cannot allocate memory.\n" ); *fwbuf = NULL; *fwsize = 0; return; } buf = *fwbuf; /* Copy bootloader image. */ memcpy(buf + 43, boot, bootlen); /* Step 2: Create the file header */ sprintf((char *)buf, "B000FF\n"); put_uint32le(0x88200000, buf+7); /* If the value below is too small, the update will attempt to flash. * Be careful when changing this (leaving it as is won't cause issues) */ put_uint32le(0xCC0CD8, buf+11); /* Step 3: Add the signature bypass record */ put_uint32le(0x88065A10, buf+15); put_uint32le(4, buf+19); put_uint32le(0xE3A00001, buf+27); put_uint32le(calc_csum(buf+27,4), buf+23); /* Step 4: Create a record for the actual code */ put_uint32le(BL_ENTRY_POINT, buf+31); put_uint32le(bootlen, buf+35); put_uint32le(calc_csum(buf + 43, bootlen), buf+39); /* Step 5: Write the footer */ put_uint32le(0, buf+*fwsize-12); put_uint32le(BL_ENTRY_POINT, buf+*fwsize-8); put_uint32le(0, buf+*fwsize-4); return; } static int readfile(const char* filename, struct filebuf *buf) { int res; FILE* fp; size_t bread; #ifdef _LARGEFILE64_SOURCE struct stat64 sb; res = stat64(filename, &sb); #else struct stat sb; res = stat(filename, &sb); #endif if(res == -1) { fprintf(stderr, "[ERR] Getting firmware file size failed!\n"); return 1; } buf->len = sb.st_size; buf->buf = (unsigned char*)malloc(buf->len); /* load firmware binary to memory. */ fp = fopen(filename, "rb"); bread = fread(buf->buf, sizeof(unsigned char), buf->len, fp); if((off_t)(bread * sizeof(unsigned char)) != buf->len) { fprintf(stderr, "[ERR] Error reading file %s!\n", filename); return 1; } fclose(fp); return 0; } int beastpatcher(const char* bootfile, const char* firmfile, int interactive) { char yesno[4]; struct mtp_info_t mtp_info; struct filebuf bootloader; struct filebuf firmware; struct filebuf fw; bootloader.buf = bootimg; bootloader.len = LEN_bootimg; if (bootfile) { if(readfile(bootfile, &bootloader) != 0) { return 1; } } if (firmfile) { if(readfile(firmfile, &firmware) != 0) { return 1; } } if (mtp_init(&mtp_info) < 0) { fprintf(stderr,"[ERR] Can not init MTP\n"); return 1; } /* Scan for attached MTP devices. */ if (mtp_scan(&mtp_info) < 0) { fprintf(stderr,"[ERR] No devices found\n"); return 1; } printf("[INFO] Found device \"%s - %s\"\n", mtp_info.manufacturer, mtp_info.modelname); printf("[INFO] Device version: \"%s\"\n",mtp_info.version); if (interactive) { if(firmfile) { printf("\nEnter i to install the Rockbox dualboot bootloader or c " "to cancel and do nothing (i/c): "); } else { printf("\nEnter i to install the Rockbox bootloader or c to cancel " "and do nothing (i/c): "); } fgets(yesno,4,stdin); } if (!interactive || yesno[0]=='i') { if(firmfile) { /* if a firmware file is given create a dualboot image. */ mknkboot(&firmware, &bootloader, &fw); } else { /* Create a single-boot bootloader from the embedded bootloader */ create_single_boot(bootloader.buf, bootloader.len, &fw.buf, &fw.len); } if (fw.buf == NULL) return 1; if (mtp_send_firmware(&mtp_info, fw.buf, fw.len) == 0) { fprintf(stderr,"[INFO] Bootloader installed successfully.\n"); } else { fprintf(stderr,"[ERR] Bootloader install failed.\n"); } /* We are now done with the firmware image */ free(fw.buf); } else { fprintf(stderr,"[INFO] Installation cancelled.\n"); } if(bootfile) { free(bootloader.buf); } if(firmfile) { free(firmware.buf); } mtp_finished(&mtp_info); return 0; } int sendfirm(const char* filename) { struct mtp_info_t mtp_info; if (mtp_init(&mtp_info) < 0) { fprintf(stderr,"[ERR] Can not init MTP\n"); return 1; } /* Scan for attached MTP devices. */ if (mtp_scan(&mtp_info) < 0) { fprintf(stderr,"[ERR] No devices found\n"); return 1; } printf("[INFO] Found device \"%s - %s\"\n", mtp_info.manufacturer, mtp_info.modelname); printf("[INFO] Device version: \"%s\"\n",mtp_info.version); mtp_send_file(&mtp_info, filename); mtp_finished(&mtp_info); return 0; }