리눅스 드라이버의 물리주소와 가상 주소

출처: http://chammoru.egloos.com/v/4168312

다른 프로세스의 메모리 공간 접근
프로세스가 시스템 호출을 통해 커널 모드로 진입하면 프로세스 메모리 공간은 커널의 메모리 공간으로 바뀐다. 커널 모드 상태의 프로세스는 수퍼바이저 권한을 갖기 때문에 시스템 내의 모든 메모리 공간에 접근할 수 있다. 그래서 이 경우에는 다른 프로세스의 메모리 공간에 접근할 수 있는데, 이때 직접 접근은 안 되고, VM에서 제공하는 특정 함수를 통해 접근할 수 있다.

리눅스 메모리 관리
. PGD (Page Directory) : pgt_t
. PMD (Page Mid level Directory) : pmd_t
. PTE (Page Table Entry) : pte_t
* 참고 : PMD는 대부분의 리눅스 시스템에 형식적으로만 존재.

물리 주소 공간을 커널 주소 공간으로 매핑
Memory Mapped I/O 방식의 물리적 주소 공간을 커널에서 사용 가능한 가상 주소로 매핑하거나 해제할 때는 다음과 같은 함수 사용한다.

// 아래 두 함수가 성공적으로 mapping되면 가상 주소의 선두 주소가 반환
void * ioremap(unsigned long offset, unsigned long size); // offset이 물리주소, size는 PAGE_SIZE의 배수
void * ioremap_nocache(unsigned long offset, unsigned long size); // offset이 물리주소, size는 PAGE_SIZE의 배수
void iounmap(void * addr); // addr은 가상주소

I/O 물리 주소와 가상 주소간의 변환 함수
리눅스 커널은 부팅 단계에서 시스템을 제어하기 위해 사용하는 시스템의 모든 I/O 제어 물리 주소나 램 영역의 물리 주소를 MMU 테이블로 미리 작성한다. 이렇게 부팅 단계에서 고정되어 할당된 메모리 주소 영역을 예약 영역(reserved area)이라고 한다. 예약된 물리 주소 영역은 PAGE_OFFSET 매크로 상수값을 이용해 물리 주소와 가상 주소간에 변환을 한다. 상수 연산만으로 물리 주소를 가상 주소로 만들기 위해 사용하는 상수와 매크로는 #include 에 정의된다.

부팅 시 예약된 주소 공간 이외에 ioremap(), kmalloc() 함수에서 반환하는 가상 주소도 PAGE_OFFSET을 이용해 물리 주소와 가상 주소로 변한된다. 이 매크로 상수를 이용하여 주소 변환을 하는 함수들은 다음과 같다.

unsigned long virt_to_phys(volatile void * address);
void * phys_to_virt(unsigned long address);
unsigned long virt_to_bus(volatile void * address);
void * bus_to_virt(unsigned long address);

virt_to_phys(), phys_to_virt()
virt_to_phys() 함수는 가상 주소를 물리 주소로 바꾸고, phys_to_virt() 함수는 물리 주소를 가상 주소로 바꾼다. 그러나 phys_to_virt() 함수는 ioremap()함수와 같은 기능을 수행하지 않는다. ioremap()함수는 요구된 물리 주소로 시작하는 영역을 커널 모드에서 사용할 수 있도록 가상 주소 공간으로 등록하지만, phys_to_virt()함수는 PAGE_OFFSET과 같은 값을 이용하여 변환 처리만 하기 때문이다. 그래서 virt_to_phys()와 phys_to_virt()함수는 커널에서 사용할 수 있도록 등록된 가상 주소와 물리 주소에 대해 사용해야 한다.

virt_to_phys(), phys_to_virt()
virt_to_phys()와 virt_to_bus() 함수는 대부분의 커널이 동작하는 시스템에 대해 동일한 기능을 수행한다. phys_to_virt()와 bus_to_virt()함수 역시 같은 기능을 수행한다. 그러나 시스템에 따라 두 함수를 구별하여 사용하는 경우는 극히 드물지만 존재한다. 그래서 리눅스에서는 이 두 종류의 함수를 구별하여 사용해야 한다. DMA와 관련된 루틴에서는 virt_to_bus()와 bus_to_virt()함수를 사용하기를 권장하고, 램이나 비디오와 같은 메모리 관련 주소 공간에는 virt_to_phys()와 phys_to_virt() 함수를 사용하기를 권장한다. 가급적 이 규칙을 지켜야 여러 시스템과 호환되는 디바이스 드라이버로 포팅할 수 있다.

이 글은 카테고리: Linux, Programming에 포함되어 있으며 태그: , , , , , , , , , (이)가 사용되었습니다. 고유주소를 북마크하세요.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다


This site uses Akismet to reduce spam. Learn how your comment data is processed.