HV: Add implements of 32bit and 64bit elf loader

This is a simply implement for the 32bit and 64bit elf loader.

The loading function first reads the image header, and finds the program
entries that are marked as PT_LOAD, then loads segments from elf file to
guest ram. After that, it finds the bss section in the elf section entries, and
clear the ram area it points to.

Limitations:
1. The e_type of the elf image must be ET_EXEC(executable). Relocatable or
   dynamic code is not supported.
2. The loader only copies program segments that has a p_type of
   PT_LOAD(loadable segment). Other segments are ignored.
3. The loader doesn’t support Sections that are relocatable
   (sh_type is SHT_REL or SHT_RELA)
4. The 64bit elf’s entry address must below 4G.
5. The elf is assumed to be able to put segments to valid guest memory.

Tracked-On: #6323

Signed-off-by: Zhou, Wu <wu.zhou@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Zhou, Wu 2021-08-12 18:40:25 +08:00 committed by wenlingz
parent c2468d2791
commit b394777908
1 changed files with 109 additions and 2 deletions

View File

@ -17,8 +17,61 @@ static void *do_load_elf64(struct acrn_vm *vm)
{
struct sw_kernel_info *sw_kernel = &(vm->sw.kernel_info);
void *p_elf_img = (void *)sw_kernel->kernel_src_addr;
struct elf64_hdr *p_elf_header64 = (struct elf64_hdr *)p_elf_img;
struct elf64_prog_entry *p_prg_tbl_head64;
struct elf64_sec_entry *p_sec_tbl_head64, *p_shstr_tbl_head64;
const char *p_shstr_tbl, *p_sec_name;
void *elf_entry = NULL, *p_elf_bss = NULL;
uint32_t i;
return p_elf_img;
/* Currently only ET_EXEC is supported */
if (p_elf_header64->e_type == ET_EXEC) {
p_prg_tbl_head64 = (struct elf64_prog_entry *)(p_elf_img + p_elf_header64->e_phoff);
/* Prepare program entries */
for (i = 0U; i < p_elf_header64->e_phnum; i++) {
/**
* We now only support PT_LOAD type. It needs to copy from file to ram
* TODO: More program types may be needed here
*/
if (p_prg_tbl_head64->p_type == PT_LOAD) {
/**
* copy_to_gpa will check whether the gpa is in EPT, and print message
* if anything wrong.
* However, the guest OS may still fail to boot if they load segments
* to invalid gpa such as ACPI area defined in ve820.
*
* We assume that the guest elf can put segments to valid gpa.
*/
(void)copy_to_gpa(vm, p_elf_img + p_prg_tbl_head64->p_offset,
p_prg_tbl_head64->p_paddr, (uint32_t)p_prg_tbl_head64->p_filesz);
/* copy_to_gpa has it's stac/clac inside. So call stac again here. */
stac();
}
p_prg_tbl_head64++;
}
/* Find and clear bss sections */
p_sec_tbl_head64 = (struct elf64_sec_entry *)(p_elf_img + p_elf_header64->e_shoff);
p_shstr_tbl_head64 = p_sec_tbl_head64 + p_elf_header64->e_shstrndx;
p_shstr_tbl = (char *)(p_elf_img + p_shstr_tbl_head64->sh_offset);
/* Currently we don't support relocatable sections(sh_type is SHT_REL or SHT_RELA).
Assume that the guest elf do not have relocatable sections. */
for (i = 0U; i < p_elf_header64->e_shnum; i++) {
/* A section entry's name is an offset, real string is in string tab */
p_sec_name = p_shstr_tbl + p_sec_tbl_head64->sh_name;
if ((strncmp(p_sec_name, "bss", 3) == 0) || (strncmp(p_sec_name, ".bss", 4) == 0)) {
p_elf_bss = gpa2hva(vm, p_sec_tbl_head64->sh_addr);
memset(p_elf_bss, 0U, p_sec_tbl_head64->sh_size);
}
p_sec_tbl_head64++;
}
elf_entry = (void *)p_elf_header64->e_entry;
} else {
pr_err("%s, elf type(%x) not supported!", __func__, p_elf_header64->e_type);
}
/* For 64bit elf, entry address above 4G is not currently supported. Assume that it's below 4G. */
return elf_entry;
}
/**
@ -29,8 +82,62 @@ static void *do_load_elf32(struct acrn_vm *vm)
{
struct sw_kernel_info *sw_kernel = &(vm->sw.kernel_info);
void *p_elf_img = (void *)sw_kernel->kernel_src_addr;
struct elf32_hdr *p_elf_header32 = (struct elf32_hdr *)p_elf_img;
struct elf32_prog_entry *p_prg_tbl_head32;
struct elf32_sec_entry *p_sec_tbl_head32, *p_shstr_tbl_head32;
const char *p_shstr_tbl, *p_sec_name;
void *elf_entry = NULL, *p_elf_bss = NULL;
uint32_t i;
return p_elf_img;
p_elf_header32 = (struct elf32_hdr *)p_elf_img;
/* Currently only ET_EXEC is supported */
if (p_elf_header32->e_type == ET_EXEC) {
p_prg_tbl_head32 = (struct elf32_prog_entry *)(p_elf_img + p_elf_header32->e_phoff);
/* Copy program entries */
for (i = 0U; i < p_elf_header32->e_phnum; i++) {
/**
* We now only support PT_LOAD type. It needs to copy from file to ram
* TODO: More program types may be needed here
*/
if (p_prg_tbl_head32->p_type == PT_LOAD) {
/**
* copy_to_gpa will check whether the gpa is in EPT, and print message
* if anything wrong.
* However, the guest OS may still fail to boot if they load segments
* to invalid gpa such as ACPI area defined in ve820.
*
* We assume that the guest elf can put segments to valid gpa.
*/
(void)copy_to_gpa(vm, p_elf_img + p_prg_tbl_head32->p_offset,
p_prg_tbl_head32->p_paddr, p_prg_tbl_head32->p_memsz);
/* copy_to_gpa has it's stac/clac inside. So call stac again here. */
stac();
}
p_prg_tbl_head32++;
}
/* Find and clear bss sections */
p_sec_tbl_head32 = (struct elf32_sec_entry *)(p_elf_img + p_elf_header32->e_shoff);
p_shstr_tbl_head32 = p_sec_tbl_head32 + p_elf_header32->e_shstrndx;
p_shstr_tbl = (char *)(p_elf_img + p_shstr_tbl_head32->sh_offset);
/* Currently we don't support relocatable sections(sh_type is SHT_REL or SHT_RELA).
Assume that the guest elf do not have relocatable sections. */
for (i = 0U; i < p_elf_header32->e_shnum; i++) {
/* A section entry's name is an offset, real string is in string tab */
p_sec_name = p_shstr_tbl + p_sec_tbl_head32->sh_name;
if ((strncmp(p_sec_name, "bss", 3) == 0) || (strncmp(p_sec_name, ".bss", 4) == 0)) {
p_elf_bss = gpa2hva(vm, p_sec_tbl_head32->sh_addr);
memset(p_elf_bss, 0U, p_sec_tbl_head32->sh_size);
}
p_sec_tbl_head32++;
}
elf_entry = (void *)(uint64_t)p_elf_header32->e_entry;
} else {
pr_err("%s, elf type(%x) not supported!", __func__, p_elf_header32->e_type);
}
return elf_entry;
}
/**