CeDOS - Commit 03e50236

Implemented execution of ELF executables
Celina Kalus
Thu, 02 Mar 2023 12:18:24 +0100
10 files changed, 230 insertions(+), 64 deletions(-)
A include/cedos/elf.h

@@ -0,0 +1,12 @@

+#ifndef ELF_H +#define ELF_H + +#include "cedos/sched/sched.h" +#include "cedos/sched/process.h" + +/*! + * Executes an elf file from memory + */ +PROCESS_ID elf_exec(VIRT_ADDR elf_pointer, uint32_t size, char *name); + +#endif
M include/cedos/mm/paging.hinclude/cedos/mm/paging.h

@@ -25,16 +25,16 @@ typedef uint32_t PAGE_TABLE_ENTRY;

/*! * Sets cr3 to new page directory and returns the old one. - * \param page_dir Address of new page directory that is supposed to be used. + * \param pd_new Address of new page directory that is supposed to be used. * \return Address of old page directory. */ -__attribute__((always_inline)) inline PHYS_ADDR switch_page_dir(PHYS_ADDR page_dir) { - uint32_t res; +__attribute__((always_inline)) inline PHYS_ADDR switch_page_dir(PHYS_ADDR pd_new) { + uint32_t pd_old; __asm__ volatile ( "mov %%cr3, %0\n" "mov %1, %%cr3" : - "=a" (res) : - "Nd" (page_dir)); - return (void*)res; + "=a" (pd_old) : + "Nd" (pd_new)); + return (void*)pd_old; } /*!
M include/linker.hinclude/linker.h

@@ -18,6 +18,10 @@ extern uint8_t __APP_VMA;

extern uint8_t __APP_LMA; extern uint8_t __APP_SIZE; +extern uint8_t __ELF_VMA; +extern uint8_t __ELF_LMA; +extern uint8_t __ELF_SIZE; + #define SS_VMA (&__SS_VMA) #define SS_LMA (&__SS_LMA) #define SS_SIZE (uint32_t)(&__SS_SIZE)

@@ -29,5 +33,9 @@

#define APP_VMA (&__APP_VMA) #define APP_LMA (&__APP_LMA) #define APP_SIZE (uint32_t)(&__APP_SIZE) + +#define ELF_VMA (&__ELF_VMA) +#define ELF_LMA (&__ELF_LMA) +#define ELF_SIZE (uint32_t)(&__ELF_SIZE) #endif
M link.txtlink.txt

@@ -37,7 +37,12 @@ {

*/apps.o(.*) } >APPLICATION_VMA - .bss : AT(LOADADDR(APPLICATION) + SIZEOF(APPLICATION)) + ELF : AT(LOADADDR(APPLICATION) + SIZEOF(APPLICATION)) + { + */apps_raw.o(.*) + } >APPLICATION_VMA + + .bss : AT(LOADADDR(ELF) + SIZEOF(ELF)) { } >KERNEL_VMA

@@ -57,6 +62,10 @@ __APP_LMA = LOADADDR(APPLICATION);

__APP_VMA = ADDR(APPLICATION); __APP_SIZE = SIZEOF(APPLICATION); +__ELF_LMA = LOADADDR(ELF); +__ELF_VMA = ADDR(ELF); +__ELF_SIZE = SIZEOF(ELF); + __KERNEL_STACK_ADDR = 0xC0400000; -ASSERT(__SS_SIZE + __KERNEL_SIZE + __APP_SIZE <= 0x48 * 0x200, "bootloader payload too big!"); +ASSERT(__SS_SIZE + __KERNEL_SIZE + __APP_SIZE + __ELF_SIZE <= 0x48 * 0x200, "bootloader payload too big!");
M makefilemakefile

@@ -52,7 +52,7 @@ export CCFLAGS

export GLOBAL_BUILD MODULES := stage1 stage2 kernel apps -OBJECTS := $(patsubst %,$(LOCAL_BUILD)/%.o,$(MODULES)) +OBJECTS := $(patsubst %,$(LOCAL_BUILD)/%.o,$(MODULES)) $(LOCAL_BUILD)/apps_raw.o DIRS := $(LOCAL_BUILD) $(MODULES): | $(DIRS)

@@ -63,10 +63,10 @@ .PHONY: build

build: $(GLOBAL_BUILD)/base.img $(GLOBAL_BUILD)/base.o $(GLOBAL_BUILD)/base.o: $(MODULES) -> $(LD) $(OBJECTS) -r -T link.txt -Map=$(LOG_DIR)/mapfile.txt --oformat elf32-i386 -o $@ +> $(LD) $(OBJECTS) -r -T link.txt -Map=$(LOG_DIR)/elf_mapfile.txt --oformat elf32-i386 -o $@ $(GLOBAL_BUILD)/base.img: $(MODULES) -> $(LD) $(OBJECTS) -T link.txt -Map=$(LOG_DIR)/mapfile.txt --oformat binary --nostdlib -o $@ +> $(LD) $(OBJECTS) -T link.txt -Map=$(LOG_DIR)/bin_mapfile.txt --oformat binary --nostdlib -o $@ .PHONY: logs logs: $(LOG_DIR)/base.sym $(LOG_DIR)/objdump.txt
M src/apps/makefilesrc/apps/makefile

@@ -20,7 +20,9 @@

.PHONY: build build: $(GLOBAL_BUILD)/apps.o $(GLOBAL_BUILD)/apps.o: $(OBJECTS) -> $(LD) -T link.txt -r $^ -o $@ --oformat elf32-i386 +> $(LD) -T link.txt $^ -o $(GLOBAL_BUILD)/apps.o --oformat elf32-i386 +> $(OBJCOPY) -I binary -O elf32-i386 $(GLOBAL_BUILD)/apps.o $(GLOBAL_BUILD)/apps_raw.o +> $(LD) -T link.txt -r $^ -o $(GLOBAL_BUILD)/apps.o --oformat elf32-i386 $(LOCAL_BUILD)/%.s.o: %.s
M src/apps/start.csrc/apps/start.c

@@ -5,8 +5,8 @@

extern void fib(void); int start(void) { - uint32_t eip, esp, ebp; - __asm__ volatile ("call jump; jump: pop %0; mov %%esp, %1; mov %%ebp, %2" : "=m" (eip), "=m" (esp), "=m" (ebp)); + //uint32_t eip, esp, ebp; + //__asm__ volatile ("call jump; jump: pop %0; mov %%esp, %1; mov %%ebp, %2" : "=m" (eip), "=m" (esp), "=m" (ebp)); fib();
A src/kernel/elf.c

@@ -0,0 +1,180 @@

+#include <stdint.h> +#include "cedos/elf.h" +#include "cedos/core.h" + +#include "assert.h" + +typedef struct { + uint8_t e_ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uint32_t entry; + uint32_t proghead_offset; + uint32_t secthead_offset; + uint32_t flags; + uint16_t header_size; + uint16_t ph_entry_size; + uint16_t ph_num; + uint16_t sh_entry_size; + uint16_t sh_num; + uint16_t sh_strndx; +} ELF_HEADER; + +typedef struct { + uint32_t type; + uint32_t offset; + VIRT_ADDR virt_addr; + PHYS_ADDR phys_addr; + uint32_t filesize; + uint32_t memsize; + uint32_t flags; + uint32_t align; +} PROG_HEADER; + +typedef enum { + SHF_WRITE = 0x01, + SHF_ALLOC = 0x02, + SHF_EXECINSTR = 0x04 +} SH_FLAGS; + +typedef struct { + uint32_t name; + uint32_t type; + union { + SH_FLAGS flags; + uint32_t value; + }; + VIRT_ADDR addr; + uint32_t offset; + uint32_t size; + uint32_t link; + uint32_t info; + uint32_t addr_align; + uint32_t entsize; +} SECT_HEADER; + +void elf_infodump(VIRT_ADDR elf_pointer, uint32_t size) { + ELF_HEADER *header = (ELF_HEADER*)elf_pointer; + + printk("Reading ELF file from location %p of length %i\n", elf_pointer, size); + printk("\n"); + + printk("ELF header size: %i\n", sizeof(ELF_HEADER)); + assert(sizeof(ELF_HEADER) == 52); + printk("\n"); + + printk("ELF header hexdump:\n"); + memdump(elf_pointer, 52); + printk("\n"); + + printk("ELF header magic number:\n"); + printk("%s\n", &(header->e_ident)); + printk("\n"); + + printk("ELF header infodump:\n"); + printk("- machine: %i\n", header->machine); + printk("- version: %i\n", header->version); + printk("- entry: %p\n", header->entry); + printk("\n"); + printk("- program headers:\n"); + printk(" - offset: %i\n", header->proghead_offset); + printk(" - entries: %i\n", header->ph_num); + printk(" - entry size: %i\n", header->ph_entry_size); + printk("\n"); + printk("- section headers:\n"); + printk(" - offset: %i\n", header->secthead_offset); + printk(" - entries: %i\n", header->sh_num); + printk(" - entry size: %i\n", header->sh_entry_size); + printk("\n"); + + printk("Enumerating sections:\n"); + + int sh_offset = header->secthead_offset; + SECT_HEADER *sect_headers = (SECT_HEADER*)(elf_pointer + sh_offset); + + int num_sections = header->sh_num; + int section_size = header->sh_entry_size; + + SECT_HEADER sect_names_sh = sect_headers[header->sh_strndx]; + VIRT_ADDR sect_names_addr = elf_pointer + sect_names_sh.offset; + + assert(sizeof(SECT_HEADER) == section_size); + + for (int i = 0; i < num_sections; i++) { + SECT_HEADER sh = sect_headers[i]; + char *name = (char*)(sect_names_addr + sh.name); + + printk("Section: %s\n", name); + printk("- type: %i\n", sh.type); + printk("- offset: %i\n", sh.offset); + printk("- size: %i\n", sh.size); + printk("- addr: %i\n", sh.addr); + printk("- addr_align: %i\n", sh.addr_align); + printk("\n"); + } +} + +PROCESS_ID elf_exec(VIRT_ADDR elf_pointer, uint32_t size, char *name) { + printk("Creating process %s...", name); + PROCESS_ID pid = sched_create(name); + printk("done, PID: %i.\n", pid); + + ELF_HEADER *header = (ELF_HEADER*)elf_pointer; + + // magic number correct + assert(((uint32_t*)(elf_pointer))[0] == 0x464C457F); + + // header size correct + assert(sizeof(ELF_HEADER) == 52); + + // get section table + int sh_offset = header->secthead_offset; + SECT_HEADER *sect_headers = (SECT_HEADER*)(elf_pointer + sh_offset); + + int num_sections = header->sh_num; + int section_size = header->sh_entry_size; + + SECT_HEADER sect_names_sh = sect_headers[header->sh_strndx]; + VIRT_ADDR sect_names_addr = elf_pointer + sect_names_sh.offset; + + assert(sizeof(SECT_HEADER) == section_size); + + // go through all sections and copy/allocate memory as necessary + printk("Enumerating %i sections:\n", num_sections); + for (int i = 0; i < num_sections; i++) { + SECT_HEADER sh = sect_headers[i]; + char *name = (char*)(sect_names_addr + sh.name); + + if ((sh.flags & SHF_ALLOC) && (sh.flags & SHF_EXECINSTR)) { + VIRT_ADDR lma = elf_pointer + sh.offset; + VIRT_ADDR vma = sh.addr; + uint32_t size = sh.size; + printk("%p\n", sh.flags); + printk("Copying code section %s to its destination ", name); + printk("(LMA: %p, VMA: %p)\n", lma, vma); + + sched_copyto(pid, lma, size, vma); + } else if (sh.flags & SHF_ALLOC) { + VIRT_ADDR lma = elf_pointer + sh.offset; + VIRT_ADDR vma = sh.addr; + printk("Allocating space for section %s ", name); + printk("(LMA: %p, VMA: %p)\n", lma, vma); + + /* TODO: alloc */ + } else { + printk("Skipping section %s\n", name); + } + } + + printk("\n"); + + printk("Entry point: %p\n", header->entry); + printk("Starting process %i...", pid); + + sched_exec(pid, header->entry); + + printk("done.\n"); + + return 0; +}
M src/kernel/main.csrc/kernel/main.c

@@ -12,6 +12,8 @@ #include "cedos/pic.h"

#include "cedos/pit.h" #include "cedos/core.h" +#include "cedos/elf.h" + #include "linker.h" #include "assert.h"

@@ -135,12 +137,9 @@

// create test tasks printk("Creating tasks.\n"); - PROCESS_ID sysinit; - sysinit = sched_create("sysinit"); - sched_copyto(sysinit, SS_VMA + (APP_LMA - SS_LMA), APP_SIZE, (VIRT_ADDR)0x10000000); - sched_exec(sysinit, APP_VMA); - //sched_exec(SS_VMA + (APP_LMA - SS_LMA), APP_SIZE, APP_VMA, "sysinit"); - + printk("Loading ELF executable.\n"); + elf_exec(SS_VMA + (ELF_LMA - SS_LMA), ELF_SIZE, "my_apps"); + printk("Starting scheduler.\n"); sched_start();
M src/kernel/sched/sched.csrc/kernel/sched/sched.c

@@ -114,50 +114,6 @@

crit_exit(); } -/*! - * Executes a task. - */ -PROCESS_ID sched_exec_legacy(VIRT_ADDR code, uint32_t code_len, PROCESS_MAIN *entry, const char *name) { - crit_enter(); - - PHYS_ADDR page_dir = create_empty_page_dir(); - - // copy app code - copy_to_pdir(code, code_len, page_dir, (VIRT_ADDR)0x10000000); - - // set process context - PROCESS *p = get_slot(); - p->name = name; - p->page_dir = page_dir; - p->eip = sched_dispatcher; - p->ebp = USER_STACK; - p->esp = USER_STACK - sizeof(SCHED_FRAME); - p->eflags = PROCESS_STD_EFLAGS; - p->entry = entry; - p->state = PSTATE_READY; - - // setup stack - static SCHED_FRAME frame; - frame.eax = frame.ebx = frame.ecx = frame.edx = 0; - frame.esi = frame.edi = 0; - frame.ebp = p->ebp; - frame.esp = p->esp; - frame.eflags = p->eflags; - frame.eip = sched_dispatcher; - frame.cs = 0x8; - - // load stack - copy_to_pdir(&frame, sizeof(frame), p->page_dir, p->esp); - - // save stack checksum - stack_compute_checksum(&(p->checksum), &frame, &(&frame)[1]); - - PROCESS_ID pid = add_process(p, current_pid); - //printk("Executing task %i...\n", pid); - - crit_exit(); - return pid; -} void sched_interrupt_c(SCHED_FRAME * volatile frame, uint32_t volatile ebp) { //kpanic("SCHEDULER STACK INFO");