summaryrefslogtreecommitdiff
path: root/utils/AMS/hacking/mkamsboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/AMS/hacking/mkamsboot.c')
-rw-r--r--utils/AMS/hacking/mkamsboot.c195
1 files changed, 110 insertions, 85 deletions
diff --git a/utils/AMS/hacking/mkamsboot.c b/utils/AMS/hacking/mkamsboot.c
index 30ca66e43b..ea434bc893 100644
--- a/utils/AMS/hacking/mkamsboot.c
+++ b/utils/AMS/hacking/mkamsboot.c
@@ -26,26 +26,33 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
26 26
27Insert a Rockbox bootloader into an AMS original firmware file. 27Insert a Rockbox bootloader into an AMS original firmware file.
28 28
29The first instruction in an AMS firmware file is always of the form: 29We replace the main firmware block (bytes 0x400..padded_firmware_size+0x400)
30with the following:
30 31
31 ldr pc, [pc, #xxx] 32Bytes 0..(firmware_size-ucl_size) - Our bootloader code
33Bytes (firmware_size-ucl_size)..firmware_size - UCL compressed OF image
34Bytes firmware_size..padded_firmware_size - UCL decompress function
32 35
33where [pc, #xxx] contains the entry point of the firmware - e.g. 0x00000138 36mkamsboot writes the following values at offsets into our bootloader code:
34 37
35mkamsboot appends the Rockbox bootloader to the end of the original 380x20 - Entry point (plus 1 - for thumb mode) of the ucl_unpack function
36firmware block in the firmware file and shifts the remaining contents of the firmware file to make space for it. 390x24 - Location of the UCL compressed version of the original firmware block
37 40
38It also replaces the contents of [pc, #xxx] with the entry point of 41mkamsboot then corrects the length (to include the UCL decompress
39our bootloader - i.e. the length of the original firmware block plus 4 42function) and checksum in the main firmware headers (both copies),
40bytes. 43creating a new legal firmware file which can be installed on the
44device.
41 45
42It then stores the original entry point from [pc, #xxx] in the first 46Our bootloader first checks for the "dual-boot" keypress, and then either:
43four bytes of the Rockbox bootloader image, which is used by the
44bootloader to dual-boot.
45 47
46Finally, mkamsboot corrects the length and checksum in the main 48a) Branches to the ucl_unpack function, which will then branch to 0x0 after
47firmware headers (both copies), creating a new legal firmware file 49 decompressing the OF.
48which can be installed on the device. 50
51b) Continues running with our test code
52
53This method uses no RAM outside the padded area of the original
54firmware block - the UCL compression can happen in-place when the
55compressed image is stored at the end of the destination buffer.
49 56
50*/ 57*/
51 58
@@ -106,35 +113,35 @@ static int calc_checksum(unsigned char* buf, uint32_t n)
106 113
107void usage(void) 114void usage(void)
108{ 115{
109 printf("Usage: mkamsboot <firmware file> <boot file> <output file>\n"); 116 printf("Usage: mkamsboot <firmware file> <ucl image> <boot file> <ucl unpack file> <output file>\n");
110 117
111 exit(1); 118 exit(1);
112} 119}
113 120
114int main(int argc, char* argv[]) 121int main(int argc, char* argv[])
115{ 122{
116 char *infile, *bootfile, *outfile; 123 char *infile, *uclfile, *bootfile, *uclunpackfile, *outfile;
117 int fdin, fdboot,fdout; 124 int fdin, fducl, fdboot, fduclunpack, fdout;
118 off_t len; 125 off_t len;
119 uint32_t n; 126 uint32_t n;
120 unsigned char* buf; 127 unsigned char* buf;
121 uint32_t ldr;
122 uint32_t origoffset;
123 uint32_t firmware_size; 128 uint32_t firmware_size;
124 uint32_t firmware_paddedsize; 129 uint32_t firmware_paddedsize;
125 uint32_t bootloader_size; 130 uint32_t bootloader_size;
126 uint32_t new_paddedsize; 131 uint32_t ucl_size;
132 uint32_t uclunpack_size;
127 uint32_t sum,filesum; 133 uint32_t sum,filesum;
128 uint32_t new_length;
129 uint32_t i; 134 uint32_t i;
130 135
131 if(argc != 4) { 136 if(argc != 6) {
132 usage(); 137 usage();
133 } 138 }
134 139
135 infile = argv[1]; 140 infile = argv[1];
136 bootfile = argv[2]; 141 uclfile = argv[2];
137 outfile = argv[3]; 142 bootfile = argv[3];
143 uclunpackfile = argv[4];
144 outfile = argv[5];
138 145
139 /* Open the bootloader file */ 146 /* Open the bootloader file */
140 fdboot = open(bootfile, O_RDONLY|O_BINARY); 147 fdboot = open(bootfile, O_RDONLY|O_BINARY);
@@ -147,6 +154,28 @@ int main(int argc, char* argv[])
147 bootloader_size = filesize(fdboot); 154 bootloader_size = filesize(fdboot);
148 155
149 156
157 /* Open the UCL-compressed image of the firmware block */
158 fduclunpack = open(uclunpackfile, O_RDONLY|O_BINARY);
159 if (fduclunpack < 0)
160 {
161 fprintf(stderr,"[ERR] Could not open %s for reading\n",uclunpackfile);
162 return 1;
163 }
164
165 uclunpack_size = filesize(fduclunpack);
166
167
168 /* Open the UCL-compressed image of the firmware block */
169 fducl = open(uclfile, O_RDONLY|O_BINARY);
170 if (fducl < 0)
171 {
172 fprintf(stderr,"[ERR] Could not open %s for reading\n",uclfile);
173 return 1;
174 }
175
176 ucl_size = filesize(fducl);
177
178
150 /* Open the firmware file */ 179 /* Open the firmware file */
151 fdin = open(infile,O_RDONLY|O_BINARY); 180 fdin = open(infile,O_RDONLY|O_BINARY);
152 181
@@ -158,9 +187,8 @@ int main(int argc, char* argv[])
158 if ((len = filesize(fdin)) < 0) 187 if ((len = filesize(fdin)) < 0)
159 return 1; 188 return 1;
160 189
161 /* We will need no more memory than the total size plus the bootloader size 190 /* Allocate memory for the OF image - we don't change the size */
162 padded to a boundary */ 191 if ((buf = malloc(len)) == NULL) {
163 if ((buf = malloc(len + PAD_TO_BOUNDARY(bootloader_size))) == NULL) {
164 fprintf(stderr,"[ERR] Could not allocate buffer for input file (%d bytes)\n",(int)len); 192 fprintf(stderr,"[ERR] Could not allocate buffer for input file (%d bytes)\n",(int)len);
165 return 1; 193 return 1;
166 } 194 }
@@ -181,91 +209,83 @@ int main(int argc, char* argv[])
181 209
182 firmware_paddedsize = PAD_TO_BOUNDARY(firmware_size); 210 firmware_paddedsize = PAD_TO_BOUNDARY(firmware_size);
183 211
184 /* Total new size */ 212 fprintf(stderr,"Original firmware size - %d bytes\n",firmware_size);
185 new_paddedsize = PAD_TO_BOUNDARY(firmware_size + bootloader_size); 213 fprintf(stderr,"Padded firmware size - %d bytes\n",firmware_paddedsize);
186 214 fprintf(stderr,"Bootloader size - %d bytes\n",bootloader_size);
187 /* Total new size of firmware file */ 215 fprintf(stderr,"UCL image size - %d bytes\n",ucl_size);
188 new_length = len + (new_paddedsize - firmware_paddedsize); 216 fprintf(stderr,"UCL unpack function size - %d bytes\n",uclunpack_size);
217 fprintf(stderr,"Original total size of firmware - %d bytes\n",(int)len);
218
219 /* Check we have room for our bootloader - in the future, we could UCL
220 pack this image as well if we need to. */
221 if (bootloader_size > (firmware_size - ucl_size)) {
222 fprintf(stderr,"[ERR] Bootloader too large (%d bytes, %d available)\n",
223 bootloader_size, firmware_size - ucl_size);
224 return 1;
225 }
189 226
190 fprintf(stderr,"Original firmware size - 0x%08x\n",firmware_size); 227 /* Check we have enough room for the UCL unpack function. This
191 fprintf(stderr,"Padded firmware size - 0x%08x\n",firmware_paddedsize); 228 needs to be outside the firmware block, so if we wanted to
192 fprintf(stderr,"Bootloader size - 0x%08x\n",bootloader_size); 229 support every firmware version, we could store this function in
193 fprintf(stderr,"New padded size - 0x%08x\n",new_paddedsize); 230 the main firmware block, and then copy it to an unused part of
194 fprintf(stderr,"Original total size of firmware - 0x%08x\n",(int)len); 231 RAM. */
195 fprintf(stderr,"New total size of firmware - 0x%08x\n",new_length); 232 if (uclunpack_size > (firmware_paddedsize - firmware_size)) {
233 fprintf(stderr,"[ERR] UCL unpack function too large (%d bytes, %d available)\n",
234 uclunpack_size, firmware_paddedsize - firmware_size);
235 return 1;
236 }
196 237
197 if (firmware_paddedsize != new_paddedsize) { 238 /* Zero the original firmware area - not needed, but helps debugging */
198 /* We don't know how to safely increase the firmware size, so abort */ 239 memset(buf + 0x400, 0, firmware_size);
199 240
200 fprintf(stderr, 241 /* Locate our bootloader code at the start of the firmware block */
201 "[ERR] Bootloader too large (%d bytes - %d bytes available), aborting.\n", 242 n = read(fdboot, buf + 0x400, bootloader_size);
202 bootloader_size, firmware_paddedsize - firmware_size);
203 243
244 if (n != bootloader_size) {
245 fprintf(stderr,"[ERR] Could not load bootloader file\n");
204 return 1; 246 return 1;
205 } 247 }
248 close(fdboot);
206 249
207 ldr = get_uint32le(&buf[0x400]); 250 /* Locate the compressed image of the original firmware block at the end
251 of the firmware block */
252 n = read(fducl, buf + 0x400 + firmware_size - ucl_size, ucl_size);
208 253
209 if ((ldr & 0xfffff000) != 0xe59ff000) { 254 if (n != ucl_size) {
210 fprintf(stderr,"[ERR] Firmware file doesn't start with an \"ldr pc, [pc, #xx]\" instruction.\n"); 255 fprintf(stderr,"[ERR] Could not load ucl file\n");
211 return 1; 256 return 1;
212 } 257 }
213 origoffset = (ldr&0xfff) + 8; 258 close(fducl);
214
215 printf("original firmware entry point: 0x%08x\n",get_uint32le(buf + 0x400 + origoffset));
216 printf("New entry point: 0x%08x\n", firmware_size + 4);
217
218#if 0
219 /* Replace the "Product: Express" string with "Rockbox" */
220 i = 0x400 + firmware_size - 7;
221 while ((i > 0x400) && (memcmp(&buf[i],"Express",7)!=0))
222 i--;
223 259
224 i = (i + 3) & ~0x3;
225
226 if (i >= 0x400) {
227 printf("Replacing \"Express\" string at offset 0x%08x\n",i);
228 memcpy(&buf[i],"Rockbox",7);
229 } else {
230 printf("Could not find \"Express\" string to replace\n");
231 }
232#endif
233 260
234 n = read(fdboot, buf + 0x400 + firmware_size, bootloader_size); 261 /* Locate our UCL unpack function in the padding after the firmware block */
262 n = read(fduclunpack, buf + 0x400 + firmware_size, uclunpack_size);
235 263
236 if (n != bootloader_size) { 264 if (n != uclunpack_size) {
237 fprintf(stderr,"[ERR] Could not bootloader file\n"); 265 fprintf(stderr,"[ERR] Could not load uclunpack file\n");
238 return 1; 266 return 1;
239 } 267 }
240 close(fdboot); 268 close(fduclunpack);
241 269
242 /* Replace first word of the bootloader with the original entry point */ 270 put_uint32le(&buf[0x420], firmware_size + 1); /* UCL unpack entry point */
243 put_uint32le(buf + 0x400 + firmware_size, get_uint32le(buf + 0x400 + origoffset)); 271 put_uint32le(&buf[0x424], firmware_size - ucl_size); /* Location of OF */
244
245#if 1
246 put_uint32le(buf + 0x400 + origoffset, firmware_size + 4);
247#endif
248 272
249 /* Update checksum */ 273 /* Update checksum */
250 sum = calc_checksum(buf + 0x400,firmware_size + bootloader_size); 274 sum = calc_checksum(buf + 0x400,firmware_size + uclunpack_size);
251 275
252 put_uint32le(&buf[0x04], sum); 276 put_uint32le(&buf[0x04], sum);
253 put_uint32le(&buf[0x204], sum); 277 put_uint32le(&buf[0x204], sum);
254 278
255 /* Update firmware block count */
256 put_uint32le(&buf[0x08], new_paddedsize / 0x200);
257 put_uint32le(&buf[0x208], new_paddedsize / 0x200);
258
259 /* Update firmware size */ 279 /* Update firmware size */
260 put_uint32le(&buf[0x0c], firmware_size + bootloader_size); 280 put_uint32le(&buf[0x0c], firmware_size + uclunpack_size);
261 put_uint32le(&buf[0x20c], firmware_size + bootloader_size); 281 put_uint32le(&buf[0x20c], firmware_size + uclunpack_size);
262 282
263 /* Update the whole-file checksum */ 283 /* Update the whole-file checksum */
264 filesum = 0; 284 filesum = 0;
265 for (i=0;i < new_length - 4; i+=4) 285 for (i=0;i < (unsigned)len - 4; i+=4)
266 filesum += get_uint32le(&buf[i]); 286 filesum += get_uint32le(&buf[i]);
267 287
268 put_uint32le(buf + new_length - 4, filesum); 288 put_uint32le(buf + len - 4, filesum);
269 289
270 290
271 /* Write the new firmware */ 291 /* Write the new firmware */
@@ -276,7 +296,12 @@ int main(int argc, char* argv[])
276 return 1; 296 return 1;
277 } 297 }
278 298
279 write(fdout, buf, new_length); 299 n = write(fdout, buf, len);
300
301 if (n != (unsigned)len) {
302 fprintf(stderr,"[ERR] Could not write firmware file\n");
303 return 1;
304 }
280 305
281 close(fdout); 306 close(fdout);
282 307