diff --git a/Makefile b/Makefile index 22636ea..2a8c3ce 100644 --- a/Makefile +++ b/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 diff --git a/Notes b/Notes index 4c06e74..06a9696 100644 --- a/Notes +++ b/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 diff --git a/defs.h b/defs.h index ec41bfe..ad51167 100644 --- a/defs.h +++ b/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); diff --git a/main.c b/main.c index 3c75389..6b07d83 100644 --- a/main.c +++ b/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; } diff --git a/proc.c b/proc.c index 2b43237..1e90e37 100644 --- a/proc.c +++ b/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? diff --git a/proc.h b/proc.h index e5c230c..39e1c49 100644 --- a/proc.h +++ b/proc.h @@ -32,3 +32,4 @@ struct proc{ }; extern struct proc proc[]; +extern struct proc *curproc; diff --git a/string.c b/string.c index aef4242..f27b025 100644 --- a/string.c +++ b/string.c @@ -1,3 +1,6 @@ +#include "types.h" +#include "defs.h" + void * memcpy(void *dst, void *src, unsigned n) { diff --git a/syscall.c b/syscall.c new file mode 100644 index 0000000..9cb20dc --- /dev/null +++ b/syscall.c @@ -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; + } +} diff --git a/syscall.h b/syscall.h new file mode 100644 index 0000000..3155dbd --- /dev/null +++ b/syscall.h @@ -0,0 +1,2 @@ +#define SYS_fork 1 +#define SYS_exit 2 diff --git a/trap.c b/trap.c index ace4c95..89c6bf5 100644 --- a/trap.c +++ b/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 } diff --git a/trapasm.S b/trapasm.S index c75ab39..c01cec0 100644 --- a/trapasm.S +++ b/trapasm.S @@ -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 diff --git a/traps.h b/traps.h new file mode 100644 index 0000000..a81903c --- /dev/null +++ b/traps.h @@ -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