日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

前言

平時我們寫Linux驅動和用戶空間交互時,都是通過copy_from_user把用戶空間傳過來的數據進行拷貝,為什么要這么做呢?

因為用戶空間是不能直接內核空間數據的,他們映射的是不同的地址空間,只能先將數據拷貝過來,然后再操作。

如果用戶空間需要傳幾MB的數據給內核,那么原來的拷貝方式顯然效率特別低,也不太現實,那怎么辦呢?

想想,之所以要拷貝是因為用戶空間不能直接訪問內核空間,那如果可以直接訪問內核空間的buffer,是不是就解決了。

簡單來說,就是讓一塊物理內存擁有兩份映射,即擁有兩個虛擬地址,一個在內核空間,一個在用戶空間。關系如下:

通過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表示由內核來決定該起始地址。

第二參數是要映射的內存空間的大小

第三個參數PROT_READ | PROT_WRITE表示映射后的空間是可讀可寫的。

第四個參數可填MAP_SHAREDMAP_PRIVATE

    MAP_SHARED:多個APP都調用mmap映射同一塊內存時, 對內存的修改大家都可以看到。就是說多個APP、驅動程序實際上訪問的都是同一塊內存
    MAP_PRIVATE:創建一個copy on write的私有映射。當APP對該內存進行修改時,其他程序是看不到這些修改的。就是當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->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
        
        /* map */
        if(remap_pfn_range(vma, vma->vm_start, phy>>PAGE_SHFIT,
                          vma->vm_end - vma->start, vma->vm_page_prot)){
     printk("mmap remap_pfn_range failed\n");
        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>>PAGE_SHIFT其實就是按page映射,除了這個參數,其他的起始地址、大小和權限都可以由用戶在系統調用函數中指定。

    當應用層調用mmap后,就會調用到驅動層的mmap函數,最終應用層的虛擬地址和驅動中的物理地址就建立了映射關系,應用層也就可以直接訪問驅動的buffer了。

以上就是Linux驅動IO篇——mmap操作的詳細內容,更多請關注www.92cms.cn其它相關文章!

分享到:
標簽:IO Linux mmap 操作 驅動
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定