request_mem_region,ioremap和phys_to_virt()

 

Linux在頭文件include/linux/ioport.h中定義了三個對I/O內存資源進行操作的宏:
(1)request_mem_region()宏,請求分配指定的I/O內存資源。
(2)check_mem_region()宏,檢查指定的I/O內存資源是否已被佔用。
(3)release_mem_region()宏,釋放指定的I/O內存資源。
這三個宏的定義如下:
#define request_mem_region(start,n,name)   __request_region(&iomem_resource, (start), (n), (name))
#define check_mem_region(start,n)    __check_region(&iomem_resource, (start), (n))
#define release_mem_region(start,n)   __release_region(&iomem_resource, (start), (n))
   其中,參數start是I/O內存資源的起始物理地址(是CPU在RAM物理地址空間中的物理地址),參數n指定I/O內存資源的大小。在請求IO內存資源成功後,開始用ioremap進行映射操作。

void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) 將一個IO地址空間映射到內核的虛擬地址空間上去,便於訪問。入口:phys_addr是要映射的起始的IO地址;size是要映射的空間的大小;flag是要映射的IO空間的和權限有關的標誌;
實現:對要映射的IO地址空間進行判斷,低PCI/ISA地址不需要重新映射,也不允許用戶將IO地址空間映射到正在使用的RAM中,最後申請一個 vm_area_struct結構,調用remap_area_pages填寫頁表,若填寫過程不成功則釋放申請的vm_area_struct空間;根據虛擬地址和欲映射的物理地址修改頁表,之後內核就可以用這個虛擬地址來訪問映射的物理地址了。
對於直接映射的I/O地址ioremap不做任何事情(比如不帶MMU的Uclinux中就直接返回物理地址) 。有了ioremap(和iounmap),設備就可以訪問任何I/O內存空間,不論它是否直接映射到虛擬地址空間。但是,這些地址永遠不能直接使用(像kmalloc返回的地址那樣用),而要用readb這種函數

/***********************************************************************/

同樣是從物理地址分配得到虛擬地址,還有以下這個函數:phys_to_virt()實際地址轉換成虛擬地址,兩者是有區別的。用ioremap 和 phys_to_virt 做物理地址於虛擬地址的轉換髮現:

addr = (unsigned int volatile *)ioremap(0x56000088,12);
printk(KERN_ALERT"%x/n",addr);
addr = (unsigned int volatile *) phys_to_virt(0x56000088);
printk(KERN_ALERT"%x/n",addr);
兩個函數返回的addr值不一樣。原因在於:
(1)在內核中phys_to_virt只是給地址減去一個固定的偏移
#ifndef __virt_to_phys
#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
#endif
注意:PHYS_OFFSET =0x50000000,在帶MMU的內核中,PAGE_OFFSET是0xc0000000;不帶MMU的內核中,與PHYS_OFFSET 同。
(2)而ioremap()的原則就是內核會根據指定的物理地址新建映射頁表,物理地址和虛擬地址的關係就由這些頁表來搭建!:
這個從ioremap的函數體可以看出來。
發佈了1 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章