syscalls: implement basic execve syscall, no argc, argv, envp support yet
This commit is contained in:
@@ -247,6 +247,89 @@ int sys_close(TrapFrame *tf)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include "../include/exec_from_file.h"
|
||||
|
||||
extern void execve_return(TrapFrame *tf);
|
||||
|
||||
int sys_execve(TrapFrame *tf) {
|
||||
const char* filename = (const char*)tf->ebx;
|
||||
|
||||
uint8_t* file_buffer;
|
||||
int err = vsf_read_file_by_path(filename, &file_buffer, root_dir);
|
||||
if (err != 0) {
|
||||
debug_log("execve: failed to read file '%s'\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Elf32_Ehdr *elf_header = (Elf32_Ehdr*)file_buffer;
|
||||
if (memcmp(elf_header->e_ident, "\x7F" "ELF", 4) != 0) {
|
||||
debug_log("execve: '%s' is not a valid ELF file\n", filename);
|
||||
free(file_buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t* new_page_dir = create_page_dir();
|
||||
if (!new_page_dir) {
|
||||
free(file_buffer);
|
||||
return -1;
|
||||
}
|
||||
uint32_t new_page_dir_phys = (uint32_t)get_physaddr((void*)new_page_dir);
|
||||
uint32_t* old_page_dir_to_free = current->pagedir;
|
||||
|
||||
set_page_dir(new_page_dir_phys);
|
||||
current->pagedir = new_page_dir;
|
||||
|
||||
void* kstack_phys = get_physaddr(current->kstack);
|
||||
map_page(kstack_phys, current->kstack, PAGE_PRESENT | PAGE_RW);
|
||||
|
||||
uint32_t highest_vaddr = 0;
|
||||
for (int i = 0; i < elf_header->e_phnum; i++) {
|
||||
Elf32_Phdr *p_header = (Elf32_Phdr *)(file_buffer + elf_header->e_phoff + i * elf_header->e_phentsize);
|
||||
if (p_header->p_type == PT_LOAD) {
|
||||
for (uint32_t vaddr = p_header->p_vaddr; vaddr < p_header->p_vaddr + p_header->p_memsz; vaddr += PAGE_SIZE) {
|
||||
void* phys_addr = alloc_page();
|
||||
map_page(phys_addr, (void*)(vaddr & ~0xFFF), PAGE_PRESENT | PAGE_RW | PAGE_USER);
|
||||
}
|
||||
memcpy((void*)p_header->p_vaddr, file_buffer + p_header->p_offset, p_header->p_filesz);
|
||||
if (p_header->p_memsz > p_header->p_filesz) {
|
||||
memset((void*)(p_header->p_vaddr + p_header->p_filesz), 0, p_header->p_memsz - p_header->p_filesz);
|
||||
}
|
||||
if (p_header->p_vaddr + p_header->p_memsz > highest_vaddr) {
|
||||
highest_vaddr = p_header->p_vaddr + p_header->p_memsz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t vaddr = USER_STACK_BOTTOM; vaddr <= USER_STACK_TOP; vaddr += PAGE_SIZE) {
|
||||
void* phys_addr = alloc_page();
|
||||
map_page(phys_addr, (void*)(vaddr & ~0xFFF), PAGE_PRESENT | PAGE_RW | PAGE_USER);
|
||||
}
|
||||
uint32_t user_esp = USER_STACK_TOP;
|
||||
user_esp -= 4; *(uint32_t*)user_esp = 0; // envp
|
||||
user_esp -= 4; *(uint32_t*)user_esp = 0; // argv
|
||||
user_esp -= 4; *(uint32_t*)user_esp = 0; // argc
|
||||
|
||||
current->brk = (void*)(DivRoundUp(highest_vaddr, PAGE_SIZE) * PAGE_SIZE);
|
||||
free(file_buffer);
|
||||
destroy_page_dir(old_page_dir_to_free);
|
||||
|
||||
tf->gs = SEG_UDATA | DPL_USER;
|
||||
tf->fs = SEG_UDATA | DPL_USER;
|
||||
tf->es = SEG_UDATA | DPL_USER;
|
||||
tf->ds = SEG_UDATA | DPL_USER;
|
||||
tf->eax = 0; tf->ecx = 0; tf->edx = 0; tf->ebx = 0;
|
||||
tf->ebp = 0; tf->esi = 0; tf->edi = 0;
|
||||
tf->eip = elf_header->e_entry;
|
||||
tf->cs = SEG_UCODE | DPL_USER;
|
||||
tf->eflags = FL_IF;
|
||||
tf->usermode_esp = user_esp;
|
||||
tf->usermode_ss = SEG_UDATA | DPL_USER;
|
||||
|
||||
execve_return(tf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_chdir(TrapFrame *tf)
|
||||
{
|
||||
//strcat(current->cwd->fat->path, "/");
|
||||
@@ -355,6 +438,10 @@ void handle_syscall(TrapFrame *tf)
|
||||
case 6://close
|
||||
tf->eax = sys_close(tf);
|
||||
break;
|
||||
|
||||
case 11://execve
|
||||
tf->eax = sys_execve(tf);
|
||||
break;
|
||||
|
||||
case 12://chdir
|
||||
tf->eax = sys_chdir(tf);
|
||||
|
||||
Reference in New Issue
Block a user