From cbd44f4bc4d9c49364f317df6111f5ad9c4213bf Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Sun, 10 Jun 2012 21:55:40 +0200 Subject: [PATCH] Update the rknano utils. This is mostly based on reverse engineer of the _RKUpgrade.dll from the SAM3xx upgrader. Change-Id: I37f4503899c7198ce463130b2ff994da9ca7dc4b --- utils/rknanoutils/rkboottool/rkboottool.c | 295 ++++++++++++++++++++-- 1 file changed, 280 insertions(+), 15 deletions(-) diff --git a/utils/rknanoutils/rkboottool/rkboottool.c b/utils/rknanoutils/rkboottool/rkboottool.c index e41224065d..f1e0e97f69 100644 --- a/utils/rknanoutils/rkboottool/rkboottool.c +++ b/utils/rknanoutils/rkboottool/rkboottool.c @@ -3,9 +3,12 @@ #include #include #include +#include #include "misc.h" -#define cprintf(col, ...) do {printf("%s", col); printf(__VA_ARGS__); }while(0) +#define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0) + +bool g_debug = false; typedef uint8_t packed_bcd_uint8_t; typedef uint16_t packed_bcd_uint16_t; @@ -72,7 +75,7 @@ struct rknano_header_t char magic[MAGIC_RKNANOFW_SIZE]; }; -char *prefix = NULL; +char *g_out_prefix = NULL; static void encode_page(uint8_t *inpg, uint8_t *outpg, const int size) { @@ -137,10 +140,10 @@ static uint16_t crc(uint8_t *buf, int size) static void save_blob(const struct rknano_blob_t *b, void *buf, uint32_t size, char *name, int suffix, bool descramble) { - if(prefix == NULL || b->size == 0 || b->offset + b->size > size) + if(g_out_prefix == NULL || b->size == 0 || b->offset + b->size > size) return; - char *path = malloc(strlen(prefix) + strlen(name) + 32); - sprintf(path, "%s%s%d.bin", prefix, name, suffix); + char *path = malloc(strlen(g_out_prefix) + strlen(name) + 32); + sprintf(path, "%s%s%d.bin", g_out_prefix, name, suffix); FILE *f = fopen(path, "wb"); uint8_t *ptr = buf + b->offset; if(descramble) @@ -164,16 +167,15 @@ static void print_blob_interval(const struct rknano_blob_t *b) cprintf(YELLOW, "%#x -> %#x", b->offset, b->offset + b->size); } -static int do_image(int argc, char **argv, uint8_t *buf, unsigned long size) +static int do_nanofw_image(uint8_t *buf, unsigned long size) { - (void) argc; - (void) argv; - if(size < sizeof(struct rknano_header_t)) return 1; struct rknano_header_t *hdr = (void *)buf; if(size < hdr->size) return 1; + if(strncmp(hdr->magic, MAGIC_RKNANOFW, MAGIC_RKNANOFW_SIZE)) + return 1; cprintf(BLUE, "Header\n"); cprintf(GREEN, " Date: "); @@ -249,18 +251,269 @@ static int do_image(int argc, char **argv, uint8_t *buf, unsigned long size) return 0; } +struct rknano_stage_header_t +{ + uint32_t addr; +} __attribute__((packed)); + +struct rknano_stage_section_t +{ + uint32_t a; + uint32_t code_pa; + uint32_t code_va; + uint32_t code_sz; + uint32_t data_pa; + uint32_t data_va; + uint32_t data_sz; + uint32_t bss_end_va; +} __attribute__((packed)); + +static int do_nanostage_image(uint8_t *buf, unsigned long size) +{ + if(size < sizeof(struct rknano_stage_section_t)) + return 1; + struct rknano_stage_header_t *hdr = (void *)buf; + + cprintf(BLUE, "Header\n"); + cprintf(GREEN, " Base Address: "); + cprintf(YELLOW, "%#x\n", hdr->addr); + + struct rknano_stage_section_t *sec = (void *)(hdr + 1); + void *end = buf + size; + + int i = 0; + while((void *)sec < end && (sec->code_sz || sec->bss_end_va)) + { + cprintf(BLUE, "Section %d\n", i); + cprintf(GREEN, " Something: "); + cprintf(YELLOW, "%#x\n", sec->a); + cprintf(GREEN, " Code: "); + cprintf(YELLOW, "%#x", sec->code_pa); + cprintf(BLUE, " |--> "); + cprintf(YELLOW, "%#x", sec->code_va); + cprintf(RED, "-(code)-"); + cprintf(YELLOW, "%#x\n", sec->code_va + sec->code_sz); + + cprintf(GREEN, " Data: "); + cprintf(YELLOW, "%#x", sec->data_pa); + cprintf(BLUE, " |--> "); + cprintf(YELLOW, "%#x", sec->data_va); + cprintf(RED, "-(data)-"); + cprintf(YELLOW, "%#x", sec->data_va + sec->data_sz); + cprintf(RED, "-(bss)-"); + cprintf(YELLOW, "%#x\n", sec->bss_end_va); + + sec++; + i++; + } + + return 0; +} + +#define MAGIC_BOOT "BOOT" +#define MAGIC_BOOT_SIZE 4 + +struct rknano_boot_header_t +{ + char magic[MAGIC_BOOT_SIZE]; + uint16_t field_4; + uint32_t field_6; + uint32_t field_A; + uint16_t field_E; + uint8_t field_10[5]; + uint32_t field_15; + uint8_t field_19; + uint32_t field_1A; + uint8_t field_1E[2]; + uint32_t field_20; + uint8_t field_24[2]; + uint32_t field_26; + uint8_t field_2A[10]; + uint32_t field_34; +} __attribute__((packed)); + +static int do_boot_image(uint8_t *buf, unsigned long size) +{ + if(sizeof(struct rknano_boot_header_t) != 0x38) + printf("aie"); + if(size < sizeof(struct rknano_boot_header_t)) + return 1; + struct rknano_boot_header_t *hdr = (void *)buf; + if(strncmp(hdr->magic, MAGIC_BOOT, MAGIC_BOOT_SIZE)) + return 1; + + cprintf(BLUE, "Header\n"); + cprintf(GREEN, " Magic: "); + cprintf(YELLOW, "%." STR(MAGIC_BOOT_SIZE) "s ", hdr->magic); + if(strncmp(hdr->magic, MAGIC_BOOT, MAGIC_BOOT_SIZE) == 0) + cprintf(RED, "OK\n"); + else + cprintf(RED, "Mismatch\n"); +#define print(str, name) cprintf(GREEN, " "str": ");cprintf(YELLOW, "%#x\n", (unsigned)hdr->name) +#define print_arr(str, name, sz) \ + cprintf(GREEN, " "str":");for(int i = 0; i < sz; i++)cprintf(YELLOW, " %#x", (unsigned)hdr->name[i]);printf("\n") + + print("field_4", field_4); + print("field_6", field_6); + print("field_A", field_A); + print("field_E", field_E); + print_arr("field_10", field_10, 5); + print("field_15", field_15); + print("field_19", field_19); + print("field_1A", field_1A); + print_arr("field_1E", field_1E, 2); + print("field_20", field_20); + print_arr("field_24", field_24, 2); + print("field_26", field_26); + print_arr("field_2A", field_2A, 10); + print("field_34", field_34); + cprintf(GREEN, "Value: "); + cprintf(YELLOW, "%#x\n", *(unsigned long *)((uint8_t *)hdr + hdr->field_34 - 10)); + + return 0; +} + +typedef struct rknano_blob_t rkfw_blob_t; + +#define MAGIC_RKFW "RKFW" +#define MAGIC_RKFW_SIZE 4 + +struct rkfw_header_t +{ + char magic[MAGIC_RKFW_SIZE]; + uint16_t hdr_size; // UNSURE + uint32_t field_6; + uint32_t field_A; + uint16_t field_E; + uint8_t field_10[5]; + uint32_t field_15; + rkfw_blob_t loader; + rkfw_blob_t update; + uint8_t pad[60]; + uint8_t field_65; +} __attribute__((packed)); + +static int do_rkfw_image(uint8_t *buf, unsigned long size) +{ + if(sizeof(struct rkfw_header_t) != 0x66) + printf("aie"); + if(size < sizeof(struct rkfw_header_t)) + return 1; + struct rkfw_header_t *hdr = (void *)buf; + if(strncmp(hdr->magic, MAGIC_RKFW, MAGIC_RKFW_SIZE)) + return 1; + + cprintf(BLUE, "Header\n"); + cprintf(GREEN, " Magic: "); + cprintf(YELLOW, "%." STR(MAGIC_RKFW_SIZE) "s ", hdr->magic); + if(strncmp(hdr->magic, MAGIC_RKFW, MAGIC_RKFW_SIZE) == 0) + cprintf(RED, "OK\n"); + else + cprintf(RED, "Mismatch\n"); + + cprintf(GREEN, " Loader: "); + print_blob_interval(&hdr->loader); + cprintf(OFF, "\n"); + save_blob(&hdr->loader, buf, size, "loader", 0, false); + + cprintf(GREEN, " Update: "); + print_blob_interval(&hdr->update); + cprintf(OFF, "\n"); + save_blob(&hdr->update, buf, size, "update", 0, false); + + print("hdr_size", hdr_size); + print("field_6", field_6); + print("field_A", field_A); + print("field_E", field_E); + print_arr("field_10", field_10, 5); + print("field_15", field_15); + print_arr("pad", pad, 60); + print("field_65", field_65); + + return 0; +} + static void usage(void) { - printf("Usage: rkboottool [options] rknanoboot.bin out_prefix\n"); + printf("Usage: rkboottool [options] rknanoboot.bin\n"); + printf("Options:\n"); + printf(" --rkfw\tUnpack a rkfw file\n"); + printf(" --rknanofw\tUnpack a regular RknanoFW file\n"); + printf(" --rkboot\tUnpack a BOOT file\n"); + printf(" --rknanostage\tUnpack a RknanoFW stage file\n"); + printf(" -o \tSet output prefix\n"); + printf("The default is to try to guess the format.\n"); + printf("If several formats are specified, all are tried.\n"); exit(1); } int main(int argc, char **argv) { - if(argc < 3) + bool try_nanofw = false; + bool try_rkfw = false; + bool try_boot = false; + bool try_nanostage = false; + + while(1) + { + static struct option long_options[] = + { + {"help", no_argument, 0, '?'}, + {"debug", no_argument, 0, 'd'}, + {"rkfw", no_argument, 0, '9'}, + {"rknanofw", no_argument, 0, 'n'}, + {"rknanostage", no_argument, 0, 's'}, + {"rkboot", no_argument, 0, 'b'}, + {"no-color", no_argument, 0, 'c'}, + {0, 0, 0, 0} + }; + + int c = getopt_long(argc, argv, "?d9nscbo:", long_options, NULL); + if(c == -1) + break; + switch(c) + { + case -1: + break; + case 'c': + enable_color(false); + break; + case 'b': + try_boot = true; + break; + case 'n': + try_nanofw = true; + break; + case 'd': + g_debug = true; + break; + case '?': + usage(); + break; + case 'o': + g_out_prefix = optarg; + break; + case '9': + try_rkfw = true; + break; + case 's': + try_nanostage = true; + break; + default: + abort(); + } + } + + if(argc - optind != 1) + { usage(); - prefix = argv[argc - 1]; - FILE *fin = fopen(argv[argc - 2], "r"); + return 1; + } + + if(!try_nanostage && !try_rkfw && !try_nanofw && !try_boot) + try_nanostage = try_rkfw = try_nanofw = try_boot = true; + + FILE *fin = fopen(argv[optind], "r"); if(fin == NULL) { perror("Cannot open boot file"); @@ -284,7 +537,19 @@ int main(int argc, char **argv) } fclose(fin); - - return do_image(argc - 1, argv, buf, size); + + if(try_nanofw && !do_nanofw_image(buf, size)) + goto Lsuccess; + if(try_rkfw && !do_rkfw_image(buf, size)) + goto Lsuccess; + if(try_boot && !do_boot_image(buf, size)) + goto Lsuccess; + if(try_nanostage && !do_nanostage_image(buf, size)) + goto Lsuccess; + cprintf(GREY, "No valid format found!\n"); + Lsuccess: + free(buf); + + return 0; }