1. 程式人生 > >mmap記憶體對映/dev/mem到使用者空間

mmap記憶體對映/dev/mem到使用者空間

  1. 核心(驅動)裡_get_fre_pages()申請物理頁面,返回物理首地址X, 
  2. 使用者空間mmap檔案/dem/mem的偏移X處到自己程序空間,對其操作 
  3. /dev/mem是系統實體記憶體映象檔案,檔案偏移X即記憶體的偏移X 
  4. 2.核心(驅動)向裝置檔案比如/dev/video1寫一定格式的資料 
  5. 使用者空間mmap檔案/dev/video1到程序空間,去讀寫

一、mmap簡介

對於mmap網路上有很多介紹的資料,我主要用來將實體地址對映到user space的虛擬地址,這樣tool才能

讀取到正確的data。

關於mmap的詳細介紹可以直接用命令:man mmap看到。下面給出一個網路連結:


二、/dev/mem簡介

其實以前訪問PCI device的MMIO space也是通過開啟裝置/dev/mem,然後通過mmap對映到user space就

可以直接訪問。

這裡的/dev/mem是整個實體地址空間的對映,之所以是實體地址空間而不是實體記憶體後面會說明。

訪問實體地址的方式如下:

int fd = open("/dev/mem", O_RDWR);        //開啟裝置

//通過mmap對映實體地址到user space的虛擬地址

virt_addr = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, physical_addr);

if (virt_addr == MAP_FAILED) {

        //打印出錯資訊

}

如果mmap出錯,那麼virt_addr返回(void *) -1,否則就返回對映到的地址。

由於/dev/mem對映的是實體地址空間,所以start設定為NULL,這樣offset就可以直接設定成實體地址。

題外話:前面說過訪問PCI device的MMIO space也可以通過這種方式訪問,但是MMIO register不是在記憶體條上,

而是在PCI device上面,但是由於這些register和記憶體一樣是統一編址,所以最後的實體地址空間是記憶體條加上

各個device的對映到記憶體地址空間的部分,所以在32-bit作業系統下,也有可能申請到大於4G的地址。

三、問題

在driver中通過alloc_pages申請得到的page,將page的實體地址export到user space,但是user space拿到這個

實體地址後並不能mmap成功。通過perror(“mmap”),發現總是返回錯誤"Operation not permitted!",後來發現是

由於kernel對user space訪問/dev/mem是有限制的,通過編譯選項:CONFIG_STRICT_DEVMEM來限制user space

對實體記憶體的訪問,這個選項的說明在arch/x86/Kconfig.debug中有說明:

config STRICT_DEVMEM
    bool "Filter access to /dev/mem"
    ---help---
      If this option is disabled, you allow userspace (root) access to all
      of memory, including kernel and userspace memory. Accidental
      access to this is obviously disastrous, but specific access can
      be used by people debugging the kernel. Note that with PAT support
      enabled, even in this case there are restrictions on /dev/mem
      use due to the cache aliasing requirements.

      If this option is switched on, the /dev/mem file only allows
      userspace access to PCI space and the BIOS code and data regions.
      This is sufficient for dosemu and X and all common users of
      /dev/mem.

      If in doubt, say Y.

只有在.config檔案中設定CONFIG_STRICT_DEVMEM=n才能獲得對整個memory的訪問許可權,在預設情況下,

CONFIG_STRICT_DEVMEM=y,這也就是之前mmap總是報錯:“Operation not permitted”的原因。

設定這個選項後,編譯kernel,然後執行tool,mmap還是返回錯誤:“Invalid argument”。後來查到還需要設定

編譯選項CONFIG_X86_PAT=n,這個選項也是預設開啟的,但是要關閉這個選項還需要開啟CONFIG_EXPERT,

否則CONFIG_X86_PAT總是關不掉。

設定好這三個編譯選項後,重新編譯kernel,然後執行tool,發現kernel已經解除了對mmap的訪問限制,可以

正確讀取對應實體地址的內容了。

最後還可以通過修改核心原始碼來實現,具體的原始檔時在/drivers/char/目錄下的mem.c檔案

static inline int  range_is_allowed(unsigned long pfn, unsigned long size);