summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--utils/rknanoutils/rkboottool/rkboottool.c295
1 files 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 <stdbool.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.h>
#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 <prefix>\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;
}