見出し画像

OS自作~FrameBufferの取得方法~

この記事の概要

今回が初めての投稿なので、すでにある程度OSの基礎はできてきています(スタート時点でのコードは下のコミットを見てください)。なので、PCIeデバイスの列挙等は済んでいる前提で、FrameBufferのアドレスの取得方法を書きます。


PCIeのクラスコード

FrameBufferはPCIeで接続しているGPUから取得できます。なので、PCIeのクラスコードを使って、PCIeデバイスのリストからGPUを識別する必要があります。PCIeのクラスコードはこのサイトに詳しく載っていますが、GPUはDisplay Controllerのことだと考えられるので、メインクラスが0x03のものだとわかります。

実機で得られるPCIeデバイス

上の写真の中にはベンダーIDが8086のものと10DEの2つのGPUがありますが、8086がIntel、10DEがNvidiaを表します。つまり、前者が内蔵グラフィックスなのに対して、後者は外付けGPUを指しています。
ちなみに、QEMUの仮想グラフィックカードのベンダーIDは1234になっています。

PCI Configuration space

PCI Configuration spaceとは?

さて、GPUを識別することができれば、既に用意してあるDeviceクラスからPCIe Configuration spaceと呼ばれるデバイスの情報を取得できます。こいつの構成はこんな感じです。

PCI Configuration spaceの構成(from wiki)

このうち、重要なのはBAR(Base Address Registers)と呼ばれる部分です。ここにMMIOの先頭アドレスなどが格納されているので、FrameBufferアドレスもここにあるでしょう。
BARにはBAR0~BAR5の6つあり、画像で言えば、横一列で一つのBARになっています。

QEMUで確認してみる

XHCIのMMIOアドレスがBAR0とBAR1の64ビットだったので、同じところをQEMUで見てみたところ、大当たりでした。ブートローダーから渡されていたアドレスと一致しました。あとから見つけたのですが、多分QEMUのレポジトリにある規格書みたいなやつに書いてあるPCI Region0,1がBAR0,1に相当するんだと思います。

ASUSの実機で確認してみる

QEMUが一発で当たったので、同じだろうと思ったら、こちらは一致しませんでした(残念)。仕方がないので勘ではなく、ちゃんと仕様書を探すことにしました。
このノートPCはNvidiaのGPUを積んでるので、Nvidiaの仕様書を探した所、ちゃんと仕様書がありました。
これを読むと(at least 16MBと書いてあるあたりから)どうもBAR2,3がFrameBufferぽいことがわかります。そこで試しにBAR2,3を出力したのが下の画像です。

実機でBAR2-3を確認すると…?

ちゃんと上の赤枠の0xc0000000に近い値の0xc000000cがBAR2-3にあるのがわかります。下2桁は理由はわかりませんがQEMUの方でも切り落として考えることになっているので、恐らく問題ないです。
ただ、上の出力はPCIeデバイスと同じ順番なので、Intelの内蔵グラフィックスのものなんですが、たまたまNvidiaの使用と同じだったということでしょう。
これですくなくともQEMUとNvidiaとIntel内蔵グラフィックスを使う機種ではブートローダーからの情報が不要となりました!

次にやること

じゃあ早速ブートローダーからの引数を消して、カーネル側でFrameBufferの処理を完結させよう!と言いたいところですが、ちょっと面倒なのと、まだ解像度などのGOPでいうModeInfoに当たる情報が得られていないので実装は次回にします。
ただ、ちゃんと解像度も目星は付いていて、MMIOの中のPFBという項目をいじれば行けそうな雰囲気があります(Horizontal display sizeとか書いてありますしね)。
というわけで次回は解像度の取得・設定方法の調査と実装をしたいと思います。

この記事が気に入ったらサポートをしてみませんか?