From 906963ae7667ae06951e12c0f02032184a4e23fd Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Tue, 19 Jun 2012 22:52:18 +0200 Subject: rknanoutils: much more sensible format guess I finally found a sensible format for the executable files. The tool now can output the loading entry to elf files. Some disassembly and analysis suggest the phys/virt addresses are correct. However the entries are somehow linked and it is still unclear how (are there "calls" to the code ? when ?). Change-Id: Ied38b5bb297176c5755b5ecb3309f4a259c18cd4 --- utils/rknanoutils/rkboottool/Makefile | 2 +- utils/rknanoutils/rkboottool/elf.c | 575 ++++++++++++++++++++++++++++++ utils/rknanoutils/rkboottool/elf.h | 94 +++++ utils/rknanoutils/rkboottool/misc.c | 7 + utils/rknanoutils/rkboottool/misc.h | 1 + utils/rknanoutils/rkboottool/rkboottool.c | 123 +++++-- 6 files changed, 779 insertions(+), 23 deletions(-) create mode 100644 utils/rknanoutils/rkboottool/elf.c create mode 100644 utils/rknanoutils/rkboottool/elf.h (limited to 'utils/rknanoutils/rkboottool') diff --git a/utils/rknanoutils/rkboottool/Makefile b/utils/rknanoutils/rkboottool/Makefile index 5bfc40416e..b98fd18646 100644 --- a/utils/rknanoutils/rkboottool/Makefile +++ b/utils/rknanoutils/rkboottool/Makefile @@ -10,7 +10,7 @@ all: $(BINS) %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< -rkboottool: rkboottool.o misc.o +rkboottool: rkboottool.o misc.o elf.o $(LD) -o $@ $^ $(LDFLAGS) clean: diff --git a/utils/rknanoutils/rkboottool/elf.c b/utils/rknanoutils/rkboottool/elf.c new file mode 100644 index 0000000000..481ab98dd6 --- /dev/null +++ b/utils/rknanoutils/rkboottool/elf.c @@ -0,0 +1,575 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "elf.h" +#include "misc.h" + +/** + * Definitions + * taken from elf.h linux header + * based on ELF specification + * based on ARM ELF specification + */ +typedef uint16_t Elf32_Half; + +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint16_t Elf32_Section; + +#define EI_NIDENT 16 + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +}Elf32_Ehdr; + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASS32 1 /* 32-bit objects */ + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ + +#define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +#define ET_EXEC 2 /* Executable file */ + +#define EM_ARM 40 /* ARM */ + +#define EV_CURRENT 1 /* Current version */ + +#define EF_ARM_HASENTRY 0x00000002 + +#define SHN_UNDEF 0 /* Undefined section */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +}Elf32_Shdr; + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +}Elf32_Phdr; + +#define PT_LOAD 1 /* Loadable program segment */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ + +void elf_init(struct elf_params_t *params) +{ + memset(params, 0, sizeof(struct elf_params_t)); +} + +extern void *xmalloc(size_t s); + +static struct elf_section_t *elf_add_section(struct elf_params_t *params) +{ + struct elf_section_t *sec = xmalloc(sizeof(struct elf_section_t)); + if(params->first_section == NULL) + params->first_section = params->last_section = sec; + else + { + params->last_section->next = sec; + params->last_section = sec; + } + sec->next = NULL; + + return sec; +} + +static struct elf_segment_t *elf_add_segment(struct elf_params_t *params) +{ + struct elf_segment_t *seg = xmalloc(sizeof(struct elf_section_t)); + if(params->first_segment == NULL) + params->first_segment = params->last_segment = seg; + else + { + params->last_segment->next = seg; + params->last_segment = seg; + } + seg->next = NULL; + + return seg; +} + +void elf_add_load_section(struct elf_params_t *params, + uint32_t load_addr, uint32_t size, const void *section) +{ + struct elf_section_t *sec = elf_add_section(params); + + sec->type = EST_LOAD; + sec->addr = load_addr; + sec->size = size; + sec->section = xmalloc(size); + memcpy(sec->section, section, size); +} + +void elf_add_fill_section(struct elf_params_t *params, + uint32_t fill_addr, uint32_t size, uint32_t pattern) +{ + if(pattern != 0x00) + { + printf("oops, non-zero filling, ignore fill section\n"); + return; + } + + struct elf_section_t *sec = elf_add_section(params); + + sec->type = EST_FILL; + sec->addr = fill_addr; + sec->size = size; + sec->pattern = pattern; +} + +void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, + elf_printf_fn_t printf, void *user) +{ + (void) printf; + + Elf32_Ehdr ehdr; + uint32_t phnum = 0; + struct elf_section_t *sec = params->first_section; + uint32_t offset = 0; + Elf32_Phdr phdr; + Elf32_Shdr shdr; + memset(&ehdr, 0, EI_NIDENT); + + while(sec) + { + if(sec->type == EST_LOAD) + { + sec->offset = offset; + offset += sec->size; + } + else + { + sec->offset = 0; + } + + phnum++; + sec = sec->next; + } + + uint32_t strtbl_offset = offset; + + ehdr.e_ident[EI_MAG0] = ELFMAG0; + ehdr.e_ident[EI_MAG1] = ELFMAG1; + ehdr.e_ident[EI_MAG2] = ELFMAG2; + ehdr.e_ident[EI_MAG3] = ELFMAG3; + ehdr.e_ident[EI_CLASS] = ELFCLASS32; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE; + ehdr.e_ident[EI_ABIVERSION] = 0; + ehdr.e_type = ET_EXEC; + ehdr.e_machine = EM_ARM; + ehdr.e_version = EV_CURRENT; + ehdr.e_entry = params->start_addr; + ehdr.e_flags = 0; + if(params->has_start_addr) + ehdr.e_flags |= EF_ARM_HASENTRY; + ehdr.e_ehsize = sizeof ehdr; + ehdr.e_phentsize = sizeof phdr; + ehdr.e_phnum = phnum; + ehdr.e_shentsize = sizeof shdr; + ehdr.e_shnum = phnum + 2; /* one for section 0 and one for string table */ + ehdr.e_shstrndx = ehdr.e_shnum - 1; + ehdr.e_phoff = ehdr.e_ehsize; + ehdr.e_shoff = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize; + + write(user, 0, &ehdr, sizeof ehdr); + + /* allocate enough size to hold any combinaison of .text/.bss in the string table: + * - one empty name ("\0") + * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0" + * - one name ".shstrtab\0" */ + char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 + + phnum * (strlen(".textXXXX") + 1)); + + strtbl_content[0] = '\0'; + strcpy(&strtbl_content[1], ".shstrtab"); + uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1; + + uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + + ehdr.e_shnum * ehdr.e_shentsize; + + sec = params->first_section; + offset = ehdr.e_phoff; + while(sec) + { + sec->offset += data_offset; + + phdr.p_type = PT_LOAD; + if(sec->type == EST_LOAD) + phdr.p_offset = sec->offset; + else + phdr.p_offset = 0; + phdr.p_paddr = sec->addr; + phdr.p_vaddr = phdr.p_paddr; /* assume identity map ? */ + phdr.p_memsz = sec->size; + if(sec->type == EST_LOAD) + phdr.p_filesz = phdr.p_memsz; + else + phdr.p_filesz = 0; + phdr.p_flags = PF_X | PF_W | PF_R; + phdr.p_align = 0; + + write(user, offset, &phdr, sizeof phdr); + + offset += sizeof(Elf32_Phdr); + sec = sec->next; + } + + sec = params->first_section; + offset = ehdr.e_shoff; + + { + shdr.sh_name = 0; + shdr.sh_type = SHT_NULL; + shdr.sh_flags = 0; + shdr.sh_addr = 0; + shdr.sh_offset = 0; + shdr.sh_size = 0; + shdr.sh_link = SHN_UNDEF; + shdr.sh_info = 0; + shdr.sh_addralign = 0; + shdr.sh_entsize = 0; + + write(user, offset, &shdr, sizeof shdr); + + offset += sizeof(Elf32_Shdr); + } + + uint32_t text_idx = 0; + uint32_t bss_idx = 0; + while(sec) + { + shdr.sh_name = strtbl_index; + if(sec->type == EST_LOAD) + { + strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++); + shdr.sh_type = SHT_PROGBITS; + } + else + { + strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++); + shdr.sh_type = SHT_NOBITS; + } + shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; + shdr.sh_addr = sec->addr; + shdr.sh_offset = sec->offset; + shdr.sh_size = sec->size; + shdr.sh_link = SHN_UNDEF; + shdr.sh_info = 0; + shdr.sh_addralign = 1; + shdr.sh_entsize = 0; + + write(user, offset, &shdr, sizeof shdr); + + offset += sizeof(Elf32_Shdr); + sec = sec->next; + } + + { + shdr.sh_name = 1; + shdr.sh_type = SHT_STRTAB; + shdr.sh_flags = 0; + shdr.sh_addr = 0; + shdr.sh_offset = strtbl_offset + data_offset; + shdr.sh_size = strtbl_index; + shdr.sh_link = SHN_UNDEF; + shdr.sh_info = 0; + shdr.sh_addralign = 1; + shdr.sh_entsize = 0; + + write(user, offset, &shdr, sizeof shdr); + + offset += sizeof(Elf32_Shdr); + } + + sec = params->first_section; + while(sec) + { + if(sec->type == EST_LOAD) + write(user, sec->offset, sec->section, sec->size); + sec = sec->next; + } + + write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index); + free(strtbl_content); +} + +bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, + elf_printf_fn_t printf, void *user) +{ + #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) + + /* read header */ + Elf32_Ehdr ehdr; + if(!read(user, 0, &ehdr, sizeof(ehdr))) + { + printf(user, true, "error reading elf header\n"); + return false; + } + /* basic checks */ + if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || + ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3) + error_printf("invalid elf header\n"); + if(ehdr.e_ident[EI_CLASS] != ELFCLASS32) + error_printf("invalid elf class: must be a 32-bit object\n"); + if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB) + error_printf("invalid elf data encoding: must be 32-bit lsb\n"); + if(ehdr.e_ident[EI_VERSION] != EV_CURRENT) + error_printf("invalid elf version\n"); + if(ehdr.e_type != ET_EXEC) + error_printf("invalid elf file: must be an executable file\n"); + if(ehdr.e_machine != EM_ARM) + error_printf("invalid elf file: must target an arm machine\n"); + if(ehdr.e_ehsize != sizeof(ehdr)) + error_printf("invalid elf file: size header mismatch\n"); + if(ehdr.e_phnum > 0 && ehdr.e_phentsize != sizeof(Elf32_Phdr)) + error_printf("invalid elf file: program header size mismatch\n"); + if(ehdr.e_shnum > 0 && ehdr.e_shentsize != sizeof(Elf32_Shdr)) + error_printf("invalid elf file: section header size mismatch\n"); + elf_set_start_addr(params, ehdr.e_entry); + + char *strtab = NULL; + if(ehdr.e_shstrndx != SHN_UNDEF) + { + Elf32_Shdr shstrtab; + if(read(user, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize, + &shstrtab, sizeof(shstrtab))) + { + strtab = xmalloc(shstrtab.sh_size); + if(!read(user, shstrtab.sh_offset, strtab, shstrtab.sh_size)) + { + free(strtab); + strtab = NULL; + } + } + } + /* run through sections */ + printf(user, false, "ELF file:\n"); + for(int i = 1; i < ehdr.e_shnum; i++) + { + uint32_t off = ehdr.e_shoff + i * ehdr.e_shentsize; + Elf32_Shdr shdr; + memset(&shdr, 0, sizeof(shdr)); + if(!read(user, off, &shdr, sizeof(shdr))) + error_printf("error reading elf section header"); + + if(shdr.sh_type == SHT_PROGBITS && shdr.sh_flags & SHF_ALLOC) + { + void *data = xmalloc(shdr.sh_size); + if(!read(user, shdr.sh_offset, data, shdr.sh_size)) + error_printf("error read self section data\n"); + elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); + free(data); + + if(strtab) + printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]); + } + else if(shdr.sh_type == SHT_NOBITS && shdr.sh_flags & SHF_ALLOC) + { + elf_add_fill_section(params, shdr.sh_addr, shdr.sh_size, 0); + if(strtab) + printf(user, false, "create fill segment for %s\n", &strtab[shdr.sh_name]); + } + else + { + if(strtab) + printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); + } + + } + free(strtab); + /* run through segments */ + for(int i = 1; i < ehdr.e_phnum; i++) + { + uint32_t off = ehdr.e_phoff + i * ehdr.e_phentsize; + Elf32_Phdr phdr; + memset(&phdr, 0, sizeof(phdr)); + if(!read(user, off, &phdr, sizeof(phdr))) + error_printf("error reading elf segment header"); + if(phdr.p_type != PT_LOAD) + continue; + struct elf_segment_t *seg = elf_add_segment(params); + seg->vaddr = phdr.p_vaddr; + seg->paddr = phdr.p_paddr; + seg->vsize = phdr.p_memsz; + seg->psize = phdr.p_filesz; + printf(user, false, "create segment [%#x,+%#x[ -> [%#x,+%#x[\n", + seg->vaddr, seg->vsize, seg->paddr, seg->psize); + } + + return true; +} + +uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr) +{ + struct elf_segment_t *seg = params->first_segment; + while(seg) + { + if(seg->vaddr <= addr && addr < seg->vaddr + seg->vsize) + return addr - seg->vaddr + seg->paddr; + seg = seg->next; + } + return addr; +} + +void elf_translate_addresses(struct elf_params_t *params) +{ + struct elf_section_t *sec = params->first_section; + while(sec) + { + sec->addr = elf_translate_virtual_address(params, sec->addr); + sec = sec->next; + } + params->start_addr = elf_translate_virtual_address(params, params->start_addr); +} + +bool elf_is_empty(struct elf_params_t *params) +{ + return params->first_section == NULL; +} + +void elf_set_start_addr(struct elf_params_t *params, uint32_t addr) +{ + params->has_start_addr = true; + params->start_addr = addr; +} + +bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr) +{ + if(params->has_start_addr && addr != NULL) + *addr = params->start_addr; + return params->has_start_addr; +} + +int elf_get_nr_sections(struct elf_params_t *params) +{ + int nr = 0; + struct elf_section_t *sec = params->first_section; + while(sec) + { + nr++; + sec = sec->next; + } + return nr; +} + +void elf_release(struct elf_params_t *params) +{ + struct elf_section_t *sec = params->first_section; + while(sec) + { + struct elf_section_t *next_sec = sec->next; + if(sec->type == EST_LOAD) + free(sec->section); + free(sec); + sec = next_sec; + } + struct elf_segment_t *seg = params->first_segment; + while(seg) + { + struct elf_segment_t *next_seg = seg->next; + free(seg); + seg = next_seg; + } +} diff --git a/utils/rknanoutils/rkboottool/elf.h b/utils/rknanoutils/rkboottool/elf.h new file mode 100644 index 0000000000..2166833276 --- /dev/null +++ b/utils/rknanoutils/rkboottool/elf.h @@ -0,0 +1,94 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __ELF_H__ +#define __ELF_H__ + +#include +#include +#include +#include +#include +#include + +/** + * API + */ +enum elf_section_type_t +{ + EST_LOAD, + EST_FILL +}; + +struct elf_section_t +{ + uint32_t addr; /* virtual address */ + uint32_t size; /* virtual size */ + enum elf_section_type_t type; + /* */ + void *section; /* data */ + uint32_t pattern; /* fill pattern */ + /* */ + struct elf_section_t *next; + /* Internal to elf_write_file */ + uint32_t offset; +}; + +struct elf_segment_t +{ + uint32_t vaddr; /* virtual address */ + uint32_t paddr; /* physical address */ + uint32_t vsize; /* virtual size */ + uint32_t psize; /* physical size */ + struct elf_segment_t *next; +}; + +struct elf_params_t +{ + bool has_start_addr; + uint32_t start_addr; + struct elf_section_t *first_section; + struct elf_section_t *last_section; + struct elf_segment_t *first_segment; + struct elf_segment_t *last_segment; +}; + +typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count); +/* write function manages it's own error state */ +typedef void (*elf_write_fn_t)(void *user, uint32_t addr, const void *buf, size_t count); +typedef void (*elf_printf_fn_t)(void *user, bool error, const char *fmt, ...); + +void elf_init(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); +void elf_add_fill_section(struct elf_params_t *params, + uint32_t fill_addr, uint32_t size, uint32_t pattern); +uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr); +void elf_translate_addresses(struct elf_params_t *params); +void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, elf_printf_fn_t printf, void *user); +bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, elf_printf_fn_t printf, + void *user); +bool elf_is_empty(struct elf_params_t *params); +void elf_set_start_addr(struct elf_params_t *params, uint32_t addr); +bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr); +int elf_get_nr_sections(struct elf_params_t *params); +void elf_release(struct elf_params_t *params); + +#endif /* __ELF_H__ */ diff --git a/utils/rknanoutils/rkboottool/misc.c b/utils/rknanoutils/rkboottool/misc.c index b8644b3bf8..108235e7fd 100644 --- a/utils/rknanoutils/rkboottool/misc.c +++ b/utils/rknanoutils/rkboottool/misc.c @@ -34,6 +34,13 @@ char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; static bool g_color_enable = true; +void *xmalloc(size_t s) +{ + void * r = malloc(s); + if(!r) bugp("malloc"); + return r; +} + void enable_color(bool enable) { g_color_enable = enable; diff --git a/utils/rknanoutils/rkboottool/misc.h b/utils/rknanoutils/rkboottool/misc.h index c4975c068c..b0658c0d31 100644 --- a/utils/rknanoutils/rkboottool/misc.h +++ b/utils/rknanoutils/rkboottool/misc.h @@ -34,6 +34,7 @@ typedef char color_t[]; extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; +void *xmalloc(size_t s); void color(color_t c); void enable_color(bool enable); diff --git a/utils/rknanoutils/rkboottool/rkboottool.c b/utils/rknanoutils/rkboottool/rkboottool.c index f913b12377..06763f86e3 100644 --- a/utils/rknanoutils/rkboottool/rkboottool.c +++ b/utils/rknanoutils/rkboottool/rkboottool.c @@ -4,7 +4,9 @@ #include #include #include +#include #include "misc.h" +#include "elf.h" #define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0) @@ -150,7 +152,10 @@ static void save_blob(const struct rknano_blob_t *b, void *buf, uint32_t size, if(g_out_prefix == NULL || b->size == 0 || b->offset + b->size > size) return; char *path = malloc(strlen(g_out_prefix) + strlen(name) + 32); - sprintf(path, "%s%s%d.bin", g_out_prefix, name, suffix); + if(suffix >= 0) + sprintf(path, "%s%s%d.bin", g_out_prefix, name, suffix); + else + sprintf(path, "%s%s.bin", g_out_prefix, name); FILE *f = fopen(path, "wb"); uint8_t *ptr = buf + b->offset; if(enc_mode != NO_ENC) @@ -274,57 +279,131 @@ static int do_nanofw_image(uint8_t *buf, unsigned long size) struct rknano_stage_header_t { uint32_t addr; + uint32_t count; } __attribute__((packed)); +/* + * The [code_pa,code_pa+code_sz[ and [data_pa,data_pa+data_sz[ ranges + * are consitent: they never overlap and have no gaps and fill the + * entire space. Furthermore they match the code sequences so it's + * reasonable to assume these fields are correct. + * The other fields are still quite unsure. */ + 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; + uint32_t bss_va; + uint32_t bss_sz; } __attribute__((packed)); +static void elf_printf(void *user, bool error, const char *fmt, ...) +{ + if(!g_debug && !error) + return; + (void) user; + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +static void elf_write(void *user, uint32_t addr, const void *buf, size_t count) +{ + FILE *f = user; + fseek(f, addr, SEEK_SET); + fwrite(buf, count, 1, f); +} + +static void extract_elf_section(struct elf_params_t *elf, int count) +{ + char *filename = xmalloc(strlen(g_out_prefix) + 32); + sprintf(filename, "%s%d.elf", g_out_prefix, count); + if(g_debug) + printf("Write entry %d to %s\n", count, filename); + + FILE *fd = fopen(filename, "wb"); + free(filename); + + if(fd == NULL) + return ; + elf_write_file(elf, elf_write, elf_printf, fd); + fclose(fd); +} + 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; + uint32_t *buf32 = (void *)buf; + cprintf(BLUE, "Dump\n"); + for(int j = 0; j < 2; j++) + cprintf(YELLOW, "%8x ", buf32[j]); + printf("\n"); + for(unsigned i = 0; i < hdr->count; i++) + { + for(int j = 0; j < 8; j++) + cprintf(YELLOW, "%8x ", buf32[i * 8 + j + 2]); + printf("\n"); + } + printf("\n"); + cprintf(BLUE, "Header\n"); cprintf(GREEN, " Base Address: "); - cprintf(YELLOW, "%#x\n", hdr->addr); + cprintf(YELLOW, "%#08x\n", hdr->addr); + cprintf(GREEN, " Load count: "); + cprintf(YELLOW, "%d\n", hdr->count); 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)) + for(unsigned i = 0; i < hdr->count; i++, sec++) { 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(YELLOW, "0x%08x", sec->code_pa); + cprintf(RED, "-(txt)-"); + cprintf(YELLOW, "0x%08x", sec->code_pa + sec->code_sz); cprintf(BLUE, " |--> "); - cprintf(YELLOW, "%#x", sec->code_va); - cprintf(RED, "-(code)-"); - cprintf(YELLOW, "%#x\n", sec->code_va + sec->code_sz); + cprintf(YELLOW, "0x%08x", sec->code_va); + cprintf(RED, "-(txt)-"); + cprintf(YELLOW, "0x%08x\n", sec->code_va + sec->code_sz); cprintf(GREEN, " Data: "); - cprintf(YELLOW, "%#x", sec->data_pa); + cprintf(YELLOW, "0x%08x", sec->data_pa); + cprintf(RED, "-(dat)-"); + cprintf(YELLOW, "0x%08x", sec->data_pa + sec->data_sz); cprintf(BLUE, " |--> "); - cprintf(YELLOW, "%#x", sec->data_va); - cprintf(RED, "-(data)-"); - cprintf(YELLOW, "%#x", sec->data_va + sec->data_sz); + cprintf(YELLOW, "0x%08x", sec->data_va); + cprintf(RED, "-(dat)-"); + cprintf(YELLOW, "0x%08x\n", sec->data_va + sec->data_sz); + + cprintf(GREEN, " Data: "); + cprintf(RED, " "); + cprintf(BLUE, " |--> "); + cprintf(YELLOW, "0x%08x", sec->bss_va); cprintf(RED, "-(bss)-"); - cprintf(YELLOW, "%#x\n", sec->bss_end_va); + cprintf(YELLOW, "0x%08x\n", sec->bss_va + sec->bss_sz); - sec++; - i++; +#if 0 + struct rknano_blob_t blob; + blob.offset = sec->code_pa - hdr->addr; + blob.size = sec->code_sz; + save_blob(&blob, buf, size, "entry.", i, NO_ENC); +#else + struct elf_params_t elf; + elf_init(&elf); + elf_add_load_section(&elf, sec->code_va, sec->code_sz, buf + sec->code_pa - hdr->addr); + elf_add_load_section(&elf, sec->data_va, sec->data_sz, buf + sec->data_pa - hdr->addr); + elf_add_fill_section(&elf, sec->bss_va, sec->bss_sz, 0); + extract_elf_section(&elf, i); + elf_release(&elf); +#endif } return 0; @@ -487,8 +566,8 @@ static int do_boot_desc(uint8_t *buf, unsigned long size, blob.offset = entry->offset; blob.size = entry->size; char name[128]; - sprintf(name, "desc_%d_ent_%S_", desc_idx, from_uni16(entry->name)); - save_blob(&blob, buf, size, name, i, PAGE_ENC); + sprintf(name, "%d.%S", desc_idx, from_uni16(entry->name)); + save_blob(&blob, buf, size, name, -1, PAGE_ENC); } return 0; -- cgit v1.2.3