summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMole Shang <[email protected]>2024-02-11 14:41:35 +0800
committerMole Shang <[email protected]>2024-02-11 14:41:35 +0800
commit48a5e34fcd07852b4a68825ce8e37feb6f6d04d7 (patch)
treeb6ec41ca1889db0122d754b0083c7d1d87cb0818
parent3673a2cdfb30e1e3936e695a3fb8adee74488d6b (diff)
downloadxv6-labs-traps.tar.gz
xv6-labs-traps.tar.bz2
xv6-labs-traps.zip
lab traps: finishtraps
-rw-r--r--Makefile3
-rw-r--r--answers-traps.txt6
-rw-r--r--kernel/defs.h1
-rw-r--r--kernel/printf.c17
-rw-r--r--kernel/proc.c19
-rw-r--r--kernel/proc.h5
-rw-r--r--kernel/riscv.h9
-rw-r--r--kernel/syscall.c6
-rw-r--r--kernel/sysproc.c26
-rw-r--r--kernel/trap.c23
-rw-r--r--user/user.h2
-rwxr-xr-xuser/usys.pl2
12 files changed, 116 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 043a9ac..ecb0f9e 100644
--- a/Makefile
+++ b/Makefile
@@ -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");