第8回 ACPI その2 ACPICAを使おう

おっと超久し振りであった。べ…べつにやる気が無くなったわけじゃないんだからね!ちょっと行き詰まってたというか、

  • 次こそは画面表示するべ
  • おっとそういえばGMA950はPCIの向こうだった…もうちょっと簡単なPCIバイスPCIに慣れてから…
  • UHCIでもやるか…あれ?I/O APICを使った場合、PCIの割り込みルーティングてどうなるのん…?
  • え…えーしーぴーあい読まないとあかんのか…
  • なんかやる気が無くなってきたなぁ…

という感じなのであった。思い出してみるとやる気が無くなったわけじゃったんだからね!


PCIの割り込みルーティング(というかPCI全般)は、TECH IのPCIの本(http://www.amazon.co.jp/dp/4789833321)を読むとよいのだが、残念ながら、割り込みルーティングに関しては、8259の割り込みについてしか書いておらんだ。
んで、ここらへんの情報については、http://people.freebsd.org/~jhb/papers/bsdcan/2007/article/article.html を読むとよいんのだが、MP Tableを読むか、ACPIを読むとよいと書いておるんだ。

MP Tableは読むだけでよいので、それで済ませてしまう方法もあるが…「いまどきのPC入門」としては、ACPIを使わないという選択肢は残念ながら有り得ないのだよ…

さて、そのような感じで、ACPIを使おうということになった。


ACPIの特徴として、その情報は、プログラミング言語 AML(ACPI Machine Language)で書かれているというのがあるなー。
EmacsEclipseExcel VBAFirefoxなどなど、カスタマイズの辿り付く先として、プログラミング言語を導入してしまうというのは比較的ありがちだなー。ACPIもそれと同じ誤ちを犯しており、設定がプログラミング言語になっているのだ。(といっても、それ以前もBIOSx86プログラムとして動いてたわけだが…)


Linuxを使ってる人なら、http://www.acpica.org/ これのソースを頂戴してきたあと、この中のcompilerというところの中でmakeすべし。そしたらiaslというツールができるなー。んで、/sys/firmware/acpi/tables/DSDTの内容をどっかにコピーしたあと、これを $ iasl -d DSDT とかすると、君の手元のマシンに書かれているAMLプログラムを閲覧させていただくことができるのよ。

バイスがツリー構造で書かれており、それぞれのデバイスには、Methodとかいうのがあるのが確認できるのぅ。Methodはオブジェクト指向的なメショッドを想像してください。ツリーの中にあるデバイスのメソッドを呼ぶと、そのデバイスを制御できるというオブジェクト指向を。


例えば、手元のDSDTを見ると、こういうのが書いておる

  Device (UHC1)
  {
      Name (_ADR, 0x001D0000)
      Name (_PRW, Package (0x02)
      {
          0x03, 
          0x03
      })
      OperationRegion (USBR, PCI_Config, 0xC4, One)
      Field (USBR, AnyAcc, NoLock, Preserve)
      {
          URES,   8
      }

      Method (_PSW, 1, NotSerialized)
      {
          If (LEqual (Arg0, Zero))
          {
              Store (Zero, URES)
          }

          If (LEqual (Arg0, One))
          {
              Store (0x03, URES)
          }
      }
  }

これは、UHCIの記述なんだが、_PSWというメソッドゥが定義されてる気がするなー、_PSWは、ACPI SPEC 3.0の7.2.11を見ると、このデバイスによるスリープからの起動の有効無効を切り換えるメソッドだという説明があって、0だとdisable、1だとenableだとあるなー。(あと3.0ではdeprecatedだという説明も書いてあるが…)
んで、ICH7の11.1.18を読むと、コンフィグレーション空間の0xC4がResume Enableレジスタになってて、それが設定できるという説明があるなー。ということを踏まえて、上のコードを読むと、なんかそんな気がしてくる。

PCIの割り込みルーティングも、このAMLで書かれたプログラムで表現されてるメソッドの戻り値になっておって、PCIバスの_PRTメソッドを呼ぶとそれが取得できるでござる。


さて、ここまで超適当に説明してきたわけだがー、何を言ってるかよくわからんという人もいると思うなー。実際書いてる人も理解がいまいち浅いという気がするね。でも、ともかく、これを実装する作業量はかなりとんでもないということが想像できたことでしょう。

  • テーブルを読んで
  • DSDTをロードして
  • DSDTに書いてあるツリー構造を解釈して
  • 状況に応じたメソッドを呼び出して
  • AMLバイトコードを実行する
  • あとGPEて何?

しかも、相手は色んな実装のマザーボードなわけで、ショボいACPI実装では簡単に問題が出そうなことが想像できることでしょう。
しかも、これだけ頑張ってできることは、電源押したらスリープすることと、PCIのルーティングテーブルが読めるだけなのだった。(しかもスリープしたあとは、ドライバの実装がヘボいせいで、スリープからの復帰には失敗するのだった)


というわけで、ACPIを自分で実装するのは、労力の割に得られるものが少なすぎるという気がするなー。
でも諦めないで!ここで使うのが、ACPICA(ACPI Component Architecture:http://www.acpica.org/)である。


ACPICAとは、Intelさんが提供してるACPI実装である。OSとは独立して動くようになっておって、各自好きなOSに組み込むことができるんだぜ!
Intelさんは、ACPI仕様の提案者のうちのひとりなので、野良実装に比べるとかなり信頼できる実装だと思われるなー。実績としては、確認した範囲で、LinuxNetBSDHaikuなどで採用されておる。

使いかたもそんなに難しくなくて、用意するものが

  • ヘッダをいっこ用意する
  • OSインターフェースを用意する

のふたつだなー。

まずヘッダ、acpicaのソースの中の、include/platformのacenvからインクルードされてる、OSヘッダがそれだなー。これを自分に都合の良いように調教してやればよろしい。調教のしかたは、
http://www.acpica.org/documentation/index.php
これの7章に書いてある定数を定義すればよろしい。platform/以下にある他のヘッダを参考にして書けば問題なかろうて。

で、OSインターフェースは、9章 OS Service Layerに書いてある関数を実装するとよろしい。ソースに入っている、osunixxf.cなどが参考になることでしょう…


たった…たったのこれだけで…あのACPIが自由自在に扱えるようになるのです!なんということでしょう!ACPICAを使った人達からは
「ACPICAを使った瞬間、textのサイズがグングン大きくなってビックリしました!」
「ACPICAのおかげでLEDがピカピカするようになりました!」
などの喜びの声が届いており、米国Intel社もその効果を認めているほどです。


ヘッダとOSインターフェースができたら、あとはAPIを呼ぶだけだなー。初期化の方法などは4章に書いてある。あとその他インターフェースは、8章に書いてある。


ACPICAを有効にしたソースをここに置いておくなー。前回までは、(手元のGOLF2では)電源を押すと即シャットダウンしていたのが、ACPIを有効にすることによって、5秒間電源ボタンを押さないとシャットダウンしないようになっていて、ACPIの効果を実感できるなー。すぐシャットダウンしないので、デバッグ時に面倒になったとも言える。

acpica/以下に、ACPICAのソースが、acpi-osqo3.cが、OS Service Layerになるなー。ただし、あんまりちゃんと動いていないとか、メモリリークしてるとかprintfがうまく動いていないとかはしばらく見なかったことにしておいて欲しい。

これでPCI割り込みルーティングテーブルもとれるようになったし、次回は、PCIバイスを使ってなんかやりたいところでござるね。音を鳴らすかもしれない。音を鳴らすのが難しいなら、むしゃくしゃしてSATAのHDDを初期化するみたいな感じになるかもしれぬ。