Which registers contain arguments to functions?
For example, which register holds 13 in main's call to printf?
user/call.asm
void main(void) {
1c: 1141 addi sp,sp,-16
1e: e406 sd ra,8(sp)
20: e022 sd s0,0(sp)
22: 0800 addi s0,sp,16
printf("%d %d\n", f(8)+1, 13);
24: 4635 li a2,13
26: 45b1 li a1,12
28: 00000517 auipc a0,0x0
2c: 7b850513 addi a0,a0,1976 # 7e0 <malloc+0xe8>
30: 00000097 auipc ra,0x0
34: 610080e7 jalr 1552(ra) # 640 <printf>
exit(0);
38: 4501 li a0,0
3a: 00000097 auipc ra,0x0
3e: 28e080e7 jalr 654(ra) # 2c8 <exit>
RISC-V 使用 a0-a7 暫存器傳遞參數
第 7 行 可以看到 13 儲存在 a2 暫存器
Where is the call to function f in the assembly code for main?
Where is the call to g?
(Hint: the compiler may inline functions.)
int g(int x) {
0: 1141 addi sp,sp,-16
2: e422 sd s0,8(sp)
4: 0800 addi s0,sp,16
return x+3;
}
6: 250d addiw a0,a0,3
8: 6422 ld s0,8(sp)
a: 0141 addi sp,sp,16
c: 8082 ret
000000000000000e <f>:
int f(int x) {
e: 1141 addi sp,sp,-16
10: e422 sd s0,8(sp)
12: 0800 addi s0,sp,16
return g(x);
}
14: 250d addiw a0,a0,3
16: 6422 ld s0,8(sp)
18: 0141 addi sp,sp,16
1a: 8082 ret
從上面及 main function 可以發現,並沒有呼叫 f() 及 g(),compiler 直接算出結果
At what address is the function printf located?
0000000000000640 <printf>:
void
printf(const char *fmt, ...)
{
640: 711d addi sp,sp,-96
642: ec06 sd ra,24(sp)
644: e822 sd s0,16(sp)
646: 1000 addi s0,sp,32
648: e40c sd a1,8(s0)
64a: e810 sd a2,16(s0)
64c: ec14 sd a3,24(s0)
64e: f018 sd a4,32(s0)
650: f41c sd a5,40(s0)
652: 03043823 sd a6,48(s0)
656: 03143c23 sd a7,56(s0)
va_list ap;
va_start(ap, fmt);
65a: 00840613 addi a2,s0,8
65e: fec43423 sd a2,-24(s0)
vprintf(1, fmt, ap);
662: 85aa mv a1,a0
664: 4505 li a0,1
666: 00000097 auipc ra,0x0
66a: de0080e7 jalr -544(ra) # 446 <vprintf>
}
0x640
What value is in the register ra just after the jalr to printf in main?
30: 00000097 auipc ra,0x0
34: 610080e7 jalr 1552(ra) # 640 <printf>
exit(0);
auipc ra, 0x0 # ra = pc + 0x0
jalr 1552(ra) # ra = pc + 4
# pc = 1552 + ra = 1552 + 0x30 = 1660 = 0x640
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?
In the following code
what is going to be printed after 'y='?
(note: the answer is not a specific value.)
Why does this happen?
printf("x=%d y=%d", 3);
diff --git a/kernel/defs.h b/kernel/defs.h
index a3c962b..4b82fc2 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.c
int cpuid(void);
diff --git a/kernel/printf.c b/kernel/printf.c
index 1a50203..d77c791 100644
--- a/kernel/printf.c
+++ b/kernel/printf.c
@@ -122,6 +122,7 @@ panic(char *s)
printf("panic: ");
printf(s);
printf("\n");
+ backtrace();
panicked = 1; // freeze uart output from other CPUs
for(;;)
;
@@ -133,3 +134,19 @@ printfinit(void)
initlock(&pr.lock, "pr");
pr.locking = 1;
}
+
+void
+backtrace()
+{
+ uint64 fp, ra, end;
+
+ fp = r_fp();
+ end = PGROUNDUP(fp);
+
+ printf("backtrace:\n");
+ while (fp < end) {
+ ra = *((uint64*)fp - 1);
+ printf("%p\n", ra - 8);
+ fp = *((uint64*)fp - 2);
+ }
+}
diff --git a/kernel/riscv.h b/kernel/riscv.h
index 20a01db..c0c7330 100644
--- a/kernel/riscv.h
+++ b/kernel/riscv.h
@@ -327,6 +327,14 @@ sfence_vma()
asm volatile("sfence.vma zero, zero");
}
+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/sysproc.c b/kernel/sysproc.c
index 3b4d5bd..bc705a3 100644
--- a/kernel/sysproc.c
+++ b/kernel/sysproc.c
@@ -67,6 +67,7 @@ sys_sleep(void)
sleep(&ticks, &tickslock);
}
release(&tickslock);
+ backtrace();
return 0;
}
diff --git a/user/printf.c b/user/printf.c
index 5c5c782..d2aa7e0 100644
--- a/user/printf.c
+++ b/user/printf.c
@@ -1,6 +1,7 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
+#include "kernel/riscv.h"
#include <stdarg.h>
diff --git a/Makefile b/Makefile
index ded5bc2..2628613 100644
--- a/Makefile
+++ b/Makefile
@@ -188,6 +188,7 @@ UPROGS=\
$U/_grind\
$U/_wc\
$U/_zombie\
+ $U/_alarmtest\
diff --git a/answers-traps.txt b/answers-traps.txt
new file mode 100644
index 0000000..1aa57ce
--- /dev/null
+++ b/answers-traps.txt
@@ -0,0 +1,24 @@
diff --git a/kernel/proc.c b/kernel/proc.c
index 959b778..e9b45b9 100644
--- a/kernel/proc.c
+++ b/kernel/proc.c
@@ -146,6 +146,12 @@ found:
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
+ // Set up alarm info.
+ p->alarmticks = 0;
+ p->alarmhandler = 0;
+ p->alarmtickspassed = 0;
+ p->alarmframe = 0;
+
return p;
}
@@ -169,6 +175,12 @@ freeproc(struct proc *p)
p->killed = 0;
p->xstate = 0;
p->state = UNUSED;
+ p->alarmticks = 0;
+ p->alarmhandler = 0;
+ p->alarmtickspassed = 0;
+ if (p->alarmframe)
+ kfree((void*)p->alarmframe);
+ p->alarmframe = 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 d021857..97d718d 100644
--- a/kernel/proc.h
+++ b/kernel/proc.h
@@ -91,6 +91,8 @@ struct proc {
int killed; // If non-zero, have been killed
int xstate; // Exit status to be returned to parent's wait
int pid; // Process ID
+ int alarmticks; // alarm ticks
+ int alarmtickspassed; // how many ticks passed.
// wait_lock must be held when using this:
struct proc *parent; // Parent process
@@ -98,8 +100,9 @@ struct proc {
// these are private to the process, so p->lock need not be held.
uint64 kstack; // Virtual address of kernel stack
uint64 sz; // Size of process memory (bytes)
+ uint64 alarmhandler; // alarm handler, called after "proc->alarmticks" ticks.
pagetable_t pagetable; // User page table
- struct trapframe *trapframe; // data page for trampoline.S
+ struct trapframe *trapframe, *alarmframe; // data page for trampoline.S
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
diff --git a/kernel/syscall.c b/kernel/syscall.c
index ed65409..751af4f 100644
--- a/kernel/syscall.c
+++ b/kernel/syscall.c
@@ -101,6 +101,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.
@@ -126,6 +128,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 bc705a3..ec51b23 100644
--- a/kernel/sysproc.c
+++ b/kernel/sysproc.c
@@ -92,3 +92,50 @@ sys_uptime(void)
release(&tickslock);
return xticks;
}
+
+uint64
+sys_sigalarm(void)
+{
+ int ticks;
+ uint64 handler;
+
+ // Get ticks & handler
+ argint(0, &ticks);
+ argaddr(1, &handler);
+
+
+ struct proc *proc = myproc();
+
+ if (ticks == 0 && handler == 0) {
+ proc->alarmhandler = 0;
+ proc->alarmticks = 0;
+ proc->alarmtickspassed = 0;
+ return 0;
+ }
+ // store data to proc
+ proc->alarmticks = ticks;
+ proc->alarmhandler = handler;
+ char *p = kalloc();
+ if (!p)
+ panic("sigalarm");
+ proc->alarmframe = (struct trapframe *)(uint64)p;
+ // save previous proc state
+ *proc->alarmframe = *proc->trapframe;
+
+ return 0;
+}
+
+uint64
+sys_sigreturn(void)
+{
+ struct proc *proc = myproc();
+ *proc->trapframe = *proc->alarmframe;
+ proc->alarmtickspassed = 0;
+
+ if (proc->alarmticks == 0) {
+ if (proc->alarmframe)
+ kfree(proc->alarmframe);
+ proc->alarmframe = 0;
+ }
+ return proc->trapframe->a0;
+}
\ No newline at end of file
diff --git a/kernel/trap.c b/kernel/trap.c
index 512c850..0ae7480 100644
--- a/kernel/trap.c
+++ b/kernel/trap.c
@@ -77,8 +77,18 @@ usertrap(void)
exit(-1);
// give up the CPU if this is a timer interrupt.
- if(which_dev == 2)
- yield();
+ if(which_dev == 2) {
+ if (p->alarmticks != 0) {
+ if (p->alarmticks != p->alarmtickspassed) {
+ p->alarmtickspassed += 1;
+ if (p->alarmticks == p->alarmtickspassed) {
+ *p->alarmframe = *p->trapframe;
+ p->trapframe->epc = p->alarmhandler;
+ }
+ }
+ }
+ yield();
+ }
usertrapret();
}
diff --git a/user/user.h b/user/user.h
index 4d398d5..9426153 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..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");