#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,
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;
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);
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);