わかりやすくQEMUを説明してみる(第1回):QEMUの利用シーン

<連載目次>

はじめに

QEMUはざっくり言うとオープンソースのCPUエミュレータです。QEMUはQuick Emulatorの略であり、読み方は「キューエミュ」や「キューエムユー」が一般的ですが、「ケミュ」と呼ばれる場合もあります。

弊社ではQEMUに関するモデリングサービスも実施しています。QEMUは非常に便利なツールなのですが、「QEMUって何?」という方が多いのではないでしょうか。

なお、弊社のQEMUモデリングサービスについては以下のURLを参照してください。

私も2010年頃QEMUに初めて触れたときはWEBなどの記事を参考にしながらQEMUを動かすことはできたものの、なんだかよくわかりませんでした。QEMUが分かりにくい理由の1つに利用シーンの種類が多いという点があるかと思います。つまり使い道がたくさんあるということです。

またQEMUはそもそも誰が使うべきものなのかについてもわかりにくいかも知れません。例えば組み込みソフトウェアエンジニアが使うケースもあれば、SoC(System On a Chip)といった半導体設計を行うハードウェアエンジニアが使うケースもあるかと思います。

そこで本連載ではQEMU初心者向けに、QEMUの仕組みについて複数回に分けてなるべくわかりやすく説明していこうと思います。QEMUの中級者および上級者にとっては物足りない内容かも知れません。なお、QEMUの具体的なインストール方法や使用方法については説明しません。

本連載のこの第1回ではQEMUおける数ある利用シーンの中の1つについて説明しQEMUとはいったい何者なのかについてなんとなくわかるところをまでを目指します。

QEMUって?

QEMUはオープンソースのCPUエミュレータおよびシステムエミュレータです。これにより、異なるCPUアーキテクチャのソフトウェアを実行したり、仮想化されたハードウェア環境を構築したりすることが可能です。と言われてもこれだけではQEMUが何者なのかについては普通はわからないと思います。QEMUが何者かについては後述の「QEMUの利用シーン」を読めばなんとなくは理解できるかと思います。

なおエミュレータというなんだか難しそうな単語を使いましたが、シミュレータと言っても良いかと思います。エミュレータとシミュレータの違いを語りだすと話がややこしくなるのでその違いについてはここでは割愛し、本連載ではエミュレータもシミュレータも同じ意味で使うことにします。ただ、半導体設計者(LSI設計者)の方からすると「いやいやエミュレータとシミュレータは全然違うでしょ」とツッコミがきそうですが、QEMUを理解する上ではとくに困らないと思います。

QEMUはC言語で開発されている高度な「ソフトウェア」です。そしてそのソースコードは公開されています。QEMUはかなり複雑であり、使い方を理解するだけでもひと苦労です。

QEMUはオープンソースであり、ライセンス形態は以下の通りです。

  1. QEMU全体はGNU GPL version2
  2. 個別ソースコードはGPL、LGPL等が混在

詳細については割愛しますが、QEMUを独自に改良して社外に公開(配布)する場合はソースコードの公開(配布)も必須となります。

QEMUの利用シーン

QEMUの理解を難しくしている原因の1つにQEMUの使い道が多岐にわたるという点があげられます。まずは以下にQEMUの利用シーンの例をいくつか挙げます。

  • 組み込み開発環境でのファームウェアテスト
  • 異なるアーキテクチャ間のソフトウェア移植
  • 仮想マシンを構築して異なるOSを動作させる

さらに具体的な例を以下に挙げます。

  • 1. ARM社のCPU搭載の実機が無い状態でARM用ソフトウェアを開発したい
    • ARM社のCPU上で動くOSありの場合。例:Linux
    • ARM社のCPU上ではOS無しの場合。いわゆるベアメタル。
    • 実機は開発済みだが、その実機が手元にない場合。例えばリモートワーク。
    • 実機は開発済みだが、実機の数が足りない。
    • 実機では再現が難しい故障を発生させたい。
    • 実機はこれから開発予定の場合。SoC等の開発をこれから実施。
  • 2. Windows上でLinuxを動かしたい
    • これはVMWareやVirtual Boxでも可能

また第1回では触れませんが、QEMU上でLinuxを動かす場合は以下の用語が登場しQEMU初学者にとっては非常に分かりにくいと感じられるかもしれません。

  • システムモード(システム・エミュレーション)
  • ユーザモード(ユーザモード・エミュレーション)
  • KVM

これに加えて、「ハイパーバイザー」などいう難しそうな用語も登場する場合があり、もうなにがなんだかよくわからない、という状況に陥っている方もいるのではないでしょうか。

なお先ほどの利用シーン例ではARM社のCPUを例としてあげましたがRISC-VなどQEMUが対応している他のCPUでも同じことが言えます。

以降、QEMUに関して利用シーンをまずは1つとりあげ深堀りしていくことにします。

利用シーン1:ARM社のCPU搭載実機完成、手元に実機なし、OS無し

今回、どのような利用シーンから説明するか迷いました。しかしこの利用シーン1についてQEMUの仕組みを理解できれば他の利用シーンについても理解がしやすくなると思いこれを選びました。

なお、連載第1回では利用シーンの概要だけ説明し、どのような仕組みでQEMUが動いているかについては第2回以降で説明することにします。

今回のQEMU利用シーンは、以下のような状況を想定しています。

・ARM社のCPUを搭載した実機は完成済み

・諸般の事情により手元に実機がないが、実機向けの組み込みソフトウェアを開発したい

より具体的には、勤務先のオフィスにてARM社のCPU搭載の実機を使って組み込みソフトウェア開発をしており、その作業の続きを自宅にて行いたいが自宅には実機がない、などという場合です。

実機がある場合

まずは実機を使った組み込みソフト開発の一般的なイメージを図1に示します。

図1 クロスコンパイルと実機

図1ではx86系のPC(パソコン)上にてCプログラムのソースコードを作成しています。ソースコード作成後、その同じPCにてARM用gcc(Cコンパイラ)を使いCソースファイルをクロスコンパイルすることによりARM用バイナリファイル(実行ファイル)を生成します。そしてARM用バイナリを実機に送り込み実機上でそのプログラムを実行します。

クロスコンパイルなどという難しそうな用語を使いましたが通常のコンパイルと基本概念は同じです。ただ、ここでARM用gccではなく通常の(x86用の)gccなどのコンパイラでコンパイルするとx86用のバイナリ(実行ファイル)ができてしまいます。このx86用のバイナリ(実行ファイル)をARM搭載の実機に送り込んで実機上で実行してもプログラムは正しく動きません。なぜならx86用バイナリにはx86用の命令がマシン語で書かれており、ARM CPUはこのx86用CPU用のマシン語命令を処理することができないからです。

クロスコンパイラとは、コンパイラが動作している環境(この場合はx86系)以外のプラットフォーム(この場合はARM CPU)向けにバイナリファイル(実行ファイル)を生成するコンパイラのことです。

ところでクロスコンパイルのようなまどろっこしいことなどせずに「実機上で直接コンパイルすればいいのでは?」と思われる方もいるかと思います。まったくその通りなのですが、実機ではリソースが限られている場合が多く、コンパイル環境等を構築することができない場合がほとんどです。また、実機がまだ無い場合はそもそも実機上でコンパイルすることはできません。

実機が無い場合

実機が無い場合はどうするかというと実機のふりをしてくれるQEMUをPC上で使います。このように実機のふりをしてくれるソフトウェアことを「仮想ハードウェア」あるいは「仮想マシン」や「仮想プラットフォーム」などと呼びます。

QEMUが実機のふりをする様子を下図に示します。

図2 クロスコンパイルとQEMU

図2ではARM CPU用バイナリ(実行ファイル)を生成するところまでは実機がある場合と同じです。実機のある場合はARM CPU用バイナリ(実行ファイル)を実機に送り込んでいましたが、実機が無い場合はARM CPU用バイナリ(実行ファイル)をQEMUに送り込みます。

QEMUに送り込むと言っても単にQEMU実行コマンドに-kernelというオプション引数として渡すだけです。図2では以下のようにQEMUを実行しています。

%qemu-system-arm -M lm3s811evb -kernel hello.elf

上記コマンドでは -Mオプションでlm3s811evbという文字列を渡しています。これは、ARM Cortex-M3 CPUを搭載したマイコンの評価ボードのモデルを意味しています。-MのMは「Machine」のMを表しています。

上記コマンドによりQEMUを実行するとPC上に「Hello World!」と表示されます(図2の右下)。 なお一般的に仮想マシンから見るとPC(パソコン)に物理的に搭載されているCPUのことを「ホストCPU」と呼びます。一方、仮想マシン内(QEMU内)で模擬してる(シミュレーションしている)CPUのことを「ゲストCPU」と呼びます。今回のケースではQEMUから見ると、x86系CPUがホストCPUで、ARM CPUがゲストCPUとなります。まとめるとホストはQEMUを実行している実際の物理マシンで、ゲストはQEMU上でエミュレートされる仮想マシンまたはソフトウェア環境を指します。

ここで1つの疑問が生じます。実機のふりをするQEMUは誰が作成するのでしょうか。例えば自社向けのSoCを搭載した実機の場合はオープンソースのQEMUがSoCのふりをしてくれるはずもありません。この場合はQEMU用のCモデルを自社で開発する必要があります。ただし各種CPUのモデルや汎用的なペリフェラル(UARTなどの周辺回路)あるいは市販の評価ボードなどに対してはあらかじめQEMUにライブラリとして登録されています。必要となるペリフェラルがライブラリとして存在しない場合は自前でQEMU用Cモデルを追加作成する必要があります。

またもともとQEMUに登録されている市販の評価ボードなどに対するCモデルは、実機に搭載されているすべてのペリフェラルをモデリングしているわけではありません。例えば、市販の評価ボードのUARTやタイマーはQEMUにモデリングされていることが多いですが、一部の専用ペリフェラルはサポートされていない場合があります。すべてのペリフェラルについてCモデルを用意しなくても組み込みソフトの開発はかなりの部分で可能となります。

次回

今回(第1回)はQEMUの利用シーンの1つについて説明しました。

次回(第2回)はQEMUがx86上でどのようにしてARM CPUの命令を実行しているのか(エミュレーションしているのか)について説明したいと思います。

<連載目次>