欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

xv6 syscall lab

程序员文章站 2022-06-19 13:47:26
...
  • 学习syscall lab

  An operating system supports two modes; the kernel mode and the user mode.When a program in user mode requires access to RAM or a hardware resource, it must ask the kernel to provide access to that particular resource. This is done via a system call. When a program makes a system call, the mode is switched from user mode to kernel mode.

  There are many system calls in an operating system which executes different types of tasks when they are called.

实验1:System call tracing
  Your first task is to modify the xv6 kernel to print out a line for each system call invocation. It is enough to print the name of the system call and the return value; you don’t need to print the system call arguments.

 //syscall.c                                                                                                                 
  132 static char syscalls_names[][6] = {
  133 [SYS_fork]    "fork",
  134 [SYS_exit]    "exit",
  135 [SYS_wait]    "wait",
  136 [SYS_pipe]    "pipe",
  137 [SYS_read]    "read",
  138 [SYS_kill]    "kill",
  139 [SYS_exec]    "exec",
  140 [SYS_fstat]   "fstat",
  141 [SYS_chdir]   "chdir",
  142 [SYS_dup]     "dup",
  143 [SYS_getpid]  "getpid",
  144 [SYS_sbrk]    "sbrk",
  145 [SYS_sleep]   "sleep",
  146 [SYS_uptime]  "uptime",
  147 [SYS_open]    "open",
  148 [SYS_write]   "write",
  149 [SYS_mknod]   "mknod",
  150 [SYS_unlink]  "unlink",
  151 [SYS_link]    "link",
  152 [SYS_mkdir]   "mkdir",
  153 [SYS_close]   "close",
  154 };
 
  156 void
  157 syscall(void)
  158 {
  159   ...
  162   num = curproc->tf->eax;
  163   if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
  164     curproc->tf->eax = syscalls[num]();
  165   ++cprintf("\talbert:syscall name:%s\t -> num:%d\n",syscalls_names[num],num);

实验2 :add a Date system call

diff --git a/Makefile b/Makefile
index 09d790c..25420f1 100644
--- a/Makefile
+++ b/Makefile
@@ -181,6 +181,7 @@ UPROGS=\
 	_usertests\
 	_wc\
 	_zombie\
+	_date\
 
 fs.img: mkfs README $(UPROGS)
 	./mkfs fs.img README $(UPROGS)
@@ -249,7 +250,7 @@ qemu-nox-gdb: fs.img xv6.img .gdbinit
 
 EXTRA=\
 	mkfs.c ulib.c user.h cat.c echo.c forktest.c grep.c kill.c\
-	ln.c ls.c mkdir.c rm.c stressfs.c usertests.c wc.c zombie.c\
+	ln.c ls.c mkdir.c rm.c stressfs.c usertests.c wc.c zombie.c date.c\
 	printf.c umalloc.c\
 	README dot-bochsrc *.pl toc.* runoff runoff1 runoff.list\
 	.gdbinit.tmpl gdbutil\
diff --git a/syscall.c b/syscall.c
index ee85261..9ad01e6 100644
--- a/syscall.c
+++ b/syscall.c
@@ -104,6 +104,9 @@ extern int sys_wait(void);
 extern int sys_write(void);
 extern int sys_uptime(void);
 
+//albert
+extern int sys_date(void);
+
 static int (*syscalls[])(void) = {
 [SYS_fork]    sys_fork,
 [SYS_exit]    sys_exit,
@@ -126,8 +129,36 @@ static int (*syscalls[])(void) = {
 [SYS_link]    sys_link,
 [SYS_mkdir]   sys_mkdir,
 [SYS_close]   sys_close,
+//albert
+[SYS_date]    sys_date,
 };
 
+//albert
+/*static char syscalls_names[][6] = {
+[SYS_fork]    "fork",
+[SYS_exit]    "exit",
+[SYS_wait]    "wait",
+[SYS_pipe]    "pipe",
+[SYS_read]    "read",
+[SYS_kill]    "kill",
+[SYS_exec]    "exec",
+[SYS_fstat]   "fstat",
+[SYS_chdir]   "chdir",
+[SYS_dup]     "dup",
+[SYS_getpid]  "getpid",
+[SYS_sbrk]    "sbrk",
+[SYS_sleep]   "sleep",
+[SYS_uptime]  "uptime",
+[SYS_open]    "open",
+[SYS_write]   "write",
+[SYS_mknod]   "mknod",
+[SYS_unlink]  "unlink",
+[SYS_link]    "link",
+[SYS_mkdir]   "mkdir",
+[SYS_close]   "close",
+[SYS_date]    "date",
+};*/
+
diff --git a/syscall.h b/syscall.h
index bc5f356..61a5b46 100644
--- a/syscall.h
+++ b/syscall.h
@@ -20,3 +20,5 @@
 #define SYS_link   19
 #define SYS_mkdir  20
 #define SYS_close  21
+//albert
+#define SYS_date  22
diff --git a/sysproc.c b/sysproc.c
index 0686d29..6491ddd 100644
--- a/sysproc.c
+++ b/sysproc.c
@@ -89,3 +89,15 @@ sys_uptime(void)
   release(&tickslock);
   return xticks;
 }
+
+
+
+//albert:return current date 
+int 
+sys_date(struct rtcdate *r)
+{
+	if(argptr(0,(void *)&r,sizeof(*r)) < 0)
+		return -1;
+	cmostime(r);
+	return 0;
+}

diff --git a/user.h b/user.h
index 4f99c52..d5aea54 100644
--- a/user.h
+++ b/user.h
@@ -23,6 +23,8 @@ int getpid(void);
 char* sbrk(int);
 int sleep(int);
 int uptime(void);
+//albert
+int date(struct rtcdate *);
 
 // ulib.c
 int stat(const char*, struct stat*);
diff --git a/usys.S b/usys.S
index 8bfd8a1..d83555f 100644
--- a/usys.S
+++ b/usys.S
@@ -29,3 +29,5 @@ SYSCALL(getpid)
 SYSCALL(sbrk)
 SYSCALL(sleep)
 SYSCALL(uptime)
+//albert
+SYSCALL(date)

添加patch之后,执行make qemu-nox,然后ls,显示添加的系统调用date。

$ ls
.              1 1 512
..             1 1 512
README         2 2 2327
cat            2 3 14509
echo           2 4 13366
forktest       2 5 8196
grep           2 6 16045
init           2 7 14247
kill           2 8 13386
ln             2 9 13332
ls             2 10 16196
mkdir          2 11 13427
rm             2 12 13404
sh             2 13 24848
stressfs       2 14 14342
usertests      2 15 67274
wc             2 16 15167
zombie         2 17 13056
date           2 18 13609
console        3 19 0

执行date:

$ date
4-6 2019 5:20:45
pid 4 date: trap 14 err 5 on cpu 1 eip 0xffffffff addr 0xffffffff--kill proc

实验3 – 调试syscall调用流程
系统调用流程为:
  date ->alltraps(trapasm.S)-> trap(trap.c)->syscall(syscall.c )

调试准备:

Documents/work/code/xv6/xv6-public$ make qemu-nox-gdb 
Documents/work/code/xv6/xv6-public$ gdb kernel
(gdb) file date.o
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Load new symbol table from "date.o"? (y or n) y
Reading symbols from date.o...done.
(gdb) b main
Breakpoint 1 at 0x20: file date.c, line 7.
(gdb) c
Continuing.
[New Thread 2]
[Switching to Thread 2]
[  1b:  20]    0x1d0:	rep stos %al,%es:(%di)

Breakpoint 1, main (argc=2, argv=0x0) at date.c:7
7	{

执行si命令直到int $0x40,64 即0x40 是system call in xv6。

│0x3aa   mov    $0xa,%ax                                                                                                    │
│0x3ad   add    %al,(%bx,%si)                                                                                               │
│0x3af   int    $0x40   

当执行了0x3af int $0x40 之后,跳转到如下地址,接着依次跳转到alltraps和trap。

   │0x80105ae8      push   $0x40                                                                                               │
   │0x80105aea      jmp    0x8010540d           //jump   alltraps                                                                           │
   │0x80105aed      (bad)                                                                                                      │
   │0x80105aee      ljmp   *0x0(%bp,%si)                                                                                       │
   │0x80105af1      push   $0x41                                                                                               │
   │0x80105af3      jmp    0x8010540d                                                                                          │
   │0x80105af6      (bad)                                                                                                      │
   │0x80105af7      ljmp   *0x0(%bp,%si)                                                                                       │
   │0x80105afa      push   $0x42 
   ...
    
   |0x8010541f      call   0x80105510       //trap

  syscall通过trapframe中的eax寄存器来确定系统调用号,从而决定调用哪个系统函数,当然eax的值或许是库函数在调用int指令的时候设置的,只是保护现场使得存放在了trapframe中,然后通过系统调用号调用具体的系统调用处理函数并返回到trapframe中的eax位置,这样恢复现场时库函数便能根据eax得到系统调用的返回值。
  每个系统调用都有不同的参数,那么在内核中的系统调用函数是如何找到这些参数?xv6提供了函数 argint、argptr 和 argstr来获得第 n 个系统调用参数。

//syscall.c:
num = curproc->tf->eax;

参考资料:
W4118: interrupt and system call.pdf
https://blog.csdn.net/yuchunyu97/article/details/78298171