亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

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

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

前言

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

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

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

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

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

通過mmap映射就可以實現(xiàn)。

應用層

應用層代碼很簡單,主要就是通過mmap系統(tǒng)調(diào)用進行映射,然后就可以對返回的地址進行操作。

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都調(diào)用mmap映射同一塊內(nèi)存時, 對內(nèi)存的修改大家都可以看到。
       *               就是說多個APP、驅(qū)動程序?qū)嶋H上訪問的都是同一塊內(nèi)存
       * MAP_PRIVATE : 創(chuàng)建一個copy on write的私有映射。
       *               當APP對該內(nèi)存進行修改時,其他程序是看不到這些修改的。
       *               就是當APP寫內(nèi)存時, 內(nèi)核會先創(chuàng)建一個拷貝給這個APP,
       *               這個拷貝是這個APP私有的, 其他APP、驅(qū)動無法訪問。
       */
buf =  mmap(NULL, 1024*8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

登錄后復制

mmap的第一個參數(shù)是想要映射的起始地址,通常設置為NULL表示由內(nèi)核來決定該起始地址。

第二參數(shù)是要映射的內(nèi)存空間的大小。

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

第四個參數(shù)可填MAP_SHAREDMAP_PRIVATE

    MAP_SHARED:多個APP都調(diào)用mmap映射同一塊內(nèi)存時, 對內(nèi)存的修改大家都可以看到。就是說多個APP、驅(qū)動程序?qū)嶋H上訪問的都是同一塊內(nèi)存。
    MAP_PRIVATE:創(chuàng)建一個copy on write的私有映射。當APP對該內(nèi)存進行修改時,其他程序是看不到這些修改的。就是當APP寫內(nèi)存時, 內(nèi)核會先創(chuàng)建一個拷貝給這個APP,這個拷貝是這個APP私有的, 其他APP、驅(qū)動無法訪問。

    驅(qū)動層

    驅(qū)動層主要是實現(xiàn)mmap接口,而mmap接口的實現(xiàn),主要是調(diào)用了remap_pfn_range函數(shù),函數(shù)原型如下:

    int remap_pfn_range(
      struct vm_area_struct *vma, 
      unsigned long addr, 
      unsigned long pfn, 
      unsigned long size, 
      pgprot_t prot);

    登錄后復制

    vma:描述一片映射區(qū)域的結(jié)構(gòu)體指針

    addr:要映射的虛擬地址起始地址

    pfn:物理內(nèi)存所對應的頁框號,就是將物理地址除以頁大小得到的值

    size:映射的大小

    prot:該內(nèi)存區(qū)域的訪問權(quán)限

    驅(qū)動主要步驟:

    1、使用kmalloc或者kzalloc函數(shù)分配一塊內(nèi)存kernel_buf,因為這樣分配的內(nèi)存物理地址是連續(xù)的,mmap后應用層會對這一個基地址去訪問這塊內(nèi)存。

    2、實現(xiàn)mmap函數(shù)

    static int hello_drv_mmap(struct file *file, struct vm_area_struct *vma)
    {
     /* 獲得物理地址 */
     unsigned long phy = virt_to_phys(kernel_buf);//kernel_buf是內(nèi)核空間分配的一塊虛擬地址空間
        
        /* 設置屬性: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將虛擬地址轉(zhuǎn)為物理地址,這里的kernel_buf是內(nèi)核空間的一塊虛擬地址空間

    2、設置屬性:不使用cache,使用buffer

    3、映射:通過remap_pfn_range函數(shù)映射,phy>>PAGE_SHIFT其實就是按page映射,除了這個參數(shù),其他的起始地址、大小和權(quán)限都可以由用戶在系統(tǒng)調(diào)用函數(shù)中指定。

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

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

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

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

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

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

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

運動步數(shù)有氧達人2018-06-03

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

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

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

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