Direct Memory Access

#1 CPU and DMA addresses

  DMA API에서 사용되는 주소 공간은 3가지가 있다. 각각의 주소 공간들은 모두 CPU, 메모리, 디바이스의 관점에서 주소 공간을 정의하여 메모리의 주소를 나타내기 위해 사용한다. 

  • Bus Address Space
    • 디바이스가 메모리에 접근하기 위해 사용하는 주소 공간
    • MMIO나 DMA를 사용할 때 주로 사용
    • IOMMU에 의해 메모리 주소에 매핑되거나 오프셋이 직접 매핑되어 사용
  • Physical Address Space
    • CPU가 접근하는 메모리의 물리 주소를 나타내는 주소 공간
    • 일반적으로 virtual address space와 매핑되어 사용
  • Virtual Address Space
    • CPU가 가상 메모리를 위해 사용하는 주소 공간
    • kmalloc(), vmalloc()과 같은 인터페이스로 반환되는 void * 형식의 주소

그림 1. Address Mapping 예

   

  각각의 주소 공간이 서로 매핑이 되어야 CPU가 디바이스의 메모리에 접근하고, 디바이스가 메모리에 접근할 수 있게 된다. 주소 공간을 매핑하는 방법은 크게 2가지가 있다. 먼저, PCIe 디바이스가 BAR를 가지고 있는 경우 커널은 BAR의 주소(A)를 읽어 호스트 브릿지를 통해 물리 메모리 주소(B)로 변환한다. 물리 메모리 주소(B)는 /proc/iomem 파일에 구조체 형식으로 정의되어 저장된다. 드라이버가 디바이스에게 요청할 때는 ioremap() 함수를 통해 물리 메모리 주소 (B)를 가상 메모리 주소(C)로 치환하여 사용한다.

  만약 디바이스가 DMA를 지원하는 경우, 드라이버는 먼저 kmalloc()과 같은 함수를 통해 물리 메모리에 버퍼를 할당(Y)하고 가상 주소를 매핑하여 해당 주소(X)를 반환한다. 그리고 버스 주소 공간과 매핑하기 위해 IOMMU를 통해 버스 주소(Z)를 물리 메모리 주소(Y)로 변환한다. 예를 들어 dma_map_single()과 같은 함수로 가상 주소(X)를 IOMMU 매핑을 통해 버스 주소(Z)와 매핑 후 반환할 수 있다. 

  DMA API는 microprocessor와 독립적으로 동작하기 때문에 DMA API를 사용할 때는 특정 버스의 DMA API보다 일반 DMA API를 사용하기를 커널 공식 문서에서는 권장한다.

#2 DMA'able memory

  일반적인 페이지 할당자(__get_free_page*(), kmalloc(), kmem_cache_alloc())을 이용하여 반환받은 가상 주소는 DMA 메모리 영역으로 사용할 수 있다. 하지만 vmalloc()으로 메모리를 할당한 경우, 가상 주소는 연속적이나 물리 메모리 주소가 연속적이지 않을 수 있기 때문에 이를 맞춰주어야 하는 번거로움이 있다. 그리고 이런 메모리 영역은 DMA와 물리적으로 작동할 수 있더라도, I/O 버퍼가 캐시 라인으로 정렬되어 있음을 보장하여야 한다. 그렇지 않으면 CPU와 DMA-incoherent 캐시의 캐시라인 공유 문제가 발생한다. (CPU는 한 word를 기준으로 I/O가 이루어지고 DMA는 하나의 캐시라인을 기준으로 I/O가 이루어지기 때문에 다른 캐시 라인이 덮어쓰일 수 있다.)

#3 DMA address capacity

  디바이스의 관점에서 DMA는 버스 주소 공간을 사용하지만 이 주소는 시스템의 주소 체계에 의해 제한될 수 있다. 예를 들어, 디바이스가 64비트 체계를 사용하더라도, 32비트 체계의 시스템을 사용함으로써 주소 공간의 크기가 32비트로 제한될 수 있다. 따라서 아래 함수를 통해 DMA mask를 설정하여 DMA 주소 체계를 매핑할 필요가 있다.

int dma_set_mask_and_coherent(struct device *dev, u64 mask); // set up streaming mask & coherent mask
int dma_set_mask(struct device *dev, u64 mask); // set up streaming mask
int dma_set_coherent_mask(struct device *dev, u64 mask); // set up coherent mask

#4 DMA direction

  DMA 방향은 아래와 같으며, 방향을 알면 성능 최적화를 위해 최대한 맞춰 설정하기를 권장한다. 또한, 특정 플랫폼에서는 page protection와 같은 write 권한 이슈가 있기 때문에 방향을 구체적으로 설정하기를 권장한다.

DMA_BIDIRECTIONAL // memory <-> device
DMA_TO_DEVICE // memory -> device
DMA_FROM_DEVICE // memory <- device
DMA_NONE // used for debugging

 

  DMA_NONE의 경우 디버깅의 용도로 많이 사용하며, 구체적인 DMA 방향을 모를 때 사용하면 어느 방향으로 DMA가 이루어지는 지 알 수 있도록 도와준다.

#5 Types of DMA mappings

내용 추가 예정

  • Consistent DMA mappings
  • Streaming DMA mapping

 

 

참조: https://www.kernel.org/doc/Documentation/DMA-API-HOWTO.txt

'컴퓨터 과학 > 운영체제' 카테고리의 다른 글

Docker Script  (0) 2024.05.17
Cgroups (Control Groups)  (0) 2024.05.17

+ Recent posts