x2APICとinterrupt remapping

以前IOAPICやMSI/MSI-Xを利用するデバイスでx2apicを利用するにはinterrupt remapingを利用すると書きました.

今回実際のマッピングを調べることがあったので,ここに要点をまとめます. 図はVT-dのドキュメントからの引用です.

前提

Interrupt RemappingのサポートはVT-dレジスタのExtended Capability Registerの3bit目(IR: Interrupt Remapping support)で示されます.

VT-dレジスタのアドレスはACPIのDMARのDRHDに記載されています.

またVT-dレジスタのGlobal Command Register (18h)のIRE: Interrupt Remapping Enableを利用してInterupt remapingを有効化します.

Interrupt Remappingの設定

Interrupt Remappingを利用するには,以下の設定が必要です.

バイス

MSI/MSI-Xを利用するデバイスは,割り込みを生成するときに,以下に示す"Remappable Format Interrut Request"でMSIを設定します.

f:id:mm_i:20190927165407p:plain

通常のMSIと異なり,割り込みアドレスに割り込みベクタ番号やdestination IDはエンコードされていません.Interrupt indexで次に説明するInterrupt remapping table entryのインデックスを指定します.

(ここから分かるように,Interrupt Remappingを利用する場合には,デバイスの方の割り込み設定も適切に設定する必要があります.デバイス設定に透過でinterrupt remappingを利用することはできません.)

IRTE (Interrupt Remapping Table Entry)

IRTEで実際の変換の内容を設定します.IRTEにはinterrupt remapping用と,posted interrupts用の二種類存在します.

interrupt remappingを利用する場合は,以下のようなエントリになります.

f:id:mm_i:20190927165449p:plain

IRTEのベースアドレスはVT-dレジスタのInterrupt Remapping Table Address Register (0B8h)に格納されています.

Invalidation

IRTEエントリのキャッシュの無効化はInvalidation Queueを用いておこないます.

確認

x2APICを有効にしたLinuxマシンでMSIの設定とRITEエントリを確認しました.

以下のMSI-Xが有効になっているデバイスが対象です.

% sudo lspci -vvv -s 05:00.0
05:00.0 Non-Volatile memory controller: OCZ Technology Group, Inc. RD400/400A SSD (rev 01) (prog-if 02 [NVM Express])
...
        Capabilities: [b0] MSI-X: Enable+ Count=8 Masked-
                Vector table: BAR=0 offset=00002000
                PBA: BAR=0 offset=00003000

MSI-X ベクタテーブル

前と同じようにMSI-Xのベクタテーブルの確認します.

% for j in `seq 0 1 64`; do; for i in `seq $((($j+1)*16-4+8192)) -4 $(($j*16+8192))`; sudo ./pcimem /sys/devices/pci0000:00/0000:00:1d.0/0000:05:00.0/resource0 $i w | tail -n1 | cut -d':' -f 2 | tr '\n' ' '; echo ; done
 0x0  0x0  0x0  0xFEE00258
 0x0  0x0  0x0  0xFEE00378
 0x0  0x0  0x0  0xFEE00398
 0x0  0x0  0x0  0xFEE003B8
 ...

左がMessage data, 一番右がMessage Addressです. 上からそれぞれ利用するIRTEのインデックスは18, 27, 28, 29です.

IRTE

適当なカーネルモジュール書いて確認したら以下のようになりました.

[ 2459.161111] vtd:   irta = 0x0000000460500000, eime = 1, s = 2^15
[ 2459.161112] vtd: 0 000000010083002d, 0000000000040500
[ 2459.161112] vtd:  P: 1
[ 2459.161113] vtd:  FPD: 0
[ 2459.161113] vtd:  Destination mode: 1
[ 2459.161113] vtd:  Redirection Hint: 1
[ 2459.161114] vtd:  Trigger Mode: 0
[ 2459.161114] vtd:  Delivery Mode: 1
[ 2459.161114] vtd:  AVAIL: 0
[ 2459.161115] vtd:  VECTOR: 131
[ 2459.161115] vtd:  Destination ID: 1
[ 2459.161115] vtd:  SID: 0x500

ここで,最初の行がInterrupt Remapping Table Address Registerの値で,eime=1なのでx2APICモードです. その下がIRTEの中身です.

参考文献