Colors of Ray+Hue'

Memory Mapping

Linux Kernel2016. 7. 28. 09:04

Memory Mapping



(원소스: 리눅스 디바이스드라이버, 유영창 저)


  • MMU에는 MMU 테이블을 유지하기위한 별도의 관리 메모리가 없다. MMU는 보통 프로세서에 내장되고, 시스템 메모리를 같이 사용한다. 그래서 프로세서가 처음 부팅되면 리눅스는 시스템 메모리의 일부를 MMU 테이블에 할당하고, 관리할 정보를 MMU 테이블에 기록한다. 이 과정에서는 MMU가 동작하지 않는다. 리눅스 커널은 MMU 테이블에 관련된 정보를 메모리에 모두 기록한 후에 MMU 테이블에 해당하는 메모리 위치를 MMU에 알려주고 MMU를 동작시킨다.
  • 메모리맵I/O 방식: 

    char *videoptr;

    videoptr = (char *) 0x000B0000;

    *videoptr = 'A';

  • 메모리 접근 명령으로 처리하는 것을 Memory Mapped I/O라 한다. 하지만, MMU가 활성화되어 동작하는 커널 모드에서는 위의 예처럼 비디오의 물리주소 0x000B0000에 접근하면 페이지폴트가 발생하여 처리되지 않는다. 따라서, 디바이스드라이버는 하드웨어를 제어하기위해 물리주소가상주소로 매핑 (MMU 가 사용되지 않는 메모리 영역의 operation에 대해서는 PA 가 사용될 수 있음, i.e. DMA)해야 한다. 메모리맵 I/O 방식의 물리적 주소공간을 커널에서 사용 가능한 주소로 매핑하거나 매핑된 영역을 해제할 때는 ioremap(), ioremap_nocache(), iounmap() 함수를 사용해야 한다.
  • kmalloc: VA physically contiguous
  • vmalloc: VA physically in-contiguous
  • kzalloc: VA physically contiguous, kalloc initialized zero - use it to expose mem to user space
  • 응용 프로그램에서는 디바이스 파일로 하드웨어를 제어하기 위해 보통 read(), write(), ioctl() 함수를 사용한다. 이 함수들은 응용 프로그램에 하드웨어의 내부구조를 숨겨주는 효과가 있다. 그러나 이런 함수들은 프로세스 메모리공간과 커널메모리 공간사이의 메모리 전달 과정이 수반되기 때문에 매우 비효율적이다. 특히나 많은 용량의 데이터가 빠르게 전달되어야 하는 사운드나 비디오 장치에 메모리 복사가 수반되는 read(), write(), ioctl() 함수를 사용한다면 시스템 성능이 저하된다. (put_user(), copy_to_user(), get_user(), copy_from_user())
  • 이렇게 비효율적인 방법을 극복하기위해 리눅스에서는 mmap() 함수를 제공하여 응용 프로그램에서 직접 하드웨어의 I/O 주소공간을 메모리 복사없이 직접적으로 사용할 수 있도록 한다. mmap() 함수는 원래 메모리 주소를 이용해 파일에 접근할 수 있도록 하는 함수다. 그러나 디바이스 파일에 적용할 경우에는 디바이스에서 제공하는 물리주소 (I/O 메모리 주소 또는 할당된 메모리 공간주소)를 응용 프로그램에서 사용할 수 있게한다. 응용 프로그램이 동작하는 프로세스의 메모리 영역에 디바이스 드라이버가 제공하는 물리주소를 매핑하면 된다.
  • 동일한 물리주소를 가상주소로 매핑하는 방법에는 두가지가 있다. 하나는 mmap() 함수를 사용하여 응용프로그램의 프로세스 가상주소에 매핑하는 방법이고, 하나는 ioremap() 함수를 사용하여 커널의 가상주소에 매핑하는 방법이다.
  • nopage 매핑방식: 디바이스 드라이버에서 mmap을 처리하는 방식은 mmap() 함수에서remap_pfn_range() 함수를 이용하여 필요한 매핑을 직접처리하는 방법과 nopage 방식을 사용해 페이지 단위로 매핑하는 방법이 있다. 앞에서 설명한 방법이 remap_pfn_range() 함수를 이용해 매핑 대상이 되는 영역을 한꺼번에 매핑하는 방법이었다면, nopage 방법은 PAGE_SIZE 단위로 매핑을 처리한다. nopage 방식은 응용 프로그램에서 mmap() 함수를 호출하여 프로세스에서 사용할 수 있는 주소를 먼저 요구한다. nopage 방식은remap_pfn_range() 함수를 이용하는 방법처럼 응용 프로그램 mmap() 함수를 호출하면 디바이스 드라이버의 파일 오퍼레이션 구조체에 정의된 mmap() 함수가 호출된다. 그러나 핲서 설명한 mmap() 함수가 요청된 영역의 매핑을 remap_pfn_range() 함수를 이용해 처리하는 것과 달리 nopage 방식에서는 mmap() 함수가 remap_page_range() 함수를 수행하지 않는다. 그래서 커널이 해당 영역을 매핑하지 않기 때문에 응용 프로그램이 mmap()을 통해 주소에 접근하면 해당 메모리 주소를 유효하지 않은 영역으로 인식하여 페이지폴트가 발생한다. 커널은 페이지 폴트가 발생하면 디바이스 드라이버로 매핑하기 위해 해당 주소공간이 예약된 주소 영역인지를 확인하고, 예약된 영역이면 vma->vm_ops->nopage에 선언된 함수를 호출한다.  nopage 방식은 물리적인 I/O 메모리공간을 응용 프로그램의 프로세스 공간에 사용하기 보다는 주로 디바이스 드라이버에 의해 할당된 메모리 공간을 공유하기 위해 사용한다. nopage 방식으로 mmap을 구현하려면 디바이스 드라이버는 가장 먼저 페이지 폴트가 발생할 때 호출된 nopage() 함수를 만들어야 한다.


  • Linear MMAP

    1. 매핑할 파일에 대해 mmap file operation이 정의 되어 있는지 검사

    2. 파일 객체의 get_unmapped_area method 호출하여 메모리 매핑에 적합한 linear address range 를 할당

    3. 파일 시스템에서 vm_file field를 파일 객체의 주소로 초기화 하고 mmap method 호출 (generic_file_mmap)

    4. Done, 기타 자잘한 검사들은 생략

    매핑은 형성 되었지만, 그에 해당하는 PFN은 아직 할당 되지 않았기 때문에 demand paging을 해야한다. 이때 프로세스가 페이지 중 하나를 참조하여 page fault exception이 발생할 때까지 PFN할당을 늦춘다.커널은 폴트가 발생한 주소에 대응하는 페이지 테이블 엔트리를 검사하고, 엔트리가 없으면 do_no_page 함수를 호출한다. 

    do_no_page 함수는 페이지 프레임 할당과 페이지 테이블 갱신과 같이 모든 요구 페이징에 공통적인 연산을 수행한다. 또한 해당 memory region 에 nopage method를 정의하고 있는지 검사한다. nopage method 가 정의 되어 있을 경우, 

    1. nopage 메소드 호출하는데 요청한 페이지를 포함하는 PFN을 반환한다. 

    2.메모리 매핑이 private 이고, 프로세스가 페이지에 쓰기를 시도하면, 방금 읽은 페이지의 복사본을 만들고 이것을 inactive page list 에 삽입하여 'COW' fault가 발생하지 않도록 한다.

    3. fault가 발생한 주소에 대응하는 페이지 테이블 엔트리를 PFN과 memory region의 vm_page_prot  field에 포함된 페이지 접근 권한으로 설정한다. 

    4. ...


    nopage Method

    결국 매핑의 실제 동작의 키는 nopage method이며 nopage는 반드시 PFN을 반환해야 한다. nopage 는 요청한 페이지가 페이지 캐시에 있는지를 찾는다. 페이지를 찾지 못하면 method는 페이지를 디스크에서 읽어야 한다. 대부분의 파일 시스템은 filemap_nopage 함수를 사용하여 nopage method를 구현한다. 이 함수는 다음과 같은 새개의 매개 변수를 받는다. 

    (area,address,type) 

    ..........................

    나중에 채워 너을 거임.

    결국 nopage method는 페이지 캐시에 해당 파일의 블록이 있는지를 검사해서 없다면 페이지 캐시에 새로운 프레임을 할당, 블록을 읽어 들인다. 이후 해당 page cache 의 PFN 를 리턴한다. 


출처

http://linuxphil.blogspot.com/2011/12/blog-post.html

Understanding the Linux Kernel, 3rd Edition