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