From ae851a082eeb68b20fd0e43973c1dcc26ab5af40 Mon Sep 17 00:00:00 2001 From: Matthias Kruk Date: Mon, 4 Nov 2019 11:06:34 +0900 Subject: [PATCH] Modify process_create() function to finalize sys_fork() implementation: - Copy the contents of the user-mode stack - Call task_prepare_fork to copy/modify the new task's kernel-mode stack - Set the state of the new task to TASK_STATE_FORKED - Set t_pgdir and other values that would normally be set by task_prepare --- kernel/core/process.c | 86 ++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/kernel/core/process.c b/kernel/core/process.c index 306e9be..cb4699a 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -9,27 +9,6 @@ #include "fd.h" #include "sched.h" -/* FIXME: Remove struct stack_frame from process.c */ -struct stack_frame { - u32_t cr3; - u32_t ds; - u32_t edi; - u32_t esi; - u32_t ebp; - u32_t esp; - u32_t ebx; - u32_t edx; - u32_t ecx; - u32_t eax; - u32_t intn; - u32_t error; - u32_t eip; - u32_t cs; - u32_t eflags; - u32_t prevesp; - u32_t ss; -} __attribute__((packed)); - enum procstate { PROC_STATE_INIT = 0, PROC_STATE_READY, @@ -103,8 +82,6 @@ static inline int DQ(process_t *p) return(ret_val); } -void* task_get_eip3(void); - int process_create(process_t **dst, pid_t pid, u32_t ppl, void *entry) { int ret_val; @@ -175,36 +152,64 @@ int process_create(process_t **dst, pid_t pid, u32_t ppl, void *entry) proc->p_id = pid; } + proc->p_tasks->t_kstack = kstack; + proc->p_tasks->t_tslice = 50; + proc->p_tasks->t_rslice = 50; + proc->p_tasks->t_proc = proc; + proc->p_tasks->t_pid = proc->p_id; + if(entry == PROC_ENTRY_FORK || entry == PROC_ENTRY_VFORK) { - struct stack_frame *stack0; task_t *ctask; + process_t *cproc; + void *custack; ctask = task_get_current(); + cproc = (process_t*)ctask->t_proc; + custack = pg_dir_get_ustack(cproc->p_pgdir); /* * In the case of fork() and vfork() we have to get the address that the * interrupt is supposed to return to. The stack that the address was pushed - * onto is located at ctask->t_kstack. + * onto is located at ctask->t_kstack. Instead of pulling the address from + * where we believe it should be on the stack, we'll just copy the entire stack + * and make the child process return to userspace the same way we do. + * The task_prepare_fork function will actually do all of this work: it will + * adjust the stack pointers for the new task, copy the kernel stack, and + * otherwise prepare it to start execution through task_switch. */ - stack0 = ((struct stack_frame*)(ctask->t_kstack + CONFIG_KERNEL_STACK_SIZE)) - 1; + proc->p_tasks->t_state = TASK_STATE_FORKED; + proc->p_tasks->t_pgdir = (u32_t)pdbr; - entry = (void*)stack0->eip; - dbg_printf("entry = 0x%08x\n", (u32_t)entry); + process_memcpy_ptop(proc, ustack, + cproc, custack, + CONFIG_USER_STACK_SIZE); - for(;;); - } + /* + * The child process will start with the instruction that is following the + * task_prepare_fork call. In the case of the parent, task_prepare_fork will + * return zero, in case of the child, the return value will be 0xf00f00ff, but + * the function that the child will be returning from is actually task_switch. + * Since any registers besides esp, ebp, and eax will be in an undefined state + * for the child process, we should not touch anything else and just return + * to user-space asap. + */ - task_prepare(proc->p_tasks, (u32_t)pdbr, (u32_t)entry, - (u32_t)kstack + CONFIG_KERNEL_STACK_SIZE, - (u32_t)ustack + CONFIG_USER_STACK_SIZE, ppl); + if(task_prepare_fork(proc->p_tasks) == 0xf00f00ff) { + /* this is the forked process */ + proc = NULL; + ret_val = 0; + goto cleanup; + } - proc->p_tasks->t_kstack = kstack; - proc->p_tasks->t_tslice = 50; - proc->p_tasks->t_rslice = 50; - proc->p_tasks->t_proc = proc; - proc->p_tasks->t_pid = proc->p_id; + /* the parent continues as usual */ + + } else { + task_prepare(proc->p_tasks, (u32_t)pdbr, (u32_t)entry, + (u32_t)kstack + CONFIG_KERNEL_STACK_SIZE, + (u32_t)ustack + CONFIG_USER_STACK_SIZE, ppl); + } ret_val = NQ(proc); @@ -544,6 +549,11 @@ int process_fork(int v) process_t *nproc; ret_val = process_create(&nproc, PID_ANY, proc->p_privl, PROC_ENTRY_FORK); + + if(!ret_val && nproc) { + /* this is the parent */ + ret_val = nproc->p_id; + } } return(ret_val); -- 2.47.3