imxtools/sbloader: implement stmp36xx recovery support
[maemo-rb.git] / utils / imxtools / sbtools / sb1.c
blob22854036c15821aabd75395e438893161f7868b6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2012 Amaury Pouly
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include <stdio.h>
22 #include <time.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include "misc.h"
26 #include "crypto.h"
27 #include "sb1.h"
29 static int sdram_size_table[] = {2, 8, 16, 32, 64};
31 #define NR_SDRAM_ENTRIES (int)(sizeof(sdram_size_table) / sizeof(sdram_size_table[0]))
33 int sb1_sdram_size_by_index(int index)
35 if(index < 0 || index >= NR_SDRAM_ENTRIES)
36 return -1;
37 return sdram_size_table[index];
40 int sb1_sdram_index_by_size(int size)
42 for(int i = 0; i < NR_SDRAM_ENTRIES; i++)
43 if(sdram_size_table[i] == size)
44 return i;
45 return -1;
48 static uint16_t swap16(uint16_t t)
50 return (t << 8) | (t >> 8);
53 static void fix_version(struct sb1_version_t *ver)
55 ver->major = swap16(ver->major);
56 ver->minor = swap16(ver->minor);
57 ver->revision = swap16(ver->revision);
60 enum sb1_error_t sb1_write_file(struct sb1_file_t *sb, const char *filename)
62 return SB1_ERROR;
65 struct sb1_file_t *sb1_read_file(const char *filename, void *u,
66 sb1_color_printf cprintf, enum sb1_error_t *err)
68 return sb1_read_file_ex(filename, 0, -1, u, cprintf, err);
71 struct sb1_file_t *sb1_read_file_ex(const char *filename, size_t offset, size_t size, void *u,
72 sb1_color_printf cprintf, enum sb1_error_t *err)
74 #define fatal(e, ...) \
75 do { if(err) *err = e; \
76 cprintf(u, true, GREY, __VA_ARGS__); \
77 free(buf); \
78 return NULL; } while(0)
80 FILE *f = fopen(filename, "rb");
81 void *buf = NULL;
82 if(f == NULL)
83 fatal(SB1_OPEN_ERROR, "Cannot open file for reading\n");
84 fseek(f, 0, SEEK_END);
85 size_t read_size = ftell(f);
86 fseek(f, offset, SEEK_SET);
87 if(size != (size_t)-1)
88 read_size = size;
89 buf = xmalloc(read_size);
90 if(fread(buf, read_size, 1, f) != 1)
92 fclose(f);
93 fatal(SB1_READ_ERROR, "Cannot read file\n");
95 fclose(f);
97 struct sb1_file_t *ret = sb1_read_memory(buf, read_size, u, cprintf, err);
98 free(buf);
99 return ret;
101 #undef fatal
104 static const char *sb1_cmd_name(int cmd)
106 switch(cmd)
108 case SB1_INST_LOAD: return "load";
109 case SB1_INST_FILL: return "fill";
110 case SB1_INST_JUMP: return "jump";
111 case SB1_INST_CALL: return "call";
112 case SB1_INST_MODE: return "mode";
113 case SB1_INST_SDRAM: return "sdram";
114 default: return "unknown";
118 static const char *sb1_datatype_name(int cmd)
120 switch(cmd)
122 case SB1_DATATYPE_UINT32: return "uint32";
123 case SB1_DATATYPE_UINT16: return "uint16";
124 case SB1_DATATYPE_UINT8: return "uint8";
125 default: return "unknown";
129 struct sb1_file_t *sb1_read_memory(void *_buf, size_t filesize, void *u,
130 sb1_color_printf cprintf, enum sb1_error_t *err)
132 struct sb1_file_t *file = NULL;
133 uint8_t *buf = _buf;
135 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
136 #define fatal(e, ...) \
137 do { if(err) *err = e; \
138 cprintf(u, true, GREY, __VA_ARGS__); \
139 sb1_free(file); \
140 return NULL; } while(0)
141 #define print_hex(c, p, len, nl) \
142 do { printf(c, ""); print_hex(p, len, nl); } while(0)
144 file = xmalloc(sizeof(struct sb1_file_t));
145 memset(file, 0, sizeof(struct sb1_file_t));
146 struct sb1_header_t *header = (struct sb1_header_t *)buf;
148 if(memcmp(header->signature, "STMP", 4) != 0)
149 fatal(SB1_FORMAT_ERROR, "Bad signature\n");
150 if(header->image_size > filesize)
151 fatal(SB1_FORMAT_ERROR, "File too small (should be at least %d bytes)\n",
152 header->image_size);
153 if(header->header_size != sizeof(struct sb1_header_t))
154 fatal(SB1_FORMAT_ERROR, "Bad header size\n");
156 printf(BLUE, "Basic info:\n");
157 printf(GREEN, " ROM version: ");
158 printf(YELLOW, "%x\n", header->rom_version);
159 printf(GREEN, " Userdata offset: ");
160 printf(YELLOW, "%x\n", header->userdata_offset);
161 printf(GREEN, " Pad: ");
162 printf(YELLOW, "%x\n", header->pad2);
164 struct sb1_version_t product_ver = header->product_ver;
165 fix_version(&product_ver);
166 struct sb1_version_t component_ver = header->component_ver;
167 fix_version(&component_ver);
169 printf(GREEN, " Product version: ");
170 printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision);
171 printf(GREEN, " Component version: ");
172 printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision);
174 printf(GREEN, " Drive tag: ");
175 printf(YELLOW, "%x\n", header->drive_tag);
177 /* copy rom version, padding and drive tag */
178 /* copy versions */
179 memcpy(&file->product_ver, &product_ver, sizeof(product_ver));
180 memcpy(&file->component_ver, &component_ver, sizeof(component_ver));
181 file->rom_version = header->rom_version;
182 file->pad2 = header->pad2;
183 file->drive_tag = header->drive_tag;
185 /* reduce size w.r.t to userdata part */
186 uint32_t userdata_size = 0;
187 if(header->userdata_offset != 0)
189 userdata_size = header->image_size - header->userdata_offset;
190 header->image_size -= userdata_size;
193 if(header->image_size % SECTOR_SIZE)
195 if(g_force)
196 printf(GREY, "Image size is not a multiple of sector size\n");
197 else
198 fatal(SB1_FORMAT_ERROR, "Image size is not a multiple of sector size\n");
201 /* find key */
202 union xorcrypt_key_t key[2];
203 bool valid_key = false;
204 uint8_t sector[SECTOR_SIZE];
206 for(int i = 0; i < g_nr_keys; i++)
208 if(!g_key_array[i].method == CRYPTO_XOR_KEY)
209 continue;
210 /* copy key and data because it's modified by the crypto code */
211 memcpy(key, g_key_array[i].u.xor_key, sizeof(key));
212 memcpy(sector, header + 1, SECTOR_SIZE - header->header_size);
213 /* try to decrypt the first sector */
214 uint32_t mark = xor_decrypt(key, sector, SECTOR_SIZE - 4 - header->header_size);
215 if(mark != *(uint32_t *)&sector[SECTOR_SIZE - 4 - header->header_size])
216 continue;
217 /* found ! */
218 valid_key = true;
219 /* copy key again it's modified by the crypto code */
220 memcpy(key, g_key_array[i].u.xor_key, sizeof(key));
221 break;
224 printf(BLUE, "Crypto\n");
225 for(int i = 0; i < 2; i++)
227 printf(RED, " Key %d\n", i);
228 printf(OFF, " ");
229 for(int j = 0; j < 64; j++)
231 printf(YELLOW, "%02x ", key[i].key[j]);
232 if((j + 1) % 16 == 0)
234 printf(OFF, "\n");
235 if(j + 1 != 64)
236 printf(OFF, " ");
241 if(!valid_key)
242 fatal(SB1_NO_VALID_KEY, "No valid key found\n");
244 /* decrypt image in-place (and removing crypto markers) */
245 void *ptr = header + 1;
246 void *copy_ptr = header + 1;
247 int offset = header->header_size;
248 for(unsigned i = 0; i < header->image_size / SECTOR_SIZE; i++)
250 int size = SECTOR_SIZE - 4 - offset;
251 uint32_t mark = xor_decrypt(key, ptr, size);
252 if(mark != *(uint32_t *)(ptr + size))
253 fatal(SB1_CHECKSUM_ERROR, "Crypto mark mismatch\n");
254 memmove(copy_ptr, ptr, size);
256 ptr += size + 4;
257 copy_ptr += size;
258 offset = 0;
261 /* reduce image size given the removed marks */
262 header->image_size -= header->image_size / SECTOR_SIZE;
264 printf(BLUE, "Commands\n");
265 struct sb1_cmd_header_t *cmd = (void *)(header + 1);
266 while((void *)cmd < (void *)header + header->image_size)
268 printf(GREEN, " Command");
269 printf(YELLOW, " %#x\n", cmd->cmd);
270 printf(YELLOW, " Size:");
271 printf(RED, " %#x\n", SB1_CMD_SIZE(cmd->cmd));
272 printf(YELLOW, " Critical:");
273 printf(RED, " %d\n", SB1_CMD_CRITICAL(cmd->cmd));
274 printf(YELLOW, " Data Type:");
275 printf(RED, " %#x ", SB1_CMD_DATATYPE(cmd->cmd));
276 printf(GREEN, "(%s)\n", sb1_datatype_name(SB1_CMD_DATATYPE(cmd->cmd)));
277 printf(YELLOW, " Bytes:");
278 printf(RED, " %#x\n", SB1_CMD_BYTES(cmd->cmd));
279 printf(YELLOW, " Boot:");
280 printf(RED, " %#x ", SB1_CMD_BOOT(cmd->cmd));
281 printf(GREEN, "(%s)\n", sb1_cmd_name(SB1_CMD_BOOT(cmd->cmd)));
282 printf(YELLOW, " Addr:");
283 printf(RED, " %#x", cmd->addr);
285 if(SB1_CMD_BOOT(cmd->cmd) == SB1_INST_SDRAM)
286 printf(GREEN, " (Chip Select=%d, Size=%d)", SB1_ADDR_SDRAM_CS(cmd->addr),
287 sb1_sdram_size_by_index(SB1_ADDR_SDRAM_SZ(cmd->addr)));
288 printf(OFF, "\n");
289 if(SB1_CMD_BOOT(cmd->cmd) == SB1_INST_FILL)
291 printf(YELLOW, " Pattern:");
292 printf(RED, " %#x\n", *(uint32_t *)(cmd + 1));
295 /* copy command */
296 struct sb1_inst_t inst;
297 memset(&inst, 0, sizeof(inst));
298 inst.cmd = SB1_CMD_BOOT(cmd->cmd);
299 inst.critical = SB1_CMD_CRITICAL(cmd->cmd);
300 inst.datatype = SB1_CMD_DATATYPE(cmd->cmd);
301 inst.size = SB1_CMD_BYTES(cmd->cmd);
303 switch(SB1_CMD_BOOT(cmd->cmd))
305 case SB1_INST_SDRAM:
306 inst.sdram.chip_select = SB1_ADDR_SDRAM_CS(cmd->addr);
307 inst.sdram.size_index = SB1_ADDR_SDRAM_SZ(cmd->addr);
308 break;
309 case SB1_INST_MODE:
310 inst.mode = cmd->addr;
311 break;
312 case SB1_INST_LOAD:
313 inst.data = malloc(inst.size);
314 memcpy(inst.data, cmd + 1, inst.size);
315 /* fallthrough */
316 default:
317 inst.addr = cmd->addr;
318 break;
321 file->insts = augment_array(file->insts, sizeof(inst), file->nr_insts, &inst, 1);
322 file->nr_insts++;
324 /* last instruction ? */
325 if(SB1_CMD_BOOT(cmd->cmd) == SB1_INST_JUMP ||
326 SB1_CMD_BOOT(cmd->cmd) == SB1_INST_MODE)
327 break;
329 cmd = (void *)cmd + 4 + 4 * SB1_CMD_SIZE(cmd->cmd);
332 /* copy userdata */
333 file->userdata_size = userdata_size;
334 if(userdata_size > 0)
336 file->userdata = malloc(userdata_size);
337 memcpy(file->userdata, (void *)header + header->userdata_offset, userdata_size);
340 return file;
341 #undef printf
342 #undef fatal
343 #undef print_hex
346 void sb1_free(struct sb1_file_t *file)
348 if(!file) return;
350 for(int i = 0; i < file->nr_insts; i++)
351 free(file->insts[i].data);
352 free(file->insts);
353 free(file->userdata);
354 free(file);
357 void sb1_dump(struct sb1_file_t *file, void *u, sb1_color_printf cprintf)
359 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
360 #define print_hex(c, p, len, nl) \
361 do { printf(c, ""); print_hex(p, len, nl); } while(0)
363 #define TREE RED
364 #define HEADER GREEN
365 #define TEXT YELLOW
366 #define TEXT2 BLUE
367 #define TEXT3 RED
368 #define SEP OFF
370 printf(BLUE, "SB1 File\n");
371 printf(TREE, "+-");
372 printf(HEADER, "Rom Ver: ");
373 printf(TEXT, "%x\n", file->rom_version);
374 printf(TREE, "+-");
375 printf(HEADER, "Pad: ");
376 printf(TEXT, "%x\n", file->pad2);
377 printf(TREE, "+-");
378 printf(HEADER, "Drive Tag: ");
379 printf(TEXT, "%x\n", file->drive_tag);
380 printf(TREE, "+-");
381 printf(HEADER, "Product Version: ");
382 printf(TEXT, "%X.%X.%X\n", file->product_ver.major, file->product_ver.minor,
383 file->product_ver.revision);
384 printf(TREE, "+-");
385 printf(HEADER, "Component Version: ");
386 printf(TEXT, "%X.%X.%X\n", file->component_ver.major, file->component_ver.minor,
387 file->component_ver.revision);
389 for(int j = 0; j < file->nr_insts; j++)
391 struct sb1_inst_t *inst = &file->insts[j];
392 printf(TREE, "+-");
393 printf(HEADER, "Command\n");
394 printf(TREE, "| +-");
395 switch(inst->cmd)
397 case SB1_INST_CALL:
398 case SB1_INST_JUMP:
399 printf(HEADER, "%s", inst->cmd == SB1_INST_CALL ? "CALL" : "JUMP");
400 printf(SEP, " | ");
401 printf(TEXT3, "crit=%d", inst->critical);
402 printf(SEP, " | ");
403 printf(TEXT, "addr=0x%08x\n", inst->addr);
404 break;
405 case SB1_INST_LOAD:
406 printf(HEADER, "LOAD");
407 printf(SEP, " | ");
408 printf(TEXT3, "crit=%d", inst->critical);
409 printf(SEP, " | ");
410 printf(TEXT, "addr=0x%08x", inst->addr);
411 printf(SEP, " | ");
412 printf(TEXT2, "len=0x%08x\n", inst->size);
413 break;
414 case SB1_INST_FILL:
415 printf(HEADER, "FILL");
416 printf(SEP, " | ");
417 printf(TEXT3, "crit=%d", inst->critical);
418 printf(SEP, " | ");
419 printf(TEXT, "addr=0x%08x", inst->addr);
420 printf(SEP, " | ");
421 printf(TEXT2, "len=0x%08x", inst->size);
422 printf(SEP, " | ");
423 printf(TEXT2, "pattern=0x%08x\n", inst->pattern);
424 break;
425 case SB1_INST_MODE:
426 printf(HEADER, "MODE");
427 printf(SEP, " | ");
428 printf(TEXT3, "crit=%d", inst->critical);
429 printf(SEP, " | ");
430 printf(TEXT, "mode=0x%08x\n", inst->addr);
431 break;
432 case SB1_INST_SDRAM:
433 printf(HEADER, "SRAM");
434 printf(SEP, " | ");
435 printf(TEXT3, "crit=%d", inst->critical);
436 printf(SEP, " | ");
437 printf(TEXT, "chip_select=%d", inst->sdram.chip_select);
438 printf(SEP, " | ");
439 printf(TEXT2, "chip_size=%d\n", sb1_sdram_size_by_index(inst->sdram.size_index));
440 break;
441 default:
442 printf(GREY, "[Unknown instruction %x]\n", inst->cmd);
443 break;
447 #undef printf
448 #undef print_hex