diff options
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | answers-traps.txt | 6 | ||||
| -rw-r--r-- | kernel/defs.h | 1 | ||||
| -rw-r--r-- | kernel/printf.c | 17 | ||||
| -rw-r--r-- | kernel/proc.c | 19 | ||||
| -rw-r--r-- | kernel/proc.h | 5 | ||||
| -rw-r--r-- | kernel/riscv.h | 9 | ||||
| -rw-r--r-- | kernel/syscall.c | 6 | ||||
| -rw-r--r-- | kernel/sysproc.c | 26 | ||||
| -rw-r--r-- | kernel/trap.c | 23 | ||||
| -rw-r--r-- | user/user.h | 2 | ||||
| -rwxr-xr-x | user/usys.pl | 2 | 
12 files changed, 116 insertions, 3 deletions
| @@ -208,7 +208,8 @@ endif  ifeq ($(LAB),traps)  UPROGS += \  	$U/_call\ -	$U/_bttest +	$U/_bttest\ +	$U/_alarmtest  endif  ifeq ($(LAB),lazy) diff --git a/answers-traps.txt b/answers-traps.txt new file mode 100644 index 0000000..dbb40f1 --- /dev/null +++ b/answers-traps.txt @@ -0,0 +1,6 @@ +a0~a7, a2 +0x26 (optimized during compile time), 0x14 (inline, unfolded) +0x666 +0x38 (next instruction) +He110 World +the value in register a2 diff --git a/kernel/defs.h b/kernel/defs.h index bd85d1f..04a0276 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -82,6 +82,7 @@ int             pipewrite(struct pipe*, uint64, int);  void            printf(char*, ...);  void            panic(char*) __attribute__((noreturn));  void            printfinit(void); +void            backtrace(void);  // proc.c  int             cpuid(void); diff --git a/kernel/printf.c b/kernel/printf.c index 1a50203..509c1c5 100644 --- a/kernel/printf.c +++ b/kernel/printf.c @@ -122,6 +122,8 @@ panic(char *s)    printf("panic: ");    printf(s);    printf("\n"); +  backtrace(); +    panicked = 1; // freeze uart output from other CPUs    for(;;)      ; @@ -133,3 +135,18 @@ printfinit(void)    initlock(&pr.lock, "pr");    pr.locking = 1;  } + +void +backtrace(void) +{ +  uint64 fp = r_fp(); +  printf("backtrace:\n"); +  uint64 stackpg = PGROUNDDOWN(fp); +  // Whereever fp points to should always live in the stack page +  while(PGROUNDDOWN(fp) == stackpg){ +    // print the return addr (stored in fp-8) +    printf("%p\n", *(uint64 *)(fp-8)); +    // load previous (upper stack) fp +    fp = *(uint64 *)(fp-16); +  } +} diff --git a/kernel/proc.c b/kernel/proc.c index 3d215a5..9a9bae9 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -39,6 +39,7 @@ proc_mapstacks(pagetable_t kpgtbl)      if(pa == 0)        panic("kalloc");      uint64 va = KSTACK((int) (p - proc)); +  p->alarm_tickspassed = 0;      kvmmap(kpgtbl, va, (uint64)pa, PGSIZE, PTE_R | PTE_W);    }  } @@ -140,6 +141,17 @@ found:    }    p->usyscall->pid = p->pid; +  // reset sigalarm props  +  p->alarm_interval = 0; +  p->alarm_handler = 0; +  p->alarm_tickspassed = 0; +  p->alarm_caninvoke = 1; +  if((p->atpfm = (struct trapframe *)kalloc()) == 0){ +    freeproc(p); +    release(&p->lock); +    return 0; +  } +    // An empty user page table.    p->pagetable = proc_pagetable(p);    if(p->pagetable == 0){ @@ -171,6 +183,13 @@ freeproc(struct proc *p)    p->usyscall = 0;    if(p->pagetable)      proc_freepagetable(p->pagetable, p->sz); +  if(p->atpfm) +    kfree((void*)p->atpfm); +  p->atpfm = 0; +  p->alarm_interval = 0; +  p->alarm_handler = 0; +  p->alarm_tickspassed = 0; +  p->alarm_caninvoke = 1;    p->pagetable = 0;    p->sz = 0;    p->pid = 0; diff --git a/kernel/proc.h b/kernel/proc.h index c816ae2..a195b02 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -106,4 +106,9 @@ struct proc {    struct file *ofile[NOFILE];  // Open files    struct inode *cwd;           // Current directory    char name[16];               // Process name (debugging) +  int alarm_interval;          // sigalarm syscall interval +  uint64 alarm_handler;        // sigalarm syscall handler +  int alarm_tickspassed;       // record how many ticks passed since last sigalarm handler call +  int alarm_caninvoke;         // prevent re-entrant calls to handler +  struct trapframe *atpfm;     // trapframe to resume after handling, must hold p->lock  }; diff --git a/kernel/riscv.h b/kernel/riscv.h index 33fa9ee..5ede50a 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -327,6 +327,15 @@ sfence_vma()    asm volatile("sfence.vma zero, zero");  } +// read the frame pointer of currently executing func +static inline uint64 +r_fp() +{ +  uint64 x; +  asm volatile("mv %0, s0" : "=r" (x) ); +  return x; +} +  typedef uint64 pte_t;  typedef uint64 *pagetable_t; // 512 PTEs diff --git a/kernel/syscall.c b/kernel/syscall.c index 394b980..8392eb4 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -110,6 +110,8 @@ extern uint64 sys_connect(void);  #ifdef LAB_PGTBL  extern uint64 sys_pgaccess(void);  #endif +extern uint64 sys_sigalarm(void); +extern uint64 sys_sigreturn(void);  // An array mapping syscall numbers from syscall.h  // to the function that handles the system call. @@ -143,6 +145,8 @@ static uint64 (*syscalls[])(void) = {  #endif  [SYS_trace]   sys_trace,  [SYS_sysinfo] sys_sysinfo, +[SYS_sigalarm] sys_sigalarm, +[SYS_sigreturn] sys_sigreturn,  };  // syscall name maps for SYS_trace: @@ -176,6 +180,8 @@ static char *syscall_names[] = {  #endif  [SYS_trace]   "trace",  [SYS_sysinfo] "sysinfo", +[SYS_sigalarm]  "sigalarm", +[SYS_sigreturn] "sigreturn",  }; diff --git a/kernel/sysproc.c b/kernel/sysproc.c index bd9d0f0..fac1d83 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -65,6 +65,9 @@ sys_sleep(void)      }      sleep(&ticks, &tickslock);    } + +  backtrace(); +    release(&tickslock);    return 0;  } @@ -124,3 +127,26 @@ sys_sysinfo(void)    return sys_info(si);  } +uint64 +sys_sigalarm(void) +{ +  struct proc *p = myproc(); +  uint64 handler; + +  argint(0, &p->alarm_interval); +  argaddr(1, &handler); +  p->alarm_handler = handler; + +  return 0; +} + +uint64 sys_sigreturn(void) +{ +  struct proc *p = myproc(); +  // retore saved trapframe to resume +  memmove(p->trapframe, p->atpfm, sizeof(struct trapframe)); +  p->alarm_tickspassed = 0; +  p->alarm_caninvoke = 1; +  // make sure return the original a0 in trapframe to pass test3 +  return p->trapframe->a0; +} diff --git a/kernel/trap.c b/kernel/trap.c index 512c850..eb8009f 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -6,6 +6,12 @@  #include "proc.h"  #include "defs.h" +/* + * Always remember that RISC-V disables interrupts when it starts to take a trap, + * so there's no need to call intr_off() at the beginning of trap handling. + * Reference: xv6-riscv-book 4.5 + */ +  struct spinlock tickslock;  uint ticks; @@ -76,9 +82,22 @@ usertrap(void)    if(killed(p))      exit(-1); -  // give up the CPU if this is a timer interrupt. -  if(which_dev == 2) +  if(which_dev == 2){ +    // timer interrupt +    if(p->alarm_interval > 0 && p->alarm_caninvoke){ +      // record sigalarm +      p->alarm_tickspassed++; +      if(p->alarm_tickspassed == p->alarm_interval){ +        // store original trapframe in p->atpfm +        memmove(p->atpfm, p->trapframe, sizeof(struct trapframe)); +        p->alarm_tickspassed = 0; +        p->alarm_caninvoke = 0; +        p->trapframe->epc = p->alarm_handler; +      } +    } +    // give up the CPU.      yield(); +  }    usertrapret();  } diff --git a/user/user.h b/user/user.h index a076f37..34591fd 100644 --- a/user/user.h +++ b/user/user.h @@ -33,6 +33,8 @@ int ugetpid(void);  #endif  int trace(int);  int sysinfo(struct sysinfo*); +int sigalarm(int ticks, void (*handler)()); +int sigreturn(void);  // ulib.c  int stat(const char*, struct stat*); diff --git a/user/usys.pl b/user/usys.pl index f084c63..33af0ad 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -40,3 +40,5 @@ entry("trace");  entry("sysinfo");  entry("connect");  entry("pgaccess"); +entry("sigalarm"); +entry("sigreturn"); | 
