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
|
CC = i386-jos-elf-gcc
|
||||||
LD = i386-jos-elf-ld
|
LD = i386-jos-elf-ld
|
||||||
OBJCOPY = i386-jos-elf-objcopy
|
OBJCOPY = i386-jos-elf-objcopy
|
||||||
OBJDUMP = i386-jos-elf-objdump
|
OBJDUMP = i386-jos-elf-objdump
|
||||||
CFLAGS = -nostdinc -I. -O
|
CFLAGS = -nostdinc -I. -O -Wall
|
||||||
|
|
||||||
xv6.img : bootblock kernel
|
xv6.img : bootblock kernel
|
||||||
dd if=/dev/zero of=xv6.img count=10000
|
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 #?
|
pass curproc explicitly, or implicit from cpu #?
|
||||||
e.g. argument to newproc()?
|
e.g. argument to newproc()?
|
||||||
|
hmm, you need a global curproc[cpu] for trap() &c
|
||||||
|
|
||||||
test stack expansion
|
test stack expansion
|
||||||
test running out of memory, process slots
|
test running out of memory, process slots
|
||||||
|
|
16
defs.h
16
defs.h
|
@ -1,6 +1,7 @@
|
||||||
// kalloc.c
|
// kalloc.c
|
||||||
char *kalloc(int n);
|
char *kalloc(int n);
|
||||||
void kfree(char *cp, int len);
|
void kfree(char *cp, int len);
|
||||||
|
void kinit(void);
|
||||||
|
|
||||||
// console.c
|
// console.c
|
||||||
void cprintf(char *fmt, ...);
|
void cprintf(char *fmt, ...);
|
||||||
|
@ -8,5 +9,16 @@ void panic(char *s);
|
||||||
|
|
||||||
// proc.c
|
// proc.c
|
||||||
struct proc;
|
struct proc;
|
||||||
void setupsegs(struct proc *p);
|
void setupsegs(struct proc *);
|
||||||
struct proc * newproc(struct proc *op);
|
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 "proc.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "x86.h"
|
#include "x86.h"
|
||||||
|
#include "traps.h"
|
||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
extern char edata[], end[];
|
extern char edata[], end[];
|
||||||
|
|
||||||
|
int
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
// clear BSS
|
// clear BSS
|
||||||
memset(edata, 0, end - edata);
|
memset(edata, 0, end - edata);
|
||||||
|
@ -27,6 +31,7 @@ main()
|
||||||
|
|
||||||
// create fake process zero
|
// create fake process zero
|
||||||
p = &proc[0];
|
p = &proc[0];
|
||||||
|
curproc = p;
|
||||||
p->state = WAITING;
|
p->state = WAITING;
|
||||||
p->sz = PAGE;
|
p->sz = PAGE;
|
||||||
p->mem = kalloc(p->sz);
|
p->mem = kalloc(p->sz);
|
||||||
|
@ -39,14 +44,28 @@ main()
|
||||||
p->tf->tf_eflags = FL_IF;
|
p->tf->tf_eflags = FL_IF;
|
||||||
setupsegs(p);
|
setupsegs(p);
|
||||||
|
|
||||||
p = newproc(&proc[0]);
|
p = newproc();
|
||||||
// xxx copy instructions to p->mem
|
|
||||||
p->mem[0] = 0x90; // nop
|
i = 0;
|
||||||
p->mem[1] = 0x90; // nop
|
p->mem[i++] = 0x90; // nop
|
||||||
p->mem[2] = 0x42; // inc %edx
|
p->mem[i++] = 0xb8; // mov ..., %eax
|
||||||
p->mem[3] = 0x42; // inc %edx
|
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_eip = 0;
|
||||||
p->tf->tf_esp = p->sz;
|
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"
|
#include "defs.h"
|
||||||
|
|
||||||
struct proc proc[NPROC];
|
struct proc proc[NPROC];
|
||||||
|
struct proc *curproc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set up a process's task state and segment descriptors
|
* 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[0] = SEG_NULL;
|
||||||
p->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, 0);
|
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_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_TSS].sd_s = 0;
|
||||||
p->gdt[SEG_UCODE] = SEG(STA_X|STA_R, (unsigned)p->mem, p->sz, 3);
|
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);
|
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.
|
* sets up the stack to return as if from system call.
|
||||||
*/
|
*/
|
||||||
struct proc *
|
struct proc *
|
||||||
newproc(struct proc *op)
|
newproc()
|
||||||
{
|
{
|
||||||
struct proc *np;
|
struct proc *np;
|
||||||
unsigned *sp;
|
unsigned *sp;
|
||||||
|
@ -52,29 +54,30 @@ newproc(struct proc *op)
|
||||||
if(np >= &proc[NPROC])
|
if(np >= &proc[NPROC])
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
np->sz = op->sz;
|
np->sz = curproc->sz;
|
||||||
np->mem = kalloc(op->sz);
|
np->mem = kalloc(curproc->sz);
|
||||||
if(np->mem == 0)
|
if(np->mem == 0)
|
||||||
return 0;
|
return 0;
|
||||||
memcpy(np->mem, op->mem, np->sz);
|
memcpy(np->mem, curproc->mem, np->sz);
|
||||||
np->kstack = kalloc(KSTACKSIZE);
|
np->kstack = kalloc(KSTACKSIZE);
|
||||||
if(np->kstack == 0){
|
if(np->kstack == 0){
|
||||||
kfree(np->mem, op->sz);
|
kfree(np->mem, curproc->sz);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
np->tf = (struct Trapframe *) (np->kstack + KSTACKSIZE - sizeof(struct Trapframe));
|
|
||||||
setupsegs(np);
|
setupsegs(np);
|
||||||
np->state = RUNNABLE;
|
|
||||||
|
|
||||||
// set up kernel stack to return to user space
|
// 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 *) np->tf;
|
||||||
*(--sp) = (unsigned) &trapret; // for return from swtch()
|
*(--sp) = (unsigned) &trapret; // for return from swtch()
|
||||||
*(--sp) = 0; // previous bp for leave in swtch()
|
*(--sp) = 0; // previous bp for leave in swtch()
|
||||||
np->esp = (unsigned) sp;
|
np->esp = (unsigned) sp;
|
||||||
np->ebp = (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;
|
return np;
|
||||||
}
|
}
|
||||||
|
@ -83,12 +86,12 @@ newproc(struct proc *op)
|
||||||
* find a runnable process and switch to it.
|
* find a runnable process and switch to it.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
swtch(struct proc *op)
|
swtch()
|
||||||
{
|
{
|
||||||
struct proc *np;
|
struct proc *np;
|
||||||
|
|
||||||
while(1){
|
while(1){
|
||||||
for(np = op + 1; np != op; np++){
|
for(np = curproc + 1; np != curproc; np++){
|
||||||
if(np == &proc[NPROC])
|
if(np == &proc[NPROC])
|
||||||
np = &proc[0];
|
np = &proc[0];
|
||||||
if(np->state == RUNNABLE)
|
if(np->state == RUNNABLE)
|
||||||
|
@ -99,10 +102,12 @@ swtch(struct proc *op)
|
||||||
// idle...
|
// idle...
|
||||||
}
|
}
|
||||||
|
|
||||||
op->ebp = read_ebp();
|
curproc->ebp = read_ebp();
|
||||||
op->esp = read_esp();
|
curproc->esp = read_esp();
|
||||||
|
|
||||||
cprintf("switching\n");
|
cprintf("swtch %x -> %x\n", curproc, np);
|
||||||
|
|
||||||
|
curproc = np;
|
||||||
|
|
||||||
// XXX callee-saved registers?
|
// XXX callee-saved registers?
|
||||||
|
|
||||||
|
|
1
proc.h
1
proc.h
|
@ -32,3 +32,4 @@ struct proc{
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct proc 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 *
|
void *
|
||||||
memcpy(void *dst, void *src, unsigned n)
|
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 "proc.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "x86.h"
|
#include "x86.h"
|
||||||
|
#include "traps.h"
|
||||||
|
|
||||||
struct Gatedesc idt[256];
|
struct Gatedesc idt[256];
|
||||||
struct Pseudodesc idt_pd = { 0, sizeof(idt) - 1, (unsigned) &idt };
|
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 trapenter();
|
||||||
extern void trapenter1();
|
extern void trapenter1();
|
||||||
|
|
||||||
|
|
||||||
int xx;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
tinit()
|
tinit()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
xx = 0;
|
|
||||||
for(i = 0; i < 256; i++){
|
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));
|
asm volatile("lidt %0" : : "g" (idt_pd.pd_lim));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
trap(struct Trapframe *tf)
|
trap(struct Trapframe *tf)
|
||||||
{
|
{
|
||||||
/* which process are we running? */
|
int v = tf->tf_trapno;
|
||||||
if(xx < 10)
|
cprintf("trap %d eip %x:%x\n", tf->tf_trapno, tf->tf_cs, tf->tf_eip);
|
||||||
cprintf("%d\n", tf->tf_trapno);
|
|
||||||
xx++;
|
if(v == T_SYSCALL){
|
||||||
//while(1)
|
curproc->tf = tf;
|
||||||
//;
|
syscall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(v == 32){
|
||||||
|
// probably clock
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
;
|
||||||
// XXX probably ought to lgdt on trap return
|
// XXX probably ought to lgdt on trap return
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ alltraps:
|
||||||
movw %ax,%es # segments
|
movw %ax,%es # segments
|
||||||
pushl %esp # pass pointer to this trapframe
|
pushl %esp # pass pointer to this trapframe
|
||||||
call trap # and call trap()
|
call trap # and call trap()
|
||||||
|
addl $4, %esp
|
||||||
# return falls through to trapret...
|
# return falls through to trapret...
|
||||||
|
|
||||||
.globl 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