diff --git a/include/metalsvm/tasks.h b/include/metalsvm/tasks.h index b84fc6fd..ca1d86a3 100644 --- a/include/metalsvm/tasks.h +++ b/include/metalsvm/tasks.h @@ -70,6 +70,9 @@ void NORETURN sys_exit(int); /* system call to create a new child process */ int sys_fork(void); +/* system call to execute a program */ +int sys_execve(const char* fname, char** argv, char** env); + #ifdef __cplusplus } #endif diff --git a/kernel/syscall.c b/kernel/syscall.c index 64ed5f6f..76ce8e10 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -76,7 +76,14 @@ int syscall_handler(uint32_t sys_nr, ...) ret = wait(status); break; } - case __NR_fstat: + case __NR_execve: { + const char* name = va_arg(vl, const char*); + char** argv = va_arg(vl, char**); + char** env = va_arg(vl, char**); + + ret = sys_execve(name, argv, env); + break; + } default: kputs("invalid system call\n"); ret = -ENOSYS; diff --git a/kernel/tasks.c b/kernel/tasks.c index 0e26b6a0..2843daec 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -191,6 +191,7 @@ int sys_fork(void) spinlock_init(&task_table[i].vma_lock); // copy VMA list + spinlock_lock(&per_core(current_task)->vma_lock); child = &task_table[i].vma_list; parent = per_core(current_task)->vma_list; tmp = NULL; @@ -210,6 +211,7 @@ int sys_fork(void) tmp = *child; child = &((*child)->next); } + spinlock_unlock(&per_core(current_task)->vma_lock); mailbox_wait_msg_init(&task_table[i].inbox); memset(task_table[i].outbox, 0x00, sizeof(mailbox_wait_msg_t*)*MAX_TASKS); @@ -239,10 +241,9 @@ int create_kernel_task(tid_t* id, entry_point_t ep, void* arg) return create_task(id, ep, arg); } -static int STDCALL user_entry(void* arg) +static int load_task(vfs_node_t* node) { uint32_t i, addr, npages, flags, stack = 0; - vfs_node_t* node = (vfs_node_t*) arg; elf_header_t header; elf_program_header_t prog_header; //elf_section_header_t sec_header; @@ -370,6 +371,11 @@ invalid: return -EINVAL; } +static int STDCALL user_entry(void* arg) +{ + return load_task((vfs_node_t*) arg); +} + int create_user_task(tid_t* id, size_t sz, const char* fname, int argc, char** argv) { vfs_node_t* node; @@ -381,6 +387,36 @@ int create_user_task(tid_t* id, size_t sz, const char* fname, int argc, char** a return create_task(id, user_entry, node); } +int sys_execve(const char* fname, char** argv, char** env) +{ + vfs_node_t* node; + vma_t* tmp; + + node = findnode_fs((char*) fname); + if (!node || !(node->type == FS_FILE)) + return -EINVAL; + + spinlock_lock(&(per_core(current_task)->vma_lock)); + + // remove old program + while((tmp = per_core(current_task)->vma_list) != NULL) { + kfree((void*) tmp->start, tmp->end - tmp->start + 1); + per_core(current_task)->vma_list = tmp->next; + kfree((void*) tmp, sizeof(vma_t)); + } + + spinlock_unlock(&(per_core(current_task)->vma_lock)); + + /* + * we use a trap gate to enter the kernel + * => eflags are not changed + * => interrupts are enabled + * => we could directly load the new task + */ + + return load_task(node); +} + tid_t wait(int32_t* result) { wait_msg_t tmp = { -1, -1};