summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2008-10-11 11:35:59 +0000
committerDave Chapman <dave@dchapman.com>2008-10-11 11:35:59 +0000
commit1c4bcfac691d4473cf513ba958c8edbdc8c97939 (patch)
treed9a4a2c8138608c5ae7728fcf24e247024a8416f
parentced0adc527b44c3041a2ac0a4a3a5c9cd805531e (diff)
downloadrockbox-1c4bcfac691d4473cf513ba958c8edbdc8c97939.tar.gz
rockbox-1c4bcfac691d4473cf513ba958c8edbdc8c97939.zip
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
-rw-r--r--rbutil/mkamsboot/Makefile98
-rw-r--r--rbutil/mkamsboot/README8
-rw-r--r--rbutil/mkamsboot/bin2c.c134
-rw-r--r--rbutil/mkamsboot/dualboot.S126
-rw-r--r--rbutil/mkamsboot/mkamsboot.c429
-rw-r--r--rbutil/mkamsboot/test.S55
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 @@
1# Change INFILE to point to your original firmware file
2INFILE=$(HOME)/FW/AMS/CLIP/m300a-1.1.17A.bin
3 1
4# OUTFILE is the file you copy to your device's root and rename to 2# We use the UCL code available in the Rockbox tools/ directory
5# (e.g.) m300a.bin
6OUTFILE=patched.bin
7 3
8# The uclpack command 4CFLAGS=-I../../tools/ucl/include
9UCLPACK=../../tools/uclpack 5LIBUCL=../../tools/ucl/src/libucl.a
10 6
11all: $(OUTFILE) 7# Edit the following variables (plus copy/paste another set of rules) when
8# adding a new target. mkamsboot.c also needs to be edited to refer to these
9# new images.
10#
11# If anyone reading this wants to improve this makefile, please do!
12 12
13mkamsboot: mkamsboot.c 13BOOTIMAGES = bootimg_clip.o bootimg_e200v2.o
14 gcc -o mkamsboot -W -Wall mkamsboot.c 14BOOTHEADERS = bootimg_clip.h bootimg_e200v2.h
15 15
16extract_fw: extract_fw.c 16CLIPFILES = dualboot-clip.o dualboot-clip.elf dualboot-clip.o \
17 gcc -o extract_fw -W -Wall extract_fw.c 17 dualboot-clip.bin bootimg_clip.c bootimg_clip.h
18
19E200V2FILES = dualboot-e200v2.o dualboot-e200v2.elf dualboot-e200v2.o \
20 dualboot-e200v2.bin bootimg_e200v2.c bootimg_e200v2.h
21
22all: mkamsboot
23
24$(LIBUCL):
25 make -C ../../tools/ucl/src libucl.a
26
27mkamsboot.o: mkamsboot.c $(BOOTHEADERS) uclimg.h
28 gcc $(CFLAGS) -c -o mkamsboot.o -W -Wall mkamsboot.c
29
30mkamsboot: mkamsboot.o $(BOOTIMAGES) uclimg.o $(LIBUCL)
31 gcc -o mkamsboot mkamsboot.o $(BOOTIMAGES) uclimg.o $(LIBUCL)
18 32
19# Rules for our test ARM application - assemble, link, then extract 33# Rules for our test ARM application - assemble, link, then extract
20# the binary code 34# the binary code
21 35
22test.o: test.S 36# CLIP
23 arm-elf-as -o test.o test.S 37
38dualboot-clip.o: dualboot.S
39 arm-elf-gcc -DSANSA_CLIP -c -o dualboot-clip.o dualboot.S
40
41dualboot-clip.elf: dualboot-clip.o
42 arm-elf-ld -e 0 -Ttext=0 -o dualboot-clip.elf dualboot-clip.o
43
44dualboot-clip.bin: dualboot-clip.elf
45 arm-elf-objcopy -O binary dualboot-clip.elf dualboot-clip.bin
46
47bootimg_clip.c bootimg_clip.h: dualboot-clip.bin bin2c
48 ./bin2c dualboot-clip.bin bootimg_clip
49
50bootimg_clip.o: bootimg_clip.c
51 gcc -c -o bootimg_clip.o bootimg_clip.c
52
53# E200V2
54
55dualboot-e200v2.o: dualboot.S
56 arm-elf-gcc -DSANSA_E200V2 -c -o dualboot-e200v2.o dualboot.S
57
58dualboot-e200v2.elf: dualboot-e200v2.o
59 arm-elf-ld -e 0 -Ttext=0 -o dualboot-e200v2.elf dualboot-e200v2.o
60
61dualboot-e200v2.bin: dualboot-e200v2.elf
62 arm-elf-objcopy -O binary dualboot-e200v2.elf dualboot-e200v2.bin
24 63
25test.elf: test.o 64bootimg_e200v2.c bootimg_e200v2.h: dualboot-e200v2.bin bin2c
26 arm-elf-ld -e 0 -Ttext=0 -o test.elf test.o 65 ./bin2c dualboot-e200v2.bin bootimg_e200v2
27 66
28test.bin: test.elf 67bootimg_e200v2.o: bootimg_e200v2.c
29 arm-elf-objcopy -O binary test.elf test.bin 68 gcc -c -o bootimg_e200v2.o bootimg_e200v2.c
30 69
31# Rules for the ucl unpack function - this is inserted in the padding at 70# Rules for the ucl unpack function
32# the end of the original firmware block
33nrv2e_d8.o: nrv2e_d8.S 71nrv2e_d8.o: nrv2e_d8.S
34 arm-elf-gcc -DPURE_THUMB -c -o nrv2e_d8.o nrv2e_d8.S 72 arm-elf-gcc -DPURE_THUMB -c -o nrv2e_d8.o nrv2e_d8.S
35 73
36# NOTE: this function has no absolute references, so the link address (-e) 74# NOTE: this function has no absolute references, so the link address (-e)
37# is irrelevant. We just link at address 0. 75# is irrelevant. We just link at address 0, but it can run from anywhere.
38nrv2e_d8.elf: nrv2e_d8.o 76nrv2e_d8.elf: nrv2e_d8.o
39 arm-elf-ld -e 0 -Ttext=0 -o nrv2e_d8.elf nrv2e_d8.o 77 arm-elf-ld -e 0 -Ttext=0 -o nrv2e_d8.elf nrv2e_d8.o
40 78
41nrv2e_d8.bin: nrv2e_d8.elf 79nrv2e_d8.bin: nrv2e_d8.elf
42 arm-elf-objcopy -O binary nrv2e_d8.elf nrv2e_d8.bin 80 arm-elf-objcopy -O binary nrv2e_d8.elf nrv2e_d8.bin
43 81
44firmware_block.ucl: firmware_block.bin 82uclimg.c uclimg.h: nrv2e_d8.bin bin2c
45 $(UCLPACK) --best --2e firmware_block.bin firmware_block.ucl 83 ./bin2c nrv2e_d8.bin uclimg
46 84
47firmware_block.bin: $(INFILE) extract_fw 85uclimg.o: uclimg.c
48 ./extract_fw $(INFILE) firmware_block.bin 86 gcc -c -o uclimg.o uclimg.c
49 87
50$(OUTFILE): mkamsboot firmware_block.ucl test.bin nrv2e_d8.bin $(INFILE) 88bin2c: bin2c.c
51 ./mkamsboot $(INFILE) firmware_block.ucl test.bin nrv2e_d8.bin $(OUTFILE) 89 gcc -o bin2c bin2c.c
52 90
53clean: 91clean:
54 rm -fr amsinfo mkamsboot test.o test.elf test.bin extract_fw \ 92 rm -f mkamsboot mkamsboot.o nrv2e_d8.o nrv2e_d8.elf nrv2e_d8.bin *~ \
55 nrv2e_d8.o nrv2e_d8.elf nrv2e_d8.bin firmware_block.bin \ 93 bin2c uclimg.c uclimg.h uclimg.o \
56 firmware_block.ucl $(OUTFILE) *~ 94 $(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 @@
1mkamsboot 1mkamsboot
2--------- 2---------
3 3
4A tool to inject some code (contained in test.S) into a firmware file. 4A tool to inject a bootloader into a Sansa V2 (AMS) firmware file.
5
6Edit the INFILE variable in the Makefile to point to the original
7firmware file you want to patch, edit "test.S" appropriately, and then
8type "make".
9
10 5
6See 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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <string.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <stdlib.h>
29
30#ifndef O_BINARY
31#define O_BINARY 0
32#endif
33
34static off_t filesize(int fd)
35{
36 struct stat buf;
37
38 fstat(fd,&buf);
39 return buf.st_size;
40}
41
42static int write_cfile(const unsigned char* buf, off_t len, const char* cname)
43{
44 char filename[256];
45 FILE* fp;
46 int i;
47
48 snprintf(filename,256,"%s.c",cname);
49
50 fp = fopen(filename,"w+");
51 if (fp == NULL) {
52 fprintf(stderr,"Couldn't open %s\n",filename);
53 return -1;
54 }
55
56 fprintf(fp,"/* Generated by bin2c */\n\n");
57 fprintf(fp,"unsigned char %s[%d] = {",cname,len);
58
59 for (i=0;i<len;i++) {
60 if ((i % 16) == 0) {
61 fprintf(fp,"\n ");
62 }
63 if (i == (len-1)) {
64 fprintf(fp,"0x%02x",buf[i]);
65 } else {
66 fprintf(fp,"0x%02x, ",buf[i]);
67 }
68 }
69 fprintf(fp,"\n};\n");
70
71 fclose(fp);
72 return 0;
73}
74
75static int write_hfile(off_t len, const char* cname)
76{
77 char filename[256];
78 FILE* fp;
79
80 snprintf(filename,256,"%s.h",cname);
81 fp = fopen(filename,"w+");
82 if (fp == NULL) {
83 fprintf(stderr,"Couldn't open %s\n",filename);
84 return -1;
85 }
86
87 fprintf(fp,"/* Generated by bin2c */\n\n");
88 fprintf(fp,"extern unsigned char %s[%d];\n",cname,len);
89 fclose(fp);
90 return 0;
91}
92
93int main (int argc, char* argv[])
94{
95 char* infile;
96 char* cname;
97 int fd;
98 unsigned char* buf;
99 int len;
100 int n;
101
102 if (argc != 3) {
103 fprintf(stderr,"Usage: bin2c file cname\n");
104 return 0;
105 }
106
107 infile=argv[1];
108 cname=argv[2];
109
110 fd = open(infile,O_RDONLY|O_BINARY);
111 if (fd < 0) {
112 fprintf(stderr,"Can not open %s\n",infile);
113 return 0;
114 }
115
116 len = filesize(fd);
117
118 buf = malloc(len);
119 n = read(fd,buf,len);
120 if (n < len) {
121 fprintf(stderr,"Short read, aborting\n");
122 return 0;
123 }
124 close(fd);
125
126 if (write_cfile(buf,len,cname) < 0) {
127 return -1;
128 }
129 if (write_hfile(len,cname) < 0) {
130 return -1;
131 }
132
133 return 0;
134}
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 @@
1.text
2
3/* This is the size of the Clip's RAM, but there is nothing to be gained
4 (at the moment) by making use of the larger RAM of other targets */
5
6.set DRAM_SIZE, 0x50000
7
8.set GPIOA, 0xC80B0000
9.set GPIOB, 0xC80C0000
10.set GPIOC, 0xC80D0000
11.set GPIOD, 0xC80E0000
12.set CGU_PERI, 0xC80F0014
13
14
15/* Vectors */
16 ldr pc, =start
17.word 0
18.word 0
19.word 0
20.word 0
21.word 0
22.word 0
23.word 0
24
25/* These values are filled in by mkamsboot - don't move them from offset 0x20 */
26uclunpack_end: .word 0 /* End of the ucl_unpack function */
27uclunpack_size: .word 0 /* Size in bytes of the ucl_unpack function */
28
29ucl_of_end: .word 0 /* End of the ucl-compressed OF image */
30ucl_of_size: .word 0 /* Size in bytes of the compressed OF image */
31
32ucl_rb_end: .word 0 /* End of the ucl-compressed RB image */
33ucl_rb_size: .word 0 /* Size in bytes of the compressed RB image */
34
35
36start:
37 /* First copy the UCL unpack function to the end of RAM */
38 ldr r0, uclunpack_end /* Source */
39 ldr r1, uclunpack_size /* Source length */
40 sub r2, r0, r1 /* Source start - 1*/
41
42 ldr r3, =DRAM_SIZE /* Destination end */
43
44uclcopy:
45 ldrb r4, [r0], #-1
46 strb r4, [r3], #-1
47 cmp r2, r3
48 bne uclcopy
49
50 add r5, r2, #2 /* r5 is entry point of copy of uclunpack */
51 /* function, plus one (for thumb mode */
52
53 /* enable gpio clock */
54 ldr r0, =CGU_PERI
55 ldr r1, [r0]
56 orr r1, r1, #(1<<16)
57 str r1, [r0]
58
59 /* we check A3 unconditionally of the model because it seems to be */
60 /* either hold, either usb on every model */
61
62 ldr r0, =GPIOA
63 mov r1, #0
64 str r1, [r0, #0x400]
65 ldr r1, [r0, #0x20] /* read pin A3 */
66
67 cmp r1, #0
68 bne boot_of
69
70 /* here are model specific tests, for dual boot without a computer */
71
72#ifdef SANSA_CLIP
73 /* HOME button */
74 ldr r0, =GPIOB
75 mov r1, #0
76 str r1, [r0, #0x400]
77 ldr r1, [r0, #0x10] /* read pin B2 */
78
79 cmp r1, #0
80 bne boot_of
81#elif defined(SANSA_E200V2)
82 /* DOWN button */
83 ldr r0, =GPIOC
84 mov r1, #0
85 str r1, [r0, #0x400]
86 ldr r1, [r0, #0x100] /* read pin C6 */
87
88 cmp r1, #0 /* C6 = #0 means button pressed */
89 beq boot_of
90#else
91 #error No target-specific key check defined!
92#endif
93
94 /* No button was held, so we boot rockbox */
95 ldr r0, ucl_rb_end /* Address of compressed image */
96 ldr r1, ucl_rb_size /* Compressed size */
97 b decompress
98
99boot_of:
100 ldr r0, ucl_of_end /* Address of compressed image */
101 ldr r1, ucl_of_size /* Compressed size */
102
103
104decompress:
105 /* At this point: */
106 /* r5 = entry point (plus one for thumb) of uclunpack function */
107 /* r3 = destination_end for copy of UCL image */
108 /* r0 = source_end for UCL image to copy */
109 /* r1 = size of UCL image to copy */
110
111 sub r4, r3, r1 /* r4 := destination_start - 1 */
112
113fw_copy:
114 ldrb r2, [r0], #-1
115 strb r2, [r3], #-1
116 cmp r3, r4 /* Stop when we reached dest_start-1 */
117 bne fw_copy
118
119 /* Call the ucl decompress function, which will branch to 0x0 */
120 /* on completion */
121 add r0, r3, #1 /* r0 := Start of compressed image */
122 /* r1 already contains compressed size */
123 mov r2, #0 /* r2 := Destination for unpacking */
124 bx r5 /* Branch to uclunpack, switching to thumb */
125
126 /* 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)
30as follows: 30as follows:
31 31
32 32
33 --------------------- 0x0 33 ---------------------- 0x0
34| | 34| |
35| Rockbox bootloader | 35| Dual-boot code |
36| | 36| |
37|---------------------| 37|----------------------|
38| EMPTY SPACE | 38| EMPTY SPACE |
39|---------------------| 39|----------------------|
40| ucl unpack function | 40| |
41|---------------------| 41| compressed RB image |
42| | 42| |
43| compressed OF image | 43|----------------------|
44| | 44| |
45| | 45| compressed OF image |
46 --------------------- 46| |
47|----------------------|
48| UCL unpack function |
49 ----------------------
47 50
48This entire block fits into the space previously occupied by the main 51This entire block fits into the space previously occupied by the main
49firmware block, and gives about 40KB of space to store the Rockbox 52firmware block - the space saved by compressing the OF image is used
50bootloader. This could be increased if we also UCL compress the 53to store the compressed version of the Rockbox bootloader. The OF
51Rockbox bootloader. 54image is typically about 120KB, which allows us to store a Rockbox
55bootloader with an uncompressed size of about 60KB-70KB.
52 56
53mkamsboot then corrects the checksums and writes a new legal firmware 57mkamsboot then corrects the checksums and writes a new legal firmware
54file which can be installed on the device. 58file which can be installed on the device.
55 59
56Our bootloader first checks for the "dual-boot" keypress, and then either: 60When the Sansa device boots, this firmware block is loaded to RAM at
61address 0x0 and executed.
57 62
58a) Copies the ucl unpack function and compressed OF image to an unused 63Firstly, the dual-boot code will copy the UCL unpack function to the
59 part of RAM and then branches to the ucl_unpack function, which 64end of RAM.
60 will then branch to 0x0 after decompressing the OF to that location. 65
66Then, depending on the detection of the dual-boot keypress, either the
67OF image or the Rockbox image is copied to the end of RAM (just before
68the ucl unpack function) and uncompress it to the start of RAM.
69
70Finally, the ucl unpack function branches to address 0x0, passing
71execution to the uncompressed firmware.
61 72
62b) Continues running with our test code
63 73
64*/ 74*/
65 75
@@ -73,14 +83,62 @@ b) Continues running with our test code
73#include <unistd.h> 83#include <unistd.h>
74#include <string.h> 84#include <string.h>
75 85
86#include <ucl/ucl.h>
87
88/* Headers for ARM code binaries */
89#include "uclimg.h"
90#include "bootimg_clip.h"
91#include "bootimg_e200v2.h"
76 92
77/* Win32 compatibility */ 93/* Win32 compatibility */
78#ifndef O_BINARY 94#ifndef O_BINARY
79#define O_BINARY 0 95#define O_BINARY 0
80#endif 96#endif
81 97
98#ifndef VERSION
99#define VERSION "0.1"
100#endif
82 101
83#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff) 102enum
103{
104 MODEL_UNKNOWN = -1,
105 MODEL_FUZE = 0,
106 MODEL_CLIP,
107 MODEL_CLIPV2,
108 MODEL_E200,
109 MODEL_M200,
110 MODEL_C200
111};
112
113static const char* model_names[] =
114{
115 "Fuze",
116 "Clip",
117 "Clip V2",
118 "E200",
119 "M200",
120 "C200"
121};
122
123static const unsigned char* bootloaders[] =
124{
125 NULL,
126 bootimg_clip,
127 NULL,
128 bootimg_e200v2,
129 NULL,
130 NULL
131};
132
133static const int bootloader_sizes[] =
134{
135 0,
136 sizeof(bootimg_clip),
137 0,
138 sizeof(bootimg_e200v2),
139 0,
140 0
141};
84 142
85 143
86/* This magic should appear at the start of any UCL file */ 144/* This magic should appear at the start of any UCL file */
@@ -105,12 +163,6 @@ static uint32_t get_uint32le(unsigned char* p)
105 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 163 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
106} 164}
107 165
108static uint32_t get_uint32be(unsigned char* p)
109{
110 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
111
112}
113
114static void put_uint32le(unsigned char* p, uint32_t x) 166static void put_uint32le(unsigned char* p, uint32_t x)
115{ 167{
116 p[0] = x & 0xff; 168 p[0] = x & 0xff;
@@ -130,186 +182,271 @@ static int calc_checksum(unsigned char* buf, uint32_t n)
130 return sum; 182 return sum;
131} 183}
132 184
133void usage(void) 185static int get_model(int model_id)
134{ 186{
135 printf("Usage: mkamsboot <firmware file> <ucl image> <boot file> <ucl unpack file> <output file>\n"); 187 switch(model_id)
188 {
189 case 0x1e:
190 return MODEL_FUZE;
191 case 0x22:
192 return MODEL_CLIP;
193 case 0x23:
194 return MODEL_C200;
195 case 0x24:
196 return MODEL_E200;
197 case 0x25:
198 return MODEL_M200;
199 case 0x27:
200 return MODEL_CLIPV2;
201 }
136 202
137 exit(1); 203 return MODEL_UNKNOWN;
138} 204}
139 205
140int main(int argc, char* argv[]) 206
207static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize)
141{ 208{
142 char *infile, *uclfile, *bootfile, *uclunpackfile, *outfile; 209 int maxsize;
143 int fdin, fducl, fdboot, fduclunpack, fdout; 210 unsigned char* outbuf;
144 off_t len; 211 int r;
145 unsigned char uclheader[26];
146 uint32_t n;
147 unsigned char* buf;
148 uint32_t firmware_size;
149 uint32_t firmware_paddedsize;
150 uint32_t bootloader_size;
151 uint32_t ucl_size;
152 uint32_t ucl_paddedsize;
153 uint32_t uclunpack_size;
154 uint32_t sum,filesum;
155 uint32_t i;
156 212
157 if(argc != 6) { 213 /* The following formula comes from the UCL documentation */
158 usage(); 214 maxsize = insize + (insize / 8) + 256;
159 }
160 215
161 infile = argv[1]; 216 /* Allocate some memory for the output buffer */
162 uclfile = argv[2]; 217 outbuf = malloc(maxsize);
163 bootfile = argv[3]; 218
164 uclunpackfile = argv[4]; 219 if (outbuf == NULL) {
165 outfile = argv[5]; 220 return NULL;
166 221 }
167 /* Open the bootloader file */ 222
168 fdboot = open(bootfile, O_RDONLY|O_BINARY); 223 r = ucl_nrv2e_99_compress(
169 if (fdboot < 0) 224 (const ucl_bytep) inbuf,
225 (ucl_uint) insize,
226 (ucl_bytep) outbuf,
227 (ucl_uintp) outsize,
228 0, 10, NULL, NULL);
229
230 if (r != UCL_E_OK || *outsize > maxsize)
170 { 231 {
171 fprintf(stderr,"[ERR] Could not open %s for reading\n",bootfile); 232 /* this should NEVER happen, and implies memory corruption */
172 return 1; 233 fprintf(stderr, "internal error - compression failed: %d\n", r);
234 free(outbuf);
235 return NULL;
173 } 236 }
174 237
175 bootloader_size = filesize(fdboot); 238 return outbuf;
239}
176 240
241static unsigned char* load_file(char* filename, off_t* bufsize)
242{
243 int fd;
244 unsigned char* buf;
245 off_t n;
177 246
178 /* Open the UCL-compressed image of the firmware block */ 247 fd = open(filename, O_RDONLY|O_BINARY);
179 fduclunpack = open(uclunpackfile, O_RDONLY|O_BINARY); 248 if (fd < 0)
180 if (fduclunpack < 0)
181 { 249 {
182 fprintf(stderr,"[ERR] Could not open %s for reading\n",uclunpackfile); 250 fprintf(stderr,"[ERR] Could not open %s for reading\n",filename);
183 return 1; 251 return NULL;
184 } 252 }
185 253
186 uclunpack_size = filesize(fduclunpack); 254 *bufsize = filesize(fd);
187 255
188 256 buf = malloc(*bufsize);
189 /* Open the UCL-compressed image of the firmware block */ 257 if (buf == NULL) {
190 fducl = open(uclfile, O_RDONLY|O_BINARY); 258 fprintf(stderr,"[ERR] Could not allocate memory for %s\n",filename);
191 if (fducl < 0) 259 return NULL;
192 {
193 fprintf(stderr,"[ERR] Could not open %s for reading\n",uclfile);
194 return 1;
195 } 260 }
196 261
197 /* Some UCL file sanity checks */ 262 n = read(fd, buf, *bufsize);
198 n = read(fducl, uclheader, sizeof(uclheader));
199 263
200 if (n != sizeof(uclheader)) { 264 if (n != *bufsize) {
201 fprintf(stderr,"[ERR] Could not read header from UCL file\n"); 265 fprintf(stderr,"[ERR] Could not read file %s\n",filename);
202 return 1; 266 return NULL;
203 } 267 }
204 268
205 if (memcmp(uclmagic, uclheader, sizeof(uclmagic))!=0) { 269 return buf;
206 fprintf(stderr,"[ERR] Invalid UCL file\n"); 270}
271
272
273int main(int argc, char* argv[])
274{
275 char *infile, *bootfile, *outfile;
276 int fdout;
277 off_t len;
278 uint32_t n;
279 unsigned char* buf;
280 int firmware_size;
281 off_t bootloader_size;
282 uint32_t ucl_size;
283 uint32_t ucl_paddedsize;
284 uint32_t sum,filesum;
285 uint8_t model_id;
286 int model;
287 uint32_t i;
288 unsigned char* of_packed;
289 int of_packedsize;
290 unsigned char* rb_unpacked;
291 unsigned char* rb_packed;
292 int rb_packedsize;
293 int fw_version;
294 int totalsize;
295 unsigned char* p;
296
297 fprintf(stderr,"mkamsboot v" VERSION " - (C) Dave Chapman 2008\n");
298 fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
299 fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
300
301 if(argc != 4) {
302 printf("Usage: mkamsboot <firmware file> <boot file> <output file>\n\n");
207 return 1; 303 return 1;
208 } 304 }
209 305
210 if (uclheader[12] != 0x2e) { 306 infile = argv[1];
211 fprintf(stderr,"[ERR] Unsupported UCL compression format (0x%02x) - only 0x2e supported.\n",uclheader[12]); 307 bootfile = argv[2];
308 outfile = argv[3];
309
310 /* Load bootloader file */
311 rb_unpacked = load_file(bootfile, &bootloader_size);
312 if (rb_unpacked == NULL) {
313 fprintf(stderr,"[ERR] Could not load %s\n",bootfile);
212 return 1; 314 return 1;
213 } 315 }
214 ucl_size = get_uint32be(&uclheader[22]) + 8;
215 ucl_paddedsize = (ucl_size + 3) & ~0x3;
216 316
217 if (ucl_size + 26 > (unsigned)filesize(fducl)) { 317 /* Load original firmware file */
218 fprintf(stderr, "[ERR] Size mismatch in UCL file\n"); 318 buf = load_file(infile, &len);
319
320 if (buf == NULL) {
321 fprintf(stderr,"[ERR] Could not load bootloader file\n");
219 return 1; 322 return 1;
220 } 323 }
221 324
222 /* Open the firmware file */ 325 /* TODO: Do some more sanity checks on the OF image - e.g. checksum */
223 fdin = open(infile,O_RDONLY|O_BINARY);
224 326
225 if (fdin < 0) { 327 if (get_uint32le(&buf[0x204])==0x0000f000) {
226 fprintf(stderr,"[ERR] Could not open %s for reading\n",infile); 328 fw_version = 2;
227 return 1; 329 model_id = buf[0x219];
330 } else {
331 fw_version = 1;
332 model_id = buf[0x215];
228 } 333 }
229 334
230 if ((len = filesize(fdin)) < 0) 335 model = get_model(model_id);
231 return 1;
232 336
233 /* Allocate memory for the OF image - we don't change the size */ 337 if (model == MODEL_UNKNOWN) {
234 if ((buf = malloc(len)) == NULL) { 338 fprintf(stderr,"[ERR] Unknown firmware - model id 0x%02x\n",model_id);
235 fprintf(stderr,"[ERR] Could not allocate buffer for input file (%d bytes)\n",(int)len);
236 return 1; 339 return 1;
237 } 340 }
238 341
239 n = read(fdin, buf, len); 342 if (bootloaders[model] == NULL) {
240 343 fprintf(stderr,"[ERR] Unsupported model - \"%s\"\n",model_names[model]);
241 if (n != (uint32_t)len) { 344 free(buf);
242 fprintf(stderr,"[ERR] Could not read firmware file\n"); 345 free(rb_unpacked);
243 return 1; 346 return 1;
244 } 347 }
245 348
246 close(fdin); 349 printf("[INFO] Patching %s firmware\n",model_names[model]);
247 350
248 /* Get the firmware size */ 351 /* Get the firmware size */
249 firmware_size = get_uint32le(&buf[0x0c]); 352 firmware_size = get_uint32le(&buf[0x0c]);
250 353
251 /* Round size up to next multiple of 0x200 */ 354 /* Compress the original firmware image */
355 of_packed = uclpack(buf + 0x400, firmware_size, &of_packedsize);
356 if (of_packed == NULL) {
357 fprintf(stderr,"[ERR] Could not compress original firmware\n");
358 free(buf);
359 free(rb_unpacked);
360 return 1;
361 }
362
363 rb_packed = uclpack(rb_unpacked, bootloader_size, &rb_packedsize);
364 if (rb_packed == NULL) {
365 fprintf(stderr,"[ERR] Could not compress %s\n",bootfile);
366 free(buf);
367 free(rb_unpacked);
368 free(of_packed);
369 return 1;
370 }
252 371
253 firmware_paddedsize = PAD_TO_BOUNDARY(firmware_size); 372 /* We are finished with the unpacked version of the bootloader */
373 free(rb_unpacked);
254 374
255 fprintf(stderr,"Original firmware size - %d bytes\n",firmware_size); 375 fprintf(stderr,"[INFO] Original firmware size: %d bytes\n",firmware_size);
256 fprintf(stderr,"Padded firmware size - %d bytes\n",firmware_paddedsize); 376 fprintf(stderr,"[INFO] Packed OF size: %d bytes\n",of_packedsize);
257 fprintf(stderr,"Bootloader size - %d bytes\n",bootloader_size); 377 fprintf(stderr,"[INFO] Bootloader size: %d bytes\n",(int)bootloader_size);
258 fprintf(stderr,"UCL image size - %d bytes (%d bytes padded)\n",ucl_size,ucl_paddedsize); 378 fprintf(stderr,"[INFO] Packed bootloader size: %d bytes\n",rb_packedsize);
259 fprintf(stderr,"UCL unpack function size - %d bytes\n",uclunpack_size); 379 fprintf(stderr,"[INFO] Dual-boot function size: %d bytes\n",bootloader_sizes[model]);
260 fprintf(stderr,"Original total size of firmware - %d bytes\n",(int)len); 380 fprintf(stderr,"[INFO] UCL unpack function size: %d bytes\n",sizeof(uclimg));
261 381
262 /* Check we have room for our bootloader - in the future, we could UCL 382 totalsize = bootloader_sizes[model] + sizeof(uclimg) + of_packedsize +
263 pack this image as well if we need to. */ 383 rb_packedsize;
264 if (bootloader_size > (firmware_size - ucl_paddedsize - uclunpack_size)) { 384
265 fprintf(stderr,"[ERR] Bootloader too large (%d bytes, %d available)\n", 385 fprintf(stderr,"[INFO] Total size of new image: %d bytes\n",totalsize);
266 bootloader_size, firmware_size - ucl_paddedsize - uclunpack_size); 386
387 if (totalsize > firmware_size) {
388 fprintf(stderr,"[ERR] No room to insert bootloader, aborting\n");
389 free(buf);
390 free(rb_unpacked);
391 free(of_packed);
267 return 1; 392 return 1;
268 } 393 }
269 394
270 /* Zero the original firmware area - not needed, but helps debugging */ 395 /* Zero the original firmware area - not needed, but helps debugging */
271 memset(buf + 0x400, 0, firmware_size); 396 memset(buf + 0x400, 0, firmware_size);
272 397
273 /* Locate our bootloader code at the start of the firmware block */
274 n = read(fdboot, buf + 0x400, bootloader_size);
275 398
276 if (n != bootloader_size) { 399 /* Insert dual-boot bootloader at offset 0 */
277 fprintf(stderr,"[ERR] Could not load bootloader file\n"); 400 memcpy(buf + 0x400, bootloaders[model], bootloader_sizes[model]);
278 return 1;
279 }
280 close(fdboot);
281 401
282 /* Locate the compressed image of the original firmware block at the end 402 /* We are filling the firmware buffer backwards from the end */
283 of the firmware block */ 403 p = buf + 0x400 + firmware_size;
284 n = read(fducl, buf + 0x400 + firmware_size - ucl_paddedsize, ucl_size);
285 404
286 if (n != ucl_size) { 405 /* 1 - UCL unpack function */
287 fprintf(stderr,"[ERR] Could not load ucl file\n"); 406 p -= sizeof(uclimg);
288 return 1; 407 memcpy(p, uclimg, sizeof(uclimg));
289 }
290 close(fducl);
291 408
409 /* 2 - Compressed copy of original firmware */
410 p -= of_packedsize;
411 memcpy(p, of_packed, of_packedsize);
292 412
293 /* Locate our UCL unpack function before copy of the compressed firmware */ 413 /* 3 - Compressed copy of Rockbox bootloader */
294 n = read(fduclunpack, buf + 0x400 + firmware_size - ucl_paddedsize - uclunpack_size, uclunpack_size); 414 p -= rb_packedsize;
415 memcpy(p, rb_packed, rb_packedsize);
295 416
296 if (n != uclunpack_size) { 417 /* Write the locations of the various images to the variables at the
297 fprintf(stderr,"[ERR] Could not load uclunpack file\n"); 418 start of the dualboot image - we save the location of the last byte
298 return 1; 419 in each image, along with the size in bytes */
299 } 420
300 close(fduclunpack); 421 /* UCL unpack function */
422 put_uint32le(&buf[0x420], firmware_size);
423 put_uint32le(&buf[0x424], sizeof(uclimg));
424
425 /* Compressed original firmware image */
426 put_uint32le(&buf[0x428], firmware_size - sizeof(uclimg));
427 put_uint32le(&buf[0x42c], of_packedsize);
301 428
302 put_uint32le(&buf[0x420], 0x40000 - ucl_paddedsize - uclunpack_size + 1); /* UCL unpack entry point */ 429 /* Compressed Rockbox image */
303 put_uint32le(&buf[0x424], 0x40000 - ucl_paddedsize); /* Location of OF */ 430 put_uint32le(&buf[0x430], firmware_size - sizeof(uclimg) - of_packedsize);
304 put_uint32le(&buf[0x428], ucl_size); /* Size of UCL image */ 431 put_uint32le(&buf[0x434], rb_packedsize);
305 put_uint32le(&buf[0x42c], firmware_size - uclunpack_size - ucl_paddedsize); /* Start of data to copy */
306 put_uint32le(&buf[0x430], uclunpack_size + ucl_paddedsize); /* Size of data to copy */
307 432
308 /* Update checksum */ 433
434 /* Update the firmware block checksum */
309 sum = calc_checksum(buf + 0x400,firmware_size); 435 sum = calc_checksum(buf + 0x400,firmware_size);
310 436
311 put_uint32le(&buf[0x04], sum); 437 if (fw_version == 1) {
312 put_uint32le(&buf[0x204], sum); 438 put_uint32le(&buf[0x04], sum);
439 put_uint32le(&buf[0x204], sum);
440 } else {
441 /* TODO: Verify that this is correct for the v2 firmware */
442
443 put_uint32le(&buf[0x08], sum);
444 put_uint32le(&buf[0x208], sum);
445
446 /* Update the header checksums */
447 put_uint32le(&buf[0x1fc], calc_checksum(buf, 0x1fc));
448 put_uint32le(&buf[0x3fc], calc_checksum(buf + 0x200, 0x1fc));
449 }
313 450
314 /* Update the whole-file checksum */ 451 /* Update the whole-file checksum */
315 filesum = 0; 452 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 @@
1/* int ucl_nrv2e_decompress_8(const unsigned char *src, unsigned char *dst,
2 unsigned long *dst_len) */
3
4.text
5.global ucl_nrv2e_decompress_8
6
7
8/* Vectors */
9 ldr pc, =start
10.word 0
11.word 0
12.word 0
13.word 0
14.word 0
15.word 0
16.word 0
17
18/* These values are filled in by mkamsboot - don't move them from offset 0x20 */
19ucl_unpack: .word 0 /* Entry point (plus 1 - for thumb) of ucl_unpack after copy*/
20ucl_start: .word 0 /* Start of the ucl-compressed OF image after copy */
21ucl_size: .word 0 /* Length in bytes of the compressed OF image */
22copy_start: .word 0 /* Start of the copy of the ucl_unpack function */
23copy_size: .word 0 /* uclunpack_size + ucl_paddedsize */
24
25start:
26 /* A delay loop - just to prove we're running */
27 mov r1, #0x500000 /* Approximately 5 seconds */
28loop: subs r1, r1, #1
29 bne loop
30
31 /* First copy the compressed firmware to unused RAM */
32
33 ldr r0, copy_start /* Source */
34 ldr r1, copy_size /* Source length */
35
36 mov r2, #0x40000 /* Destination end */
37 sub r2, r2, r1
38
39memcpy:
40 ldrb r3, [r0], #1
41 strb r3, [r2], #1
42 cmp r2, #0x40000 /* Stop when we reached dest_end */
43 bne memcpy
44
45 /* Call the ucl decompress function, which will branch to 0x0 */
46 /* on completion */
47
48 ldr r0, ucl_start /* Address of compressed image */
49 ldr r1, ucl_size /* Compressed size */
50 mov r2, #0 /* Destination */
51
52 ldr r3, ucl_unpack
53 bx r3
54
55 /* never reached */