-
Notifications
You must be signed in to change notification settings - Fork 5
AHCI Memo
AHCI (Advanced Host Controller Interface) についてのメモ書き
2016/05/05 by uchan
最終的に SATA ディスクを制御することを目標に、しかし知的好奇心が満たされるよう、最短経路よりは少し豊富な情報を提供する。 AHCI デバイスのメモリ空間、FIS の種類と構造、ATA コマンドの送受信方法、ATA コマンドの種類などを扱う。
- AHCI デバイスを発見する
- ベースクラス 01h、サブクラス 06h の PCI デバイスを探す
- 各メモリマップを設定する
- Command List や Received FIS 等のメモリ領域を設定する
- SATA デバイスを探す
- 何番ポートにどんなディスクが接続されているか、されていないか
- READ DMA コマンドを準備する
- Command List 上に READ DMA コマンドを構築する
- コマンドを送信する
- PxCI レジスタのコマンドスロット番号に対応するビットに 1 を書く
- 事前に PxCMD.ST を 1 にセットしておく必要がある
- 割り込みを待ってデータを受け取る
- 割り込みを有効にしておけば、すべてのコマンドのやり取りが終わった後で割り込まれる
- 割り込み後、PRDT に設定したメモリ領域にデータが格納されている
AHCI の機能は PCI デバイスとして実装される。そのため、もちろん PCI コンフィグレーションレジスタを持つ。6 本ある 32 ビット BAR のうち、最後の 1 本(オフセット 24h)が AHCI の制御に使われる BAR である。これを ABAR (AHCI Base Address Register) と呼ぶ。
他の BAR はオプショナルであり AHCI には関係ない。AHCI に対応しない古いソフトウェアをサポートするため、IDE コントローラを実装するのに使われたりする。
すべての BAR は BIOS や UEFI が適切な値を設定しているはずなので、自作 OS 側では何も設定する必要はない。cf) PCI Memo
ABAR で指される領域に AHCI コントローラ(HBA: Host Bus Adapter)を制御するレジスタ群がある。さらにその中にもアドレスを格納するレジスタがあり、いろいろなメモリ領域が数珠つなぎになっている。その様子を図示する。
AHCI コントローラを制御するためのレジスタ群である。PCI コンフィギュレーション空間にある ABAR によってメモリにマップしてアクセスする。32 ビット幅のレジスタの集合。
HBA Memory Registers は大きく Generic Host Control レジスタと Port Control レジスタに分かれる。前者は名前の通り AHCI コントローラ全体に影響するレジスタだ。後者は同じ構造のレジスタが SATA ポートごとに一組用意されている。規格上は最大 32 ポートまで扱えるが、実際に使える数は AHCI コントローラに依存する。
この HBA が持つ能力を示すためのレジスタ。64 ビットアドレッシングが可能か(ビット 31)とか、ネイティブなコマンドキューをサポートしているか(ビット 30)など、ビットごとに各機能のサポート状況を示す。
以下、主なビットについて示す。カッコ内はビット番号。
S64A(31) はこの HBA が 64 ビットアドレッシングをサポートしていることを示す。
SAM(18) はこの HBA が AHCI モードだけをサポートしていることを示す。1 なら AHCI モードのみ、0 ならレガシーモードもサポートする。
NP(4:0) はこの HBA のシリコンチップがサポートする SATA ポートの最大数-1 を表す。0h なら 1 ポートだけサポートする。1fh なら 32 ポートをサポートする。どんな HBA も最低 1 ポートはサポートしなくてはならない。
HBA のグローバルな設定などを行うレジスタ。
ビット 31 は HBA の動作モードを取得または設定する。1 なら AHCI モード、0 ならレガシーモード(IDE モード)。レガシーモードをサポートしない HBA の場合、リードオンリーで 1 固定。
ビット 1 は割り込みが有効であることを示す。1 なら有効。
ビット 0 はリセット用ビット。1 を書くと内部リセットが発生し、データ転送およびキューイングに関するすべての状態が初期化される。
ソフトウェアから使えるポート(実装されたポート)に対応するビットが 1 となる、リードオンリーなレジスタ。1 の個数は CAP.NP+1 を超えてはいけないが、それより少ないことはあり得る。
ポート毎に存在するレジスタ群。レジスタ名の「x」にはポート番号 0 から 31 が入る。
Command List という構造体が置かれているメモリ領域を指すレジスタ。物理メモリアドレスを格納する。その領域は 1K バイトにアラインされている必要があるので、ビット 9:0 は 0 固定。
64 ビットアドレッシングがサポートされている場合、上位 32 ビットは Offset 04h にある PxCLBU レジスタに格納する。
Received FIS という構造体が置かれているメモリ領域を指すレジスタ。物理メモリアドレスを格納する。その領域は 256 バイトにアラインされている必要があるので、ビット 7:0 は 0 固定。
64 ビットアドレッシングがサポートされている場合、上位 32 ビットは Offset 0Ch にある PxFBU レジスタに格納する。
Command List の中でデバイスに送信するコマンドスロットを選択するレジスタ。ビット 0 がコマンドスロット 0 に対応する。ソフトウェアは、あるコマンドスロットの送信準備が完了したことを示すために 1 を書き込む。そのコマンドの BSY, DRQ, ERR ビットをクリアするような FIS を HBA が受け取ると、HBA が 0 を書き込む。
Command List はその名の通り、複数のコマンドを格納するリストである。SATA ディスクは内部にコマンドキューを持っていて、読み書き命令の実行順を最適化する機能を持つ。それに合わせ、HBA にも複数のコマンドを一度に送信する仕組みがあるのだ。
Command List は要素数 32 の Command Header の配列である。1 つの Command Header は 1 つの SATA コマンドに対応する。
Command Header は CTBA0 レジスタを通して Command Table 構造を指し示す。Command Table の中に実際の SATA コマンド("IDENTIFY DEVICE" など)を構築する。図中の CFIS がコマンドを構築するメモリ領域である。
Command List の各要素を Command Slot と呼ぶこともある。32 個のスロットのうち、空いている任意のスロットにコマンドを構築し… というような文脈で「スロット」を使うことが多いように思う。
SATA コマンドをデバイスに送る手順は次。
- Command List の空いているスロットに好きなだけコマンドを構築する
- PxCI の対応するビットに 1 を書き込む
- HBA が自動的にコマンドをデバイスに送り、応答を待つ
デバイスへ送る 1 つの SATA コマンドと、ホストとデバイス間で送受信するデータを置く場所を指定する PRDT からなる。SATA コマンドの戻り値は Command Header ではなく、PxFB で指示された Received FIS に書かれる。
1 つの FIS を置く領域。
デバイスに書き込むデータやデバイスから読み込んだデータを置くメモリ領域を指定する。0 個から 65535 個までの要素を持つ配列で、1 つの要素は 4 つのダブルワードレジスタからなる。
個々の要素は 1 つのメモリ領域(データブロック)の先頭アドレスとサイズを指定する。それぞれの要素で指定されるメモリ領域は互いに連続している必要はない。細切れのメモリ領域を 1 つのデータセットとして扱えるというわけだ。
データブロックの先頭を指す 32 ビットの物理メモリアドレス。2 バイト境界にアラインされている必要がある。
データブロックの先頭アドレスの上位 32 ビット。HBA が 64 ビットアドレッシングをサポートしている(CAP.S64A が 1)ときのみ有効。
セットすると、このエントリのデータの送受信が終わったときに割り込みが発生するらしい。データセット全体の送受信完了ではなく、あくまでこの PRD エントリの完了を知らせるようだ。詳しくは分からない。
データブロックのバイト数。
デバイスから送られてきた FIS を格納する領域である。
IDENTIFY DEVICE コマンドの実行過程を例に Received FIS の使われ方を見てみる。
- ホストがデバイスに IDENTIFY DEVICE をセットした Register FIS を送信する
- デバイスが 256 バイトの情報を内部バッファに用意する
- デバイスがホストに、データの準備完了とデータサイズを伝えるため PIO Setup FIS を送信する
- PIO Setup FIS の送信に成功したら、続けてホストが DATA FIS を送信する
この中で 3 でホストが受信した PIO Setup FIS が Received FIS に書き込まれる。DATA FIS もデバイスから受信する FIS であるが、Received FIS 領域には書き込まれず、直接 PRD で指定されたメモリ領域へ書き込まれる。
- Offset 00h: DSFIS - DMA Setup FIS
- Offset 20h: PSFIS: PIO Setup FIS
- Offset 40h: RFIS - D2H Register FIS
- Offset 58h: SDBFIS - Set Device Bits FIS
- Offset 60h: UFIS - Unknown FIS
FIS (Frame Information Structure) は SATA においてホストとデバイス間のデータ転送の基本単位である。SATA は Parallel ATA と同じコマンド体系であり、FIS は ATA コマンドを包み込んだものと捉えることもできる。