summaryrefslogtreecommitdiff
path: root/trap.c
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2019-05-31 09:45:59 -0400
committerRobert Morris <[email protected]>2019-05-31 09:45:59 -0400
commit2ec1959fd1016a18ef3b2d154ce7076be8f237e4 (patch)
tree1aa75252085964283b3a2c735771f4da02346517 /trap.c
parent0f90388c893d1924e89e2e4d2187eda0004e9d73 (diff)
downloadxv6-labs-2ec1959fd1016a18ef3b2d154ce7076be8f237e4.tar.gz
xv6-labs-2ec1959fd1016a18ef3b2d154ce7076be8f237e4.tar.bz2
xv6-labs-2ec1959fd1016a18ef3b2d154ce7076be8f237e4.zip
fork/wait/exit work
Diffstat (limited to 'trap.c')
-rw-r--r--trap.c166
1 files changed, 85 insertions, 81 deletions
diff --git a/trap.c b/trap.c
index 4c58cb2..d0368ce 100644
--- a/trap.c
+++ b/trap.c
@@ -1,109 +1,113 @@
#include "types.h"
-#include "defs.h"
#include "param.h"
#include "memlayout.h"
-#include "mmu.h"
+#include "riscv.h"
#include "proc.h"
-#include "x86.h"
-#include "traps.h"
#include "spinlock.h"
+#include "defs.h"
-// Interrupt descriptor table (shared by all CPUs).
-struct intgate idt[256];
-extern uint64 vectors[]; // in vectors.S: array of 256 entry pointers
struct spinlock tickslock;
uint ticks;
+extern char trampstart[], trampvec[];
+
+void kerneltrap();
+
void
-tvinit(void)
+trapinit(void)
{
int i;
- for(i=0; i<256; i++) {
- idt[i] = INTDESC(SEG_KCODE, vectors[i], INT_P | SEG_INTR64);
- }
- idtinit();
-
+ // send interrupts and exceptions to kerneltrap().
+ w_stvec((uint64)kerneltrap);
+
initlock(&tickslock, "time");
}
+//
+// handle an interrupt, exception, or system call from user space.
+// called from trampoline.S
+//
void
-idtinit(void)
+usertrap(void)
{
- struct desctr dtr;
+ if((r_sstatus() & SSTATUS_SPP) != 0)
+ panic("usertrap: not from user mode");
+
+ // send interrupts and exceptions to kerneltrap(),
+ // since we're now in the kernel.
+ w_stvec((uint64)kerneltrap);
+
+ struct proc *p = myproc();
+
+ // save user program counter.
+ p->tf->epc = r_sepc();
+
+ if(r_scause() == 8){
+ // system call
+ printf("usertrap(): system call pid=%d syscall=%d\n", p->pid, p->tf->a7);
+
+ // sepc points to the ecall instruction,
+ // but we want to return to the next instruction.
+ p->tf->epc += 4;
- dtr.limit = sizeof(idt) - 1;
- dtr.base = (uint64)idt;
- lidt((void *)&dtr.limit);
+ syscall();
+ } else {
+ printf("usertrap(): unexpected scause 0x%x pid=%d\n", r_scause(), p->pid);
+ panic("usertrap");
+ }
+
+ usertrapret();
}
-//PAGEBREAK: 41
+//
+// return to user space
+//
void
-trap(struct trapframe *tf)
+usertrapret(void)
{
- switch(tf->trapno){
- case T_IRQ0 + IRQ_TIMER:
- if(cpuid() == 0){
- acquire(&tickslock);
- ticks++;
- wakeup(&ticks);
- release(&tickslock);
- }
- lapiceoi();
- break;
- case T_IRQ0 + IRQ_IDE:
- ideintr();
- lapiceoi();
- break;
- case T_IRQ0 + IRQ_IDE+1:
- // Bochs generates spurious IDE1 interrupts.
- break;
- case T_IRQ0 + IRQ_KBD:
- kbdintr();
- lapiceoi();
- break;
- case T_IRQ0 + IRQ_COM1:
- uartintr();
- lapiceoi();
- break;
- case T_IRQ0 + 7:
- case T_IRQ0 + IRQ_SPURIOUS:
- cprintf("cpu%d: spurious interrupt at %x:%x\n",
- cpuid(), tf->cs, tf->rip);
- lapiceoi();
- break;
-
- //PAGEBREAK: 13
- default:
- if(myproc() == 0 || (tf->cs&3) == 0){
- // In kernel, it must be our mistake.
- cprintf("unexpected trap %d from cpu %d rip %x (cr2=0x%x)\n",
- tf->trapno, cpuid(), tf->rip, rcr2());
- panic("trap");
- }
- // In user space, assume process misbehaved.
- cprintf("pid %d %s: trap %d err %d on cpu %d "
- "rip 0x%x addr 0x%x--kill proc\n",
- myproc()->pid, myproc()->name, tf->trapno,
- tf->err, cpuid(), tf->rip, rcr2());
- myproc()->killed = 1;
- }
+ struct proc *p = myproc();
+
+ // XXX turn off interrupts, since we're switching
+ // now from kerneltrap() to usertrap().
+
+ // send interrupts and exceptions to trampoline.S
+ w_stvec(TRAMPOLINE + (trampvec - trampstart));
+
+ // set up values that trampoline.S will need when
+ // the process next re-enters the kernel.
+ p->tf->kernel_satp = r_satp();
+ p->tf->kernel_sp = (uint64)p->kstack + PGSIZE;
+ p->tf->kernel_trap = (uint64)usertrap;
- // Force process exit if it has been killed and is in user space.
- // (If it is still executing in the kernel, let it keep running
- // until it gets to the regular system call return.)
- if(myproc() && myproc()->killed && (tf->cs&3) == DPL_USER)
- exit();
-
- // Force process to give up CPU on clock tick.
- // If interrupts were on while locks held, would need to check nlock.
- if(myproc() && myproc()->state == RUNNING &&
- tf->trapno == T_IRQ0+IRQ_TIMER)
- yield();
+ // set up the registers that trampoline.S's sret will use
+ // to get to user space.
- // Check if the process has been killed since we yielded
- if(myproc() && myproc()->killed && (tf->cs&3) == DPL_USER)
- exit();
+ // set S Previous Privilege mode to User.
+ unsigned long x = r_sstatus();
+ x &= ~SSTATUS_SPP; // clear SPP to 0 for user mode
+ w_sstatus(x);
+
+ // set S Exception Program Counter to the saved user pc.
+ w_sepc(p->tf->epc);
+
+ // tell trampline.S the user page table to switch to.
+ uint64 satp = MAKE_SATP(p->pagetable);
+
+ // jump to trampoline.S at the top of memory, which
+ // switches to the user page table, restores user registers,
+ // and switches to user mode with sret.
+ ((void (*)(uint64,uint64))TRAMPOLINE)(TRAMPOLINE - PGSIZE, satp);
}
+// interrupts and exceptions from kernel code go here,
+// on whatever the current kernel stack is.
+// must be 4-byte aligned to fit in stvec.
+void __attribute__ ((aligned (4)))
+kerneltrap()
+{
+ if((r_sstatus() & SSTATUS_SPP) == 0)
+ panic("kerneltrap: not from supervisor mode");
+ panic("kerneltrap");
+}