Linux가 PCIe의 주변 장치에 DMA(직접 메모리 액세스)를 수행할 수 있는 권한을 부여하는 방법과 시기를 알아내려고 합니다. 커널에서 DMA가 어떻게 시작되는지 읽었습니다.DMA API 가이드, 하지만 여전히 몇 가지 사항을 명확히 하고 싶습니다.
이 질문은 이 질문과 관련이 있습니다.DMA 공격으로부터 Linux를 강화하는 방법은 무엇입니까?아마도IOMMU에 대한 의견그것이 답입니다. HOWTO는 통과하면서 IOMMU를 언급하고 말했습니다.
I/O 장치는 세 번째 유형의 주소인 "버스 주소"를 사용합니다. 장치의 MMIO 주소에 레지스터가 있거나 DMA를 수행하여 시스템 메모리를 읽거나 쓰는 경우 장치에서 사용하는 주소는 버스 주소입니다. 일부 시스템에서는 버스 주소가 CPU 물리적 주소와 동일하지만 일반적으로 다릅니다. IOMMU와 호스트 브리지는 물리적 주소와 버스 주소 간의 임의 매핑을 생성할 수 있습니다.
그러나 DMA 공격에 대한 질문에 대한 답변에서는 IOMMU를 참조하지 않고 공격을 완화할 것을 제안하므로 IOMMU가 있는 시스템이 얼마나 흔한지 궁금합니다. 이것이 서버에는 공통 아키텍처이지만 PC에는 적용되지 않습니까?
IOMMU 매핑으로 액세스가 정의된 경우 언제 설정됩니까?
HOWTO에서 그들은 "어떤 메모리가 DMA를 지원합니까?"라고 썼습니다.
알아야 할 첫 번째 정보는 DMA 매핑 도구가 사용할 수 있는 커널 메모리입니다. 이에 대한 기록되지 않은 규칙 세트가 있으며, 이 기사에서는 최종적으로 이를 기록해 보려고 합니다.
페이지 할당자(즉, __get_free_page*()) 또는 범용 메모리 할당자(즉, kmalloc() 또는 kmem_cache_alloc())를 통해 메모리를 얻는 경우 주소를 사용하여 해당 메모리로 DMA 전송을 수행할 수 있습니다. 이 루틴에서 반환되었습니다.
그러나 그들은 장치에 일부 권한을 부여하고 실제로 DMA를 활성화하는 것에 대해서는 언급하지 않았습니다. 이로 인해 장치가 허가 없이 즉시 해당 메모리에 쓸 수 있는지 궁금합니다. 그렇다면 할당은 운영 체제의 소프트웨어 비즈니스이므로 장치가 다른 메모리에도 쓸 수 있다는 의미입니다.
문제는 언제 주 메모리 블록을 PCIe 버스에서 쓸 수 있느냐는 것입니다.
그러나 다음은 대답이 될 수 있습니다:
올바른 작동을 위해서는 DMA 마스크를 설정하여 장치의 DMA 주소 지정 기능을 커널에 알려야 합니다.
이는
dma_set_mask_and_coherent()
::를 호출하여 수행 됩니다.int dma_set_mask_and_coherent(struct device *dev, u64 mask);
그러면 스트리밍 API와 일관성 API 모두에 대한 마스크가 설정됩니다.
이러한 호출은 일반적으로 0을 반환합니다. 이는 귀하가 제공한 주소 마스크가 주어지면 장치가 컴퓨터에서 DMA를 올바르게 수행할 수 있음을 나타냅니다. 그러나 마스크가 너무 작아서 지정된 시스템에서 지원할 수 없는 경우 오류가 반환될 수 있습니다.0이 아닌 값을 반환하면 장치가 이 플랫폼에서 DMA를 올바르게 수행할 수 없으며 그렇게 하려고 하면 정의되지 않은 동작이 발생합니다.. 이 기능 계열이 성공을 반환하지 않는 한
dma_set_mask
이 장치에서 DMA를 사용하면 안 됩니다 .
아하! 그렇다면 DMA 마스크가 메모리에 대한 액세스를 정의합니까? 함수군은 dma_set_mask
할당 방식에 상관없이 메인 메모리의 DMA를 가능하게 하는 API인가요? 기본적으로 "올바른 작동을 위해서는 장치의 DMA 주소 지정 기능을 커널에 알리기 위해 DMA 마스크를 설정해야 합니다"는 무엇을 의미합니까? DMA 마스크로 커널에 무엇을 알리고 있습니까? 일부 소프트웨어나 하드웨어 기술(예: IOMMU)을 통해 PCIe 버스에서 물리적 메모리에 대한 액세스를 정의합니까, 아니면 외부 장치에서 메모리 조각을 사용할 수 있다는 사실을 커널에 알리기만 하여 커널이 해당 메모리를 사용할 수 없도록 합니까? 가상 메모리 시스템과 같은 자체 목적. 마지막 시나리오는 단지 "장치에 DMA 주소 지정 기능을 알리는 것"이기 때문에 가능성이 더 높아 보입니다. 그런 다음 시스템은 외부 장치의 임의 DMA 액세스에 대해 열린 상태를 유지합니다.
또한 IOMMU가 MMU처럼 작동한다는 것을 올바르게 이해하고 있습니까? 각 장치에 대한 메모리 맵을 설정합니까? 따라서 IOMMU는 허용된 매핑 외부의 메모리에 액세스하려고 시도하는 모든 장치를 차단합니다. segfault와 같은 일부 인터럽트를 CPU에 보내나요? 이 경우에는 "정의되지 않은 동작"이 없으며 액세스가 차단될 뿐 그 이상은 없습니다.
아마도 이 문제는 다음과도 관련이 있을 것입니다.PCIe 장치에서 RAM에 액세스할 수 없습니다., CPU가 다른 PC에서 Windows 또는 Linux를 실행 중인 경우 RAM은 PCIe의 FPGA에서 액세스할 수 있지만 Linux의 기본 PC에서는 액세스할 수 없습니다. 따라서 Windows에서는 어떻게든 RAM에 대한 액세스를 허용하지만 Linux에서는 그렇지 않습니다. DMA를 허용하려면 Linux에서 무엇을 해야 합니까?