32
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

QEMUに仮想PCIデバイスを追加する(1) : 作ったもの

Last updated at Posted at 2015-01-04

※ 色々と誤りや不適切な部分があると思うので気づいたら直します。

QEMUを触ってみたかったのと、実際にハードウェアと通信する
デバイスドライバを書いてみたかったので、
とりあえずQEMUに仮想PCIデバイス(キャラクタデバイス)を追加しました。
これは単純な機能のテストのみで、実用的なデバイスではありません。
なぜPCIキャラクタデバイスかというと、恐らく最も簡単だろうと判断したからです。

そもそもデバイスドライバ自体書いてみたことがなかったので、
それについてもまとめました。

分量が多くなったので、いくつかに分けています。

(2) 前提知識 (PCI / デバイスドライバ)
[(3) 開発/動作環境]
(http://qiita.com/rafilia/items/ff02c38be2ab01220fcb)
[(4) 仮想デバイス/ドライバの登録]
(http://qiita.com/rafilia/items/ba73703babb92276b55a)
[(5) I/Oポートの使用]
(http://qiita.com/rafilia/items/9e8d62444be472e573c2)
[(6) メモリマップドI/O / ioctl の使用]
(http://qiita.com/rafilia/items/8f2ec3c612d4002c12c0)
[(7) 割り込みの設定]
(http://qiita.com/rafilia/items/b719d8adf1f39d956670)
[(8) DMAの設定]
(http://qiita.com/rafilia/items/90bb23e7f4437bd2dd35)

作成したコードは以下にあります。
https://github.com/rafilia/system_simulation

作成したプログラムと主な機能

  1. QEMU仮想デバイス (test_pci_device.c) : QEMU と一緒にコンパイル

    • PCIデバイスをQEMUへ登録
    • デバイスが使用する I/O ポート / メモリマップドI/O 領域の設定
    • PCI コンフィギュレーション空間の設定
    • I/O ポート / メモリマップドI/O に対する read/write 関数
    • DMA転送/割り込みの発行
  2. デバイスドライバ (test_pci_driver.c) : ローダブルモジュールとしてコンパイル

    • PCI デバイスとしてのドライバの登録
    • キャラクタデバイスとしての登録
    • 割り込み、DMAの設定
    • 各システムコールに対応する関数の設定
      (open/close/read/write/llseek/unlocked_ioctl)
    • 割り込みハンドラを用意
    • I/Oポート / メモリマップドI/O を用いてデバイスと通信
  3. ユーザープログラム (test_pci_user.c)

    • デバイスドライバに対するシステムコールを発行
      (open/close/read/write/lseek/ioctl)
    • I/O ポート / メモリマップド I/O / 割り込み / DMA 転送を
      チェックする関数

ユーザープログラムはファイルとしてキャラクタデバイスを扱います。
ユーザープログラムが使用するシステムコールに対応する関数をデバイスドライバに
用意する必要があります。必ずしも全てのシステムコール
をドライバに実装する必要はありません。関数名は基本的に同じですが
間にカーネルが入るために引数が異なります。
また一部関数名が異なるものもあります。
(ユーザー : close, lseek, ioctl / ドライバ : release, llseek, unlocked_ioctl)。

ドライバとデバイスの通信には in/out 命令 (I/Oポートの場合) やread/write
(メモリマップド I/O の場合) を用います。そのため、仮想デバイス側では
in/out, read/write 処理に対応する関数を用意します
(なお、QEMU仮想デバイスではどちらもread/writeという関数名になっています)。
DMA 転送を用いる場合は必要な初期化を設定した後で
out/write 命令などを用いてドライバがデバイスへ通信開始を知らせます。

なお、LinuxはBuildroot を用いて構成したものを使用し、
デバイスドライバはローダブルモジュールとして、Linux 起動後にinsmod/mknodする方針としました。
すべてのプログラムはホストコンピュータ(Ubuntu 64bit)上で
開発を行い、それらをマウントしたディスクイメージにコピーした後に
QEMUを起動しました。

アーキテクチャは 32bit x86 (i386) を対象にしています。
エンディアンの違いや32bit/64bitの違いは特に考えていません。

また今回はどのようにハードウェアと通信するか、といった点のみを考えたため、
実際のドライバで必要となる排他制御(一度に複数のアクセス要求があった場合にどうするか)や、
read/write にバッファを入れるといったことは行っていません。

参考にした本など

デバイスドライバ

Linux デバイスドライバの本には以下の3冊があります。

  1. Linux デバイスドライバ 第3版

  2. Linux デバイスドライバプログラミング

  3. Essential Linux Device Drivers

どれも Kernel 2.6 を対象としており5年以上前の本なのでやや古く、関数名などが変わっている
部分もあるため注意します(ドライバの関数名が ioctl > unlocked_ioctl など)。
特にオライリー本を参考にしましたが、PCIの部分については最後の洋書も参考になりました。

オライリー本の英語版pdfは公開されており、来年第四版が出る予定のようです。

また、PCIの実装についてはこのwebページ (http://free-electrons.com/doc/pci-drivers.pdf) も参考にしました。

QEMU

QEMU には特にまとまった資料がないため、頑張ってソースコードを読みます。
なお、多少のドキュメントが docs/ 以下や各ヘッダファイルに書いてあります。
また、hw/misc/pci-testdev.c といういかにもな名前のソースコードがあったので
これを参考にしました。


はじめ: [(1) 作ったもの]
(http://qiita.com/rafilia/items/f7646d12212da2a85bd8)

次: (2) 前提知識 (PCI / デバイスドライバ)

32
36
0

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
32
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?