81 lines
2.4 KiB
C
81 lines
2.4 KiB
C
//---
|
|
// fxBoot:loader:entry - ELF Loader entry
|
|
//---
|
|
#include "fxBoot/hypervisor.h"
|
|
#include "fxBoot/fs/smemfs.h"
|
|
#include "fxBoot/elf.h"
|
|
|
|
#include <gint/std/stdlib.h>
|
|
#include <gint/std/string.h>
|
|
|
|
#include "./src/hypervisor/internal/elf.h"
|
|
|
|
/* error string list */
|
|
const struct hel_error_db image_error_db[] = {
|
|
{.id = hel_image_success, .strerror = "valid"},
|
|
{.id = hel_image_size_error, .strerror = "size error"},
|
|
{.id = hel_image_type_error, .strerror = "type error"},
|
|
{.id = hel_image_mem_error, .strerror = "out of memory error"},
|
|
{.id = 0xdeb0cad0, .strerror = NULL},
|
|
};
|
|
|
|
/* hypervisor_elf_loader_image_error(): Display image error information */
|
|
int hypervisor_elf_loader_image_error(int errnum)
|
|
{
|
|
return (hypervisor_elf_loader_error(image_error_db,
|
|
"ELF image ", errnum));
|
|
}
|
|
|
|
/* loader_load_image() - Load the program into Virtual Memory */
|
|
int hypervisor_elf_loader_image_load(struct hworld *world,
|
|
struct smemfs_inode *inode, Elf32_Ehdr *header)
|
|
{
|
|
Elf32_Phdr program;
|
|
void *paddress;
|
|
off_t offset;
|
|
uint16_t i;
|
|
|
|
/* Walk one time to get the entier program size and check ELF
|
|
validity. */
|
|
i = -1;
|
|
world->memory.program.size = 0;
|
|
while (++i < header->e_phnum) {
|
|
offset = header->e_phoff + (i * sizeof(Elf32_Phdr));
|
|
if (smemfs_pread(inode, &program, sizeof(Elf32_Phdr), offset)
|
|
!= sizeof(Elf32_Phdr)) {
|
|
return (hel_image_size_error);
|
|
}
|
|
if (program.p_type != PT_LOAD)
|
|
return (hel_image_type_error);
|
|
world->memory.program.size += program.p_memsz;
|
|
}
|
|
|
|
/* Allocate programe memory */
|
|
world->memory.program.start = calloc(world->memory.program.size, 1);
|
|
if (world->memory.program.start == NULL)
|
|
return (hel_image_mem_error);
|
|
|
|
/* Now, load all program section into physical memory. To do this, we
|
|
read each program header, generate the "real" physical address of
|
|
the segment then dump data.
|
|
|
|
Nota that the p_inodesz can be smaller than p_memsz so, we need to
|
|
wipe the segment area before the dump. */
|
|
i = -1;
|
|
while (++i < header->e_phnum) {
|
|
offset = header->e_phoff + (i * sizeof(Elf32_Phdr));
|
|
smemfs_pread(inode, &program, sizeof(Elf32_Phdr), offset);
|
|
|
|
paddress = program.p_vaddr + world->memory.program.start;
|
|
|
|
memset(paddress, 0, program.p_memsz);
|
|
smemfs_pread(inode, paddress,
|
|
program.p_filesz, program.p_offset);
|
|
}
|
|
|
|
/* Generate program entry address */
|
|
world->context.cpu.spc = (uint32_t)header->e_entry;
|
|
world->context.cpu.spc += (uintptr_t)world->memory.program.start;
|
|
return (hel_image_success);
|
|
}
|