kern
diff src/proc.c @ 57:437360696883
I think we're done for now. two processes seem to be scheduled and switched just fine, fork seems to work (NO CoW YET!)
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 16 Aug 2011 03:26:53 +0300 |
parents | 0be4615594df |
children | ef9cc2e90277 |
line diff
1.1 --- a/src/proc.c Mon Aug 15 06:17:58 2011 +0300 1.2 +++ b/src/proc.c Tue Aug 16 03:26:53 2011 +0300 1.3 @@ -1,6 +1,7 @@ 1.4 #include <stdio.h> 1.5 #include <string.h> 1.6 #include <assert.h> 1.7 +#include <errno.h> 1.8 #include "config.h" 1.9 #include "proc.h" 1.10 #include "tss.h" 1.11 @@ -17,7 +18,8 @@ 1.12 static void start_first_proc(void); 1.13 1.14 /* defined in proc-asm.S */ 1.15 -uint32_t switch_stack(uint32_t new_stack); 1.16 +uint32_t switch_stack(uint32_t new_stack, uint32_t *old_stack); 1.17 +void just_forked(void); 1.18 1.19 /* defined in test_proc.S */ 1.20 void test_proc(void); 1.21 @@ -62,7 +64,6 @@ 1.22 start_first_proc(); /* XXX never returns */ 1.23 } 1.24 1.25 - 1.26 static void start_first_proc(void) 1.27 { 1.28 struct process *p; 1.29 @@ -134,6 +135,66 @@ 1.30 intr_ret(ifrm); 1.31 } 1.32 1.33 +int fork(void) 1.34 +{ 1.35 + int i, pid; 1.36 + struct process *p, *parent; 1.37 + 1.38 + disable_intr(); 1.39 + 1.40 + /* find a free process slot */ 1.41 + /* TODO don't search up to MAX_PROC if uid != 0 */ 1.42 + pid = -1; 1.43 + for(i=1; i<MAX_PROC; i++) { 1.44 + if(proc[i].id == 0) { 1.45 + pid = i; 1.46 + break; 1.47 + } 1.48 + } 1.49 + 1.50 + if(pid == -1) { 1.51 + /* process table full */ 1.52 + return -EAGAIN; 1.53 + } 1.54 + 1.55 + 1.56 + p = proc + pid; 1.57 + parent = get_current_proc(); 1.58 + 1.59 + /* allocate a kernel stack for the new process */ 1.60 + if((p->kern_stack_pg = pgalloc(KERN_STACK_SIZE / PGSIZE, MEM_KERNEL)) == -1) { 1.61 + return -EAGAIN; 1.62 + } 1.63 + p->ctx.stack_ptr = PAGE_TO_ADDR(p->kern_stack_pg) + KERN_STACK_SIZE; 1.64 + 1.65 + /* we need to copy the current interrupt frame to the new kernel stack so 1.66 + * that the new process will return to the same point as the parent, just 1.67 + * after the fork syscall. 1.68 + */ 1.69 + p->ctx.stack_ptr -= sizeof(struct intr_frame); 1.70 + memcpy((void*)p->ctx.stack_ptr, get_intr_frame(), sizeof(struct intr_frame)); 1.71 + /* child's return from fork returns 0 */ 1.72 + ((struct intr_frame*)p->ctx.stack_ptr)->regs.eax = 0; 1.73 + 1.74 + /* XXX describe */ 1.75 + p->ctx.stack_ptr -= 4; 1.76 + *(uint32_t*)p->ctx.stack_ptr = (uint32_t)just_forked; 1.77 + 1.78 + /* initialize the rest of the process structure */ 1.79 + p->id = pid; 1.80 + p->parent = parent->id; 1.81 + p->next = p->prev = 0; 1.82 + 1.83 + /* will be copied on write */ 1.84 + p->user_stack_pg = parent->user_stack_pg; 1.85 + 1.86 + p->ctx.pgtbl_paddr = clone_vm(CLONE_COW); 1.87 + 1.88 + /* done, now let's add it to the scheduler runqueue */ 1.89 + add_proc(p->id); 1.90 + 1.91 + return pid; 1.92 +} 1.93 1.94 void context_switch(int pid) 1.95 { 1.96 @@ -147,13 +208,7 @@ 1.97 new = proc + pid; 1.98 1.99 if(last_pid != pid) { 1.100 - /* push all registers onto the stack before switching stacks */ 1.101 - push_regs(); 1.102 - 1.103 - prev->ctx.stack_ptr = switch_stack(new->ctx.stack_ptr); 1.104 - 1.105 - /* restore registers from the new stack */ 1.106 - pop_regs(); 1.107 + set_current_pid(new->id); 1.108 1.109 /* switch to the new process' address space */ 1.110 set_pgdir_addr(new->ctx.pgtbl_paddr); 1.111 @@ -162,9 +217,21 @@ 1.112 * we enter from userspace 1.113 */ 1.114 tss->esp0 = PAGE_TO_ADDR(new->kern_stack_pg) + KERN_STACK_SIZE; 1.115 + 1.116 + /* push all registers onto the stack before switching stacks */ 1.117 + push_regs(); 1.118 + 1.119 + /* XXX: when switching to newly forked processes this switch_stack call 1.120 + * WILL NOT RETURN HERE. It will return to just_forked instead. So the 1.121 + * rest of this function will not run. 1.122 + */ 1.123 + switch_stack(new->ctx.stack_ptr, &prev->ctx.stack_ptr); 1.124 + 1.125 + /* restore registers from the new stack */ 1.126 + pop_regs(); 1.127 + } else { 1.128 + set_current_pid(new->id); 1.129 } 1.130 - 1.131 - set_current_pid(new->id); 1.132 } 1.133 1.134