rockbox/utils/MTP/beastpatcher/beastpatcher.c
Dominik Riebeling 9d242ab167 Add error messages to a few more failure cases to beastpatcher.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26978 a1c6a512-1295-4272-9138-f99709370657
2010-06-19 21:27:43 +00:00

287 lines
8.3 KiB
C

/***************************************************************************
* __________ __ ___.
* 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 <stdio.h>
#if !defined(_MSC_VER)
#include <unistd.h>
#include <fcntl.h>
#endif
#include <string.h>
#include <stdlib.h>
#if !defined(_MSC_VER)
#include <inttypes.h>
#else
#include "pstdint.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#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) {
fprintf(stderr,"[ERR] Reading bootloader file failed.\n");
return 1;
}
}
if (firmfile) {
if(readfile(firmfile, &firmware) != 0) {
fprintf(stderr,"[ERR] Reading firmware file failed.\n");
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. */
if(mknkboot(&firmware, &bootloader, &fw))
{
fprintf(stderr,"[ERR] Creating dualboot firmware failed.\n");
return 1;
}
}
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)
{
fprintf(stderr,"[ERR] Creating the bootloader failed.\n");
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;
}