Separate system call path from trap path. Passes usertests on 1 and 2 cpus.

This commit is contained in:
Frans Kaashoek 2018-10-09 14:28:54 -04:00
parent f241e67d91
commit 54e6f829e4
8 changed files with 106 additions and 88 deletions

3
defs.h
View file

@ -9,6 +9,7 @@ struct spinlock;
struct sleeplock; struct sleeplock;
struct stat; struct stat;
struct superblock; struct superblock;
struct sysframe;
// bio.c // bio.c
void binit(void); void binit(void);
@ -156,7 +157,7 @@ int argaddr(int, uint64 *);
int fetchint(uint64, int*); int fetchint(uint64, int*);
int fetchstr(uint64, char**); int fetchstr(uint64, char**);
int fetchaddr(uint64, uint64*); int fetchaddr(uint64, uint64*);
void syscall(void); void syscall(struct sysframe*);
// timer.c // timer.c
void timerinit(void); void timerinit(void);

9
exec.c
View file

@ -85,8 +85,8 @@ exec(char *path, char **argv)
ustack[1] = argc; ustack[1] = argc;
ustack[2] = sp - (argc+1)*sizeof(uint64); // argv pointer ustack[2] = sp - (argc+1)*sizeof(uint64); // argv pointer
curproc->tf->rdi = argc; curproc->sf->rdi = argc;
curproc->tf->rsi = sp - (argc+1)*sizeof(uint64); curproc->sf->rsi = sp - (argc+1)*sizeof(uint64);
sp -= (3+argc+1) * sizeof(uint64); sp -= (3+argc+1) * sizeof(uint64);
if(copyout(pgdir, sp, ustack, (3+argc+1)*sizeof(uint64)) < 0) if(copyout(pgdir, sp, ustack, (3+argc+1)*sizeof(uint64)) < 0)
@ -102,9 +102,8 @@ exec(char *path, char **argv)
oldpgdir = curproc->pgdir; oldpgdir = curproc->pgdir;
curproc->pgdir = pgdir; curproc->pgdir = pgdir;
curproc->sz = sz; curproc->sz = sz;
curproc->tf->rip = elf.entry; // main curproc->sf->rcx = elf.entry; // main
curproc->tf->rcx = elf.entry; curproc->sf->rsp = sp;
curproc->tf->rsp = sp;
switchuvm(curproc); switchuvm(curproc);
freevm(oldpgdir, oldsz); freevm(oldpgdir, oldsz);
return 0; return 0;

26
proc.c
View file

@ -17,10 +17,8 @@ static struct proc *initproc;
int nextpid = 1; int nextpid = 1;
extern void forkret(void); extern void forkret(void);
// we can return two ways out of the kernel and // for returning out of the kernel
// for new processes we can choose either way
extern void sysexit(void); extern void sysexit(void);
extern void trapret(void);
static void wakeup1(void *chan); static void wakeup1(void *chan);
@ -102,16 +100,16 @@ found:
} }
sp = p->kstack + KSTACKSIZE; sp = p->kstack + KSTACKSIZE;
// Leave room for trap frame. // Leave room for syscall frame.
sp -= sizeof *p->tf; sp -= sizeof *p->sf;
if ((uint64) sp % 16) if ((uint64) sp % 16)
panic("misaligned sp"); panic("misaligned sp");
p->tf = (struct trapframe*)sp; p->sf = (struct sysframe*)sp;
// Set up new context to start executing at forkret, // Set up new context to start executing at forkret,
// which returns to trapret. // which returns to sysexit.
sp -= sizeof(uint64); sp -= sizeof(uint64);
*(uint64*)sp = (uint64)sysexit; *(uint64*)sp = (uint64)sysexit;
@ -138,12 +136,10 @@ userinit(void)
panic("userinit: out of memory?"); panic("userinit: out of memory?");
inituvm(p->pgdir, _binary_initcode_start, (uint64)_binary_initcode_size); inituvm(p->pgdir, _binary_initcode_start, (uint64)_binary_initcode_size);
p->sz = PGSIZE; p->sz = PGSIZE;
memset(p->tf, 0, sizeof(*p->tf)); memset(p->sf, 0, sizeof(*p->sf));
p->tf->cs = SEG_UCODE | DPL_USER; p->sf->r11 = FL_IF;
p->tf->ss = SEG_UDATA | DPL_USER; p->sf->rsp = PGSIZE;
p->tf->r11 = FL_IF; p->sf->rcx = 0; // beginning of initcode.S
p->tf->rsp = PGSIZE;
p->tf->rcx = 0; // beginning of initcode.S
safestrcpy(p->name, "initcode", sizeof(p->name)); safestrcpy(p->name, "initcode", sizeof(p->name));
p->cwd = namei("/"); p->cwd = namei("/");
@ -204,10 +200,10 @@ fork(void)
} }
np->sz = curproc->sz; np->sz = curproc->sz;
np->parent = curproc; np->parent = curproc;
*np->tf = *curproc->tf; *np->sf = *curproc->sf;
// Clear %eax so that fork returns 0 in the child. // Clear %eax so that fork returns 0 in the child.
np->tf->rax = 0; np->sf->rax = 0;
for(i = 0; i < NOFILE; i++) for(i = 0; i < NOFILE; i++)
if(curproc->ofile[i]) if(curproc->ofile[i])

2
proc.h
View file

@ -47,7 +47,7 @@ struct proc {
enum procstate state; // Process state enum procstate state; // Process state
int pid; // Process ID int pid; // Process ID
struct proc *parent; // Parent process struct proc *parent; // Parent process
struct trapframe *tf; // Trap frame for current syscall struct sysframe *sf; // Syscall frame for current syscall
struct context *context; // swtch() here to run process struct context *context; // swtch() here to run process
void *chan; // If non-zero, sleeping on chan void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed int killed; // If non-zero, have been killed

View file

@ -62,17 +62,17 @@ fetcharg(int n)
struct proc *curproc = myproc(); struct proc *curproc = myproc();
switch (n) { switch (n) {
case 0: case 0:
return curproc->tf->rdi; return curproc->sf->rdi;
case 1: case 1:
return curproc->tf->rsi; return curproc->sf->rsi;
case 2: case 2:
return curproc->tf->rdx; return curproc->sf->rdx;
case 3: case 3:
return curproc->tf->r10; return curproc->sf->r10;
case 4: case 4:
return curproc->tf->r8; return curproc->sf->r8;
case 5: case 5:
return curproc->tf->r9; return curproc->sf->r9;
} }
panic("fetcharg"); panic("fetcharg");
return -1; return -1;
@ -169,18 +169,31 @@ static int (*syscalls[])(void) = {
[SYS_close] sys_close, [SYS_close] sys_close,
}; };
void static void
syscall(void) dosyscall(void)
{ {
int num; int num;
struct proc *curproc = myproc(); struct proc *curproc = myproc();
num = curproc->tf->rax; num = curproc->sf->rax;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
curproc->tf->rax = syscalls[num](); curproc->sf->rax = syscalls[num]();
} else { } else {
cprintf("%d %s: unknown sys call %d\n", cprintf("%d %s: unknown sys call %d\n",
curproc->pid, curproc->name, num); curproc->pid, curproc->name, num);
curproc->tf->rax = -1; curproc->sf->rax = -1;
} }
} }
void
syscall(struct sysframe *sf)
{
if(myproc()->killed)
exit();
myproc()->sf = sf;
dosyscall();
if(myproc()->killed)
exit();
return;
}

10
trap.c
View file

@ -41,16 +41,6 @@ idtinit(void)
void void
trap(struct trapframe *tf) trap(struct trapframe *tf)
{ {
if(tf->trapno == T_SYSCALL){
if(myproc()->killed)
exit();
myproc()->tf = tf;
syscall();
if(myproc()->killed)
exit();
return;
}
switch(tf->trapno){ switch(tf->trapno){
case T_IRQ0 + IRQ_TIMER: case T_IRQ0 + IRQ_TIMER:
if(cpuid() == 0){ if(cpuid() == 0){

View file

@ -25,7 +25,7 @@ alltraps:
push %rbx push %rbx
push %rax push %rax
cmpw $KCSEG, CSOFF(%rsp) # compare to saved cs cmpw $SEG_KCODE, CSOFF(%rsp) # compare to saved cs
jz 1f jz 1f
swapgs swapgs
@ -36,7 +36,7 @@ alltraps:
.globl trapret .globl trapret
trapret: trapret:
cli cli
cmpw $KCSEG, CSOFF(%rsp) # compare to saved cs cmpw $SEG_KCODE, CSOFF(%rsp) # compare to saved cs
jz 1f jz 1f
swapgs swapgs
@ -58,11 +58,12 @@ trapret:
add $16, %rsp # discard trapnum and errorcode add $16, %rsp # discard trapnum and errorcode
iretq iretq
#PAGEBREAK! #PAGEBREAK!
# syscall_entry jumps here after syscall instruction # syscall jumps here after syscall instruction
.globl sysentry .globl sysentry
sysentry: # Build trap frame. sysentry: # Build syscall frame.
// load kernel stack address // load kernel stack address
swapgs swapgs
movq %rax, %gs:0 // save %rax in syscallno of cpu entry movq %rax, %gs:0 // save %rax in syscallno of cpu entry
@ -75,63 +76,54 @@ sysentry: # Build trap frame.
movq %rax, %rsp movq %rax, %rsp
movq %gs:0, %rax // restore rax movq %gs:0, %rax // restore rax
// push usp to make a valid trapframe
push $(UDSEG|0x3)
push %gs:8 push %gs:8
// safe eflags and eip
push %r11
push $(UCSEG|0x3)
push %rcx push %rcx
// push errno and trapno to make stack look like a trap push %r11
push $0 push %rax
push $64
// push values on kernel stack
push %r15
push %r14
push %r13
push %r12
push %r11
push %r10
push %r9
push %r8
push %rdi
push %rsi
push %rbp push %rbp
push %rdx push %rbx
push %rcx push %r12
push %rbx push %r13
push %rax push %r14
push %r15
push %r9
push %r8
push %r10
push %rdx
push %rsi
push %rdi
mov %rsp, %rdi # frame in arg1 mov %rsp, %rdi # frame in arg1
call trap call syscall
#PAGEBREAK! # fall through to sysexit
# Return falls through to trapret...
.globl sysexit .globl sysexit
sysexit: sysexit:
# to make sure we don't get any interrupts on the user stack while in # to make sure we don't get any interrupts on the user stack while in
# supervisor mode. insufficient? (see vunerability reports for sysret) # supervisor mode. insufficient? (see vunerability reports for sysret)
cli cli
pop %rax
pop %rbx
pop %rcx
pop %rdx
pop %rbp
pop %rsi
pop %rdi pop %rdi
pop %rsi
pop %rdx
pop %r10
pop %r8 pop %r8
pop %r9 pop %r9
pop %r10
pop %r11
pop %r12
pop %r13
pop %r14
pop %r15
add $(5*8), %rsp # discard trapnum, errorcode, rip, cs and rflags pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %rbp
pop %rax
pop %r11
pop %rcx
mov (%rsp),%rsp # switch to the user stack mov (%rsp),%rsp # switch to the user stack
# there are two more values on the stack, but we don't care about them # there are two more values on the stack, but we don't care about them
swapgs swapgs

27
x86.h
View file

@ -166,6 +166,33 @@ struct trapframe {
uint64 ss; uint64 ss;
}__attribute__((packed)); }__attribute__((packed));
struct sysframe {
// arguments
uint64 rdi;
uint64 rsi;
uint64 rdx;
uint64 r10;
uint64 r8;
uint64 r9;
// callee-saved registers
uint64 r15;
uint64 r14;
uint64 r13;
uint64 r12;
uint64 rbx;
uint64 rbp;
// return value
uint64 rax;
// syscall registers
uint64 r11; // eflags
uint64 rcx; // rip
uint64 rsp;
}__attribute__((packed));
#endif #endif
#define TF_CS 144 // offset in trapframe for saved cs #define TF_CS 144 // offset in trapframe for saved cs