2008-10-11 13:11:47 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
2008-10-11 13:13:44 +00:00
|
|
|
* $Id$
|
2008-10-11 13:11:47 +00:00
|
|
|
*
|
|
|
|
* mkamsboot.c - a tool for merging bootloader code into an Sansa V2
|
|
|
|
* (AMS) firmware file
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008 Dave Chapman
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2008-05-11 18:29:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
Insert a Rockbox bootloader into an AMS original firmware file.
|
|
|
|
|
2008-10-02 12:37:47 +00:00
|
|
|
We replace the main firmware block (bytes 0x400..0x400+firmware_size)
|
|
|
|
as follows:
|
|
|
|
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
---------------------- 0x0
|
|
|
|
| |
|
|
|
|
| Dual-boot code |
|
|
|
|
| |
|
|
|
|
|----------------------|
|
|
|
|
| EMPTY SPACE |
|
|
|
|
|----------------------|
|
|
|
|
| |
|
|
|
|
| compressed RB image |
|
|
|
|
| |
|
|
|
|
|----------------------|
|
|
|
|
| |
|
|
|
|
| compressed OF image |
|
|
|
|
| |
|
|
|
|
|----------------------|
|
|
|
|
| UCL unpack function |
|
|
|
|
----------------------
|
2008-10-02 12:37:47 +00:00
|
|
|
|
|
|
|
This entire block fits into the space previously occupied by the main
|
2008-10-11 11:35:59 +00:00
|
|
|
firmware block - the space saved by compressing the OF image is used
|
|
|
|
to store the compressed version of the Rockbox bootloader. The OF
|
|
|
|
image is typically about 120KB, which allows us to store a Rockbox
|
|
|
|
bootloader with an uncompressed size of about 60KB-70KB.
|
2008-10-02 12:37:47 +00:00
|
|
|
|
|
|
|
mkamsboot then corrects the checksums and writes a new legal firmware
|
|
|
|
file which can be installed on the device.
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
When the Sansa device boots, this firmware block is loaded to RAM at
|
|
|
|
address 0x0 and executed.
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
Firstly, the dual-boot code will copy the UCL unpack function to the
|
|
|
|
end of RAM.
|
|
|
|
|
|
|
|
Then, depending on the detection of the dual-boot keypress, either the
|
|
|
|
OF image or the Rockbox image is copied to the end of RAM (just before
|
|
|
|
the ucl unpack function) and uncompress it to the start of RAM.
|
|
|
|
|
|
|
|
Finally, the ucl unpack function branches to address 0x0, passing
|
|
|
|
execution to the uncompressed firmware.
|
2008-10-01 09:15:44 +00:00
|
|
|
|
|
|
|
|
2008-05-11 18:29:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
#include <ucl/ucl.h>
|
|
|
|
|
|
|
|
/* Headers for ARM code binaries */
|
|
|
|
#include "uclimg.h"
|
|
|
|
#include "bootimg_clip.h"
|
|
|
|
#include "bootimg_e200v2.h"
|
2008-05-11 18:29:53 +00:00
|
|
|
|
|
|
|
/* Win32 compatibility */
|
|
|
|
#ifndef O_BINARY
|
|
|
|
#define O_BINARY 0
|
|
|
|
#endif
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
#ifndef VERSION
|
|
|
|
#define VERSION "0.1"
|
|
|
|
#endif
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
MODEL_UNKNOWN = -1,
|
|
|
|
MODEL_FUZE = 0,
|
|
|
|
MODEL_CLIP,
|
|
|
|
MODEL_CLIPV2,
|
|
|
|
MODEL_E200,
|
|
|
|
MODEL_M200,
|
|
|
|
MODEL_C200
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char* model_names[] =
|
|
|
|
{
|
|
|
|
"Fuze",
|
|
|
|
"Clip",
|
|
|
|
"Clip V2",
|
|
|
|
"E200",
|
|
|
|
"M200",
|
|
|
|
"C200"
|
|
|
|
};
|
|
|
|
|
|
|
|
static const unsigned char* bootloaders[] =
|
|
|
|
{
|
|
|
|
NULL,
|
|
|
|
bootimg_clip,
|
|
|
|
NULL,
|
|
|
|
bootimg_e200v2,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const int bootloader_sizes[] =
|
|
|
|
{
|
|
|
|
0,
|
|
|
|
sizeof(bootimg_clip),
|
|
|
|
0,
|
|
|
|
sizeof(bootimg_e200v2),
|
|
|
|
0,
|
|
|
|
0
|
|
|
|
};
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-12 19:34:47 +00:00
|
|
|
/* Model names used in the Rockbox header in ".sansa" files - these match the
|
|
|
|
-add parameter to the "scramble" tool */
|
|
|
|
static const char* rb_model_names[] =
|
|
|
|
{
|
|
|
|
NULL,
|
|
|
|
"clip",
|
|
|
|
NULL,
|
|
|
|
"e2v2",
|
2008-10-19 14:11:01 +00:00
|
|
|
"m2v2",
|
2008-10-12 19:34:47 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Model numbers used to initialise the checksum in the Rockbox header in
|
|
|
|
".sansa" files - these are the same as MODEL_NUMBER in config-target.h */
|
|
|
|
static const int rb_model_num[] =
|
|
|
|
{
|
|
|
|
0,
|
2008-10-19 14:11:01 +00:00
|
|
|
40,
|
2008-10-12 19:34:47 +00:00
|
|
|
0,
|
2008-10-19 14:11:01 +00:00
|
|
|
41,
|
|
|
|
42,
|
2008-10-12 19:34:47 +00:00
|
|
|
0
|
|
|
|
};
|
|
|
|
|
2008-05-11 18:29:53 +00:00
|
|
|
|
|
|
|
static off_t filesize(int fd) {
|
|
|
|
struct stat buf;
|
|
|
|
|
|
|
|
if (fstat(fd,&buf) < 0) {
|
|
|
|
perror("[ERR] Checking filesize of input file");
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return(buf.st_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t get_uint32le(unsigned char* p)
|
|
|
|
{
|
|
|
|
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
|
|
|
}
|
|
|
|
|
2008-10-12 19:34:47 +00:00
|
|
|
static uint32_t get_uint32be(unsigned char* p)
|
|
|
|
{
|
|
|
|
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
|
|
|
|
}
|
|
|
|
|
2008-05-11 18:29:53 +00:00
|
|
|
static void put_uint32le(unsigned char* p, uint32_t x)
|
|
|
|
{
|
|
|
|
p[0] = x & 0xff;
|
|
|
|
p[1] = (x >> 8) & 0xff;
|
|
|
|
p[2] = (x >> 16) & 0xff;
|
|
|
|
p[3] = (x >> 24) & 0xff;
|
|
|
|
}
|
|
|
|
|
2008-10-12 19:34:47 +00:00
|
|
|
static uint32_t calc_checksum(unsigned char* buf, uint32_t n)
|
2008-05-11 18:29:53 +00:00
|
|
|
{
|
|
|
|
uint32_t sum = 0;
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
for (i=0;i<n;i+=4)
|
|
|
|
sum += get_uint32le(buf + i);
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
static int get_model(int model_id)
|
2008-05-11 18:29:53 +00:00
|
|
|
{
|
2008-10-11 11:35:59 +00:00
|
|
|
switch(model_id)
|
|
|
|
{
|
|
|
|
case 0x1e:
|
|
|
|
return MODEL_FUZE;
|
|
|
|
case 0x22:
|
|
|
|
return MODEL_CLIP;
|
|
|
|
case 0x23:
|
|
|
|
return MODEL_C200;
|
|
|
|
case 0x24:
|
|
|
|
return MODEL_E200;
|
|
|
|
case 0x25:
|
|
|
|
return MODEL_M200;
|
|
|
|
case 0x27:
|
|
|
|
return MODEL_CLIPV2;
|
|
|
|
}
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
return MODEL_UNKNOWN;
|
2008-05-11 18:29:53 +00:00
|
|
|
}
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
|
|
|
|
static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize)
|
2008-05-11 18:29:53 +00:00
|
|
|
{
|
2008-10-11 11:35:59 +00:00
|
|
|
int maxsize;
|
|
|
|
unsigned char* outbuf;
|
|
|
|
int r;
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* The following formula comes from the UCL documentation */
|
|
|
|
maxsize = insize + (insize / 8) + 256;
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* Allocate some memory for the output buffer */
|
|
|
|
outbuf = malloc(maxsize);
|
|
|
|
|
|
|
|
if (outbuf == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = ucl_nrv2e_99_compress(
|
|
|
|
(const ucl_bytep) inbuf,
|
|
|
|
(ucl_uint) insize,
|
|
|
|
(ucl_bytep) outbuf,
|
|
|
|
(ucl_uintp) outsize,
|
|
|
|
0, 10, NULL, NULL);
|
|
|
|
|
|
|
|
if (r != UCL_E_OK || *outsize > maxsize)
|
2008-05-11 18:29:53 +00:00
|
|
|
{
|
2008-10-11 11:35:59 +00:00
|
|
|
/* this should NEVER happen, and implies memory corruption */
|
|
|
|
fprintf(stderr, "internal error - compression failed: %d\n", r);
|
|
|
|
free(outbuf);
|
|
|
|
return NULL;
|
2008-05-11 18:29:53 +00:00
|
|
|
}
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
return outbuf;
|
|
|
|
}
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
static unsigned char* load_file(char* filename, off_t* bufsize)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
unsigned char* buf;
|
|
|
|
off_t n;
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
fd = open(filename, O_RDONLY|O_BINARY);
|
|
|
|
if (fd < 0)
|
2008-10-01 09:15:44 +00:00
|
|
|
{
|
2008-10-11 11:35:59 +00:00
|
|
|
fprintf(stderr,"[ERR] Could not open %s for reading\n",filename);
|
|
|
|
return NULL;
|
2008-10-01 09:15:44 +00:00
|
|
|
}
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
*bufsize = filesize(fd);
|
2008-10-01 09:15:44 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
buf = malloc(*bufsize);
|
|
|
|
if (buf == NULL) {
|
|
|
|
fprintf(stderr,"[ERR] Could not allocate memory for %s\n",filename);
|
|
|
|
return NULL;
|
2008-10-01 09:15:44 +00:00
|
|
|
}
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
n = read(fd, buf, *bufsize);
|
2008-10-01 18:28:55 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
if (n != *bufsize) {
|
|
|
|
fprintf(stderr,"[ERR] Could not read file %s\n",filename);
|
|
|
|
return NULL;
|
2008-10-01 18:28:55 +00:00
|
|
|
}
|
2008-10-01 09:15:44 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-12 19:34:47 +00:00
|
|
|
static unsigned char* load_rockbox_file(char* filename, int model, off_t* bufsize)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
unsigned char* buf;
|
|
|
|
unsigned char header[8];
|
|
|
|
uint32_t sum;
|
|
|
|
off_t n;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
fd = open(filename, O_RDONLY|O_BINARY);
|
|
|
|
if (fd < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"[ERR] Could not open %s for reading\n",filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read Rockbox header */
|
|
|
|
n = read(fd, header, sizeof(header));
|
|
|
|
if (n != sizeof(header)) {
|
|
|
|
fprintf(stderr,"[ERR] Could not read file %s\n",filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for correct model string */
|
|
|
|
if (memcmp(rb_model_names[model],header + 4,4)!=0) {
|
|
|
|
fprintf(stderr,"[ERR] Model name \"%s\" not found in %s\n",
|
|
|
|
rb_model_names[model],filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
*bufsize = filesize(fd) - sizeof(header);
|
|
|
|
|
|
|
|
buf = malloc(*bufsize);
|
|
|
|
if (buf == NULL) {
|
|
|
|
fprintf(stderr,"[ERR] Could not allocate memory for %s\n",filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = read(fd, buf, *bufsize);
|
|
|
|
|
|
|
|
if (n != *bufsize) {
|
|
|
|
fprintf(stderr,"[ERR] Could not read file %s\n",filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check checksum */
|
|
|
|
sum = rb_model_num[model];
|
|
|
|
for (i = 0; i < *bufsize; i++) {
|
|
|
|
/* add 8 unsigned bits but keep a 32 bit sum */
|
|
|
|
sum += buf[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sum != get_uint32be(header)) {
|
|
|
|
fprintf(stderr,"[ERR] Checksum mismatch in %s\n",filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
char *infile, *bootfile, *outfile;
|
|
|
|
int fdout;
|
|
|
|
off_t len;
|
|
|
|
uint32_t n;
|
|
|
|
unsigned char* buf;
|
|
|
|
int firmware_size;
|
|
|
|
off_t bootloader_size;
|
|
|
|
uint32_t sum,filesum;
|
|
|
|
uint8_t model_id;
|
|
|
|
int model;
|
|
|
|
uint32_t i;
|
|
|
|
unsigned char* of_packed;
|
|
|
|
int of_packedsize;
|
|
|
|
unsigned char* rb_unpacked;
|
|
|
|
unsigned char* rb_packed;
|
|
|
|
int rb_packedsize;
|
|
|
|
int fw_version;
|
|
|
|
int totalsize;
|
|
|
|
unsigned char* p;
|
|
|
|
|
2008-10-11 13:13:44 +00:00
|
|
|
fprintf(stderr,"mkamsboot v" VERSION " - (C) Dave Chapman and Rafaël Carré 2008\n");
|
2008-10-11 11:35:59 +00:00
|
|
|
fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
|
|
|
|
fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
|
|
|
|
|
|
|
|
if(argc != 4) {
|
|
|
|
printf("Usage: mkamsboot <firmware file> <boot file> <output file>\n\n");
|
2008-10-01 18:28:55 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
infile = argv[1];
|
|
|
|
bootfile = argv[2];
|
|
|
|
outfile = argv[3];
|
|
|
|
|
|
|
|
/* Load original firmware file */
|
|
|
|
buf = load_file(infile, &len);
|
|
|
|
|
|
|
|
if (buf == NULL) {
|
|
|
|
fprintf(stderr,"[ERR] Could not load bootloader file\n");
|
2008-10-01 18:28:55 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2008-10-01 09:15:44 +00:00
|
|
|
|
2008-10-12 19:34:47 +00:00
|
|
|
/* TODO: Do some more sanity checks on the OF image */
|
|
|
|
|
|
|
|
if (get_uint32le(buf + len - 4) != calc_checksum(buf, len - 4)) {
|
|
|
|
fprintf(stderr,"[ERR] Whole file checksum failed - %s\n",infile);
|
|
|
|
return 1;
|
|
|
|
}
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
if (get_uint32le(&buf[0x204])==0x0000f000) {
|
|
|
|
fw_version = 2;
|
|
|
|
model_id = buf[0x219];
|
|
|
|
} else {
|
|
|
|
fw_version = 1;
|
|
|
|
model_id = buf[0x215];
|
2008-05-11 18:29:53 +00:00
|
|
|
}
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
model = get_model(model_id);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
if (model == MODEL_UNKNOWN) {
|
|
|
|
fprintf(stderr,"[ERR] Unknown firmware - model id 0x%02x\n",model_id);
|
2008-05-11 18:29:53 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
if (bootloaders[model] == NULL) {
|
|
|
|
fprintf(stderr,"[ERR] Unsupported model - \"%s\"\n",model_names[model]);
|
|
|
|
free(buf);
|
|
|
|
free(rb_unpacked);
|
2008-05-11 18:29:53 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-10-12 19:34:47 +00:00
|
|
|
/* Load bootloader file */
|
|
|
|
rb_unpacked = load_rockbox_file(bootfile, model, &bootloader_size);
|
|
|
|
if (rb_unpacked == NULL) {
|
|
|
|
fprintf(stderr,"[ERR] Could not load %s\n",bootfile);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
printf("[INFO] Patching %s firmware\n",model_names[model]);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
|
|
|
/* Get the firmware size */
|
|
|
|
firmware_size = get_uint32le(&buf[0x0c]);
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* Compress the original firmware image */
|
|
|
|
of_packed = uclpack(buf + 0x400, firmware_size, &of_packedsize);
|
|
|
|
if (of_packed == NULL) {
|
|
|
|
fprintf(stderr,"[ERR] Could not compress original firmware\n");
|
|
|
|
free(buf);
|
|
|
|
free(rb_unpacked);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_packed = uclpack(rb_unpacked, bootloader_size, &rb_packedsize);
|
|
|
|
if (rb_packed == NULL) {
|
|
|
|
fprintf(stderr,"[ERR] Could not compress %s\n",bootfile);
|
|
|
|
free(buf);
|
|
|
|
free(rb_unpacked);
|
|
|
|
free(of_packed);
|
|
|
|
return 1;
|
|
|
|
}
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* We are finished with the unpacked version of the bootloader */
|
|
|
|
free(rb_unpacked);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
fprintf(stderr,"[INFO] Original firmware size: %d bytes\n",firmware_size);
|
|
|
|
fprintf(stderr,"[INFO] Packed OF size: %d bytes\n",of_packedsize);
|
|
|
|
fprintf(stderr,"[INFO] Bootloader size: %d bytes\n",(int)bootloader_size);
|
|
|
|
fprintf(stderr,"[INFO] Packed bootloader size: %d bytes\n",rb_packedsize);
|
|
|
|
fprintf(stderr,"[INFO] Dual-boot function size: %d bytes\n",bootloader_sizes[model]);
|
|
|
|
fprintf(stderr,"[INFO] UCL unpack function size: %d bytes\n",sizeof(uclimg));
|
2008-10-01 09:15:44 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
totalsize = bootloader_sizes[model] + sizeof(uclimg) + of_packedsize +
|
|
|
|
rb_packedsize;
|
|
|
|
|
|
|
|
fprintf(stderr,"[INFO] Total size of new image: %d bytes\n",totalsize);
|
|
|
|
|
|
|
|
if (totalsize > firmware_size) {
|
|
|
|
fprintf(stderr,"[ERR] No room to insert bootloader, aborting\n");
|
|
|
|
free(buf);
|
|
|
|
free(rb_unpacked);
|
|
|
|
free(of_packed);
|
2008-10-01 09:15:44 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-01 09:15:44 +00:00
|
|
|
/* Zero the original firmware area - not needed, but helps debugging */
|
|
|
|
memset(buf + 0x400, 0, firmware_size);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* Insert dual-boot bootloader at offset 0 */
|
|
|
|
memcpy(buf + 0x400, bootloaders[model], bootloader_sizes[model]);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* We are filling the firmware buffer backwards from the end */
|
|
|
|
p = buf + 0x400 + firmware_size;
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* 1 - UCL unpack function */
|
|
|
|
p -= sizeof(uclimg);
|
|
|
|
memcpy(p, uclimg, sizeof(uclimg));
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* 2 - Compressed copy of original firmware */
|
|
|
|
p -= of_packedsize;
|
|
|
|
memcpy(p, of_packed, of_packedsize);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* 3 - Compressed copy of Rockbox bootloader */
|
|
|
|
p -= rb_packedsize;
|
|
|
|
memcpy(p, rb_packed, rb_packedsize);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* Write the locations of the various images to the variables at the
|
|
|
|
start of the dualboot image - we save the location of the last byte
|
|
|
|
in each image, along with the size in bytes */
|
|
|
|
|
|
|
|
/* UCL unpack function */
|
2008-10-11 12:02:23 +00:00
|
|
|
put_uint32le(&buf[0x420], firmware_size - 1);
|
2008-10-11 11:35:59 +00:00
|
|
|
put_uint32le(&buf[0x424], sizeof(uclimg));
|
|
|
|
|
|
|
|
/* Compressed original firmware image */
|
2008-10-11 12:02:23 +00:00
|
|
|
put_uint32le(&buf[0x428], firmware_size - sizeof(uclimg) - 1);
|
2008-10-11 11:35:59 +00:00
|
|
|
put_uint32le(&buf[0x42c], of_packedsize);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
/* Compressed Rockbox image */
|
2008-10-11 12:02:23 +00:00
|
|
|
put_uint32le(&buf[0x430], firmware_size - sizeof(uclimg) - of_packedsize - 1);
|
2008-10-11 11:35:59 +00:00
|
|
|
put_uint32le(&buf[0x434], rb_packedsize);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
|
|
|
|
/* Update the firmware block checksum */
|
2008-10-02 12:37:47 +00:00
|
|
|
sum = calc_checksum(buf + 0x400,firmware_size);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
2008-10-11 11:35:59 +00:00
|
|
|
if (fw_version == 1) {
|
|
|
|
put_uint32le(&buf[0x04], sum);
|
|
|
|
put_uint32le(&buf[0x204], sum);
|
|
|
|
} else {
|
|
|
|
/* TODO: Verify that this is correct for the v2 firmware */
|
|
|
|
|
|
|
|
put_uint32le(&buf[0x08], sum);
|
|
|
|
put_uint32le(&buf[0x208], sum);
|
|
|
|
|
|
|
|
/* Update the header checksums */
|
|
|
|
put_uint32le(&buf[0x1fc], calc_checksum(buf, 0x1fc));
|
|
|
|
put_uint32le(&buf[0x3fc], calc_checksum(buf + 0x200, 0x1fc));
|
|
|
|
}
|
2008-05-11 18:29:53 +00:00
|
|
|
|
|
|
|
/* Update the whole-file checksum */
|
|
|
|
filesum = 0;
|
2008-10-01 09:15:44 +00:00
|
|
|
for (i=0;i < (unsigned)len - 4; i+=4)
|
2008-05-11 18:29:53 +00:00
|
|
|
filesum += get_uint32le(&buf[i]);
|
|
|
|
|
2008-10-01 09:15:44 +00:00
|
|
|
put_uint32le(buf + len - 4, filesum);
|
2008-05-11 18:29:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Write the new firmware */
|
|
|
|
fdout = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
|
|
|
|
|
|
|
|
if (fdout < 0) {
|
|
|
|
fprintf(stderr,"[ERR] Could not open %s for writing\n",outfile);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-10-01 09:15:44 +00:00
|
|
|
n = write(fdout, buf, len);
|
|
|
|
|
|
|
|
if (n != (unsigned)len) {
|
|
|
|
fprintf(stderr,"[ERR] Could not write firmware file\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2008-05-11 18:29:53 +00:00
|
|
|
|
|
|
|
close(fdout);
|
|
|
|
|
2008-10-11 12:51:13 +00:00
|
|
|
fprintf(stderr," *****************************************************************************\n");
|
|
|
|
fprintf(stderr," *** THIS CODE IS UNTESTED - DO NOT USE IF YOU CAN NOT RECOVER YOUR DEVICE ***\n");
|
|
|
|
fprintf(stderr," *****************************************************************************\n");
|
|
|
|
|
2008-05-11 18:29:53 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|