借り初めのひみつきち

仮ブログです。

QEMU RISC-V virt マシンで VGA を使う

さいきん QEMU RISC-V virt マシンで何ができるか色々探していたところ、なんと VGA が使えることがわかったので記事を書きます。

github.com

最新の RISC-V で古き良き VGA が動いてるのが面白いだけです。実用性はあまりありません。笑

解説

qemu で virtio-vga を使うと PCIバイスが生えてきますが、実は本来の virtio の機能のほかに PCI VGA の機能もあります。

そもそも RISC-V で PCIバイスにアクセスする方法ですが、 DeviceTree から /soc/pci を探し、 pci-host-ecam-generic というプロトコルを使ってコンフィグレーションレジスタにアクセスできます。*1

本来はここで PCIバイスの列挙が必要ですが、 QEMU は固定値っぽいので省略してアドレス 0x3000_8000 から始まる PCI コンフィグレーションレジスタで virtio-vga にアクセスできます。

QEMU RISC-V のファームウェアでは全く設定されていないようなので BAR とコマンドレジスタを自力で設定する必要があります。 サンプルでは適当なアドレスで決め打ちします。

https://github.com/neri/riscv-vga-sample/blob/main/src/main.rs#L22

BAR の設定が終わったらいよいよ VGA の設定をします。 通常の VGA は I/O アドレス 0x3C0〜に主要な機能がありますが、 virtio-vga では BAR2 の MMIO + 0x400 〜の MMIO レジスタとして実装されています。 これをうまく設定すると VGA として動きます。

ここではみんな大好き 320x200 8bit カラーのモード13hと同じ設定をします。

https://github.com/neri/riscv-vga-sample/blob/main/src/vga.rs

設定が終わったら embedded-graphics の DrawTarget として動作するラッパークラスを作ります。

https://github.com/neri/riscv-vga-sample/blob/main/src/main.rs#L99

これで簡単に画面が表示できました。

しかし、よく考えてください。 解像度 320x200 8bit カラーしか使えない VGA より、普通の virtio-vga として使った方がもっと広くて綺麗な画面が使えます。 それとも 640x480 の 4bit プレーンがお好みですか?そんなわけありませんよね。

いかがでしたか?

調べてみたけどあまり役に立ちませんでした。 多分これが一番無駄だと思います。

*1:実は ECAM というのは PCIe のコンフィグレーションのことなので、古き良き PCI バスの場合は pci-host-cam-generic になります。ここでは使いませんが。