物理地址映射是什么
為了保證CPU執(zhí)行指令時(shí)可正確訪問(wèn)存儲(chǔ)單元,需將用戶程序中的邏輯地址轉(zhuǎn)換為運(yùn)行時(shí)由機(jī)器直接尋址的物理地址,這一過(guò)程稱為地址映射。那么物理地址映射是什么呢?下面大家跟著學(xué)習(xí)啦小編一起來(lái)了解一下吧。
物理地址映射方法
一般情況下,Linux系統(tǒng)中,進(jìn)程的4GB內(nèi)存空間被劃分成為兩個(gè)部分------用戶空間和內(nèi)核空間,大小分別為0~3G,3~4G。
用戶進(jìn)程通常情況下,只能訪問(wèn)用戶空間的虛擬地址,不能訪問(wèn)到內(nèi)核空間。
每個(gè)進(jìn)程的用戶空間都是完全獨(dú)立、互不相干的,用戶進(jìn)程各自有不同的頁(yè)表。而內(nèi)核空間是由內(nèi)核負(fù)責(zé)映射,它并不會(huì)跟著進(jìn)程改變,是固定的。內(nèi)核空間地址有自己對(duì)應(yīng)的頁(yè)表,內(nèi)核的虛擬空間獨(dú)立于其他程序。
3~4G之間的內(nèi)核空間中,從低地址到高地址依次為:物理內(nèi)存映射區(qū)—隔離帶—vmalloc虛擬內(nèi)存分配區(qū)—隔離帶—高端內(nèi)存映射區(qū)—專用頁(yè)面映射區(qū)—保留區(qū)。
【內(nèi)核空間內(nèi)存動(dòng)態(tài)申請(qǐng)】
主要包括三個(gè)函數(shù):kmalloc(), __get_free_pages, vmalloc。
kmalloc(), __get_free_pages申請(qǐng)的內(nèi)存位于物理地址映射區(qū),而且在物理上也是連續(xù)的,它們與真實(shí)的物理地址只有一個(gè)固定的偏移,因此存在較簡(jiǎn)單的轉(zhuǎn)換關(guān)系。而vmalloc申請(qǐng)的內(nèi)存位于vmalloc虛擬內(nèi)存分配區(qū)(這些區(qū)都是以線性地址為度量),它在虛擬內(nèi)存空間給出一塊連續(xù)的內(nèi)存區(qū),實(shí)質(zhì)上,這片連續(xù)的虛擬內(nèi)存在物理內(nèi)存中并不一定連續(xù),而vmalloc申請(qǐng)的虛擬內(nèi)存和物理內(nèi)存之間也沒(méi)有簡(jiǎn)單的換算關(guān)系。
因?yàn)関malloc申請(qǐng)的在虛擬內(nèi)存空間連續(xù)的內(nèi)存區(qū)在物理內(nèi)存中并不一定連續(xù),可以想象為了完成vmalloc,新的頁(yè)表需要被建立,因此,知識(shí)調(diào)用vmalloc來(lái)分配少量?jī)?nèi)存是不妥的。
一般來(lái)講,kmalloc用來(lái)分配小于128K的內(nèi)存,而更大的內(nèi)存塊需要用vmalloc來(lái)實(shí)現(xiàn)。
【虛擬地址與物理地址關(guān)系】
對(duì)于內(nèi)核物理內(nèi)存映射區(qū)的虛擬內(nèi)存(用kmalloc(), __get_free_pages申請(qǐng)的),使用virt_to_phys()和phys_to_virt()來(lái)實(shí)現(xiàn)物理地址和內(nèi)核虛擬地址之間的互相轉(zhuǎn)換。它實(shí)際上,僅僅做了3G的地址移位。
上述方法適用于常規(guī)內(nèi)存(內(nèi)核物理內(nèi)存映射區(qū)),高端內(nèi)存的虛擬地址與物理地址之間不存在如此簡(jiǎn)單的換算關(guān)系。因?yàn)樗婕暗搅朔蛛x物理頁(yè)的頁(yè)表控制機(jī)制。
【ioremap】
在ARM中,設(shè)備的寄存器或者存儲(chǔ)塊的這部分空間屬于內(nèi)存空間的一部分,我們稱之為IO內(nèi)存。
在內(nèi)核中訪問(wèn)IO內(nèi)存之前,我們只有IO內(nèi)存的物理地址,這樣是無(wú)法通過(guò)軟件直接訪問(wèn)的,需要首先用ioremap()函數(shù)將設(shè)備所處的物理地址映射到內(nèi)核虛擬地址空間(3GB~4GB)。然后,才能根據(jù)映射所得到的內(nèi)核虛擬地址范圍,通過(guò)訪問(wèn)指令訪問(wèn)這些IO內(nèi)存資源。
在將I/O內(nèi)存資源的物理地址映射成核心虛地址后,理論上講我們就可以象讀寫(xiě)RAM那樣直接讀寫(xiě)I/O內(nèi)存資源了。為了保證驅(qū)動(dòng)程序的跨平臺(tái)的可移植性,我們應(yīng)該使用Linux中特定的函數(shù)來(lái)訪問(wèn)I/O內(nèi)存資源,而不應(yīng)該通過(guò)指向核心虛地址的指針來(lái)訪問(wèn)。
【mmap】
用mmap映射一個(gè)設(shè)備,意味著使用戶空間的一段地址關(guān)聯(lián)到設(shè)備內(nèi)存上,這使得只要程序在分配的地址范圍內(nèi)進(jìn)行讀取或者寫(xiě)入,實(shí)際上就是對(duì)設(shè)備的訪問(wèn)。這種數(shù)據(jù)傳輸是直接的,不需要用到內(nèi)核空間作為數(shù)據(jù)轉(zhuǎn)移的中間站。
remap_page_range函數(shù)的功能是構(gòu)造用于映射一段物理地址的新頁(yè)表,實(shí)現(xiàn)了內(nèi)核空間與用戶空間的映射。
在內(nèi)核驅(qū)動(dòng)程序的初始化階段,通過(guò)ioremap()將物理地址映射到內(nèi)核虛擬空間;在驅(qū)動(dòng)程序的mmap系統(tǒng)調(diào)用中,使用remap_page_range()將該塊ROM映射到用戶虛擬空間。這樣內(nèi)核空間和用戶空間都能訪問(wèn)這段被映射后的虛擬地址。
Ioremap:
進(jìn)程空間ç內(nèi)核空間çIO內(nèi)存
其中,后面兩個(gè)指的是同一段物理內(nèi)存區(qū)域,只是一個(gè)為虛擬地址,一個(gè)為物理地址。進(jìn)程空間和內(nèi)核空間對(duì)應(yīng)著不同的物理地址,它們之間的數(shù)據(jù)傳遞,是實(shí)際的數(shù)據(jù)的拷貝。
Mmap:
進(jìn)程空間çIO內(nèi)存
其中,進(jìn)程空間mmap得到的那段虛擬地址跟IO內(nèi)存對(duì)應(yīng)著同一段物理地址。這個(gè)過(guò)程沒(méi)有額外的數(shù)據(jù)中轉(zhuǎn),讀寫(xiě)都直接針對(duì)硬件的物理地址進(jìn)行。
一般來(lái)講,小數(shù)據(jù)量的傳輸用ioremap()就足夠了,
【IO內(nèi)存的一般訪問(wèn)方法】
1. 首先是調(diào)用request_mem_region()申請(qǐng)資源,即告訴內(nèi)核,本驅(qū)動(dòng)正在使用這段物理內(nèi)存,其他驅(qū)動(dòng)不得訪問(wèn)它們。在設(shè)備驅(qū)動(dòng)模塊加載或open()函數(shù)中進(jìn)行。
2. 接著講寄存器地址通過(guò)ioremap()映射到內(nèi)核空間虛擬地址,之后就可以通過(guò)Linux設(shè)備訪問(wèn)編程接口訪問(wèn)這些設(shè)備的寄存器了。在設(shè)備驅(qū)動(dòng)初始化、write(),read(),ioctl()函數(shù)中進(jìn)行。
3. 訪問(wèn)完成之后,應(yīng)對(duì)ioremap()申請(qǐng)的虛擬地址進(jìn)行釋放,并釋放release_mem_region()申請(qǐng)的IO內(nèi)存資源。在設(shè)備驅(qū)動(dòng)模塊卸載或release()函數(shù)中進(jìn)行。
看過(guò)“ 物理地址映射是什么 ”的人還看了: