summaryrefslogtreecommitdiff
path: root/rbutil/mkamsboot/mkamsboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/mkamsboot/mkamsboot.c')
-rw-r--r--rbutil/mkamsboot/mkamsboot.c598
1 files changed, 305 insertions, 293 deletions
diff --git a/rbutil/mkamsboot/mkamsboot.c b/rbutil/mkamsboot/mkamsboot.c
index 65b88af994..4210d3bd7c 100644
--- a/rbutil/mkamsboot/mkamsboot.c
+++ b/rbutil/mkamsboot/mkamsboot.c
@@ -24,7 +24,17 @@
24 24
25/* 25/*
26 26
27Insert a Rockbox bootloader into an AMS original firmware file. 27Insert a Rockbox bootloader into a Sansa AMS original firmware file.
28
29Layout of a Sansa AMS original firmware file:
30
31 ---------------------- 0x0
32| HEADER |
33|----------------------| 0x400
34| FIRMWARE BLOCK |
35|----------------------| 0x400 + firmware block size
36| LIBRARIES/DATA |
37 ---------------------- END
28 38
29We replace the main firmware block (bytes 0x400..0x400+firmware_size) 39We replace the main firmware block (bytes 0x400..0x400+firmware_size)
30as follows: 40as follows:
@@ -50,9 +60,12 @@ as follows:
50 60
51This entire block fits into the space previously occupied by the main 61This entire block fits into the space previously occupied by the main
52firmware block - the space saved by compressing the OF image is used 62firmware block - the space saved by compressing the OF image is used
53to store the compressed version of the Rockbox bootloader. The OF 63to store the compressed version of the Rockbox bootloader.
54image is typically about 120KB, which allows us to store a Rockbox 64
55bootloader with an uncompressed size of about 60KB-70KB. 65On version 1 firmwares, the OF image is typically about 120KB, which allows
66us to store a Rockbox bootloader with an uncompressed size of about 60KB-70KB.
67Version 2 firmwares are bigger and are stored in SDRAM (instead of IRAM).
68In both cases, the RAM we are using is mapped at offset 0x0.
56 69
57mkamsboot then corrects the checksums and writes a new legal firmware 70mkamsboot then corrects the checksums and writes a new legal firmware
58file which can be installed on the device. 71file which can be installed on the device.
@@ -65,7 +78,7 @@ end of RAM.
65 78
66Then, depending on the detection of the dual-boot keypress, either the 79Then, 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 80OF 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. 81the ucl unpack function) and uncompressed to the start of RAM.
69 82
70Finally, the ucl unpack function branches to address 0x0, passing 83Finally, the ucl unpack function branches to address 0x0, passing
71execution to the uncompressed firmware. 84execution to the uncompressed firmware.
@@ -73,7 +86,6 @@ execution to the uncompressed firmware.
73 86
74*/ 87*/
75 88
76
77#include <stdio.h> 89#include <stdio.h>
78#include <stdlib.h> 90#include <stdlib.h>
79#include <stdint.h> 91#include <stdint.h>
@@ -85,27 +97,22 @@ execution to the uncompressed firmware.
85 97
86#include <ucl/ucl.h> 98#include <ucl/ucl.h>
87 99
88/* Headers for ARM code binaries */ 100#include "mkamsboot.h"
89#include "nrv2e_d8.h" 101
90#include "md5.h" 102#include "md5.h"
91 103
92#include "dualboot_clip.h" 104/* Header for ARM code binaries */
93#include "dualboot_e200v2.h" 105#include "dualboot.h"
94#include "dualboot_fuze.h"
95#include "dualboot_m200v4.h"
96#include "dualboot_c200v2.h"
97 106
98/* Win32 compatibility */ 107/* Win32 compatibility */
99#ifndef O_BINARY 108#ifndef O_BINARY
100#define O_BINARY 0 109#define O_BINARY 0
101#endif 110#endif
102 111
103#ifndef VERSION 112#define VERSION "1.0"
104#define VERSION "0.1"
105#endif
106 113
107enum 114/* Supported models */
108{ 115enum {
109 MODEL_UNKNOWN = -1, 116 MODEL_UNKNOWN = -1,
110 MODEL_FUZE = 0, 117 MODEL_FUZE = 0,
111 MODEL_CLIP, 118 MODEL_CLIP,
@@ -115,31 +122,31 @@ enum
115 MODEL_C200V2, 122 MODEL_C200V2,
116}; 123};
117 124
118static const char* model_names[] = 125/* Descriptive name of these models */
119{ 126static const char* model_names[] = {
120 "Fuze", 127 "Fuze",
121 "Clip", 128 "Clip",
122 "Clip V2", 129 "Clip v2",
123 "e200 v2", 130 "e200 v2",
124 "m200 v4", 131 "m200 v4",
125 "c200 v2" 132 "c200 v2"
126}; 133};
127 134
128static const unsigned char* bootloaders[] = 135/* Dualboot functions for these models */
129{ 136static const unsigned char* bootloaders[] = {
130 dualboot_fuze, 137 dualboot_fuze,
131 dualboot_clip, 138 dualboot_clip,
132 NULL, 139 dualboot_clipv2,
133 dualboot_e200v2, 140 dualboot_e200v2,
134 dualboot_m200v4, 141 dualboot_m200v4,
135 dualboot_c200v2, 142 dualboot_c200v2,
136}; 143};
137 144
138static const int bootloader_sizes[] = 145/* Size of dualboot functions for these models */
139{ 146static const int bootloader_sizes[] = {
140 sizeof(dualboot_fuze), 147 sizeof(dualboot_fuze),
141 sizeof(dualboot_clip), 148 sizeof(dualboot_clip),
142 0, 149 sizeof(dualboot_clipv2),
143 sizeof(dualboot_e200v2), 150 sizeof(dualboot_e200v2),
144 sizeof(dualboot_m200v4), 151 sizeof(dualboot_m200v4),
145 sizeof(dualboot_c200v2), 152 sizeof(dualboot_c200v2),
@@ -147,11 +154,10 @@ static const int bootloader_sizes[] =
147 154
148/* Model names used in the Rockbox header in ".sansa" files - these match the 155/* Model names used in the Rockbox header in ".sansa" files - these match the
149 -add parameter to the "scramble" tool */ 156 -add parameter to the "scramble" tool */
150static const char* rb_model_names[] = 157static const char* rb_model_names[] = {
151{
152 "fuze", 158 "fuze",
153 "clip", 159 "clip",
154 NULL, 160 "clv2",
155 "e2v2", 161 "e2v2",
156 "m2v4", 162 "m2v4",
157 "c2v2", 163 "c2v2",
@@ -159,11 +165,10 @@ static const char* rb_model_names[] =
159 165
160/* Model numbers used to initialise the checksum in the Rockbox header in 166/* Model numbers used to initialise the checksum in the Rockbox header in
161 ".sansa" files - these are the same as MODEL_NUMBER in config-target.h */ 167 ".sansa" files - these are the same as MODEL_NUMBER in config-target.h */
162static const int rb_model_num[] = 168static const int rb_model_num[] = {
163{
164 43, 169 43,
165 40, 170 40,
166 0, 171 60,
167 41, 172 41,
168 42, 173 42,
169 44 174 44
@@ -172,7 +177,7 @@ static const int rb_model_num[] =
172struct md5sums { 177struct md5sums {
173 int model; 178 int model;
174 char *version; 179 char *version;
175 int fw_version; 180 int fw_version; /* version 2 is used in Clipv2 and Fuzev2 firmwares */
176 char *md5; 181 char *md5;
177}; 182};
178 183
@@ -181,27 +186,32 @@ struct md5sums {
181static struct md5sums sansasums[] = { 186static struct md5sums sansasums[] = {
182 /* NOTE: Different regional versions of the firmware normally only 187 /* NOTE: Different regional versions of the firmware normally only
183 differ in the filename - the md5sums are identical */ 188 differ in the filename - the md5sums are identical */
184 { MODEL_E200V2, "3.01.11", 1, "e622ca8cb6df423f54b8b39628a1f0a3" }, 189
185 { MODEL_E200V2, "3.01.14", 1, "2c1d0383fc3584b2cc83ba8cc2243af6" }, 190 /* model version fw_version md5 */
186 { MODEL_E200V2, "3.01.16", 1, "12563ad71b25a1034cf2092d1e0218c4" }, 191 { MODEL_E200V2, "3.01.11", 1, "e622ca8cb6df423f54b8b39628a1f0a3" },
187 192 { MODEL_E200V2, "3.01.14", 1, "2c1d0383fc3584b2cc83ba8cc2243af6" },
188 { MODEL_FUZE, "1.01.11", 1, "cac8ffa03c599330ac02c4d41de66166" }, 193 { MODEL_E200V2, "3.01.16", 1, "12563ad71b25a1034cf2092d1e0218c4" },
189 { MODEL_FUZE, "1.01.15", 1, "df0e2c1612727f722c19a3c764cff7f2" }, 194
190 { MODEL_FUZE, "1.01.22", 1, "5aff5486fe8dd64239cc71eac470af98" }, 195 { MODEL_FUZE, "1.01.11", 1, "cac8ffa03c599330ac02c4d41de66166" },
191 { MODEL_FUZE, "1.02.26", 1, "7c632c479461c48c8833baed74eb5e4f" }, 196 { MODEL_FUZE, "1.01.15", 1, "df0e2c1612727f722c19a3c764cff7f2" },
192 197 { MODEL_FUZE, "1.01.22", 1, "5aff5486fe8dd64239cc71eac470af98" },
193 { MODEL_C200V2, "3.02.05", 1, "b6378ebd720b0ade3fad4dc7ab61c1a5" }, 198 { MODEL_FUZE, "1.02.26", 1, "7c632c479461c48c8833baed74eb5e4f" },
194 199
195 { MODEL_M200V4, "4.00.45", 1, "82e3194310d1514e3bbcd06e84c4add3" }, 200 { MODEL_C200V2, "3.02.05", 1, "b6378ebd720b0ade3fad4dc7ab61c1a5" },
196 { MODEL_M200V4, "4.01.08-A", 1, "fc9dd6116001b3e6a150b898f1b091f0" }, 201
197 { MODEL_M200V4, "4.01.08-E", 1, "d3fb7d8ec8624ee65bc99f8dab0e2369" }, 202 { MODEL_M200V4, "4.00.45", 1, "82e3194310d1514e3bbcd06e84c4add3" },
198 203 { MODEL_M200V4, "4.01.08-A", 1, "fc9dd6116001b3e6a150b898f1b091f0" },
199 { MODEL_CLIP, "1.01.17", 1, "12caad785d506219d73f538772afd99e" }, 204 { MODEL_M200V4, "4.01.08-E", 1, "d3fb7d8ec8624ee65bc99f8dab0e2369" },
200 { MODEL_CLIP, "1.01.18", 1, "d720b266bd5afa38a198986ef0508a45" }, 205
201 { MODEL_CLIP, "1.01.20", 1, "236d8f75189f468462c03f6d292cf2ac" }, 206 { MODEL_CLIP, "1.01.17", 1, "12caad785d506219d73f538772afd99e" },
202 { MODEL_CLIP, "1.01.29", 1, "c12711342169c66e209540cd1f27cd26" }, 207 { MODEL_CLIP, "1.01.18", 1, "d720b266bd5afa38a198986ef0508a45" },
203 { MODEL_CLIP, "1.01.30", 1, "f2974d47c536549c9d8259170f1dbe4d" }, 208 { MODEL_CLIP, "1.01.20", 1, "236d8f75189f468462c03f6d292cf2ac" },
204 { MODEL_CLIP, "1.01.32", 1, "d835d12342500732ffb9c4ee54abec15" }, 209 { MODEL_CLIP, "1.01.29", 1, "c12711342169c66e209540cd1f27cd26" },
210 { MODEL_CLIP, "1.01.30", 1, "f2974d47c536549c9d8259170f1dbe4d" },
211 { MODEL_CLIP, "1.01.32", 1, "d835d12342500732ffb9c4ee54abec15" },
212
213 { MODEL_CLIPV2, "2.01.16", 2, "c57fb3fcbe07c2c9b360f060938f80cb" },
214 { MODEL_CLIPV2, "2.01.32", 2, "0ad3723e52022509089d938d0fbbf8c5" }
205}; 215};
206 216
207#define NUM_MD5S (sizeof(sansasums)/sizeof(sansasums[0])) 217#define NUM_MD5S (sizeof(sansasums)/sizeof(sansasums[0]))
@@ -209,7 +219,7 @@ static struct md5sums sansasums[] = {
209static off_t filesize(int fd) { 219static off_t filesize(int fd) {
210 struct stat buf; 220 struct stat buf;
211 221
212 if (fstat(fd,&buf) < 0) { 222 if (fstat(fd, &buf) < 0) {
213 perror("[ERR] Checking filesize of input file"); 223 perror("[ERR] Checking filesize of input file");
214 return -1; 224 return -1;
215 } else { 225 } else {
@@ -217,30 +227,26 @@ static off_t filesize(int fd) {
217 } 227 }
218} 228}
219 229
220static uint32_t get_uint32le(unsigned char* p) 230static uint32_t get_uint32le(unsigned char* p) {
221{
222 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 231 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
223} 232}
224 233
225static uint32_t get_uint32be(unsigned char* p) 234static uint32_t get_uint32be(unsigned char* p) {
226{
227 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 235 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
228} 236}
229 237
230static void put_uint32le(unsigned char* p, uint32_t x) 238static void put_uint32le(unsigned char* p, uint32_t x) {
231{
232 p[0] = x & 0xff; 239 p[0] = x & 0xff;
233 p[1] = (x >> 8) & 0xff; 240 p[1] = (x >> 8) & 0xff;
234 p[2] = (x >> 16) & 0xff; 241 p[2] = (x >> 16) & 0xff;
235 p[3] = (x >> 24) & 0xff; 242 p[3] = (x >> 24) & 0xff;
236} 243}
237 244
238void calc_MD5(unsigned char* buf, int len, char *md5str) 245void calc_MD5(unsigned char* buf, int len, char *md5str) {
239{
240 int i; 246 int i;
241 md5_context ctx; 247 md5_context ctx;
242 unsigned char md5sum[16]; 248 unsigned char md5sum[16];
243 249
244 md5_starts(&ctx); 250 md5_starts(&ctx);
245 md5_update(&ctx, buf, len); 251 md5_update(&ctx, buf, len);
246 md5_finish(&ctx, md5sum); 252 md5_finish(&ctx, md5sum);
@@ -249,9 +255,8 @@ void calc_MD5(unsigned char* buf, int len, char *md5str)
249 sprintf(md5str + 2*i, "%02x", md5sum[i]); 255 sprintf(md5str + 2*i, "%02x", md5sum[i]);
250} 256}
251 257
252 258/* Calculate a simple checksum used in Sansa Original Firmwares */
253static uint32_t calc_checksum(unsigned char* buf, uint32_t n) 259static uint32_t calc_checksum(unsigned char* buf, uint32_t n) {
254{
255 uint32_t sum = 0; 260 uint32_t sum = 0;
256 uint32_t i; 261 uint32_t i;
257 262
@@ -261,10 +266,8 @@ static uint32_t calc_checksum(unsigned char* buf, uint32_t n)
261 return sum; 266 return sum;
262} 267}
263 268
264static int get_model(int model_id) 269static int get_model(int model_id) {
265{ 270 switch(model_id) {
266 switch(model_id)
267 {
268 case 0x1e: 271 case 0x1e:
269 return MODEL_FUZE; 272 return MODEL_FUZE;
270 case 0x22: 273 case 0x22:
@@ -282,9 +285,8 @@ static int get_model(int model_id)
282 return MODEL_UNKNOWN; 285 return MODEL_UNKNOWN;
283} 286}
284 287
285 288/* Compress using nrv2e algorithm : Thumb decompressor fits in 168 bytes ! */
286static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize) 289static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize) {
287{
288 int maxsize; 290 int maxsize;
289 unsigned char* outbuf; 291 unsigned char* outbuf;
290 int r; 292 int r;
@@ -295,10 +297,9 @@ static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize)
295 /* Allocate some memory for the output buffer */ 297 /* Allocate some memory for the output buffer */
296 outbuf = malloc(maxsize); 298 outbuf = malloc(maxsize);
297 299
298 if (outbuf == NULL) { 300 if (outbuf == NULL)
299 return NULL; 301 return NULL;
300 } 302
301
302 r = ucl_nrv2e_99_compress( 303 r = ucl_nrv2e_99_compress(
303 (const ucl_bytep) inbuf, 304 (const ucl_bytep) inbuf,
304 (ucl_uint) insize, 305 (ucl_uint) insize,
@@ -306,8 +307,7 @@ static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize)
306 (ucl_uintp) outsize, 307 (ucl_uintp) outsize,
307 0, 10, NULL, NULL); 308 0, 10, NULL, NULL);
308 309
309 if (r != UCL_E_OK || *outsize > maxsize) 310 if (r != UCL_E_OK || *outsize > maxsize) {
310 {
311 /* this should NEVER happen, and implies memory corruption */ 311 /* this should NEVER happen, and implies memory corruption */
312 fprintf(stderr, "internal error - compression failed: %d\n", r); 312 fprintf(stderr, "internal error - compression failed: %d\n", r);
313 free(outbuf); 313 free(outbuf);
@@ -317,42 +317,105 @@ static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize)
317 return outbuf; 317 return outbuf;
318} 318}
319 319
320static unsigned char* load_file(char* filename, off_t* bufsize) 320#define ERROR(format, ...) \
321{ 321 do { \
322 snprintf(errstr, errstrsize, format, __VA_ARGS__); \
323 goto error; \
324 } while(0)
325
326/* Loads a Sansa AMS Original Firmware file into memory */
327unsigned char* load_of_file(
328 char* filename, off_t* bufsize, char* md5sum, int* model,
329 int* fw_version, int* firmware_size, unsigned char** of_packed,
330 int* of_packedsize, char* errstr, int errstrsize
331) {
322 int fd; 332 int fd;
323 unsigned char* buf; 333 unsigned char* buf =NULL;
324 off_t n; 334 off_t n;
335 unsigned int i=0;
336 uint32_t checksum;
337 int model_id;
338 unsigned int last_word;
325 339
326 fd = open(filename, O_RDONLY|O_BINARY); 340 fd = open(filename, O_RDONLY|O_BINARY);
327 if (fd < 0) 341 if (fd < 0)
328 { 342 ERROR("[ERR] Could not open %s for reading\n", filename);
329 fprintf(stderr,"[ERR] Could not open %s for reading\n",filename);
330 return NULL;
331 }
332 343
333 *bufsize = filesize(fd); 344 *bufsize = filesize(fd);
334 345
335 buf = malloc(*bufsize); 346 buf = malloc(*bufsize);
336 if (buf == NULL) { 347 if (buf == NULL)
337 fprintf(stderr,"[ERR] Could not allocate memory for %s\n",filename); 348 ERROR("[ERR] Could not allocate memory for %s\n", filename);
338 return NULL;
339 }
340 349
341 n = read(fd, buf, *bufsize); 350 n = read(fd, buf, *bufsize);
342 351
343 if (n != *bufsize) { 352 if (n != *bufsize)
344 fprintf(stderr,"[ERR] Could not read file %s\n",filename); 353 ERROR("[ERR] Could not read file %s\n", filename);
345 return NULL; 354
355 /* check the file */
356
357 /* Calculate MD5 checksum of OF */
358 calc_MD5(buf, *bufsize, md5sum);
359
360 while ((i < NUM_MD5S) && (strcmp(sansasums[i].md5, md5sum) != 0))
361 i++;
362
363 if (i < NUM_MD5S) {
364 *model = sansasums[i].model;
365 *fw_version = sansasums[i].fw_version;
366 } else {
367 fprintf(stderr, "[WARN] ****** Original firmware unknown ******\n");
368 if (get_uint32le(&buf[0x204])==0x0000f000) {
369 *fw_version = 2;
370 model_id = buf[0x219];
371 } else {
372 *fw_version = 1;
373 model_id = buf[0x215];
374 }
375
376 *model = get_model(model_id);
377
378 if (*model == MODEL_UNKNOWN)
379 ERROR("[ERR] Unknown firmware - model id 0x%02x\n", model_id);
346 } 380 }
347 381
382 /* TODO: Do some more sanity checks on the OF image. Some images (like
383 m200v4) dont have a checksum at the end, only padding (0xdeadbeef). */
384 last_word = *bufsize - 4;
385 checksum = get_uint32le(buf + last_word);
386 if (checksum != 0xefbeadde && checksum != calc_checksum(buf, last_word))
387 ERROR("%s", "[ERR] Whole file checksum failed\n");
388
389 if (bootloaders[*model] == NULL)
390 ERROR("[ERR] Unsupported model - \"%s\"\n", model_names[*model]);
391
392
393 /* Get the firmware size */
394 if (*fw_version == 1)
395 *firmware_size = get_uint32le(&buf[0x0c]);
396 else /* fw_version == 2 */
397 *firmware_size = get_uint32le(&buf[0x10]);
398
399 /* Compress the original firmware image */
400 *of_packed = uclpack(buf + 0x400, *firmware_size, of_packedsize);
401 if (*of_packed == NULL)
402 ERROR("[ERR] Could not compress %s\n", filename);
403
348 return buf; 404 return buf;
349}
350 405
406error:
407 free(buf);
408 return NULL;
409}
351 410
352static unsigned char* load_rockbox_file(char* filename, int model, off_t* bufsize) 411/* Loads a rockbox bootloader file into memory */
353{ 412unsigned char* load_rockbox_file(
413 char* filename, int model, int* bufsize, int* rb_packedsize,
414 char* errstr, int errstrsize
415) {
354 int fd; 416 int fd;
355 unsigned char* buf; 417 unsigned char* buf = NULL;
418 unsigned char* packed = NULL;
356 unsigned char header[8]; 419 unsigned char header[8];
357 uint32_t sum; 420 uint32_t sum;
358 off_t n; 421 off_t n;
@@ -360,39 +423,28 @@ static unsigned char* load_rockbox_file(char* filename, int model, off_t* bufsiz
360 423
361 fd = open(filename, O_RDONLY|O_BINARY); 424 fd = open(filename, O_RDONLY|O_BINARY);
362 if (fd < 0) 425 if (fd < 0)
363 { 426 ERROR("[ERR] Could not open %s for reading\n", filename);
364 fprintf(stderr,"[ERR] Could not open %s for reading\n",filename);
365 return NULL;
366 }
367 427
368 /* Read Rockbox header */ 428 /* Read Rockbox header */
369 n = read(fd, header, sizeof(header)); 429 n = read(fd, header, sizeof(header));
370 if (n != sizeof(header)) { 430 if (n != sizeof(header))
371 fprintf(stderr,"[ERR] Could not read file %s\n",filename); 431 ERROR("[ERR] Could not read file %s\n", filename);
372 return NULL;
373 }
374 432
375 /* Check for correct model string */ 433 /* Check for correct model string */
376 if (memcmp(rb_model_names[model],header + 4,4)!=0) { 434 if (memcmp(rb_model_names[model], header + 4, 4)!=0)
377 fprintf(stderr,"[ERR] Model name \"%s\" not found in %s\n", 435 ERROR("[ERR] Model name \"%s\" not found in %s\n",
378 rb_model_names[model],filename); 436 rb_model_names[model], filename);
379 return NULL;
380 }
381 437
382 *bufsize = filesize(fd) - sizeof(header); 438 *bufsize = filesize(fd) - sizeof(header);
383 439
384 buf = malloc(*bufsize); 440 buf = malloc(*bufsize);
385 if (buf == NULL) { 441 if (buf == NULL)
386 fprintf(stderr,"[ERR] Could not allocate memory for %s\n",filename); 442 ERROR("[ERR] Could not allocate memory for %s\n", filename);
387 return NULL;
388 }
389 443
390 n = read(fd, buf, *bufsize); 444 n = read(fd, buf, *bufsize);
391 445
392 if (n != *bufsize) { 446 if (n != *bufsize)
393 fprintf(stderr,"[ERR] Could not read file %s\n",filename); 447 ERROR("[ERR] Could not read file %s\n", filename);
394 return NULL;
395 }
396 448
397 /* Check checksum */ 449 /* Check checksum */
398 sum = rb_model_num[model]; 450 sum = rb_model_num[model];
@@ -401,176 +453,36 @@ static unsigned char* load_rockbox_file(char* filename, int model, off_t* bufsiz
401 sum += buf[i]; 453 sum += buf[i];
402 } 454 }
403 455
404 if (sum != get_uint32be(header)) { 456 if (sum != get_uint32be(header))
405 fprintf(stderr,"[ERR] Checksum mismatch in %s\n",filename); 457 ERROR("[ERR] Checksum mismatch in %s\n", filename);
406 return NULL;
407 }
408 return buf;
409}
410
411
412int main(int argc, char* argv[])
413{
414 char *infile, *bootfile, *outfile;
415 int fdout;
416 off_t len;
417 uint32_t n;
418 unsigned char* buf;
419 int firmware_size;
420 off_t bootloader_size;
421 uint32_t sum,filesum;
422 uint8_t model_id;
423 int model;
424 uint32_t i;
425 unsigned char* of_packed;
426 int of_packedsize;
427 unsigned char* rb_unpacked;
428 unsigned char* rb_packed;
429 int rb_packedsize;
430 int fw_version;
431 int totalsize;
432 unsigned char* p;
433 uint32_t checksum;
434 char md5sum[33]; /* 32 hex digits, plus terminating zero */
435
436 fprintf(stderr,"mkamsboot v" VERSION " - (C) Dave Chapman and Rafaël Carré 2008\n");
437 fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
438 fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
439
440 if(argc != 4) {
441 printf("Usage: mkamsboot <firmware file> <boot file> <output file>\n\n");
442 return 1;
443 }
444
445 infile = argv[1];
446 bootfile = argv[2];
447 outfile = argv[3];
448
449 /* Load original firmware file */
450 buf = load_file(infile, &len);
451
452 if (buf == NULL) {
453 fprintf(stderr,"[ERR] Could not load %s\n",infile);
454 return 1;
455 }
456
457 /* Calculate MD5 checksum of OF */
458 calc_MD5(buf, len, md5sum);
459 458
460 fprintf(stderr,"[INFO] MD5 sum - %s\n",md5sum); 459 packed = uclpack(buf, *bufsize, rb_packedsize);
460 if(packed == NULL)
461 ERROR("[ERR] Could not compress %s\n", filename);
461 462
462 i = 0; 463 free(buf);
463 while ((i < NUM_MD5S) && (strcmp(sansasums[i].md5, md5sum) != 0)) 464 return packed;
464 i++;
465 465
466 if (i < NUM_MD5S) { 466error:
467 model = sansasums[i].model; 467 free(buf);
468 fw_version = sansasums[i].fw_version; 468 return NULL;
469 fprintf(stderr,"[INFO] Original firmware MD5 checksum match - %s %s\n", 469}
470 model_names[model], sansasums[i].version);
471 } else {
472 if (get_uint32le(&buf[0x204])==0x0000f000) {
473 fw_version = 2;
474 model_id = buf[0x219];
475 } else {
476 fw_version = 1;
477 model_id = buf[0x215];
478 }
479
480 model = get_model(model_id);
481
482#if 0
483 /* if you are a tester this info might help */
484 fprintf(stderr,"[WARN] ****** Original firmware unknown ******\n");
485 if (model == MODEL_UNKNOWN) {
486 fprintf(stderr,"[ERR] Unknown firmware - model id 0x%02x\n",
487 model_id);
488 free(buf);
489 return 1;
490 }
491#else
492 /* else you don't want to brick your player */
493 fprintf(stderr, "[ERR] Original firmware untested - aborting\n");
494 free(buf);
495 return 1;
496#endif
497 }
498
499
500 /* TODO: Do some more sanity checks on the OF image. Some images (like
501 m200v4) dont have a checksum at the end, only padding (0xdeadbeef). */
502 checksum = get_uint32le(buf + len - 4);
503 if (checksum != 0xefbeadde && checksum != calc_checksum(buf, len - 4)) {
504
505 fprintf(stderr,"[ERR] Whole file checksum failed - %s\n",infile);
506 free(buf);
507 return 1;
508 }
509
510 if (bootloaders[model] == NULL) {
511 fprintf(stderr,"[ERR] Unsupported model - \"%s\"\n",model_names[model]);
512 free(buf);
513 return 1;
514 }
515
516 /* Load bootloader file */
517 rb_unpacked = load_rockbox_file(bootfile, model, &bootloader_size);
518 if (rb_unpacked == NULL) {
519 fprintf(stderr,"[ERR] Could not load %s\n",bootfile);
520 free(buf);
521 return 1;
522 }
523
524 printf("[INFO] Patching %s firmware\n",model_names[model]);
525
526 /* Get the firmware size */
527 firmware_size = get_uint32le(&buf[0x0c]);
528
529 /* Compress the original firmware image */
530 of_packed = uclpack(buf + 0x400, firmware_size, &of_packedsize);
531 if (of_packed == NULL) {
532 fprintf(stderr,"[ERR] Could not compress original firmware\n");
533 free(buf);
534 free(rb_unpacked);
535 return 1;
536 }
537
538 rb_packed = uclpack(rb_unpacked, bootloader_size, &rb_packedsize);
539 if (rb_packed == NULL) {
540 fprintf(stderr,"[ERR] Could not compress %s\n",bootfile);
541 free(buf);
542 free(rb_unpacked);
543 free(of_packed);
544 return 1;
545 }
546
547 /* We are finished with the unpacked version of the bootloader */
548 free(rb_unpacked);
549
550 fprintf(stderr,"[INFO] Original firmware size: %d bytes\n",firmware_size);
551 fprintf(stderr,"[INFO] Packed OF size: %d bytes\n",of_packedsize);
552 fprintf(stderr,"[INFO] Bootloader size: %d bytes\n",(int)bootloader_size);
553 fprintf(stderr,"[INFO] Packed bootloader size: %d bytes\n",rb_packedsize);
554 fprintf(stderr,"[INFO] Dual-boot function size: %d bytes\n",bootloader_sizes[model]);
555 fprintf(stderr,"[INFO] UCL unpack function size: %d bytes\n",sizeof(nrv2e_d8));
556
557 totalsize = bootloader_sizes[model] + sizeof(nrv2e_d8) + of_packedsize +
558 rb_packedsize;
559 470
560 fprintf(stderr,"[INFO] Total size of new image: %d bytes\n",totalsize); 471#undef ERROR
561 472
562 if (totalsize > firmware_size) { 473/* Patches a Sansa AMS Original Firmware file */
563 fprintf(stderr,"[ERR] No room to insert bootloader, aborting\n"); 474void patch_firmware(
564 free(buf); 475 int model, int fw_version, int firmware_size, unsigned char* buf,
565 free(rb_unpacked); 476 int len, unsigned char* of_packed, int of_packedsize,
566 free(of_packed); 477 unsigned char* rb_packed, int rb_packedsize
567 return 1; 478) {
568 } 479 unsigned char *p;
480 uint32_t sum, filesum;
481 unsigned int i;
569 482
570 /* Zero the original firmware area - not needed, but helps debugging */ 483 /* Zero the original firmware area - not needed, but helps debugging */
571 memset(buf + 0x400, 0, firmware_size); 484 memset(buf + 0x400, 0, firmware_size);
572 485
573
574 /* Insert dual-boot bootloader at offset 0 */ 486 /* Insert dual-boot bootloader at offset 0 */
575 memcpy(buf + 0x400, bootloaders[model], bootloader_sizes[model]); 487 memcpy(buf + 0x400, bootloaders[model], bootloader_sizes[model]);
576 488
@@ -589,7 +501,7 @@ int main(int argc, char* argv[])
589 p -= rb_packedsize; 501 p -= rb_packedsize;
590 memcpy(p, rb_packed, rb_packedsize); 502 memcpy(p, rb_packed, rb_packedsize);
591 503
592 /* Write the locations of the various images to the variables at the 504 /* Write the locations of the various images to the variables at the
593 start of the dualboot image - we save the location of the last byte 505 start of the dualboot image - we save the location of the last byte
594 in each image, along with the size in bytes */ 506 in each image, along with the size in bytes */
595 507
@@ -602,19 +514,18 @@ int main(int argc, char* argv[])
602 put_uint32le(&buf[0x42c], of_packedsize); 514 put_uint32le(&buf[0x42c], of_packedsize);
603 515
604 /* Compressed Rockbox image */ 516 /* Compressed Rockbox image */
605 put_uint32le(&buf[0x430], firmware_size - sizeof(nrv2e_d8) - of_packedsize - 1); 517 put_uint32le(&buf[0x430], firmware_size - sizeof(nrv2e_d8) - of_packedsize
518 - 1);
606 put_uint32le(&buf[0x434], rb_packedsize); 519 put_uint32le(&buf[0x434], rb_packedsize);
607 520
608 521
609 /* Update the firmware block checksum */ 522 /* Update the firmware block checksum */
610 sum = calc_checksum(buf + 0x400,firmware_size); 523 sum = calc_checksum(buf + 0x400, firmware_size);
611 524
612 if (fw_version == 1) { 525 if (fw_version == 1) {
613 put_uint32le(&buf[0x04], sum); 526 put_uint32le(&buf[0x04], sum);
614 put_uint32le(&buf[0x204], sum); 527 put_uint32le(&buf[0x204], sum);
615 } else { 528 } else {
616 /* TODO: Verify that this is correct for the v2 firmware */
617
618 put_uint32le(&buf[0x08], sum); 529 put_uint32le(&buf[0x08], sum);
619 put_uint32le(&buf[0x208], sum); 530 put_uint32le(&buf[0x208], sum);
620 531
@@ -629,29 +540,130 @@ int main(int argc, char* argv[])
629 filesum += get_uint32le(&buf[i]); 540 filesum += get_uint32le(&buf[i]);
630 541
631 put_uint32le(buf + len - 4, filesum); 542 put_uint32le(buf + len - 4, filesum);
543}
632 544
545/* returns size of new firmware block */
546int total_size(int model, int rb_packedsize, int of_packedsize) {
547 return bootloader_sizes[model] + sizeof(nrv2e_d8) + of_packedsize +
548 rb_packedsize;
549}
550
551#ifndef LIB
552/* standalone executable */
553int main(int argc, char* argv[]) {
554 char *infile, *bootfile, *outfile;
555 int fdout;
556 off_t len;
557 uint32_t n;
558 unsigned char* buf;
559 int firmware_size;
560 int bootloader_size;
561 int model;
562 unsigned char* of_packed;
563 int of_packedsize;
564 unsigned char* rb_packed;
565 int rb_packedsize;
566 int fw_version;
567 int totalsize;
568 char md5sum[33]; /* 32 hex digits, plus terminating zero */
569 char errstr[200];
570
571 fprintf(stderr,
572"mkamsboot v" VERSION " - (C) Dave Chapman and Rafaël Carré 2008\n"
573"This is free software; see the source for copying conditions. There is NO\n"
574"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
575"\n");
576
577 if(argc != 4) {
578 printf("Usage: mkamsboot <firmware file> <boot file> <output file>\n");
579 return 1;
580 }
581
582 infile = argv[1];
583 bootfile = argv[2];
584 outfile = argv[3];
585
586 /* Load original firmware file */
587 buf = load_of_file(infile, &len, md5sum, &model, &fw_version,
588 &firmware_size, &of_packed, &of_packedsize, errstr, sizeof(errstr));
589
590 if (buf == NULL) {
591 fprintf(stderr, "%s", errstr);
592 fprintf(stderr, "[ERR] Could not load %s\n", infile);
593 return 1;
594 }
595
596 fprintf(stderr, "[INFO] Original firmware MD5 checksum match - %s\n",
597 model_names[model]);
598
599
600 /* Load bootloader file */
601 rb_packed = load_rockbox_file(bootfile, model, &bootloader_size,
602 &rb_packedsize, errstr, sizeof(errstr));
603 if (rb_packed == NULL) {
604 fprintf(stderr, "%s", errstr);
605 fprintf(stderr, "[ERR] Could not load %s\n", bootfile);
606 free(buf);
607 free(of_packed);
608 return 1;
609 }
610
611 printf("[INFO] Patching %s firmware\n", model_names[model]);
612
613 fprintf(stderr, "[INFO] Original firmware size: %d bytes\n",
614 firmware_size);
615 fprintf(stderr, "[INFO] Packed OF size: %d bytes\n",
616 of_packedsize);
617 fprintf(stderr, "[INFO] Bootloader size: %d bytes\n",
618 (int)bootloader_size);
619 fprintf(stderr, "[INFO] Packed bootloader size: %d bytes\n",
620 rb_packedsize);
621 fprintf(stderr, "[INFO] Dual-boot function size: %d bytes\n",
622 bootloader_sizes[model]);
623 fprintf(stderr, "[INFO] UCL unpack function size: %d bytes\n",
624 sizeof(nrv2e_d8));
625
626 totalsize = total_size(model, of_packedsize, rb_packedsize);
627
628 fprintf(stderr, "[INFO] Total size of new image: %d bytes\n", totalsize);
629
630 if (totalsize > firmware_size) {
631 fprintf(stderr, "[ERR] No room to insert bootloader, aborting\n");
632 free(buf);
633 free(of_packed);
634 free(rb_packed);
635 return 1;
636 }
637
638 patch_firmware(model, fw_version, firmware_size, buf, len, of_packed,
639 of_packedsize, rb_packed, rb_packedsize);
633 640
634 /* Write the new firmware */ 641 /* Write the new firmware */
635 fdout = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666); 642 fdout = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
636 643
637 if (fdout < 0) { 644 if (fdout < 0) {
638 fprintf(stderr,"[ERR] Could not open %s for writing\n",outfile); 645 fprintf(stderr, "[ERR] Could not open %s for writing\n", outfile);
646 free(buf);
647 free(of_packed);
648 free(rb_packed);
639 return 1; 649 return 1;
640 } 650 }
641 651
642 n = write(fdout, buf, len); 652 n = write(fdout, buf, len);
643 653
644 if (n != (unsigned)len) { 654 if (n != (unsigned)len) {
645 fprintf(stderr,"[ERR] Could not write firmware file\n"); 655 fprintf(stderr, "[ERR] Could not write firmware file\n");
656 free(buf);
657 free(of_packed);
658 free(rb_packed);
646 return 1; 659 return 1;
647 } 660 }
648 661
649 close(fdout); 662 close(fdout);
650 663 free(buf);
651 fprintf(stderr," *****************************************************************************\n"); 664 free(of_packed);
652 fprintf(stderr," *** THIS CODE IS UNTESTED - DO NOT USE IF YOU CAN NOT RECOVER YOUR DEVICE ***\n"); 665 free(rb_packed);
653 fprintf(stderr," *****************************************************************************\n");
654 666
655 return 0; 667 return 0;
656
657} 668}
669#endif