このページの目次
IOMMU と DMA API
カバー範囲: IOMMU ハードウェア → DMA API (coherent/streaming) → swiotlb → IOMMU ドメイン → VFIO → 仮想化における IOMMU カーネルバージョン: 2.6 ~ 6.x
IOMMU の原理
IOMMU はデバイスに IO アドレス変換を提供します (CPU の MMU に例えられます):
デバイス視点のアドレス (IOVA) → IOMMU ページテーブル → 物理アドレス
機能:
1. アドレス変換: デバイスは IOVA しか「見えず」、実際の物理アドレスは不明
2. 分離: 各デバイス/ドメインは独立したページテーブルを持つ → A は B のメモリにアクセスできない
3. 割り込みリマップ: MSI アドレスは IOMMU によって変換される → MSI インジェクション攻撃を防ぐ
4. 連続メモリ: 分散した物理ページを、デバイス視点で連続した IOVA にマッピング → DMA バッファ割り当てを簡素化
実装:
Intel: VT-d (DMAR テーブル)
AMD: AMD-Vi (IVRS テーブル)
ARM: SMMU (System MMU)
DMA API
// include/linux/dma-mapping.h
// デバイスドライバは、DMA 用に物理メモリを手動で割り当て/解放すべきではない → DMA API を使用する必要がある
// 用途: デスクリプタリング、デバイスステータスページ (CPU とデバイスが同じ領域を頻繁に読み書き)
// 特性: CPU とデバイスが常に一貫した状態を参照 → キャッシュの自動同期
void *;
void ;
// 用途: データバッファ (1回限りの使用、方向は固定)
// 特性: 明示的な同期が必要 → Coherent よりもパフォーマンスに優れる
dma_addr_t ;
void ;
// direction: DMA_TO_DEVICE (書き込み), DMA_FROM_DEVICE (読み取り), DMA_BIDIRECTIONAL
int ;
内部実装: プラットフォームに応じた選択
IOMMU がある場合:
dma_map_single → iommu_dma_map_page() → IOMMU ドメイン内にマッピングを作成
→ ゼロコピー (IOVA から物理アドレスへのマッピングのみで、データのコピーは不要)
IOMMU がない場合:
dma_map_single → DMA でアクセス可能な範囲が物理アドレス範囲より小さい場合 → SWIOTLB バウンスバッファを使用
→ 低アドレス領域に一時的なバッファを割り当て → データをコピー (パフォーマンスの低下)
SWIOTLB: ソフトウェアバウンスバッファ
デバイスの DMA アドレス指定範囲が限られている場合 (例: 32ビットPCIデバイスは 0~4GB しかアクセスできない)...:
SWIOTLB は低アドレス領域 (DMAゾーン) にバウンスバッファを予約する
dma_map: データを高アドレスから → コピー → バウンスバッファ (DMA アクセス可能な範囲内)
dma_unmap: バウンスバッファから → コピー → ユーザーバッファ (DMA_FROM_DEVICE の場合)
起動パラメータ: swiotlb=65536 (64MB のバウンスバッファを割り当て)
IOMMU ドメインとグループ
// drivers/iommu/
// ドメイン: IOMMU ページテーブルの抽象化 (一連の IOVA → 物理アドレスのマッピング)
// グループ: ハードウェア分離ユニット (同じグループ内のデバイスは互いにアクセス可能)
// IOMMU グループは VFIO の分離境界である:
// グループ内のデバイスは互いに分離できない → 同一の VM に割り当てる必要がある
// /sys/kernel/iommu_groups/*/devices/*
VFIO: ユーザー空間デバイスドライバ
// drivers/vfio/
// ユーザー空間プログラムがハードウェアに直接 (ただし安全に) アクセスできるようにする:
// 1. IOMMU 分離: デバイスを独自の IOMMU ドメインにマッピング → ホストメモリにアクセスできない
// 2. MMIO パススルー: デバイスの BAR をマッピング → ユーザー空間から直接 mmap 可能
// 3. 割り込み転送: デバイス割り込み → IOMMU 割り込みリマップ → eventfd → QEMU/ユーザー空間
// QEMU: vfio-pci → PCI パススルー → ゲストがハードウェアに直接アクセス
// SPDK: ユーザー空間 NVMe ドライバ → データパスのゼロコピー
参考
- ソースコード:
kernel/dma/,drivers/iommu/intel/,drivers/iommu/arm/,drivers/vfio/ - カーネルドキュメント:
Documentation/core-api/dma-api.rst - LWN: 「The DMA API」、「IOMMU groups and VFIO」
キーワード: IOMMU, DMA API, dma_map_single, coherent DMA, swiotlb, IOMMU ドメイン, VFIO