#include <config.h>
#include <l4io.h>
#include <l4/bootinfo.h>
#include "kickstart.h"
#include "elf.h"
#include "lib.h"
template<typename T>
inline T min(T v1, T v2)
{
if(v1 < v2)
return v1;
return v2;
}
template<typename T>
inline T max(T v1, T v2)
{
if(v1 > v2)
return v1;
return v2;
}
bool elf_load32 (L4_Word_t file_start,
L4_Word_t file_end,
L4_Word_t *memory_start,
L4_Word_t *memory_end,
L4_Word_t *entry);
bool elf_find_sections32 (L4_Word_t addr,
L4_Boot_SimpleExec_t * exec);
bool elf_load64 (L4_Word_t file_start,
L4_Word_t file_end,
L4_Word_t *memory_start,
L4_Word_t *memory_end,
L4_Word_t *entry);
bool elf_find_sections64 (L4_Word_t addr,
L4_Boot_SimpleExec_t * exec);
bool __elf_func(elf_load) (L4_Word_t file_start,
L4_Word_t file_end,
L4_Word_t *memory_start,
L4_Word_t *memory_end,
L4_Word_t *entry)
{
ehdr_t* eh = (ehdr_t*) file_start;
if (eh->type != 2)
{
l4_printf(" No executable\n");
return false;
}
if (eh->phoff == 0)
{
l4_printf("Wrong PHDR table offset\n");
return false;
}
l4_printf(" => %p\n", (void *)(L4_Word_t)eh->entry);
L4_Word_t max_addr = 0U;
L4_Word_t min_addr = ~0U;
for (L4_Word_t i = 0; i < eh->phnum; i++)
{
phdr_t* ph = (phdr_t*)(L4_Word_t)
(file_start + eh->phoff + eh->phentsize * i);
if (ph->type == PT_LOAD)
{
l4_printf(" (%p,%p)->%p\n",
(void *)(L4_Word_t) (file_start + ph->offset),
(void *)(L4_Word_t) ph->fsize,
(void *)(L4_Word_t) ph->paddr);
memcopy(ph->paddr, file_start + ph->offset, ph->fsize);
memset (ph->paddr + ph->fsize, 0, ph->msize - ph->fsize);
min_addr = min(min_addr, ph->paddr);
max_addr = max(max_addr, ph->paddr + max(ph->msize, ph->fsize));
}
}
*memory_start = min_addr;
*memory_end = max_addr;
*entry = eh->entry;
return true;
}
bool __elf_func(elf_find_sections) (L4_Word_t addr,
L4_Boot_SimpleExec_t * exec)
{
ehdr_t * eh = (ehdr_t *) addr;
if (eh->type != 2)
return false;
if (eh->phoff == 0)
return false;
memset ((L4_Word_t) exec, 0, sizeof (*exec));
exec->type = L4_BootInfo_SimpleExec;
exec->version = 1;
exec->initial_ip = eh->entry;
exec->offset_next = sizeof (*exec);
if (eh->phoff != 0 && eh->shoff == 0)
{
for (L4_Word_t i = 0; i < eh->phnum; i++)
{
phdr_t * ph = (phdr_t *) (L4_Word_t) (addr + eh->phoff + eh->phentsize * i);
if ((ph->flags & PF_W) == 0)
{
exec->text_pstart = ph->paddr;
exec->text_vstart = ph->paddr;
exec->text_size = ph->fsize;
}
else
{
exec->data_pstart = ph->paddr;
exec->data_vstart = ph->paddr;
exec->data_size = ph->fsize;
}
if (ph->msize > ph->fsize)
{
exec->bss_pstart = ph->paddr + ph->fsize;
exec->bss_vstart = ph->vaddr + ph->fsize;
exec->bss_size = ph->msize - ph->fsize;
}
}
return true;
}
L4_Word_t tlow = ~0UL, thigh = 0;
L4_Word_t dlow = ~0UL, dhigh = 0;
L4_Word_t blow = ~0UL, bhigh = 0;
for (L4_Word_t i = 0; i < eh->shnum; i++)
{
shdr_t * sh = (shdr_t *) (L4_Word_t)
(addr + eh->shoff + eh->shentsize * i);
if (sh->type == SHT_PROGBITS)
{
if ((sh->flags & SHF_ALLOC) &&
((sh->flags & SHF_EXECINSTR) || (~sh->flags & SHF_WRITE)))
{
if (sh->addr < tlow)
tlow = sh->addr;
if (sh->addr + sh->size > thigh)
thigh = sh->addr + sh->size;
}
else if ((sh->flags & SHF_ALLOC) &&
(sh->flags & SHF_WRITE))
{
if (sh->addr < dlow)
dlow = sh->addr;
if (sh->addr + sh->size > dhigh)
dhigh = sh->addr + sh->size;
}
}
else if (sh->type == SHT_NOBITS)
{
if (sh->addr < blow)
blow = sh->addr;
if (sh->addr + sh->size > bhigh)
bhigh = sh->addr + sh->size;
}
}
#define INSEGMENT(a) (a >= ph->vaddr && a < (ph->vaddr + ph->msize))
#define PADDR(a) (ph->paddr + a - ph->vaddr)
for (L4_Word_t i = 0; i < eh->phnum; i++)
{
phdr_t * ph = (phdr_t *) (L4_Word_t)
(addr + eh->phoff + eh->phentsize * i);
if (INSEGMENT (tlow))
{
exec->text_pstart = PADDR (tlow);
exec->text_vstart = tlow;
exec->text_size = thigh - tlow;
}
if (INSEGMENT (dlow))
{
exec->data_pstart = PADDR (dlow);
exec->data_vstart = dlow;
exec->data_size = dhigh - dlow;
}
if (INSEGMENT (blow))
{
exec->bss_pstart = PADDR (blow);
exec->bss_vstart = blow;
exec->bss_size = bhigh - blow;
}
}
return true;
}
#if !defined(ELF_32on64) && !defined(ELF_64on32)
@param
@param
@param
@param
@param
@returns
bool elf_load (L4_Word_t file_start,
L4_Word_t file_end,
L4_Word_t *memory_start,
L4_Word_t *memory_end,
L4_Word_t *entry)
{
ehdr_t* eh = (ehdr_t*) file_start;
if (!((eh->ident[0] == 0x7F) &&
(eh->ident[1] == 'E') &&
(eh->ident[2] == 'L') &&
(eh->ident[3] == 'F')))
{
return false;
}
#if defined(L4_32BIT) || defined(ALSO_ELF32)
if (eh->is_32bit ())
return elf_load32 (file_start, file_end,
memory_start, memory_end, entry);
#endif
#if defined(L4_64BIT) || defined(ALSO_ELF64)
if (eh->is_64bit ())
return elf_load64 (file_start, file_end,
memory_start, memory_end, entry);
#endif
return false;
}
@param
@param
@returns
bool elf_find_sections (L4_Word_t addr,
L4_Boot_SimpleExec_t * exec)
{
ehdr_t * eh = (ehdr_t *) addr;
if (!((eh->ident[0] == 0x7F) &&
(eh->ident[1] == 'E') &&
(eh->ident[2] == 'L') &&
(eh->ident[3] == 'F')))
{
return false;
}
#if defined(L4_32BIT) || defined(ELF_32on64)
if (eh->is_32bit ())
return elf_find_sections32 (addr, exec);
#endif
#if defined(L4_64BIT) || defined(ELF_64on32)
if (eh->is_64bit ())
return elf_find_sections64 (addr, exec);
#endif
return false;
}
#endif