LoginSignup
6
2

More than 3 years have passed since last update.

WSL2 と QEMU と Vim で xv6 のステップ実行環境をつくる

Last updated at Posted at 2021-03-22

はじめに

Tech Commit の LT発表会 で OS のコードリ-ディングをやってらっしゃる方のお話を聞いて、自分もまた UNIX V6 のコード読みたい欲が高まり、積ん読してた書籍 をパラパラめくってみたのですがやはり難しい。
記載されている古い書き方の C言語やアセンブリを解読しつつ OS の仕組みを理解するのは自分の場合茨の道だなぁとあらためて感じました。
エミュレータ で実際にコードを動かしながら読めば分かりやすいのかな?と思い色々調べているうちに、xv6 というマサチューセッツ工科大(MIT) の Operating System Engineering のクラスで使用される UNIX V6 を ANSI の C で書き換えて x86 (またはRISC-V) ベースに作りなおされた OS がある!という事を知ったので、早速動かしてみようと思い立ちました。

xv6 について

UNIX V6 がベースであるため OS の基本的なアイディアがほぼ全て詰まっているけどコード量は1万行弱(Linuxの場合2200万行以上)で、OS の学習にはもってこいだと思います。

xv6 が起動する仮想環境の準備

xv6 は仮想マシン上で動かすことが想定されており、bochs や QEMU で動くように環境が整備されています。以前は x86 の仮想環境で動作しましたが、最近の版では RISC-V に変わっているためクロスコンパイル用の開発ツールをインストールする必要があります。Linux の場合は比較的簡単です。
今回は WSL2 でやりましたが、Ubuntu20.04 でも全く同じ手順で大丈夫だと思います。

まずは必要なパッケージをインストールします。

$ sudo apt-get install qemu-kvm git build-essential gdb-multiarch qemu-system-misc gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu texinfo

次に xv6 のソースコードを取得しビルドします。

$ git clone git://github.com/mit-pdos/xv6-riscv.git
$ cd xv6-riscv
$ make

ここまで出来たら QEMU で xv6 を起動してみます。 同ディレクトリ上で make qemu と打ちます。

$ make qemu
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 1 starting
hart 2 starting
init: starting sh
$

上記の様に起動し、ターミナル上で xv6 のシェルが起動し入力を受け付ける様になります。
xv6 から抜けるには [ctrl-A][x]の順にタイプします。

GDB のインストール

GDB(GNUデバッガ)は、プログラムの不具合解析や値を参照・一時的に変更する等して動作をテストする際に使用するツールです。ここでは RISC-V 用にクロスデバッグ可能な gdb をインストールします。
こちらからソースコードをダウンロードし、以下の手順でインストールします。

$ tar xvzf gdb-10.1.tar.gz
$ cd gdb-10.1
$ ./configure --program-prefix=riscv- --target=riscv
$ make
$ sudo make install

(※上記でパスが通ったディレクトリにインストールされなかった為、 sudo cp gdb/gdb /usr/local/bin でバイナリを配置しました。ここ後で修正します。)

Vim によるステップ実行

Vim8.1 から、標準で GDB を扱える用になっています。これがものすごく便利です。

まずは xv6 を gdb モードで起動します。


$ make qemu-gdb
*** Now run 'gdb' in another window.
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 -S -gdb tcp::26000

もう一つ別なターミナルを起動後 xv6-riscv ディレクトリに移動し vim を起動、コマンドモードで :Termdebug kernel/kernel とタイプすると、下図の様な画面になります。
fig1.jpg

左上の gdb のウィンドウで下記の様にタイプします。

(gdb) target remote localhost:26000
(gdb) cd kernel/
(gdb) directory .
(gdb) b main
(gdb) c

すると、main.c の 13行目にブレークポイントが設定され、画面が下図の様になります。
fig2.jpg

あとは右ウィンドウの任意の行でマウスを右クリックすることによりブレークポイントを設置したり、変数のマウスオーバーによる値の表示、上部メニュー (Step Next Finish Cont Stop Eval) のクリックでステップ実行などの操作が自由に実施できます!

gif1.gif

おわりに

vim の :Termdebug は初めて使いましたが、こんなに便利だとは思いませんでした笑
これで OS コードリーディングがめっちゃ捗りますね!

興味があったら是非試してみてくださーい、ではでは!

6
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2