MIT 6.s081 xv6-lab-2025

环境配置

1
sudo apt-get install git build-essential gdb-multiarch qemu-system-misc gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu 
  • 然后git仓库,cd 文件 make qemu
  • 这是可能会卡住不动,可能需要补充一下
    1
    sudo apt install gcc-riscv64-unknown-elf-gcc

Lab 1 Utilities

Sleep

  • 十分简单的一个实验,提醒的就是关于测试环境的运行,不要在 make qemu 中运行,是在 git 下来那个仓库中运行。
  • 关于 qemu 的退出,注意是先同时按下 Ctrl + A ,然后松开,按下 X。

Sixfive

  • 需要先根据给 kernel 和 User 中的一些文件(比如 stat fstat),先学会如何打开和读写文件。(得看之前在sleep 中提示的一些文件)
  • 记得看看他们 include 的文件,可以跳转看看,你会得到一些帮助(AI 很有用)
  • 网络上也可以查找一些有关读写文件的函数,他们也很有用。
  • Sixfive 的简单来说是从-./这些字符中提取数字。
  • 你可以使用一个缓冲区存储数字(如果它不是字符的话),逐步遍历从文件中读取的内容(数字的拼凑涉及一些智力游戏)

Memdump

  • 关于 %d %c (或者更多)与 printf 相关的内容,或许你可以问问 AI ,他会给你更多内容,大概会得到想要的。
  • 需要注意的是,给你的内容不一定需要完全照搬,可能你需要一些调整(比如,你看看他给的 uint 定义)
  • 注意 char * data 的相关用法,你可以一些简单的方法得到其中的数据并解析出来。

Find 

  • 注意他给你的关于要读东西提示,大概率能获得一些东西。
  • 利用好 User 中的一些函数,他们会给出帮助。
  • 如果你完成了Sixfive ,你会有一些想法。
  • 想想递归的操作,想想如何用读出来的文件名字拼凑一个文件目录(ai 可以给出一些想法)
  • 不要忘记字符串的结尾'\0',它值得注意和判断。

Exec

  • 如果你完成了上述内容,相信你从命令行中读取参数已经是得心应手,你在 find 只需要另加一个函数拆分它们而已,提取你需要的那一部分而已。
  • 注意 Fork 与 Exec 与 Wait 的用法

碎碎念

  • 周末周日两天写完 Lab 1 ,用时 4+3+4 合计 11 小时
  • 先说下我写的时候的整体思路
    • 首先会看提示,如果不明白就问 AI,具体来说,比如 Memdump 中给的示例输出结果,我就是问了 AI,这很有帮助。
    • 然后就是找相关的文件读,找自己需要那些部分的内容,需要用到那些函数,看看整个过程需要那些调用什么,不行还是问 AI
    • 下来阶段就是自己写了,自己写的时候就是经常卡住。我的自己回想了下,大概分为两个方面,一个是==不知道该做些什么==,另一个是==知道该干啥但不会==,解决办法还是问 AI ,一步一步的,不知道思路就让 ==AI 提示思路==,不知道方法就问==如果我想要什么什么该怎么做==
    • 走到这一部分应该可以写出来一个差不多的框架了,剩下时间就是调试了,当然如果你在这里还是可以让 ai 帮你修改。
  • 写的时间并没有很多,在读代码和调试花费的时间最多,我在 find 里面了犯了一个错误,当时想着提示 ls 函数,当时读完看着里面有函数好像用上,救把想着复用了里面的函数,结果最后还是大改了,看了其他人的代码,我的显得更加麻烦了。
  • 我觉得关键不是如何完成这个实验,而从这一个个实验中查找和问 AI的过程更加令人珍贵的,
  • 这里引用一下

Note 对于用户态程序,只需将对应系统调用编号 (SYS_sleep) 存入 a7 寄存器,随后执行 ecall 指令即可进入内核执行 sleep 系统调用。

站在用户的视角,系统调用宛如一个黑匣,只需把对应参数存入对应内存或寄存器,执行 ecall 后便能得到一个我们期望的状态。jyy :”操作系统中没有任何魔法。” —— 那我们便会有疑问,ecall 后执行了什么代码?ecall 又是如何定位到对应代码?

然而面对庞大的内核代码,一行行的检索代码显然是不优雅的,曾经最为普遍的解决方式大概是阅读 xv6 book —— Chapter 4 Traps and system calls,然而当今更为推荐利用 AI 帮助我们检索代码,例如:

QA: 在 xv6 中,当用户进程执行 ecall 指令(RISC-V 平台)后,处理器会触发一个 陷入(trap),从用户态(U-mode)切换到内核态(S-mode),并执行相应的内核代码。以下是 sleep 系统调用的执行流程: 123balabala… 总结: 整个 sleep 系统调用流程:

  1. 用户进程执行 sleep(n),触发 ecall

  2. usertrap() 处理 ecall,调用 syscall()

  3. syscall() 调用 sys_sleep(),进入 sleep()

  4. sleep() 使进程睡眠,调用 sched() 进行调度。

  5. 时钟中断 clockintr() 增加 ticks,调用 wakeup() 唤醒进程。

  6. scheduler() 重新调度 sleep 进程,恢复执行。

  • AI 是很好的老师,我们应该会它们。

Lab 2 System calls

Using gdb

  • 教你如何使用 gdb 的教程(不过我不太喜欢用),我在做的时候运行 gdb并没有自动连接 qemu,得 target 一下端口。

Sandbox a command / Sandbox with allowed pathnames

  • 我先说下容易做到的想法,就是直接用 mask &(1 << system calls)进行判断可以了(如果按照他的那些要求把前置工作理顺了
  • 当然,问题显而易见的,整个程序的颗粒度不够,更详细的测试样例就不会通过(比如后续关于访问路径的问题就不能解决)
  • 你需要对这些输入的路径文件进行更详细的判断
  • 我先说下我错误的思路,尽量不要在 open 和 exec 中进行判断路径是否合法(我是这样做了,当但最后还是没有弄明白,但仔细看题目,他好像也不要求在其中更改内容),在 syscall 中初始化的进行判断(记得在 sys_interpose() 完成参数获取),如果是 open 和 exec 类的调用,单独抽出来就行了路径合法判断就行了。
  • 可能需要的某些函数没有(你可能需要手搓一下)

Attack xv6

  • 用最简单的方法就行
  • 注意 sprk 函数的用法和给你 data 数组
  • 撞“页”就是了

碎碎念

  • 本次耗时 3+3+1
  • 说起来也是写了不少公开课了,体感上是题目给的要求更容易读懂了,第一次开始学的时期,“知识的诅咒”总是留在身上,写完了才完完全全清楚了。
  • 快到 11 月份了,时间真是过的飞快,按照之前的计划我应该在 11 月上旬把 lab 写完的,可惜按照现在一周两个的进度是完不成了,转完专业后要补的课太麻烦了,这学期要比正常情况多上4 门,不然时间还是相当充裕的。
  • 计网本来打算在 11 月开的,这下也是遥遥无期了,刷题也是少的可怜,学不完啊,学不完啊
  • 世事悠悠浑未了,年光冉冉今如许