From b4f6fd74e9b49e74cc31ef841f4725064181076b Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Sat, 29 Jan 2022 20:45:35 +0100 Subject: [PATCH] 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 --- CMakeLists.txt | 5 +- include/vxBoot/builtin.h | 1 + include/vxBoot/loader.h | 106 ++++++++++++++++++++++---- include/vxBoot/terminal.h | 14 ++++ src/builtin/log.c | 40 ++++++++++ src/builtin/ls.c | 2 +- src/cli/entry.c | 1 + src/loader/elf/got.c | 120 +++++++++-------------------- src/loader/elf/header.c | 113 ++++++++++++++++++++++++++-- src/loader/elf/image.c | 58 +++++++------- src/loader/elf/rela.c | 154 ++++++++++++++++++++++++++++++++++++++ src/loader/entry.c | 30 ++++---- src/loader/scan.c | 2 +- src/terminal/log.c | 24 ++++++ src/terminal/write.c | 20 +++-- 15 files changed, 531 insertions(+), 159 deletions(-) create mode 100644 src/builtin/log.c create mode 100644 src/loader/elf/rela.c create mode 100644 src/terminal/log.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 85f7b5d..b376d3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/include/vxBoot/builtin.h b/include/vxBoot/builtin.h index 34b9073..d5ed7c8 100644 --- a/include/vxBoot/builtin.h +++ b/include/vxBoot/builtin.h @@ -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__*/ diff --git a/include/vxBoot/loader.h b/include/vxBoot/loader.h index 583f56e..7ed5490 100644 --- a/include/vxBoot/loader.h +++ b/include/vxBoot/loader.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__*/ diff --git a/include/vxBoot/terminal.h b/include/vxBoot/terminal.h index 49c6a1d..b787b32 100644 --- a/include/vxBoot/terminal.h +++ b/include/vxBoot/terminal.h @@ -3,6 +3,7 @@ #include #include +#include #include /* 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); diff --git a/src/builtin/log.c b/src/builtin/log.c new file mode 100644 index 0000000..d58188e --- /dev/null +++ b/src/builtin/log.c @@ -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); +} diff --git a/src/builtin/ls.c b/src/builtin/ls.c index 903b9c3..ddc04d8 100644 --- a/src/builtin/ls.c +++ b/src/builtin/ls.c @@ -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" diff --git a/src/cli/entry.c b/src/cli/entry.c index 45af8bf..c01c318 100644 --- a/src/cli/entry.c +++ b/src/cli/entry.c @@ -15,6 +15,7 @@ struct { {.name = "ld", &ld_main}, {.name = "hw", &hw_main}, {.name = "help", &help_main}, + {.name = "log", &log_main}, {.name = NULL, NULL} }; diff --git a/src/loader/elf/got.c b/src/loader/elf/got.c index 1a765b1..5e3132c 100644 --- a/src/loader/elf/got.c +++ b/src/loader/elf/got.c @@ -1,106 +1,60 @@ #include "vxBoot/loader.h" -#include "vxBoot/fs/smemfs.h" #include "vxBoot/terminal.h" #include - -/* 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; diff --git a/src/loader/elf/header.c b/src/loader/elf/header.c index cb5ee68..da8f6c6 100644 --- a/src/loader/elf/header.c +++ b/src/loader/elf/header.c @@ -2,6 +2,9 @@ #include "vxBoot/fs/smemfs.h" #include "vxBoot/loader.h" +#include +#include + /* 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); } diff --git a/src/loader/elf/image.c b/src/loader/elf/image.c index 870237c..cf5ff82 100644 --- a/src/loader/elf/image.c +++ b/src/loader/elf/image.c @@ -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); diff --git a/src/loader/elf/rela.c b/src/loader/elf/rela.c new file mode 100644 index 0000000..0a8fa6b --- /dev/null +++ b/src/loader/elf/rela.c @@ -0,0 +1,154 @@ +#include "vxBoot/loader.h" +#include "vxBoot/fs/smemfs.h" +#include "vxBoot/terminal.h" + +#include +#include + +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); +} diff --git a/src/loader/entry.c b/src/loader/entry.c index 43e249c..658d411 100644 --- a/src/loader/entry.c +++ b/src/loader/entry.c @@ -10,7 +10,8 @@ #include -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); } diff --git a/src/loader/scan.c b/src/loader/scan.c index bc19006..b897546 100644 --- a/src/loader/scan.c +++ b/src/loader/scan.c @@ -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"); diff --git a/src/terminal/log.c b/src/terminal/log.c new file mode 100644 index 0000000..c16dfe4 --- /dev/null +++ b/src/terminal/log.c @@ -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); +} diff --git a/src/terminal/write.c b/src/terminal/write.c index 6cb8f9b..643a782 100644 --- a/src/terminal/write.c +++ b/src/terminal/write.c @@ -6,17 +6,14 @@ #include #include -/* 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); +}