Major rework of mkamsboot, extending work done by Rafael Carre. We now build one "dualboot.bin" mini-bootloader per target and embed it in the mkamsboot binary. The user of mkamsboot just needs to provide an original firmware file, and a Rockbox bootloader file. This code currently supports just the Clip (hardware revision 1) and the E200v2 - button checks are needed for the other V2 targets. NOTE: This is completely untested on-target, and may brick your device.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18767 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Dave Chapman 2008-10-11 11:35:59 +00:00
parent ced0adc527
commit 1c4bcfac69
6 changed files with 623 additions and 247 deletions

View file

@ -1,56 +1,94 @@
# Change INFILE to point to your original firmware file
INFILE=$(HOME)/FW/AMS/CLIP/m300a-1.1.17A.bin
# OUTFILE is the file you copy to your device's root and rename to
# (e.g.) m300a.bin
OUTFILE=patched.bin
# We use the UCL code available in the Rockbox tools/ directory
# The uclpack command
UCLPACK=../../tools/uclpack
CFLAGS=-I../../tools/ucl/include
LIBUCL=../../tools/ucl/src/libucl.a
all: $(OUTFILE)
# Edit the following variables (plus copy/paste another set of rules) when
# adding a new target. mkamsboot.c also needs to be edited to refer to these
# new images.
#
# If anyone reading this wants to improve this makefile, please do!
mkamsboot: mkamsboot.c
gcc -o mkamsboot -W -Wall mkamsboot.c
BOOTIMAGES = bootimg_clip.o bootimg_e200v2.o
BOOTHEADERS = bootimg_clip.h bootimg_e200v2.h
extract_fw: extract_fw.c
gcc -o extract_fw -W -Wall extract_fw.c
CLIPFILES = dualboot-clip.o dualboot-clip.elf dualboot-clip.o \
dualboot-clip.bin bootimg_clip.c bootimg_clip.h
E200V2FILES = dualboot-e200v2.o dualboot-e200v2.elf dualboot-e200v2.o \
dualboot-e200v2.bin bootimg_e200v2.c bootimg_e200v2.h
all: mkamsboot
$(LIBUCL):
make -C ../../tools/ucl/src libucl.a
mkamsboot.o: mkamsboot.c $(BOOTHEADERS) uclimg.h
gcc $(CFLAGS) -c -o mkamsboot.o -W -Wall mkamsboot.c
mkamsboot: mkamsboot.o $(BOOTIMAGES) uclimg.o $(LIBUCL)
gcc -o mkamsboot mkamsboot.o $(BOOTIMAGES) uclimg.o $(LIBUCL)
# Rules for our test ARM application - assemble, link, then extract
# the binary code
test.o: test.S
arm-elf-as -o test.o test.S
# CLIP
test.elf: test.o
arm-elf-ld -e 0 -Ttext=0 -o test.elf test.o
dualboot-clip.o: dualboot.S
arm-elf-gcc -DSANSA_CLIP -c -o dualboot-clip.o dualboot.S
test.bin: test.elf
arm-elf-objcopy -O binary test.elf test.bin
dualboot-clip.elf: dualboot-clip.o
arm-elf-ld -e 0 -Ttext=0 -o dualboot-clip.elf dualboot-clip.o
# Rules for the ucl unpack function - this is inserted in the padding at
# the end of the original firmware block
dualboot-clip.bin: dualboot-clip.elf
arm-elf-objcopy -O binary dualboot-clip.elf dualboot-clip.bin
bootimg_clip.c bootimg_clip.h: dualboot-clip.bin bin2c
./bin2c dualboot-clip.bin bootimg_clip
bootimg_clip.o: bootimg_clip.c
gcc -c -o bootimg_clip.o bootimg_clip.c
# E200V2
dualboot-e200v2.o: dualboot.S
arm-elf-gcc -DSANSA_E200V2 -c -o dualboot-e200v2.o dualboot.S
dualboot-e200v2.elf: dualboot-e200v2.o
arm-elf-ld -e 0 -Ttext=0 -o dualboot-e200v2.elf dualboot-e200v2.o
dualboot-e200v2.bin: dualboot-e200v2.elf
arm-elf-objcopy -O binary dualboot-e200v2.elf dualboot-e200v2.bin
bootimg_e200v2.c bootimg_e200v2.h: dualboot-e200v2.bin bin2c
./bin2c dualboot-e200v2.bin bootimg_e200v2
bootimg_e200v2.o: bootimg_e200v2.c
gcc -c -o bootimg_e200v2.o bootimg_e200v2.c
# Rules for the ucl unpack function
nrv2e_d8.o: nrv2e_d8.S
arm-elf-gcc -DPURE_THUMB -c -o nrv2e_d8.o nrv2e_d8.S
# NOTE: this function has no absolute references, so the link address (-e)
# is irrelevant. We just link at address 0.
# is irrelevant. We just link at address 0, but it can run from anywhere.
nrv2e_d8.elf: nrv2e_d8.o
arm-elf-ld -e 0 -Ttext=0 -o nrv2e_d8.elf nrv2e_d8.o
nrv2e_d8.bin: nrv2e_d8.elf
arm-elf-objcopy -O binary nrv2e_d8.elf nrv2e_d8.bin
firmware_block.ucl: firmware_block.bin
$(UCLPACK) --best --2e firmware_block.bin firmware_block.ucl
uclimg.c uclimg.h: nrv2e_d8.bin bin2c
./bin2c nrv2e_d8.bin uclimg
firmware_block.bin: $(INFILE) extract_fw
./extract_fw $(INFILE) firmware_block.bin
uclimg.o: uclimg.c
gcc -c -o uclimg.o uclimg.c
$(OUTFILE): mkamsboot firmware_block.ucl test.bin nrv2e_d8.bin $(INFILE)
./mkamsboot $(INFILE) firmware_block.ucl test.bin nrv2e_d8.bin $(OUTFILE)
bin2c: bin2c.c
gcc -o bin2c bin2c.c
clean:
rm -fr amsinfo mkamsboot test.o test.elf test.bin extract_fw \
nrv2e_d8.o nrv2e_d8.elf nrv2e_d8.bin firmware_block.bin \
firmware_block.ucl $(OUTFILE) *~
rm -f mkamsboot mkamsboot.o nrv2e_d8.o nrv2e_d8.elf nrv2e_d8.bin *~ \
bin2c uclimg.c uclimg.h uclimg.o \
$(BOOTIMAGES) $(CLIPFILES) $(E200V2FILES)

View file

@ -1,10 +1,6 @@
mkamsboot
---------
A tool to inject some code (contained in test.S) into a firmware file.
Edit the INFILE variable in the Makefile to point to the original
firmware file you want to patch, edit "test.S" appropriately, and then
type "make".
A tool to inject a bootloader into a Sansa V2 (AMS) firmware file.
See comments in mkamsboot.c and dualboot.S for more information.

134
rbutil/mkamsboot/bin2c.c Normal file
View file

@ -0,0 +1,134 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 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.
*
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
static off_t filesize(int fd)
{
struct stat buf;
fstat(fd,&buf);
return buf.st_size;
}
static int write_cfile(const unsigned char* buf, off_t len, const char* cname)
{
char filename[256];
FILE* fp;
int i;
snprintf(filename,256,"%s.c",cname);
fp = fopen(filename,"w+");
if (fp == NULL) {
fprintf(stderr,"Couldn't open %s\n",filename);
return -1;
}
fprintf(fp,"/* Generated by bin2c */\n\n");
fprintf(fp,"unsigned char %s[%d] = {",cname,len);
for (i=0;i<len;i++) {
if ((i % 16) == 0) {
fprintf(fp,"\n ");
}
if (i == (len-1)) {
fprintf(fp,"0x%02x",buf[i]);
} else {
fprintf(fp,"0x%02x, ",buf[i]);
}
}
fprintf(fp,"\n};\n");
fclose(fp);
return 0;
}
static int write_hfile(off_t len, const char* cname)
{
char filename[256];
FILE* fp;
snprintf(filename,256,"%s.h",cname);
fp = fopen(filename,"w+");
if (fp == NULL) {
fprintf(stderr,"Couldn't open %s\n",filename);
return -1;
}
fprintf(fp,"/* Generated by bin2c */\n\n");
fprintf(fp,"extern unsigned char %s[%d];\n",cname,len);
fclose(fp);
return 0;
}
int main (int argc, char* argv[])
{
char* infile;
char* cname;
int fd;
unsigned char* buf;
int len;
int n;
if (argc != 3) {
fprintf(stderr,"Usage: bin2c file cname\n");
return 0;
}
infile=argv[1];
cname=argv[2];
fd = open(infile,O_RDONLY|O_BINARY);
if (fd < 0) {
fprintf(stderr,"Can not open %s\n",infile);
return 0;
}
len = filesize(fd);
buf = malloc(len);
n = read(fd,buf,len);
if (n < len) {
fprintf(stderr,"Short read, aborting\n");
return 0;
}
close(fd);
if (write_cfile(buf,len,cname) < 0) {
return -1;
}
if (write_hfile(len,cname) < 0) {
return -1;
}
return 0;
}

126
rbutil/mkamsboot/dualboot.S Normal file
View file

@ -0,0 +1,126 @@
.text
/* This is the size of the Clip's RAM, but there is nothing to be gained
(at the moment) by making use of the larger RAM of other targets */
.set DRAM_SIZE, 0x50000
.set GPIOA, 0xC80B0000
.set GPIOB, 0xC80C0000
.set GPIOC, 0xC80D0000
.set GPIOD, 0xC80E0000
.set CGU_PERI, 0xC80F0014
/* Vectors */
ldr pc, =start
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
/* These values are filled in by mkamsboot - don't move them from offset 0x20 */
uclunpack_end: .word 0 /* End of the ucl_unpack function */
uclunpack_size: .word 0 /* Size in bytes of the ucl_unpack function */
ucl_of_end: .word 0 /* End of the ucl-compressed OF image */
ucl_of_size: .word 0 /* Size in bytes of the compressed OF image */
ucl_rb_end: .word 0 /* End of the ucl-compressed RB image */
ucl_rb_size: .word 0 /* Size in bytes of the compressed RB image */
start:
/* First copy the UCL unpack function to the end of RAM */
ldr r0, uclunpack_end /* Source */
ldr r1, uclunpack_size /* Source length */
sub r2, r0, r1 /* Source start - 1*/
ldr r3, =DRAM_SIZE /* Destination end */
uclcopy:
ldrb r4, [r0], #-1
strb r4, [r3], #-1
cmp r2, r3
bne uclcopy
add r5, r2, #2 /* r5 is entry point of copy of uclunpack */
/* function, plus one (for thumb mode */
/* enable gpio clock */
ldr r0, =CGU_PERI
ldr r1, [r0]
orr r1, r1, #(1<<16)
str r1, [r0]
/* we check A3 unconditionally of the model because it seems to be */
/* either hold, either usb on every model */
ldr r0, =GPIOA
mov r1, #0
str r1, [r0, #0x400]
ldr r1, [r0, #0x20] /* read pin A3 */
cmp r1, #0
bne boot_of
/* here are model specific tests, for dual boot without a computer */
#ifdef SANSA_CLIP
/* HOME button */
ldr r0, =GPIOB
mov r1, #0
str r1, [r0, #0x400]
ldr r1, [r0, #0x10] /* read pin B2 */
cmp r1, #0
bne boot_of
#elif defined(SANSA_E200V2)
/* DOWN button */
ldr r0, =GPIOC
mov r1, #0
str r1, [r0, #0x400]
ldr r1, [r0, #0x100] /* read pin C6 */
cmp r1, #0 /* C6 = #0 means button pressed */
beq boot_of
#else
#error No target-specific key check defined!
#endif
/* No button was held, so we boot rockbox */
ldr r0, ucl_rb_end /* Address of compressed image */
ldr r1, ucl_rb_size /* Compressed size */
b decompress
boot_of:
ldr r0, ucl_of_end /* Address of compressed image */
ldr r1, ucl_of_size /* Compressed size */
decompress:
/* At this point: */
/* r5 = entry point (plus one for thumb) of uclunpack function */
/* r3 = destination_end for copy of UCL image */
/* r0 = source_end for UCL image to copy */
/* r1 = size of UCL image to copy */
sub r4, r3, r1 /* r4 := destination_start - 1 */
fw_copy:
ldrb r2, [r0], #-1
strb r2, [r3], #-1
cmp r3, r4 /* Stop when we reached dest_start-1 */
bne fw_copy
/* Call the ucl decompress function, which will branch to 0x0 */
/* on completion */
add r0, r3, #1 /* r0 := Start of compressed image */
/* r1 already contains compressed size */
mov r2, #0 /* r2 := Destination for unpacking */
bx r5 /* Branch to uclunpack, switching to thumb */
/* never reached */

View file

@ -30,36 +30,46 @@ We replace the main firmware block (bytes 0x400..0x400+firmware_size)
as follows:
--------------------- 0x0
| |
| Rockbox bootloader |
| |
|---------------------|
| EMPTY SPACE |
|---------------------|
| ucl unpack function |
|---------------------|
| |
| compressed OF image |
| |
| |
---------------------
---------------------- 0x0
| |
| Dual-boot code |
| |
|----------------------|
| EMPTY SPACE |
|----------------------|
| |
| compressed RB image |
| |
|----------------------|
| |
| compressed OF image |
| |
|----------------------|
| UCL unpack function |
----------------------
This entire block fits into the space previously occupied by the main
firmware block, and gives about 40KB of space to store the Rockbox
bootloader. This could be increased if we also UCL compress the
Rockbox bootloader.
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.
mkamsboot then corrects the checksums and writes a new legal firmware
file which can be installed on the device.
Our bootloader first checks for the "dual-boot" keypress, and then either:
When the Sansa device boots, this firmware block is loaded to RAM at
address 0x0 and executed.
a) Copies the ucl unpack function and compressed OF image to an unused
part of RAM and then branches to the ucl_unpack function, which
will then branch to 0x0 after decompressing the OF to that location.
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.
b) Continues running with our test code
*/
@ -73,14 +83,62 @@ b) Continues running with our test code
#include <unistd.h>
#include <string.h>
#include <ucl/ucl.h>
/* Headers for ARM code binaries */
#include "uclimg.h"
#include "bootimg_clip.h"
#include "bootimg_e200v2.h"
/* Win32 compatibility */
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifndef VERSION
#define VERSION "0.1"
#endif
#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
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
};
/* This magic should appear at the start of any UCL file */
@ -105,12 +163,6 @@ static uint32_t get_uint32le(unsigned char* p)
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
static uint32_t get_uint32be(unsigned char* p)
{
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
}
static void put_uint32le(unsigned char* p, uint32_t x)
{
p[0] = x & 0xff;
@ -130,186 +182,271 @@ static int calc_checksum(unsigned char* buf, uint32_t n)
return sum;
}
void usage(void)
static int get_model(int model_id)
{
printf("Usage: mkamsboot <firmware file> <ucl image> <boot file> <ucl unpack file> <output file>\n");
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;
}
exit(1);
return MODEL_UNKNOWN;
}
static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize)
{
int maxsize;
unsigned char* outbuf;
int r;
/* The following formula comes from the UCL documentation */
maxsize = insize + (insize / 8) + 256;
/* 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)
{
/* this should NEVER happen, and implies memory corruption */
fprintf(stderr, "internal error - compression failed: %d\n", r);
free(outbuf);
return NULL;
}
return outbuf;
}
static unsigned char* load_file(char* filename, off_t* bufsize)
{
int fd;
unsigned char* buf;
off_t n;
fd = open(filename, O_RDONLY|O_BINARY);
if (fd < 0)
{
fprintf(stderr,"[ERR] Could not open %s for reading\n",filename);
return NULL;
}
*bufsize = filesize(fd);
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;
}
return buf;
}
int main(int argc, char* argv[])
{
char *infile, *uclfile, *bootfile, *uclunpackfile, *outfile;
int fdin, fducl, fdboot, fduclunpack, fdout;
char *infile, *bootfile, *outfile;
int fdout;
off_t len;
unsigned char uclheader[26];
uint32_t n;
unsigned char* buf;
uint32_t firmware_size;
uint32_t firmware_paddedsize;
uint32_t bootloader_size;
int firmware_size;
off_t bootloader_size;
uint32_t ucl_size;
uint32_t ucl_paddedsize;
uint32_t uclunpack_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;
if(argc != 6) {
usage();
fprintf(stderr,"mkamsboot v" VERSION " - (C) Dave Chapman 2008\n");
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");
return 1;
}
infile = argv[1];
uclfile = argv[2];
bootfile = argv[3];
uclunpackfile = argv[4];
outfile = argv[5];
bootfile = argv[2];
outfile = argv[3];
/* Open the bootloader file */
fdboot = open(bootfile, O_RDONLY|O_BINARY);
if (fdboot < 0)
{
fprintf(stderr,"[ERR] Could not open %s for reading\n",bootfile);
/* Load bootloader file */
rb_unpacked = load_file(bootfile, &bootloader_size);
if (rb_unpacked == NULL) {
fprintf(stderr,"[ERR] Could not load %s\n",bootfile);
return 1;
}
bootloader_size = filesize(fdboot);
/* Load original firmware file */
buf = load_file(infile, &len);
/* Open the UCL-compressed image of the firmware block */
fduclunpack = open(uclunpackfile, O_RDONLY|O_BINARY);
if (fduclunpack < 0)
{
fprintf(stderr,"[ERR] Could not open %s for reading\n",uclunpackfile);
if (buf == NULL) {
fprintf(stderr,"[ERR] Could not load bootloader file\n");
return 1;
}
uclunpack_size = filesize(fduclunpack);
/* TODO: Do some more sanity checks on the OF image - e.g. checksum */
if (get_uint32le(&buf[0x204])==0x0000f000) {
fw_version = 2;
model_id = buf[0x219];
} else {
fw_version = 1;
model_id = buf[0x215];
}
/* Open the UCL-compressed image of the firmware block */
fducl = open(uclfile, O_RDONLY|O_BINARY);
if (fducl < 0)
{
fprintf(stderr,"[ERR] Could not open %s for reading\n",uclfile);
model = get_model(model_id);
if (model == MODEL_UNKNOWN) {
fprintf(stderr,"[ERR] Unknown firmware - model id 0x%02x\n",model_id);
return 1;
}
/* Some UCL file sanity checks */
n = read(fducl, uclheader, sizeof(uclheader));
if (n != sizeof(uclheader)) {
fprintf(stderr,"[ERR] Could not read header from UCL file\n");
if (bootloaders[model] == NULL) {
fprintf(stderr,"[ERR] Unsupported model - \"%s\"\n",model_names[model]);
free(buf);
free(rb_unpacked);
return 1;
}
if (memcmp(uclmagic, uclheader, sizeof(uclmagic))!=0) {
fprintf(stderr,"[ERR] Invalid UCL file\n");
return 1;
}
if (uclheader[12] != 0x2e) {
fprintf(stderr,"[ERR] Unsupported UCL compression format (0x%02x) - only 0x2e supported.\n",uclheader[12]);
return 1;
}
ucl_size = get_uint32be(&uclheader[22]) + 8;
ucl_paddedsize = (ucl_size + 3) & ~0x3;
if (ucl_size + 26 > (unsigned)filesize(fducl)) {
fprintf(stderr, "[ERR] Size mismatch in UCL file\n");
return 1;
}
/* Open the firmware file */
fdin = open(infile,O_RDONLY|O_BINARY);
if (fdin < 0) {
fprintf(stderr,"[ERR] Could not open %s for reading\n",infile);
return 1;
}
if ((len = filesize(fdin)) < 0)
return 1;
/* Allocate memory for the OF image - we don't change the size */
if ((buf = malloc(len)) == NULL) {
fprintf(stderr,"[ERR] Could not allocate buffer for input file (%d bytes)\n",(int)len);
return 1;
}
n = read(fdin, buf, len);
if (n != (uint32_t)len) {
fprintf(stderr,"[ERR] Could not read firmware file\n");
return 1;
}
close(fdin);
printf("[INFO] Patching %s firmware\n",model_names[model]);
/* Get the firmware size */
firmware_size = get_uint32le(&buf[0x0c]);
/* Round size up to next multiple of 0x200 */
/* 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;
}
firmware_paddedsize = PAD_TO_BOUNDARY(firmware_size);
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;
}
fprintf(stderr,"Original firmware size - %d bytes\n",firmware_size);
fprintf(stderr,"Padded firmware size - %d bytes\n",firmware_paddedsize);
fprintf(stderr,"Bootloader size - %d bytes\n",bootloader_size);
fprintf(stderr,"UCL image size - %d bytes (%d bytes padded)\n",ucl_size,ucl_paddedsize);
fprintf(stderr,"UCL unpack function size - %d bytes\n",uclunpack_size);
fprintf(stderr,"Original total size of firmware - %d bytes\n",(int)len);
/* We are finished with the unpacked version of the bootloader */
free(rb_unpacked);
/* Check we have room for our bootloader - in the future, we could UCL
pack this image as well if we need to. */
if (bootloader_size > (firmware_size - ucl_paddedsize - uclunpack_size)) {
fprintf(stderr,"[ERR] Bootloader too large (%d bytes, %d available)\n",
bootloader_size, firmware_size - ucl_paddedsize - uclunpack_size);
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));
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);
return 1;
}
/* Zero the original firmware area - not needed, but helps debugging */
memset(buf + 0x400, 0, firmware_size);
/* Locate our bootloader code at the start of the firmware block */
n = read(fdboot, buf + 0x400, bootloader_size);
if (n != bootloader_size) {
fprintf(stderr,"[ERR] Could not load bootloader file\n");
return 1;
}
close(fdboot);
/* Insert dual-boot bootloader at offset 0 */
memcpy(buf + 0x400, bootloaders[model], bootloader_sizes[model]);
/* Locate the compressed image of the original firmware block at the end
of the firmware block */
n = read(fducl, buf + 0x400 + firmware_size - ucl_paddedsize, ucl_size);
/* We are filling the firmware buffer backwards from the end */
p = buf + 0x400 + firmware_size;
if (n != ucl_size) {
fprintf(stderr,"[ERR] Could not load ucl file\n");
return 1;
}
close(fducl);
/* 1 - UCL unpack function */
p -= sizeof(uclimg);
memcpy(p, uclimg, sizeof(uclimg));
/* 2 - Compressed copy of original firmware */
p -= of_packedsize;
memcpy(p, of_packed, of_packedsize);
/* 3 - Compressed copy of Rockbox bootloader */
p -= rb_packedsize;
memcpy(p, rb_packed, rb_packedsize);
/* 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 */
put_uint32le(&buf[0x420], firmware_size);
put_uint32le(&buf[0x424], sizeof(uclimg));
/* Compressed original firmware image */
put_uint32le(&buf[0x428], firmware_size - sizeof(uclimg));
put_uint32le(&buf[0x42c], of_packedsize);
/* Compressed Rockbox image */
put_uint32le(&buf[0x430], firmware_size - sizeof(uclimg) - of_packedsize);
put_uint32le(&buf[0x434], rb_packedsize);
/* Locate our UCL unpack function before copy of the compressed firmware */
n = read(fduclunpack, buf + 0x400 + firmware_size - ucl_paddedsize - uclunpack_size, uclunpack_size);
if (n != uclunpack_size) {
fprintf(stderr,"[ERR] Could not load uclunpack file\n");
return 1;
}
close(fduclunpack);
put_uint32le(&buf[0x420], 0x40000 - ucl_paddedsize - uclunpack_size + 1); /* UCL unpack entry point */
put_uint32le(&buf[0x424], 0x40000 - ucl_paddedsize); /* Location of OF */
put_uint32le(&buf[0x428], ucl_size); /* Size of UCL image */
put_uint32le(&buf[0x42c], firmware_size - uclunpack_size - ucl_paddedsize); /* Start of data to copy */
put_uint32le(&buf[0x430], uclunpack_size + ucl_paddedsize); /* Size of data to copy */
/* Update checksum */
/* Update the firmware block checksum */
sum = calc_checksum(buf + 0x400,firmware_size);
put_uint32le(&buf[0x04], sum);
put_uint32le(&buf[0x204], sum);
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));
}
/* Update the whole-file checksum */
filesum = 0;

View file

@ -1,55 +0,0 @@
/* int ucl_nrv2e_decompress_8(const unsigned char *src, unsigned char *dst,
unsigned long *dst_len) */
.text
.global ucl_nrv2e_decompress_8
/* Vectors */
ldr pc, =start
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
/* These values are filled in by mkamsboot - don't move them from offset 0x20 */
ucl_unpack: .word 0 /* Entry point (plus 1 - for thumb) of ucl_unpack after copy*/
ucl_start: .word 0 /* Start of the ucl-compressed OF image after copy */
ucl_size: .word 0 /* Length in bytes of the compressed OF image */
copy_start: .word 0 /* Start of the copy of the ucl_unpack function */
copy_size: .word 0 /* uclunpack_size + ucl_paddedsize */
start:
/* A delay loop - just to prove we're running */
mov r1, #0x500000 /* Approximately 5 seconds */
loop: subs r1, r1, #1
bne loop
/* First copy the compressed firmware to unused RAM */
ldr r0, copy_start /* Source */
ldr r1, copy_size /* Source length */
mov r2, #0x40000 /* Destination end */
sub r2, r2, r1
memcpy:
ldrb r3, [r0], #1
strb r3, [r2], #1
cmp r2, #0x40000 /* Stop when we reached dest_end */
bne memcpy
/* Call the ucl decompress function, which will branch to 0x0 */
/* on completion */
ldr r0, ucl_start /* Address of compressed image */
ldr r1, ucl_size /* Compressed size */
mov r2, #0 /* Destination */
ldr r3, ucl_unpack
bx r3
/* never reached */