Lab 1: Xv6 and Unix utilities
Lab 1: Xv6 and Unix utilities
这个lab将会使你熟悉xv6个它的系统调用。
Boot xv6 (easy)
你可以在Athena或者你自己的电脑上进行这些实验。如果你使用自己电脑进行实验,你需要看一下lab tools page中的配置提示。
如果你使用 Athena,你必须使用 x86 机器;也就是说,uname -a
应该显示 i386 GNU/Linux
或 i686 GNU/Linux
或 x86_64 GNU/Linux
。你可以通过 ssh -X athena.dialup.mit.edu
登录到公共 Athena 主机。我们在 Athena 上为你设置了适当的编译器和模拟器。要使用它们,请运行 add -f 6.828
。你必须在每次登录时运行此命令(或将其添加到你的 ~/.environment
文件中)。如果你在编译或运行 qemu 时遇到晦涩的错误,请检查你是否添加了课程锁存器。 获取 xv6 实验的 git 仓库源代码:
$ git clone git://g.csail.mit.edu/xv6-labs-2022
Cloning into 'xv6-labs-2022'...
...
$ cd xv6-labs-2022
仓库设置为在克隆仓库时检出 util
分支。
$ git status
On branch util
Your branch is up to date with 'origin/util'.
nothing to commit, working tree clean
xv6-labs-2022
仓库与书中的 xv6-riscv
略有不同;它主要添加了一些文件。如果你好奇,可以查看 git 日志:
$ git log
你将需要使用 Git 版本控制系统分发的文件来完成这个和后续的实验任务。对于每个实验,你将检出(git checkout util
)一个为该实验定制的 xv6 版本。要了解更多关于 Git 的信息,请查看 Git 用户手册,或者你可能会发现这个面向计算机的 Git 概述很有用。Git 允许你跟踪对代码所做的更改。例如,如果你完成了其中一个练习,并且想要检查你的进度,你可以通过运行以下命令提交你的更改:
$ git commit -am 'my solution for util lab exercise 1'
Created commit 60d2135: my solution for util lab exercise 1
1 files changed, 1 insertions(+), 0 deletions(-)
$
你可以使用 git diff
命令跟踪你的更改。运行 git diff
将显示自上次提交以来对代码的更改,而 git diff origin/util
将显示相对于初始 util
代码的更改。在这里,origin/util
是你为课程下载的初始代码的 git 分支名称。
构建并运行 xv6:
$ make qemu
riscv64-unknown-elf-gcc -c -o kernel/entry.o kernel/entry.S
riscv64-unknown-elf-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -DSOL_UTIL -MD -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie -c -o kernel/start.o kernel/start.c
...
riscv64-unknown-elf-ld -z max-page-size=4096 -N -e main -Ttext 0 -o user/_zombie user/zombie.o user/ulib.o user/usys.o user/printf.o user/umalloc.o
riscv64-unknown-elf-objdump -S user/_zombie > user/zombie.asm
riscv64-unknown-elf-objdump -t user/_zombie | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$/d' > user/zombie.sym
mkfs/mkfs fs.img README user/xargstest.sh user/_cat user/_echo user/_forktest user/_grep user/_init user/_kill user/_ln user/_ls user/_mkdir user/_rm user/_sh user/_stressfs user/_usertests user/_grind user/_wc user/_zombie
nmeta 46 (boot, super, log blocks 30 inode blocks 13, bitmap blocks 1) blocks 954 total 1000
balloc: first 591 blocks have been allocated
balloc: write bitmap block at sector 45
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
xv6 kernel is booting
hart 2 starting
hart 1 starting
init: starting sh
$
如果你在提示符下输入 ls
,你应该会看到类似以下的输出:
$ ls
. 1 1 1024
.. 1 1 1024
README 2 2 2227
xargstest.sh 2 3 93
cat 2 4 32864
echo 2 5 31720
forktest 2 6 15856
grep 2 7 36240
init 2 8 32216
kill 2 9 31680
ln 2 10 31504
ls 2 11 34808
mkdir 2 12 31736
rm 2 13 31720
sh 2 14 54168
stressfs 2 15 32608
usertests 2 16 178800
grind 2 17 47528
wc 2 18 33816
zombie 2 19 31080
console 3 20 0
这些是 mkfs
包含在初始文件系统中的文件;大多数是你可以运行的程序。你刚刚运行了其中一个:ls
。
xv6 没有 ps
命令,但是,如果你输入 Ctrl-p
,内核将打印每个进程的信息。如果你现在尝试,你会看到两行:一行是 init
,另一行是 sh
。
要退出 qemu,请输入:Ctrl-a x
(同时按下 Ctrl
和 a
,然后按 x
)。
评分和提交程序
你可以运行 make grade
来使用评分程序测试你的解决方案。助教将使用相同的评分程序为你的实验提交评分。此外,我们还将为实验安排检查会议(见评分政策)。
实验代码附带了 GNU Make 规则,以简化提交过程。在提交实验的最终更改后,输入 make handin
以提交你的实验。有关如何提交的详细说明,请参见下文。
sleep (easy)
重要
你需要在 xv6 中实现一个 UNIX 程序 sleep
,该程序会暂停用户指定的时间(以 ticks 为单位)。ticks 是 xv6 内核定义的时间概念,即定时器芯片两次中断之间的时间。你的解决方案应该放在文件 user/sleep.c
中。 ### 提示:
- 阅读 xv6 书籍的第 1 章:在开始编码之前,先阅读 xv6 书籍的第 1 章,了解 xv6 的基本概念和系统调用。
- 参考其他用户程序:查看
user/
目录下的其他程序(例如user/echo.c
、user/grep.c
和user/rm.c
),了解如何获取传递给程序的命令行参数。 - 处理用户忘记传递参数的情况:如果用户忘记传递参数,
sleep
应该打印一条错误消息。 - 将字符串转换为整数:命令行参数以字符串形式传递;你可以使用
atoi
将其转换为整数(参见user/ulib.c
)。 - 使用系统调用
sleep
:使用sleep
系统调用。 - 查看系统调用的实现:查看
kernel/sysproc.c
中的sys_sleep
函数,了解sleep
系统调用在 xv6 内核中的实现;查看user/user.h
中的sleep
函数定义,了解如何在用户程序中调用sleep
;查看user/usys.S
中的汇编代码,了解如何从用户代码跳转到内核代码执行sleep
。 - 退出程序:
main
函数完成后应调用exit(0)
。 - 将程序添加到 Makefile:将你的
sleep
程序添加到Makefile
中的UPROGS
;完成后,运行make qemu
将编译你的程序,并且你可以在 xv6 shell 中运行它。 - 学习 C 语言:查看 Kernighan 和 Ritchie 的《C 程序设计语言》(第二版)(K&R),学习 C 语言。
运行程序:
$ make qemu
...
init: starting sh
$ sleep 10
(nothing happens for a little while)
$
如果你的程序如上所示运行时暂停,则你的解决方案是正确的。运行 make grade
查看你是否通过了 sleep
测试。
注意,make grade
会运行所有测试,包括下面任务的测试。如果你想运行特定任务的评分测试,可以输入:
$ ./grade-lab-util sleep
这将运行与 sleep
匹配的评分测试。或者,你可以输入:
$ make GRADEFLAGS=sleep grade
实验代码
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
int sleepTime ;
if(argc < 2){
fprintf(2, "Usage: sleep time...\n");
exit(1);
}
sleepTime = atoi(argv[1]);
sleep(sleepTime);
return 0;
}
pingpong (easy)
重要
编写一个使用 UNIX 系统调用通过一对管道在两个进程之间进行“乒乓”字节交换的程序。父进程应向子进程发送一个字节;子进程应打印“pid: received ping”,其中 pid 是它的进程 ID,将字节写入管道发送给父进程,然后退出;父进程应从子进程读取字节,打印“pid: received pong”,然后退出。你的解决方案应放在文件 user/pingpong.c
中。