1. 程式人生 > >ioremap()的原理及意義

ioremap()的原理及意義

void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
入口: phys_addr:要對映的起始的IO地址;

size:要對映的空間的大小;

flags:要對映的IO空間的和許可權有關的標誌;

功能: 將一個IO地址空間對映到核心的虛擬地址空間上去,便於訪問;

實現:對要對映的IO地址空間進行判斷,低PCI/ISA地址不需要重新對映,也不允許使用者將IO地址空間對映到正在使用的RAM中,最後申請一 個 vm_area_struct結構,呼叫remap_area_pages填寫頁表,若填寫過程不成功則釋放申請的vm_area_struct空 間;

意義:
比如isa裝置和pci裝置,或者是fb,硬體的跳線或者是物理連線方式決定了硬體上的記憶體影射到的cpu實體地址。
在核心訪問這些地址必須分配給這段記憶體以虛擬地址,這正是__ioremap
的意義所在 ,需要注意的是,實體記憶體已經"存在"了,無需alloc page給這段地址了.

檔案中的註釋也是比較詳盡的,並且只 暴露了__ioremap,iounmap兩個函式供其他模
塊呼叫,函式remap_area_pte,remap_area_pmd,remap_area_pages只為__ioremap所用.

--------
為了使軟體訪問I/O記憶體,必須為裝置分配虛擬地址.這就是ioremap的工作.這個函式專門用來為I/O記憶體區域分配虛擬地址(空間).對於直接對映的I/O地址ioremap不做任何事情(uClinux中是這麼實現的??)
有了ioremap(和iounmap),裝置就可以訪問任何I/O記憶體空間,不論它是否直接對映到虛擬地址空間.但是,這些地址永遠不能直接使用(指實體地址),而要用readb這種函式.

根據計算機平臺和所使用匯流排的不同,I/O 記憶體可能是,也可能不是通過頁表訪問的,通過頁表訪問的是統一編址(PowerPC),否則是獨立編址(Intel)。如果訪問是經由頁表進行的,核心必須首先安排實體地址使其對裝置驅動 程式可見(這通常意味著在進行任何 I/O 之前必須先呼叫 ioremap
)。如果訪問無需頁表,那麼 I/O 記憶體區域就很象 I/O 埠,可以使 用適當形式的函式讀寫它們。

不管訪問 I/O 記憶體時是否需要呼叫 ioremap,都不鼓勵直接使用指向 I/O 記憶體的指標。儘管(在“I/O 埠和 I/O 記憶體” 介紹過)I/O 記憶體在硬體一級是象普通 RAM 一樣定址的,但在“I/O 暫存器和常規記憶體”中描述過的那些需要額外小心的情況中已經建議不要使用普 通指標。相反,使用“包裝的”函式訪問 I/O 記憶體,一方面在所有平臺上都是安全的,另一方面,在可以直接對指標指向的記憶體區域執行操作的時候,該函式 是經過優化的

-------

自己原以為當給顯示卡上的儲存空間分配了匯流排地址A以後,它所對應的虛擬空間就隨之確定了.也就是A+3G.可是事實上,在ioremap
.c檔案裡面的實現並不是這樣的.所用的函式是 __ioremap(unsigned long phys_addr, unsigned long size, unsigned
long flags)實現的時候是為從phys_addr開始的size大小的實體地址分配一塊虛擬地址.注意這裡是分配,而不是指定.我所認為的分配應該是指定即根據phys_addr得到其所對應的虛擬地址是phys_addr+3G.
本人認為一合理的解釋是這樣的:系統虛擬空間中對映的非IO卡上的地址空間滿足3G差關係,而IO卡上的
儲存空間就不滿足了.歡迎討論

在X86體系下的,CPU的實體地址和PCI匯流排地址共用一個空間。linux核心將3G-4G的虛擬地址固定對映到了實體地址的0-1G的地方。但是如果外圍裝置上的地址高於1G,例如某塊PCI卡分配到了一個高於1G的地址,就需要呼叫ioremap來重新建立該實體地址(匯流排地址)和虛擬地址之間的對映。這個對映過程是這樣的:在ioremap.c檔案的__ioremap函式中首先對將來對映的實體地址進行檢查,也就是不能重新對映640K-1M地址(由於歷史的原因,實體地址640k到1M空間被保留給了顯示卡),普通的 ram地也不能重新被對映。之後呼叫get_vm_area獲得可用的虛擬地址,然後根這虛擬地址和欲對映的實體地址修改頁表,之後核心就可以用這個虛擬地址來訪問對映的實體地址了。