103 lines
2.9 KiB
C
103 lines
2.9 KiB
C
#include "vxBoot/fs/smemfs.h"
|
|
#include "vxBoot/loader.h"
|
|
#include "vxBoot/terminal.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* error string list */
|
|
const struct ld_error_db image_error_db[] = {
|
|
{.id = ld_image_success, .strerror = "valid"},
|
|
{.id = ld_image_size_error, .strerror = "size error"},
|
|
{.id = ld_image_type_error, .strerror = "type error"},
|
|
{.id = ld_image_mem_error, .strerror = "out of memory error"},
|
|
{.id = ld_image_mem_not_available, .strerror = "memory not available"},
|
|
{.id = 0xdeb0cad0, .strerror = NULL},
|
|
};
|
|
|
|
/* hypervisor_elf_loader_image_error(): Display image error information */
|
|
int loader_image_error(int const errnum)
|
|
{
|
|
return (loader_error(image_error_db, "ELF image ", errnum));
|
|
}
|
|
|
|
/* loader_load_image() - Load the program into Virtual Memory */
|
|
int loader_image_load(struct kernel * const kernel)
|
|
{
|
|
Elf32_Phdr *phdr;
|
|
uintptr_t paddress;
|
|
uintptr_t origin;
|
|
uintptr_t vmin;
|
|
uintptr_t vmax;
|
|
|
|
/* Walk one time to get the entier program size and check ELF
|
|
validity. */
|
|
vmin = 0xffffffff;
|
|
vmax = 0x00000000;
|
|
phdr = kernel->elf.phdr;
|
|
kernel->memory.program.size = 0;
|
|
for (int i = 0; i < kernel->elf.hdr.e_phnum; ++i) {
|
|
if (phdr[i].p_vaddr >= 0xe5007000 && phdr[i].p_vaddr <= 0xe5009000)
|
|
continue;
|
|
if (phdr[i].p_vaddr < vmin)
|
|
vmin = phdr[i].p_vaddr;
|
|
if (phdr[i].p_vaddr + phdr[i].p_memsz > vmax)
|
|
vmax = phdr[i].p_vaddr + phdr[i].p_memsz;
|
|
}
|
|
kernel->memory.program.size = vmax - vmin;
|
|
kernel->memory.program.elf.vmin = vmin;
|
|
kernel->memory.program.elf.vmax = vmax;
|
|
|
|
terminal_log(
|
|
LOG_DEBUG,
|
|
"program size = %d\n"
|
|
"program vmin = %p\n"
|
|
"program vmax = %p\n",
|
|
kernel->memory.program.size,
|
|
kernel->memory.program.elf.vmin,
|
|
kernel->memory.program.elf.vmax
|
|
);
|
|
|
|
/* check available space in RAM to load the image */
|
|
if (kernel->memory.program.size >= kernel->hardware.ram.available)
|
|
return (ld_image_mem_not_available);
|
|
|
|
/* set the kernel's origin address */
|
|
origin = kernel->hardware.ram.physical.kernel_addr;
|
|
origin |= 0xa0000000;
|
|
kernel->memory.program.start = (void*)origin;
|
|
|
|
/* Now, load all program section into physical memory. To do this, we
|
|
read each program hdr, generate the "real" physical address of
|
|
the segment then dump data.
|
|
|
|
Note that the p_filesz can be smaller than p_memsz so, we need to
|
|
wipe the segment area before the dump. */
|
|
for (int i = 0; i < kernel->elf.hdr.e_phnum; ++i){
|
|
paddress = (uintptr_t)phdr[i].p_vaddr;
|
|
if (paddress < 0xe5007000 || paddress > 0xe5009000) {
|
|
paddress -= vmin;
|
|
paddress += (uintptr_t)kernel->memory.program.start;
|
|
}
|
|
|
|
smemfs_pread(
|
|
kernel->inode,
|
|
(void*)paddress,
|
|
phdr[i].p_filesz,
|
|
phdr[i].p_offset
|
|
);
|
|
memset(
|
|
(void*)paddress,
|
|
0x00,
|
|
phdr[i].p_memsz - phdr[i].p_filesz
|
|
);
|
|
}
|
|
|
|
|
|
/* Generate program entry address */
|
|
kernel->entry = (uintptr_t)kernel->elf.hdr.e_entry - vmin;
|
|
kernel->entry += (uintptr_t)kernel->hardware.ram.physical.kernel_addr;
|
|
kernel->entry |= (uintptr_t)0x80000000;
|
|
return (ld_image_success);
|
|
}
|