I chose to do riscv today but doing x86 will probably be faster.

Compiling the RISCV Toolchain

We need to do this to obtain riscv64-unknown-linux-gnu-gcc

git clone --depth 1 https://github.com/mit-pdos/xv6-riscv
git clone --depth 1 https://github.com/riscv-collab/riscv-gnu-toolchain
cd riscv-gnu-toolchain
sudo apt-get install autoconf automake autotools-dev curl python3 python3-pip libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev ninja-build git cmake libglib2.0-dev
./configure --prefix=/opt/riscv
sudo make linux # this takes forever

Compiling QEMU

We need to do this to obtain qemu-system-riscv64

git clone --branch v5.0.0 --depth 1 https://github.com/qemu/qemu
cd qemu
./configure --target-list=riscv64-softmmu --disable-docs
make -j8
sudo make install

Compiling xv6

cd ../xv6-riscv
TOOLPREFIX=/opt/riscv/bin/riscv64-unknown-linux-gnu- make qemu

If all goes well, you should boot into a shell

xv6 kernel is booting

hart 1 starting
hart 2 starting
init: starting sh
$ 
$ ls
.              1 1 1024
..             1 1 1024
README         2 2 2305

To exit qemu, press Ctrl-A X.

Debugging xv6

Optionally, run with gdb attached

TOOLPREFIX=/opt/riscv/bin/riscv64-unknown-linux-gnu- make qemu-gdb

Then, in another terminal, run

/opt/riscv/bin/riscv64-unknown-linux-gnu-gdb
target remote :26000 # or whatever port they said above
continue
Ctrl-C # to send interrupt
break swtch
c
# go back and type something in the shell

Poking the kernel code

sh.c Command Types

I injected the following into sh.c.

  struct pipecmd *pcmd;
  struct redircmd *rcmd;
  fprintf(2, "tch is here, type = %d\n", cmd->type);

  if(cmd == 0)
    exit(1);

Then I recompiled using make qemu. The output is

$ ls 
tch is here, type = 1
... # rest of output

If we look at sh.c, we see that 1 corresponds to EXEC.

#define EXEC  1
#define REDIR 2
#define PIPE  3
#define LIST  4
#define BACK  5
  • EXEC is running any command
  • REDIR is for redirecting output via > to a file
  • PIPE is for piping output via | to another program
  • LIST is for a list of commands, separated by ;
  • BACK is for running a command in the background using &

Balemarthy Part 5 talks about the implementation in detail.

Let’s try to implement a few new features following this Harshal tutorial. We will do that in another post!