목차
驱动层 " >驱动层
운영 및 유지보수 리눅스 운영 및 유지 관리 Linux 드라이버 IO 문서 - mmap 작업

Linux 드라이버 IO 문서 - mmap 작업

Jul 31, 2023 pm 03:55 PM
linux

머리말

보통 Linux 드라이버를 작성하고 사용자 공간과 상호작용할 때 copy_from_user사용자 공간에서 전달된 데이터를 복사합니다. 왜 이러나요? copy_from_user把用户空间传过来的数据进行拷贝,为什么要这么做呢?

因为用户空间是不能直接内核空间数据的,他们映射的是不同的地址空间,只能先将数据拷贝过来,然后再操作。

如果用户空间需要传几MB的数据给内核,那么原来的拷贝方式显然效率特别低,也不太现实,那怎么办呢?

想想,之所以要拷贝是因为用户空间不能直接访问内核空间,那如果可以直接访问内核空间的buffer,是不是就解决了。

简单来说,就是让一块物理内存拥有两份映射,即拥有两个虚拟地址,一个在内核空间,一个在用户空间。关系如下:

Linux 드라이버 IO 문서 - mmap 작업

通过mmap映射就可以实现。

应用层

应用层代码很简单,主要就是通过mmap系统调用进行映射,然后就可以对返回的地址进行操作。

char * buf;
/* 1. 打开文件 */
 fd = open("/dev/hello", O_RDWR);
 if (fd == -1)
 {
      printf("can not open file /dev/hello\n");
      return -1;
 }

/* 2. mmap
       * MAP_SHARED  : 多个APP都调用mmap映射同一块内存时, 对内存的修改大家都可以看到。
       *               就是说多个APP、驱动程序实际上访问的都是同一块内存
       * MAP_PRIVATE : 创建一个copy on write的私有映射。
       *               当APP对该内存进行修改时,其他程序是看不到这些修改的。
       *               就是当APP写内存时, 内核会先创建一个拷贝给这个APP,
       *               这个拷贝是这个APP私有的, 其他APP、驱动无法访问。
       */
buf =  mmap(NULL, 1024*8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
로그인 후 복사

mmap的第一个参数是想要映射的起始地址,通常设置为NULL사용자 공간은 커널 공간 데이터에 직접 접근할 수 없기 때문에 서로 다른 주소 공간을 매핑하므로 데이터를 먼저 복사한 다음 작동할 수 있습니다.

사용자 공간에서 몇 MB의 데이터를 커널로 전송해야 한다면 원본 복사 방법은 분명히 매우 비효율적이고 비현실적이므로 어떻게 해야 할까요? 🎜🎜생각해 보세요. 복사하는 이유는 사용자 공간이 커널 공간에 직접 접근할 수 없기 때문입니다. 그러면 커널 공간의 버퍼에 직접 접근할 수 있다면 해결될까요? 🎜🎜🎜간단히 말하면 물리적 메모리 조각에 두 개의 매핑이 있다는 의미입니다. 즉, 커널 공간에 하나, 사용자 공간에 하나, 총 두 개의 가상 주소가 있다는 의미입니다. 🎜관계는 다음과 같습니다: 🎜
Linux 드라이버 IO 문서 - mmap 작업
🎜Bymmap 매핑이 가능합니다. 🎜🎜🎜🎜🎜애플리케이션 레이어🎜🎜 🎜🎜🎜애플리케이션 레이어 코드는 매우 간단합니다. 주로 mmap🎜 시스템 호출🎜을 사용하여 매핑을 수행한 다음 반환된 주소에 대해 작업을 수행할 수 있습니다. 🎜
int remap_pfn_range(
  struct vm_area_struct *vma, 
  unsigned long addr, 
  unsigned long pfn, 
  unsigned long size, 
  pgprot_t prot);
로그인 후 복사
로그인 후 복사
🎜mmap의 첫 번째 매개변수는 매핑하려는 시작 주소. 일반적으로 NULL < /code>, 🎜는 커널이 시작 주소 🎜를 결정한다는 의미입니다. 🎜<p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">두 번째 매개변수는 <strong>매핑할 메모리 공간의 크기</strong>입니다. </p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">세 번째 매개변수<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px; background-color: rgba(27, 31, 35 , 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">PROT_READ | PROT_WRITE 표시 매핑된 공간은 PROT_READ | PROT_WRITE表示映射后的空间是可读可写的。

第四个参数可填MAP_SHAREDMAP_PRIVATE읽고 쓸 수 있습니다

. 🎜🎜네 번째 매개변수는 MAP_SHARED</code > 또는 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px; background-color: rgba(27, 31, 35, 0.05) ; 글꼴 계열: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">MAP_PRIVATE:🎜
  • <코드 스타일="글꼴 크기: 14px;패딩: 2px 4px;국경 반경: 4px;마진 오른쪽: 2px;마진 왼쪽: 2px;배경 색상: rgba(27, 31, 35, 0.05 );font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">MAP_SHARED: 다중<코드 스타일 ="글꼴 크기: 14px; 패딩: 2px 4px; 테두리 반경: 4px; 여백 오른쪽: 2px; 여백 왼쪽: 2px; 배경 색상: rgba(27, 31, 35, 0.05); 글꼴 가족: "Operator Mono", Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">APP 모두 mmap 동일한 메모리를 매핑하면 모든 사람이 메모리에 대한 수정 사항을 볼 수 있습니다. 즉, 여러 APP, 드라이버 실제 모두 동일한 메모리에 액세스합니다.
  • MAP_SHARED:多个APP都调用mmap映射同一块内存时, 对内存的修改大家都可以看到。就是说多个APP、驱动程序实际上访问的都是同一块内存
  • MAP_PRIVATE:创建一个copy on write的私有映射。当APP对该内存进行修改时,其他程序是看不到这些修改的。就是当APP写内存时, 内核会先创建一个拷贝给这个APP,这个拷贝是这个APP🎜MAP_PRIVATE</ 코드>: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px; background-color: rgba(27, 31, 35)를 생성합니다. , 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">쓰기 시 복사 비공개 매핑. APP가 이 메모리를 수정하면 다른 프로그램 이러한 수정 사항을 볼 수 없습니다. 이는APP메모리에 쓸 때 커널은 먼저 이에 대한 복사본을 생성합니다APP, 이 복사본은 APP은 비공개이므로 다른 앱과 운전자가 접근할 수 없습니다.
  • 驱动层

    驱动层主要是实现mmap接口,而mmap接口的实现,主要是调用了remap_pfn_range函数,函数原型如下:

    int remap_pfn_range(
      struct vm_area_struct *vma, 
      unsigned long addr, 
      unsigned long pfn, 
      unsigned long size, 
      pgprot_t prot);
    로그인 후 복사
    로그인 후 복사

    vma:描述一片映射区域的结构体指针

    addr:要映射的虚拟地址起始地址

    pfn:物理内存所对应的页框号,就是将物理地址除以页大小得到的值

    size:映射的大小

    prot:该内存区域的访问权限

    驱动主要步骤:

    1、使用kmalloc或者kzalloc函数分配一块内存kernel_buf,因为这样分配的内存物理地址是连续的,mmap后应用层会对这一个基地址去访问这块内存。

    2、实现mmap函数

    static int hello_drv_mmap(struct file *file, struct vm_area_struct *vma)
    {
     /* 获得物理地址 */
     unsigned long phy = virt_to_phys(kernel_buf);//kernel_buf是内核空间分配的一块虚拟地址空间
        
        /* 设置属性:cache, buffer*/
     vma-&gt;vm_page_prot = pgprot_writecombine(vma-&gt;vm_page_prot);
        
        /* map */
        if(remap_pfn_range(vma, vma-&gt;vm_start, phy&gt;&gt;PAGE_SHFIT,
                          vma-&gt;vm_end - vma-&gt;start, vma-&gt;vm_page_prot)){
     printk(&quot;mmap remap_pfn_range failed\n&quot;);
        return -ENOBUFS;
     }
     return 0;
    }
    
    static struct file_operations my_fops = {
     .mmap = hello_drv_mmap,
    };
    로그인 후 복사

    1、通过virt_to_phys将虚拟地址转为物理地址,这里的kernel_buf是内核空间的一块虚拟地址空间

    2、设置属性:不使用cache,使用buffer

    3、映射:通过remap_pfn_range函数映射,phy&gt;&gt;PAGE_SHIFT其实就是按page映射,除了这个参数,其他的起始地址、大小和权限都可以由用户在系统调用函数中指定

    当应用层调用mmap后,就会调用到驱动层的mmap函数,最终应用层的虚拟地址和驱动中的物理地址就建立了映射关系,应用层也就可以直接访问驱动的buffer了。

    위 내용은 Linux 드라이버 IO 문서 - mmap 작업의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

    뜨거운 기사 태그

    메모장++7.3.1

    메모장++7.3.1

    사용하기 쉬운 무료 코드 편집기

    SublimeText3 중국어 버전

    SublimeText3 중국어 버전

    중국어 버전, 사용하기 매우 쉽습니다.

    스튜디오 13.0.1 보내기

    스튜디오 13.0.1 보내기

    강력한 PHP 통합 개발 환경

    드림위버 CS6

    드림위버 CS6

    시각적 웹 개발 도구

    SublimeText3 Mac 버전

    SublimeText3 Mac 버전

    신 수준의 코드 편집 소프트웨어(SublimeText3)

    Android TV Box, 비공식 Ubuntu 24.04 업그레이드 제공 Android TV Box, 비공식 Ubuntu 24.04 업그레이드 제공 Sep 05, 2024 am 06:33 AM

    Android TV Box, 비공식 Ubuntu 24.04 업그레이드 제공

    DeepSeek 웹 버전 입구 DeepSeek 공식 웹 사이트 입구 DeepSeek 웹 버전 입구 DeepSeek 공식 웹 사이트 입구 Feb 19, 2025 pm 04:54 PM

    DeepSeek 웹 버전 입구 DeepSeek 공식 웹 사이트 입구

    DeepSeek을 설치하는 방법 DeepSeek을 설치하는 방법 Feb 19, 2025 pm 05:48 PM

    DeepSeek을 설치하는 방법

    BitPie Bitpie 지갑 앱 다운로드 주소 BitPie Bitpie 지갑 앱 다운로드 주소 Sep 10, 2024 pm 12:10 PM

    BitPie Bitpie 지갑 앱 다운로드 주소

    Bitget 공식 웹 사이트 설치 (2025 초보자 안내서) Bitget 공식 웹 사이트 설치 (2025 초보자 안내서) Feb 21, 2025 pm 08:42 PM

    Bitget 공식 웹 사이트 설치 (2025 초보자 안내서)

    Zabbix 3.4 소스 코드 컴파일 설치 Zabbix 3.4 소스 코드 컴파일 설치 Sep 04, 2024 am 07:32 AM

    Zabbix 3.4 소스 코드 컴파일 설치

    자세한 설명: 쉘 스크립트 변수 판단 매개변수 명령 자세한 설명: 쉘 스크립트 변수 판단 매개변수 명령 Sep 02, 2024 pm 03:25 PM

    자세한 설명: 쉘 스크립트 변수 판단 매개변수 명령

    Ouyi OKX 설치 패키지가 직접 포함되어 있습니다 Ouyi OKX 설치 패키지가 직접 포함되어 있습니다 Feb 21, 2025 pm 08:00 PM

    Ouyi OKX 설치 패키지가 직접 포함되어 있습니다

    See all articles