kernel_samsung_a53x/drivers/vision3/dsp/dl/dsp-elf-loader.c
2024-06-15 16:02:09 -03:00

1007 lines
25 KiB
C
Executable file

// SPDX-License-Identifier: GPL-2.0
/*
* Samsung Exynos SoC series dsp driver
*
* Copyright (c) 2019 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*/
#include <linux/kernel.h>
#include "dl/dsp-elf-loader.h"
#include "dl/dsp-lib-manager.h"
#include "dl/dsp-common.h"
static const char elf_magic[] = {
0x7f,
'E',
'L',
'F'
};
static const char elf_class[][6] = {
"\0",
"ELF32",
"ELF64"
};
static const char elf_endian[][15] = {
"\0",
"Little endian",
"Big endian"
};
static const char elf_os[][20] = {
"System V",
"HP-UX",
"NetBSD",
"Linux",
"GNU Hurd",
"Solaris",
"AIX",
"IRIX",
"FreeBSD",
"Tru64",
"Novell Modesto",
"OpenBSD",
"OpenVMS",
"NonStop Kernel",
"AROS",
"Fenix OS",
"Cloud ABI"
};
static const char elf_type[][10] = {
"NONE",
"REL",
"EXEC",
"DYN",
"CORE",
"LOOS",
"HIOS",
"LOPROC",
"HIPROC"
};
unsigned int dsp_elf32_rela_get_sym_idx(struct dsp_elf32_rela *rela)
{
return rela->r_info >> 8;
}
unsigned int dsp_elf32_rela_get_rule_idx(struct dsp_elf32_rela *rela)
{
return rela->r_info & ((1 << 8) - 1);
}
static void __dsp_elf32_init_mem(struct dsp_elf32_mem *mem)
{
dsp_list_head_init(&mem->robss);
dsp_list_head_init(&mem->rodata);
dsp_list_head_init(&mem->bss);
dsp_list_head_init(&mem->data);
dsp_list_head_init(&mem->rela);
}
static void __dsp_elf32_init(struct dsp_elf32 *elf)
{
elf->data = NULL;
__dsp_elf32_init_mem(&elf->DMb);
__dsp_elf32_init_mem(&elf->DMb_local);
__dsp_elf32_init_mem(&elf->DRAMb);
__dsp_elf32_init_mem(&elf->TCMb);
__dsp_elf32_init_mem(&elf->TCMb_local);
__dsp_elf32_init_mem(&elf->SFRw);
dsp_list_head_init(&elf->text.text);
dsp_list_head_init(&elf->text.rela);
dsp_list_head_init(&elf->bss_sym);
dsp_list_head_init(&elf->extern_sym);
dsp_hash_tab_init(&elf->symhash);
}
static int __dsp_elf32_check_magic(struct dsp_dl_lib_file *file)
{
int ck = 0;
int idx;
if (file->size < 4) {
DL_ERROR("Elf file is invalid(%u)\n", file->size);
return -1;
}
for (idx = 0; idx < 4; idx++)
if (((char *)(file->mem))[idx] != elf_magic[idx])
ck = -1;
return ck;
}
int dsp_elf32_check_range(struct dsp_elf32 *elf, size_t size)
{
if (size > elf->size) {
DL_ERROR("invalid size range of elf(%zu/%zu)\n",
size, elf->size);
return -1;
}
return 0;
}
static void *__dsp_elf32_get_ptr(struct dsp_elf32 *elf, void *src, size_t size)
{
if ((src < (void *)elf->data) ||
(src + size > (void *)elf->data + elf->size)) {
DL_ERROR("invalid ptr access\n");
return NULL;
}
if (src + size < src) {
DL_ERROR("ptr overflow\n");
return NULL;
}
return src;
}
static int __dsp_elf32_get_symtab(int idx, struct dsp_elf32 *elf)
{
struct dsp_elf32_shdr *shdr;
struct dsp_elf32_shdr *str_hdr;
shdr = __dsp_elf32_get_ptr(elf, elf->shdr + idx,
sizeof(struct dsp_elf32_shdr));
if (!shdr) {
DL_ERROR("shdr is NULL\n");
return -1;
}
if (!shdr->sh_entsize) {
DL_ERROR("sh_entsize must not be zero\n");
return -1;
}
elf->symtab_num = shdr->sh_size / shdr->sh_entsize;
elf->symtab = __dsp_elf32_get_ptr(elf, elf->data + shdr->sh_offset,
sizeof(struct dsp_elf32_sym) * elf->symtab_num);
if (!elf->symtab) {
DL_ERROR("elf->symtab is NULL\n");
return -1;
}
str_hdr = __dsp_elf32_get_ptr(elf, elf->shdr + shdr->sh_link,
sizeof(struct dsp_elf32_shdr));
if (!str_hdr) {
DL_ERROR("str_hdr is NULL\n");
return -1;
}
elf->strtab = __dsp_elf32_get_ptr(elf, elf->data + str_hdr->sh_offset,
sizeof(char));
if (!elf->strtab) {
DL_ERROR("elf->strtab is NULL\n");
return -1;
}
return 0;
}
static void __dsp_elf32_get_text(int idx, struct dsp_elf32 *elf)
{
struct dsp_elf32_idx_node *sec;
DL_DEBUG("Elf32 get text\n");
sec = (struct dsp_elf32_idx_node *)dsp_dl_malloc(
sizeof(*sec), "Text idx node");
sec->idx = idx;
dsp_list_node_init(&sec->node);
dsp_list_node_push_back(&elf->text.text, &sec->node);
}
static void __dsp_elf32_idx_node_push_back(int idx, struct dsp_list_head *head)
{
struct dsp_elf32_idx_node *sec;
sec = (struct dsp_elf32_idx_node *)dsp_dl_malloc(
sizeof(*sec), "Idx node");
sec->idx = idx;
dsp_list_node_init(&sec->node);
dsp_list_node_push_back(head, &sec->node);
}
static void __dsp_elf32_get_mem(int idx, const char *mem_name,
struct dsp_list_head *DMb, struct dsp_list_head *DMb_local,
struct dsp_list_head *DRAMb, struct dsp_list_head *TCMb,
struct dsp_list_head *TCMb_local, struct dsp_list_head *SFRw)
{
DL_DEBUG("Elf32 get mem\n");
if (strncmp("DMb", mem_name, 3) == 0) {
const char *local_name = mem_name + 5;
DL_DEBUG("local_name : %s(%zu)\n",
local_name, strlen(local_name));
if (strlen(local_name) == 13 &&
strncmp(".thread_local", local_name, 13) == 0) {
DL_DEBUG("sec : %d to DMb_local\n", idx);
__dsp_elf32_idx_node_push_back(idx, DMb_local);
} else {
DL_DEBUG("sec : %d to DMb\n", idx);
__dsp_elf32_idx_node_push_back(idx, DMb);
}
} else if (strncmp("TCMb", mem_name, 4) == 0) {
const char *local_name = mem_name + 6;
DL_DEBUG("local_name : %s(%zu)\n",
local_name, strlen(local_name));
if (strlen(local_name) == 13 &&
strncmp(".thread_local", local_name, 13) == 0) {
DL_DEBUG("sec : %d to TCMb_local\n", idx);
__dsp_elf32_idx_node_push_back(idx, TCMb_local);
} else {
DL_DEBUG("sec : %d to TCMb\n", idx);
__dsp_elf32_idx_node_push_back(idx, TCMb);
}
} else if (strncmp("DRAMb", mem_name, 5) == 0)
__dsp_elf32_idx_node_push_back(idx, DRAMb);
else if (strncmp("SFRw", mem_name, 4) == 0)
__dsp_elf32_idx_node_push_back(idx, SFRw);
}
static int __dsp_elf32_rela_node_push_back(int idx, struct dsp_list_head *head,
struct dsp_elf32 *elf)
{
struct dsp_elf32_shdr *shdr;
struct dsp_elf32_rela_node *sec;
shdr = __dsp_elf32_get_ptr(elf, elf->shdr + idx,
sizeof(struct dsp_elf32_shdr));
if (!shdr) {
DL_ERROR("shdr is NULL\n");
return -1;
}
if (!shdr->sh_entsize) {
DL_ERROR("sh_entsize must not be zero\n");
return -1;
}
sec = (struct dsp_elf32_rela_node *)dsp_dl_malloc(sizeof(*sec),
"Rela node");
sec->idx = idx;
sec->rela_num = shdr->sh_size / shdr->sh_entsize;
sec->rela = __dsp_elf32_get_ptr(elf, elf->data + shdr->sh_offset,
sizeof(struct dsp_elf32_rela) * sec->rela_num);
if (!sec->rela) {
DL_ERROR("sec->rela is NULL\n");
return -1;
}
dsp_list_node_init(&sec->node);
dsp_list_node_push_back(head, &sec->node);
return 0;
}
static int __dsp_elf32_get_mem_rela(int idx, const char *sec_name,
struct dsp_elf32 *elf, struct dsp_list_head *text,
struct dsp_list_head *DMb, struct dsp_list_head *DMb_local,
struct dsp_list_head *DRAMb, struct dsp_list_head *TCMb,
struct dsp_list_head *TCMb_local, struct dsp_list_head *SFRw)
{
int ret;
struct dsp_list_head *head = NULL;
DL_DEBUG("Elf32 get mem rela\n");
if (strncmp("text", sec_name, 4) == 0) {
head = text;
} else if (strncmp("data.", sec_name, 5) == 0) {
const char *mem_name = sec_name + 5;
if (strncmp("DMb", mem_name, 3) == 0) {
const char *local_name = mem_name + 5;
if (strlen(local_name) == 13 &&
strncmp(".thread_local", local_name,
13) == 0)
head = DMb_local;
else
head = DMb;
} else if (strncmp("TCMb", mem_name, 4) == 0) {
const char *local_name = mem_name + 6;
if (strlen(local_name) == 13 &&
strncmp(".thread_local", local_name,
13) == 0)
head = TCMb_local;
else
head = TCMb;
} else if (strncmp("DRAMb", mem_name, 5) == 0) {
head = DRAMb;
} else if (strncmp("SFRw", mem_name, 4) == 0) {
head = SFRw;
}
}
if (head) {
ret = __dsp_elf32_rela_node_push_back(idx, head, elf);
if (ret == -1) {
DL_ERROR("Failed rela node push back\n");
return -1;
}
}
return 0;
}
static int __dsp_elf32_get_bss_symhash(struct dsp_elf32 *elf)
{
unsigned int idx;
struct dsp_elf32_sym *sym;
int ndx;
struct dsp_elf32_idx_node *symnode;
DL_DEBUG("Elf32 get bss symhash\n");
for (idx = 0; idx < elf->symtab_num; idx++) {
sym = &elf->symtab[idx];
ndx = sym->st_shndx;
if (ndx > 0 && ndx < elf->hdr->e_shnum) {
const char *sym_str;
const char *shstr;
sym_str = __dsp_elf32_get_ptr(elf, elf->strtab +
sym->st_name, sizeof(char));
if (!sym_str) {
DL_ERROR("sym_str is NULL\n");
return -1;
}
shstr = __dsp_elf32_get_ptr(elf, elf->shstrtab +
elf->shdr[ndx].sh_name, sizeof(char));
if (!shstr) {
DL_ERROR("shstr is NULL\n");
return -1;
}
dsp_hash_push(&elf->symhash, sym_str, sym);
if (strncmp(".bss", shstr, 4) == 0 ||
strncmp(".robss", shstr, 6) == 0) {
symnode =
(struct dsp_elf32_idx_node *)
dsp_dl_malloc(
sizeof(*symnode),
"bss sym Idx node");
symnode->idx = idx;
dsp_list_node_init(&symnode->node);
dsp_list_node_push_back(&elf->bss_sym,
&symnode->node);
}
}
}
return 0;
}
static int __dsp_elf32_get_extern_sym(struct dsp_elf32 *elf)
{
int ret;
unsigned int idx;
struct dsp_elf32_sym *sym;
int ndx;
struct dsp_elf32_idx_node *symnode;
DL_DEBUG("Elf32 get extern symbols\n");
for (idx = 0; idx < elf->symtab_num; idx++) {
sym = &elf->symtab[idx];
ndx = sym->st_shndx;
if (ndx == 0) {
const char *sym_str;
sym_str = __dsp_elf32_get_ptr(elf, elf->strtab +
sym->st_name, sizeof(char));
if (!sym_str) {
DL_ERROR("sym_str is NULL\n");
return -1;
}
ret = dsp_hash_get(&elf->symhash, sym_str,
(void **)&sym);
if (ret == -1) {
symnode =
(struct dsp_elf32_idx_node *)
dsp_dl_malloc(
sizeof(*symnode),
"extern sym node");
symnode->idx = idx;
dsp_list_node_init(&symnode->node);
dsp_list_node_push_back(&elf->extern_sym,
&symnode->node);
}
}
}
return 0;
}
int dsp_elf32_load(struct dsp_elf32 *elf, struct dsp_dl_lib_file *file)
{
int ret;
struct dsp_elf32_shdr *shstrtab_hdr;
int idx;
DL_DEBUG("Elf32 load\n");
ret = __dsp_elf32_check_magic(file);
if (ret == -1) {
DL_ERROR("CHK_ERR\n");
return -1;
}
elf->data = (char *)file->mem;
elf->size = file->size;
elf->hdr = __dsp_elf32_get_ptr(elf, elf->data,
sizeof(struct dsp_elf32_hdr));
if (!elf->hdr) {
DL_ERROR("elf->hdr is NULL\n");
return -1;
}
elf->shdr = __dsp_elf32_get_ptr(elf, elf->data + elf->hdr->e_shoff,
sizeof(struct dsp_elf32_shdr));
if (!elf->shdr) {
DL_ERROR("elf->shdr is NULL\n");
return -1;
}
elf->shdr_num = elf->hdr->e_shnum;
shstrtab_hdr = __dsp_elf32_get_ptr(elf, elf->shdr +
elf->hdr->e_shstrndx, sizeof(struct dsp_elf32_shdr));
if (!shstrtab_hdr) {
DL_ERROR("shstrtab_hdr is NULL\n");
return -1;
}
elf->shstrtab = __dsp_elf32_get_ptr(elf, elf->data +
shstrtab_hdr->sh_offset, sizeof(char));
if (!elf->shstrtab) {
DL_ERROR("elf->shstrtab is NULL\n");
return -1;
}
for (idx = 0; idx < elf->hdr->e_shnum; idx++) {
struct dsp_elf32_shdr *shdr;
const char *shdr_name;
shdr = __dsp_elf32_get_ptr(elf, elf->shdr + idx,
sizeof(struct dsp_elf32_shdr));
if (!shdr) {
DL_ERROR("shdr is NULL\n");
return -1;
}
shdr_name = __dsp_elf32_get_ptr(elf, elf->shstrtab +
shdr->sh_name, sizeof(char));
if (!shdr_name) {
DL_ERROR("shdr_name is NULL\n");
return -1;
}
if (shdr->sh_type == 2) {
ret = __dsp_elf32_get_symtab(idx, elf);
if (ret == -1) {
DL_ERROR("Failed to get symtab\n");
return -1;
}
} else if (strcmp(".text", shdr_name) == 0) {
__dsp_elf32_get_text(idx, elf);
} else if (strncmp(".robss.", shdr_name, 7) == 0) {
const char *mem_name = shdr_name + 7;
__dsp_elf32_get_mem(idx, mem_name, &elf->DMb.robss,
&elf->DMb_local.robss,
&elf->DRAMb.robss, &elf->TCMb.robss,
&elf->TCMb_local.robss,
&elf->SFRw.robss);
} else if (strncmp(".bss.", shdr_name, 5) == 0) {
const char *mem_name = shdr_name + 5;
__dsp_elf32_get_mem(idx, mem_name, &elf->DMb.bss,
&elf->DMb_local.bss, &elf->DRAMb.bss,
&elf->TCMb.bss, &elf->TCMb_local.bss,
&elf->SFRw.bss);
} else if (strncmp(".data.", shdr_name, 6) == 0) {
const char *mem_name = shdr_name + 6;
__dsp_elf32_get_mem(idx, mem_name, &elf->DMb.data,
&elf->DMb_local.data, &elf->DRAMb.data,
&elf->TCMb.data, &elf->TCMb_local.data,
&elf->SFRw.data);
} else if (strncmp(".rodata.", shdr_name, 8) == 0) {
const char *mem_name = shdr_name + 8;
__dsp_elf32_get_mem(idx, mem_name, &elf->DMb.rodata,
&elf->DMb_local.rodata,
&elf->DRAMb.rodata, &elf->TCMb.rodata,
&elf->TCMb_local.rodata,
&elf->SFRw.rodata);
} else if (strncmp(".rela.", shdr_name, 6) == 0) {
const char *sec_name = shdr_name + 6;
ret = __dsp_elf32_get_mem_rela(idx, sec_name, elf,
&elf->text.rela, &elf->DMb.rela,
&elf->DMb_local.rela, &elf->DRAMb.rela,
&elf->TCMb.rela, &elf->TCMb_local.rela,
&elf->SFRw.rela);
if (ret == -1) {
DL_ERROR("Failed to get mem rela\n");
return -1;
}
}
}
ret = __dsp_elf32_get_bss_symhash(elf);
if (ret == -1) {
DL_ERROR("Failed to get bss symhash\n");
return -1;
}
ret = __dsp_elf32_get_extern_sym(elf);
if (ret == -1) {
DL_ERROR("Failed to get extern sym\n");
return -1;
}
return 0;
}
static void __dsp_elf32_mem_free(struct dsp_elf32_mem *mem)
{
dsp_list_free(&mem->robss, struct dsp_elf32_idx_node, node);
dsp_list_free(&mem->bss, struct dsp_elf32_idx_node, node);
dsp_list_free(&mem->rodata, struct dsp_elf32_idx_node, node);
dsp_list_free(&mem->data, struct dsp_elf32_idx_node, node);
dsp_list_free(&mem->rela, struct dsp_elf32_rela_node, node);
}
static void __dsp_elf32_text_free(struct dsp_elf32_text *text)
{
dsp_list_free(&text->text, struct dsp_elf32_idx_node, node);
dsp_list_free(&text->rela, struct dsp_elf32_rela_node, node);
}
void dsp_elf32_free(struct dsp_elf32 *elf)
{
dsp_list_free(&elf->bss_sym, struct dsp_elf32_idx_node, node);
dsp_list_free(&elf->extern_sym, struct dsp_elf32_idx_node, node);
dsp_hash_free(&elf->symhash, 0);
__dsp_elf32_mem_free(&elf->DMb);
__dsp_elf32_mem_free(&elf->DMb_local);
__dsp_elf32_mem_free(&elf->TCMb);
__dsp_elf32_mem_free(&elf->TCMb_local);
__dsp_elf32_mem_free(&elf->DRAMb);
__dsp_elf32_mem_free(&elf->SFRw);
__dsp_elf32_text_free(&elf->text);
}
static unsigned int __dsp_elf32_align_4byte(unsigned int size)
{
return (size + 0x3) & ~(0x3);
}
static unsigned int __dsp_elf32_get_section_list_size(
struct dsp_list_head *head, struct dsp_elf32 *elf)
{
unsigned int total = 0;
struct dsp_list_node *node;
dsp_list_for_each(node, head) {
struct dsp_elf32_idx_node *idx_node =
container_of(node, struct dsp_elf32_idx_node, node);
struct dsp_elf32_shdr *sec = elf->shdr + idx_node->idx;
unsigned int size = sec->sh_size;
total += __dsp_elf32_align_4byte(size);
}
return total;
}
unsigned int dsp_elf32_get_text_size(struct dsp_elf32 *elf)
{
return __dsp_elf32_get_section_list_size(&elf->text.text, elf);
}
unsigned int dsp_elf32_get_mem_size(struct dsp_elf32_mem *mem,
struct dsp_elf32 *elf)
{
unsigned int total = 0;
total += __dsp_elf32_get_section_list_size(&mem->robss, elf);
total += __dsp_elf32_get_section_list_size(&mem->rodata, elf);
total += __dsp_elf32_get_section_list_size(&mem->bss, elf);
total += __dsp_elf32_get_section_list_size(&mem->data, elf);
return total;
}
void dsp_elf32_print(struct dsp_elf32 *elf)
{
dsp_elf32_hdr_print(elf);
dsp_elf32_shdr_print(elf);
dsp_elf32_symtab_print(elf);
dsp_elf32_bss_sym_print(elf);
dsp_elf32_extern_sym_print(elf);
dsp_elf32_symhash_print(elf);
dsp_elf32_text_print(elf);
dsp_elf32_DMb_print(elf);
dsp_elf32_DMb_local_print(elf);
dsp_elf32_DRAMb_print(elf);
dsp_elf32_TCMb_print(elf);
dsp_elf32_TCMb_local_print(elf);
dsp_elf32_SFRw_print(elf);
}
void dsp_elf32_hdr_print(struct dsp_elf32 *elf)
{
int idx;
struct dsp_elf32_hdr *header = elf->hdr;
DL_DEBUG(DL_BORDER);
DL_DEBUG("Elf header\n");
DL_BUF_STR("Elf Magic number : ");
for (idx = 0; idx < 16; idx++)
DL_BUF_STR("%x ", header->e_ident[idx]);
DL_BUF_STR("\n");
DL_PRINT_BUF(DEBUG);
DL_DEBUG("Class : %s\n", elf_class[header->e_ident[EI_CLASS]]);
DL_DEBUG("Endian : %s\n", elf_endian[header->e_ident[EI_DATA]]);
DL_DEBUG("Version : %d\n", header->e_ident[EI_VERSION]);
DL_DEBUG("OS ABI : %s\n", elf_os[header->e_ident[EI_OSABI]]);
DL_DEBUG("ABI VERSION : %d\n", header->e_ident[EI_ABIVERSION]);
DL_DEBUG("OBJ Type : %s\n", elf_type[header->e_type]);
DL_DEBUG("Machine id : %#x\n", header->e_machine);
DL_DEBUG("Elf version : %d\n", header->e_version);
DL_DEBUG("Entry point : %#x\n", header->e_entry);
DL_DEBUG("Program header address : %#x\n", header->e_phoff);
DL_DEBUG("Section header address : %#x\n", header->e_shoff);
DL_DEBUG("Flag : %d\n", header->e_flags);
DL_DEBUG("Header Size : %d\n", header->e_ehsize);
DL_DEBUG("Program header size : %d\n", header->e_phentsize);
DL_DEBUG("Program header entry : %d\n", header->e_phnum);
DL_DEBUG("Section header size : %d\n", header->e_shentsize);
DL_DEBUG("Section header entry : %d\n", header->e_shnum);
DL_DEBUG("Section header string table index : %d\n",
header->e_shstrndx);
}
void dsp_elf32_shdr_print(struct dsp_elf32 *elf)
{
unsigned int idx;
struct dsp_elf32_shdr *shdr = elf->shdr;
char *shstrtab = elf->shstrtab;
DL_DEBUG(DL_BORDER);
DL_DEBUG("section header\n");
for (idx = 0; idx < elf->shdr_num; idx++) {
DL_BUF_STR("[%d] ", idx);
DL_BUF_STR("%s ", shstrtab + shdr[idx].sh_name);
DL_BUF_STR("type:%d ", shdr[idx].sh_type);
DL_BUF_STR("flag:%#x ", shdr[idx].sh_flags);
DL_BUF_STR("addr:%#x ", shdr[idx].sh_addr);
DL_BUF_STR("off:%#x ", shdr[idx].sh_offset);
DL_BUF_STR("sz:%d ", shdr[idx].sh_size);
DL_BUF_STR("link:%d ", shdr[idx].sh_link);
DL_BUF_STR("info:%d ", shdr[idx].sh_info);
DL_BUF_STR("align:%d ", shdr[idx].sh_addralign);
DL_BUF_STR("entsz:%d\n", shdr[idx].sh_entsize);
DL_PRINT_BUF(DEBUG);
}
}
static void __dsp_elf32_print_sym(struct dsp_elf32_sym *sym, char *strtab)
{
DL_BUF_STR("%s ", strtab + sym->st_name);
DL_BUF_STR("value:%#x ", sym->st_value);
DL_BUF_STR("sz:%d ", sym->st_size);
DL_BUF_STR("info:%d ", sym->st_info);
DL_BUF_STR("other:%d ", sym->st_other);
DL_BUF_STR("ndx:%d\n", sym->st_shndx);
DL_PRINT_BUF(DEBUG);
}
void dsp_elf32_symtab_print(struct dsp_elf32 *elf)
{
unsigned int idx;
DL_DEBUG(DL_BORDER);
DL_DEBUG("symbol table\n");
for (idx = 0; idx < elf->symtab_num; idx++) {
DL_BUF_STR("[%d]: ", idx);
__dsp_elf32_print_sym(&elf->symtab[idx], elf->strtab);
}
}
void dsp_elf32_bss_sym_print(struct dsp_elf32 *elf)
{
struct dsp_list_node *node;
DL_DEBUG(DL_BORDER);
DL_DEBUG("bss symbols\n");
dsp_list_for_each(node, &elf->bss_sym) {
struct dsp_elf32_idx_node *symnode =
container_of(node, struct dsp_elf32_idx_node, node);
struct dsp_elf32_sym *sym = &elf->symtab[symnode->idx];
DL_BUF_STR("[bss]: ");
__dsp_elf32_print_sym(sym, elf->strtab);
}
}
void dsp_elf32_extern_sym_print(struct dsp_elf32 *elf)
{
struct dsp_list_node *node;
DL_DEBUG(DL_BORDER);
DL_DEBUG("extern symbols\n");
dsp_list_for_each(node, &elf->extern_sym) {
struct dsp_elf32_idx_node *symnode =
container_of(node, struct dsp_elf32_idx_node, node);
struct dsp_elf32_sym *sym = &elf->symtab[symnode->idx];
DL_BUF_STR("[extern]: ");
__dsp_elf32_print_sym(sym, elf->strtab);
}
}
void dsp_elf32_symhash_print(struct dsp_elf32 *elf)
{
int idx;
struct dsp_list_node *node;
DL_DEBUG(DL_BORDER);
DL_DEBUG("symbol hash table\n");
for (idx = 0; idx < DSP_HASH_MAX; idx++) {
dsp_list_for_each(node, &elf->symhash.list[idx]) {
struct dsp_hash_node *hash_node =
container_of(node, struct dsp_hash_node, node);
struct dsp_elf32_sym *sym =
(struct dsp_elf32_sym *)hash_node->value;
DL_BUF_STR("key[%u] ", hash_node->key);
__dsp_elf32_print_sym(sym, elf->strtab);
}
}
}
static void __dsp_elf32_print_rela(struct dsp_list_head *rela_list,
struct dsp_elf32 *elf)
{
unsigned int idx;
unsigned int r_info;
struct dsp_elf32_rela *rela;
struct dsp_list_node *node;
struct dsp_elf32_rela_node *rela_node;
dsp_list_for_each(node, rela_list) {
rela_node = container_of(node,
struct dsp_elf32_rela_node, node);
DL_DEBUG(".rela[%d]\n", rela_node->idx);
rela = rela_node->rela;
for (idx = 0; idx < rela_node->rela_num; idx++) {
r_info = rela[idx].r_info;
DL_BUF_STR("[%d]: ", idx);
DL_BUF_STR("offset:%d ", rela[idx].r_offset);
DL_BUF_STR("info:%#x ", r_info);
DL_BUF_STR("sym:%d(%s) ", r_info >> 8, elf->strtab +
elf->symtab[r_info >> 8].st_name);
DL_BUF_STR("reltype:%d ", r_info & 0xff);
DL_BUF_STR("r_addend:%d\n", rela[idx].r_addend);
DL_PRINT_BUF(DEBUG);
}
DL_DEBUG("\n");
}
}
void dsp_elf32_text_print(struct dsp_elf32 *elf)
{
unsigned int idx;
int jdx;
struct dsp_list_node *node;
DL_DEBUG(DL_BORDER);
DL_DEBUG("Elf32 mem : text(%u)\n",
dsp_elf32_get_text_size(elf));
dsp_list_for_each(node, &elf->text.text) {
struct dsp_elf32_idx_node *idx_node =
container_of(node, struct dsp_elf32_idx_node, node);
struct dsp_elf32_shdr *text_hdr = elf->shdr + idx_node->idx;
unsigned int *text = (unsigned int *)(elf->data +
text_hdr->sh_offset);
size_t size = __dsp_elf32_align_4byte(text_hdr->sh_size) /
sizeof(unsigned int);
DL_DEBUG(".text[%d]\n", idx_node->idx);
for (idx = 0; idx < size; idx++) {
if (idx != 0 && idx % 4 == 0) {
DL_BUF_STR("\n");
DL_PRINT_BUF(DEBUG);
}
DL_BUF_STR("0x");
for (jdx = 0; jdx < 4; jdx++)
DL_BUF_STR("%02x",
((const unsigned char *)
(text + idx))[jdx]);
DL_BUF_STR(" ");
}
DL_BUF_STR("\n");
DL_PRINT_BUF(DEBUG);
DL_DEBUG("\n");
}
__dsp_elf32_print_rela(&elf->text.rela, elf);
}
static void __dsp_elf32_print_mem(struct dsp_elf32_mem *mem,
struct dsp_elf32 *elf)
{
unsigned int idx;
struct dsp_list_node *node;
dsp_list_for_each(node, &mem->robss) {
struct dsp_elf32_idx_node *idx_node =
container_of(node, struct dsp_elf32_idx_node, node);
struct dsp_elf32_shdr *bss_hdr = elf->shdr + idx_node->idx;
DL_DEBUG("robss[%d] : %d\n", idx_node->idx, bss_hdr->sh_size);
}
dsp_list_for_each(node, &mem->rodata) {
struct dsp_elf32_idx_node *idx_node =
container_of(node, struct dsp_elf32_idx_node, node);
struct dsp_elf32_shdr *rodata_hdr = elf->shdr + idx_node->idx;
unsigned int *rodata = (unsigned int *)(elf->data +
rodata_hdr->sh_offset);
size_t size = __dsp_elf32_align_4byte(rodata_hdr->sh_size) /
sizeof(unsigned int);
DL_DEBUG("\n");
DL_DEBUG("rodata[%d]\n", idx_node->idx);
for (idx = 0; idx < size; idx++) {
if (idx != 0 && idx % 4 == 0) {
DL_BUF_STR("\n");
DL_PRINT_BUF(DEBUG);
}
DL_BUF_STR("0x%08x ", rodata[idx]);
}
DL_BUF_STR("\n");
DL_PRINT_BUF(DEBUG);
}
dsp_list_for_each(node, &mem->bss) {
struct dsp_elf32_idx_node *idx_node =
container_of(node, struct dsp_elf32_idx_node, node);
struct dsp_elf32_shdr *bss_hdr = elf->shdr + idx_node->idx;
DL_DEBUG("bss[%d] : %d\n", idx_node->idx, bss_hdr->sh_size);
}
dsp_list_for_each(node, &mem->data) {
struct dsp_elf32_idx_node *idx_node =
container_of(node, struct dsp_elf32_idx_node, node);
struct dsp_elf32_shdr *data_hdr = elf->shdr + idx_node->idx;
unsigned int *data = (unsigned int *)(elf->data +
data_hdr->sh_offset);
size_t size = __dsp_elf32_align_4byte(data_hdr->sh_size) /
sizeof(unsigned int);
DL_DEBUG("\n");
DL_DEBUG("data[%d]\n", idx_node->idx);
for (idx = 0; idx < size; idx++) {
if (idx != 0 && idx % 4 == 0) {
DL_BUF_STR("\n");
DL_PRINT_BUF(DEBUG);
}
DL_BUF_STR("0x%08x ", data[idx]);
}
DL_BUF_STR("\n");
DL_PRINT_BUF(DEBUG);
}
__dsp_elf32_print_rela(&mem->rela, elf);
}
void dsp_elf32_DMb_print(struct dsp_elf32 *elf)
{
DL_DEBUG(DL_BORDER);
DL_DEBUG("Elf32 mem : DMb(%u)\n",
dsp_elf32_get_mem_size(&elf->DMb, elf));
__dsp_elf32_print_mem(&elf->DMb, elf);
}
void dsp_elf32_DMb_local_print(struct dsp_elf32 *elf)
{
DL_DEBUG(DL_BORDER);
DL_DEBUG("Elf32 mem : DMb_local(%u)\n",
dsp_elf32_get_mem_size(&elf->DMb_local, elf));
__dsp_elf32_print_mem(&elf->DMb_local, elf);
}
void dsp_elf32_DRAMb_print(struct dsp_elf32 *elf)
{
DL_DEBUG(DL_BORDER);
DL_DEBUG("Elf32 mem : DRAMb(%u)\n",
dsp_elf32_get_mem_size(&elf->DRAMb, elf));
__dsp_elf32_print_mem(&elf->DRAMb, elf);
}
void dsp_elf32_TCMb_print(struct dsp_elf32 *elf)
{
DL_DEBUG(DL_BORDER);
DL_DEBUG("Elf32 mem : TCMb(%u)\n",
dsp_elf32_get_mem_size(&elf->TCMb, elf));
__dsp_elf32_print_mem(&elf->TCMb, elf);
}
void dsp_elf32_TCMb_local_print(struct dsp_elf32 *elf)
{
DL_DEBUG(DL_BORDER);
DL_DEBUG("Elf32 mem : TCMb_local(%u)\n",
dsp_elf32_get_mem_size(&elf->TCMb_local, elf));
__dsp_elf32_print_mem(&elf->TCMb_local, elf);
}
void dsp_elf32_SFRw_print(struct dsp_elf32 *elf)
{
DL_DEBUG(DL_BORDER);
DL_DEBUG("Elf32 mem : SFRw(%u)\n",
dsp_elf32_get_mem_size(&elf->SFRw, elf));
__dsp_elf32_print_mem(&elf->SFRw, elf);
}
int dsp_elf32_load_libs(struct dsp_dl_lib_info *infos,
struct dsp_lib **libs, int libs_size)
{
int ret, idx;
DL_DEBUG("load elf\n");
for (idx = 0; idx < libs_size; idx++) {
if (!libs[idx]->elf) {
struct dsp_elf32 *elf;
DL_DEBUG("Load ELF for library %s\n",
libs[idx]->name);
elf = (struct dsp_elf32 *)
dsp_dl_malloc(sizeof(*elf), "Elf");
__dsp_elf32_init(elf);
libs[idx]->elf = elf;
ret = dsp_elf32_load(libs[idx]->elf,
&infos[idx].file);
if (ret == -1) {
DL_ERROR("CHK_ERR\n");
return -1;
}
}
}
return 0;
}