Direct Memory Access

여태까지 컴퓨터는 직접 메모리에 대해 접근하지 않고 가상 메모리를 사용하는 것으로 배웠는데, 만약 직접 메모리 접근이 있다면?

DMA(Direct Memory Access)란?

CPU를 거치지 않고 I/O 장치가 메인 메모리와 직접 데이터 블록을 주고받게 해 주는 하드웨어 메커니즘입니다. OS입장에서 보면 “장치 ↔ 메모리 복사”라는 반복적이고 대용량인 일을 CPU로부터 떼어 내어 병렬성CPU 자유도를 확보하는 핵심 최적화 기법이다.

왜 DMA가 필요한가?

전통적 PIO(Programmed I/O)DMA가 주는 이점
CPU가 I/O 레지스터를 통해 바이트 단위로 데이터를 옮기면 레이턴시·오버헤드가 큼한 번에 수십~수천 바이트 블록을 메모리로 직행 ⇒ CPU cycles 절약
빠른 장치(SSD, 10 GbE NIC 등)는 CPU 속도보다 I/O 대역폭이 큼 → CPU가 “목”이 됨DMA 엔진이 버스 마스터로 동작해 메모리 버스를 직접 차단·사용
멀티코어 시대에 CPU는 계산에 집중하고 싶음CPU는 전송 시작/종료만 관리 → I/O wait 시간 줄고, 캐시 miss도 감소
  • 덕분에 대역폭·지연시간 모두 절감, 특히 디스크 I/O, 네트워크 카드, 오디오 스트리밍처럼 폭이 넓고 반복적인 전송에 필수적이다

기본 구성 요소

  1. DMA 컨트롤러(DMAC)

    • 전용 칩(고전 ISA-DMA) 또는 주변장치 내부 DMA 엔진(PCIe, NVMe 컨트롤러)

    • 소스/목적지 물리 주소, 전송 길이, 모드, 제어 플래그 등을 저장하는 레지스터(메모리 맵 레지스터) 보유

    • 여러 채널이 있으면 동시에 여러 장치 지원

  2. 시스템 버스

    • CPU ↔ 메모리 ↔ DMA 컨트롤러가 공유

    • CPU와 DMAC가 동시에 쓰지 않도록 버스 중재(bus arbitration) 를 수행

  3. 메모리 버스

    • DMAC가 버스 마스터(master) 권한을 요청(Bus Request, BR) → 메모리와 직접 주고받음
  4. 주변장치(Device)

    • 디스크, NIC, GPU, 오디오 코드 … 데이터가 실제로 존재/필요한 곳
  5. CPU & OS

    • 전송 파라미터를 DMAC 레지스터에 써 주고, 완료 인터럽트(DMA done)를 처리
  6. I/O 장치(버스 마스터 가능 장치)

    • PCIe NIC, NVMe SSD, GPU 등은 자체 DMA 엔진을 내장해 버스 마스터 가 되기도 한다

DMA 레지스터 SRC, DST, LEN

레지스터역할일반적 크기세부 사항
SRC (Source Address)읽어 올 원본 주소. 장치 → RAM 전송이면 장치 쪽 FIFO 주소, RAM → 장치 전송이면 RAM의 시작 주소32 bit(SoC) 또는 64 bit(서버)* 버스트·비버스트 여부, 버스트 길이에 따라 자동 증가(inc) 여부 선택 플래그 존재
* Scatter-Gather 모드에선 “다음 표(list) 항목” 주소로 해석되기도 함
DST (Destination Address)쓰기 대상 주소32/64 bit* 자동 증가/고정 선택 가능 (예: 오디오 DAC 같은 스트리밍 장치는 고정 주소, 메모리 버퍼는 증가)
LEN (Length / Count)총 바이트(혹은 워드) 수16 bit(65 kB) ~ 32 bit(4 GB) 이상* 전송이 끝날 때마다 LEN–; 0 → 인터럽트 발생
* 어떤 컨트롤러는 LEN 대신 COUNT×DATA_WIDTH 형태 사용

요약 : SRC·DST는 “어디서 → 어디로”를, LEN은 “얼마나”를 알려주는 좌표 + 거리 정보라고 생각하면 된다

동작 흐름 (x86 PC 예시)

단계신호선 & 동작
① CPU 설정DMAC 레지스터에 <소스, 목적지, 길이, 모드> 기록 후 Bus Request(BR) 활성화
② 버스 획득CPU가 Bus Grant(BG)로 응답 → CPU 파이프라인이 버스를 놓고 다른 연산(레지스터 계산 등) 수행
③ 데이터 전송DMAC가 메모리 ↔ 장치 간 버스 싸이클 생성
④ 완료 인터럽트전송 길이가 0이 되면 DMAC가 CPU에 DMA 완료 인터럽트. CPU는 이후 버스 재획득

중요 : DMAC가 버스를 잡은 동안 메모리 전체 버스 주도권을 갖기 때문에 CPU는 RAM을 전혀 접근하지 못한다. 개별 “주소 권한”이 아닌 “버스 소유권”의 문제다. 이 때문에 짝수 클럭마다 한 워드만 빼앗고 바로 돌려주는 Cycle Stealing 모드가 등장했다

동작 흐름 더 자세히

DMA

1 단계 - CPU까 준비만 하고 손을 뗀다

  1. 전송 파라미터 설정

    • SRC, DST, LEN, MODE을 레지스터에 값을 써 넣습니다

    • 마지막으로 Enable 플래그를 1로 두면 DMAC가 “이제 내가 처리할게!”하고 대기

  2. 버스 요청(BR 신호)

    • DMAC는 버스 중재기(arbiter)에게 “버스 좀 빌려주세요” 라고 손을 듦

2 단계 - 버스 소유권 교환

  1. CPU → DMAC ‘Bus Grant(BG)’

    • CPU가 진행 중인 버스 싸이클을 마치면 주소·데이터 라인을 tristate해 두고 계산 같은 비-버스 작업에 집중함

      • tristate란, 여러개의 마스터(CPU, DMAC, GPU…)가 하나의 전선을 공유하고, 한 쪽이 0V, 다른쪽이 동시에 Vcc를 내보내면 단락(short) 위험을 방지하고자 버스를 넘겨받은 쪽만 드라이버를 켜고 나머지는 Hi-Z로 물러나야 함

      • 버스가 필요 없는 작업이란, 파이프라인이 레지스터와 내부 캐시 만으로 실행 가능한 명령들

  2. DMAC가 버스 장악

    • 이 순간부터 RAM과 I/O 장치 사이를 오가는 모든 신호는 DMAC가 생성

    • CPU는 RAM을 못 만지기 때문에 캐시 miss가 나도 대기해야 함

3 단계 - 실제 데이터 이동

  1. 전송 모드에 따른 사이클

    • Burst/Block : LEN만큼 연속으로 → 최고속, 대신 CPU 길게 정지

    • Cycle-Stealing : 한 사이클씩 “훔치고” 바로 돌려줌 → 실시간 오디어/비디오

    • Scatter-Gather : 메모리 리스트 따라 다중 블록 자동 전송 → NVMe·NIC

  2. 주소·카운터 자동 증가

    • DMAC 내부 카운터가 0이 될 때까지 SRC++, DST++, LEN–

4 단계 - 전송 완료 알림

  1. DMA 완료 인터럽트

    • LEN==0 → DMAC가 IRQ를 날리고 버스 요청을 내림

    • CPU는 인터럽트 핸들러에서 데이터 후처리(예: 패킷 파싱, 디스크 블록 체크섬) 수행

  2. 버스 복귀

    • Arbiter가 다시 CPU에 ‘Bus Grant’ → 평상시 메모리 접근 재개

전송 모드

모드특징사용 예시
Single-word/Cycle-Stealing버스 싸이클 1 개만 “훔친” 뒤 즉시 CPU에 반환 → CPU 지연 최소실시간 오디오, 비디오 스트림
Block/Burst전체 블록(혹은 버스트) 한 번에 전송 → 가장 빠르지만 CPU 길게 정지SATA, SDIO, 대부분의 PCIe 장치
Demand/Scatter-Gather장치가 필요할 때마다, 혹은 메모리 리스트 기반 다중 블록 이동고성능 NIC, NVMe SSD, GPU VRAM 업로드

현대 시스템에서의 DMA 변화

  1. PCIe Bus mastering - 주변장치가 메인 메모리를 완전히 “빌려” 직접 읽고/쓴다

  2. IOMMU(DMA-Remapping) - 가상화·보안 목적. 장치가 접근 가능한 주소를 OS가 테이블로 전환 → 버퍼 오염·DMA 공격 방어

  3. Cache coherency 문제 - CPU 캐시에 남은 더러운(line dirty) 데이터 vs DMA가 본 메모리 불일치. 해결 : dma_sync_*() - (Linux)·Cache flush, non-cacheable region, snoopint 버스.

  4. Zero-copy - 네트워크 스택이나 GPU ↔ CPU 사이에서 “복사 없는” 파이프라인 구축 (DPDK, RDMA, CUDA cudaMemcpyAsync 등)

    • 운영체제 버퍼를 추가로 “복사(copy)”하지 않고, 장치 ↔ 응용이 같은 메모리 페이지를 공유하도록 하는 기법. CPU가 불필요한 memcpy()를 안 하므로 지연과 캐시오염↓
  5. RDMA(Remode DMA) - NIC가 원격 호스트의 메모리에까지 DMA 쓰기/읽기를 수행. 커널 네트워크 스택을 우회하여 μs 단위 지연시간을 제공한다. 고속 HPC, 데이터베이스 복제에서 필수

장점과 단점 요약

장점

- CPU 사용률 감소, 전력 효율 ↑

- 대역폭 활용 극대화(PCIe Gen4 x4 ≈ 8 GB/s 급)

- 실시간 스트리밍 지원(오디오 스터터링 방지 등)

단점

- 하드웨어·드라이버 복잡도 증가

- 버스 우선순위 조정 실패 시 CPU 지연 가능

- 캐시 일관성, 보안("DMA 공격") 이슈 처리 필요

    - IOMMU로 보완

실무 예시

장치DMA 활용
SSD/NVMe플래시 컨트롤러가 OS 버퍼를 읽어 와 NAND로 쓰기, 반대 방향 읽기
10 GbE NIC패킷을 커널 버퍼나 XSP ring으로 직접 놓고, 완료 시 인터럽트
GPU대용량 텍스처/버퍼를 PCIe로 복사하거나, VRAM↔CPU RAM pinned transfer
Audio CodecPCM 버퍼를 주기적으로 DMA → DAC, 실시간 재생
USB 컨트롤러호스트 메모리의 전송 링(Transfer Ring)을 DMA 로 순회

운영체제 관점

  • Linux : dma_map_single(), dma_alloc_coherent(), struct dma_async_tx_descriptor, DMAengine 프레임워크

  • Windows : WdfDmaTransaction*, KeFlushIoBuffers(), Scatter/Gather 목록 지원

  • RTOS(FreeRTOS, Zephyr) : MCU마다 별도의 DMAMUX & HAP API 제공


© 2022 JeongHwan Yun.