mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-02 07:28:21 +00:00
elf loading and userland
This commit is contained in:
Binary file not shown.
@@ -35,6 +35,7 @@ static void reloadgdtr(){
|
|||||||
gdtr.offset = &arch_getcls()->gdt;
|
gdtr.offset = &arch_getcls()->gdt;
|
||||||
gdtr.size = sizeof(gdt_t) - 1;
|
gdtr.size = sizeof(gdt_t) - 1;
|
||||||
asm("lgdt (%%rax)" : : "a"(&gdtr) : "memory");
|
asm("lgdt (%%rax)" : : "a"(&gdtr) : "memory");
|
||||||
|
asm("ltr %%ax" : : "a"(0x48));
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdt_init(){
|
void gdt_init(){
|
||||||
|
|||||||
@@ -4,20 +4,22 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
uint32_t IOPB;
|
uint32_t reserved;
|
||||||
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;
|
|
||||||
uint64_t rsp0;
|
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;
|
} __attribute((packed)) ist_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,5 +24,6 @@ void arch_mmu_init();
|
|||||||
void arch_mmu_apinit();
|
void arch_mmu_apinit();
|
||||||
arch_mmu_tableptr arch_mmu_newcontext();
|
arch_mmu_tableptr arch_mmu_newcontext();
|
||||||
void arch_mmu_switchcontext(arch_mmu_tableptr);
|
void arch_mmu_switchcontext(arch_mmu_tableptr);
|
||||||
|
void arch_mmu_changeflags(arch_mmu_tableptr context, void* addr, size_t flags, size_t count);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+18
-2
@@ -115,9 +115,11 @@ static uint64_t getmapping(arch_mmu_tableptr context, void* vaddr){
|
|||||||
size_t pt = (addr >> 21) & 0b111111111;
|
size_t pt = (addr >> 21) & 0b111111111;
|
||||||
size_t page = (addr >> 12) & 0b111111111;
|
size_t page = (addr >> 12) & 0b111111111;
|
||||||
|
|
||||||
if(!context[pdpt]) return 0;
|
uint64_t* table = next(context, pdpt);
|
||||||
|
|
||||||
uint64_t* table = next(context, pd);
|
if(!table) return 0;
|
||||||
|
|
||||||
|
table = next(table, pd);
|
||||||
|
|
||||||
if(!table) return 0;
|
if(!table) return 0;
|
||||||
|
|
||||||
@@ -142,6 +144,20 @@ bool arch_mmu_isaccessed(arch_mmu_tableptr context, void* addr){
|
|||||||
return (getmapping(context, addr) & ARCH_MMU_MAP_ACCESSED) != 0;
|
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){
|
int arch_mmu_map(arch_mmu_tableptr context, void* paddr, void* vaddr, size_t flags){
|
||||||
uint64_t entry;
|
uint64_t entry;
|
||||||
changeentry(&entry, paddr, flags);
|
changeentry(&entry, paddr, flags);
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#define TRACE_MAXDEPTH 10
|
#define TRACE_MAXDEPTH 10
|
||||||
|
|
||||||
static void tracestack(uint64_t** addr){
|
static void tracestack(uint64_t** addr){
|
||||||
|
|
||||||
for(size_t depth = 0; depth < TRACE_MAXDEPTH; ++depth){
|
for(size_t depth = 0; depth < TRACE_MAXDEPTH; ++depth){
|
||||||
|
|
||||||
uint64_t *calleeaddr = *(addr + 1);
|
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("Panic location: %p\n", reg->rip);
|
||||||
|
|
||||||
|
if(reg->rbp != 0){
|
||||||
printf("Stack trace:\n");
|
printf("Stack trace:\n");
|
||||||
tracestack((uint64_t**)reg->rbp);
|
tracestack((uint64_t**)reg->rbp);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ static int tmpfs_read(int *error, vnode_t* node, void* buff, size_t count, size_
|
|||||||
if(count > sizemax)
|
if(count > sizemax)
|
||||||
count = sizemax;
|
count = sizemax;
|
||||||
|
|
||||||
memcpy(buff, node->fsdata, count);
|
memcpy(buff, node->fsdata + offset, count);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#define ELF_FLAG_WRITABLE 2
|
#define ELF_FLAG_WRITABLE 2
|
||||||
#define ELF_FLAG_READABLE 4
|
#define ELF_FLAG_READABLE 4
|
||||||
|
|
||||||
|
#define STACK_TOP 0x800000000000
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#define KERNEL_SPACE_START 0xFFFF800000000000
|
#define KERNEL_SPACE_START 0xFFFF800000000000
|
||||||
#define KERNEL_SPACE_END 0xFFFFFFFFFFFFFFFF
|
#define KERNEL_SPACE_END 0xFFFFFFFFFFFFFFFF
|
||||||
#define USER_SPACE_START 0
|
#define USER_SPACE_START 0x1000
|
||||||
#define USER_SPACE_END 0x00007FFFFFFFFFFF
|
#define USER_SPACE_END 0x00007FFFFFFFFFFF
|
||||||
|
|
||||||
#define VMM_TYPE_FREE 0
|
#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);
|
bool vmm_map(void* paddr, void* vaddr, size_t pagec, size_t mmuflags);
|
||||||
void* vmm_alloc(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_setfree(void* addr, size_t pagec);
|
||||||
|
bool vmm_allocnowat(void* addr, size_t mmuflags, size_t size);
|
||||||
vmm_context* vmm_newcontext();
|
vmm_context* vmm_newcontext();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -206,7 +206,7 @@ void pmm_init(){
|
|||||||
|
|
||||||
if(current->length < bitmapsize || current->base < 0x100000) continue;
|
if(current->length < bitmapsize || current->base < 0x100000) continue;
|
||||||
|
|
||||||
bitmap = (size_t*)current->base;
|
bitmap = (void*)current->base + (size_t)limine_hhdm_offset;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
+34
-1
@@ -351,7 +351,7 @@ static void getcontextinfo(void* addr, int** lock, vmm_mapping*** start){
|
|||||||
vmm_context *context = arch_getcls()->context;
|
vmm_context *context = arch_getcls()->context;
|
||||||
|
|
||||||
*lock = &context->lock;
|
*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;
|
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
|
// called by the page fault handler
|
||||||
|
|
||||||
bool vmm_dealwithrequest(void* addr){
|
bool vmm_dealwithrequest(void* addr){
|
||||||
|
|||||||
@@ -1,6 +1,36 @@
|
|||||||
#include <kernel/elf.h>
|
#include <kernel/elf.h>
|
||||||
#include <kernel/alloc.h>
|
#include <kernel/alloc.h>
|
||||||
|
#include <kernel/vmm.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <arch/cls.h>
|
||||||
|
|
||||||
|
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){
|
static bool check_header64(elf_header64* header){
|
||||||
// XXX throw this into arch
|
// 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){
|
int elf_load(thread_t* thread, vnode_t* node, char** argv, char** env){
|
||||||
|
|
||||||
elf_header64 header;
|
elf_header64 header;
|
||||||
@@ -91,6 +205,8 @@ int elf_load(thread_t* thread, vnode_t* node, char** argv, char** env){
|
|||||||
|
|
||||||
for(size_t currentph = 0; currentph < header.ph_count; ++currentph){
|
for(size_t currentph = 0; currentph < header.ph_count; ++currentph){
|
||||||
|
|
||||||
|
// read ph
|
||||||
|
|
||||||
readc = vfs_read(&err, node, &ph, header.ph_size, header.ph_pos + currentph*header.ph_size);
|
readc = vfs_read(&err, node, &ph, header.ph_size, header.ph_pos + currentph*header.ph_size);
|
||||||
|
|
||||||
if(err) goto _fail;
|
if(err) goto _fail;
|
||||||
@@ -103,12 +219,46 @@ int elf_load(thread_t* thread, vnode_t* node, char** argv, char** env){
|
|||||||
if(ph.type != PH_TYPE_LOAD)
|
if(ph.type != PH_TYPE_LOAD)
|
||||||
continue;
|
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;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ thread_t* sched_newuthread(void* ip, size_t kstacksize, void* stack, proc_t* pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread->priority = prio;
|
thread->priority = prio;
|
||||||
|
thread->proc = proc;
|
||||||
arch_regs_setupuser(thread->regs, ip, stack, true);
|
arch_regs_setupuser(thread->regs, ip, stack, true);
|
||||||
|
|
||||||
if(run)
|
if(run)
|
||||||
@@ -268,18 +269,21 @@ void sched_runinit(){
|
|||||||
|
|
||||||
proc_t* proc = thread->proc;
|
proc_t* proc = thread->proc;
|
||||||
|
|
||||||
|
vmm_switchcontext(proc->context);
|
||||||
|
|
||||||
proc->root = vfs_root();
|
proc->root = vfs_root();
|
||||||
proc->cwd = vfs_root();
|
proc->cwd = vfs_root();
|
||||||
proc->pid = 1;
|
proc->pid = 1;
|
||||||
|
|
||||||
vnode_t* node;
|
vnode_t* node;
|
||||||
size_t ret = vfs_open(&node, vfs_root(), "sbin/init");
|
size_t ret = vfs_open(&node, vfs_root(), "sbin/init");
|
||||||
|
|
||||||
if(ret){
|
if(ret){
|
||||||
printf("Open failed: %s\n", strerror(ret));
|
printf("Open failed: %s\n", strerror(ret));
|
||||||
_panic("Could not load init", 0);
|
_panic("Could not load init", 0);
|
||||||
}
|
}
|
||||||
char** argv = {"/sbin/init", ""};
|
char* argv[] = {"/sbin/init", NULL};
|
||||||
char** env = {""};
|
char* env[] = {NULL};
|
||||||
|
|
||||||
ret = elf_load(thread, node, argv, env);
|
ret = elf_load(thread, node, argv, env);
|
||||||
|
|
||||||
@@ -287,6 +291,7 @@ void sched_runinit(){
|
|||||||
printf("ELF load error: %s\n", strerror(ret));
|
printf("ELF load error: %s\n", strerror(ret));
|
||||||
_panic("Could not load init", 0);
|
_panic("Could not load init", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch_thread(thread);
|
switch_thread(thread);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user