1. ?概述
程序通常運(yùn)行在虛擬內(nèi)存空間,虛擬內(nèi)存的大小由處理器位數(shù)決定。對(duì)于32位處理器,其地址范圍是0~0xFFFF_FFFF,即4GB;對(duì)于64位處理器,其地址范圍是0~0xFFFF_FFFF_FFFF_FFFF,這個(gè)范圍就是程序能夠產(chǎn)生的地址范圍,其中的某個(gè)地址就稱為虛擬地址。
和虛擬內(nèi)存(virtual memory)相對(duì)應(yīng)的是物理內(nèi)存(physical memort),物理內(nèi)存是現(xiàn)實(shí)世界中直接使用的存儲(chǔ)器,其中的某個(gè)地址就是物理地址。物理內(nèi)存的大小不能超過處理器最大可以尋址的空間。例如,32位處理器的物理內(nèi)存(一般簡(jiǎn)稱為內(nèi)存)可以是256MB,即PM的范圍是0~0xFFF_FFFF,也可以將物理內(nèi)存增加到4GB,此時(shí)虛擬內(nèi)存和物理內(nèi)存的地址空間大小是相同的。
使用了虛擬地址,則處理器輸出的地址就是虛擬地址,這個(gè)地址不會(huì)直接送到物理存儲(chǔ)器中,而要先進(jìn)行地址轉(zhuǎn)換。負(fù)責(zé)地址轉(zhuǎn)換的部件稱為內(nèi)存管理單元(Memory Manage Unit, MMU),如下圖。
使用虛擬存儲(chǔ)器的系統(tǒng)
使用虛擬存儲(chǔ)器不僅便于程序在處理器中運(yùn)行,還給程序編寫帶來好處。在直接使用物理存儲(chǔ)器的處理器中,如果要同時(shí)運(yùn)行多個(gè)程序,需要為每個(gè)程序都分配一塊地址空間,每個(gè)程序都需要在這個(gè)地址空間內(nèi)運(yùn)行,這樣極大地限制了程序的編寫,而且不能使處理器隨便地運(yùn)行程序。
通過操作系統(tǒng)動(dòng)態(tài)地將每個(gè)程序的虛擬地址轉(zhuǎn)化為物理地址,還可以實(shí)現(xiàn)程序的保護(hù)。即使兩個(gè)程序使用了同一個(gè)虛擬地址,它們也會(huì)對(duì)應(yīng)到不同的物理地址,因此可以保證每個(gè)程序的內(nèi)容不會(huì)被其他程序隨便改寫。通過這種方式,還可以實(shí)現(xiàn)程序間的共享,例如操作系統(tǒng)內(nèi)核提供了打印(printf)函數(shù),第一個(gè)程序在地址A使用了printf,第二個(gè)程序在地址B使用了printf,操作系統(tǒng)在地址轉(zhuǎn)換的時(shí)候,會(huì)將地址A和B轉(zhuǎn)換為同樣的物理地址,這個(gè)物理地址就是printf函數(shù)在物理存儲(chǔ)器中的實(shí)際地址,這樣就實(shí)現(xiàn)了程序的共享。雖然兩個(gè)程序都用了printf,但沒必要使printf占用物理內(nèi)存的兩個(gè)地方,因此,使用虛擬存儲(chǔ)器不僅可以降低物理存儲(chǔ)器的容量需求,還可以帶來另外的好處:保護(hù)(protect)和共享(share)。
一個(gè)處理器要支持現(xiàn)代的操作系統(tǒng),就必須支持虛擬存儲(chǔ)器,它是操作系統(tǒng)里非常重要的內(nèi)容。
2. ?地址轉(zhuǎn)換
目前最通用的虛擬內(nèi)存是基于分頁(page)的虛擬存儲(chǔ)器。虛擬地址空間以頁為單位劃分,典型的頁大小為4KB,相應(yīng)的物理地址也進(jìn)行同樣大小的劃分。由于歷史原因,物理地址空間中不叫做頁,而稱為frame,它和頁的大小必須相等。當(dāng)程序開始運(yùn)行時(shí),會(huì)將當(dāng)前需要的部分內(nèi)容從硬盤中搬移到物理內(nèi)存中,每次搬移的單位就是一個(gè)頁的大小。由于只有在需要時(shí)才將一個(gè)頁的內(nèi)容放到物理內(nèi)存中,這種方式就稱為demand page,它使處理器可以運(yùn)行比物理內(nèi)存更大的程序。
對(duì)于一個(gè)虛擬地址,VA[11:0]表示頁內(nèi)的位置,稱為page offset,VA剩余的部分用來表示哪個(gè)頁,也稱為VPN(Virtual Page Number)。相應(yīng)的,物理地址的PA[11:0]表示frame內(nèi)的位置,稱為frame offset,而PA剩余的部分表示哪個(gè)frame,稱為PFN(Physical Frame Number)。由于頁和frame的大小一樣,所以VA到PA的轉(zhuǎn)換實(shí)際上就是VPN到PFN的轉(zhuǎn)換,offset不需要變化。
2.1 ?單級(jí)頁表
在使用虛擬內(nèi)存的系統(tǒng)中,都是用一張表來存儲(chǔ)虛擬地址到物理地址(實(shí)際上是VPN到PFN)的對(duì)應(yīng)關(guān)系,這個(gè)表稱為頁表(Page Table,PT),也稱為轉(zhuǎn)換表(translation table)。這個(gè)表一般放在物理內(nèi)存中,使用虛擬地址來尋址,表格中被尋址到的內(nèi)容就是該虛擬地址對(duì)應(yīng)的物理地址。每個(gè)程序都有自己的頁表,為了指示程序的頁表在物理內(nèi)存中的位置,處理器中一般會(huì)有一個(gè)頁表寄存器(Page Table Register,PTR),用來存放當(dāng)前運(yùn)行程序的頁表在物理內(nèi)存中的起始地址。每次操作系統(tǒng)將一個(gè)程序調(diào)入物理內(nèi)存中執(zhí)行時(shí),會(huì)將寄存器PTR設(shè)置好。當(dāng)然,這種機(jī)制可以工作的前提是頁表位于物理內(nèi)存中一片連續(xù)的地址空間內(nèi)。
下圖表示如何使用PTR從物理內(nèi)存中定位到一個(gè)頁表,并使用虛擬地址來尋址頁表,從而找到對(duì)應(yīng)的物理地址。其實(shí),使用PTR和虛擬地址來尋址,相當(dāng)于用它們兩個(gè)共同組成一個(gè)地址,來尋址物理內(nèi)存。
圖中每個(gè)頁的大小是4K,使用PTR和虛擬地址共同來尋址,找到對(duì)應(yīng)的表項(xiàng)(entry),當(dāng)表項(xiàng)對(duì)應(yīng)的valid為1時(shí),表示這個(gè)虛擬地址所在的4KB空間已經(jīng)被OS映射到物理內(nèi)存中,可以直接從物理內(nèi)存中找到這個(gè)虛擬地址對(duì)應(yīng)的數(shù)據(jù)。這時(shí)訪問當(dāng)前頁內(nèi)任意的地址,就是訪問物理內(nèi)存中被映射的那個(gè)4KB的空間了。如果被尋址的表項(xiàng)的valid是0,表示這個(gè)虛擬地址對(duì)應(yīng)的4KB空間還沒有被操作系統(tǒng)映射到物理內(nèi)存,此時(shí)就產(chǎn)生Page Fault類型的異常,需要操作系統(tǒng)從更下一級(jí)的存儲(chǔ)器(例如硬盤或閃存)將這個(gè)頁對(duì)應(yīng)的4KB內(nèi)容搬移到物理內(nèi)存。
通過頁表進(jìn)行地址轉(zhuǎn)換
圖中使用了32位的虛擬地址,頁表在物理內(nèi)存中的起始地址用PTR來指示。虛擬地址的尋址空間是2^32字節(jié),即4GB;物理地址的尋址空間是2^30字節(jié),即1GB。在頁表中的一個(gè)表項(xiàng)(entry)能夠映射4KB的大小,為了能映射整個(gè)4GB的空間,需要表項(xiàng)的個(gè)數(shù)應(yīng)該是4GB/4KB=1M,也就是2^20,因此需要20位來尋址。也就是說32位的虛擬地址分成兩部分,低12bit用來尋址一個(gè)頁內(nèi)的內(nèi)容,高20bit用來尋址哪個(gè)頁,因此真正尋址頁表只需要VPN就夠了。從頁表中找到的內(nèi)容也不是整個(gè)物理地址,而只是PFN。
需要注意,頁表的結(jié)構(gòu)不同于cache,頁表中包括了所有VPN的映射關(guān)系,所以可以直接用VPN對(duì)頁表進(jìn)行尋址,而不需要使用Tag。
可以采用很多方法來減少一個(gè)進(jìn)程的頁表對(duì)于存儲(chǔ)空間的需求,最常用的是多級(jí)頁表(Hierarchical Page Table),可以減少頁表對(duì)于物理存儲(chǔ)空間的占用,而且非常容易使用硬件實(shí)現(xiàn)。與之對(duì)應(yīng),本節(jié)所講述的頁表稱為單級(jí)頁表(Single Page Table),也稱為線性頁表(Linear Page Table)。
2.2 ?多級(jí)頁表
將一個(gè)4MB的線性頁表劃分為若干個(gè)更小的頁表,稱它們?yōu)樽禹摫?,處理器在?zhí)行進(jìn)程的時(shí)候,不需要一下子把整個(gè)線性頁表都放入物理內(nèi)存中,而是根據(jù)需求逐步地放入這些子頁表。而且,這些子頁表不需要占用連續(xù)的物理內(nèi)存空間。也就是說,相鄰的子頁表可以放在物理內(nèi)存中不連續(xù)的位置,這樣也提高了物理內(nèi)存的利用效率。但是,由于所有的子頁表是不連續(xù)地放在物理內(nèi)存中,所以依舊需要一個(gè)表,來記錄每個(gè)子頁表在物理內(nèi)存中存儲(chǔ)的位置,稱這個(gè)表格為第一級(jí)頁表(Level1 Page Table),而那些子頁表為第二級(jí)頁表(Level2 Page Table)。
兩級(jí)頁表
這樣,要得到一個(gè)虛擬地址對(duì)應(yīng)的數(shù)據(jù),先訪問第一級(jí)頁表,得到第二級(jí)頁表的基地址,再去第二級(jí)頁表得到對(duì)應(yīng)的物理地址,然后就可以在物理內(nèi)存中取出相應(yīng)的數(shù)據(jù)。
例如,對(duì)于一個(gè)32位虛擬地址、頁大小為4KB的系統(tǒng),如果采用線性頁表,則頁表中表項(xiàng)個(gè)數(shù)為2^20,將其等分為2^10等份,每個(gè)等份就是一個(gè)第二級(jí)頁表,共有1024個(gè)第二級(jí)頁表,對(duì)應(yīng)著第一級(jí)頁表的1024個(gè)表項(xiàng)。也就是說,第一級(jí)頁表需要10位地址來進(jìn)行尋址。每個(gè)二級(jí)頁表中,表項(xiàng)個(gè)數(shù)為1024,也需要10位地址來尋址。
下圖中,一個(gè)頁表中的表項(xiàng)簡(jiǎn)稱為PTE,當(dāng)操作系統(tǒng)創(chuàng)建一個(gè)進(jìn)程時(shí),就在物理內(nèi)存中為這個(gè)進(jìn)程找到一個(gè)連續(xù)的4KB空間,存在這個(gè)進(jìn)程的第一級(jí)頁表,并且將第一級(jí)頁表在物理內(nèi)存中起始地址放到PTR寄存器中,在ARM是TTB寄存器,X86是CR3寄存器等。隨著這個(gè)進(jìn)程的進(jìn)行,操作系統(tǒng)會(huì)逐步在物理內(nèi)存中創(chuàng)建第二級(jí)頁表,每次創(chuàng)建一個(gè)第二級(jí)頁表,操作系統(tǒng)就要將它的起始地址放到第一級(jí)頁表對(duì)應(yīng)的表項(xiàng)中。
使用兩級(jí)頁表進(jìn)行地址轉(zhuǎn)換
在很多硬件實(shí)現(xiàn)Page Table Walk的處理器中,都采用了多級(jí)頁表的結(jié)構(gòu)。Page Table Walk是指當(dāng)發(fā)生TLB缺失時(shí),需要從頁表中找到對(duì)應(yīng)的映射關(guān)系并將其寫回到TLB的過程。
使用這種多級(jí)頁表結(jié)構(gòu),每一級(jí)的頁表都需要存儲(chǔ)在物理內(nèi)存中,因此要得到一個(gè)虛擬地址對(duì)應(yīng)的數(shù)據(jù),需要多次訪問物理內(nèi)存。顯然,這個(gè)過程消耗的時(shí)間是很長。對(duì)于一個(gè)二級(jí)頁表,需要訪問兩次物理內(nèi)存,才能得到虛擬地址對(duì)應(yīng)的物理地址,然后還需要訪問一次物理內(nèi)存得到數(shù)據(jù),因此要得到虛擬地址對(duì)應(yīng)的數(shù)據(jù),共需要訪問三次物理內(nèi)存。
使用虛擬存儲(chǔ)器的優(yōu)點(diǎn)總結(jié):
讓每個(gè)程序都有獨(dú)立的地址空間。
引入虛擬地址到物理地址的映射,為物理內(nèi)存的管理帶來方便,可以更靈活地對(duì)其進(jìn)行分配和釋放,在虛擬內(nèi)存上連續(xù)的地址空間可以映射到物理內(nèi)存上不連續(xù)的空間。
在處理器中如果存在多個(gè)進(jìn)程,為這些進(jìn)程分配的物理內(nèi)存之和可能大于實(shí)際可用的物理內(nèi)存,虛擬存儲(chǔ)器的管理使得這種情況下各個(gè)進(jìn)程仍能夠正常運(yùn)行,此時(shí)為各個(gè)進(jìn)程分配的只是虛擬存儲(chǔ)器的頁,這些頁可能存在物理內(nèi)存中,也可能臨時(shí)存在于更下一級(jí)的硬盤中,在硬盤中這部分空間被稱為swap空間。當(dāng)物理內(nèi)存不夠用時(shí),將物理內(nèi)存中一些不常用的頁保存到硬盤上的swap空間。因此處理器等效可以使用的物理內(nèi)存的總量是物理內(nèi)存的大小 + 硬盤中swap空間的大小。
利用虛擬存儲(chǔ)器,可以管理每一個(gè)頁的訪問權(quán)限。從硬件角度,單純的物理內(nèi)存本身不具有各種權(quán)限的屬性,它的任何地址都可以被讀寫,而操作系統(tǒng)則要求在物理內(nèi)存中實(shí)現(xiàn)不同的訪問權(quán)限。例如一個(gè)進(jìn)程的代碼段(text)一般不能被修改,而數(shù)據(jù)段(data)一般可讀可寫。這些權(quán)限的管理通過頁表來實(shí)現(xiàn),在頁表中設(shè)置每個(gè)頁的屬性,操作系統(tǒng)和MMU可以控制每個(gè)頁的訪問權(quán)限。
3. ?TLB和Cache
3.1 ?TLB的設(shè)計(jì)
3.1.1 ?概述
對(duì)兩級(jí)頁表來說,需要訪問兩次物理內(nèi)存才可以得到虛擬地址對(duì)應(yīng)的物理地址(一次訪問第一級(jí)頁表,另一次訪問第二級(jí)頁表),而物理內(nèi)存的運(yùn)行速度相對(duì)于處理器是很慢的。此時(shí)可以借鑒Cache的設(shè)計(jì)理念,使用一個(gè)速度比較快的緩存,將頁表中最近使用的PTE緩存下來,因?yàn)樗鼈冊(cè)谝院罂赡芾^續(xù)使用,尤其對(duì)于取指令來說,考慮到程序本身的串行性,會(huì)順序地從一個(gè)頁內(nèi)取指令,將PTE緩存起來能夠加快一個(gè)頁內(nèi)4KB內(nèi)容的地址轉(zhuǎn)換速度。
由于歷史原因,緩存PTE的部件一般不叫Cache,而叫TLB (Translation Lookaside buffer),在TLB中存儲(chǔ)了頁表中最近使用過的PTE。本質(zhì)上,TLB就是頁表的Cache。但是TLB不同于一般的cache,它只有時(shí)間相關(guān)性(Temporal Locality),也就是現(xiàn)在訪問的頁,很有可能在以后繼續(xù)被訪問。至于空間相關(guān)性(Spatial Locality),TLB沒有明顯的規(guī)律,因?yàn)樵谝粋€(gè)頁內(nèi)有很多情況,都可能使程序跳轉(zhuǎn)到其他不相鄰的頁中取指令或數(shù)據(jù),也就是說,雖然當(dāng)前在訪問一個(gè)頁,但未必會(huì)訪問它相鄰的頁。
TLB本質(zhì)上是Cache,有三種組織方法:直接相連(direct mapped)、組相連(set associative)和全相連(fully associative)?,F(xiàn)代的處理器,很多都采用兩級(jí)TLB,第一級(jí)TLB分為指令TLB(I-TLB)和數(shù)據(jù)TLB(D-TLB),一般采用全相連的方式;第二級(jí)TLB是指令和數(shù)據(jù)共享,一般采用組相連的方式,這種設(shè)計(jì)方法和多級(jí)Cache一樣。
TLB是頁表的Cache,所以TLB的內(nèi)容完全來自于頁表,下圖為一個(gè)全相連的TLB,從處理器送出的虛擬地址首先送到TLB中進(jìn)行查找,如果TLB對(duì)應(yīng)的內(nèi)容是有效的(即valid位為1),則表示TLB命中,可以直接使用從TLB得到的物理地址來尋址物理內(nèi)存;如果TLB缺失(即valid位為0),那么需要訪問物理內(nèi)存中的頁表,此時(shí)有如下兩種情況:
(1) 在頁表中找到的PTE是有效的,即這個(gè)虛擬地址所屬的頁存在于物理內(nèi)存中,那么就可以直接從頁表中找到對(duì)應(yīng)的物理地址,使用它來尋址物理內(nèi)存從而得到需要的數(shù)據(jù),同時(shí)將頁表中的這個(gè)PTE寫回到TLB中,供以后使用。
(2) 在頁表中找到的PTE是無效的,即這個(gè)虛擬地址所屬的頁不在物理內(nèi)存中,造成這種現(xiàn)象的原因很多,例如這個(gè)頁在以前沒有被使用過,或者這個(gè)頁已經(jīng)被交換到了硬盤中等,此時(shí)就應(yīng)該產(chǎn)生Page Fault類型的異常,通知操作系統(tǒng)來處理這個(gè)情況,操作系統(tǒng)需要從硬盤中將相應(yīng)的頁搬移到物理內(nèi)存中,將它在物理內(nèi)存中的首地址放到頁表內(nèi)對(duì)應(yīng)的PTE中,并將這個(gè)PTE的內(nèi)容寫到TLB中。
TLB的內(nèi)容
圖中,因?yàn)門LB采用了全相連的方式,所以相比頁表,多了一個(gè)Tag的項(xiàng),它保存了虛擬地址的VPN,用來對(duì)TLB進(jìn)行匹配查找,TLB中其它的項(xiàng)完全來自于頁表,每當(dāng)發(fā)生TLB缺失時(shí),將PTE從頁表中搬移到TLB內(nèi)。
現(xiàn)代處理器都支持大小可變的頁,由操作系統(tǒng)來管理。根據(jù)不同應(yīng)用特點(diǎn)選用不同大小的頁,可以最大限度利用TLB中有限的空間,同時(shí)又不至于在頁內(nèi)產(chǎn)生更多的碎片。為了支持這種特性,在TLB中需要相應(yīng)的位進(jìn)行管理,例如MIPS處理器的TLB中,有一個(gè)12位的Pagemask項(xiàng),它用來指示當(dāng)前被映射的頁的大小。
采用不同大小的頁,在尋址TLB時(shí),進(jìn)行的地址比較也是不同的,對(duì)于1MB大小的頁,只需要將VA[31:20]作為Tag,參與地址比較就可以了,虛擬地址剩余的20位將用來尋址頁的內(nèi)部。不僅如此,對(duì)TLB的尋址還受到其他內(nèi)容的影響,例如ASID和Global位。
3.1.2 ?TLB缺失
當(dāng)一個(gè)虛擬地址查找TLB,發(fā)現(xiàn)需要的內(nèi)容不在其中時(shí),就發(fā)生了TLB缺失(miss),由于TLB本身的容量很小,所以TLB缺失發(fā)生的頻率比較高,很多情況下都可以發(fā)生TLB缺失,主要有以下幾種:
(1) 虛擬地址對(duì)應(yīng)的頁不在物理內(nèi)存中,此時(shí)頁表中沒有對(duì)應(yīng)的PTE,而TLB是頁表的cache,自然TLB中也不可能有。
(2) 虛擬地址對(duì)應(yīng)的頁在物理內(nèi)存中,因此頁表中有對(duì)應(yīng)的PTE,但這個(gè)PTE還沒有放到TLB中,這種情況也經(jīng)常發(fā)生,畢竟TLB的內(nèi)容遠(yuǎn)小于頁表。
(3) 虛擬地址對(duì)應(yīng)的頁在物理內(nèi)存中,因此頁表中有對(duì)應(yīng)的PTE,這個(gè)PTE也曾存在于TLB中,但后來被替換出去了,現(xiàn)在這個(gè)頁又重新使用了,此時(shí)這個(gè)PTE就存在于頁表中,但不在TLB內(nèi)。
其實(shí),(2)和(3)兩種情況是在說同一件事情,即虛擬地址和物理地址的映射關(guān)系存在于頁表中,而不存在于TLB中,此時(shí)只需要從頁表中就可以找到這個(gè)映射關(guān)系,因此它們的處理時(shí)間比情況(1)要短。
解決TLB缺失的本質(zhì)就是要從頁表中找到對(duì)應(yīng)的映射關(guān)系,并將其寫回到TLB內(nèi),這個(gè)過程稱為Page Table Walk,可以使用硬件狀態(tài)機(jī)來完成,也可以使用軟件來做,它們各有優(yōu)缺點(diǎn),各自工作流程如下:
(1) 軟件實(shí)現(xiàn)Page Table Walk。軟件實(shí)現(xiàn)可以保證最大的靈活性,但一般也需要硬件配合,來減少工作量。一旦發(fā)現(xiàn)TLB缺失,硬件把產(chǎn)生TLB缺失的虛擬地址保存到一個(gè)特殊寄存器中,同時(shí)產(chǎn)生一個(gè)TLB缺失類型的異常,在異常處理程序中,軟件使用保存在特殊寄存器當(dāng)中的虛擬地址去尋址物理內(nèi)存中的頁表,找到對(duì)應(yīng)的PTE,并寫回到TLB中,很顯然,處理器需要支持直接操作TLB的指令,如寫TLB指令和讀TLB指令等。對(duì)于超標(biāo)量處理器,對(duì)異常處理時(shí),會(huì)將流水線中所有的指令抹掉,這樣會(huì)產(chǎn)生一些性能上缺失,但可以實(shí)現(xiàn)靈活的TLB替換算法,MIPS和Alpha處理器一般采用這種方法。
(2) 硬件實(shí)現(xiàn)Page Table Walk。硬件實(shí)現(xiàn)一般由MMU完成。TLB缺失時(shí),MMU自動(dòng)使用當(dāng)前的虛擬地址去尋址物理內(nèi)存中的頁表,多級(jí)頁表的最大優(yōu)點(diǎn)就是容易使用硬件進(jìn)行查找,只需要使用一個(gè)狀態(tài)機(jī)逐級(jí)進(jìn)行查找就可以,如果從頁表中找到的PTE是有效的,那么將它寫回到TLB,這個(gè)過程全部由硬件自動(dòng)完成。如果MMU發(fā)現(xiàn)查找到的PTE是無效的,那么就只能產(chǎn)生Page Fault類型的異常,由操作系統(tǒng)來處理整個(gè)情況。使用硬件處理TLB缺失更適合超標(biāo)量處理器,它不需要打斷流水線,因此性能會(huì)好一點(diǎn),但是需要操作系統(tǒng)保證頁表已經(jīng)在物理內(nèi)存中建立好了,并且操作系統(tǒng)需要將頁表的基地址預(yù)先寫到處理器內(nèi)部的寄存器中(例如PTR),這樣才能保證硬件可以正確地尋址頁表,ARM、PowerPC和x86處理器都采用這種方法。
3.1.3 ?TLB的寫入
當(dāng)一個(gè)頁從硬盤搬移到物理內(nèi)存之后,操作系統(tǒng)需要知道這個(gè)頁中的內(nèi)容在物理內(nèi)存中是否被改變過。如果沒有被改變過,當(dāng)這個(gè)頁需要被替換時(shí)可以直接進(jìn)行覆蓋,因?yàn)榭偰軓挠脖P中找到這個(gè)頁的備份;如果這個(gè)頁的內(nèi)容在物理內(nèi)存中被修改過(例如store指令的地址落在了這個(gè)頁內(nèi)),那么在硬盤中存儲(chǔ)的頁就過時(shí)了,在物理內(nèi)存中的這個(gè)頁要被替換時(shí),需要先將它從物理內(nèi)存中寫回到硬盤,因此需要在頁表中,對(duì)每個(gè)被修改的頁加以標(biāo)記,稱為臟狀態(tài)位(dirty),當(dāng)物理內(nèi)存中的一個(gè)頁要被替換時(shí),首先檢查它在頁表中對(duì)應(yīng)PTE的臟狀態(tài)位,如果為1,需要先將這個(gè)頁寫回到硬盤,然后才能將其覆蓋。
使用TLB作為頁表的緩存之后,處理器送出的虛擬地址會(huì)首先訪問TLB,如果命中,那么可以直接從TLB中得到物理地址,不需要再訪問頁表。執(zhí)行l(wèi)oad/store指令都會(huì)使 TLB中對(duì)應(yīng)的“使用位use”變?yōu)?1,表示這個(gè)頁中的某些數(shù)據(jù)最近被訪問過;如果是 store指令,還會(huì)使臟狀態(tài)位dirty也變?yōu)?,表示這個(gè)頁中的某些數(shù)據(jù)被改變了。但如果采用寫回(Write Back)的TLB,那么使用位use和臟狀態(tài)位dirty改變的信息并不會(huì)馬上從TLB中寫回到頁表,只有等到TLB中的一個(gè)表項(xiàng)要被替換的時(shí)候,才會(huì)將它對(duì)應(yīng)的信息寫回到頁表中,這會(huì)給操作系統(tǒng)進(jìn)行頁表替換帶來問題,因?yàn)轫摫碇杏涗浀臓顟B(tài)位(use和dirty)可能是過時(shí)的。一種比較容易的解決辦法就是操作系統(tǒng)在Page Fault發(fā)生時(shí),首先將TLB中的內(nèi)容寫回到頁表,然后就可以根據(jù)頁表中的信息進(jìn)行后續(xù)處理了。
實(shí)際上,操作系統(tǒng)完全可以認(rèn)為被TLB記錄的所有頁都是需要被使用的,這些頁在物理內(nèi)存中不能夠被替換。操作系統(tǒng)可以使用一些辦法來記錄頁表中哪些PTE被放到了TLB中來實(shí)現(xiàn)。
如果在系統(tǒng)中使用了D-Cache,那么物理內(nèi)存中每個(gè)頁的最新內(nèi)容都可能存在D-Cache中,要將這個(gè)頁的內(nèi)容寫回到硬盤,首先需要確認(rèn)D-Cache中是否保留著這個(gè)頁的數(shù)據(jù)。因此在進(jìn)行頁表替換時(shí),操作系統(tǒng)就必須有能力從D-Cache中找出這個(gè)頁的內(nèi)容,并將其寫回到物理內(nèi)存中。
3.1.4 ?對(duì)TLB進(jìn)行控制
如果由于某些原因?qū)е乱粋€(gè)頁的映射關(guān)系在頁表中不存在了,那么它在TLB中也不應(yīng)該存在,而操作系統(tǒng)在一些情況下,會(huì)把某些頁的映射關(guān)系從頁表中抹掉,例如:
(1) 當(dāng)一個(gè)進(jìn)程結(jié)束時(shí),這個(gè)進(jìn)程的指令(code)、數(shù)據(jù)(data)和堆棧(stack)所占據(jù)的頁表就需要變?yōu)闊o效,這樣就釋放了這個(gè)進(jìn)程占據(jù)的物理內(nèi)存空間。但是,此時(shí)在I-TLB中可能存在這個(gè)進(jìn)程的程序?qū)?yīng)的PTE,在D-TLB中可能還存在著這個(gè)進(jìn)程的數(shù)據(jù)和堆棧的PTE,此時(shí)需要將I-TLB和D-TLB中和這個(gè)進(jìn)程相關(guān)的所有內(nèi)容置為無效,如果沒有使用ASID,最簡(jiǎn)單的做法就是將I-TLB和D-TLB中的全部?jī)?nèi)容都置為無效,這樣保證新的進(jìn)程可以使用一個(gè)干凈的TLB;如果實(shí)現(xiàn)了ASID,只需將這個(gè)進(jìn)程對(duì)應(yīng)的內(nèi)容在TLB中置為無效就可以了。
(2) 當(dāng)一個(gè)進(jìn)程占用的物理內(nèi)存過大時(shí),操作系統(tǒng)可能會(huì)將這個(gè)進(jìn)程中的一部分不經(jīng)常使用頁寫回到硬盤中,這些頁在頁表中對(duì)應(yīng)的映射關(guān)系也應(yīng)該置為無效,此時(shí)也需要將I-TLB和D-TLB中對(duì)應(yīng)的內(nèi)容置為無效,但是,一般操作系統(tǒng)會(huì)盡量避免將存在于TLB中的頁置為無效,因?yàn)檫@些頁在以后很可能會(huì)被繼續(xù)使用。
因此,抽象出來,對(duì)TLB的管理需要包括的內(nèi)容有如下幾點(diǎn):
能夠?qū)-TLB和D-TLB的所有表項(xiàng)(entry)置為無效;
能夠?qū)-TLB和D-TLB中某個(gè)ASID對(duì)應(yīng)的所有表項(xiàng)置為無效;
能夠?qū)-TLB和D-TLB中某個(gè)VPN對(duì)應(yīng)的表項(xiàng)置為無效;
不同的處理器有著不同的方法來對(duì)TLB進(jìn)行管理。在ARM處理器中,使用系統(tǒng)控制協(xié)處理器(ARM稱之為CP15)中的寄存器對(duì)TLB進(jìn)行控制,因此處理器只需要使用訪問協(xié)處理器的指令(MCR和MRC)來向CP15中對(duì)應(yīng)的寄存器寫入相應(yīng)的值,就可以對(duì)TLB進(jìn)行操作。