diff options
author | Dave Chapman <dave@dchapman.com> | 2008-10-11 11:35:59 +0000 |
---|---|---|
committer | Dave Chapman <dave@dchapman.com> | 2008-10-11 11:35:59 +0000 |
commit | 1c4bcfac691d4473cf513ba958c8edbdc8c97939 (patch) | |
tree | d9a4a2c8138608c5ae7728fcf24e247024a8416f /rbutil | |
parent | ced0adc527b44c3041a2ac0a4a3a5c9cd805531e (diff) |
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
Diffstat (limited to 'rbutil')
-rw-r--r-- | rbutil/mkamsboot/Makefile | 98 | ||||
-rw-r--r-- | rbutil/mkamsboot/README | 8 | ||||
-rw-r--r-- | rbutil/mkamsboot/bin2c.c | 134 | ||||
-rw-r--r-- | rbutil/mkamsboot/dualboot.S | 126 | ||||
-rw-r--r-- | rbutil/mkamsboot/mkamsboot.c | 429 | ||||
-rw-r--r-- | rbutil/mkamsboot/test.S | 55 |
6 files changed, 613 insertions, 237 deletions
diff --git a/rbutil/mkamsboot/Makefile b/rbutil/mkamsboot/Makefile index 4040c716b5..e3d98f03f0 100644 --- a/rbutil/mkamsboot/Makefile +++ b/rbutil/mkamsboot/Makefile @@ -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 + +dualboot-clip.o: dualboot.S + arm-elf-gcc -DSANSA_CLIP -c -o dualboot-clip.o dualboot.S + +dualboot-clip.elf: dualboot-clip.o + arm-elf-ld -e 0 -Ttext=0 -o dualboot-clip.elf dualboot-clip.o + +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 -test.elf: test.o - arm-elf-ld -e 0 -Ttext=0 -o test.elf test.o +bootimg_e200v2.c bootimg_e200v2.h: dualboot-e200v2.bin bin2c + ./bin2c dualboot-e200v2.bin bootimg_e200v2 -test.bin: test.elf - arm-elf-objcopy -O binary test.elf test.bin +bootimg_e200v2.o: bootimg_e200v2.c + gcc -c -o bootimg_e200v2.o bootimg_e200v2.c -# Rules for the ucl unpack function - this is inserted in the padding at -# the end of the original firmware block +# 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) diff --git a/rbutil/mkamsboot/README b/rbutil/mkamsboot/README index bf9ea698a2..bd0d2a3eea 100644 --- a/rbutil/mkamsboot/README +++ b/rbutil/mkamsboot/README @@ -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. diff --git a/rbutil/mkamsboot/bin2c.c b/rbutil/mkamsboot/bin2c.c new file mode 100644 index 0000000000..dce8013c31 --- /dev/null +++ b/rbutil/mkamsboot/bin2c.c @@ -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; +} diff --git a/rbutil/mkamsboot/dualboot.S b/rbutil/mkamsboot/dualboot.S new file mode 100644 index 0000000000..786f610aef --- /dev/null +++ b/rbutil/mkamsboot/dualboot.S @@ -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 */ diff --git a/rbutil/mkamsboot/mkamsboot.c b/rbutil/mkamsboot/mkamsboot.c index 52ead58b69..e617b1204a 100644 --- a/rbutil/mkamsboot/mkamsboot.c +++ b/rbutil/mkamsboot/mkamsboot.c @@ -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; } -int main(int argc, char* argv[]) + +static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize) { - char *infile, *uclfile, *bootfile, *uclunpackfile, *outfile; - int fdin, fducl, fdboot, fduclunpack, 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; - uint32_t ucl_size; - uint32_t ucl_paddedsize; - uint32_t uclunpack_size; - uint32_t sum,filesum; - uint32_t i; + int maxsize; + unsigned char* outbuf; + int r; - if(argc != 6) { - usage(); - } + /* The following formula comes from the UCL documentation */ + maxsize = insize + (insize / 8) + 256; - infile = argv[1]; - uclfile = argv[2]; - bootfile = argv[3]; - uclunpackfile = argv[4]; - outfile = argv[5]; - - /* Open the bootloader file */ - fdboot = open(bootfile, O_RDONLY|O_BINARY); - if (fdboot < 0) + /* 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) { - fprintf(stderr,"[ERR] Could not open %s for reading\n",bootfile); - return 1; + /* this should NEVER happen, and implies memory corruption */ + fprintf(stderr, "internal error - compression failed: %d\n", r); + free(outbuf); + return NULL; } - bootloader_size = filesize(fdboot); + return outbuf; +} +static unsigned char* load_file(char* filename, off_t* bufsize) +{ + int fd; + unsigned char* buf; + off_t n; - /* Open the UCL-compressed image of the firmware block */ - fduclunpack = open(uclunpackfile, O_RDONLY|O_BINARY); - if (fduclunpack < 0) + fd = open(filename, O_RDONLY|O_BINARY); + if (fd < 0) { - fprintf(stderr,"[ERR] Could not open %s for reading\n",uclunpackfile); - return 1; + fprintf(stderr,"[ERR] Could not open %s for reading\n",filename); + return NULL; } - uclunpack_size = filesize(fduclunpack); + *bufsize = filesize(fd); - - /* 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); - return 1; + buf = malloc(*bufsize); + if (buf == NULL) { + fprintf(stderr,"[ERR] Could not allocate memory for %s\n",filename); + return NULL; } - /* Some UCL file sanity checks */ - n = read(fducl, uclheader, sizeof(uclheader)); + n = read(fd, buf, *bufsize); - if (n != sizeof(uclheader)) { - fprintf(stderr,"[ERR] Could not read header from UCL file\n"); - return 1; + if (n != *bufsize) { + fprintf(stderr,"[ERR] Could not read file %s\n",filename); + return NULL; } - if (memcmp(uclmagic, uclheader, sizeof(uclmagic))!=0) { - fprintf(stderr,"[ERR] Invalid UCL file\n"); + return buf; +} + + +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 ucl_size; + uint32_t ucl_paddedsize; + 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; + + 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; } - if (uclheader[12] != 0x2e) { - fprintf(stderr,"[ERR] Unsupported UCL compression format (0x%02x) - only 0x2e supported.\n",uclheader[12]); + infile = argv[1]; + bootfile = argv[2]; + outfile = argv[3]; + + /* 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; } - 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"); + /* Load original firmware file */ + buf = load_file(infile, &len); + + if (buf == NULL) { + fprintf(stderr,"[ERR] Could not load bootloader file\n"); return 1; } - /* Open the firmware file */ - fdin = open(infile,O_RDONLY|O_BINARY); + /* TODO: Do some more sanity checks on the OF image - e.g. checksum */ - if (fdin < 0) { - fprintf(stderr,"[ERR] Could not open %s for reading\n",infile); - return 1; + if (get_uint32le(&buf[0x204])==0x0000f000) { + fw_version = 2; + model_id = buf[0x219]; + } else { + fw_version = 1; + model_id = buf[0x215]; } - if ((len = filesize(fdin)) < 0) - return 1; + model = get_model(model_id); - /* 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); + if (model == MODEL_UNKNOWN) { + fprintf(stderr,"[ERR] Unknown firmware - model id 0x%02x\n",model_id); return 1; } - n = read(fdin, buf, len); - - if (n != (uint32_t)len) { - fprintf(stderr,"[ERR] Could not read firmware file\n"); + if (bootloaders[model] == NULL) { + fprintf(stderr,"[ERR] Unsupported model - \"%s\"\n",model_names[model]); + free(buf); + free(rb_unpacked); 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; + } + + 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; + } - firmware_paddedsize = PAD_TO_BOUNDARY(firmware_size); + /* We are finished with the unpacked version of the bootloader */ + free(rb_unpacked); - 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); + 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)); - /* 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); + 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); - /* Locate our UCL unpack function before copy of the compressed firmware */ - n = read(fduclunpack, buf + 0x400 + firmware_size - ucl_paddedsize - uclunpack_size, uclunpack_size); + /* 3 - Compressed copy of Rockbox bootloader */ + p -= rb_packedsize; + memcpy(p, rb_packed, rb_packedsize); - if (n != uclunpack_size) { - fprintf(stderr,"[ERR] Could not load uclunpack file\n"); - return 1; - } - close(fduclunpack); + /* 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); - 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 */ + /* Compressed Rockbox image */ + put_uint32le(&buf[0x430], firmware_size - sizeof(uclimg) - of_packedsize); + put_uint32le(&buf[0x434], rb_packedsize); - /* 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; diff --git a/rbutil/mkamsboot/test.S b/rbutil/mkamsboot/test.S deleted file mode 100644 index a4757b44ce..0000000000 --- a/rbutil/mkamsboot/test.S +++ /dev/null @@ -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 */ |