primitive fork and exit system calls
This commit is contained in:
parent
cb83c71628
commit
a4c03dea09
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;
|
||||
}
|
||||
}
|
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…
Reference in a new issue