forked from len0rd/rockbox
rknanotools: fix rknano stages processing
Change-Id: Ia88f5aa2a6c56b312f80b31afab41d1dc68b871b
This commit is contained in:
parent
d22bb548b2
commit
b8d35c042d
3 changed files with 212 additions and 81 deletions
|
@ -21,6 +21,14 @@
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
|
static char *strdup(const char *str)
|
||||||
|
{
|
||||||
|
int len = strlen(str);
|
||||||
|
char *s = malloc(len + 1);
|
||||||
|
memcpy(s, str, len + 1);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Definitions
|
* Definitions
|
||||||
* taken from elf.h linux header
|
* taken from elf.h linux header
|
||||||
|
@ -189,43 +197,55 @@ static struct elf_segment_t *elf_add_segment(struct elf_params_t *params)
|
||||||
}
|
}
|
||||||
|
|
||||||
void elf_add_load_section(struct elf_params_t *params,
|
void elf_add_load_section(struct elf_params_t *params,
|
||||||
uint32_t load_addr, uint32_t size, const void *section)
|
uint32_t load_addr, uint32_t size, const void *section, const char *name)
|
||||||
{
|
{
|
||||||
struct elf_section_t *sec = elf_add_section(params);
|
struct elf_section_t *sec = elf_add_section(params);
|
||||||
|
char buffer[32];
|
||||||
|
if(name == NULL)
|
||||||
|
{
|
||||||
|
sprintf(buffer, ".text%d", params->unique_index++);
|
||||||
|
name = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
sec->type = EST_LOAD;
|
sec->type = EST_LOAD;
|
||||||
sec->addr = load_addr;
|
sec->addr = load_addr;
|
||||||
sec->size = size;
|
sec->size = size;
|
||||||
sec->section = xmalloc(size);
|
sec->section = xmalloc(size);
|
||||||
|
sec->name = strdup(name);
|
||||||
memcpy(sec->section, section, size);
|
memcpy(sec->section, section, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void elf_add_fill_section(struct elf_params_t *params,
|
void elf_add_fill_section(struct elf_params_t *params,
|
||||||
uint32_t fill_addr, uint32_t size, uint32_t pattern)
|
uint32_t fill_addr, uint32_t size, uint32_t pattern)
|
||||||
{
|
{
|
||||||
|
char buffer[32];
|
||||||
|
sprintf(buffer, ".bss%d", params->unique_index++);
|
||||||
|
|
||||||
if(pattern != 0x00)
|
if(pattern != 0x00)
|
||||||
{
|
{
|
||||||
printf("oops, non-zero filling, ignore fill section\n");
|
printf("oops, non-zero filling, ignore fill section\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct elf_section_t *sec = elf_add_section(params);
|
struct elf_section_t *sec = elf_add_section(params);
|
||||||
|
|
||||||
sec->type = EST_FILL;
|
sec->type = EST_FILL;
|
||||||
sec->addr = fill_addr;
|
sec->addr = fill_addr;
|
||||||
sec->size = size;
|
sec->size = size;
|
||||||
sec->pattern = pattern;
|
sec->pattern = pattern;
|
||||||
|
sec->name = strdup(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void elf_write_file(struct elf_params_t *params, elf_write_fn_t write,
|
void elf_write_file(struct elf_params_t *params, elf_write_fn_t write,
|
||||||
elf_printf_fn_t printf, void *user)
|
elf_printf_fn_t printf, void *user)
|
||||||
{
|
{
|
||||||
(void) printf;
|
(void) printf;
|
||||||
|
|
||||||
Elf32_Ehdr ehdr;
|
Elf32_Ehdr ehdr;
|
||||||
uint32_t phnum = 0;
|
uint32_t phnum = 0;
|
||||||
struct elf_section_t *sec = params->first_section;
|
struct elf_section_t *sec = params->first_section;
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
|
uint32_t strtbl_size = 1; /* offset 0 is for the NULL name */
|
||||||
Elf32_Phdr phdr;
|
Elf32_Phdr phdr;
|
||||||
Elf32_Shdr shdr;
|
Elf32_Shdr shdr;
|
||||||
memset(&ehdr, 0, EI_NIDENT);
|
memset(&ehdr, 0, EI_NIDENT);
|
||||||
|
@ -241,7 +261,9 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write,
|
||||||
{
|
{
|
||||||
sec->offset = 0;
|
sec->offset = 0;
|
||||||
}
|
}
|
||||||
|
sec->name_offset = strtbl_size;
|
||||||
|
strtbl_size += strlen(sec->name) + 1;
|
||||||
|
|
||||||
phnum++;
|
phnum++;
|
||||||
sec = sec->next;
|
sec = sec->next;
|
||||||
}
|
}
|
||||||
|
@ -275,16 +297,14 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write,
|
||||||
|
|
||||||
write(user, 0, &ehdr, sizeof ehdr);
|
write(user, 0, &ehdr, sizeof ehdr);
|
||||||
|
|
||||||
/* allocate enough size to hold any combinaison of .text/.bss in the string table:
|
/* the last name offset gives the size of the section, we need to add a small
|
||||||
* - one empty name ("\0")
|
* amount of .shstrtab name */
|
||||||
* - at most N names of the form ".textXXXX\0" or ".bssXXXX\0"
|
uint32_t shstrtab_index = strtbl_size;
|
||||||
* - one name ".shstrtab\0" */
|
strtbl_size += strlen(".shstrtab") + 1;
|
||||||
char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 +
|
char *strtbl_content = malloc(strtbl_size);
|
||||||
phnum * (strlen(".textXXXX") + 1));
|
/* create NULL and shstrtab names */
|
||||||
|
|
||||||
strtbl_content[0] = '\0';
|
strtbl_content[0] = '\0';
|
||||||
strcpy(&strtbl_content[1], ".shstrtab");
|
strcpy(&strtbl_content[shstrtab_index], ".shstrtab");
|
||||||
uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1;
|
|
||||||
|
|
||||||
uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize +
|
uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize +
|
||||||
ehdr.e_shnum * ehdr.e_shentsize;
|
ehdr.e_shnum * ehdr.e_shentsize;
|
||||||
|
@ -294,7 +314,8 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write,
|
||||||
while(sec)
|
while(sec)
|
||||||
{
|
{
|
||||||
sec->offset += data_offset;
|
sec->offset += data_offset;
|
||||||
|
strcpy(&strtbl_content[sec->name_offset], sec->name);
|
||||||
|
|
||||||
phdr.p_type = PT_LOAD;
|
phdr.p_type = PT_LOAD;
|
||||||
if(sec->type == EST_LOAD)
|
if(sec->type == EST_LOAD)
|
||||||
phdr.p_offset = sec->offset;
|
phdr.p_offset = sec->offset;
|
||||||
|
@ -336,21 +357,13 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write,
|
||||||
offset += sizeof(Elf32_Shdr);
|
offset += sizeof(Elf32_Shdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t text_idx = 0;
|
|
||||||
uint32_t bss_idx = 0;
|
|
||||||
while(sec)
|
while(sec)
|
||||||
{
|
{
|
||||||
shdr.sh_name = strtbl_index;
|
shdr.sh_name = sec->name_offset;
|
||||||
if(sec->type == EST_LOAD)
|
if(sec->type == EST_LOAD)
|
||||||
{
|
|
||||||
strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++);
|
|
||||||
shdr.sh_type = SHT_PROGBITS;
|
shdr.sh_type = SHT_PROGBITS;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++);
|
|
||||||
shdr.sh_type = SHT_NOBITS;
|
shdr.sh_type = SHT_NOBITS;
|
||||||
}
|
|
||||||
shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR;
|
shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR;
|
||||||
shdr.sh_addr = sec->addr;
|
shdr.sh_addr = sec->addr;
|
||||||
shdr.sh_offset = sec->offset;
|
shdr.sh_offset = sec->offset;
|
||||||
|
@ -367,12 +380,12 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write,
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
shdr.sh_name = 1;
|
shdr.sh_name = shstrtab_index;
|
||||||
shdr.sh_type = SHT_STRTAB;
|
shdr.sh_type = SHT_STRTAB;
|
||||||
shdr.sh_flags = 0;
|
shdr.sh_flags = 0;
|
||||||
shdr.sh_addr = 0;
|
shdr.sh_addr = 0;
|
||||||
shdr.sh_offset = strtbl_offset + data_offset;
|
shdr.sh_offset = strtbl_offset + data_offset;
|
||||||
shdr.sh_size = strtbl_index;
|
shdr.sh_size = strtbl_size;
|
||||||
shdr.sh_link = SHN_UNDEF;
|
shdr.sh_link = SHN_UNDEF;
|
||||||
shdr.sh_info = 0;
|
shdr.sh_info = 0;
|
||||||
shdr.sh_addralign = 1;
|
shdr.sh_addralign = 1;
|
||||||
|
@ -391,7 +404,7 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write,
|
||||||
sec = sec->next;
|
sec = sec->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index);
|
write(user, strtbl_offset + data_offset, strtbl_content, strtbl_size);
|
||||||
free(strtbl_content);
|
free(strtbl_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +412,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
|
||||||
elf_printf_fn_t printf, void *user)
|
elf_printf_fn_t printf, void *user)
|
||||||
{
|
{
|
||||||
#define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;})
|
#define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;})
|
||||||
|
|
||||||
/* read header */
|
/* read header */
|
||||||
Elf32_Ehdr ehdr;
|
Elf32_Ehdr ehdr;
|
||||||
if(!read(user, 0, &ehdr, sizeof(ehdr)))
|
if(!read(user, 0, &ehdr, sizeof(ehdr)))
|
||||||
|
@ -459,7 +472,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
|
||||||
void *data = xmalloc(shdr.sh_size);
|
void *data = xmalloc(shdr.sh_size);
|
||||||
if(!read(user, shdr.sh_offset, data, shdr.sh_size))
|
if(!read(user, shdr.sh_offset, data, shdr.sh_size))
|
||||||
error_printf("error read self section data\n");
|
error_printf("error read self section data\n");
|
||||||
elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data);
|
elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data, NULL);
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
if(strtab)
|
if(strtab)
|
||||||
|
@ -476,7 +489,6 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
|
||||||
if(strtab)
|
if(strtab)
|
||||||
printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type);
|
printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
free(strtab);
|
free(strtab);
|
||||||
/* run through segments */
|
/* run through segments */
|
||||||
|
@ -562,6 +574,7 @@ void elf_release(struct elf_params_t *params)
|
||||||
struct elf_section_t *next_sec = sec->next;
|
struct elf_section_t *next_sec = sec->next;
|
||||||
if(sec->type == EST_LOAD)
|
if(sec->type == EST_LOAD)
|
||||||
free(sec->section);
|
free(sec->section);
|
||||||
|
free(sec->name);
|
||||||
free(sec);
|
free(sec);
|
||||||
sec = next_sec;
|
sec = next_sec;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ struct elf_section_t
|
||||||
uint32_t addr; /* virtual address */
|
uint32_t addr; /* virtual address */
|
||||||
uint32_t size; /* virtual size */
|
uint32_t size; /* virtual size */
|
||||||
enum elf_section_type_t type;
|
enum elf_section_type_t type;
|
||||||
|
char *name;
|
||||||
/* <union> */
|
/* <union> */
|
||||||
void *section; /* data */
|
void *section; /* data */
|
||||||
uint32_t pattern; /* fill pattern */
|
uint32_t pattern; /* fill pattern */
|
||||||
|
@ -49,6 +50,7 @@ struct elf_section_t
|
||||||
struct elf_section_t *next;
|
struct elf_section_t *next;
|
||||||
/* Internal to elf_write_file */
|
/* Internal to elf_write_file */
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
uint32_t name_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct elf_segment_t
|
struct elf_segment_t
|
||||||
|
@ -68,6 +70,7 @@ struct elf_params_t
|
||||||
struct elf_section_t *last_section;
|
struct elf_section_t *last_section;
|
||||||
struct elf_segment_t *first_segment;
|
struct elf_segment_t *first_segment;
|
||||||
struct elf_segment_t *last_segment;
|
struct elf_segment_t *last_segment;
|
||||||
|
int unique_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count);
|
typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count);
|
||||||
|
@ -77,7 +80,7 @@ typedef void (*elf_printf_fn_t)(void *user, bool error, const char *fmt, ...);
|
||||||
|
|
||||||
void elf_init(struct elf_params_t *params);
|
void elf_init(struct elf_params_t *params);
|
||||||
void elf_add_load_section(struct elf_params_t *params,
|
void elf_add_load_section(struct elf_params_t *params,
|
||||||
uint32_t load_addr, uint32_t size, const void *section);
|
uint32_t load_addr, uint32_t size, const void *section, const char *name);
|
||||||
void elf_add_fill_section(struct elf_params_t *params,
|
void elf_add_fill_section(struct elf_params_t *params,
|
||||||
uint32_t fill_addr, uint32_t size, uint32_t pattern);
|
uint32_t fill_addr, uint32_t size, uint32_t pattern);
|
||||||
uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr);
|
uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr);
|
||||||
|
|
|
@ -15,6 +15,11 @@ bool g_debug = false;
|
||||||
typedef uint8_t packed_bcd_uint8_t;
|
typedef uint8_t packed_bcd_uint8_t;
|
||||||
typedef uint16_t packed_bcd_uint16_t;
|
typedef uint16_t packed_bcd_uint16_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RKnanoFW
|
||||||
|
* contains resources and code stages
|
||||||
|
*/
|
||||||
|
|
||||||
struct rknano_date_t
|
struct rknano_date_t
|
||||||
{
|
{
|
||||||
packed_bcd_uint16_t year;
|
packed_bcd_uint16_t year;
|
||||||
|
@ -176,7 +181,7 @@ static void save_blob(const struct rknano_blob_t *b, void *buf, uint32_t size,
|
||||||
}
|
}
|
||||||
encode_page(buff_ptr, out_ptr, len);
|
encode_page(buff_ptr, out_ptr, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(f)
|
if(f)
|
||||||
{
|
{
|
||||||
fwrite(ptr, b->size, 1, f);
|
fwrite(ptr, b->size, 1, f);
|
||||||
|
@ -276,6 +281,11 @@ static int do_nanofw_image(uint8_t *buf, unsigned long size)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RKNano stage
|
||||||
|
* contains code and memory mapping
|
||||||
|
*/
|
||||||
|
|
||||||
struct rknano_stage_header_t
|
struct rknano_stage_header_t
|
||||||
{
|
{
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
|
@ -283,21 +293,28 @@ struct rknano_stage_header_t
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The [code_pa,code_pa+code_sz[ and [data_pa,data_pa+data_sz[ ranges
|
* NOTE this theory has not been tested against actual code, it's still a guess
|
||||||
* are consistent: they never overlap and have no gaps and fill the
|
* The firmware is too big to fit in memory so it's split into sections,
|
||||||
* entire space. Furthermore they match the code sequences so it's
|
* each section having a "virtual address" and a "physical address".
|
||||||
* reasonable to assume these fields are correct.
|
* Except it gets tricky because the RKNano doesn't have a MMU but a MPU,
|
||||||
* The other fields are still quite unsure. */
|
* so most probably the OF divides the memory into regions (8 would match
|
||||||
|
* hardware capabilities), each being able to contain one of the sections
|
||||||
|
* in the OF file. To gracefully handle jumps between sections, my guess is
|
||||||
|
* that the entire OF is linked as a flat image, cut into pieces and
|
||||||
|
* then each code section get relocated except for jump/calls outside of it:
|
||||||
|
* this will trigger an access fault when trying to access another section, which
|
||||||
|
* the OF can trap and then load the corresponding section.
|
||||||
|
*/
|
||||||
|
|
||||||
struct rknano_stage_section_t
|
struct rknano_stage_section_t
|
||||||
{
|
{
|
||||||
uint32_t code_pa;
|
|
||||||
uint32_t code_va;
|
uint32_t code_va;
|
||||||
|
uint32_t code_pa;
|
||||||
uint32_t code_sz;
|
uint32_t code_sz;
|
||||||
uint32_t data_pa;
|
|
||||||
uint32_t data_va;
|
uint32_t data_va;
|
||||||
|
uint32_t data_pa;
|
||||||
uint32_t data_sz;
|
uint32_t data_sz;
|
||||||
uint32_t bss_va;
|
uint32_t bss_pa;
|
||||||
uint32_t bss_sz;
|
uint32_t bss_sz;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
@ -319,14 +336,14 @@ static void elf_write(void *user, uint32_t addr, const void *buf, size_t count)
|
||||||
fwrite(buf, count, 1, f);
|
fwrite(buf, count, 1, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void extract_elf_section(struct elf_params_t *elf, int count)
|
static void extract_elf_section(struct elf_params_t *elf)
|
||||||
{
|
{
|
||||||
if(g_out_prefix == NULL)
|
if(g_out_prefix == NULL)
|
||||||
return;
|
return;
|
||||||
char *filename = xmalloc(strlen(g_out_prefix) + 32);
|
char *filename = xmalloc(strlen(g_out_prefix) + 32);
|
||||||
sprintf(filename, "%s%d.elf", g_out_prefix, count);
|
sprintf(filename, "%s.elf", g_out_prefix);
|
||||||
if(g_debug)
|
if(g_debug)
|
||||||
printf("Write entry %d to %s\n", count, filename);
|
printf("Write stage to %s\n", filename);
|
||||||
|
|
||||||
FILE *fd = fopen(filename, "wb");
|
FILE *fd = fopen(filename, "wb");
|
||||||
free(filename);
|
free(filename);
|
||||||
|
@ -337,67 +354,149 @@ static void extract_elf_section(struct elf_params_t *elf, int count)
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct range_t
|
||||||
|
{
|
||||||
|
unsigned long start, size;
|
||||||
|
int section;
|
||||||
|
int type;
|
||||||
|
};
|
||||||
|
|
||||||
|
int range_cmp(const void *_a, const void *_b)
|
||||||
|
{
|
||||||
|
const struct range_t *a = _a, *b = _b;
|
||||||
|
if(a->start == b->start)
|
||||||
|
return a->size - b->size;
|
||||||
|
return a->start - b->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RANGE_TXT 0
|
||||||
|
#define RANGE_DAT 1
|
||||||
|
|
||||||
static int do_nanostage_image(uint8_t *buf, unsigned long size)
|
static int do_nanostage_image(uint8_t *buf, unsigned long size)
|
||||||
{
|
{
|
||||||
if(size < sizeof(struct rknano_stage_section_t))
|
if(size < sizeof(struct rknano_stage_section_t))
|
||||||
return 1;
|
return 1;
|
||||||
struct rknano_stage_header_t *hdr = (void *)buf;
|
struct rknano_stage_header_t *hdr = (void *)buf;
|
||||||
|
size_t hdr_size = sizeof(struct rknano_stage_header_t) +
|
||||||
|
hdr->count * sizeof(struct rknano_stage_section_t);
|
||||||
|
if(size < hdr_size)
|
||||||
|
return 1;
|
||||||
|
|
||||||
cprintf(BLUE, "Header\n");
|
cprintf(BLUE, "Header\n");
|
||||||
cprintf(GREEN, " Base Address: ");
|
cprintf(GREEN, " Base Address: ");
|
||||||
cprintf(YELLOW, "%#08x\n", hdr->addr);
|
cprintf(YELLOW, "%#08x\n", hdr->addr);
|
||||||
cprintf(GREEN, " Load count: ");
|
cprintf(GREEN, " Section count: ");
|
||||||
cprintf(YELLOW, "%d\n", hdr->count);
|
cprintf(YELLOW, "%d\n", hdr->count);
|
||||||
|
|
||||||
struct rknano_stage_section_t *sec = (void *)(hdr + 1);
|
|
||||||
|
|
||||||
|
struct rknano_stage_section_t *sec = (void *)(hdr + 1);
|
||||||
|
struct elf_params_t elf;
|
||||||
|
elf_init(&elf);
|
||||||
|
bool error = false;
|
||||||
|
/* track range for overlap */
|
||||||
|
struct range_t *ranges = malloc(sizeof(struct range_t) * 2 * hdr->count);
|
||||||
|
int nr_ranges = 0;
|
||||||
for(unsigned i = 0; i < hdr->count; i++, sec++)
|
for(unsigned i = 0; i < hdr->count; i++, sec++)
|
||||||
{
|
{
|
||||||
cprintf(BLUE, "Section %d\n", i);
|
cprintf(BLUE, "Section %d\n", i);
|
||||||
cprintf(GREEN, " Code: ");
|
cprintf(GREEN, " Code: ");
|
||||||
cprintf(YELLOW, "0x%08x", sec->code_pa);
|
|
||||||
cprintf(RED, "-(txt)-");
|
|
||||||
cprintf(YELLOW, "0x%08x", sec->code_pa + sec->code_sz);
|
|
||||||
cprintf(BLUE, " |--> ");
|
|
||||||
cprintf(YELLOW, "0x%08x", sec->code_va);
|
cprintf(YELLOW, "0x%08x", sec->code_va);
|
||||||
cprintf(RED, "-(txt)-");
|
cprintf(RED, "-(txt)-");
|
||||||
cprintf(YELLOW, "0x%08x\n", sec->code_va + sec->code_sz);
|
cprintf(YELLOW, "0x%08x", sec->code_va + sec->code_sz);
|
||||||
|
cprintf(BLUE, " |--> ");
|
||||||
|
cprintf(YELLOW, "0x%08x", sec->code_pa);
|
||||||
|
cprintf(RED, "-(txt)-");
|
||||||
|
cprintf(YELLOW, "0x%08x\n", sec->code_pa + sec->code_sz);
|
||||||
|
|
||||||
|
/* add ranges */
|
||||||
|
ranges[nr_ranges].start = sec->code_va;
|
||||||
|
ranges[nr_ranges].size = sec->code_sz;
|
||||||
|
ranges[nr_ranges].section = i;
|
||||||
|
ranges[nr_ranges].type = RANGE_TXT;
|
||||||
|
ranges[nr_ranges + 1].start = sec->data_va;
|
||||||
|
ranges[nr_ranges + 1].size = sec->data_sz;
|
||||||
|
ranges[nr_ranges + 1].section = i;
|
||||||
|
ranges[nr_ranges + 1].type = RANGE_DAT;
|
||||||
|
nr_ranges += 2;
|
||||||
|
|
||||||
cprintf(GREEN, " Data: ");
|
cprintf(GREEN, " Data: ");
|
||||||
cprintf(YELLOW, "0x%08x", sec->data_pa);
|
|
||||||
cprintf(RED, "-(dat)-");
|
|
||||||
cprintf(YELLOW, "0x%08x", sec->data_pa + sec->data_sz);
|
|
||||||
cprintf(BLUE, " |--> ");
|
|
||||||
cprintf(YELLOW, "0x%08x", sec->data_va);
|
cprintf(YELLOW, "0x%08x", sec->data_va);
|
||||||
cprintf(RED, "-(dat)-");
|
cprintf(RED, "-(dat)-");
|
||||||
cprintf(YELLOW, "0x%08x\n", sec->data_va + sec->data_sz);
|
cprintf(YELLOW, "0x%08x", sec->data_va + sec->data_sz);
|
||||||
|
cprintf(BLUE, " |--> ");
|
||||||
|
cprintf(YELLOW, "0x%08x", sec->data_pa);
|
||||||
|
cprintf(RED, "-(dat)-");
|
||||||
|
cprintf(YELLOW, "0x%08x\n", sec->data_pa + sec->data_sz);
|
||||||
|
|
||||||
cprintf(GREEN, " Data: ");
|
cprintf(GREEN, " Data: ");
|
||||||
cprintf(RED, " ");
|
cprintf(RED, " ");
|
||||||
cprintf(BLUE, " |--> ");
|
cprintf(BLUE, " |--> ");
|
||||||
cprintf(YELLOW, "0x%08x", sec->bss_va);
|
cprintf(YELLOW, "0x%08x", sec->bss_pa);
|
||||||
cprintf(RED, "-(bss)-");
|
cprintf(RED, "-(bss)-");
|
||||||
cprintf(YELLOW, "0x%08x\n", sec->bss_va + sec->bss_sz);
|
cprintf(YELLOW, "0x%08x\n", sec->bss_pa + sec->bss_sz);
|
||||||
|
|
||||||
#if 0
|
#define check_range_(start,sz) \
|
||||||
struct rknano_blob_t blob;
|
((start) >= hdr_size && (start) + (sz) <= size)
|
||||||
blob.offset = sec->code_pa - hdr->addr;
|
#define check_range(start,sz) \
|
||||||
blob.size = sec->code_sz;
|
((start) >= hdr->addr && check_range_((start) - hdr->addr, sz))
|
||||||
save_blob(&blob, buf, size, "entry.", i, NO_ENC);
|
/* check ranges */
|
||||||
#else
|
if(sec->code_sz != 0 && !check_range(sec->code_va, sec->code_sz))
|
||||||
struct elf_params_t elf;
|
{
|
||||||
elf_init(&elf);
|
cprintf(GREY, "Invalid stage: out of bound code\n");
|
||||||
elf_add_load_section(&elf, sec->code_va, sec->code_sz, buf + sec->code_pa - hdr->addr);
|
error = true;
|
||||||
elf_add_load_section(&elf, sec->data_va, sec->data_sz, buf + sec->data_pa - hdr->addr);
|
break;
|
||||||
elf_add_fill_section(&elf, sec->bss_va, sec->bss_sz, 0);
|
}
|
||||||
extract_elf_section(&elf, i);
|
if(sec->data_sz != 0 && !check_range(sec->data_va, sec->data_sz))
|
||||||
elf_release(&elf);
|
{
|
||||||
#endif
|
cprintf(GREY, "Invalid stage: out of bound data\n");
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#undef check_range_
|
||||||
|
#undef check_range
|
||||||
|
|
||||||
|
char buffer[32];
|
||||||
|
if(sec->code_sz != 0)
|
||||||
|
{
|
||||||
|
sprintf(buffer, ".text.%d", i);
|
||||||
|
elf_add_load_section(&elf, sec->code_va, sec->code_sz,
|
||||||
|
buf + sec->code_va - hdr->addr, buffer);
|
||||||
|
}
|
||||||
|
if(sec->data_sz != 0)
|
||||||
|
{
|
||||||
|
sprintf(buffer, ".data.%d", i);
|
||||||
|
elf_add_load_section(&elf, sec->data_va, sec->data_sz,
|
||||||
|
buf + sec->data_va - hdr->addr, buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/* sort ranges and check overlap */
|
||||||
|
qsort(ranges, nr_ranges, sizeof(struct range_t), range_cmp);
|
||||||
|
for(int i = 1; i < nr_ranges; i++)
|
||||||
|
{
|
||||||
|
if(ranges[i - 1].start + ranges[i - 1].size > ranges[i].start)
|
||||||
|
{
|
||||||
|
error = true;
|
||||||
|
static const char *type[] = {"txt", "dat"};
|
||||||
|
cprintf(GREY, "Section overlap: section %d %s intersects section %d %s\n",
|
||||||
|
ranges[i - 1].section, type[ranges[i - 1].type], ranges[i].section,
|
||||||
|
type[ranges[i].type]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!error)
|
||||||
|
extract_elf_section(&elf);
|
||||||
|
/* FIXME for full information, we could add segments to the ELF file to
|
||||||
|
* keep the mapping, but it's unclear if that would do any good */
|
||||||
|
elf_release(&elf);
|
||||||
|
free(ranges);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RKNano BOOT
|
||||||
|
* contains named bootloader stages
|
||||||
|
*/
|
||||||
|
|
||||||
#define MAGIC_BOOT "BOOT"
|
#define MAGIC_BOOT "BOOT"
|
||||||
#define MAGIC_BOOT_SIZE 4
|
#define MAGIC_BOOT_SIZE 4
|
||||||
|
|
||||||
|
@ -428,6 +527,8 @@ struct rknano_boot_header_t
|
||||||
uint32_t field_34;
|
uint32_t field_34;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define BOOT_CHIP_RKNANO 0x30
|
||||||
|
|
||||||
struct rknano_boot_entry_t
|
struct rknano_boot_entry_t
|
||||||
{
|
{
|
||||||
uint8_t entry_size; // unsure
|
uint8_t entry_size; // unsure
|
||||||
|
@ -588,7 +689,7 @@ static int do_boot_image(uint8_t *buf, unsigned long size)
|
||||||
cprintf(RED, "OK\n");
|
cprintf(RED, "OK\n");
|
||||||
else
|
else
|
||||||
cprintf(RED, "Mismatch\n");
|
cprintf(RED, "Mismatch\n");
|
||||||
|
|
||||||
#define print(str, name) cprintf(GREEN, " "str": ");cprintf(YELLOW, "%#x\n", (unsigned)hdr->name)
|
#define print(str, name) cprintf(GREEN, " "str": ");cprintf(YELLOW, "%#x\n", (unsigned)hdr->name)
|
||||||
#define print_arr(str, name, sz) \
|
#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")
|
cprintf(GREEN, " "str":");for(int i = 0; i < sz; i++)cprintf(YELLOW, " %#x", (unsigned)hdr->name[i]);printf("\n")
|
||||||
|
@ -602,8 +703,12 @@ static int do_boot_image(uint8_t *buf, unsigned long size)
|
||||||
hdr->hour, hdr->minute, hdr->second);
|
hdr->hour, hdr->minute, hdr->second);
|
||||||
|
|
||||||
cprintf(GREEN, " Chip: ");
|
cprintf(GREEN, " Chip: ");
|
||||||
cprintf(YELLOW, "%#x\n", hdr->chip);
|
cprintf(YELLOW, "%#x ", hdr->chip);
|
||||||
|
if(hdr->chip == BOOT_CHIP_RKNANO)
|
||||||
|
cprintf(RED, "(RKNANO)\n");
|
||||||
|
else
|
||||||
|
cprintf(RED, "(unknown)\n");
|
||||||
|
|
||||||
print_arr("field_2A", field_2B, 9);
|
print_arr("field_2A", field_2B, 9);
|
||||||
print("field_34", field_34);
|
print("field_34", field_34);
|
||||||
|
|
||||||
|
@ -625,10 +730,15 @@ static int do_boot_image(uint8_t *buf, unsigned long size)
|
||||||
cprintf(RED, "OK\n");
|
cprintf(RED, "OK\n");
|
||||||
else
|
else
|
||||||
cprintf(RED, "Mismatch\n");
|
cprintf(RED, "Mismatch\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RKFW
|
||||||
|
* contains bootloader and update
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct rknano_blob_t rkfw_blob_t;
|
typedef struct rknano_blob_t rkfw_blob_t;
|
||||||
|
|
||||||
#define MAGIC_RKFW "RKFW"
|
#define MAGIC_RKFW "RKFW"
|
||||||
|
@ -637,7 +747,7 @@ typedef struct rknano_blob_t rkfw_blob_t;
|
||||||
struct rkfw_header_t
|
struct rkfw_header_t
|
||||||
{
|
{
|
||||||
char magic[MAGIC_RKFW_SIZE];
|
char magic[MAGIC_RKFW_SIZE];
|
||||||
uint16_t hdr_size; // UNSURE
|
uint16_t hdr_size;
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t code;
|
uint32_t code;
|
||||||
uint16_t year;
|
uint16_t year;
|
||||||
|
@ -652,6 +762,8 @@ struct rkfw_header_t
|
||||||
uint8_t pad[61];
|
uint8_t pad[61];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define RKFW_CHIP_RKNANO 0x30
|
||||||
|
|
||||||
static int do_rkfw_image(uint8_t *buf, unsigned long size)
|
static int do_rkfw_image(uint8_t *buf, unsigned long size)
|
||||||
{
|
{
|
||||||
if(size < sizeof(struct rkfw_header_t))
|
if(size < sizeof(struct rkfw_header_t))
|
||||||
|
@ -686,8 +798,12 @@ static int do_rkfw_image(uint8_t *buf, unsigned long size)
|
||||||
hdr->hour, hdr->minute, hdr->second);
|
hdr->hour, hdr->minute, hdr->second);
|
||||||
|
|
||||||
cprintf(GREEN, " Chip: ");
|
cprintf(GREEN, " Chip: ");
|
||||||
cprintf(YELLOW, "%#x\n", hdr->chip);
|
cprintf(YELLOW, "%#x ", hdr->chip);
|
||||||
|
if(hdr->chip == RKFW_CHIP_RKNANO)
|
||||||
|
cprintf(RED, "(RKNANO)\n");
|
||||||
|
else
|
||||||
|
cprintf(RED, "(unknown)\n");
|
||||||
|
|
||||||
cprintf(GREEN, " Loader: ");
|
cprintf(GREEN, " Loader: ");
|
||||||
print_blob_interval(&hdr->loader);
|
print_blob_interval(&hdr->loader);
|
||||||
cprintf(OFF, "\n");
|
cprintf(OFF, "\n");
|
||||||
|
@ -852,7 +968,7 @@ int main(int argc, char **argv)
|
||||||
perror("Cannot read file");
|
perror("Cannot read file");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fin);
|
fclose(fin);
|
||||||
|
|
||||||
if(try_nanofw && !do_nanofw_image(buf, size))
|
if(try_nanofw && !do_nanofw_image(buf, size))
|
||||||
|
@ -873,4 +989,3 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue