MIT 6.s081 (6.1810) 学习记录-Lab1-Xv6 and Unix utilities
基础环境
首先要根据lab tools page 配置Linux环境,我使用的是Ubuntu 22.04的服务器版本
1 | sudo apt-get install git build-essential gdb-multiarch qemu-system-misc gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu |
环境测试
由于本实验的运行环境在RISC-V架构下,所以需要测试在RISC-V的基本环境下是否可以正常编译并运行xv6系统
1 | 版本检查 |
获取并启动xv6(easy)
从git仓库中获取xv6源代码
1 | git clone git://g.csail.mit.edu/xv6-labs-2023 |
编译并运行xv6
1 | make qemu |
启动后应该会有如下输出:
1 | qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -global virtio-mmio.force-legacy=false -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 |
此时xv6系统已经正常启动,并且已经启动sh终端,在$的提示符后输入ls会显示当前文件夹的输出:
1 | ls |
此时一个简单的xv6操作系统就启动好了,如果要在Linux终端中退出xv6,需要按下Ctrl+A然后按下X回到正常的Linux终端
实现用户级sleep程序 (easy)
题目要求:Implement a user-level
sleepprogram for xv6, along the lines of the UNIX sleep command. Yoursleepshould pause for a user-specified number of ticks. A tick is a notion of time defined by the xv6 kernel, namely the time between two interrupts from the timer chip. Your solution should be in the fileuser/sleep.c.
按照 UNIX sleep 命令的思路,为 xv6 实现用户级sleep程序。您的sleep应暂停用户指定的刻度数。时钟周期是 xv6 内核定义的时间概念,即定时器芯片两次中断之间的时间。您的解决方案应该位于文件user/sleep.c中。
-
将代码放入
user/sleep.c中。查看user/中的一些其他程序(例如user/echo.c、user/grep.c和user/rm.c)以了解命令行参数如何被传递给一个程序1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// user/echo.c
int
main(int argc, char *argv[])
//argc是命令行参数的数量,包括程序名称本身,当它的值为1时,只有程序名本身
// argv是一个指向字符指针的指针,用于存储命令行参数的字符串。它的每一个字符串都是一个命令行参数
{
int i;
for(i = 1; i < argc; i++){
write(1, argv[i], strlen(argv[i]));
if(i + 1 < argc){
write(1, " ", 1);
} else {
write(1, "\n", 1);
}
}
exit(0);
} -
将
sleep程序添加到 Makefile 中的UPROGS中;完成此操作后,make qemu将编译您的程序,并且您将能够从 xv6 shell 运行它 -
使用系统调用
sleep完成sleep.c,如果用户忘记传递参数,sleep 应该打印一条错误消息,命令行参数作为字符串传递,可以使用atoi将其转换为整数(可参阅 user/ulib.c)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int
main(int argc, char *argv[])
{
if(argc < 1){
fprintf(2, "sleep: missing operand\nusage: sleep time...\n");
exit(1); //表示异常退出.这个1是返回给操作系统的。
}else{
sleep(atoi(argv[1]));
}
exit(0); //表示正常退出
}
fprintf函数的第一个参数为文件指针(文件描述符),通常在Unix系统中:
0:标准输入(stdin)
1:标准输出(stdout)
2:标准错误输出(stderr)
-
从 xv6 shell 运行程序:
1
2
3make qemu
sleep 10
./grade-lab-util sleep #使用Grade进行成绩测试
pingpong (easy)
题目要求:Write a user-level program that uses xv6 system calls to ‘‘ping-pong’’ a byte between two processes over a pair of pipes, one for each direction. The parent should send a byte to the child; the child should print “
: received ping”, where is its process ID, write the byte on the pipe to the parent, and exit; the parent should read the byte from the child, print “ : received pong”, and exit. Your solution should be in the file user/pingpong.c.
编写一个用户级程序,使用 xv6 系统调用通过一对管道(每个方向一个)在两个进程之间“乒乓”一个字节。父进程应向子进程发送一个字节;子进程应打印“:已收到 ping”,其中 是其进程 ID,将管道上的字节写入到父进程,然后退出;父进程应该从子进程读取字节,打印“:收到 pong”,然后退出。您的解决方案应该位于文件user/pingpong.c中。
-
使用
pipe创建管道;int pipe(int p[]) Create a pipe, put read/write file descriptors in p[0] and p[1].
-
使用
fork创建一个子进程;int fork() Create a process, return child’s PID.
-
使用
read从管道读取,使用write写入管道;int write(int fd, char *buf, int n) Write n bytes from buf to file descriptor fd; returns n.
int read(int fd, char *buf, int n) Read n bytes into buf; returns number read; or 0 if end of file.
-
使用
getpid查找调用进程的进程ID;int getpid() Return the current process’s PID.
xv6 采用传统的内核形式,是一个为正在运行的程序提供服务的特殊程序。每个正在运行的程序(称为进程)都有包含指令、数据和堆栈的内存,这些指令实现程序的计算。
计算机通常具有许多进程,但只有一个内核,当进程需要调用内核服务时,它会调用系统调用,这是操作系统接口中的调用之一。系统调用进入内核,由内核执行服务并返回。
1 |
|
