From 261d7d37437186238d94757a8c2ce1eef5881127 Mon Sep 17 00:00:00 2001 From: Matheus Date: Sun, 14 Aug 2022 20:19:38 -0300 Subject: [PATCH] elf loading and userland --- initrd/sbin/init | Bin 4640 -> 4640 bytes src/arch/x86_64/gdt.c | 1 + src/arch/x86_64/include/arch/ist.h | 28 ++--- src/arch/x86_64/include/arch/mmu.h | 1 + src/arch/x86_64/mmu.c | 24 ++++- src/arch/x86_64/panic.c | 8 +- src/fs/tmpfs.c | 2 +- src/include/kernel/elf.h | 1 + src/include/kernel/vmm.h | 3 +- src/sys/mm/pmm.c | 2 +- src/sys/mm/vmm.c | 37 ++++++- src/sys/sched/elf.c | 158 ++++++++++++++++++++++++++++- src/sys/sched/scheduler.c | 9 +- 13 files changed, 243 insertions(+), 31 deletions(-) diff --git a/initrd/sbin/init b/initrd/sbin/init index 0eafe29056c288d7d2931ac05315c6b39bb64d2a..b1e255e7e8d7ff5fbb5e68aa996e0abc5e68dcca 100755 GIT binary patch delta 16 YcmZ3WvOr}6vjF3ti5q1WD+n+F05f3)d;kCd delta 16 YcmZ3WvOr}6vjF42i5q1WD+n+F05fp~egFUf diff --git a/src/arch/x86_64/gdt.c b/src/arch/x86_64/gdt.c index 16d44103..836f5156 100644 --- a/src/arch/x86_64/gdt.c +++ b/src/arch/x86_64/gdt.c @@ -35,6 +35,7 @@ static void reloadgdtr(){ gdtr.offset = &arch_getcls()->gdt; gdtr.size = sizeof(gdt_t) - 1; asm("lgdt (%%rax)" : : "a"(&gdtr) : "memory"); + asm("ltr %%ax" : : "a"(0x48)); } void gdt_init(){ diff --git a/src/arch/x86_64/include/arch/ist.h b/src/arch/x86_64/include/arch/ist.h index a8f6aa45..7cb0f2f5 100644 --- a/src/arch/x86_64/include/arch/ist.h +++ b/src/arch/x86_64/include/arch/ist.h @@ -4,20 +4,22 @@ #include typedef struct{ - uint32_t IOPB; - uint64_t reserved3; - uint64_t ist7; - uint64_t ist6; - uint64_t ist5; - uint64_t ist4; - uint64_t ist3; - uint64_t ist2; - uint64_t ist1; - uint64_t reserved2; - uint64_t rsp2; - uint64_t rsp1; + uint32_t reserved; uint64_t rsp0; - uint64_t reserved; + uint64_t rsp1; + uint64_t rsp2; + uint32_t reserved2; + uint64_t ist1; + uint64_t ist2; + uint64_t ist3; + uint64_t ist4; + uint64_t ist5; + uint64_t ist6; + uint64_t ist7; + uint32_t reserved3; + uint32_t reserved4; + uint32_t reserved5; + uint32_t IOPB; } __attribute((packed)) ist_t; #endif diff --git a/src/arch/x86_64/include/arch/mmu.h b/src/arch/x86_64/include/arch/mmu.h index 5cb2a2e6..0e0ba80d 100644 --- a/src/arch/x86_64/include/arch/mmu.h +++ b/src/arch/x86_64/include/arch/mmu.h @@ -24,5 +24,6 @@ void arch_mmu_init(); void arch_mmu_apinit(); arch_mmu_tableptr arch_mmu_newcontext(); void arch_mmu_switchcontext(arch_mmu_tableptr); +void arch_mmu_changeflags(arch_mmu_tableptr context, void* addr, size_t flags, size_t count); #endif diff --git a/src/arch/x86_64/mmu.c b/src/arch/x86_64/mmu.c index d97f08d6..42b891da 100644 --- a/src/arch/x86_64/mmu.c +++ b/src/arch/x86_64/mmu.c @@ -114,11 +114,13 @@ static uint64_t getmapping(arch_mmu_tableptr context, void* vaddr){ size_t pd = (addr >> 30) & 0b111111111; size_t pt = (addr >> 21) & 0b111111111; size_t page = (addr >> 12) & 0b111111111; + + uint64_t* table = next(context, pdpt); + + if(!table) return 0; + + table = next(table, pd); - if(!context[pdpt]) return 0; - - uint64_t* table = next(context, pd); - if(!table) return 0; table = next(table, pt); @@ -142,6 +144,20 @@ bool arch_mmu_isaccessed(arch_mmu_tableptr context, void* addr){ return (getmapping(context, addr) & ARCH_MMU_MAP_ACCESSED) != 0; } +void arch_mmu_changeflags(arch_mmu_tableptr context, void* addr, size_t flags, size_t count){ + for(size_t i = 0; i < count; ++i){ + uint64_t mapping = getmapping(context, addr); + if(!mapping) + continue; + mapping &= ~(0xFFF); // get addr + mapping &= ~ARCH_MMU_MAP_NOEXEC; + mapping |= flags; + setpage(context, addr, mapping); + addr += PAGE_SIZE; + } + +} + int arch_mmu_map(arch_mmu_tableptr context, void* paddr, void* vaddr, size_t flags){ uint64_t entry; changeentry(&entry, paddr, flags); diff --git a/src/arch/x86_64/panic.c b/src/arch/x86_64/panic.c index 99fef7ce..01de8224 100644 --- a/src/arch/x86_64/panic.c +++ b/src/arch/x86_64/panic.c @@ -8,7 +8,6 @@ #define TRACE_MAXDEPTH 10 static void tracestack(uint64_t** addr){ - for(size_t depth = 0; depth < TRACE_MAXDEPTH; ++depth){ uint64_t *calleeaddr = *(addr + 1); @@ -34,8 +33,11 @@ __attribute((noreturn)) void _panic(char* reason, arch_regs *reg){ ); printf("Panic location: %p\n", reg->rip); - printf("Stack trace:\n"); - tracestack((uint64_t**)reg->rbp); + + if(reg->rbp != 0){ + printf("Stack trace:\n"); + tracestack((uint64_t**)reg->rbp); + } } diff --git a/src/fs/tmpfs.c b/src/fs/tmpfs.c index 41ed3010..2ad58e42 100644 --- a/src/fs/tmpfs.c +++ b/src/fs/tmpfs.c @@ -61,7 +61,7 @@ static int tmpfs_read(int *error, vnode_t* node, void* buff, size_t count, size_ if(count > sizemax) count = sizemax; - memcpy(buff, node->fsdata, count); + memcpy(buff, node->fsdata + offset, count); return count; diff --git a/src/include/kernel/elf.h b/src/include/kernel/elf.h index 4be54914..6ef95cb4 100644 --- a/src/include/kernel/elf.h +++ b/src/include/kernel/elf.h @@ -26,6 +26,7 @@ #define ELF_FLAG_WRITABLE 2 #define ELF_FLAG_READABLE 4 +#define STACK_TOP 0x800000000000 typedef struct{ uint32_t magic; diff --git a/src/include/kernel/vmm.h b/src/include/kernel/vmm.h index ab1bac35..82c52385 100644 --- a/src/include/kernel/vmm.h +++ b/src/include/kernel/vmm.h @@ -7,7 +7,7 @@ #define KERNEL_SPACE_START 0xFFFF800000000000 #define KERNEL_SPACE_END 0xFFFFFFFFFFFFFFFF -#define USER_SPACE_START 0 +#define USER_SPACE_START 0x1000 #define USER_SPACE_END 0x00007FFFFFFFFFFF #define VMM_TYPE_FREE 0 @@ -59,5 +59,6 @@ bool vmm_unmap(void* addr, size_t pagec); bool vmm_map(void* paddr, void* vaddr, size_t pagec, size_t mmuflags); void* vmm_alloc(size_t pagec, size_t mmuflags); bool vmm_setfree(void* addr, size_t pagec); +bool vmm_allocnowat(void* addr, size_t mmuflags, size_t size); vmm_context* vmm_newcontext(); #endif diff --git a/src/sys/mm/pmm.c b/src/sys/mm/pmm.c index 8f56a96d..cd04139d 100644 --- a/src/sys/mm/pmm.c +++ b/src/sys/mm/pmm.c @@ -206,7 +206,7 @@ void pmm_init(){ if(current->length < bitmapsize || current->base < 0x100000) continue; - bitmap = (size_t*)current->base; + bitmap = (void*)current->base + (size_t)limine_hhdm_offset; break; diff --git a/src/sys/mm/vmm.c b/src/sys/mm/vmm.c index 4a93a647..00219c8c 100644 --- a/src/sys/mm/vmm.c +++ b/src/sys/mm/vmm.c @@ -150,7 +150,7 @@ static bool setmap(vmm_mapping** mapstart, void* addr, size_t pagec, size_t mmuf vmm_mapping* map = *mapstart; while(map && addr > map->end) map = map->next; - + if(!map) return false; vmm_mapping* newmap = allocatefirst(); @@ -351,7 +351,7 @@ static void getcontextinfo(void* addr, int** lock, vmm_mapping*** start){ vmm_context *context = arch_getcls()->context; *lock = &context->lock; - *start = context->userstart; + *start = &context->userstart; } @@ -435,6 +435,39 @@ bool vmm_map(void* paddr, void* vaddr, size_t pagec, size_t mmuflags){ return result; } +bool vmm_allocnowat(void* addr, size_t mmuflags, size_t size){ + int* lock; + vmm_mapping** start; + bool result = true; + + addr = addr - ((uintptr_t)addr % PAGE_SIZE); + + getcontextinfo(addr, &lock, &start); + + size = size / PAGE_SIZE + (size % PAGE_SIZE ? 1 : 0); + + spinlock_acquire(lock); + + // XXX allocate 1 page at a time to reduce fragmentation + + void* paddr = pmm_alloc(size); + if(!paddr) + result = false; + else + result = setmap(start, addr, size, mmuflags, VMM_TYPE_ANON, 0, 0); + + for(size_t page = 0; page < size && result; ++page) + result = arch_mmu_map(arch_getcls()->context->context, paddr + page*PAGE_SIZE, addr + page*PAGE_SIZE, mmuflags); + + if(!result) + pmm_free(paddr, size); + + spinlock_release(lock); + + return result; + +} + // called by the page fault handler bool vmm_dealwithrequest(void* addr){ diff --git a/src/sys/sched/elf.c b/src/sys/sched/elf.c index 12b34f9d..7c4d0fc3 100644 --- a/src/sys/sched/elf.c +++ b/src/sys/sched/elf.c @@ -1,6 +1,36 @@ #include #include +#include #include +#include +#include + +typedef struct{ + uint64_t a_type; + uint64_t a_val; +} auxv64_t; + +typedef struct { + + +} auxv64_list; + +static size_t phflagtommuflag(size_t phflags){ + + size_t mmuflags = 0; + + if(phflags & ELF_FLAG_EXECUTABLE == 0) + mmuflags |= ARCH_MMU_MAP_NOEXEC; + + if(phflags & ELF_FLAG_WRITABLE) + mmuflags |= ARCH_MMU_MAP_WRITE; + + if(phflags & ELF_FLAG_READABLE) + mmuflags |= ARCH_MMU_MAP_READ; + + return mmuflags | ARCH_MMU_MAP_USER; + +} static bool check_header64(elf_header64* header){ // XXX throw this into arch @@ -21,6 +51,90 @@ static bool check_header64(elf_header64* header){ } +static void* stacksetup(char* interp, char** argv, char** env){ + size_t argc = 0; + size_t envc = 0; + size_t initialsize = 0; + size_t argdatasize = 0; + size_t envdatasize = 0; + size_t auxvsize = 8; + + while(argv[argc]){ + argdatasize += strlen(argv[argc]) + 1; + initialsize += strlen(argv[argc]) + 1; + ++argc; + } + + while(env[envc]){ + envdatasize += strlen(env[envc]) + 1; + initialsize += strlen(env[envc]) + 1; + ++envc; + } + + if(interp){ + argdatasize += strlen(interp) + 1; + initialsize += strlen(interp) + 1; + initialsize += sizeof(char*); // interpreter ptr + } + + // pointers to args and envs + + initialsize += argc*sizeof(char*); //args + initialsize += envc*sizeof(char*); //envs + initialsize += 2*sizeof(char**); //argv envp + initialsize += sizeof(size_t); //argc + + // allocate memory for the initial section of the stack + + + if(!vmm_allocnowat(STACK_TOP - initialsize, ARCH_MMU_MAP_READ | ARCH_MMU_MAP_WRITE | ARCH_MMU_MAP_NOEXEC | ARCH_MMU_MAP_USER, initialsize)) return NULL; + + // get the addresses to copy the data to + + char* argdatastart = STACK_TOP - argdatasize; + char* envdatastart = argdatastart - envdatasize; + // auxvstart will be aligned + void* auxvstart = (void*)(((uintptr_t)envdatastart & (~0xF)) - auxvsize); + // count + 1 because of a null entry + char** envstart = auxvstart - (envc + 1)*sizeof(char*); + char** argstart = (void*)envstart - (argc + 1)*sizeof(char*); + if(interp) + --argstart; + size_t* argcptr = (void*)argstart - sizeof(size_t); + + // XXX auxv + + // copy the data + + if(interp){ + strcpy(argdatastart, interp); + *argstart++ = argdatastart; + argdatastart += strlen(interp) + 1; + } + + for(size_t i = 0; i < argc; ++i){ + strcpy(argdatastart, argv[i]); + *argstart++ = argdatastart; + argdatastart += strlen(argv[i]) + 1; + } + + *argstart = NULL; + + for(size_t i = 0; i < envc; ++i){ + strcpy(envdatastart, env[i]); + *envstart++ = envdatastart; + envdatastart += strlen(env[i]) + 1; + } + + if(interp) + argc++; + *argcptr = argc; + + + return argcptr; + +} + int elf_load(thread_t* thread, vnode_t* node, char** argv, char** env){ elf_header64 header; @@ -88,27 +202,63 @@ int elf_load(thread_t* thread, vnode_t* node, char** argv, char** env){ } // load program into memory - + for(size_t currentph = 0; currentph < header.ph_count; ++currentph){ - readc = vfs_read(&err, node, &ph, header.ph_size, header.ph_pos + currentph*header.ph_size); + // read ph + readc = vfs_read(&err, node, &ph, header.ph_size, header.ph_pos + currentph*header.ph_size); + if(err) goto _fail; if(readc != header.ph_size){ err = EINVAL; goto _fail; } - + if(ph.type != PH_TYPE_LOAD) continue; + if(!vmm_allocnowat((void*)ph.memaddr, phflagtommuflag(ph.flags), ph.msize)){ + err = ENOMEM; + goto _fail; + } + // set up temporary mmu flags to copy data - + arch_mmu_changeflags(arch_getcls()->context->context, ph.memaddr, ARCH_MMU_MAP_READ | ARCH_MMU_MAP_WRITE, ph.msize / PAGE_SIZE + (ph.msize % PAGE_SIZE ? 1 : 0)); + + // read program data + + readc = vfs_read(&err, node, (void*)ph.memaddr, ph.fsize, ph.offset); + + if(err) + goto _fail; + + if(readc != ph.fsize){ + err = EINVAL; + goto _fail; + } + + // zero if needed + + size_t zerocount = ph.msize - ph.fsize; + + if(zerocount){ + void* zeroaddr = ph.memaddr + ph.fsize; + memset(zeroaddr, 0, zerocount); + } + + // reset proper mmu flags + + arch_mmu_changeflags(arch_getcls()->context->context, ph.memaddr, phflagtommuflag(ph.flags), ph.msize / PAGE_SIZE + (ph.msize % PAGE_SIZE ? 1 : 0)); + + } + void* stack = stacksetup(interp, argv, env); + arch_regs_setupuser(thread->regs, (void*)header.entry, stack, true); return 0; diff --git a/src/sys/sched/scheduler.c b/src/sys/sched/scheduler.c index fa7c713b..14186af9 100644 --- a/src/sys/sched/scheduler.c +++ b/src/sys/sched/scheduler.c @@ -226,6 +226,7 @@ thread_t* sched_newuthread(void* ip, size_t kstacksize, void* stack, proc_t* pro } thread->priority = prio; + thread->proc = proc; arch_regs_setupuser(thread->regs, ip, stack, true); if(run) @@ -268,18 +269,21 @@ void sched_runinit(){ proc_t* proc = thread->proc; + vmm_switchcontext(proc->context); + proc->root = vfs_root(); proc->cwd = vfs_root(); proc->pid = 1; vnode_t* node; size_t ret = vfs_open(&node, vfs_root(), "sbin/init"); + if(ret){ printf("Open failed: %s\n", strerror(ret)); _panic("Could not load init", 0); } - char** argv = {"/sbin/init", ""}; - char** env = {""}; + char* argv[] = {"/sbin/init", NULL}; + char* env[] = {NULL}; ret = elf_load(thread, node, argv, env); @@ -287,6 +291,7 @@ void sched_runinit(){ printf("ELF load error: %s\n", strerror(ret)); _panic("Could not load init", 0); } + switch_thread(thread); }