Lab1: Xv6 and Unix utilities
This lab will familiarize you with xv6 and its system calls.
Boot xv6 (easy)
You can do these labs on an Athena machine or on your own computer. If you use your own computer, have a look at the lab tools page for setup tips.
If you use Athena, you must use an x86 machine; that is, uname -a
should mention i386 GNU/Linux
or i686 GNU/Linux
or x86_64 GNU/Linux
. You can log into a public Athena host with ssh -X athena.dialup.mit.edu
. We have set up the appropriate compilers and simulators for you on Athena. To use them, run add -f 6.828. You must run this command every time you log in (or add it to your ~/.environment
file). If you get obscure errors while compiling or running qemu
, check that you added the course locker.
Fetch the xv6 source for the lab and check out the util
branch:
$ git clone git://g.csail.mit.edu/xv6-labs-2021
Cloning into 'xv6-labs-2021'...
...
$ cd xv6-labs-2021
$ git checkout util
Branch 'util' set up to track remote branch 'util' from 'origin'.
Switched to a new branch 'util'
The xv6-labs-2021 repository differs slightly from the book’s xv6-riscv; it mostly adds some files. If you are curious look at the git log:
$ git log
The files you will need for this and subsequent lab assignments are distributed using the Git version control system. Above you switched to a branch (git checkout util) containing a version of xv6 tailored to this lab. To learn more about Git, take a look at the Git user’s manual, or, you may find this CS-oriented overview of Git useful. Git allows you to keep track of the changes you make to the code. For example, if you are finished with one of the exercises, and want to checkpoint your progress, you can commit your changes by running:
$ 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(-)
$
You can keep track of your changes by using the git diff command. Running git diff will display the changes to your code since your last commit, and git diff origin/util will display the changes relative to the initial xv6-labs-2021 code. Here, origin/xv6-labs-2021
is the name of the git branch with the initial code you downloaded for the class.
Build and run 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
$
If you type ls
at the prompt, you should see output similar to the following:
$ ls
. 1 1 1024
.. 1 1 1024
README 2 2 2059
xargstest.sh 2 3 93
cat 2 4 24256
echo 2 5 23080
forktest 2 6 13272
grep 2 7 27560
init 2 8 23816
kill 2 9 23024
ln 2 10 22880
ls 2 11 26448
mkdir 2 12 23176
rm 2 13 23160
sh 2 14 41976
stressfs 2 15 24016
usertests 2 16 148456
grind 2 17 38144
wc 2 18 25344
zombie 2 19 22408
console 3 20 0
These are the files that mkfs
includes in the initial file system; most are programs you can run. You just ran one of them: ls
.
xv6 has no ps
command, but, if you type Ctrl-p, the kernel will print information about each process. If you try it now, you’ll see two lines: one for init
, and one for sh
.
To quit qemu type: Ctrl-a x.
Grading and hand-in procedure
You can run make grade to test your solutions with the grading program. The TAs will use the same grading program to assign your lab submission a grade. Separately, we will also have check-off meetings for labs (see Grading policy).
The lab code comes with GNU Make rules to make submission easier. After committing your final changes to the lab, type make handin to submit your lab. For detailed instructions on how to submit see below.
sleep (easy)
Implement the UNIX program sleep
for xv6; your sleep
should 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 file user/sleep.c
.
Some hints:
- Before you start coding, read Chapter 1 of the xv6 book.
- Look at some of the other programs in
user/
(e.g.,user/echo.c
,user/grep.c
, anduser/rm.c
) to see how you can obtain the command-line arguments passed to a program. - If the user forgets to pass an argument, sleep should print an error message.
- The command-line argument is passed as a string; you can convert it to an integer using
atoi
(see user/ulib.c). - Use the system call
sleep
. - See
kernel/sysproc.c
for the xv6 kernel code that implements thesleep
system call (look forsys_sleep
),user/user.h
for the C definition ofsleep
callable from a user program, anduser/usys.S
for the assembler code that jumps from user code into the kernel forsleep
. - Make sure
main
callsexit()
in order to exit your program. - Add your
sleep
program toUPROGS
in Makefile; once you’ve done that,make qemu
will compile your program and you’ll be able to run it from the xv6 shell. - Look at Kernighan and Ritchie’s book The C programming language (second edition) (K&R) to learn about C.
Run the program from the xv6 shell:
$ make qemu
...
init: starting sh
$ sleep 10
(nothing happens for a little while)
$
Your solution is correct if your program pauses when run as shown above. Run make grade to see if you indeed pass the sleep tests.
Note that make grade runs all tests, including the ones for the assignments below. If you want to run the grade tests for one assignment, type:
$ ./grade-lab-util sleep
This will run the grade tests that match “sleep”. Or, you can type:
$ make GRADEFLAGS=sleep grade
which does the same.
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int autoi(const char*s){
int n=0;
while('0'<=*s&&*s<='9'){
n=n*10+*s-'0';
}
return n;
}
int
main(int argc,char*argv[]){
if(argc!=2){
// //2表示标准错误输出
// fprintf(2, "usage: grep [time]\n");
fprintf(2,"usage: grep [time]\n");
//1表示异常退出
exit(1);
}
int n=autoi(argv[1]);
sleep(n);
exit(0);
}
pingpong (easy)
Write a program that uses UNIX 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
.
Some hints:
- Use
pipe
to create a pipe. - Use
fork<