diff --git a/arch/x86/kernel/entry64.asm b/arch/x86/kernel/entry64.asm index eec5e326..506cd729 100644 --- a/arch/x86/kernel/entry64.asm +++ b/arch/x86/kernel/entry64.asm @@ -407,13 +407,6 @@ gdt_flush: lgdt [gp] ret -; determines the current instruction pointer (after the jmp) -global read_eip -read_eip: - pop rax ; Get the return address - jmp rax ; Return. Can't use RET because return - ; address popped off the stack. - ; In just a few pages in this tutorial, we will add our Interrupt ; Service Routines (ISRs) right here! global isr0 diff --git a/arch/x86/kernel/gdt.c b/arch/x86/kernel/gdt.c index dcee770a..7765aa8b 100644 --- a/arch/x86/kernel/gdt.c +++ b/arch/x86/kernel/gdt.c @@ -59,7 +59,7 @@ int arch_fork(task_t* task) { struct state* state; task_t* curr_task = per_core(current_task); - size_t esp, state_size; + size_t state_size; if (BUILTIN_EXPECT(!task, 0)) return -EINVAL; @@ -78,6 +78,7 @@ int arch_fork(task_t* task) memcpy(task->stack, curr_task->stack, KERNEL_STACK_SIZE); #ifdef CONFIG_X86_32 + size_t esp; asm volatile ("mov %%esp, %0" : "=m"(esp)); esp -= (size_t) curr_task->stack; esp += (size_t) task->stack; @@ -107,8 +108,48 @@ int arch_fork(task_t* task) // This will be the entry point for the new task. read_ip cleanups the stack asm volatile ("push %0; call read_ip" :: "r"(&state->eip) : "%eax"); #else -#warning Currently, not supported! - return -1; + size_t rsp; + asm volatile ("mov %%rsp, %0" : "=m"(rsp)); + rsp -= (size_t) curr_task->stack; + rsp += (size_t) task->stack; + + state = (struct state*) (rsp - state_size); + //memset(state, 0x00, state_size); + + asm volatile ("push %rax"); + asm volatile ("push %rcx"); + asm volatile ("push %rdx"); + asm volatile ("push %rbx"); + asm volatile ("push %rbp"); + asm volatile ("push %rsi"); + asm volatile ("push %rdi"); + asm volatile ("push %r8"); + asm volatile ("push %r9"); + asm volatile ("push %r10"); + asm volatile ("push %r11"); + + asm volatile ("pop %0" : "=m"(state->r11)); + asm volatile ("pop %0" : "=m"(state->r10)); + asm volatile ("pop %0" : "=m"(state->r9)); + asm volatile ("pop %0" : "=m"(state->r8)); + asm volatile ("pop %0" : "=m"(state->rdi)); + asm volatile ("pop %0" : "=m"(state->rsi)); + asm volatile ("pop %0" : "=m"(state->rbp)); + asm volatile ("pop %0" : "=m"(state->rbx)); + asm volatile ("pop %0" : "=m"(state->rdx)); + asm volatile ("pop %0" : "=m"(state->rcx)); + asm volatile ("pop %0" : "=m"(state->rax)); + + state->rsp = rsp; + task->last_stack_pointer = (size_t*) state; + state->int_no = 0xB16B00B5; + state->error = 0xC03DB4B3; + state->cs = 0x08; + state->ss = 0x10; + asm volatile ("pushf; pop %0" : "=m"(state->rflags)); // store the current RFLAGS + asm volatile ("leaq (%%rip), %0;": "=r"(state->rip)); // store current instruction pointer + + state->rflags |= (1 << 9); // enable interrupts #endif return 0; @@ -266,7 +307,7 @@ void gdt_install(void) gdt_set_gate(2, 0, limit, GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, GDT_FLAG_4K_GRAN | mode); - + /* * Create code segement for userspace applications (ring 3) */ diff --git a/kernel/tasks.c b/kernel/tasks.c index 2ed00eb0..3d92fd31 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -258,13 +258,6 @@ static void NORETURN do_exit(int arg) { flags = irq_nested_disable(); drop_vma_list(); - - /* - * This marks all userpages as free. Nevertheless they are still existing - * and used by the MMU until the task finishes. Therefore we need to disable - * context switching by disabling interrupts (see above)! We may also make use - * of the TLB and global kernel pages. - */ drop_page_map(); #if 1 @@ -368,13 +361,17 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio, uin new_task->id = i; new_task->status = TASK_READY; new_task->last_stack_pointer = NULL; - new_task->stack = create_stack(); new_task->flags = TASK_DEFAULT_FLAGS; new_task->prio = prio; new_task->last_core = 0; spinlock_init(&new_task->vma_lock); new_task->vma_list = NULL; new_task->fildes_table = NULL; + new_task->stack = create_stack(); + if (BUILTIN_EXPECT(!new_task->stack, 0)) { + ret = -ENOMEM; + goto out; + } mailbox_wait_msg_init(&new_task->inbox); memset(new_task->outbox, 0x00, sizeof(mailbox_wait_msg_t*)*MAX_TASKS); @@ -435,16 +432,18 @@ int sys_fork(void) goto out; } + kprintf("sys_fork: parent id = %u, child id = %u\n", parent_task->id , child_task->id); // TODO: remove + atomic_int32_set(&child_task->user_usage, 0); ret = copy_page_map(child_task, 1); - if (ret < 0) { + if (BUILTIN_EXPECT(ret < 0, 0)) { ret = -ENOMEM; goto out; } ret = copy_vma_list(child_task); - if (BUILTIN_EXPECT(!ret, 0)) { + if (BUILTIN_EXPECT(ret < 0, 0)) { ret = -ENOMEM; goto out; } @@ -452,6 +451,10 @@ int sys_fork(void) child_task->id = i; child_task->last_stack_pointer = NULL; child_task->stack = create_stack(); + if (BUILTIN_EXPECT(!child_task->stack, 0)) { + ret = -ENOMEM; + goto out; + } // init fildes_table child_task->fildes_table = kmalloc(sizeof(filp_t)*NR_OPEN); @@ -712,7 +715,7 @@ static int load_task(load_args_t* largs) memset((void*) stack, 0x00, npages*PAGE_SIZE); // create vma regions for the user-level stack - flags = VMA_CACHEABLE; + flags = VMA_CACHEABLE | VMA_USER; if (prog_header.flags & PF_R) flags |= VMA_READ; if (prog_header.flags & PF_W) @@ -899,6 +902,9 @@ int sys_execve(const char* fname, char** argv, char** env) char *dest, *src; int ret, argc = 0; int envc = 0; + task_t* curr_task = per_core(current_task); + + kprintf("sys_execve: fname = %s, argv = %p, env = %p\n", fname, argv, env); // TODO: remove node = findnode_fs((char*) fname); if (!node || !(node->type == FS_FILE)) @@ -941,8 +947,17 @@ int sys_execve(const char* fname, char** argv, char** env) while ((*dest++ = *src++) != 0); } + + spinlock_lock(&curr_task->vma_lock); + // remove old program - drop_vma_list(); + vma_t *vma; + for (vma=curr_task->vma_list; vma; vma = vma->next) + pfree((void*) vma->start, vma->end - vma->start); + + // TODO: Heap? + + spinlock_unlock(&curr_task->vma_lock); /* * we use a trap gate to enter the kernel