Linux 메모리 맵(mmap)

본문 편집http://www.2cto.com/os/201204/129464.html
http://hi.baidu.com/yoursguang/blog/item/81f77f387720022296ddd814.html
http://mikeconan6.blog.163.com/blog/static/129723052200991811411776/?fromdm&isFromSearchEngine=yes
개술
          메모리 맵 은 쉽게 말 하면 사용자 공간의 메모리 영역 을 커 널 공간 에 투사 하 는 것 입 니 다.맵 이 성공 한 후에 사용자 가 이 메모리 영역 에 대한 수정 은 커 널 공간 에 직접 반영 할 수 있 습 니 다.마찬가지 로 커 널 공간 이 이 지역 에 대한 수정 도 사용자 공간 을 직접 반영 합 니 다.그러면 커 널 공간<->사용자 공간 둘 사이 에 대량의 데이터 전송 등 작업 이 필요 하 다 면 효율 이 매우 높다.
다음은 일반적인 파일 을 사용자 공간 에 비 추 는 메모리 영역 설명도 입 니 다.
그림 1:
 
기본 함수
   
 mmap 함 수 는 유 닉 스/linux 에서 시스템 호출 입 니 다.자세 한 내용 은<유 닉 스 Netword programming>권 2 12.2 절 을 참고 하 십시오.
mmap 시스템 호출 은 메모리 공 유 를 위 한 것 이 아 닙 니 다.프로 세 스 는 일반 파일 에 대한 접근 방식 과 달리 읽 기와 쓰기 메모리 처럼 일반 파일 을 조작 할 수 있 습 니 다.Posix 나 시스템 V 의 공유 메모리 IPC 는 순 전 히 공유 목적 에 사용 된다.물론
mmap()가 공유 메모 리 를 실현 하 는 것 도 주요 응용 중의 하나 이다.
          
mmap 시스템 호출 은 프로 세 스 간 에 같은 일반 파일 을 매 핑 하여 공유 메모 리 를 실현 합 니 다.일반 파일 이 프로 세 스 주소 공간 에 비 친 후 프로 세 스 는 일반 메모리 에 접근 하 는 것 처럼 파일 에 접근 할 수 있 습 니 다.read(),write()등 을 호출 하지 않 아 도 됩 니 다.mmap 는 공간 을 할당 하지 않 고 호출 프로 세 스 의 주소 공간 에 파일 을 표시 합 니 다.(그러나 virutal memory 를 차지 합 니 다)그리고 memcpy 등 으로 파일 을 쓸 수 있 습 니 다.write()를 사용 하지 않 아 도 됩 니 다.다 쓴 후에 메모리 의 내용 은 파일 에 바로 업데이트 되 지 않 고 일정 시간 지연 되 어 호출 할 수 있 습 니 다.
msync()는 당신 이 쓴 내용 을 즉시 파일 에 저장 할 수 있 도록 명시 적 으로 동기 화 합 니 다.
이 점 은 구동 과 관련 이 있 을 것 이다.통과
mmap 에서 파일 을 쓰 는 방식 은 파일 의 길 이 를 늘 릴 수 없습니다.매 핑 할 길이 가 호출 되 고 있 기 때 문 입 니 다.
mmap()에서 결 정 했 습 니 다.메모리 맵 을 취소 하려 면 호출 할 수 있 습 니 다.
메모리 맵 취소
void * 
mmap
(void *
start,
 size_t 
length
, int 
prot
 , int 
flags
, int
 fd
, off_t 
offset
)
mmap 는 파일 을 메모리 공간 에 비 추 는 데 사 용 됩 니 다.쉽게 말 하면
mmap
파일 의 내용 을 메모리 에 이미지 로 만 듭 니 다.맵 이 성공 한 후에 사용자 가 이 메모리 구역 에 대한 수정 은 커 널 공간 에 직접 반영 할 수 있 습 니 다.마찬가지 로 커 널 공간 이 이 구역 에 대한 수정 도 사용자 공간 을 직접 반영 합 니 다.그러면 커 널 공간<->사용자 공간 둘 사이 에 대량의 데이터 전송 등 작업 이 필요 하 다 면 효율 이 매우 높다.
start:매 핑 할 메모리 영역의 시작 주 소 는 보통 사용 합 니 다.
NULL(
NULL
0)。
NULL 은 메모리 주 소 를 커 널 에서 지정 합 니 다.
length:매 핑 할 메모리 영역의 크기
prot:원 하 는 메모리 보호 표지 입 니 다.파일 의 열기 모드 와 충돌 할 수 없습니다.아래 의 어떤 값 으로 or 연산 을 통 해 합 리 적 으로 조합 할 수 있 습 니 다.
PROT_EXEC
 //페이지 내용 이 실 행 될 수 있 습 니 다.
PROT_READ  
//페이지 내용 을 읽 을 수 있 습 니 다.
PROT_WRITE 
//페이지 를 쓸 수 있 습 니 다.
PROT_NONE 
 //페이지 접근 불가
flags:맵 대상 의 종 류 를 지정 합 니 다.맵 옵션 과 맵 페이지 를 공유 할 수 있 습 니까?그것 의 값 은 하나 이상 의 하위 조합 체 일 수 있다.
MAP_FIXED:지정 한 맵 시작 주 소 를 사용 합 니 다.start 와 len 매개 변수 가 지정 한 메모리 영역 이 기 존 맵 공간 에 겹 치면 겹 치 는 부분 이 버 려 집 니 다.지정 한 시작 주 소 를 사용 할 수 없 으 면 작업 이 실 패 됩 니 다.그리고 시작 주 소 는 페이지 의 경계 에 있어 야 합 니 다.
MAP_SHARED:맵 영역 에 대한 기록 데 이 터 는 파일 로 복사 되 며,이 파일 을 비 추 는 다른 프로 세 스 가 공유 할 수 있 습 니 다.
MAP_PRIVATE:기록 할 때 복사 하 는 개인 맵 을 만 듭 니 다.메모리 영역의 기록 은 원본 파일 에 영향 을 주지 않 습 니 다.이 표지 와 상기 표 지 는 서로 배척 하 는 것 으로 그 중의 하나 만 사용 할 수 있다.
MAP_DENYWRITE:이 표 지 는 무시 되 었 습 니 다.
MAP_EXECUTABLE:동상
MAP_NORESERVE:이 맵 을 위해 교환 공간 을 유지 하지 마 세 요.교환 공간 이 유지 되면 맵 영역 수정 이 보 장 될 수 있 습 니 다.교환 공간 이 보존 되 지 않 고 메모리 가 부족 할 때 맵 영역 에 대한 수정 은 세그먼트 위반 신 호 를 일 으 킬 수 있 습 니 다.
MAP_LOCKED:맵 영역의 페이지 를 잠 그 고 페이지 가 메모리 로 교환 되 는 것 을 방지 합 니 다.
MAP_GROWSDOWN:스 택 에 사용 되 며 커 널 VM 시스템 에 맵 영역 을 아래로 확장 할 수 있 음 을 알려 줍 니 다.
MAP_ANONYMOUS :익명 맵,맵 영역 은 파일 과 연결 되 지 않 습 니 다.
MAP_ANON :MAP_애 니 마우스 의 별칭 은 더 이상 사용 되 지 않 는 다.
MAP_FILE :호 환 표지,무시.
MAP_32BIT:프로 세 스 주소 공간의 낮은 2GB,맵FIXED 지정 시 무시 합 니 다.현재 이 표 지 는 x86-64 플랫폼 에서 만 지 원 됩 니 다.
MAP_POPULATE :파일 맵 을 위해 미리 읽 는 방식 으로 페이지 표를 준비 합 니 다.이후 맵 영역 에 대한 접근 은 페이지 위반 으로 막 히 지 않 습 니 다.
MAP_NONBLOCK:MAPPOPULATE 를 함께 사용 할 때 만 의미 가 있 습 니 다.미리 읽 기 를 실행 하지 않 고 메모리 에 존재 하 는 페이지 에 만 페이지 입 구 를 만 듭 니 다.
fd:파일 설명자(open 함수 에서 되 돌아 오기)
offset:비 치 는 대상(즉 파일)이 거기서 부터 비 치 는 것 을 표시 합 니 다.보통 0 을 사용 합 니 다.이 값 은 크기 가 PAGE 여야 합 니 다.SIZE 의 정수 배
설명  
성공 적 으로 실 행 될 때,mmap()는 매 핑 된 영역의 바늘 을 되 돌려 주 고,munmap()는 0 을 되 돌려 줍 니 다.실패 시 mmap()를 MAP 로 되 돌려 줍 니 다.FAILED[그 값 은(void*)-1],munmap 반환-1 입 니 다.errno 는 다음 값 으로 설정 되 어 있 습 니 다.  
EACCES:접근 오류
EAGAIN:파일 이 잠 겨 있 거나 너무 많은 메모리 가 잠 겨 있 습 니 다.
EBADF:fd 는 올 바른 파일 설명 어가 아 닙 니 다.
EINVAL:하나 이상 의 인자 가 잘못 되 었 습 니 다.
ENFILE:파일 열기 에 대한 시스템 제한 에 도 달 했 습 니 다.
ENODEV:파일 이 있 는 파일 시스템 은 메모리 맵 을 지원 하지 않 습 니 다.
ENOMEM:메모리 가 부족 하거나 프로 세 스 가 최대 메모리 맵 수 를 초과 하 였 습 니 다.
EPERM:권한 부족,조작 불가
ETXTBSY:이미 작 성 된 방식 으로 파일 을 열 고 MAP 를 지정 합 니 다.DENYWRITE 로고
SIGSEGV:읽 기 전용 영역 에 쓰기
SIGBUS:프로 세 스 에 속 하지 않 는 메모리 에 접근 해 보십시오
int 
munmap
(void *
start,
 size_t 
length)
start:매 핑 된 메모리 영역의 시작 주 소 를 취소 합 니 다.
length:맵 의 메모리 영역 크기 를 취소 합 니 다.
설명  
성공 적 으로 실행 되 었 을 때 munmap()는 0 을 되 돌려 줍 니 다.실패 시 munmap 반환-1
int 
msync
(const void *start, size_t length, int flags); 
맵 메모리 의 내용 변경 은 파일 에 바로 업데이트 되 지 않 고 일정 시간 지연 되 어 호출 할 수 있 습 니 다.
msync()메모리 업데이트 가 파일 에 바로 저 장 될 수 있 도록 디 스 플레이 동기 화 합 니 다.
start:동기 화 할 메모리 영역의 시작 주소 입 니 다.
length:동기 화 할 메모리 영역의 크기
flag:flags 는 다음 세 가지 값 중 하나 일 수 있 습 니 다. 
MS_ASYNC:Kernel 에서 자 료 를 빨리 기록 해 주세요. 
MS_SYNC:msync 가 끝나 고 돌아 오기 전에 자 료 를 기록 합 니 다. 
MS_INVALIDATE:핵심 이 쓰기 여 부 를 스스로 결정 하고 특수 한 상황 에서 만 사용 하도록 합 니 다.
3.사용자 공간 과 드라이버 의 메모리 맵
3.1 기본 과정
  우선,드라이버 는 먼저 메모리 한 토막 을 분배 하고,이어서 사용자 프로 세 스 는 라 이브 러 리 함 수 를 통과 한다
mmap()
커 널 이 커 널 공간 에 얼마나 큰 메모 리 를 비 추 는 지 알려 줍 니 다.커 널 은 일련의 함수 호출 을 거 쳐 해당 하 는 드라이버 를 호출 합 니 다.
file_operation
지정
mmap
함수
remap_pfn_range()
맵 관 계 를 맺 습 니 다.
3.2 매 핑 의 실현
 먼저 드라이버 에 한 페이지 크기 의 메모 리 를 할당 한 다음,사용자 프로 세 스 는 mmap()를 통 해 사용자 공간의 크기 도 한 페이지 의 메모리 로 커 널 공간 이라는 메모리 에 표시 합 니 다.맵 이 완료 되면 드라이버 는 이 메모리 에 10 개의 바이트 데 이 터 를 쓰 고 사용자 프로 세 스 는 이 데 이 터 를 표시 합 니 다.
드라이버:

  1 #include <linux/miscdevice.h>
  2 #include <linux/delay.h>
  3 #include <linux/kernel.h>
  4 #include <linux/module.h>
  5 #include <linux/init.h>
  6 #include <linux/mm.h>
  7 #include <linux/fs.h>
  8 #include <linux/types.h>
  9 #include <linux/delay.h>
10 #include <linux/moduleparam.h>
11 #include <linux/slab.h>
12 #include <linux/errno.h>
13 #include <linux/ioctl.h>
14 #include <linux/cdev.h>
15 #include <linux/string.h>
16 #include <linux/list.h>
17 #include <linux/pci.h>
18 #include <linux/gpio.h>
19  
20  
21 #define DEVICE_NAME "mymap"
22  
23  
24 static unsigned char array [ 10 ]={ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 };
25 static unsigned char * buffer ;
26  
27  
28 static int my_open ( struct inode * inode , struct file * file )
29 {
30     return 0 ;
31 }
32  
33  
34 static int my_map ( struct file * filp , struct vm_area_struct * vma )
35 {    
36     unsigned long page ;
37     unsigned char i ;
38     unsigned long start = ( unsigned long ) vma -> vm_start ;
39     //unsigned long end =  (unsigned long)vma->vm_end;
40     unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start);
41 
42     //
43     page = virt_to_phys(buffer);    
44     // vma page
45     if(remap_pfn_range(vma,start,page>>PAGE_SHIFT,size,PAGE_SHARED))// , PAGE_SHIFT
46         return -1; 
47 
48     // 10
49     for(i=0;i<10;i++)
50         buffer[i] = array[i];
51     
52     return 0;
53 }
54 
55 
56 static struct file_operations dev_fops = {
57     .owner    = THIS_MODULE,
58     .open    = my_open,
59     .mmap   = my_map,
60 };
61 
62 static struct miscdevice misc = {
63     .minor = MISC_DYNAMIC_MINOR,
64     .name = DEVICE_NAME,
65     .fops = &dev_fops,
66 };
67 
68 
69 static int __init dev_init(void)
70 {
71     int ret;    
72 
73     //
74     ret = misc_register(&misc);
75     //
76     buffer = (unsigned char *)kmalloc(PAGE_SIZE,GFP_KERNEL);
77     //
78     SetPageReserved(virt_to_page(buffer));
79 
80     return ret;
81 }
82 
83 
84 static void __exit dev_exit(void)
85 {
86     //
87     misc_deregister(&misc);
88     //
89     ClearPageReserved(virt_to_page(buffer));
90     //
91     kfree(buffer);
92 }
93 
94 
95 module_init(dev_init);
96 module_exit(dev_exit);
97 MODULE_LICENSE("GPL");
98 MODULE_AUTHOR("LKN@SCUT");
 

응용 프로그램: 
 

1 #include <unistd.h>  
2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <fcntl.h>
  6 #include <linux/fb.h>
  7 #include <sys/mman.h>
  8 #include <sys/ioctl.h>  
  9    
10 #define PAGE_SIZE 4096
11  
12  
13 int main ( int argc , char * argv [])
14 {
15     int fd ;
16     int i ;
17     unsigned char * p_map ;
18     
19     //
20     fd = open("/dev/mymap",O_RDWR);
21     if(fd < 0)
22     {
23         printf("open fail
");
24         exit(1);
25     }
26 
27     //
28     p_map = (unsigned char *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
29     if(p_map == MAP_FAILED)
30     {
31         printf("mmap fail
");
32         goto here;
33     }  
34 
35     // 10
36     for(i=0;i<10;i++)
37         printf("%d
",p_map[i]);
38     
39 
40 here:
41     munmap(p_map, PAGE_SIZE);
42     return 0;
43 }
 

먼저 드라이버 를 불 러 온 후 프로그램 을 실행 합 니 다.사용자 공간 인쇄 는 다음 과 같 습 니 다.
0
1
2
3
4
5
6
7
8
9
끝나다

좋은 웹페이지 즐겨찾기