虛擬化(9)-更快的地址翻譯(TLB)
在看文章前可以先看下這個,
吳海波:專欄的序。
先有個大概的認識會對閱讀有所幫助。
上一章我們看到分頁機制下的地址翻譯是有多慢,為了更快,os表示已經無能為力,這個時候就要找到os的好基友hardware來幫忙了。為什麼很慢?因為我們要訪問PT,而PT在內存裡面,訪問內存的幾百個時鐘週期實在是太長了,那我們把PT都放到MMU裡面吧,但是上一章已經說了,PT太大,mmu放不下,那好吧,我們退而求其次,借鑒緩存的方式,我把最近常用的PTE放在mmu中,這樣只需要在mmu中很小的空間,就可以提高地址翻譯的效率啦。
加入TLB後,我們的地址翻譯的流程如下:
VPN = (VirtualAddress & VPN_MASK) >> SHIFT//獲取虛擬頁號
(Success, TlbEntry) = TLB_Lookup(VPN)//判斷該頁號是否在TLB中
if (Success == True) // TLB Hit//如果TLB命中
if (CanAccess(TlbEntry.ProtectBits) == True)//並且PTE的訪問標記也是校驗通過
Offset = VirtualAddress & OFFSET_MASK//獲取地址的偏移量
PhysAddr = (TlbEntry.PFN << SHIFT) | Offset//獲取物理地址
Register = AccessMemory(PhysAddr)//訪問內存數據
else
RaiseException(PROTECTION_FAULT)//如果許可權校驗有問題,則報錯
else // TLB Miss,TLB中不包含這個虛擬頁號對應的PTE,那麼就只能按照老方法來做了。
PTEAddr = PTBR + (VPN * sizeof(PTE))
PTE = AccessMemory(PTEAddr)
if (PTE.Valid == False)
RaiseException(SEGMENTATION_FAULT)
else if (CanAccess(PTE.ProtectBits) == False)
RaiseException(PROTECTION_FAULT)
else
TLB_Insert(VPN, PTE.PFN, PTE.ProtectBits)//這裡表示緩存改PTE,這樣下次就不會再MISS了。
RetryInstruction()
TLB miss後由誰處理?
那麼如果TLB miss了,是os還是硬體來負責處理呢?對X86來說,是硬體,而對於別的一些架構的cpu來說則是os來處理。如果是硬體來處理,那麼硬體就需要知道PT在哪裡,比如Intel x86的架構,使用一個固定的多級頁表,和CR3寄存器來指向最近使用的PT。如果是OS來處理,在發生tlb miss的時候,硬體只需要產生一個異常就可以了。不過需要注意的是,和其他的一些system call不一樣,這個tlb miss後的異常處理好後,需要執行發生異常的指令而不是下一條指令。另外要注意的是,os來處理tlb miss,要避免產生更多的tlb miss(比如你的處理程序不在內存中,還需要從disk載入,然後再緩存,然後。。。。。),當然避免的方式也有很多,比如tlb miss 的處理程序一直保存在內存中,或者保留一個tlb的條目專門保存處理程序的信息。使用os處理的首要好處就是靈活性,因為os可以在不改變硬體的情況下使用任何一種數據結構來實現頁表。另外就是簡單,當發生tlb miss 的時候硬體只需要一個異常就可以了。
TLB一般包括哪些信息?
讓我們更詳細地查看硬體TLB的內容。一個典型的TLB可能有32、64或128個條目,也就是所謂的全相連(fully associative)(其實這個是對緩存結構的一種劃分,還有各種其他的類型,在高速緩存中應用較多)。基本上,這意味著任何給定的翻譯都可以在TLB中的任何位置,硬體將並行搜索整個TLB以找到所需的轉換(快的飛起啊)。TLB條目可能如下所示:
VPN | PFN | other bits
VPN和PFN這個就不用說了,肯定是要有的,不然虛擬和物理就連接不起來了。更有趣的是「other bits」。例如,TLB通常具有有效位,該有效位表示該條目是否有效。同樣常見的是保護位,其確定頁面如何可以被訪問(就像頁表中一樣)。例如,代碼頁可以標記為「讀取」和「執行」,而堆頁面可能被標記為「讀取」,並且寫。還可以有一些其它欄位,包括地址空間標識符(address-space identifier)、臟位(dirty bit)等等。
TLB怎麼處理進程切換?
因為PT的信息在process是不共享的,所以當process切換為新的時候,老的tlb緩存就不準了。一種方式是在上下文切換的時候清空原有的tlb,另外一種是給每個process一個編號,就像PID一樣,我們稱為address space identifier (ASID),不過這個值比PID要小(比如PID是32位,ASID是8位)
TBL的替換策略是什麼?
當tlb中的條目存儲滿了,再次發生tlb miss就需要替換老的。這裡給出2種策略,一種是最近沒有使用的條目替換掉,一種是隨機選擇條目進行替換。隨機的好處是可以避免第一種策略的一個弊端。比如tlb可以存儲n個條目,但是一個循環是在n+1個條目間運行,那麼就會出現tlb全部miss,但是隨機替換就不會。
一個真實的TLB條目是什麼樣的?