在linux中,pfn全稱“page frame number”,是物理內(nèi)存區(qū)域編號(hào)?!皃age frame”是針對(duì)物理內(nèi)存而言的,把物理內(nèi)存分成一個(gè)個(gè)的page size的區(qū)域,并且給每一個(gè)page編號(hào),而這個(gè)編號(hào)就是PFN。
本教程操作環(huán)境:linux5.9.8系統(tǒng)、Dell G3電腦。
1、什么是page frame?
操作系統(tǒng)最重要的作用之一就是管理計(jì)算機(jī)系統(tǒng)中的各種資源,做為最重要的資源:內(nèi)存,我們必須管理起來(lái)。在linux操作系統(tǒng)中,物理內(nèi)存是按照page size來(lái)管理的,具體page size是多少是和硬件以及l(fā)inux系統(tǒng)配置相關(guān)的,4k是最經(jīng)典的設(shè)定。因此,對(duì)于物理內(nèi)存,我們將其分成一個(gè)個(gè)按page size排列的page,每一個(gè)物理內(nèi)存中的page size的內(nèi)存區(qū)域我們稱之page frame。我們針對(duì)每一個(gè)物理的page frame建立一個(gè)struct page的數(shù)據(jù)結(jié)構(gòu)來(lái)跟蹤每一個(gè)物理頁(yè)面的使用情況:是用于內(nèi)核的正文段?還是用于進(jìn)程的頁(yè)表?是用于各種file cache還是處于free狀態(tài)……
每一個(gè)page frame有一個(gè)一一對(duì)應(yīng)的page數(shù)據(jù)結(jié)構(gòu),系統(tǒng)中定義了page_to_pfn和pfn_to_page的宏用來(lái)在page frame number和page數(shù)據(jù)結(jié)構(gòu)之間進(jìn)行轉(zhuǎn)換,具體如何轉(zhuǎn)換是和memory modle相關(guān),我們會(huì)在第三章詳細(xì)描述linux kernel中的3種內(nèi)存模型。
2、什么是PFN?
對(duì)于一個(gè)計(jì)算機(jī)系統(tǒng),其整個(gè)物理地址空間應(yīng)該是從0開(kāi)始,到實(shí)際系統(tǒng)能支持的最大物理空間為止的一段地址空間。在ARM系統(tǒng)中,假設(shè)物理地址是32個(gè)bit,那么其物理地址空間就是4G,在ARM64系統(tǒng)中,如果支持的物理地址bit數(shù)目是48個(gè),那么其物理地址空間就是256T。當(dāng)然,實(shí)際上這么大的物理地址空間并不是都用于內(nèi)存,有些也屬于I/O空間(當(dāng)然,有些cpu arch有自己獨(dú)立的io address space)。因此,內(nèi)存所占據(jù)的物理地址空間應(yīng)該是一個(gè)有限的區(qū)間,不可能覆蓋整個(gè)物理地址空間。不過(guò),現(xiàn)在由于內(nèi)存越來(lái)越大,對(duì)于32位系統(tǒng),4G的物理地址空間已經(jīng)無(wú)法滿足內(nèi)存的需求,因此會(huì)有high memory這個(gè)概念,后續(xù)會(huì)詳細(xì)描述。
PFN是page frame number的縮寫(xiě),所謂page frame,就是針對(duì)物理內(nèi)存而言的,把物理內(nèi)存分成一個(gè)個(gè)的page size的區(qū)域,并且給每一個(gè)page 編號(hào),這個(gè)編號(hào)就是PFN。假設(shè)物理內(nèi)存從0地址開(kāi)始,那么PFN等于0的那個(gè)頁(yè)幀就是0地址(物理地址)開(kāi)始的那個(gè)page。假設(shè)物理內(nèi)存從x地址開(kāi)始,那么第一個(gè)頁(yè)幀號(hào)碼就是(x>>PAGE_SHIFT)。
PFN的取值范圍是 0—-(memory size >> 12)。
但是由于物理內(nèi)存映射的關(guān)系,物理內(nèi)存的0地址對(duì)應(yīng)到到系統(tǒng)上并不是物理地址的0。 例如:s3c2440上,內(nèi)存的地址是從0x30000000開(kāi)始的。當(dāng)連接ram后,ram的0地址在s3c2440看來(lái),就是0x30000000. 所以在系統(tǒng)中 pfn的值 應(yīng)該等于 (physical address – memory base address) >> 12 。
但是linux中,用的又都是虛擬地址,所以要先將 virtual address轉(zhuǎn)換成 physical address 才行。 所以在linux中有個(gè)宏定義 將內(nèi)核線性空間的虛擬地址和pfn轉(zhuǎn)換:
#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) //__pa() 將虛擬地址轉(zhuǎn)化成物理地址 #define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT)
所以pfn在linux內(nèi)核中應(yīng)該對(duì)應(yīng)的是頁(yè)幀號(hào)??梢酝ㄟ^(guò)簡(jiǎn)單的轉(zhuǎn)換找到對(duì)應(yīng)的物理地址。
每個(gè)物理上的頁(yè),內(nèi)核給與之分配了一個(gè)描述符來(lái)描述: page。 pfn可以和page進(jìn)行轉(zhuǎn)換:
#define page_to_pfn __page_to_pfn #define pfn_to_page __pfn_to_page
所有的page結(jié)構(gòu)存放在mem_map中,方便進(jìn)行管理。
由于linux是將物理內(nèi)存分成4K大小的頁(yè)來(lái)進(jìn)行管理的。所以在軟件上也會(huì)設(shè)置MMU進(jìn)行匹配對(duì)應(yīng)。后面敘述。
linux將4G的虛擬空間分成了用戶空間和內(nèi)核空間。用戶空間是0—3G,內(nèi)核空間是3G—4G。 從內(nèi)核空間可以訪問(wèn)到用戶空間,但是從用戶空間必須通過(guò)系統(tǒng)調(diào)用來(lái)能訪問(wèn)內(nèi)核空間。