primitive fork and exit system calls
This commit is contained in:
		
							parent
							
								
									cb83c71628
								
							
						
					
					
						commit
						a4c03dea09
					
				
					 12 changed files with 166 additions and 37 deletions
				
			
		
							
								
								
									
										5
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,10 +1,11 @@
 | 
			
		|||
OBJS = main.o console.o string.o kalloc.o proc.o trapasm.o trap.o vectors.o
 | 
			
		||||
OBJS = main.o console.o string.o kalloc.o proc.o trapasm.o trap.o vectors.o \
 | 
			
		||||
       syscall.o
 | 
			
		||||
 | 
			
		||||
CC = i386-jos-elf-gcc
 | 
			
		||||
LD = i386-jos-elf-ld
 | 
			
		||||
OBJCOPY = i386-jos-elf-objcopy
 | 
			
		||||
OBJDUMP = i386-jos-elf-objdump
 | 
			
		||||
CFLAGS = -nostdinc -I. -O
 | 
			
		||||
CFLAGS = -nostdinc -I. -O -Wall
 | 
			
		||||
 | 
			
		||||
xv6.img : bootblock kernel
 | 
			
		||||
	dd if=/dev/zero of=xv6.img count=10000
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								Notes
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								Notes
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -40,6 +40,7 @@ one segment array per cpu, or per process?
 | 
			
		|||
 | 
			
		||||
pass curproc explicitly, or implicit from cpu #?
 | 
			
		||||
  e.g. argument to newproc()?
 | 
			
		||||
  hmm, you need a global curproc[cpu] for trap() &c
 | 
			
		||||
 | 
			
		||||
test stack expansion
 | 
			
		||||
test running out of memory, process slots
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								defs.h
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								defs.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
// kalloc.c
 | 
			
		||||
char *kalloc(int n);
 | 
			
		||||
void kfree(char *cp, int len);
 | 
			
		||||
void kinit(void);
 | 
			
		||||
 | 
			
		||||
// console.c
 | 
			
		||||
void cprintf(char *fmt, ...);
 | 
			
		||||
| 
						 | 
				
			
			@ -8,5 +9,16 @@ void panic(char *s);
 | 
			
		|||
 | 
			
		||||
// proc.c
 | 
			
		||||
struct proc;
 | 
			
		||||
void setupsegs(struct proc *p);
 | 
			
		||||
struct proc * newproc(struct proc *op);
 | 
			
		||||
void setupsegs(struct proc *);
 | 
			
		||||
struct proc * newproc(void);
 | 
			
		||||
void swtch(void);
 | 
			
		||||
 | 
			
		||||
// trap.c
 | 
			
		||||
void tinit(void);
 | 
			
		||||
 | 
			
		||||
// string.c
 | 
			
		||||
void * memcpy(void *dst, void *src, unsigned n);
 | 
			
		||||
void * memset(void *dst, int c, unsigned n);
 | 
			
		||||
 | 
			
		||||
// syscall.c
 | 
			
		||||
void syscall(void);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										33
									
								
								main.c
									
										
									
									
									
								
							
							
						
						
									
										33
									
								
								main.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -4,12 +4,16 @@
 | 
			
		|||
#include "proc.h"
 | 
			
		||||
#include "defs.h"
 | 
			
		||||
#include "x86.h"
 | 
			
		||||
#include "traps.h"
 | 
			
		||||
#include "syscall.h"
 | 
			
		||||
 | 
			
		||||
extern char edata[], end[];
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main()
 | 
			
		||||
{
 | 
			
		||||
  struct proc *p;
 | 
			
		||||
  int i;
 | 
			
		||||
  
 | 
			
		||||
  // clear BSS
 | 
			
		||||
  memset(edata, 0, end - edata);
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +31,7 @@ main()
 | 
			
		|||
 | 
			
		||||
  // create fake process zero
 | 
			
		||||
  p = &proc[0];
 | 
			
		||||
  curproc = p;
 | 
			
		||||
  p->state = WAITING;
 | 
			
		||||
  p->sz = PAGE;
 | 
			
		||||
  p->mem = kalloc(p->sz);
 | 
			
		||||
| 
						 | 
				
			
			@ -39,14 +44,28 @@ main()
 | 
			
		|||
  p->tf->tf_eflags = FL_IF;
 | 
			
		||||
  setupsegs(p);
 | 
			
		||||
 | 
			
		||||
  p = newproc(&proc[0]);
 | 
			
		||||
  // xxx copy instructions to p->mem
 | 
			
		||||
  p->mem[0] = 0x90; // nop 
 | 
			
		||||
  p->mem[1] = 0x90; // nop 
 | 
			
		||||
  p->mem[2] = 0x42; // inc %edx
 | 
			
		||||
  p->mem[3] = 0x42; // inc %edx
 | 
			
		||||
  p = newproc();
 | 
			
		||||
 | 
			
		||||
  i = 0;
 | 
			
		||||
  p->mem[i++] = 0x90; // nop 
 | 
			
		||||
  p->mem[i++] = 0xb8; // mov ..., %eax
 | 
			
		||||
  p->mem[i++] = SYS_fork;
 | 
			
		||||
  p->mem[i++] = 0;
 | 
			
		||||
  p->mem[i++] = 0;
 | 
			
		||||
  p->mem[i++] = 0;
 | 
			
		||||
  p->mem[i++] = 0xcd; // int
 | 
			
		||||
  p->mem[i++] = T_SYSCALL;
 | 
			
		||||
  p->mem[i++] = 0xb8; // mov ..., %eax
 | 
			
		||||
  p->mem[i++] = SYS_exit;
 | 
			
		||||
  p->mem[i++] = 0;
 | 
			
		||||
  p->mem[i++] = 0;
 | 
			
		||||
  p->mem[i++] = 0;
 | 
			
		||||
  p->mem[i++] = 0xcd; // int
 | 
			
		||||
  p->mem[i++] = T_SYSCALL;
 | 
			
		||||
  p->tf->tf_eip = 0;
 | 
			
		||||
  p->tf->tf_esp = p->sz;
 | 
			
		||||
 | 
			
		||||
  swtch(&proc[0]);
 | 
			
		||||
  swtch();
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										35
									
								
								proc.c
									
										
									
									
									
								
							
							
						
						
									
										35
									
								
								proc.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
#include "defs.h"
 | 
			
		||||
 | 
			
		||||
struct proc proc[NPROC];
 | 
			
		||||
struct proc *curproc;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * set up a process's task state and segment descriptors
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +26,8 @@ setupsegs(struct proc *p)
 | 
			
		|||
  p->gdt[0] = SEG_NULL;
 | 
			
		||||
  p->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, 0);
 | 
			
		||||
  p->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0);
 | 
			
		||||
  p->gdt[SEG_TSS] = SEG16(STS_T32A, (unsigned) &p->ts, sizeof(p->ts), 0);
 | 
			
		||||
  p->gdt[SEG_TSS] = SEG16(STS_T32A, (unsigned) &p->ts,
 | 
			
		||||
                                sizeof(p->ts), 0);
 | 
			
		||||
  p->gdt[SEG_TSS].sd_s = 0;
 | 
			
		||||
  p->gdt[SEG_UCODE] = SEG(STA_X|STA_R, (unsigned)p->mem, p->sz, 3);
 | 
			
		||||
  p->gdt[SEG_UDATA] = SEG(STA_W, (unsigned)p->mem, p->sz, 3);
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +43,7 @@ extern void trapret();
 | 
			
		|||
 * sets up the stack to return as if from system call.
 | 
			
		||||
 */
 | 
			
		||||
struct proc *
 | 
			
		||||
newproc(struct proc *op)
 | 
			
		||||
newproc()
 | 
			
		||||
{
 | 
			
		||||
  struct proc *np;
 | 
			
		||||
  unsigned *sp;
 | 
			
		||||
| 
						 | 
				
			
			@ -52,29 +54,30 @@ newproc(struct proc *op)
 | 
			
		|||
  if(np >= &proc[NPROC])
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
  np->sz = op->sz;
 | 
			
		||||
  np->mem = kalloc(op->sz);
 | 
			
		||||
  np->sz = curproc->sz;
 | 
			
		||||
  np->mem = kalloc(curproc->sz);
 | 
			
		||||
  if(np->mem == 0)
 | 
			
		||||
    return 0;
 | 
			
		||||
  memcpy(np->mem, op->mem, np->sz);
 | 
			
		||||
  memcpy(np->mem, curproc->mem, np->sz);
 | 
			
		||||
  np->kstack = kalloc(KSTACKSIZE);
 | 
			
		||||
  if(np->kstack == 0){
 | 
			
		||||
    kfree(np->mem, op->sz);
 | 
			
		||||
    kfree(np->mem, curproc->sz);
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
  np->tf = (struct Trapframe *) (np->kstack + KSTACKSIZE - sizeof(struct Trapframe));
 | 
			
		||||
  setupsegs(np);
 | 
			
		||||
  np->state = RUNNABLE;
 | 
			
		||||
  
 | 
			
		||||
  // set up kernel stack to return to user space
 | 
			
		||||
  *(np->tf) = *(op->tf);
 | 
			
		||||
  np->tf = (struct Trapframe *) (np->kstack + KSTACKSIZE - sizeof(struct Trapframe));
 | 
			
		||||
  *(np->tf) = *(curproc->tf);
 | 
			
		||||
  sp = (unsigned *) np->tf;
 | 
			
		||||
  *(--sp) = (unsigned) &trapret;  // for return from swtch()
 | 
			
		||||
  *(--sp) = 0;  // previous bp for leave in swtch()
 | 
			
		||||
  np->esp = (unsigned) sp;
 | 
			
		||||
  np->ebp = (unsigned) sp;
 | 
			
		||||
 | 
			
		||||
  cprintf("newproc esp %x ebp %x mem %x\n", np->esp, np->ebp, np->mem);
 | 
			
		||||
  np->state = RUNNABLE;
 | 
			
		||||
 | 
			
		||||
  cprintf("newproc %x\n", np);
 | 
			
		||||
 | 
			
		||||
  return np;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -83,12 +86,12 @@ newproc(struct proc *op)
 | 
			
		|||
 * find a runnable process and switch to it.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
swtch(struct proc *op)
 | 
			
		||||
swtch()
 | 
			
		||||
{
 | 
			
		||||
  struct proc *np;
 | 
			
		||||
  
 | 
			
		||||
  while(1){
 | 
			
		||||
    for(np = op + 1; np != op; np++){
 | 
			
		||||
    for(np = curproc + 1; np != curproc; np++){
 | 
			
		||||
      if(np == &proc[NPROC])
 | 
			
		||||
        np = &proc[0];
 | 
			
		||||
      if(np->state == RUNNABLE)
 | 
			
		||||
| 
						 | 
				
			
			@ -99,10 +102,12 @@ swtch(struct proc *op)
 | 
			
		|||
    // idle...
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  op->ebp = read_ebp();
 | 
			
		||||
  op->esp = read_esp();
 | 
			
		||||
  curproc->ebp = read_ebp();
 | 
			
		||||
  curproc->esp = read_esp();
 | 
			
		||||
 | 
			
		||||
  cprintf("switching\n");
 | 
			
		||||
  cprintf("swtch %x -> %x\n", curproc, np);
 | 
			
		||||
 | 
			
		||||
  curproc = np;
 | 
			
		||||
 | 
			
		||||
  // XXX callee-saved registers?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								proc.h
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								proc.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -32,3 +32,4 @@ struct proc{
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
extern struct proc proc[];
 | 
			
		||||
extern struct proc *curproc;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								string.c
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								string.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,6 @@
 | 
			
		|||
#include "types.h"
 | 
			
		||||
#include "defs.h"
 | 
			
		||||
 | 
			
		||||
void *
 | 
			
		||||
memcpy(void *dst, void *src, unsigned n)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										50
									
								
								syscall.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								syscall.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
#include "types.h"
 | 
			
		||||
#include "param.h"
 | 
			
		||||
#include "mmu.h"
 | 
			
		||||
#include "proc.h"
 | 
			
		||||
#include "defs.h"
 | 
			
		||||
#include "x86.h"
 | 
			
		||||
#include "traps.h"
 | 
			
		||||
#include "syscall.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * User code makes a system call with INT T_SYSCALL.
 | 
			
		||||
 * System call number in %eax.
 | 
			
		||||
 * Arguments on the stack.
 | 
			
		||||
 *
 | 
			
		||||
 * Return value? Error indication? Errno?
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
sys_fork()
 | 
			
		||||
{
 | 
			
		||||
  newproc();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
sys_exit()
 | 
			
		||||
{
 | 
			
		||||
  curproc->state = UNUSED;
 | 
			
		||||
  // XXX free resources. notify parent. abandon children.
 | 
			
		||||
  swtch();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
syscall()
 | 
			
		||||
{
 | 
			
		||||
  int num = curproc->tf->tf_regs.reg_eax;
 | 
			
		||||
 | 
			
		||||
  cprintf("%x sys %d\n", curproc, num);
 | 
			
		||||
  switch(num){
 | 
			
		||||
  case SYS_fork:
 | 
			
		||||
    sys_fork();
 | 
			
		||||
    break;
 | 
			
		||||
  case SYS_exit:
 | 
			
		||||
    sys_exit();
 | 
			
		||||
    break;
 | 
			
		||||
  default:
 | 
			
		||||
    cprintf("unknown sys call %d\n", num);
 | 
			
		||||
    // XXX fault
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								syscall.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								syscall.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
#define SYS_fork 1
 | 
			
		||||
#define SYS_exit 2
 | 
			
		||||
							
								
								
									
										30
									
								
								trap.c
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								trap.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
#include "proc.h"
 | 
			
		||||
#include "defs.h"
 | 
			
		||||
#include "x86.h"
 | 
			
		||||
#include "traps.h"
 | 
			
		||||
 | 
			
		||||
struct Gatedesc idt[256];
 | 
			
		||||
struct Pseudodesc idt_pd = { 0, sizeof(idt) - 1, (unsigned) &idt };
 | 
			
		||||
| 
						 | 
				
			
			@ -12,29 +13,36 @@ extern unsigned vectors[]; /* vectors.S, array of 256 entry point addresses */
 | 
			
		|||
extern void trapenter();
 | 
			
		||||
extern void trapenter1();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int xx;
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
tinit()
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  xx = 0;
 | 
			
		||||
  for(i = 0; i < 256; i++){
 | 
			
		||||
    SETGATE(idt[i], 1, SEG_KCODE << 3, vectors[i], 3);
 | 
			
		||||
    SETGATE(idt[i], 1, SEG_KCODE << 3, vectors[i], 0);
 | 
			
		||||
  }
 | 
			
		||||
  SETGATE(idt[T_SYSCALL], T_SYSCALL, SEG_KCODE << 3, vectors[48], 3);
 | 
			
		||||
  asm volatile("lidt %0" : : "g" (idt_pd.pd_lim));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
trap(struct Trapframe *tf)
 | 
			
		||||
{
 | 
			
		||||
  /* which process are we running? */
 | 
			
		||||
  if(xx < 10)
 | 
			
		||||
    cprintf("%d\n", tf->tf_trapno);
 | 
			
		||||
  xx++;
 | 
			
		||||
  //while(1)
 | 
			
		||||
  //;
 | 
			
		||||
  int v = tf->tf_trapno;
 | 
			
		||||
  cprintf("trap %d eip %x:%x\n", tf->tf_trapno, tf->tf_cs, tf->tf_eip);
 | 
			
		||||
 | 
			
		||||
  if(v == T_SYSCALL){
 | 
			
		||||
    curproc->tf = tf;
 | 
			
		||||
    syscall();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(v == 32){
 | 
			
		||||
    // probably clock
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while(1)
 | 
			
		||||
    ;
 | 
			
		||||
  // XXX probably ought to lgdt on trap return
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ alltraps:
 | 
			
		|||
        movw %ax,%es        #  segments
 | 
			
		||||
        pushl %esp      # pass pointer to this trapframe
 | 
			
		||||
        call    trap        #  and call trap()
 | 
			
		||||
        addl $4, %esp
 | 
			
		||||
        # return falls through to trapret...
 | 
			
		||||
        
 | 
			
		||||
        .globl trapret
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										26
									
								
								traps.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								traps.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
// system defined:
 | 
			
		||||
#define T_DIVIDE     0		// divide error
 | 
			
		||||
#define T_DEBUG      1		// debug exception
 | 
			
		||||
#define T_NMI        2		// non-maskable interrupt
 | 
			
		||||
#define T_BRKPT      3		// breakpoint
 | 
			
		||||
#define T_OFLOW      4		// overflow
 | 
			
		||||
#define T_BOUND      5		// bounds check
 | 
			
		||||
#define T_ILLOP      6		// illegal opcode
 | 
			
		||||
#define T_DEVICE     7		// device not available 
 | 
			
		||||
#define T_DBLFLT     8		// double fault
 | 
			
		||||
/* #define T_COPROC  9 */	// reserved (not generated by recent processors)
 | 
			
		||||
#define T_TSS       10		// invalid task switch segment
 | 
			
		||||
#define T_SEGNP     11		// segment not present
 | 
			
		||||
#define T_STACK     12		// stack exception
 | 
			
		||||
#define T_GPFLT     13		// genernal protection fault
 | 
			
		||||
#define T_PGFLT     14		// page fault
 | 
			
		||||
/* #define T_RES    15 */	// reserved
 | 
			
		||||
#define T_FPERR     16		// floating point error
 | 
			
		||||
#define T_ALIGN     17		// aligment check
 | 
			
		||||
#define T_MCHK      18		// machine check
 | 
			
		||||
#define T_SIMDERR   19		// SIMD floating point error
 | 
			
		||||
 | 
			
		||||
// These are arbitrarily chosen, but with care not to overlap
 | 
			
		||||
// processor defined exceptions or interrupt vectors.
 | 
			
		||||
#define T_SYSCALL   48		// system call
 | 
			
		||||
#define T_DEFAULT   500		// catchall
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue