운영체제 기본/Linux/메모리 매핑/MMIO 장치 매핑: 두 판 사이의 차이
mmap 유형별 동작과 Linux v6.12 구현 설명 |
Linux 계층형 경로에 맞춰 문서 링크 갱신 |
||
| (같은 사용자의 중간 판 하나는 보이지 않습니다) | |||
| 1번째 줄: | 1번째 줄: | ||
{{이전 다음 문서 | {{이전 다음 문서 | ||
|이전=← 이전 문서<br>[[운영체제 기본/ | |이전=← 이전 문서<br>[[운영체제 기본/Linux/메모리 매핑/파일 매핑과 COW|파일 매핑과 COW]] | ||
|목차=[[운영체제 기본/ | |목차=[[운영체제 기본/Linux/메모리 매핑|메모리 매핑 목차]] | ||
|다음=마지막 문서 | |다음=마지막 문서 | ||
}} | }} | ||
| 75번째 줄: | 75번째 줄: | ||
{{이전 다음 문서 | {{이전 다음 문서 | ||
|이전=← 이전 문서<br>[[운영체제 기본/ | |이전=← 이전 문서<br>[[운영체제 기본/Linux/메모리 매핑/파일 매핑과 COW|파일 매핑과 COW]] | ||
|목차=[[운영체제 기본/ | |목차=[[운영체제 기본/Linux/메모리 매핑|메모리 매핑 목차]] | ||
|다음=마지막 문서 | |다음=마지막 문서 | ||
}} | }} | ||
{{운영체제 기본 둘러보기}} | {{운영체제 기본 둘러보기}} | ||
2026년 11월 1일 (일) 02:23 기준 최신판
메모리 매핑 입출력(Memory-Mapped I/O, MMIO)은 CPU의 주소 공간에 장치 레지스터나 장치 메모리를 배치하고 load/store로 접근하는 방식이다. 장치 드라이버는 허용한 MMIO 구간을 사용자 프로세스에 mmap()으로 공개할 수 있다. 이때 주소 변환은 페이지 테이블을 사용하지만, 변환된 주소의 대상은 일반적인 파일의 페이지 캐시나 새 익명 RAM이 아니다.
Linux v6.12의 UIO(Userspace I/O)에서 UIO_MEM_PHYS로 MMIO 자원을 공개하는 기본 경로를 예로 든다. 여기서는 MAP_SHARED로 장치 자원을 직접 접근하는 경우를 다룬다. 장치 파일의 매핑은 드라이버마다 다르며, 모든 /dev 파일의 매핑이 MMIO인 것은 아니다.
사용자 주소와 장치 주소
사용자 프로세스의 가상 주소 → 사용자 페이지 테이블 → 드라이버가 허용한 장치 물리 주소 → 버스와 장치의 레지스터 또는 메모리
CPU가 값을 읽거나 쓰는 형식은 메모리 접근이지만, 장치에서는 읽기가 상태를 지우거나 쓰기가 동작을 시작할 수도 있다. 따라서 RAM에 데이터를 저장하는 것처럼 무조건 복사하거나, 임의의 폭으로 접근할 수 없다. 장치가 정한 레지스터 폭·정렬·엔디언과 읽기·쓰기 순서를 따라야 한다. 기본 개념은 장치 제어와 입출력과 연결된다.
드라이버가 내부적으로 사용하는 ioremap()과도 구별한다. ioremap()은 커널에서 사용할 I/O 주소 매핑을 만드는 인터페이스이고, 여기서는 사용자 프로세스의 VMA와 페이지 테이블을 설정하는 mmap() 콜백을 다룬다.[1]
UIO의 매핑 선택과 범위 검사
UIO 장치는 /dev/uio0 같은 장치 파일을 제공한다. 한 장치에 여러 매핑 영역이 있으면, UIO의 mmap() 오프셋은 영역 번호 × 페이지 크기다. 예를 들어 영역 0은 오프셋 0, 영역 1은 오프셋 한 페이지를 사용한다. 이는 일반 파일의 바이트 오프셋을 그대로 장치의 물리 주소에 더하는 규약이 아니다.[2]
mmap(장치 fd, offset = map 번호 × PAGE_SIZE) → 공통 mmap 설정 → file->f_op->mmap = uio_mmap → vm_pgoff로 등록된 map 선택 → 영역 크기와 요청 범위 검사 → UIO_MEM_PHYS → uio_mmap_physical
uio_mmap()은 등록된 영역 번호가 유효한지와 요청한 페이지 수를 검사한다. 드라이버가 자체 info->mmap 콜백을 제공하면 그쪽으로 넘기고, 그렇지 않으면 등록된 메모리 유형에 따라 처리한다. 여기서 따라가는 기본 물리 매핑은 uio_mmap_physical()이다.[3]
이 함수는 물리 시작 주소의 페이지 정렬과 요청 길이를 다시 검사한다. 사용자 프로세스가 원하는 임의의 물리 주소를 넣어 매핑하는 것이 아니라, 커널 드라이버가 등록한 자원 안에서만 매핑을 구성한다. 장치 파일 접근 권한과 드라이버의 범위 검사가 사용자 프로세스에 공개되는 범위를 제한한다.[3]
PFN 매핑과 PTE 설치
물리 페이지 프레임 번호(PFN, Page Frame Number)는 물리 주소에서 페이지 내부 오프셋을 제외한 번호다. UIO 기본 물리 매핑은 등록된 물리 시작 주소를 PAGE_SHIFT만큼 이동해 시작 PFN을 구하고, remap_pfn_range()에 사용자 주소·크기·페이지 속성과 함께 넘긴다.
uio_mmap_physical → vm_page_prot = pgprot_noncached(vm_page_prot) → remap_pfn_range(vma, vm_start, 물리 시작 PFN, 길이, vm_page_prot) → 사용자 PTE를 장치 PFN에 연결
remap_pfn_range()의 내부 경로는 VMA에 VM_IO, VM_PFNMAP, VM_DONTEXPAND, VM_DONTDUMP를 설정하고 PFN을 가리키는 특수 PTE를 설치한다. 일반 RAM 페이지의 struct page를 페이지 캐시에서 가져오는 경로와 구분되며, 이 예에서는 매핑을 만드는 중에 PTE가 설치된다. 따라서 첫 load에서 반드시 파일 폴트를 일으켜 장치 내용을 읽어오는 구조가 아니다.[3][4]
일반 파일의 private COW처럼 장치 레지스터의 사본을 RAM에 만들어 쓰게 하면 장치에 명령이 전달되지 않는다. MMIO 매핑은 드라이버가 허용하는 공유 방식과 접근 규약에 맞춰 사용해야 한다. 파일 장에서 설명한 private 사본·page cache·writeback 모델을 MMIO에 그대로 적용하지 않는다.
아키텍처별 메모리 속성
MMIO의 페이지 테이블에는 읽기·쓰기 권한뿐 아니라 적절한 메모리 속성도 필요하다. 장치 레지스터를 일반 RAM처럼 캐시하면 실제 장치 접근과 다른 결과를 만들 수 있다. UIO의 기본 UIO_MEM_PHYS 경로는 pgprot_noncached()를 사용하지만, 이 함수의 하드웨어 표현은 아키텍처에 따라 다르다.
| 아키텍처 | Linux v6.12의 처리 |
|---|---|
| x86-64 | pgprot_noncached()가 UC-에 해당하는 캐시 속성을 적용한다. PFN 매핑 과정에서 기존 메모리 유형과의 호환성도 검토한다. |
| RISC-V RV64 | pgprot_noncached()가 I/O용 속성을 선택한다. Svpbmt를 사용하는 경우 PTE의 PBMT 필드로 I/O 유형을 표현하며, 실제 사용 가능한 표현은 CPU 확장과 플랫폼에 달려 있다. |
x86-64의 캐시 속성 비트를 RISC-V에 그대로 옮길 수 없으며, 모든 RV64 시스템에서 Svpbmt를 사용하는 것도 아니다. 공통 드라이버는 아키텍처 도우미를 호출하고, 하드웨어·플랫폼에 맞는 속성 처리는 그 아래에서 맡는다.[5][6][7]
캐시 속성만으로 장치 접근 순서와 완료 조건까지 모두 해결되지는 않는다. volatile도 컴파일러의 접근 처리에 관여할 뿐, 장치에 필요한 메모리 장벽이나 접근 완료 확인을 모두 대신하지 않는다. 실제 접근은 장치와 플랫폼의 사용자 공간 인터페이스가 정한 규칙을 따라야 한다.[1]
장치 매핑과 일반 메모리의 경계
UIO 자체도 메모리 유형을 나누어 처리한다. UIO_MEM_DMA_COHERENT는 dma_mmap_coherent()를 사용하고, RAM을 공개하는 유형에는 다른 처리 경로가 있다. 장치와 데이터를 주고받는 DMA 버퍼가 물리적으로 RAM에 있는 경우와, 장치 레지스터를 MMIO로 접근하는 경우를 구별해야 한다.[3]
어떤 드라이버는 접근 시 폴트 처리기에서 PFN을 넣기도 한다. 따라서 이 장의 매핑 시점 PTE 설치는 UIO 기본 물리 매핑의 구체적인 경로이며, 모든 장치 드라이버에 대한 규칙은 아니다. 공통점은 VMA가 장치 드라이버의 정책과 연결되고, 그 정책이 사용자 주소의 실제 대상을 정한다는 것이다.
참고 문헌
- ↑ 1.0 1.1 Linux Kernel Documentation, Bus-Independent Device Accesses, ioremap과 I/O 접근 규칙.
- ↑ Linux Kernel Documentation, The Userspace I/O HOWTO, UIO의 mmap과 map 영역 선택.
- ↑ 3.0 3.1 3.2 3.3 Linux v6.12, drivers/uio/uio.c, uio_mmap, uio_find_mem_index, uio_mmap_physical.
- ↑ Linux v6.12, mm/memory.c, remap_pfn_range, remap_pfn_range_internal, remap_pte_range.
- ↑ Linux v6.12, arch/x86/include/asm/pgtable.h, pgprot_noncached.
- ↑ Linux v6.12, arch/riscv/include/asm/pgtable.h, pgprot_noncached.
- ↑ Linux v6.12, arch/riscv/include/asm/pgtable-64.h, PBMT와 대안 선택.