binfmt: ELF support load to LMA

Load all sections to LMA not VMA, so the startup code(e.g. start.S) need
relocate .data section to the final address(VMA) and zero .bss section by self.

For example, SiFli and Actions: Background: Device with small sram,
Bootloader run in sram and psram, need boot to Application, with memory overlap
and without XIP. VMA of .data is in "psram" and LMA in "rom", if not enable
`ELF_LOADTO_LMA`, ELF loader will load the section to VMA (will fill bootloader
itself).

Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
This commit is contained in:
wangjianyu3 2023-08-21 20:28:56 +08:00 committed by Xiang Xiao
parent d7359bf076
commit c749e4bfbd
7 changed files with 163 additions and 1 deletions

View File

@ -142,6 +142,23 @@ static void elf_dumploadinfo(FAR struct elf_loadinfo_s *loadinfo)
binfo(" e_shnum: %d\n", loadinfo->ehdr.e_shnum);
binfo(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx);
if (loadinfo->phdr && loadinfo->ehdr.e_phnum > 0)
{
for (i = 0; i < loadinfo->ehdr.e_phnum; i++)
{
FAR Elf_Phdr *phdr = &loadinfo->phdr[i];
binfo("Programs %d:\n", i);
binfo(" p_type: %08jx\n", (uintmax_t)phdr->p_type);
binfo(" p_offset: %08jx\n", (uintmax_t)phdr->p_offset);
binfo(" p_vaddr: %08jx\n", (uintmax_t)phdr->p_vaddr);
binfo(" p_paddr: %08jx\n", (uintmax_t)phdr->p_paddr);
binfo(" p_filesz: %08jx\n", (uintmax_t)phdr->p_filesz);
binfo(" p_memsz: %08jx\n", (uintmax_t)phdr->p_memsz);
binfo(" p_flags: %08jx\n", (uintmax_t)phdr->p_flags);
binfo(" p_align: %08x\n", phdr->p_align);
}
}
if (loadinfo->shdr && loadinfo->ehdr.e_shnum > 0)
{
for (i = 0; i < loadinfo->ehdr.e_shnum; i++)

View File

@ -73,3 +73,11 @@ config ELF_COREDUMP
The memory state embeds a snapshot of all segments mapped in the
memory space of the program. The CPU state contains register values
when the core dump has been generated.
config ELF_LOADTO_LMA
bool "ELF load sections to LMA"
default n
---help---
Load all section to LMA not VMA, so the startup code(e.g. start.S) need
relocate .data section to the final address(VMA) and zero .bss section
by self.

View File

@ -65,6 +65,20 @@ int elf_verifyheader(FAR const Elf_Ehdr *header);
int elf_read(FAR struct elf_loadinfo_s *loadinfo, FAR uint8_t *buffer,
size_t readsize, off_t offset);
/****************************************************************************
* Name: elf_loadphdrs
*
* Description:
* Loads program headers into memory.
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int elf_loadphdrs(FAR struct elf_loadinfo_s *loadinfo);
/****************************************************************************
* Name: elf_loadshdrs
*

View File

@ -123,6 +123,41 @@ static void elf_elfsize(FAR struct elf_loadinfo_s *loadinfo)
loadinfo->datasize = datasize;
}
#ifdef CONFIG_ELF_LOADTO_LMA
/****************************************************************************
* Name: elf_vma2lma
*
* Description:
* Convert section`s VMA to LMA according to PhysAddr(p_paddr) of
* Program Header.
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
static int elf_vma2lma(FAR struct elf_loadinfo_s *loadinfo,
FAR Elf_Shdr *shdr, FAR Elf_Addr *lma)
{
int i;
for (i = 0; i < loadinfo->ehdr.e_phnum; i++)
{
FAR Elf_Phdr *phdr = &loadinfo->phdr[i];
if (shdr->sh_addr >= phdr->p_vaddr &&
shdr->sh_addr < phdr->p_vaddr + phdr->p_memsz)
{
*lma = phdr->p_paddr + shdr->sh_addr - phdr->p_vaddr;
return 0;
}
}
return -ENOENT;
}
#endif
/****************************************************************************
* Name: elf_loadfile
*
@ -178,9 +213,20 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo)
{
if (shdr->sh_type != SHT_NOBITS)
{
Elf_Addr addr = shdr->sh_addr;
#ifdef CONFIG_ELF_LOADTO_LMA
ret = elf_vma2lma(loadinfo, shdr, &addr);
if (ret < 0)
{
berr("ERROR: Failed to convert addr %d: %d\n", i, ret);
return ret;
}
#endif
/* Read the section data from sh_offset to specified region */
ret = elf_read(loadinfo, (FAR uint8_t *)shdr->sh_addr,
ret = elf_read(loadinfo, (FAR uint8_t *)addr,
shdr->sh_size, shdr->sh_offset);
if (ret < 0)
{
@ -189,6 +235,7 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo)
}
}
#ifndef CONFIG_ELF_LOADTO_LMA
/* If there is no data in an allocated section, then the
* allocated section must be cleared.
*/
@ -197,6 +244,7 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo)
{
memset((FAR uint8_t *)shdr->sh_addr, 0, shdr->sh_size);
}
#endif
continue;
}
@ -284,6 +332,15 @@ int elf_load(FAR struct elf_loadinfo_s *loadinfo)
binfo("loadinfo: %p\n", loadinfo);
DEBUGASSERT(loadinfo && loadinfo->file.f_inode);
/* Load program headers into memory */
ret = elf_loadphdrs(loadinfo);
if (ret < 0)
{
berr("ERROR: elf_loadphdrs failed: %d\n", ret);
goto errout_with_buffers;
}
/* Load section headers into memory */
ret = elf_loadshdrs(loadinfo);

View File

@ -165,6 +165,65 @@ static inline int elf_sectname(FAR struct elf_loadinfo_s *loadinfo,
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: elf_loadphdrs
*
* Description:
* Loads program headers into memory.
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int elf_loadphdrs(FAR struct elf_loadinfo_s *loadinfo)
{
size_t phdrsize;
int ret;
DEBUGASSERT(loadinfo->phdr == NULL);
/* Verify that there are programs */
if (loadinfo->ehdr.e_phnum < 1)
{
berr("No programs(?)\n");
return -EINVAL;
}
/* Get the total size of the program header table */
phdrsize = (size_t)loadinfo->ehdr.e_phentsize *
(size_t)loadinfo->ehdr.e_phnum;
if (loadinfo->ehdr.e_phoff + phdrsize > loadinfo->filelen)
{
berr("Insufficient space in file for program header table\n");
return -ESPIPE;
}
/* Allocate memory to hold a working copy of the program header table */
loadinfo->phdr = (FAR FAR Elf_Phdr *)kmm_malloc(phdrsize);
if (!loadinfo->phdr)
{
berr("Failed to allocate the program header table. Size: %ld\n",
(long)phdrsize);
return -ENOMEM;
}
/* Read the program header table into memory */
ret = elf_read(loadinfo, (FAR uint8_t *)loadinfo->phdr, phdrsize,
loadinfo->ehdr.e_phoff);
if (ret < 0)
{
berr("Failed to read program header table: %d\n", ret);
}
return ret;
}
/****************************************************************************
* Name: elf_loadshdrs
*

View File

@ -94,6 +94,12 @@ int elf_freebuffers(FAR struct elf_loadinfo_s *loadinfo)
{
/* Release all working allocations */
if (loadinfo->phdr)
{
kmm_free((FAR void *)loadinfo->phdr);
loadinfo->phdr = NULL;
}
if (loadinfo->shdr)
{
kmm_free(loadinfo->shdr);

View File

@ -91,6 +91,7 @@ struct elf_loadinfo_s
int filemode; /* Mode of the file system */
Elf_Ehdr ehdr; /* Buffered ELF file header */
FAR Elf_Phdr *phdr; /* Buffered ELF program headers */
FAR Elf_Shdr *shdr; /* Buffered ELF section headers */
uint8_t *iobuffer; /* File I/O buffer */