← ARMv9 해설DUJINLABS.COM

Source deep dive 08 · SMMUv3 · STE · CD · CMDQ · EVTQ

ARM SMMUv3·IOMMU·DMA 소스 분석

CPU가 아닌 device의 주소 번역이라는 개념에서 시작해, PCIe StreamID가 STE·CD를 선택하고 Linux가 IOMMU domain을 attach한 뒤 CMDQ로 TLB를 지우며 EVTQ fault를 처리하는 실제 경로를 분석한다.

Kernel
Linux v6.18.37
Device ID
SID · PASID
Tables
STE · CD
Queues
CMDQ · EVTQ

SMMU는 device가 내는 주소 앞에 놓인 MMU다

CPU program은 VA를 내고 CPU MMU가 번역한다. DMA device는 IOVA를 내며 SMMU가 허용된 PA로 번역한다. SMMU가 없거나 bypass면 잘못된 device가 다른 process·VM memory를 덮을 수 있다.

Isolation

device마다 접근 가능한 physical memory 범위를 제한한다.

IOVA

device가 사용하는 주소 공간으로 contiguous PA일 필요가 없다.

Domain

여러 device가 공유할 수 있는 translation·protection 정책 단위다.

Fault

잘못된 DMA를 memory corruption 전에 event로 보고한다.

StreamID와 SubstreamID가 어느 translation을 쓸지 고른다

ID출처선택 대상
StreamID (SID)SoC interconnect 또는 PCIe Requester IDStream Table Entry.
SubstreamID (SSID)PASID 같은 process context IDContext Descriptor.
ASIDStage-1 address spaceSMMU TLB의 S1 번역 식별.
VMIDStage-2 domainVM별 S2 번역 식별.

PCI BDF와 SID가 항상 같은 숫자는 아니다. firmware의 iommu-map, ACPI IORT와 root-complex wiring이 실제 변환을 정한다.

STE가 큰 경로를, CD가 process별 Stage-1을 정한다

구조Index핵심 내용
STESIDabort/bypass/S1/S2/nested mode, CD table pointer, VMID·VTTBR·VTCR.
CDSSID/PASIDASID, TTBR0, TCR, MAIR와 Stage-1 permission.
I/O page tableIOVAoutput PA, read/write permission, memory attribute.
IOTLBSID/SSID/ASID/VMID와 IOVA최근 번역 cache.

arm-smmu-v3.hSTRTAB_STE_*CTXDESC_CD_* mask는 architecture descriptor를 Linux가 어떻게 encoding하는지 보여 준다.

Device probe에서 SID와 SMMU master를 묶는다

장치 발견

PCI/Platform device 발견
→ IOMMU firmware specifier 해석
→ arm_smmu_probe_device(dev)
→ SID 목록과 SMMU instance 확인
→ struct arm_smmu_master 생성
→ feature: ATS/PRI/PASID/stall 검사
→ IOMMU group 결정

arm_smmu_probe_device()가 device와 SMMU의 software 관계를 만든다.

IOMMU group은 서로 독립 격리가 가능한 최소 device 집합이다. 같은 group의 device 일부만 VM에 넘기면 peer DMA나 shared reset 때문에 격리가 깨질 수 있다.

Domain attach가 STE를 실제 translation mode로 바꾼다

  1. IOMMU core가 paging domain을 할당한다.
  2. arm_smmu_domain_finalise()가 Stage-1 또는 Stage-2 page-table config, ASID/VMID를 준비한다.
  3. arm_smmu_attach_dev()가 device의 master와 domain 호환성을 검사한다.
  4. 새 target STE를 만들어 SID별 Stream Table에 설치한다.
  5. CFGI_STE command와 sync로 SMMU가 옛 STE cache를 사용하지 않게 한다.
  6. ATS가 켜졌다면 device ATC 상태와 ordering도 맞춘다.

핵심 함수는 arm_smmu_domain_finalise()arm_smmu_attach_dev()이다.

DMA API가 IOVA→PA page table을 만든다

Mapping path

driver dma_map_*()
→ DMA/IOMMU layer가 IOVA 할당
→ iommu_map_pages()
→ arm_smmu_map_pages()
→ io_pgtable_ops.map_pages()
→ page-table descriptor write
→ device DMA 시작

arm_smmu_map_pages()는 architecture-independent io-pgtable backend에 mapping을 맡긴다.

unmap은 PTE를 지우는 것에서 끝나지 않는다. outstanding DMA가 끝났는지, SMMU IOTLB와 device ATC가 옛 번역을 갖고 있지 않은지 확인해야 한다.

CMDQ는 SMMU에게 configuration·TLB 변경을 명령한다

Command목적언제 필요한가
CFGI_STE/CDcached descriptor 무효화STE·CD를 변경한 뒤.
TLBI_NH_ASID/VAStage-1 IOTLB 무효화ASID 또는 IOVA mapping 변경.
TLBI_S2_IPA/VMALLStage-2 IOTLB 무효화VM IPA mapping 변경.
ATC_INVdevice Address Translation Cache 무효화ATS device의 mapping 변경.
CMD_SYNC앞선 command 완료 확인새 mapping을 안전하게 사용하기 전.

arm_smmu_cmdq_issue_cmdlist()과 range invalidation helper가 queue producer/consumer와 sync를 관리한다.

EVTQ는 잘못된 DMA를 SID·주소·원인과 함께 보고한다

SMMU가 STE fetch, CD fetch, translation, permission, address-size fault를 발견하면 Event Queue에 record를 쓰고 interrupt를 발생시킨다. arm_smmu_evtq_thread()이 record를 소비한다.

Fault 분석 순서

event type 확인
→ SID로 device/master 역추적
→ SSID/PASID와 IOVA 확인
→ 현재 domain과 STE/CD mode 확인
→ IOVA page table walk
→ DMA direction·length·lifetime 확인
→ ATS/PRI 사용 시 device cache·response 확인

“Unhandled context fault”만 보고 page table bug라 단정하지 않는다. stale DMA, 잘못된 firmware SID, early unmap, missing permission과 device reset race가 모두 후보다.

SVA·ATS·PRI는 process 주소 공간을 device와 공유한다

기능역할추가 위험
SVACPU process VA와 device IOVA 모델을 공유mm lifetime, PASID bind와 process exit 동기화.
PASID/SSID한 device의 여러 address space 식별잘못된 PASID가 다른 process CD를 선택하지 않게 검증.
ATSdevice가 translation을 cacheSMMU TLBI 외에 ATC invalidation 필요.
PRIdevice page request와 fault recoverystall queue, timeout과 process fault 처리.

VM device assignment에서는 CPU Stage-2와 SMMU Stage-2를 맞춘다

VFIO로 device를 VM에 할당하면 guest의 IOVA/IPA 계약과 host memory pinning, SMMU domain이 일치해야 한다. CPU가 guest RAM을 접근할 수 있다고 device도 자동 접근 가능한 것은 아니다.

Realm device assignment는 여기에 PAS/GPT와 device security state가 추가된다. 이 Linux v6.18.37의 일반 SMMUv3 driver 경로만으로 Realm private DMA가 자동 안전해진다고 결론 내리면 안 된다.

Linux v6.18.37 소스 지도

파일심볼·구조체책임
arm-smmu-v3.carm_smmu_probe_device, arm_smmu_attach_devdevice 발견과 domain 연결
arm-smmu-v3.carm_smmu_map_pages, unmap_pagesI/O page-table mapping
arm-smmu-v3.carm_smmu_cmdq_issue_cmdlistconfiguration·TLBI command
arm-smmu-v3.carm_smmu_evtq_threadhardware event 처리
arm-smmu-v3.harm_smmu_ste, arm_smmu_cdhardware descriptor layout
arm-smmu-v3.harm_smmu_master, arm_smmu_domainLinux software ownership

DMA fault를 장치까지 역추적한다

기본 자료 수집

dmesg | grep -Ei 'smmu|iommu|fault|sid|stream'
find /sys/kernel/iommu_groups -maxdepth 2 -type l
lspci -nnvv
cat /proc/iomem
sudo trace-cmd record -e iommu -e dma_fence
grep . /sys/kernel/debug/iommu/* 2>/dev/null

event의 SID, IOVA, access type과 device BDF를 먼저 고정한다. 그다음 mapping lifetime과 driver DMA API 사용을 검사하고 마지막에 SMMU descriptor를 의심한다.

근거 자료