vxBoot - 1.2.0 : RELA patch
@add <> vxBoot/builtin/log : log builtin which handle log level <> vxBoot/cli/entry : add log buitin <> vxBoot/loader/elf/rela : relocalize special reloc type (R_SH_DIR32) <> vxBoot/terminal/write : add terminal_vwrite which use a va_list arg @update <> CMakeList.txt : dump version + add new sources files <> include/vxBoot/loader : rework the API and add Elf32_Rela information <> include/vxBoot/terminal : add log information <> vxBoot/loader/elf/got : rework information fetching <> vxBoot/loader/elf/header : rework information fetching <> vxBoot/loader/elf/image : rework information fetching <> vxBoot/loader/elf/entry : rework information fetching <> vxBoot/loader/scan : rework information fetching @fix <> vxBoot/loader/rela : relocalize special reloc type (R_SH_DIR32) <> vxBoot/builtin/ls : help display
This commit is contained in:
parent
3971b78a29
commit
b4f6fd74e9
|
@ -1,5 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
project(vxBoot VERSION 1.1.1 LANGUAGES C)
|
||||
project(vxBoot VERSION 1.1.2 LANGUAGES C)
|
||||
|
||||
include(GenerateG1A)
|
||||
include(GenerateG3A)
|
||||
|
@ -20,14 +20,17 @@ set(SOURCES
|
|||
src/terminal/read.c
|
||||
src/terminal/util.c
|
||||
src/terminal/write.c
|
||||
src/terminal/log.c
|
||||
src/builtin/ls.c
|
||||
src/builtin/help.c
|
||||
src/builtin/hw.c
|
||||
src/builtin/ld.c
|
||||
src/builtin/log.c
|
||||
src/loader/scan.c
|
||||
src/loader/elf/header.c
|
||||
src/loader/elf/image.c
|
||||
src/loader/elf/got.c
|
||||
src/loader/elf/rela.c
|
||||
src/loader/error.c
|
||||
src/loader/entry.c
|
||||
src/loader/info.c
|
||||
|
|
|
@ -9,5 +9,6 @@ extern int os_main(int argc, char **argv);
|
|||
extern int hw_main(int argc, char **argv);
|
||||
extern int ld_main(int argc, char **argv);
|
||||
extern int help_main(int argc, char **argv);
|
||||
extern int log_main(int argc, char **argv);
|
||||
|
||||
#endif /*__VXBOOT_BUILTIN_H__*/
|
||||
|
|
|
@ -113,6 +113,62 @@ typedef struct {
|
|||
#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */
|
||||
#define SHT_NUM 19 /* Number of defined types. */
|
||||
|
||||
/* Relocation table entry with addend (in section of type SHT_RELA). */
|
||||
|
||||
typedef struct {
|
||||
uint32_t r_offset; /* Address */
|
||||
uint32_t r_info; /* Relocation type and symbol index */
|
||||
int32_t r_addend; /* Addend */
|
||||
} Elf32_Rela;
|
||||
|
||||
/* How to extract and insert information held in the r_info field. */
|
||||
|
||||
#define ELF32_R_SYM(val) ((val) >> 8)
|
||||
#define ELF32_R_TYPE(val) ((val) & 0xff)
|
||||
#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
|
||||
|
||||
/* SH relocs. */
|
||||
#define R_SH_NONE 0
|
||||
#define R_SH_DIR32 1
|
||||
#define R_SH_REL32 2
|
||||
#define R_SH_DIR8WPN 3
|
||||
#define R_SH_IND12W 4
|
||||
#define R_SH_DIR8WPL 5
|
||||
#define R_SH_DIR8WPZ 6
|
||||
#define R_SH_DIR8BP 7
|
||||
#define R_SH_DIR8W 8
|
||||
#define R_SH_DIR8L 9
|
||||
#define R_SH_SWITCH16 25
|
||||
#define R_SH_SWITCH32 26
|
||||
#define R_SH_USES 27
|
||||
#define R_SH_COUNT 28
|
||||
#define R_SH_ALIGN 29
|
||||
#define R_SH_CODE 30
|
||||
#define R_SH_DATA 31
|
||||
#define R_SH_LABEL 32
|
||||
#define R_SH_SWITCH8 33
|
||||
#define R_SH_GNU_VTINHERIT 34
|
||||
#define R_SH_GNU_VTENTRY 35
|
||||
#define R_SH_TLS_GD_32 144
|
||||
#define R_SH_TLS_LD_32 145
|
||||
#define R_SH_TLS_LDO_32 146
|
||||
#define R_SH_TLS_IE_32 147
|
||||
#define R_SH_TLS_LE_32 148
|
||||
#define R_SH_TLS_DTPMOD32 149
|
||||
#define R_SH_TLS_DTPOFF32 150
|
||||
#define R_SH_TLS_TPOFF32 151
|
||||
#define R_SH_GOT32 160
|
||||
#define R_SH_PLT32 161
|
||||
#define R_SH_COPY 162
|
||||
#define R_SH_GLOB_DAT 163
|
||||
#define R_SH_JMP_SLOT 164
|
||||
#define R_SH_RELATIVE 165
|
||||
#define R_SH_GOTOFF 166
|
||||
#define R_SH_GOTPC 167
|
||||
/* Keep this the last entry. */
|
||||
#define R_SH_NUM 256
|
||||
|
||||
|
||||
/* Symbol table entry. */
|
||||
|
||||
typedef struct {
|
||||
|
@ -129,7 +185,7 @@ typedef struct {
|
|||
//---
|
||||
|
||||
/* kernel loading information */
|
||||
struct kernel_info {
|
||||
struct kernel {
|
||||
/* kernel entry */
|
||||
uintptr_t entry;
|
||||
|
||||
|
@ -147,6 +203,24 @@ struct kernel_info {
|
|||
|
||||
/* hardware information */
|
||||
struct hwinfo hardware;
|
||||
|
||||
/* file information */
|
||||
struct smemfs_inode const *inode;
|
||||
|
||||
/* ELF information */
|
||||
struct {
|
||||
Elf32_Ehdr hdr;
|
||||
Elf32_Shdr *shdr;
|
||||
Elf32_Phdr *phdr;
|
||||
struct {
|
||||
Elf32_Sym *tab;
|
||||
int nb;
|
||||
} sym;
|
||||
char * shstrtab;
|
||||
char * strtab;
|
||||
uintptr_t * got;
|
||||
int got_nb;
|
||||
} elf;
|
||||
};
|
||||
|
||||
/* internal kernel image list */
|
||||
|
@ -174,8 +248,6 @@ extern int loader_kernel_img_count(void);
|
|||
#define LOADER_CHECK 4
|
||||
extern int loader(struct smemfs_inode const * restrict const inode, int mode);
|
||||
|
||||
/* loader_info() : display ELF PIE file information */
|
||||
extern int loader_info(struct smemfs_inode const * inode, Elf32_Ehdr *header);
|
||||
|
||||
//---
|
||||
// Error ldpers
|
||||
|
@ -207,10 +279,13 @@ enum {
|
|||
/* loader_header_get() : get / check ELF header information */
|
||||
extern int loader_header_get(
|
||||
struct smemfs_inode const * restrict const inode,
|
||||
Elf32_Ehdr *hdr
|
||||
Elf32_Ehdr *header
|
||||
);
|
||||
|
||||
/* loader_header_check() : load and check the file header validity */
|
||||
extern int loader_header_check(struct smemfs_inode * restrict const inode);
|
||||
extern int loader_header_check(struct kernel * const kernel);
|
||||
|
||||
/* loader_header_error() : display error message */
|
||||
extern int loader_header_error(int errnum);
|
||||
|
||||
|
||||
|
@ -219,6 +294,8 @@ extern int loader_header_error(int errnum);
|
|||
//---
|
||||
// ELF image ldpers
|
||||
//---
|
||||
|
||||
/* returned value */
|
||||
enum {
|
||||
ld_image_success = 0,
|
||||
ld_image_size_error = -1,
|
||||
|
@ -226,28 +303,25 @@ enum {
|
|||
ld_image_mem_error = -3,
|
||||
ld_image_mem_not_available = -4,
|
||||
};
|
||||
|
||||
/* loader_image_load() : try to load the entier image data */
|
||||
extern int loader_image_load(
|
||||
struct smemfs_inode const * restrict const inode,
|
||||
struct kernel_info * restrict const info,
|
||||
Elf32_Ehdr *hdr
|
||||
);
|
||||
extern int loader_image_load(struct kernel * const kernel);
|
||||
|
||||
/* loader_image_error() : Display error message */
|
||||
extern int loader_image_error(int const errnum);
|
||||
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// GOT helpers
|
||||
// Relocs helpers
|
||||
//---
|
||||
|
||||
/* loader_got_patch() : Try to patch the GOT section */
|
||||
extern int loader_got_patch(
|
||||
struct smemfs_inode const * restrict const inode,
|
||||
struct kernel_info * const kernel,
|
||||
Elf32_Ehdr *hdr
|
||||
);
|
||||
extern int loader_got_patch(struct kernel * const kernel);
|
||||
|
||||
/* loader_rela_patch() : Try to patch the RELA section */
|
||||
extern int loader_rela_patch(struct kernel * const kernel);
|
||||
|
||||
|
||||
#endif /*__VXBOOT_LOADER_H__*/
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
/* internal terminal hardcoded information */
|
||||
|
@ -63,8 +64,21 @@ extern struct terminal terminal;
|
|||
//---
|
||||
// User interface
|
||||
//---
|
||||
enum {
|
||||
LOG_EMERG,
|
||||
LOG_ALERT,
|
||||
LOG_CRIT,
|
||||
LOG_ERR,
|
||||
LOG_WARNING,
|
||||
LOG_NOTICE,
|
||||
LOG_INFO,
|
||||
LOG_DEBUG
|
||||
};
|
||||
|
||||
extern int terminal_open(void);
|
||||
extern int terminal_write(const char *format, ...);
|
||||
extern int terminal_vwrite(const char *format, va_list ap);
|
||||
extern int terminal_log(int level, const char *format, ...);
|
||||
extern int terminal_read(void *buffer, size_t nb);
|
||||
extern int terminal_close(void);
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
#include "vxBoot/builtin.h"
|
||||
#include "vxBoot/terminal.h"
|
||||
|
||||
/* current log level */
|
||||
extern int user_log_level;
|
||||
|
||||
/* log_help() : display help message */
|
||||
static int log_help(void)
|
||||
{
|
||||
terminal_write(
|
||||
"+---+-----------+---------------------+\n"
|
||||
"|Lvl|Name |Description |\n"
|
||||
"| 0 |LOG_EMERG |system is unusable |\n"
|
||||
"| 1 |LOG_ALERT |action must be taken |\n"
|
||||
"| 2 |LOG_CRIT |critical condition |\n"
|
||||
"| 3 |LOG_ERR |error condition |\n"
|
||||
"| 4 |LOG_WARNING|warning condition |\n"
|
||||
"| 5 |LOG_NOTICE |significant condition|\n"
|
||||
"| 6 |LOG_INFO |informational message|\n"
|
||||
"| 7 |LOG_DEBUG |debug-level message |\n"
|
||||
"\n"
|
||||
"current level = %d\n",
|
||||
user_log_level
|
||||
);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* ls_main() : entry of the "ls" builtin */
|
||||
int log_main(int argc, char **argv)
|
||||
{
|
||||
if (argc <= 1)
|
||||
return (log_help());
|
||||
if (argv[1][0] < '0' || argv[1][0] > '7') {
|
||||
terminal_write("log: argument not recognized\n");
|
||||
return (-1);
|
||||
}
|
||||
user_log_level = argv[1][0] - '0';
|
||||
return (0);
|
||||
}
|
|
@ -18,7 +18,7 @@ static void ls_help(void)
|
|||
"\n"
|
||||
"DESCRIPTION\n"
|
||||
" List file information about FILEs (from the root directory only). The"
|
||||
" display is inspired from the utilitary `tree` in UNIX environment.\n"
|
||||
" display is inspired from the utilitary `tree` in UNIX environment.\n"
|
||||
"\n"
|
||||
" -h,--help\n"
|
||||
" Display this help message\n"
|
||||
|
|
|
@ -15,6 +15,7 @@ struct {
|
|||
{.name = "ld", &ld_main},
|
||||
{.name = "hw", &hw_main},
|
||||
{.name = "help", &help_main},
|
||||
{.name = "log", &log_main},
|
||||
{.name = NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,106 +1,60 @@
|
|||
#include "vxBoot/loader.h"
|
||||
#include "vxBoot/fs/smemfs.h"
|
||||
#include "vxBoot/terminal.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* loader_get_section() : Try to find section information using its name */
|
||||
static int loader_get_section(
|
||||
Elf32_Shdr *shdr,
|
||||
char const * const name,
|
||||
struct smemfs_inode const * restrict const inode,
|
||||
Elf32_Ehdr *hdr
|
||||
) {
|
||||
char buff[16];
|
||||
off_t stroff;
|
||||
off_t shoff;
|
||||
|
||||
/* find the section header table */
|
||||
shoff = hdr->e_shoff;
|
||||
|
||||
/* find the section string table ".strtable" */
|
||||
smemfs_pread(
|
||||
inode,
|
||||
shdr, sizeof(Elf32_Shdr),
|
||||
shoff + (sizeof(Elf32_Shdr) * hdr->e_shstrndx)
|
||||
);
|
||||
stroff = shdr->sh_offset;
|
||||
|
||||
/* walk throught each section and find the .got section */
|
||||
for (int i = 0; i < hdr->e_shnum; ++i) {
|
||||
smemfs_pread(inode, shdr, sizeof(Elf32_Shdr), shoff);
|
||||
smemfs_pread(inode, buff, 16, shdr->sh_name + stroff);
|
||||
if (strcmp(buff, name) == 0)
|
||||
return (0);
|
||||
shoff += sizeof(Elf32_Shdr);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* loader_get_symbols() : get symbols information */
|
||||
static int loader_get_symbol(
|
||||
Elf32_Sym *sym,
|
||||
char const * const name,
|
||||
struct smemfs_inode const * restrict const inode,
|
||||
Elf32_Ehdr *hdr
|
||||
){
|
||||
Elf32_Shdr symhdr;
|
||||
Elf32_Shdr strhdr;
|
||||
char buff[64];
|
||||
int off;
|
||||
static void *loader_get_symbol(
|
||||
struct kernel * restrict const kernel,
|
||||
char const * restrict const name
|
||||
) {
|
||||
char * strtab;
|
||||
uintptr_t sym;
|
||||
|
||||
/* frist, find the symtab section */
|
||||
loader_get_section(&symhdr, ".symtab", inode, hdr);
|
||||
loader_get_section(&strhdr, ".strtab", inode, hdr);
|
||||
|
||||
/* walk throut the table */
|
||||
off = symhdr.sh_offset;
|
||||
for (uint32_t i = 0 ; i < symhdr.sh_size / sizeof(Elf32_Sym) ; ++i) {
|
||||
smemfs_pread(inode, sym, sizeof(Elf32_Sym), off);
|
||||
smemfs_pread(inode, buff, 64, sym->st_name + strhdr.sh_offset);
|
||||
if (strcmp(buff, name) == 0)
|
||||
return (0);
|
||||
off += sizeof(Elf32_Sym);
|
||||
strtab = kernel->elf.strtab;
|
||||
for (int i = 0 ; i < kernel->elf.sym.nb ; ++i) {
|
||||
if (strcmp(&strtab[kernel->elf.sym.tab[i].st_name], name) != 0)
|
||||
continue;
|
||||
sym = (uintptr_t)kernel->elf.sym.tab[i].st_value;
|
||||
sym += (uintptr_t)kernel->hardware.ram.physical.kernel_addr;
|
||||
sym |= (uintptr_t)0xa0000000;
|
||||
return((void*)sym);
|
||||
}
|
||||
return (-1);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
/* loader_got_patch() : Try to patch the GOT/PLT section */
|
||||
int loader_got_patch(
|
||||
struct smemfs_inode const * restrict const inode,
|
||||
struct kernel_info * const kernel,
|
||||
Elf32_Ehdr *hdr
|
||||
) {
|
||||
Elf32_Shdr shdr;
|
||||
Elf32_Sym sym;
|
||||
int loader_got_patch(struct kernel * const kernel)
|
||||
{
|
||||
uintptr_t *__got__;
|
||||
uintptr_t *got;
|
||||
uintptr_t addr;
|
||||
uintptr_t got;
|
||||
|
||||
/* first, try to find the __GLOBAL_OFFSET_TABLE__ symbol */
|
||||
if (loader_get_symbol(&sym, "_GLOBAL_OFFSET_TABLE_", inode, hdr)) {
|
||||
terminal_write("_GLOBAL_OFFSET_TABLE_ not found...\n");
|
||||
/* first, try to find the _GLOBAL_OFFSET_TABLE_ symbol */
|
||||
__got__ = loader_get_symbol(kernel, "_GLOBAL_OFFSET_TABLE_");
|
||||
if (__got__ == NULL) {
|
||||
terminal_log(
|
||||
LOG_NOTICE,
|
||||
"_GLOBAL_OFFSET_TABLE_ not found...\n"
|
||||
);
|
||||
return (0);
|
||||
}
|
||||
__got__ = kernel->memory.program.start;
|
||||
__got__ = (void*)((uintptr_t)__got__ + (uintptr_t)sym.st_value);
|
||||
terminal_write(" __GOT__ found at %p...\n", __got__);
|
||||
|
||||
|
||||
/* and we need to relocalise the "real" GOT section and update the
|
||||
hardcoded address in the same time */
|
||||
loader_get_section(&shdr, ".got", inode, hdr);
|
||||
got = kernel->memory.program.start;
|
||||
got = (void*)((uintptr_t)got + (uintptr_t)shdr.sh_addr);
|
||||
terminal_write(" GOT found at %p...\n", got);
|
||||
got = (uintptr_t)kernel->elf.got;
|
||||
got += (uintptr_t)kernel->hardware.ram.physical.kernel_addr;
|
||||
got |= (uintptr_t)0xa0000000;
|
||||
|
||||
/* perform transation */
|
||||
for (uint32_t i = 0 ; i < shdr.sh_size >> 2 ; ++i) {
|
||||
terminal_write(" path symbols %p...\n", got[i]);
|
||||
addr = got[i];
|
||||
terminal_log(LOG_DEBUG, " _GOT_ found at %p...\n", __got__);
|
||||
terminal_log(LOG_DEBUG, " .got found at %p...\n", got);
|
||||
for (int i = 0 ; i < kernel->elf.got_nb ; ++i) {
|
||||
terminal_log(
|
||||
LOG_DEBUG,
|
||||
" patch symbols %p...\n",
|
||||
((uintptr_t*)got)[i]
|
||||
);
|
||||
addr = ((uintptr_t*)got)[i];
|
||||
addr += (uintptr_t)kernel->hardware.ram.physical.kernel_addr;
|
||||
addr |= (uintptr_t)0x80000000;
|
||||
__got__[i] = addr;
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#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"},
|
||||
|
@ -23,9 +26,14 @@ int loader_header_error(int const errnum)
|
|||
|
||||
/* loader_header_get(): Get ELF header and check validity */
|
||||
int loader_header_get(
|
||||
struct smemfs_inode const * restrict const inode,
|
||||
Elf32_Ehdr *header
|
||||
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);
|
||||
|
@ -60,9 +68,102 @@ int loader_header_get(
|
|||
return (ld_header_valid);
|
||||
}
|
||||
|
||||
/* hypervisor_elf_loader_header_check(): Check ELF header validity */
|
||||
int loader_header_check(struct smemfs_inode * restrict const inode)
|
||||
/* hypervisor_elf_loader_header_check():
|
||||
Check ELF header validity and dump usefull sections information */
|
||||
int loader_header_check(struct kernel * const kernel)
|
||||
{
|
||||
Elf32_Ehdr header;
|
||||
return (loader_header_get(inode, &header));
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -22,41 +22,40 @@ int loader_image_error(int const errnum)
|
|||
}
|
||||
|
||||
/* loader_load_image() - Load the program into Virtual Memory */
|
||||
int loader_image_load(
|
||||
struct smemfs_inode const * restrict const inode,
|
||||
struct kernel_info * restrict const kernel,
|
||||
Elf32_Ehdr *hdr
|
||||
) {
|
||||
Elf32_Phdr program;
|
||||
int loader_image_load(struct kernel * const kernel)
|
||||
{
|
||||
Elf32_Phdr *phdr;
|
||||
uintptr_t paddress;
|
||||
uintptr_t origin;
|
||||
uintptr_t vmin;
|
||||
uintptr_t vmax;
|
||||
off_t offset;
|
||||
uint16_t i;
|
||||
|
||||
|
||||
/* Walk one time to get the entier program size and check ELF
|
||||
validity. */
|
||||
i = -1;
|
||||
vmin = 0xffffffff;
|
||||
vmax = 0x00000000;
|
||||
phdr = kernel->elf.phdr;
|
||||
kernel->memory.program.size = 0;
|
||||
while (++i < hdr->e_phnum) {
|
||||
offset = hdr->e_phoff + (i * sizeof(Elf32_Phdr));
|
||||
if (smemfs_pread(inode, &program, sizeof(Elf32_Phdr), offset)
|
||||
!= sizeof(Elf32_Phdr)) {
|
||||
return (ld_image_size_error);
|
||||
}
|
||||
if (program.p_vaddr < vmin)
|
||||
vmin = program.p_vaddr;
|
||||
if (program.p_vaddr + program.p_memsz > vmax)
|
||||
vmax = program.p_vaddr + program.p_memsz;
|
||||
for (int i = 0; i < kernel->elf.hdr.e_phnum; ++i) {
|
||||
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);
|
||||
|
@ -72,25 +71,22 @@ int loader_image_load(
|
|||
|
||||
Note that the p_filesz can be smaller than p_memsz so, we need to
|
||||
wipe the segment area before the dump. */
|
||||
i = -1;
|
||||
while (++i < hdr->e_phnum) {
|
||||
offset = hdr->e_phoff + (i * sizeof(Elf32_Phdr));
|
||||
smemfs_pread(inode, &program, sizeof(Elf32_Phdr), offset);
|
||||
|
||||
paddress = (uintptr_t)program.p_vaddr - vmin;
|
||||
for (int i = 0; i < kernel->elf.hdr.e_phnum; ++i) {
|
||||
paddress = (uintptr_t)phdr[i].p_vaddr - vmin;
|
||||
paddress += (uintptr_t)kernel->memory.program.start;
|
||||
|
||||
memset((void*)paddress, 0x00, program.p_memsz);
|
||||
memset((void*)paddress, 0x00, phdr[i].p_memsz);
|
||||
smemfs_pread(
|
||||
inode,
|
||||
kernel->inode,
|
||||
(void*)paddress,
|
||||
program.p_filesz,
|
||||
program.p_offset
|
||||
phdr[i].p_filesz,
|
||||
phdr[i].p_offset
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/* Generate program entry address */
|
||||
kernel->entry = (uintptr_t)hdr->e_entry - vmin;
|
||||
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);
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
#include "vxBoot/loader.h"
|
||||
#include "vxBoot/fs/smemfs.h"
|
||||
#include "vxBoot/terminal.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct {
|
||||
char const * restrict const name;
|
||||
uint16_t id;
|
||||
} const table[] = {
|
||||
{"R_SH_NONE", 0},
|
||||
{"R_SH_DIR32", 1},
|
||||
{"R_SH_REL32", 2},
|
||||
{"R_SH_DIR8WPN", 3},
|
||||
{"R_SH_IND12W", 4},
|
||||
{"R_SH_DIR8WPL", 5},
|
||||
{"R_SH_DIR8WPZ", 6},
|
||||
{"R_SH_DIR8BP", 7},
|
||||
{"R_SH_DIR8W", 8},
|
||||
{"R_SH_DIR8L", 9},
|
||||
{"R_SH_SWITCH16", 25},
|
||||
{"R_SH_SWITCH32", 26},
|
||||
{"R_SH_USES", 27},
|
||||
{"R_SH_COUNT", 28},
|
||||
{"R_SH_ALIGN", 29},
|
||||
{"R_SH_CODE", 30},
|
||||
{"R_SH_DATA", 31},
|
||||
{"R_SH_LABEL", 32},
|
||||
{"R_SH_SWITCH8", 33},
|
||||
{"R_SH_GNU_VTINHERIT", 4},
|
||||
{"R_SH_GNU_VTENTRY", 5},
|
||||
{"R_SH_TLS_GD_32", 144},
|
||||
{"R_SH_TLS_LD_32", 145},
|
||||
{"R_SH_TLS_LDO_32", 146},
|
||||
{"R_SH_TLS_IE_32", 147},
|
||||
{"R_SH_TLS_LE_32", 148},
|
||||
{"R_SH_TLS_DTPMOD32", 49},
|
||||
{"R_SH_TLS_DTPOFF32", 50},
|
||||
{"R_SH_TLS_TPOFF32", 51},
|
||||
{"R_SH_GOT32", 160},
|
||||
{"R_SH_PLT32", 161},
|
||||
{"R_SH_COPY", 162},
|
||||
{"R_SH_GLOB_DAT", 163},
|
||||
{"R_SH_JMP_SLOT", 164},
|
||||
{"R_SH_RELATIVE", 165},
|
||||
{"R_SH_GOTOFF", 166},
|
||||
{"R_SH_GOTPC", 167},
|
||||
{"R_SH_NUM", 256},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
/* loader_reloc_symbols() : relocalize symbols */
|
||||
static int loader_reloc_section(
|
||||
Elf32_Rela *rela,
|
||||
int nb_rela,
|
||||
char const * const name,
|
||||
struct kernel * const kernel
|
||||
) {
|
||||
uintptr_t voff;
|
||||
uintptr_t val;
|
||||
uintptr_t loc;
|
||||
int type;
|
||||
|
||||
/* logs */
|
||||
terminal_log(
|
||||
LOG_INFO,
|
||||
" section '%s' with %d entries\n",
|
||||
name, nb_rela
|
||||
);
|
||||
|
||||
/* precalculate relocalisation operation */
|
||||
voff = (uintptr_t)kernel->hardware.ram.physical.kernel_addr;
|
||||
voff |= (uintptr_t)0x80000000;
|
||||
|
||||
/* try to relocalise symbols */
|
||||
for (int i = 0; i < nb_rela; ++i) {
|
||||
type = -1;
|
||||
for (int j = 0; table[j].name != NULL; ++j) {
|
||||
if (table[j].id != ELF32_R_TYPE(rela[i].r_info))
|
||||
continue;
|
||||
if (ELF32_R_TYPE(rela[i].r_info) == R_SH_NUM)
|
||||
return (0);
|
||||
type = j;
|
||||
break;
|
||||
}
|
||||
if (type < 0) {
|
||||
terminal_write("unable to relocalize symbols %d\n", i);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
loc = rela[i].r_offset;
|
||||
loc += (uintptr_t)kernel->hardware.ram.physical.kernel_addr;
|
||||
loc |= (uintptr_t)0xa0000000;
|
||||
|
||||
val = kernel->elf.sym.tab[ELF32_R_SYM(rela[i].r_info)].st_value;
|
||||
|
||||
switch (table[type].id) {
|
||||
case R_SH_GOT32:
|
||||
case R_SH_PLT32:
|
||||
case R_SH_GOTPC:
|
||||
case R_SH_GOTOFF:
|
||||
break;
|
||||
case R_SH_DIR32:
|
||||
//terminal_log(
|
||||
// LOG_DEBUG,
|
||||
// " %08x %-8s %08x\n",
|
||||
// rela[i].r_offset,
|
||||
// table[type].name,
|
||||
// val
|
||||
//);
|
||||
*(uintptr_t *)loc = voff + val;
|
||||
break;
|
||||
default:
|
||||
terminal_log(
|
||||
LOG_ALERT,
|
||||
" [%d] type %s not supported yet o(x_x)o\n",
|
||||
i, table[type].name
|
||||
);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* loader_rela_patch() : Try to patch the GOT/PLT section */
|
||||
int loader_rela_patch(struct kernel * const kernel)
|
||||
{
|
||||
Elf32_Rela *rela;
|
||||
int error;
|
||||
|
||||
rela = NULL;
|
||||
for (int i = 0; i < kernel->elf.hdr.e_shnum; ++i) {
|
||||
if (kernel->elf.shdr[i].sh_type != SHT_RELA)
|
||||
continue;
|
||||
rela = realloc(rela, kernel->elf.shdr[i].sh_size);
|
||||
smemfs_pread(
|
||||
kernel->inode,
|
||||
rela,
|
||||
kernel->elf.shdr[i].sh_size,
|
||||
kernel->elf.shdr[i].sh_offset
|
||||
);
|
||||
error = loader_reloc_section(
|
||||
rela,
|
||||
kernel->elf.shdr[i].sh_size / sizeof(Elf32_Rela),
|
||||
&kernel->elf.shstrtab[kernel->elf.shdr[i].sh_name],
|
||||
kernel
|
||||
);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
return (0);
|
||||
}
|
|
@ -10,7 +10,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
static int dump_reloc(struct kernel_info *kernel)
|
||||
/* dump_reloc() : dump the relocalized image */
|
||||
static int dump_reloc(struct kernel *kernel)
|
||||
{
|
||||
int handle;
|
||||
int size;
|
||||
|
@ -30,45 +31,41 @@ static int dump_reloc(struct kernel_info *kernel)
|
|||
/* loader_inode: Load a ELF programm (PIE) */
|
||||
int loader(struct smemfs_inode const * restrict const inode, int mode)
|
||||
{
|
||||
struct kernel_info kernel;
|
||||
Elf32_Ehdr header;
|
||||
struct kernel kernel;
|
||||
int err;
|
||||
|
||||
if (inode == NULL)
|
||||
return (-1);
|
||||
|
||||
terminal_write("> try to load ELF file \"%s\"\n", inode->name);
|
||||
memset(&kernel, 0x00, sizeof(struct kernel));
|
||||
kernel.inode = inode;
|
||||
|
||||
terminal_write("> check header information...\n");
|
||||
err = loader_header_get(inode, &header);
|
||||
err = loader_header_check(&kernel);
|
||||
if (err != 0) {
|
||||
loader_header_error(err);
|
||||
return (-2);
|
||||
}
|
||||
|
||||
if (mode == LOADER_INFO)
|
||||
return loader_info(inode, &header);
|
||||
|
||||
terminal_write("> generate kernel geometry...\n");
|
||||
memset(&kernel, 0x00, sizeof(struct kernel_info));
|
||||
hardware_get_info(&kernel.hardware);
|
||||
|
||||
terminal_write("> load image...\n");
|
||||
err = loader_image_load(inode, &kernel, &header);
|
||||
err = loader_image_load(&kernel);
|
||||
if (err != 0) {
|
||||
loader_image_error(err);
|
||||
return (-3);
|
||||
}
|
||||
|
||||
terminal_write("> path the GOT table...\n");
|
||||
loader_got_patch(inode, &kernel, &header);
|
||||
//FIXME: check returned value
|
||||
terminal_write("> relocalize symbols...\n");
|
||||
loader_rela_patch(&kernel);
|
||||
|
||||
if (mode == LOADER_CHECK)
|
||||
return (0);
|
||||
terminal_write("> path the GOT table...\n");
|
||||
loader_got_patch(&kernel);
|
||||
|
||||
terminal_write("%s successfully loaded !\n", inode->name);
|
||||
if (mode == LOADER_DUMP) {
|
||||
if (mode == LOADER_DUMP || mode == LOADER_CHECK) {
|
||||
terminal_write(
|
||||
"kernel information:\n"
|
||||
"|-- kernel entry: %p\n"
|
||||
|
@ -85,6 +82,9 @@ int loader(struct smemfs_inode const * restrict const inode, int mode)
|
|||
kernel.memory.program.elf.vmin,
|
||||
kernel.memory.program.elf.vmax
|
||||
);
|
||||
if (mode == LOADER_CHECK)
|
||||
return (0);
|
||||
|
||||
gint_world_switch(GINT_CALL((void*)&dump_reloc, (void*)&kernel));
|
||||
return (0);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ static int loader_list_img(struct ldimg **image, struct smemfs_inode *inode)
|
|||
counter += loader_list_img(image, inode->child);
|
||||
goto anchor;
|
||||
}
|
||||
if (loader_header_check(inode) == ld_header_valid) {
|
||||
if (loader_header_get(inode, NULL) == ld_header_valid) {
|
||||
(*image) = calloc(1, sizeof(struct ldimg));
|
||||
if ((*image) == NULL) {
|
||||
terminal_write("hypervisor: out of memory :(\n");
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#include "vxBoot/terminal.h"
|
||||
|
||||
/* define the user log level */
|
||||
int user_log_level = LOG_INFO;
|
||||
|
||||
int terminal_log(int level, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int nb;
|
||||
|
||||
if (level > user_log_level)
|
||||
return (0);
|
||||
|
||||
va_start(ap, format);
|
||||
nb = terminal_vwrite(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (level == LOG_DEBUG) {
|
||||
int tmp;
|
||||
terminal_read(&tmp, 4);
|
||||
}
|
||||
|
||||
return (nb);
|
||||
}
|
|
@ -6,17 +6,14 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* terminal_write() - printf wrapper for the terminal device */
|
||||
int terminal_write(const char *format, ...)
|
||||
/* terminal_vwrite() : printf wrapper for the terminal device with va_list */
|
||||
int terminal_vwrite(const char *format, va_list ap)
|
||||
{
|
||||
char buffer[1024];
|
||||
va_list ap;
|
||||
int nb;
|
||||
|
||||
/* process the format */
|
||||
va_start(ap, format);
|
||||
nb = vsnprintf(buffer, 1024, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* update the internal buffer */
|
||||
terminal_buffer_insert(buffer, nb);
|
||||
|
@ -27,3 +24,16 @@ int terminal_write(const char *format, ...)
|
|||
dupdate();
|
||||
return (nb);
|
||||
}
|
||||
|
||||
/* terminal_write() - printf wrapper for the terminal device */
|
||||
int terminal_write(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int nb;
|
||||
|
||||
va_start(ap, format);
|
||||
nb = terminal_vwrite(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return (nb);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue