diff --git a/defs.h b/defs.h index fd9ecb4..763eb75 100644 --- a/defs.h +++ b/defs.h @@ -9,6 +9,7 @@ struct spinlock; struct sleeplock; struct stat; struct superblock; +struct sysframe; // bio.c void binit(void); @@ -156,7 +157,7 @@ int argaddr(int, uint64 *); int fetchint(uint64, int*); int fetchstr(uint64, char**); int fetchaddr(uint64, uint64*); -void syscall(void); +void syscall(struct sysframe*); // timer.c void timerinit(void); diff --git a/exec.c b/exec.c index b1a9229..743437a 100644 --- a/exec.c +++ b/exec.c @@ -85,8 +85,8 @@ exec(char *path, char **argv) ustack[1] = argc; ustack[2] = sp - (argc+1)*sizeof(uint64); // argv pointer - curproc->tf->rdi = argc; - curproc->tf->rsi = sp - (argc+1)*sizeof(uint64); + curproc->sf->rdi = argc; + curproc->sf->rsi = sp - (argc+1)*sizeof(uint64); sp -= (3+argc+1) * sizeof(uint64); if(copyout(pgdir, sp, ustack, (3+argc+1)*sizeof(uint64)) < 0) @@ -102,9 +102,8 @@ exec(char *path, char **argv) oldpgdir = curproc->pgdir; curproc->pgdir = pgdir; curproc->sz = sz; - curproc->tf->rip = elf.entry; // main - curproc->tf->rcx = elf.entry; - curproc->tf->rsp = sp; + curproc->sf->rcx = elf.entry; // main + curproc->sf->rsp = sp; switchuvm(curproc); freevm(oldpgdir, oldsz); return 0; diff --git a/proc.c b/proc.c index 14c3da8..55e435c 100644 --- a/proc.c +++ b/proc.c @@ -17,10 +17,8 @@ static struct proc *initproc; int nextpid = 1; extern void forkret(void); -// we can return two ways out of the kernel and -// for new processes we can choose either way +// for returning out of the kernel extern void sysexit(void); -extern void trapret(void); static void wakeup1(void *chan); @@ -102,16 +100,16 @@ found: } sp = p->kstack + KSTACKSIZE; - // Leave room for trap frame. - sp -= sizeof *p->tf; + // Leave room for syscall frame. + sp -= sizeof *p->sf; if ((uint64) sp % 16) panic("misaligned sp"); - p->tf = (struct trapframe*)sp; + p->sf = (struct sysframe*)sp; // Set up new context to start executing at forkret, - // which returns to trapret. + // which returns to sysexit. sp -= sizeof(uint64); *(uint64*)sp = (uint64)sysexit; @@ -138,12 +136,10 @@ userinit(void) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, (uint64)_binary_initcode_size); p->sz = PGSIZE; - memset(p->tf, 0, sizeof(*p->tf)); - p->tf->cs = SEG_UCODE | DPL_USER; - p->tf->ss = SEG_UDATA | DPL_USER; - p->tf->r11 = FL_IF; - p->tf->rsp = PGSIZE; - p->tf->rcx = 0; // beginning of initcode.S + memset(p->sf, 0, sizeof(*p->sf)); + p->sf->r11 = FL_IF; + p->sf->rsp = PGSIZE; + p->sf->rcx = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); @@ -204,10 +200,10 @@ fork(void) } np->sz = curproc->sz; np->parent = curproc; - *np->tf = *curproc->tf; + *np->sf = *curproc->sf; // Clear %eax so that fork returns 0 in the child. - np->tf->rax = 0; + np->sf->rax = 0; for(i = 0; i < NOFILE; i++) if(curproc->ofile[i]) diff --git a/proc.h b/proc.h index e421e44..9261766 100644 --- a/proc.h +++ b/proc.h @@ -47,7 +47,7 @@ struct proc { enum procstate state; // Process state int pid; // Process ID 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 void *chan; // If non-zero, sleeping on chan int killed; // If non-zero, have been killed diff --git a/syscall.c b/syscall.c index 481bde8..b815f28 100644 --- a/syscall.c +++ b/syscall.c @@ -62,17 +62,17 @@ fetcharg(int n) struct proc *curproc = myproc(); switch (n) { case 0: - return curproc->tf->rdi; + return curproc->sf->rdi; case 1: - return curproc->tf->rsi; + return curproc->sf->rsi; case 2: - return curproc->tf->rdx; + return curproc->sf->rdx; case 3: - return curproc->tf->r10; + return curproc->sf->r10; case 4: - return curproc->tf->r8; + return curproc->sf->r8; case 5: - return curproc->tf->r9; + return curproc->sf->r9; } panic("fetcharg"); return -1; @@ -169,18 +169,31 @@ static int (*syscalls[])(void) = { [SYS_close] sys_close, }; -void -syscall(void) +static void +dosyscall(void) { int num; struct proc *curproc = myproc(); - num = curproc->tf->rax; + num = curproc->sf->rax; if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { - curproc->tf->rax = syscalls[num](); + curproc->sf->rax = syscalls[num](); } else { cprintf("%d %s: unknown sys call %d\n", 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; +} + diff --git a/trap.c b/trap.c index afa0e18..4c58cb2 100644 --- a/trap.c +++ b/trap.c @@ -41,16 +41,6 @@ idtinit(void) void 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){ case T_IRQ0 + IRQ_TIMER: if(cpuid() == 0){ diff --git a/trapasm.S b/trapasm.S index fc71336..6b6b567 100644 --- a/trapasm.S +++ b/trapasm.S @@ -25,7 +25,7 @@ alltraps: push %rbx push %rax - cmpw $KCSEG, CSOFF(%rsp) # compare to saved cs + cmpw $SEG_KCODE, CSOFF(%rsp) # compare to saved cs jz 1f swapgs @@ -36,7 +36,7 @@ alltraps: .globl trapret trapret: cli - cmpw $KCSEG, CSOFF(%rsp) # compare to saved cs + cmpw $SEG_KCODE, CSOFF(%rsp) # compare to saved cs jz 1f swapgs @@ -58,11 +58,12 @@ trapret: add $16, %rsp # discard trapnum and errorcode iretq + #PAGEBREAK! -# syscall_entry jumps here after syscall instruction +# syscall jumps here after syscall instruction .globl sysentry -sysentry: # Build trap frame. +sysentry: # Build syscall frame. // load kernel stack address swapgs movq %rax, %gs:0 // save %rax in syscallno of cpu entry @@ -75,63 +76,54 @@ sysentry: # Build trap frame. movq %rax, %rsp movq %gs:0, %rax // restore rax - // push usp to make a valid trapframe - push $(UDSEG|0x3) push %gs:8 - // safe eflags and eip - push %r11 - push $(UCSEG|0x3) push %rcx - // push errno and trapno to make stack look like a trap - push $0 - push $64 + push %r11 + push %rax - // 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 %rdx - push %rcx - push %rbx - push %rax + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + push %r9 + push %r8 + push %r10 + push %rdx + push %rsi + push %rdi + mov %rsp, %rdi # frame in arg1 - call trap -#PAGEBREAK! - -# Return falls through to trapret... + call syscall + # fall through to sysexit + .globl sysexit sysexit: # to make sure we don't get any interrupts on the user stack while in # supervisor mode. insufficient? (see vunerability reports for sysret) cli - - pop %rax - pop %rbx - pop %rcx - pop %rdx - pop %rbp - pop %rsi + pop %rdi + pop %rsi + pop %rdx + pop %r10 pop %r8 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 # there are two more values on the stack, but we don't care about them swapgs diff --git a/x86.h b/x86.h index 17bec0d..1ae64ac 100644 --- a/x86.h +++ b/x86.h @@ -166,6 +166,33 @@ struct trapframe { uint64 ss; }__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 #define TF_CS 144 // offset in trapframe for saved cs