]> git.corax.cc Git - corax/commitdiff
Modify process_create() function to finalize sys_fork() implementation:
authorMatthias Kruk <m@m10k.eu>
Mon, 4 Nov 2019 02:06:34 +0000 (11:06 +0900)
committerMatthias Kruk <m@m10k.eu>
Mon, 4 Nov 2019 02:06:34 +0000 (11:06 +0900)
 - 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

index 306e9bed3884e55ddb779a1bd1691bc4ecc28eb5..cb4699a484ebc52b39eb725944fb13b7085a3755 100644 (file)
@@ -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);