Linux v6.18.37 · Arm SMMUv3 · IHI 0070C.a의 해당 규칙 별도 명시

SMMU는 누구의 주소를 변환합니까?

SID·PASID로 변환 표를 고르는 과정과 실제 주소 변환을 구분하고, SVA의 page fault와 DMA 종료 조건을 살펴봅니다.

식별자는 표를 고르고, 표는 주소를 바꿉니다

장치가 메모리를 읽거나 쓸 때는 접근할 주소뿐 아니라 어느 장치의 요청인지도 구별해야 합니다. 한 장치가 여러 프로세스의 작업을 받는다면 어느 주소 공간을 사용할지도 정해야 합니다. SMMU를 읽다가 StreamID와 PASID, 가상 주소가 모두 숫자로 나오더라도 같은 종류의 값으로 취급하지 않습니다.

이름무엇을 구별합니까?주소와의 차이
StreamID, SIDSMMU에 들어오는 요청의 stream입니다. 대응하는 Stream Table Entry, STE를 선택합니다.STE에는 변환 단계와 표의 위치 등이 있습니다. SID 자체가 데이터가 놓인 주소는 아닙니다.
SubstreamID, SSID / PCIe PASID지원되는 구성에서 같은 stream 안의 Stage-1 문맥을 구별합니다. PASID가 SMMU의 SSID로 전달되는 관계를 고려합니다.Context Descriptor, CD를 선택할 식별자입니다. Linux PID나 페이지의 주소로 해석하지 않습니다.
ASID / VMID각 변환 문맥을 translation cache에서 구별하는 데 쓰입니다.CD의 ASID와 요청의 PASID가 반드시 같은 숫자인 것은 아닙니다.
VA / IOVA / IPA / PA접근할 메모리 위치를 나타냅니다.VA는 가상 주소, IOVA는 I/O 주소 공간의 주소, IPA는 중간 물리 주소, PA는 최종 물리 주소입니다. 어느 단계의 입력인지 함께 적어야 합니다.

PCIe Requester ID와 SID도 무조건 같은 숫자는 아닙니다. 예를 들어 ACPI의 IORT를 사용하는 v6.18.37 코드는 PCI DMA alias를 IORT의 ID mapping에 넣고 나온 streamid를 등록합니다. firmware가 기술한 연결과 alias를 확인해야 합니다. IORT는 장치와 IOMMU 사이의 연결·식별자 대응을 알리는 ACPI 표입니다. iort_pci_iommu_init·iort_id_map

식별자 선택과 주소 변환의 두 가지 역할
  1. 요청: SID 0x120, 유효한 SSID 7, 주소 0x00401234

    장치가 보내는 한 요청을 설명용 숫자로 나타냈습니다. 주소 외에 읽기·쓰기와 권한 정보도 필요합니다.

    SID로 stream 설정을 찾습니다.

  2. STE: Stage-1과 Stage-2 설정

    이 예에서는 두 단계를 모두 사용하고 여러 CD를 허용합니다.

    SSID로 Stage-1 문맥을 고릅니다.

  3. CD 7: 사용할 Stage-1 표와 ASID

    이 CD가 가리키는 표에 주소 0x00401234를 적용합니다.

    선택한 표로 주소와 접근 권한을 확인합니다.

  4. 변환 결과: IPA를 거쳐 PA

    식별자 7을 물리 주소로 계산한 결과가 아닙니다. 7로 고른 표가 입력 주소의 대응을 정합니다.

화살표는 설정을 찾고 변환을 적용하는 관계입니다. 실제 구현이 매 요청마다 메모리의 모든 표를 순서대로 읽는다는 뜻은 아닙니다. SMMU가 설정과 변환 결과를 캐시에 보관할 수 있습니다.

Linux의 arm_smmu_make_s1_cd는 CD에 ASID와 표의 시작 주소, 메모리 속성을 채웁니다. arm_smmu_map_pages는 별도로 iova와 paddr의 대응을 페이지 표에 만듭니다. 문맥을 선택하는 값과 변환할 주소가 코드에서도 별개의 인자로 다뤄집니다. CD 구성·페이지 매핑

같은 주소에 PASID만 다르면 어떻게 됩니까?

두 문맥이 같은 가상 주소를 서로 다른 메모리에 연결했다고 가정하겠습니다. 두 단계 모두 4 KiB 페이지를 쓰며, 표와 권한·메모리 속성이 유효한 예입니다. 아래 숫자는 원리를 설명하기 위해 정했으며 실제 장치에서 읽은 값이 아닙니다.

항목문맥 A문맥 B
SID0x1200x120
SSID / 선택한 CD7 / CD 79 / CD 9
입력 주소0x004012340x00401234
Stage-1 페이지 대응0x00401000 → IPA 0x800010000x00401000 → IPA 0x90001000
Stage-2 페이지 대응0x80001000 → PA 0x1200010000x90001000 → PA 0x130001000
최종 데이터 위치PA 0x120001234PA 0x130001234

0x234는 페이지 안의 위치입니다. 이 예에서는 각 단계가 페이지 번호를 바꾸고 같은 offset을 유지합니다. SID가 같아도 CD가 다르면 Stage-1 표가 달라질 수 있습니다. 반대로 서로 다른 식별자가 같은 메모리를 공유하도록 매핑할 수도 있으므로, 식별자가 다르다는 사실만으로 두 buffer가 반드시 분리되었다고 판단하지 않습니다.

문맥 A의 요청을 따라갑니다

1. 요청을 해석합니다

입력 주소는 0x00401234이며 SSID는 7입니다. 7에 페이지 크기를 곱해서 메모리 주소를 만드는 과정이 아닙니다. 선택된 CD의 설정과 페이지 표를 사용합니다.

2. Stage-1 대응을 적용합니다

입력 페이지 0x00401000에 대한 IPA 페이지는 0x80001000입니다. offset 0x234를 포함한 중간 주소는 0x80001234입니다. 권한을 허용하지 않거나 매핑이 없으면 정상 결과가 나오지 않습니다.

3. Stage-2 대응을 적용합니다

IPA 페이지 0x80001000은 PA 페이지 0x120001000에 연결되어 있습니다. 따라서 최종 데이터 주소는 0x120001234입니다. 이 변환이 성공했다는 사실과 장치의 읽기·쓰기 완료는 별개입니다.

4. SSID를 9로 바꿔 비교합니다

다른 조건이 같아도 CD 9의 Stage-1 표를 사용하므로 이 예의 최종 주소는 0x130001234입니다. Linux가 선택한 PASID를 장치 작업에 올바르게 넣는 과정이 필요한 이유입니다.

단계는 설명을 위해 나눈 변환 과정입니다. 주소 사이의 →는 매핑 관계이며 메모리 복사 방향이나 CPU register의 대입 순서가 아닙니다. 페이지 표를 읽는 과정 자체의 Stage-2 변환은 생략했습니다.

구성데이터 주소의 변환주의할 점
Stage-1만 사용입력 VA 또는 IOVA → PA일반 DMA용 IOVA 표가 반드시 CPU 프로세스의 표와 같은 것은 아닙니다.
Stage-2만 사용입력 IPA → PA항상 장치 쪽 Stage-1이 먼저 있다는 뜻은 아닙니다.
두 단계 사용VA → IPA → PACPU의 Stage-2와 SMMU의 Stage-2가 자동으로 하나의 설정이 되는 것은 아닙니다.
허용된 bypass해당 변환 단계를 건너뜁니다.장치가 모든 메모리에 안전하게 접근한다는 보장은 아닙니다. 설정과 접근 경계를 별도로 봐야 합니다.

IOMMUFD 문서는 커널이 관리하는 HWPT_PAGING과 그 위에 연결되는 HWPT_NESTED를 구분합니다. 중첩 구성에서는 장치의 Stage-1 표를 guest·사용자 공간이 관리하고, 부모의 Stage-2가 최종 접근 범위를 제한하는 관계를 표현합니다. CPU KVM memslot을 등록한 사실만으로 장치의 매핑까지 끝났다고 볼 수 없습니다. IOMMUFD 객체와 nested translation

SubstreamID가 없는 요청과 값이 0인 요청도 다릅니다

구형 설명의 “Stage-1이 꺼져 있는데 SubstreamID를 붙이면 요청이 종료된다”는 부분은 무조건 틀린 설명이 아닙니다. Arm IHI 0070C.a의 해당 규칙과 맞습니다. 다만 SMMU가 활성화되어 STE 설정을 적용하는 경우라는 전제를 붙여야 합니다. SMMU 전체를 비활성화한 global bypass와 STE의 Stage-1 bypass는 같은 상태가 아닙니다.

IHI 0070C.a에서 확인할 조건해당 규칙
STE에서 Stage-1이 비활성이고 요청에 SubstreamID가 있습니다.요청을 abort하며 C_BAD_SUBSTREAMID를 보고합니다.
Stage-1과 여러 CD를 사용하지만 요청에 SubstreamID가 없습니다.S1DSS 설정에 따라 종료, Stage-1 bypass, CD 0 선택 중 동작이 정해집니다.
S1DSS가 SubstreamID 없는 요청에 CD 0을 사용하도록 설정되었습니다.이 경우 SubstreamID 0을 명시해서 보낸 요청은 종료됩니다.

따라서 “없으면 0”으로 치환해서 해석하면 조건을 놓칩니다. 위 표는 2019년의 IHI 0070C.a 규칙을 확인한 것이며, 모든 후속 확장과 구현을 망라한 표는 아닙니다. Arm IHI 0070C.a · 3.3.2·3.9·STE S1DSS

SVA는 같은 주소 공간을 쓰게 하는 기능입니다

SVA, Shared Virtual Addressing은 장치가 프로세스의 가상 주소 공간을 이용하도록 연결하는 기능입니다. “주소가 같다”와 “CPU가 접근할 수 있으면 장치도 아무 준비 없이 접근한다”는 다릅니다. 지원되는 장치·IOMMU·커널 설정과 연결 절차, 권한 검사가 필요합니다.

서로 다른 경로입력과 만들어지는 관계그 호출이 하지 않는 일
일반 DMA mapping커널 드라이버가 buffer를 장치용 DMA 주소에 연결합니다.DMA 전송을 시작하거나 완료시키지 않습니다.
커널 SVA bindingiommu_sva_bind_device(dev, mm)가 장치와 mm_struct 주소 공간을 연결합니다.장치 작업 queue에 주소와 PASID를 자동으로 제출하지 않습니다.
사용자 공간 IOMMUFD mappingIOMMU_IOAS_MAP이 등록한 사용자 메모리 범위와 IOVA의 대응을 만듭니다.현재 프로세스의 모든 VA를 장치에 자동 공개하는 SVA binding과 같지 않습니다.

mm_struct는 프로세스의 주소 공간을 관리하는 커널 객체입니다. 여러 thread가 이를 공유할 수 있으므로 task 하나와 주소 공간 하나를 항상 일대일로 보면 안 됩니다. SVA bind의 호출자는 유효한 mm 참조를 유지해야 하며, 실패는 ERR_PTR로 돌아옵니다. 성공한 handle에서 iommu_sva_get_pasid로 얻은 값은 장치가 사용할 문맥 식별자이지 process PID가 아닙니다. SVA bind·PASID 취득·unbind

이 버전의 arm_smmu_make_sva_cd는 mm가 있으면 mm->pgd의 물리 주소를 CD의 표 시작 주소에 반영합니다. pgd는 CPU 주소 공간의 최상위 페이지 표를 가리키는 포인터입니다. 이 코드가 사용자 buffer의 내용을 CD에 복사하는 것은 아닙니다. 또한 arm_smmu_sva_supported는 coherency, 주소 폭, page granule 등의 조건을 확인하므로 SMMUv3라는 이름만으로 SVA 사용 가능 여부를 정할 수 없습니다. SVA CD 구성과 지원 조건

SVA·ATS·PRI·stall을 같은 기능으로 읽지 않습니다

이름역할혼동하기 쉬운 부분
SVA장치가 프로세스 주소 공간을 사용하도록 연결합니다.주소 공간 공유를 뜻하며, page fault 해결 방식이나 장치 완료 자체의 이름이 아닙니다.
ATS, Address Translation ServicesPCIe 장치가 변환을 요청하고 장치의 ATC에 결과를 보관할 수 있게 합니다.ATC는 Address Translation Cache입니다. 모든 SMMU 내부 cache와 같은 저장소가 아닙니다.
PRI, Page Request InterfacePCIe 장치가 필요한 페이지에 대해 page request를 보내고 응답받는 절차입니다.CPU page fault와 같은 하드웨어 예외가 발생한다는 뜻은 아닙니다. 드라이버의 실제 지원을 확인해야 합니다.
SMMU stall과 IOPF지원되는 구성이 fault 난 요청을 보류하고 소프트웨어에 I/O page fault를 알립니다.PCIe PRI queue의 처리와 구별해야 합니다. Linux에는 EVTQ의 stalled event를 처리하는 별도 경로가 있습니다.

ATS와 PRI의 일반적인 관계는 Linux의 x86 SVA 문서에서도 설명합니다. 다만 그 문서의 ENQCMD·IA32_PASID 같은 x86 명령·register를 ARM 구현에 그대로 옮기지 않습니다. PCIe ATS·PRI와 x86 전용 절차의 구분

Linux v6.18.37의 Arm SMMUv3에서 특히 확인할 부분은 arm_smmu_handle_ppr입니다. 이 함수는 PRI 요청을 예상 밖의 요청으로 기록하고, 해당 request group의 마지막 요청이면 PRI_RESP_DENY 응답을 만듭니다. 이 코드를 “PRI로 요청을 받으면 페이지를 준비해서 DMA를 계속시킨다”라고 설명할 수는 없습니다. 이 판정은 이 태그의 이 드라이버 경로에 대한 것이며 모든 IOMMU나 다른 커널 버전의 지원 여부를 대신하지 않습니다. arm_smmu_handle_ppr·arm_smmu_priq_thread

지원되는 SVA stall 경로에서 page fault를 처리하는 순서
  1. SMMU가 stalled event를 EVTQ에 남깁니다.

    EVTQ는 event queue입니다. fault 주소와 SID, 유효한 SSID, 접근 권한, stall tag를 보고합니다.

    Linux가 이벤트를 I/O page fault 정보로 옮깁니다.

  2. 해당 장치·PASID의 주소 공간을 찾습니다.

    IOMMU fault 전달 경로를 거쳐 SVA handler가 mm와 VMA를 확인합니다. VMA는 주소 공간 안의 유효한 메모리 영역입니다.

    주소와 권한이 맞을 때 page fault 해결을 시도합니다.

  3. handle_mm_fault의 결과를 확인합니다.

    유효한 영역이 없거나 권한이 맞지 않거나 page fault 처리가 실패하면 성공으로 답하지 않습니다.

    성공·실패 결과로 보류된 요청에 응답합니다.

  4. SMMU에 CMD_RESUME을 보냅니다.

    arm_smmu_page_response는 성공이면 RETRY, 실패이면 ABORT를 선택합니다. 재시도 허용은 DMA 작업 전체 완료 통지가 아닙니다.

화살표는 fault 보고와 소프트웨어 처리 순서입니다. PCIe PRIQ 처리 그림이 아닙니다. 장치·SMMU의 stall 지원, SVA 연결과 IOPF 준비가 갖춰진 경로를 가정합니다.

arm_smmu_enable_iopf는 CONFIG_ARM_SMMU_V3_SVA를 확인합니다. CONFIG 이름은 커널 빌드에서 기능 포함 여부를 정한 값입니다. 기능이 빌드되었다는 사실만으로 실행 중 모든 장치에서 stall이 활성화되지는 않습니다. 이 버전은 stall을 사용하는 IOPF 등록 경로에서 stream이 하나인 장치를 요구하는 조건도 둡니다. IOPF 활성화 조건·event 변환·page response iommu_sva_handle_mm의 VMA·권한 검사

예전 VFIO ioctl 이름은 현재 헤더와 대조합니다

예전 자료에 등장하는 VFIO_DEVICE_BIND_TASK는 v6.18.37의 공개 include/uapi/linux/vfio.h에서 제공하는 ioctl 이름이 아닙니다. 그 이름을 현재 실행 가능한 예제처럼 옮기면 안 됩니다. 아래는 이 태그의 VFIO device cdev와 IOMMUFD 경로입니다. 기존 VFIO group/container 경로가 모두 사라졌다는 뜻은 아니며, 커널 드라이버의 SVA API와도 구분합니다.

현재 인터페이스·객체사용 목적값을 읽을 때 주의할 점
VFIO_DEVICE_BIND_IOMMUFDVFIO device cdev를 지정한 IOMMUFD에 연결합니다.out_devid는 그 연결을 가리키는 handle입니다. SID나 장치의 PA가 아닙니다.
IOMMU_IOAS_ALLOC / IOASI/O 주소 공간 객체를 만듭니다.ioas_id는 객체 ID입니다. 주소 공간에 아직 원하는 buffer 매핑이 있다는 뜻은 아닙니다.
IOMMU_IOAS_MAPuser_va와 length로 지정한 메모리를 IOVA에 매핑합니다.user_va와 iova는 역할이 다른 주소입니다. FIXED_IOVA가 없으면 할당된 IOVA가 출력됩니다.
IOMMU_HWPT_ALLOC / HWPT장치가 사용할 변환 표 객체를 준비합니다.hwpt_id는 객체 ID입니다. 페이지 표의 물리 주소가 아닙니다. 지원되는 중첩 구성과 flag를 확인합니다.
VFIO_DEVICE_ATTACH_IOMMUFD_PT연결된 device 또는 PASID에 IOAS/HWPT를 붙입니다.pasid 필드는 VFIO_DEVICE_ATTACH_PASID flag를 설정한 경우에 의미가 있습니다.

PASID를 사용하는 HWPT에는 IOMMU_HWPT_ALLOC_PASID 같은 할당 조건이 있으며, 하드웨어·드라이버가 요청을 지원하지 않으면 실패할 수 있습니다. 헤더에 구조체가 있다는 것만으로 모든 장치가 그 동작을 지원한다고 판단하지 않습니다. 중첩 SMMUv3 설정도 허용된 STE 필드만 받을 수 있고 부모 변환을 통해 접근 가능한 표여야 합니다. IOAS·HWPT·SMMUv3 설정 정의 VFIO cdev bind·attach 정의

/* 이미 bind한 device cdev와 호환되는 HWPT를 준비한 뒤의 요청 예입니다. */
struct vfio_device_attach_iommufd_pt req = {
    .argsz = sizeof(req),
    .flags = VFIO_DEVICE_ATTACH_PASID,
    .pt_id = hwpt_id,
    .pasid = pasid,
};
int rc = ioctl(device_fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &req);
코드이 줄의 의미
struct … req = { … }사용자 공간에서 ioctl에 넘길 요청 구조체를 준비합니다. SMMU register를 직접 쓰는 문장이 아닙니다.
.argsz = sizeof(req)호출자가 준비한 구조체의 바이트 크기를 알립니다. 커널이 인자 형식을 확인할 때 사용합니다.
.flags = VFIO_DEVICE_ATTACH_PASID이 요청이 특정 PASID에 대한 attach임을 표시합니다. PASID 숫자 자체를 flag에 넣지 않습니다.
.pt_id = hwpt_id이 IOMMUFD에서 앞서 준비한 호환 HWPT 객체의 ID를 넣습니다. &변수나 페이지 표의 PA를 넘기는 칸이 아닙니다.
.pasid = pasid장치에서 사용하도록 관리하는 PASID 값을 넣습니다. 임의의 PID를 넣어 프로세스를 찾게 하는 인터페이스가 아닙니다.
ioctl(…, &req)device_fd에 요청을 제출합니다. 사용자 공간에서는 rc가 -1이면 errno를 확인합니다. 성공해도 장치 작업 제출·DMA 완료까지 수행한 것은 아닙니다.

위 코드는 필드의 의미를 보기 위한 일부입니다. fd 생성, 권한, 기능 확인, 객체 할당, 오류 처리와 해제를 포함한 완전한 실행 프로그램은 아닙니다. attach의 pt_id는 입력뿐 아니라 출력 의미도 있으므로 반환 뒤에는 API가 돌려준 값을 기준으로 관리합니다. 이전 글의 구형 ioctl 하나를 다른 ioctl 하나로 이름만 바꿔 이식할 수는 없습니다. IOMMUFD 객체의 연결 관계

프로세스가 끝났다고 장치도 멈춘 것은 아닙니다

CPU가 buffer를 더 사용하지 않아도 장치는 이미 받은 명령으로 DMA를 수행할 수 있습니다. SVA에서는 프로세스 주소 공간이 해제될 때 장치 쪽 변환도 함께 정리해야 합니다. 이때 CPU TLB, SMMU의 변환 cache, ATS 장치의 ATC, 실제 장치 작업의 완료를 나누어 봐야 합니다.

주소 공간 해제와 DMA 정리에서 확인할 상태

1. 장치에 작업이 남아 있을 수 있습니다

CPU가 프로세스 종료를 시작해도 이미 제출된 장치 작업이 사라지는 것은 아닙니다. queue 제출 중단·취소·완료 대기는 장치 드라이버와 장치의 절차에 따라 처리해야 합니다.

2. SMMU의 SVA 문맥을 막습니다

v6.18.37의 arm_smmu_mm_release는 CD를 유효한 형태로 유지하면서 새 표 탐색을 막는 CD를 기록합니다. mm가 NULL인 arm_smmu_make_sva_cd가 그 구성을 만듭니다. CD를 단순히 잘못된 구조체로 만드는 것과 다릅니다.

3. 이전 변환 결과를 정리합니다

같은 release 경로에서 ASID에 대한 SMMU translation cache와 장치 ATC의 무효화 절차를 호출합니다. 이전 주소 대응이 남은 상태로 메모리나 식별자를 재사용하지 않기 위한 처리입니다. CPU TLB 처리만 설명하고 끝낼 수 없습니다.

4. 장치 종료 조건과 binding 수명을 맞춥니다

iommu_sva_unbind_device의 호출 조건은 해당 PASID로 더 이상 transaction을 발행하지 않고, 남은 page request가 IOMMU까지 전달된 상태입니다. unbind를 호출하면 장치가 자동으로 모든 작업을 완료한다고 가정하지 않습니다. 성공한 bind 참조마다 대응하는 unbind가 필요합니다.

단계는 주소 공간 해제 때 확인할 상태와 책임입니다. 모든 장치의 종료 함수가 이 순서대로 호출된다는 실행 trace가 아닙니다. 새 작업 차단과 실제 전송 완료·취소는 장치별로 보장해야 하며 cache 무효화가 그 책임을 대신하지 않습니다.

arm_smmu_mm_release의 주석도 DMA가 아직 실행 중일 수 있음을 전제로 합니다. 따라서 “주소 공간을 해제했다”, “변환 cache를 비웠다”, “장치가 buffer 쓰기를 끝냈다”는 세 문장을 구분해서 써야 합니다. 오류나 강제 종료에서는 정상 완료 대신 abort·reset을 선택할 수 있으며, 메모리를 재사용해도 안전한 시점은 장치와 커널의 종료 절차가 보장해야 합니다. mm release·TLB·ATC 무효화 unbind의 호출 조건

기존 코드 분석과 함께 확인할 위치

확인할 질문v6.18.37에서 읽을 위치
SID는 어디서 정해집니까?IORT의 iort_pci_iommu_init → iort_node_map_id와 장치의 IOMMU 설정을 확인합니다. 화살표는 함수의 호출 관계입니다.
CD에 어떤 값이 들어갑니까?arm_smmu_make_s1_cd와 arm_smmu_make_sva_cd를 비교합니다. 일반 IOVA 표와 프로세스 mm->pgd를 혼동하지 않습니다.
fault는 재시도할 수 있습니까?EVTQ의 stall 처리, SVA의 VMA·권한 검사, arm_smmu_page_response를 연결합니다. PRIQ handler는 따로 읽습니다.
지금 쓰는 사용자 API입니까?include/uapi/linux/vfio.h와 iommufd.h의 동일 태그를 확인합니다. 과거 글의 ioctl 명칭만으로 예제를 만들지 않습니다.
매핑 해제 뒤 buffer를 돌려줘도 됩니까?변환 제거와 cache 동기화뿐 아니라 장치의 완료·중단 조건을 확인합니다.

기존 SMMUv3 분석에는 STE·CD 구성, domain attach와 IOTLB 동기화 helper의 설명이 있습니다. 이 글은 그 코드를 다시 나열하기보다 식별자와 주소의 실제 의미, fault 처리의 지원 범위, 사용자 API와 buffer 수명에서 생기기 쉬운 오해를 보충합니다. 코드와 API는 v6.18.37을 기준으로 대조했으며, 설명용 주소 예제를 실제 하드웨어 실행 결과로 제시하지 않았습니다.