This lab makes you familiar with xv6 and its system calls.
Install QEMU and gcc for RISC-V following the directions on the tools page.
Fetch the xv6 source for the lab and check out a new branch for your solution to this lab:
The xv6-21au repository differs slightly from the book’s xv6-riscv in order to make the labs easier.
The files you will need for this and subsequent lab assignments in this course are distributed using the Git version control system. Above you created a new branch (“util”) for your solutions for the utilities 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:
You can keep track of your changes by using the git diff command.
For example,
git diff will display the changes to your code since your last commit,
and git diff origin/xv6-21au will display the changes relative to the initial
xv6-21au code. Here, origin/xv6-21au
is the name of the git branch with the initial code you downloaded for the class.
Build xv6:
If you type ls at the prompt, you should see output similar to the following:
These are the programs/files that mkfs
includes in the initial
file system. You just ran one of them: ls
.
To quit QEMU, type Ctrl-a x, which means:
You may create a private fork of the xv6 repository for collaboration or backup (e.g., using the CSE GitLab). You can add this new repository as a git remote to which you can push/pull your commits. For example, to back up branch to a remote named “mybackup” for the repository at url, you can run:
Do not host your lab code on publicly accessible web sites (e.g., GitHub) or file spaces (e.g., CSE GitLab’s non-private projects).
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.
To turn in your assignments, use make tarball to make a tar file, and upload the file via Canvas.
If you have either uncomitted changes or untracked files, you will see output similar to the following:
Inspect the above lines and make sure all files that your lab
solution needs are tracked (i.e., not listed in a line that begins
with ??
).
You can cause Git to track a new file that you create using git add filename.
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:
user/
((e.g., user/echo.c
, user/grep.c
, and user/rm.c
)) to see how you can obtain the command-line arguments passed to a program.atoi
(see user/ulib.c
).sleep
.kernel/sysproc.c
for the xv6 kernel code that implements the sleep
system call (look for sys_sleep
), user/user.h
for the C definition of sleep
callable from a user program, and user/usys.S
for the assembler code that jumps from user code into the kernel for sleep.exit()
in order to exit your program.UPROGS
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.Run the program from the xv6 shell:
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:
This will run the grade tests that match “sleep”. Or, you can type:
which does the same.
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
“<pid>: received ping”, where <pid> 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 “<pid>: received pong”, and exit.
Your solution should be in the file user/pingpong.c
.
Some hints:
pipe
to create a pipe.fork
to create a child.read
to read from the pipe, and write
to write to the pipe.getpid
to find the process ID of the calling process.UPROGS
in Makefile
.user/user.h
; the source (other than for system calls)
is in user/ulib.c
, user/printf.c
, and user/umalloc.c
.Run the program from the xv6 shell and it should produce the following output:
Your solution is correct if your program exchanges a byte between two processes and produces output as shown above.
Write a concurrent version of prime sieve using pipes. This idea
is due to Doug McIlroy, inventor of Unix pipes. The picture halfway
down this page and the surrounding
text explain how to do it. Your solution should be in the file
user/primes.c
.
Your goal is to use pipe
and fork
to set up the pipeline. The
first process feeds the numbers 2 through 35 into the pipeline. For
each prime number, you will arrange to create one process that reads
from its left neighbor over a pipe and writes to its right neighbor
over another pipe. Since xv6 has limited number of file descriptors
and processes, the first process can stop at 35.
Some hints:
read
returns zero when the write-side of a pipe is closed.int
s to the pipes,
rather than using formatted ASCII I/O.UPROGS
in Makefile
.Your solution is correct if it produces the following output:
Write a simple version of the Unix find
program: find all the files
in a directory tree whose name matches a string. Your solution
should be in the file user/find.c
.
Some hints:
user/ls.c
to see how to read directories.==
does not compare strings like in Python. Use strcmp()
instead.UPROGS
in Makefile
.Your solution is correct if produces the following output (when the file system contains a file a/b
):
Write a simple version of the Unix xargs
program: read lines from
standard input and run a command for each line, supplying the line
as arguments to the command. Your solution should be in the file
user/xargs.c
.
The following example illustrates xarg’s behavior:
Note that the command here is “echo bye” and the additional arguments are “hello too”, making the command “echo bye hello too”, which outputs “bye hello too”.
Some hints:
fork
and exec
system call to invoke the command on each
line of input. Use wait
in the parent to wait for the child to
complete running the command.kernel/param.h
declares MAXARG
, which may be useful if you need to declare an argv array.UPROGS
in Makefile
.xargs
, find
, and grep
combine well:
will run “grep hello” on each file named b
in the directories below “.
”.
To test your solution for xargs, run the shell script xargstest.sh
.
Your solution is correct if it produces the following output:
You may have to fix bugs in your find program. The output has many
$
because the xv6 shell is primitive and doesn’t realize it is
processing commands from a file instead of from the console, and
prints a $
for each command in the file.
Write an uptime program that prints the uptime in terms of ticks using the uptime
system call.
Support regular expressions in name matching. grep.c
has some primitive support for regular expressions.
The xv6 shell (user/sh.c
) is a minimal shell and lacks many features found in real shell.
You can improve it. Here are some suggestions:
$
when processing shell commands from a file.This completes the lab. In the lab directory, commit your changes, type make tarball, and submit the tarball through Canvas.