MIT6.1810 Lab: system calls 实验记录

在做实验时,可以根据实验提示,阅读相关资料,下面先附上相关链接
xv6 中文文档
xv6 英文文档
RISC-V 特权指令
b站相关中英文翻译视频
b站对应视频翻译文档

该实验中需要向 xv6 中添加一些新的系统调用,目的是熟悉 xv6 和 其系统调用。实验地址

首先执行相应的 git 命令切换 git 分支
$ git fetch (从远程仓库下载最新的提交和分支信息)
$ git checkout syscall (切换到名为 syscall 的分支)
$ make clean (确保下一次编译是从干净状态开始,避免旧文件导致的问题)

在实验开始前,建议先观看对应视频内容( OS Organization and System Call),然后再根据官方实验文档进行操作。

1. using gdb

如何使用 gdb 调试 xv6 内核
1、首先需要启动 qemu 内部的一个 gdb server,启动之后,qemu 会等待 gdb 客户端连接 (注意输出信息最后的端口号)
$ make qemu-gdb
在这里插入图片描述
2、之后在另一个终端窗口中启动一个 gdb 客户端

  • 支持多架构的 gdb
    $ gdb-multiarch kernel/kernel
  • 或标准版本的 gdb
    $ gdb kernel/kernel
  • 其他版本自行查阅资料

3、然后需要连接到 qemu
(gdb) target remote <:port>
出现类似下图输出就代表成功了,至此就可以使用 gdb 调试 xv6 内核了
在这里插入图片描述

实验需求:回答文档中问题, 并将答案存放在 answers-syscall.txt (与user文件夹同级)中:

问题 1: Looking at the backtrace output, which function called syscall?

 根据文档提示输入以下 gdb 命令
 (gdb) b syscall  // 在 syscall 函数处设置断点
 (gdb) c		  // 继续执行程序,直到遇到断点或程序结束
 (gdb) layout src // 切换到源代码布局模式,显示当前执行的源代码
 (gdb) backtrace  // 打印当前的调用栈,显示程序执行到当前断点时的函数调用链

 自行查阅 backtrace 命令,分析输出信息,即可得到 问题1 答案

问题 2:What is the value of p->trapframe->a7 and what does that value represent? (Hint: look user/initcode.S, the first user program xv6 starts.)

 根据文档提示在 问题1 的基础上,连续输入 n
 (gdb) n
 (gdb) n	
  ... 		    // 直至语句 num = p->trapframe->a7 执行完毕
 (gdb) p /x num	// 以 十六 进制输出 num
 $1 = 0x7

 根据提示可以知道 user/initcode.S 是 xv6 启动的第一个用户程序,其 start 代码段中会将 SYS_exec 送入 a7,然后执行 ecall,
 切换到内核态,然后操作系统会执行 syscall 函数,将寄存器 a7 的内容送入 num。

 查看 kernel/syscall.h,可知输出数字 7 正好对应 SYS_exec 系统调用。

问题 3. What was the previous mode that the CPU was in?

 根据文档提示输入
 (gdb) p/x $sstatus 
 $2 = 0x200000022       (一般为 32 位或 64 位,我这里可能是某些硬件原因输出 36)

 查看 RISC-V特权指令 文档,搜索 sstatus,发现 sstatus 的第 8 位 SPP,表示是从哪个模式切换过来的;
 将 0x200000022 转换为 2 进制,可以看出其 SPP 位为 0,表示从 User-mode 切换来的。

在这里插入图片描述

问题 4. Write down the assembly instruction the kernel is panicing at. Which register corresponds to the variable num?

 根据文档信息,修改 kernel/syscall.c 文件内容
  num = *(int*) 0;
  // num = p->trapframe->a7;
 重新运行 qemu
 $ make qemu
 
 xv6 kernel is booting

 hart 2 starting
 hart 1 starting
 scause=0xd sepc=0x80001c6c stval=0x0
 panic: kerneltrap
 
 程序出现 panic ,需要我们去查明错误原因。
 
 根据文档提示,我们先看 sepc 的作用,它用于当 异常或中断 发生时,记录当前执行的指令地址。
 当从 异常或中断 中返回时,CPU 会使用 sepc 寄存器中的值来恢复到异常发生之前的执行状态。
 
 根据上述输出 sepc=0x80001c6c,在 kernel/kernel.asm 中查找该地址,可以看到
 num = *(int*) 0;
 80001c6c:	00002683          	lw	a3,0(zero) # 0 <_entry-0x80000000>
 即当 pc 为 0x80001c6c 时的指令为 num = *(int*) 0; 故这就是导致出错的地方。
 
 根据文档我们还需要进行验证。
 (gdb) b *0x80001c6c
 (gdb) layout asm
 (gdb) c
 发现当程序执行到 0x80001c6c 时,执行的语句为 lw a3 0(zer0) #0x0

问题 5. Why does the kernel crash? Hint: look at figure 3-3 in the text; is address 0 mapped in the kernel address space? Is that confirmed by the value in scause above? (See description of scause in RISC-V privileged instructions)
我们要对 问题4 出现的原因进行解释,为什么当 num 赋值为 0 时,程序会崩溃。
根据文档提示查看 xv6 英文文档 图3.3 或 中文文档 图2.2,两张图结合看
在这里插入图片描述

从图片中可以看出,xv6 内核的虚拟地址空间从 0x80000000 (KERNBASE) 开始,映射到物理地址,而 地址0 不在内核的映射范围内。

lw a3, 0(zero) 试图从内存地址 0 处加载数据,当内核试图访问未映射的地址时,会触发 缺页异常(Page Fault)。

之后我们需要查看 scause 进行验证,RISC-V 特权指令的文档中说明了 
When a trap is delegated to S-mode, the scause register is written with the trap cause;
当陷阱被委托给 内核模式 时,陷阱原因被写入 scause 寄存器;

回到刚才运行 qemu 时输出的报错信息,scause=0xd (13),查看 RISC-V 特权指令文档 表4.2,发现 13 对应 Load page fault.

问题 6. What is the name of the process that was running when the kernel paniced? What is its process id (pid)?

 根据文档提示输入
 (gdb) p p->name
  $1 = "initcode\000\000\000\000\000\000\000"
 (gdb) p p->pid
  $2 = 1

2. system call tracing

  • 需求
    添加一个系统调用跟踪功能,接收一个参数(整数掩码),该位指定要跟踪哪些系统调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值