fix several issues relating to elf and registers and add mmap

This commit is contained in:
Matheus
2022-08-18 17:50:34 -03:00
parent fc6d0000c5
commit 0984a6458d
9 changed files with 243 additions and 34 deletions
+18 -14
View File
@@ -5,6 +5,12 @@ section .text
push rbp push rbp
mov rbp, [rsp+24] ; save CS for usermode checking
; check and patch ss if it is invalid because of the syscall instruction
cmp qword [rsp+48], 0x33
jne .keepgoing
mov qword [rsp+48], 0x43
.keepgoing:
push rsi push rsi
push rdi push rdi
push r15 push r15
@@ -22,12 +28,13 @@ section .text
mov rax, ds
cmp rax,0x40 cmp rbp,0x3b
jne .noswapgs jne .noswapgs
swapgs swapgs
.noswapgs: .noswapgs:
mov rax, ds
push rax push rax
mov rax, es mov rax, es
push rax push rax
@@ -38,10 +45,10 @@ section .text
; now use kernel segments for data ; now use kernel segments for data
mov rax, 0x30 ;mov rax, 0x38
mov ds, rax ;mov ds, rax
mov es, rax ;mov es, rax
mov ss, rax ;mov ss, rax
mov rdi,cr2 mov rdi,cr2
push rdi push rdi
@@ -52,18 +59,15 @@ section .text
add rsp, 24 ; cr2 gs fs add rsp, 24 ; cr2 gs fs
cmp rbp,0x3b
jne .noswapgspop
swapgs
.noswapgspop:
pop rax pop rax
cmp rax,0x43
je .dontpopsegs
mov es,rax mov es,rax
pop rax pop rax
mov ds,rax mov ds,rax
swapgs
jmp .poprest
.dontpopsegs:
add rsp,8 ; ds
.poprest:
pop rax pop rax
pop rbx pop rbx
pop rcx pop rcx
+7 -3
View File
@@ -2,12 +2,13 @@ section .rodata
extern syscall_libc_log extern syscall_libc_log
func_count equ 1 extern syscall_mmap
func_count equ 2
func_table: func_table:
dq syscall_libc_log dq syscall_libc_log
dq syscall_mmap
section .text section .text
global asm_syscall_entry global asm_syscall_entry
@@ -46,10 +47,13 @@ asm_syscall_entry:
push r9 push r9
push r10 push r10
; system V C abi expects the third param to be in rcx ; system V C abi expects the third param to be in rcx
; but the param is in rdx because of the syscall instruction ; but the param is in rdx because of the syscall instruction
mov rcx, rdx mov rcx, r10
call [func_table + rax * 8] call [func_table + rax * 8]
+2
View File
@@ -60,6 +60,8 @@ typedef struct{
#define PH_TYPE_DYNAMIC 2 #define PH_TYPE_DYNAMIC 2
#define PH_TYPE_INTERPRETER 3 #define PH_TYPE_INTERPRETER 3
#define PH_TYPE_NOTE 4 #define PH_TYPE_NOTE 4
#define PH_TYPE_SHLIB 5
#define PH_TYPE_PHDR 6
typedef struct{ typedef struct{
uint32_t type; uint32_t type;
+1
View File
@@ -7,5 +7,6 @@ typedef struct {
} syscallret; } syscallret;
syscallret syscall_libc_log(char* str); syscallret syscall_libc_log(char* str);
syscallret syscall_mmap(void* hint, size_t len, int prot, int flags, int fd, off_t offset);
#endif #endif
+5 -2
View File
@@ -7,8 +7,10 @@
#define KERNEL_SPACE_START 0xFFFF800000000000 #define KERNEL_SPACE_START 0xFFFF800000000000
#define KERNEL_SPACE_END 0xFFFFFFFFFFFFFFFF #define KERNEL_SPACE_END 0xFFFFFFFFFFFFFFFF
#define USER_SPACE_START 0x1000 #define USER_SPACE_START 0x0
#define USER_SPACE_END 0x00007FFFFFFFFFFF #define USER_SPACE_END (void*)0x00007FFFFFFFFFFF
#define USER_ALLOC_START (void*)0x1000
#define VMM_TYPE_FREE 0 #define VMM_TYPE_FREE 0
#define VMM_TYPE_ANON 1 #define VMM_TYPE_ANON 1
@@ -60,5 +62,6 @@ 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); bool vmm_allocnowat(void* addr, size_t mmuflags, size_t size);
void* vmm_allocfrom(void* addr, size_t mmuflags, size_t size);
vmm_context* vmm_newcontext(); vmm_context* vmm_newcontext();
#endif #endif
+45 -2
View File
@@ -106,6 +106,17 @@ static char* debugnames[] = {
"FILE" "FILE"
}; };
static void debug_dumpusermappings(){
vmm_mapping* map = arch_getcls()->context->userstart;
printf("User mappings:\n");
while(map != NULL){
printf("START: %016p END: %016p MMUFLAGS: %016p DATA: %016p OFFSET: %lu TYPE: %s\n", map->start, map->end, map->mmuflags, map->data, map->offset, debugnames[map->type]);
map = map->next;
}
}
static void debug_dumpkernelmappings(){ static void debug_dumpkernelmappings(){
vmm_mapping* map = kmapstart; vmm_mapping* map = kmapstart;
@@ -375,6 +386,31 @@ void* vmm_alloc(size_t pagec, size_t mmuflags){
return addr; return addr;
} }
void* vmm_allocfrom(void* addr, size_t mmuflags, size_t pagec){
int* lock;
vmm_mapping** start;
getcontextinfo(addr, &lock, &start);
spinlock_acquire(lock);
addr = findfirstfreearea(findmappingfromaddr(*start, addr), pagec);
if(!addr)
goto _done;
if(!setmap(start, addr, pagec, mmuflags, VMM_TYPE_ANON, 0, 0))
addr = NULL;
_done:
spinlock_release(lock);
return addr;
}
bool vmm_unmap(void* addr, size_t pagec){ bool vmm_unmap(void* addr, size_t pagec){
int* lock; int* lock;
@@ -448,6 +484,14 @@ bool vmm_allocnowat(void* addr, size_t mmuflags, size_t size){
spinlock_acquire(lock); spinlock_acquire(lock);
vmm_mapping* m = findmappingfromaddr(*start, addr);
if(m->type != VMM_TYPE_FREE || (addr + size*PAGE_SIZE-1) > m->end){
spinlock_release(lock);
return false;
}
// XXX allocate 1 page at a time to reduce fragmentation // XXX allocate 1 page at a time to reduce fragmentation
void* paddr = pmm_alloc(size); void* paddr = pmm_alloc(size);
@@ -481,7 +525,6 @@ bool vmm_dealwithrequest(void* addr){
spinlock_acquire(lock); spinlock_acquire(lock);
bool status; bool status;
vmm_mapping* map = findmappingfromaddr(*start, addr); vmm_mapping* map = findmappingfromaddr(*start, addr);
void* paddr; void* paddr;
@@ -498,7 +541,7 @@ bool vmm_dealwithrequest(void* addr){
addr = (size_t)addr & ~(0xFFF); addr = (size_t)addr & ~(0xFFF);
printf("Demand paging %p\n", addr); //printf("Demand paging %p\n", addr);
+64 -9
View File
@@ -57,7 +57,7 @@ static void* stacksetup(char* interp, char** argv, char** env, elf_header64 head
size_t initialsize = 0; size_t initialsize = 0;
size_t argdatasize = 0; size_t argdatasize = 0;
size_t envdatasize = 0; size_t envdatasize = 0;
size_t auxvsize = 5*8; // FIXME better way of keeping track of this size_t auxvsize = 5*16; // FIXME better way of keeping track of this
while(argv[argc]){ while(argv[argc]){
argdatasize += strlen(argv[argc]) + 1; argdatasize += strlen(argv[argc]) + 1;
@@ -90,8 +90,7 @@ static void* stacksetup(char* interp, char** argv, char** env, elf_header64 head
// get the addresses to copy the data to // get the addresses to copy the data to
elf_ph64* phdrdatastart = STACK_TOP - header.ph_count * header.ph_size; char* argdatastart = STACK_TOP - argdatasize;
char* argdatastart = (void*) phdrdatastart - argdatasize;
char* envdatastart = argdatastart - envdatasize; char* envdatastart = argdatastart - envdatasize;
auxv64_t* auxvstart = (void*)(((uintptr_t)envdatastart & (~0xF)) - auxvsize); auxv64_t* auxvstart = (void*)(((uintptr_t)envdatastart & (~0xF)) - auxvsize);
@@ -108,11 +107,9 @@ static void* stacksetup(char* interp, char** argv, char** env, elf_header64 head
// AT_PHDR // AT_PHDR
auxvstart->a_type = AT_PHDR; auxvstart->a_type = AT_PHDR;
auxvstart->a_val = (uint64_t)phdrdatastart; auxvstart->a_val = (uint64_t)phs;
auxvstart++; auxvstart++;
memcpy(phdrdatastart, phs, header.ph_count * header.ph_size);
// AT_PHENT // AT_PHENT
auxvstart->a_type = AT_PHENT; auxvstart->a_type = AT_PHENT;
@@ -123,6 +120,7 @@ static void* stacksetup(char* interp, char** argv, char** env, elf_header64 head
auxvstart->a_type = AT_PHNUM; auxvstart->a_type = AT_PHNUM;
auxvstart->a_val = header.ph_count; auxvstart->a_val = header.ph_count;
auxvstart++;
// AT_ENTRY // AT_ENTRY
@@ -133,6 +131,7 @@ static void* stacksetup(char* interp, char** argv, char** env, elf_header64 head
// AT_NULL // AT_NULL
auxvstart->a_type = AT_NULL; auxvstart->a_type = AT_NULL;
auxvstart->a_val = 0;
// copy the data // copy the data
@@ -174,6 +173,7 @@ int elf_load(thread_t* thread, vnode_t* node, char** argv, char** env){
elf_header64 header; elf_header64 header;
elf_header64 progheader; elf_header64 progheader;
vnode_t* prognode = node;
elf_ph64 ph; elf_ph64 ph;
int err = 0; int err = 0;
@@ -193,7 +193,7 @@ int elf_load(thread_t* thread, vnode_t* node, char** argv, char** env){
// and also save the executable's program headers // and also save the executable's program headers
// for auxv // for auxv
elf_ph64 progphs[header.ph_count]; elf_ph64* progphs;
for(size_t currentph = 0; currentph < header.ph_count; ++currentph){ 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); readc = vfs_read(&err, node, &ph, header.ph_size, header.ph_pos + currentph*header.ph_size);
@@ -202,7 +202,8 @@ int elf_load(thread_t* thread, vnode_t* node, char** argv, char** env){
if(readc != header.ph_size) if(readc != header.ph_size)
return EINVAL; return EINVAL;
memcpy(progphs+currentph, &ph, sizeof(elf_ph64)); if(ph.type == PH_TYPE_PHDR)
progphs = (elf_ph64*)ph.memaddr;
if(ph.type == PH_TYPE_INTERPRETER){ if(ph.type == PH_TYPE_INTERPRETER){
@@ -210,7 +211,7 @@ int elf_load(thread_t* thread, vnode_t* node, char** argv, char** env){
progheader = header; progheader = header;
char* interp = alloc(ph.fsize + 1); interp = alloc(ph.fsize + 1);
if(!interp) if(!interp)
return ENOMEM; return ENOMEM;
@@ -300,9 +301,63 @@ int elf_load(thread_t* thread, vnode_t* node, char** argv, char** env){
} }
// also load the executable memory image if we're using an interpreter
if(interp){
for(size_t currentph = 0; currentph < header.ph_count; ++currentph){
// read ph
readc = vfs_read(&err, prognode, &ph, progheader.ph_size, progheader.ph_pos + currentph*progheader.ph_size);
if(err) goto _fail;
if(readc != progheader.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, prognode, (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, progheader, progphs); void* stack = stacksetup(interp, argv, env, progheader, progphs);
+1 -1
View File
@@ -17,7 +17,7 @@ syscallret syscall_libc_log(char* str){
strcpy(buf, str); strcpy(buf, str);
printf("%s", str); printf("%s\n", str);
ret.errno = 0; ret.errno = 0;
ret.ret = 0; ret.ret = 0;
+97
View File
@@ -0,0 +1,97 @@
#include <kernel/syscalls.h>
#include <kernel/vmm.h>
#include <sys/types.h>
#include <errno.h>
// linux abi
#define PROT_NONE 0x00
#define PROT_READ 0x01
#define PROT_WRITE 0x02
#define PROT_EXEC 0x04
#define MAP_FILE 0x00
#define MAP_SHARED 0x01
#define MAP_PRIVATE 0x02
#define MAP_FIXED 0x10
#define MAP_ANON 0x20
#define MAP_ANONYMOUS 0x20
#define MAP_NORESERVE 0x4000
#define MS_ASYNC 0x01
#define MS_INVALIDATE 0x02
#define MS_SYNC 0x04
#define MCL_CURRENT 0x01
#define MCL_FUTURE 0x02
#define POSIX_MADV_NORMAL 0
#define POSIX_MADV_RANDOM 1
#define POSIX_MADV_SEQUENTIAL 2
#define POSIX_MADV_WILLNEED 3
#define POSIX_MADV_DONTNEED 4
#define MADV_NORMAL 0
#define MADV_RANDOM 1
#define MADV_SEQUENTIAL 2
#define MADV_WILLNEED 3
#define MADV_DONTNEED 4
#define MADV_FREE 8
#define MREMAP_MAYMOVE 1
#define MREMAP_FIXED 2
#define MFD_CLOEXEC 1U
#define MFD_ALLOW_SEALING 2U
syscallret syscall_mmap(void* hint, size_t len, int prot, int flags, int fd, off_t offset){
syscallret retv;
retv.ret = -1;
retv.errno = 0;
if(len == 0 || hint > USER_SPACE_END){
retv.errno = EINVAL;
return retv;
}
if(flags != (MAP_ANON | MAP_PRIVATE)){
retv.errno = ENOSYS;
return retv;
}
size_t mmuflags = 0;
if(prot & PROT_READ)
mmuflags |= ARCH_MMU_MAP_READ;
if(prot & PROT_WRITE)
mmuflags |= ARCH_MMU_MAP_WRITE;
if(!prot & PROT_EXEC)
mmuflags |= ARCH_MMU_MAP_NOEXEC;
mmuflags |= ARCH_MMU_MAP_USER;
size_t plen = len / PAGE_SIZE + (len % PAGE_SIZE ? 1 : 0);
void* ret = NULL;
if(hint)
ret = vmm_allocnowat(hint, mmuflags, plen) ? hint : NULL; // TODO demand page
if(!ret && !(flags & MAP_FIXED))
ret = vmm_allocfrom(USER_ALLOC_START, mmuflags, len);
if(!ret){
retv.errno = ENOMEM;
if(flags & MAP_ANON)
memset(ret, 0, plen);
}
else
retv.ret = ret;
return retv;
}