170 lines
4.4 KiB
C
170 lines
4.4 KiB
C
#include "vxBoot/terminal.h"
|
|
#include "vxBoot/fs/smemfs.h"
|
|
#include "vxBoot/loader.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* error string list */
|
|
const struct ld_error_db header_error_db[] = {
|
|
{.id = ld_header_valid, .strerror = "valid"},
|
|
{.id = ld_header_size_error, .strerror = "size error"},
|
|
{.id = ld_header_magic_error, .strerror = "magic error"},
|
|
{.id = ld_header_class_error, .strerror = "class error"},
|
|
{.id = ld_header_indent_error, .strerror = "indent error"},
|
|
{.id = ld_header_type_error, .strerror = "type error"},
|
|
{.id = ld_header_machine_error, .strerror = "machine error"},
|
|
{.id = ld_header_version_error, .strerror = "version error"},
|
|
{.id = 0xdeb0cad0, .strerror = NULL},
|
|
};
|
|
|
|
/* loader_header_error(): Display header error information */
|
|
int loader_header_error(int const errnum)
|
|
{
|
|
return (loader_error(header_error_db, "ELF header", errnum));
|
|
}
|
|
|
|
/* loader_header_get(): Get ELF header and check validity */
|
|
int loader_header_get(
|
|
struct smemfs_inode const * restrict const inode,
|
|
Elf32_Ehdr *header
|
|
) {
|
|
Elf32_Ehdr tmp;
|
|
|
|
if (header == NULL)
|
|
header = &tmp;
|
|
|
|
/* try to read the ELF header */
|
|
if (smemfs_pread(inode, header, sizeof(*header), 0) != sizeof(*header))
|
|
return (ld_header_size_error);
|
|
|
|
/* Check magic number */
|
|
if (header->e_ident[EI_MAG0] != ELFMAG0
|
|
|| header->e_ident[EI_MAG1] != ELFMAG1
|
|
|| header->e_ident[EI_MAG2] != ELFMAG2
|
|
|| header->e_ident[EI_MAG3] != ELFMAG3) {
|
|
return (ld_header_magic_error);
|
|
}
|
|
|
|
/* Check class */
|
|
if (header->e_ident[EI_CLASS] != ELFCLASS32)
|
|
return (ld_header_class_error);
|
|
|
|
/* Check data encoding */
|
|
if (header->e_ident[EI_DATA] != ELFDATA2MSB)
|
|
return (ld_header_indent_error);
|
|
|
|
/* Check ELF type */
|
|
if (header->e_type != ET_DYN && header->e_type != ET_EXEC)
|
|
return (ld_header_type_error);
|
|
|
|
/* Check ELF specifique instruction */
|
|
if (header->e_machine != EM_SH)
|
|
return (ld_header_machine_error);
|
|
|
|
/* Check ELF version */
|
|
if (header->e_version != EV_CURRENT)
|
|
return (ld_header_version_error);
|
|
return (ld_header_valid);
|
|
}
|
|
|
|
/* hypervisor_elf_loader_header_check():
|
|
Check ELF header validity and dump usefull sections information */
|
|
int loader_header_check(struct kernel * const kernel)
|
|
{
|
|
Elf32_Shdr *shdr;
|
|
char * shstrtab;
|
|
int error;
|
|
|
|
error = loader_header_get(kernel->inode, &kernel->elf.hdr);
|
|
if (error != ld_header_valid)
|
|
return (error);
|
|
|
|
kernel->elf.shdr = malloc(
|
|
kernel->elf.hdr.e_shnum * kernel->elf.hdr.e_shentsize
|
|
);
|
|
smemfs_pread(
|
|
kernel->inode,
|
|
kernel->elf.shdr,
|
|
kernel->elf.hdr.e_shnum * kernel->elf.hdr.e_shentsize,
|
|
kernel->elf.hdr.e_shoff
|
|
);
|
|
|
|
kernel->elf.shstrtab = malloc(
|
|
kernel->elf.shdr[kernel->elf.hdr.e_shstrndx].sh_size
|
|
);
|
|
smemfs_pread(
|
|
kernel->inode,
|
|
kernel->elf.shstrtab,
|
|
kernel->elf.shdr[kernel->elf.hdr.e_shstrndx].sh_size,
|
|
kernel->elf.shdr[kernel->elf.hdr.e_shstrndx].sh_offset
|
|
);
|
|
|
|
kernel->elf.phdr = malloc(kernel->elf.hdr.e_phnum * sizeof(Elf32_Phdr));
|
|
smemfs_pread(
|
|
kernel->inode,
|
|
kernel->elf.phdr,
|
|
kernel->elf.hdr.e_phnum * sizeof(Elf32_Phdr),
|
|
kernel->elf.hdr.e_phoff
|
|
);
|
|
|
|
shdr = kernel->elf.shdr;
|
|
shstrtab = kernel->elf.shstrtab;
|
|
kernel->elf.sym.tab = NULL;
|
|
kernel->elf.sym.nb = 0;
|
|
kernel->elf.strtab = NULL;
|
|
kernel->elf.got = NULL;
|
|
for (int i = 0; i < kernel->elf.hdr.e_shnum; ++i) {
|
|
if (shdr[i].sh_type == SHT_SYMTAB) {
|
|
if (kernel->elf.sym.tab == NULL) {
|
|
kernel->elf.sym.tab = malloc(shdr[i].sh_size);
|
|
smemfs_pread(
|
|
kernel->inode,
|
|
kernel->elf.sym.tab,
|
|
shdr[i].sh_size,
|
|
shdr[i].sh_offset
|
|
);
|
|
kernel->elf.sym.nb = shdr[i].sh_size;
|
|
kernel->elf.sym.nb /= sizeof(Elf32_Sym);
|
|
}
|
|
continue;
|
|
}
|
|
if (kernel->elf.strtab == NULL) {
|
|
if (strcmp(".strtab", &shstrtab[shdr[i].sh_name]) == 0){
|
|
kernel->elf.strtab = malloc(shdr[i].sh_size);
|
|
smemfs_pread(
|
|
kernel->inode,
|
|
kernel->elf.strtab,
|
|
shdr[i].sh_size,
|
|
shdr[i].sh_offset
|
|
);
|
|
continue;
|
|
}
|
|
}
|
|
if (kernel->elf.got == NULL) {
|
|
if (strcmp(".got", &shstrtab[shdr[i].sh_name]) == 0) {
|
|
kernel->elf.got = (void*)(uintptr_t)shdr[i].sh_addr;
|
|
kernel->elf.got_nb = shdr[i].sh_size;
|
|
kernel->elf.got_nb /= sizeof(uintptr_t);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
terminal_log(
|
|
LOG_DEBUG,
|
|
"symtab = %p with %d entries\n"
|
|
"shstrtab = %p\n"
|
|
"strtab = %p\n"
|
|
"shdr = %p\n"
|
|
"phdr = %p\n"
|
|
"got = %p\n",
|
|
kernel->elf.sym.tab, kernel->elf.sym.nb,
|
|
kernel->elf.shstrtab,
|
|
kernel->elf.strtab,
|
|
kernel->elf.shdr,
|
|
kernel->elf.phdr,
|
|
kernel->elf.got
|
|
);
|
|
return (0);
|
|
}
|