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