Run the following code. unsigned int i = 0x00646c72; printf(“H%x Wo%s”, 57616, &i); What is the output? Here’s an ASCII table that maps bytes to characters. The output depends on that fact that the RISC-V is little-endian. If the RISC-V were instead big-endian what would you set i to in order to yield the same output? Would you need to change 57616 to a different value?
void usertrap(void) { ... // give up the CPU if this is a timer interrupt. if (which_dev == 2) { p->alarm_passed++; if (p->alarm_passed == p->alarm_threshold) { *(p->alarm_prev_trapframe) = *(p->trapframe); p->trapframe->epc = p->alarm_handler; } yield(); } ... }
diff --git a/Makefile b/Makefile index 46997f8..b5eaf29 100644 --- a/Makefile +++ b/Makefile @@ -188,6 +188,7 @@ UPROGS=\ $U/_grind\ $U/_wc\ $U/_zombie\ + $U/_alarmtest\ diff --git a/kernel/proc.c b/kernel/proc.c index 4315d58..ae8d6ed 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -133,6 +133,13 @@ allocproc(void) return 0; } + // Allocate a trapframe page for alarm + if ((p->alarm_prev_trapframe = (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) { @@ -147,6 +154,10 @@ allocproc(void) p->context.ra = (uint64)forkret; p->context.sp = p->kstack + PGSIZE; + p->alarm_passed = 0; + p->alarm_threshold = 0; + p->alarm_handler = 0; + return p; } @@ -159,6 +170,9 @@ freeproc(struct proc *p) if (p->trapframe) kfree((void *)p->trapframe); p->trapframe = 0; + if (p->alarm_prev_trapframe) + kfree((void *)p->alarm_prev_trapframe); + p->alarm_prev_trapframe = 0; if (p->pagetable) proc_freepagetable(p->pagetable, p->sz); p->pagetable = 0; @@ -170,6 +184,10 @@ freeproc(struct proc *p) p->killed = 0; p->xstate = 0; p->state = UNUSED; + + p->alarm_passed = 0; + p->alarm_threshold = 0; + p->alarm_handler = 0; } // Create a user page table for a given process, with no user memory, diff --git a/kernel/proc.h b/kernel/proc.h index a74496c..fe3d174 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -104,4 +104,10 @@ struct proc { struct file *ofile[NOFILE]; // Open files struct inode *cwd; // Current directory char name[16]; // Process name (debugging) + + // traps alarm + int alarm_passed; + int alarm_threshold; + uint64 alarm_handler; + struct trapframe *alarm_prev_trapframe; }; diff --git a/kernel/syscall.c b/kernel/syscall.c index b1f6d3d..4e19877 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -102,6 +102,8 @@ extern uint64 sys_unlink(void); extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +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. @@ -113,6 +115,7 @@ static uint64 (*syscalls[])(void) = { [SYS_sleep] sys_sleep, [SYS_uptime] sys_uptime, [SYS_open] sys_open, [SYS_write] sys_write, [SYS_mknod] sys_mknod, [SYS_unlink] sys_unlink, [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 1e1f4ba..2133a24 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 \ No newline at end of file diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 0cd201d..0c61942 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -93,3 +93,30 @@ sys_uptime(void) release(&tickslock); return xticks; } + +uint64 +sys_sigalarm(void) +{ + int period; + uint64 handler; + struct proc *p = myproc(); + + argint(0, &period); + argaddr(1, &handler); + + p->alarm_threshold = period; + p->alarm_handler = handler; + + return 0; +} + +uint64 +sys_sigreturn(void) +{ + struct proc *p = myproc(); + + *(p->trapframe) = *(p->alarm_prev_trapframe); + p->alarm_passed = 0; + + return p->trapframe->a0; +} diff --git a/kernel/trap.c b/kernel/trap.c index 0dcd358..58de139 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -79,8 +79,19 @@ usertrap(void) exit(-1); // give up the CPU if this is a timer interrupt. - if (which_dev == 2) + if (which_dev == 2) { + + // stop generating periodic alarm calls if threshold is 0 + if (p->alarm_threshold != 0) { + p->alarm_passed++; + + if (p->alarm_passed == p->alarm_threshold) { + *(p->alarm_prev_trapframe) = *(p->trapframe); + p->trapframe->epc = p->alarm_handler; + } + } yield(); + } usertrapret(); } diff --git a/user/alarmtest.c b/user/alarmtest.c index 2337221..9abd157 100644 --- a/user/alarmtest.c +++ b/user/alarmtest.c @@ -106,6 +106,7 @@ test1() // occurred; another is that that registers may not be // restored correctly, causing i or j or the address ofj // to get an incorrect value. + printf("\n test1: i: %d, j:%d\n", i, j); printf("\ntest1 failed: foo() executed fewer times than it was called\n"); } else { diff --git a/user/user.h b/user/user.h index 5837a96..fdcc993 100644 --- a/user/user.h +++ b/user/user.h @@ -22,6 +22,8 @@ int getpid(void); char *sbrk(int); int sleep(int); int uptime(void); +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 01e426e..3c258dc 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -36,3 +36,5 @@ sub entry { entry("sbrk"); entry("sleep"); entry("uptime"); +entry("sigalarm"); +entry("sigreturn"); \ No newline at end of file
测试结果
最后,执行 make grade 查看结果,
== Test answers-traps.txt == answers-traps.txt: OK == Test backtrace test == backtrace test: OK (3.9s) == Test running alarmtest == (5.6s) == Test alarmtest: test0 == alarmtest: test0: OK == Test alarmtest: test1 == alarmtest: test1: OK == Test alarmtest: test2 == alarmtest: test2: OK == Test alarmtest: test3 == alarmtest: test3: OK == Test usertests == usertests: OK (149.0s) == Test time == time: OK Score: 95/95