QEMU
QEMUによる分岐命令の実現方法が分かったので、次はロードストア命令について実現方法を見ていきたいと思う。例えばRISC-VにおけるLD命令とSD命令を実行する場合、どのようにx86命令に変換されるのだろうか? LD x10, 0(data) SD x10, 8(data) 以下のような…
QEMUで分岐命令を取り扱う場合、主に以下のような手順で取り扱われることを見てきた。 source1に新しいオペランドを確保する。gen_get_gpr(source1, a->rs1)によりsource1にrs1の情報を格納する。 source2に新しいオペランドを確保する。gen_get_gpr(source2…
QEMUの調査続き。次は分岐命令をどのように処理しているのか見ていこう。 例えばBEQ命令がどのようにx86に処理されるのかを見てみよう。 qemu/target/riscv/insn_trans/trans_rvi.inc.c static bool trans_beq(DisasContext *ctx, arg_beq *a) { return gen_…
QEMUはTCG(Tiny Code Generator)と呼ばれる仕組みを使ってゲストマシンの機械語をホストマシンの機械語に変換している。ゲストマシンの機械語は、QEMU実行中にTCGに変換され、これをなるべく最小のホスト機械語に変換することでほぼネイティブなホスト機械…
前回の、QEMUにおけるプロローグコードおよびターゲット関数呼び出しのルーチンを見て、もう少しx86のアセンブリコードについて勉強してみようと思った。 QEMUの実行ログを見ると、最初のブートコードは以下のようになっている。 PROLOGUE: [size=45] 0x7f13…
TCGの続き。続いて、TCGを使ってどのようにRISC-Vのコードをx86上で実行しているのかをチェックする。このためには、まずは関数のプロローグを調べていく必要があるだろう。 デバッグ情報を出力しながらQEMUを実行する。 $ qemu-system-riscv64 --machine vi…
TCGの続き。TCGによるエンコードをもっと詳しく見るために、TCGContextを眺めてみる。 qemu/include/tcg/tcg.h struct TCGContext { uint8_t *pool_cur, *pool_end; TCGPool *pool_first, *pool_current, *pool_first_large; int nb_labels; ... TCGTemp *fr…
TCGの続き。TCGによるエンコードをもっと詳しく見るために、最適化を抑制すべくいろいろ変更してみた。 git diff tcg/i386/tcg-target.inc.c diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index ec083bddcf..d86ccdf05b 100644 --- …
QEMUは高速なエミュレーションが可能な理由の一つに、TCGを使った高速なバイナリ変換機構がある。TCGの役割は、ターゲットバイナリからTCG(Tiny Code Generator)を用いた中間表現に変換し、ホスト形式のバイナリに変換する2つの機構が存在している。 TCGがど…
QEMU実装の続き。CSR命令の実装が足りていないので、いくつか主要なものを実装していく。現時点ではmhartidしか実装していないので追加していく。csr.cにはCSR命令追加のテンプレートが用意されているのでこれを使っていく。 qemu/target/myriscvx/csr.c /* …
QEMU実装の続き。命令実装を進めていく中で、次に実装すべきは分岐命令だ。QEMUで分岐命令をどのように実装するかについて検討を行う。 まずは分岐命令の定義だ。分岐命令はデコードテーブルの中で以下のようにして定義する。 qemu/target/myriscvx/insn32.d…
前回のQEMUの実行ログを見ると、命令のニーモニックが出力されていなかった。どうしたら命令のディスアセンブルが表示されるんだろう?ということでいろいろ調査した。 IN: Priv: 3; Virt: 0 0x0000000000001000: OBJD-T: 9702000093850202732540f1 このOBJD…
とりあえずQEMUのブートコードだけ動かしたいので、次はCSR命令を実装しなければならない。RISC-VのCSR命令がQEMUでどのように実行されているかを解析しよう。 まず、CSR命令をinsn32.decodeに追加する。これでCSR命令のデコーダが自動的に追加され、trans_x…
前回の続き。所望の場所から命令をフェッチできるようになったので、次は命令デコーダを追加していきたい。QEMUにおける命令デコーダはDSLで記述されており、MYRISCVXの場合はqemu/target/myriscvx/insn32.decodeに置いている。これはRISC-Vにおけるデコーダ…
前回QEMUのトレース情報を取得しながらシミュレーションをスタートできるようになったが、よく見てみると最初の命令でいきなりIllegal Instructionで例外に飛んでいる。当たり前だ、そこに命令は配置されておらず、しかもデコーダもろくに実装していないので…
QEMUにはトレース出力用の関数を自動的に生成するフレームワークが存在している。これは命令トレースを出力するのとは異なり、各種イベントを取得するためのフレームワークを生成するものだ。 まず、取りたいイベントを定義しなければならない。target/myris…
QEMUのデバッグ続き。次に落ちたのは以下の部分。GDBで確認する。 $ gdb ${QEMU_BUILD}/myriscvx64-softmmu/qemu-system-myriscvx64 Starting program: ${QEMU_BUILD}/myriscvx64-softmmu/qemu-system-myriscvx64 --machine virt --d in_asm --nographic --k…
QEMUの続き。QEMUのRISC-V対応においてバイナリのシミュレーション方法とログの出し方が分かったわけだが、これをMYRISCVXに移植したい。つまり同じコマンドをqemu-system-myriscvx64に適用することを考える。 まずは変換のための初期化関数から。 qemu/targ…
QEMUの続き。QEMUのRISC-V対応においてバイナリのシミュレーション方法とログの出し方が分かったわけだが、これをMYRISCVXに移植したい。つまり同じコマンドをqemu-system-myriscvx64に適用することを考える。 ./qemu-system-myriscvx64 --machine none --d …
QEMUの続き。前回、QEMUを使ってLinux向けにコンパイルされたバイナリを実行することができるようになったが、ベアメタルのバイナリを動かすことはまだできていない。目標としてはとりあえずriscv-tests関係のプログラムを動かすことができるようになりたい…
QEMUの続き。QEMUを使ってRISC-Vのアプリケーションやベンチマークを走らせたい。とりあえずは普通のRISC-Vのバイナリで動作を確認するところから始めよう。 main.c #include <stdio.h> int main() { printf("Hello World\n"); return 0; } $ riscv64-unknown-linux-g</stdio.h>…
QEMUの続き。独自ターゲットでビルドしてみる。前回の続き。 gen_load()とgen_store()で使用されている関数を定義しなければならない。 gen_get_gpr():GPRから値を取得する関数。 /* Wrapper for getting reg values - need to check of reg is zero since …
QEMUの続き。独自ターゲットでビルドしてみる。前回の続き。 QEMUのデコーダを作っていく。QEMUのデコーダはDSLを使って記述するらしい。translate.cで呼び出されているecode_insn32()を作っていく。 qemu/target/myriscvx/translate.c static void decode_o…
QEMUの続き。独自ターゲットでビルドしてみる。前回の続き trans_xxx()の関数がみんな消えてしまったのはおそらく最適化で消されたので、一応念のためDebugビルドしてオブジェクトをダンプしてみた。 $ ../configure --enable-debug --disable-pie --target-…
QEMUの続き。独自ターゲットでビルドしてみる。static const TranslatorOps myriscvx_tr_opsで必要な関数を調査する。 必要な関数を確認しながら追加していく。myriscvx_tr_breakpoint_check()の中で、デバッグ例外を発生させることが必要だ。 static bool m…
QEMUの続き。独自ターゲットでビルドしてみる。static const TranslatorOps myriscvx_tr_opsで必要な関数を調査する。 一つずつ見ていこう。myriscvx_tr_init_disas_context()を見てみる。Disasということから、これはディスアセンブル(というかログ?)を…
QEMUの続き。独自ターゲットでビルドしてみる。 次に追加したのはmyriscvx_cpu_fp_enable()である。これはどうも浮動小数点を使用したかを確認するらしい。浮動小数点命令が有効になっていても、mstatus.fsが0になっていればfalseになる。つまりこれはコンテ…
QEMUの続き。独自ターゲットでビルドしてみる。myriscvx64コンフィグレーションを用意した。 MYRISCVXCPUはCPUMYRISCVXStateを包むラッパーのようなものらしい。envメンバ変数としてMYRISCVXStateを含んでおり、cfgメンバはRISC-Vのオプションを指定できるよ…
QEMUの続き。独自ターゲットでビルドしてみる。myriscvx64コンフィグレーションを用意した。 ../configure --disable-werror --target-list=myriscvx64-softmmu make -j$(nproc) default_configs/myriscvx64-softmmu.mak # Default configuration for myrisc…
QEMUのソースコードをGitHubからダウンロードして中身を見てみる。riscvと名のつくディレクトリがどの程度あるか探してみた。 $ find . -name riscv ./hw/riscv ./include/hw/riscv ./linux-user/riscv ./target/riscv ./tcg/riscv ビルドするには以下を実行…