日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

6.S081 Xv6 Lab 4 traps

發(fā)布時(shí)間:2023/12/9 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 6.S081 Xv6 Lab 4 traps 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Lab: traps

6.S081 的 Xv6 RISC-V Lab traps,實(shí)驗(yàn)內(nèi)容:

  • https://pdos.csail.mit.edu/6.S081/2020/labs/traps.html
$ git fetch $ git checkout traps $ make clean

RISC-V assembly

這題沒什么具體要做的,就看一看,跟著題目學(xué)一下 RISC- V 匯編。

Backtrace

這題主要是實(shí)現(xiàn)打印函數(shù)棧。就是 GDB 里面 bt 的這種效果:

(gdb) bt #0 fork () at kernel/proc.c:260 #1 0x0000000080002c3c in sys_fork () at kernel/sysproc.c:29 #2 0x0000000080002bb0 in syscall () at kernel/syscall.c:140 #3 0x000000008000289a in usertrap () at kernel/trap.c:67 #4 0x0000000000000050 in ?? ()

關(guān)鍵代碼

kernel/riscv.h: 實(shí)現(xiàn)一個(gè)獲取當(dāng)前 frame pointer 的方法:

static inline uint64 r_fp() {uint64 x;asm volatile("mv %0, s0" : "=r" (x) );return x; }

kernel/printf.c: 打印 backtrace:

void backtrace(void) {printf("backtrace:\n");uint64 fp = r_fp();while (PGROUNDDOWN(fp) < PGROUNDUP(fp)) {printf("%p\n", *(uint64*)(fp-8));fp = *(uint64*)(fp-16);} }

Diff

diff --git a/kernel/defs.h b/kernel/defs.h index 4b9bbc0..137c786 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -80,6 +80,7 @@ int pipewrite(struct pipe*, uint64, int);void printf(char*, ...);void panic(char*) __attribute__((noreturn));void printfinit(void); +void backtrace(void);// proc.cint cpuid(void); diff --git a/kernel/printf.c b/kernel/printf.c index e1347de..fbdeb68 100644 --- a/kernel/printf.c +++ b/kernel/printf.c @@ -121,6 +121,9 @@ panic(char *s)printf("panic: ");printf(s);printf("\n"); + + backtrace(); +panicked = 1; // freeze uart output from other CPUsfor(;;); @@ -132,3 +135,18 @@ printfinit(void)initlock(&pr.lock, "pr");pr.locking = 1;} + +// print a backtrace: +// a list of the function calls on the stack above +// the point at which the error occurred. +void +backtrace(void) +{ + printf("backtrace:\n"); + uint64 fp = r_fp(); + while (PGROUNDDOWN(fp) < PGROUNDUP(fp)) { + printf("%p\n", *(uint64*)(fp-8)); + fp = *(uint64*)(fp-16); + } +} + diff --git a/kernel/riscv.h b/kernel/riscv.h index 0aec003..c95316e 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -319,6 +319,16 @@ sfence_vma()asm volatile("sfence.vma zero, zero");}+// compiler stores the frame pointer of the currently +// executing function in s0. +// this function reads current frame pointer, namely s0 +static inline uint64 +r_fp() +{ + uint64 x; + asm volatile("mv %0, s0" : "=r" (x) ); + return x; +}#define PGSIZE 4096 // bytes per page#define PGSHIFT 12 // bits of offset within a page diff --git a/kernel/sysproc.c b/kernel/sysproc.c index e8bcda9..a520959 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -58,6 +58,8 @@ sys_sleep(void)int n;uint ticks0;+ backtrace(); +if(argint(0, &n) < 0)return -1;acquire(&tickslock);

Alarm

做一套系統(tǒng)調(diào)用,在用戶進(jìn)程每運(yùn)行指定次數(shù)時(shí)鐘后,調(diào)用該進(jìn)程提供的一個(gè) handler。

其實(shí)也不難,(我覺得比頁表簡單),跟著 hint 一步步做就行了。

關(guān)鍵實(shí)現(xiàn)

  • kernel/proc.h: 在 proc 結(jié)構(gòu)體里添加需要的字段(間隔時(shí)長、已運(yùn)行時(shí)長計(jì)數(shù)、處理函數(shù)地址(vm)、保存 alarm 前的寄存器):
  • struct proc {...int alarm_interval; // the alarm interval (ticks)int alarm_passed; // how many ticks have passed since the last calluint64 alarm_handler; // pointer to the alarm handler functionstruct trapframe etpfm; // trapframe to resume }
  • 添加 sys_sigalarm 系統(tǒng)調(diào)用:接收參數(shù),為進(jìn)程設(shè)置 alarm 的間隔時(shí)長和處理函數(shù)。最終的實(shí)現(xiàn)在 kernel/sysproc.c (添加新系統(tǒng)調(diào)用的完整步驟見:6.S081 Xv6 Lab 2: system calls):
  • uint64 sys_sigalarm(void) {int interval;uint64 handler;if(argint(0, &interval) < 0)return -1;if(argaddr(1, &handler) < 0)return -1;struct proc *p = myproc();p->alarm_interval = interval;p->alarm_handler = handler;return 0; }
  • 在 usertrap (kernel/trap.c)中處理時(shí)鐘中斷時(shí),如果進(jìn)程需要 alarm 就保存當(dāng)前 trapframe 到 etpfm,調(diào)用 handler (把 handler 地址放到 trapframe->epc,回到用戶空間之后就會運(yùn)行該函數(shù)):
  • void usertrap(void) {...if(which_dev == 2) {// alarmif (p->alarm_interval) {if (++p->alarm_passed == p->alarm_interval) {memmove(&(p->etpfm), p->trapframe, sizeof(struct trapframe));// return to alarm handler: call p->alarm_handler();p->trapframe->epc = p->alarm_handler;}}yield();}... }
  • 實(shí)現(xiàn) sys_sigalarm 系統(tǒng)調(diào)用,恢復(fù) alarm 前的 trapframe(回到用戶空間就會接著 alarm 之前的 PC 開始運(yùn)行),把 alarm_passed 計(jì)數(shù)器置為零(允許下一次 alarm):
  • uint64 sys_sigreturn(void) {struct proc *p = myproc();memmove(p->trapframe, &(p->etpfm), sizeof(struct trapframe));p->alarm_passed = 0;return 0; }

    某bug的sizeof

    我做的時(shí)候不小心寫了個(gè) sizeof 的語法錯(cuò)誤,找了半個(gè)小時(shí)呢。。。(這個(gè)問題超初學(xué)者的,,我對8起 K&R)

    我一開始是這么寫的:

    struct trapframe {...}struct proc {...struct trapframe *trapframe;struct trapframe etpfm; }void usertrap(void) {...memmove(&(p->etpfm), p->trapframe, sizeof(p->trapframe));... }uint64 sys_sigreturn(void) {...memmove(p->trapframe, &(p->etpfm), sizeof(p->trapframe));... }

    解決:把 sizeof(p->trapframe) 改成 sizeof(struct trapframe)。

    Diff

    emmm,上一題做完忘記 commit 了,所以下面這個(gè) diff 也包含了上一題(backtrace)的:

    diff --git a/Makefile b/Makefile index 1fa367e..a74296b 100644 --- a/Makefile +++ b/Makefile @@ -175,6 +175,7 @@ UPROGS=\$U/_grind\$U/_wc\$U/_zombie\ + $U/_alarmtest\diff --git a/grade-lab-traps b/grade-lab-traps index 058e77b..8619bbe 100755 --- a/grade-lab-traps +++ b/grade-lab-traps @@ -60,7 +60,7 @@ def test_alarmtest_test2():def test_usertests():r.run_qemu(shell_script(['usertests' - ]), timeout=300) + ]), timeout=500)r.match('^ALL TESTS PASSED$')@test(1, "time") diff --git a/kernel/defs.h b/kernel/defs.h index 4b9bbc0..137c786 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -80,6 +80,7 @@ int pipewrite(struct pipe*, uint64, int);void printf(char*, ...);void panic(char*) __attribute__((noreturn));void printfinit(void); +void backtrace(void);// proc.cint cpuid(void); diff --git a/kernel/printf.c b/kernel/printf.c index e1347de..fbdeb68 100644 --- a/kernel/printf.c +++ b/kernel/printf.c @@ -121,6 +121,9 @@ panic(char *s)printf("panic: ");printf(s);printf("\n"); + + backtrace(); +panicked = 1; // freeze uart output from other CPUsfor(;;); @@ -132,3 +135,18 @@ printfinit(void)initlock(&pr.lock, "pr");pr.locking = 1;} + +// print a backtrace: +// a list of the function calls on the stack above +// the point at which the error occurred. +void +backtrace(void) +{ + printf("backtrace:\n"); + uint64 fp = r_fp(); + while (PGROUNDDOWN(fp) < PGROUNDUP(fp)) { + printf("%p\n", *(uint64*)(fp-8)); + fp = *(uint64*)(fp-16); + } +} + diff --git a/kernel/proc.c b/kernel/proc.c index dab1e1d..237fecb 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -127,6 +127,11 @@ found:p->context.ra = (uint64)forkret;p->context.sp = p->kstack + PGSIZE;+ // Initialize alarm + p->alarm_interval = 0; + p->alarm_passed = 0; + p->alarm_handler = 0; +return p;}diff --git a/kernel/proc.h b/kernel/proc.h index 9c16ea7..2dac44f 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -103,4 +103,9 @@ struct proc {struct file *ofile[NOFILE]; // Open filesstruct inode *cwd; // Current directorychar name[16]; // Process name (debugging) + + int alarm_interval; // the alarm interval (ticks) + int alarm_passed; // how many ticks have passed since the last call + uint64 alarm_handler; // pointer to the alarm handler function + struct trapframe etpfm; // trapframe to resume, 啊, 不會xv6的動(dòng)態(tài)內(nèi)存分配,所以這里直接 hardcode 一個(gè)對象了。}; diff --git a/kernel/riscv.h b/kernel/riscv.h index 0aec003..c95316e 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -319,6 +319,16 @@ sfence_vma()asm volatile("sfence.vma zero, zero");}+// compiler stores the frame pointer of the currently +// executing function in s0. +// this function reads current frame pointer, namely s0 +static inline uint64 +r_fp() +{ + uint64 x; + asm volatile("mv %0, s0" : "=r" (x) ); + return x; +}#define PGSIZE 4096 // bytes per page#define PGSHIFT 12 // bits of offset within a page diff --git a/kernel/syscall.c b/kernel/syscall.c index c1b3670..eb079af 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -104,6 +104,8 @@ extern uint64 sys_unlink(void);extern uint64 sys_wait(void);extern uint64 sys_write(void);extern uint64 sys_uptime(void); +extern uint64 sys_sigalarm(void); +extern uint64 sys_sigreturn(void);static uint64 (*syscalls[])(void) = {[SYS_fork] sys_fork, @@ -127,6 +129,8 @@ static uint64 (*syscalls[])(void) = {[SYS_link] sys_link,[SYS_mkdir] sys_mkdir,[SYS_close] sys_close, +[SYS_sigalarm] sys_sigalarm, +[SYS_sigreturn] sys_sigreturn,};void diff --git a/kernel/syscall.h b/kernel/syscall.h index bc5f356..382d781 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -20,3 +20,5 @@#define SYS_link 19#define SYS_mkdir 20#define SYS_close 21 +#define SYS_sigalarm 22 +#define SYS_sigreturn 23 diff --git a/kernel/sysproc.c b/kernel/sysproc.c index e8bcda9..5b64016 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -58,6 +58,8 @@ sys_sleep(void)int n;uint ticks0;+ backtrace(); +if(argint(0, &n) < 0)return -1;acquire(&tickslock); @@ -95,3 +97,32 @@ sys_uptime(void)release(&tickslock);return xticks;} + +uint64 +sys_sigalarm(void) +{ + int interval; + uint64 handler; + + if(argint(0, &interval) < 0) + return -1; + + if(argaddr(1, &handler) < 0) + return -1; + + struct proc *p = myproc(); + + p->alarm_interval = interval; + p->alarm_handler = handler; + + return 0; +} + +uint64 +sys_sigreturn(void) +{ + struct proc *p = myproc(); + memmove(p->trapframe, &(p->etpfm), sizeof(struct trapframe)); + p->alarm_passed = 0; + return 0; +} diff --git a/kernel/trap.c b/kernel/trap.c index a63249e..9f2a64b 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -77,8 +77,20 @@ usertrap(void)exit(-1);// give up the CPU if this is a timer interrupt. - if(which_dev == 2) + if(which_dev == 2) { + // alarm + if (p->alarm_interval /*&& p->alarm_handler*/) { // handler addr might be 0 + if (++p->alarm_passed == p->alarm_interval) { + memmove(&(p->etpfm), p->trapframe, sizeof(struct trapframe)); + // return to alarm handler: call p->alarm_handler(); + p->trapframe->epc = p->alarm_handler; + // printf("[DEBUG] alarm: %s(%d), handler=%x\n", + // p->name, p->pid, p->alarm_handler); + // p->alarm_passed = 0; // sigreturn 時(shí)再恢復(fù): prevent re-entrant calls to the handler + } + }yield(); + }usertrapret();} diff --git a/user/alarmtest.c b/user/alarmtest.c index 38f09ff..427c460 100644 --- a/user/alarmtest.c +++ b/user/alarmtest.c @@ -101,6 +101,7 @@ test1()// restored correctly, causing i or j or the address ofj// to get an incorrect value.printf("\ntest1 failed: foo() executed fewer times than it was called\n"); + printf("\ti=%d, j=%d\n", i, j);} else {printf("test1 passed\n");} diff --git a/user/user.h b/user/user.h index b71ecda..57404e0 100644 --- a/user/user.h +++ b/user/user.h @@ -23,6 +23,8 @@ int getpid(void);char* sbrk(int);int sleep(int);int uptime(void); +int sigalarm(int ticks, void (*handler)()); +int sigreturn(void);// ulib.cint stat(const char*, struct stat*); diff --git a/user/usys.pl b/user/usys.pl index 01e426e..fa548b0 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -36,3 +36,5 @@ entry("getpid");entry("sbrk");entry("sleep");entry("uptime"); +entry("sigalarm"); +entry("sigreturn");

    實(shí)驗(yàn)結(jié)果

    最后,make grade (我的機(jī)器上跑 usertests 巨慢,要改一下 timeout 才能通過。。):

    == Test answers-traps.txt == answers-traps.txt: OK == Test backtrace test == $ make qemu-gdb backtrace test: OK (4.7s) == Test running alarmtest == $ make qemu-gdb (3.9s) == Test alarmtest: test0 == alarmtest: test0: OK == Test alarmtest: test1 == alarmtest: test1: OK == Test alarmtest: test2 == alarmtest: test2: OK == Test usertests == $ make qemu-gdb usertests: OK (448.3s) (Old xv6.out.usertests failure log removed) == Test time == time: OK Score: 85/85

    EOF


    By CDFMLR 2020-03-28

    頂部圖片來自于小歪API,系隨機(jī)選取的圖片,僅用于檢測屏幕顯示的機(jī)械、光電性能,與文章的任何內(nèi)容及觀點(diǎn)無關(guān),也并不代表本人局部或全部同意、支持或者反對其中的任何內(nèi)容及觀點(diǎn)。如有侵權(quán),聯(lián)系刪除。

    總結(jié)

    以上是生活随笔為你收集整理的6.S081 Xv6 Lab 4 traps的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。