# Lab: xv6

This lab makes you familiar with xv6 and its system calls.

## Boot xv6

Login to Athena (e.g., ssh -X athena.dialup.mit.edu) and attach the course locker: (You must run this command every time you log in; or add it to your ~/.environment file.)

    $ add -f 6.828

Fetch the xv6 source:

    $ mkdir 6.828
    $ cd 6.828
    $ git clone git://github.com/mit-pdos/xv6-riscv.git
    Cloning into 'xv6-riscv'...
    ...
    $

XXX pointer to an update tools page

Build xv6 on Athena:

    $ cd xv6-public
    $ makeriscv64-linux-gnu-gcc    -c -o kernel/entry.o kernel/entry.S
    riscv64-linux-gnu-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -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
    ...
    $ make qemu
    ...
    mkfs/mkfs fs.img README 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/_wc user/_zombie user/_cow
    nmeta 46 (boot, super, log blocks 30 inode blocks 13, bitmap blocks 1) blocks 954 total 1000
    balloc: first 497 blocks have been allocated
    balloc: write bitmap block at sector 45
    qemu-system-riscv64 -machine virt -kernel kernel/kernel -m 3G -smp 3 -nographic -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
    hart 0 starting
    hart 2 starting
    hart 1 starting
    init: starting sh
    $

If you type `ls` at the prompt, you should output similar to the following:

    $ ls
    .              1 1 1024
    ..             1 1 1024
    README         2 2 2181
    cat            2 3 21024
    echo           2 4 19776
    forktest       2 5 11456
    grep           2 6 24512
    init           2 7 20656
    kill           2 8 19856
    ln             2 9 19832
    ls             2 10 23280
    mkdir          2 11 19952
    rm             2 12 19936
    sh             2 13 38632
    stressfs       2 14 20912
    usertests      2 15 106264
    wc             2 16 22160
    zombie         2 17 19376
    cow            2 18 27152
    console        3 19 0

These are the programs/files that `mkfs` includes in the initial file system. You just ran one of them: `ls`.

## sleep

Implement the UNIX program sleep for xv6; your sleep should pause for a user-specified number of ticks.

Some hints:

- Look at some of the other programs in `user/` 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 user/usys.S and kernel/sysproc.c).
- Make sure `main` calls `exit()` in order to exit your program.
- Add the program to `UPROGS` in Makefile and compile user programs by typing `make fs.img`.

Run the program from the xv6 shell:

          $ make qemu
          ...
          init: starting sh
          $ sleep 10
          (waits for a little while)
          $

Optional: write an uptime program that prints the uptime in terms of ticks using the `uptime` system call.

## pingpong

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 sends by writing a byte to `fd[1]` and the child receives it by reading from `fd[0]`. After receiving a byte from parent, the child responds with its own byte by writing to `fd[1]`, which the parent then reads.

Some hints:

- Use `pipe` to create a pipe.
- Use `fork` to create a child.
- Use `read` to read from the pipe, and `write` to write to the pipe.

## primes

Write a concurrent version of prime sieve using pipes. This idea is due to Doug McIlroy, inventor of Unix pipes. The picture halfway down the page and the text surrounding it explain how to do it.

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:

- Be careful to close file descriptors that a process doesn't need, because otherwise your program will run xv6 out of resources before the first process reaches 35.
- Once the first process reach 35, you should arrange that the pipeline terminates cleanly (Hint: read will return an end-of-file when the write-side of the pipe is closed).

## find

Write a simple version of the UNIX find program: find all the files in a directory tree whose name matches a string. For example if the file system contains a file `a/b`, then running find as follows should produce:

        $ find . b
        ./a/b
        $

Some hints:

- Look at user/ls.c to see how to read directories.
- Use recursion to run find in sub-directories.
- Don't recurse into "." and "..".

Optional: support regular expressions in name matching. Grep has some primitive support for regular expressions.

## xargs

Write a simple version of the UNIX xargs program: read lines from standard in and run a command for each line, supplying the line as arguments to the command. The following example illustrates xarg's behavior:

        $ xargs echo bye
        hello too
        bye hello too

        $

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".

xargs and find combine well:

        find . b | xargs grep hello

will run "grep hello" on each file named b in the directories below ".".

Some hints:

- Use `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.
- Read from stdin a character at the time until the newline character ('\n').
- kernel/param.h declares MAXARG, which may be useful if you need to declare an argv.

## Optional: modify the shell

There are endless ways in which the shell could be extended. Here are some suggestions:

- Modify the shell to support wait.
- Modify the shell to support lists of commands, separated by ";"
- Modify the shell to support sub-shells by implementing "(" and ")"
- Modify the shell to allow users to edit the command line