From 8a9208612eec8ddae4c418485d848ecfa0613699 Mon Sep 17 00:00:00 2001 From: Anton Kling Date: Mon, 30 Oct 2023 22:12:14 +0100 Subject: Meta: Move kernel and userland to their own folders. This is to allow both the kernel and the userland to share certain header files and to make the folder structure a bit more clear. --- kernel/elf.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 kernel/elf.c (limited to 'kernel/elf.c') diff --git a/kernel/elf.c b/kernel/elf.c new file mode 100644 index 0000000..7316a0c --- /dev/null +++ b/kernel/elf.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include + +void *load_elf_file(const char *f, uint32_t *ds) { + // ELFHeader *header = kmalloc(sizeof(ELFHeader)); + ELFHeader header; + int fd = vfs_open(f, O_RDONLY, 0); + if (fd < 0) { + return NULL; + } + + if (sizeof(header) != vfs_pread(fd, &header, sizeof(header), 0)) { + return NULL; + } + + if (0 != memcmp(header.e_ident, "\x7F\x45\x4C\x46" /* "\x7FELF" */, 4)) { + klog("Incorrect ELF signature", LOG_ERROR); + return NULL; + } + + if (0 > fd) { + return NULL; + } + Elf32_Phdr program_header; + assert(sizeof(program_header) == header.e_phentsize); + uint32_t header_offset = header.e_phoff; + uintptr_t end_of_code = 0; + for (int i = 0; i < header.e_phnum; + i++, header_offset += header.e_phentsize) { + if (0 >= + vfs_pread(fd, &program_header, sizeof(program_header), header_offset)) { + return NULL; + } + + // FIXME: Only one type is supported, which is 1(load). More should be + // added. + assert(1 == program_header.p_type); + + // 1. Clear p_memsz bytes at p_vaddr to 0.(We also allocate frames for + // that range) + uint32_t p_memsz = program_header.p_memsz; + uint32_t p_vaddr = program_header.p_vaddr; + + uint32_t pages_to_allocate = + (uint32_t)align_page((void *)(p_vaddr + p_memsz)); + pages_to_allocate -= p_vaddr - (p_vaddr % 0x1000); + pages_to_allocate /= 0x1000; + + mmu_allocate_region((void *)p_vaddr, pages_to_allocate * 0x1000, + MMU_FLAG_RW, NULL); + + flush_tlb(); + + uintptr_t e = program_header.p_vaddr + program_header.p_memsz; + if (e > end_of_code) + end_of_code = e; + + memset((void *)program_header.p_vaddr, 0, program_header.p_memsz); + + // 2. Copy p_filesz bytes from p_offset to p_vaddr + int rc = vfs_pread(fd, (void *)program_header.p_vaddr, + program_header.p_filesz, program_header.p_offset); + + assert(rc == (int)program_header.p_filesz); + } + *ds = end_of_code; + vfs_close(fd); + return (void *)header.e_entry; +} -- cgit v1.2.3