armv8虛擬內存架構簡述

粗略看了一下armv8的虛擬內存的文檔。記錄一下,細節留待以後用到時再去細究。

程序在運行的時候使用的內存一般是虛擬內存,需要經過轉換才能接觸到物理內存。其中的底層支持就是硬件架構,現代架構都是支持硬件虛擬內存轉換的,一般就是說提供MMU。armv8架構作爲現代架構也不例外,但是不太一樣的是armv8架構支持兩級轉換:stage 1 和stage 2.

上圖包含了安全世界和非安全世界的東西,由於安全世界的東西過於複雜(主要是我也不懂),下面我們就忽略掉安全世界的東西。從上圖的第四條:VA->IPA->PA.很明顯,VA到PA可以最多經過兩次轉換,當然每個stage都是可以取消的,比如只有stage1 或只有stage2. 爲什麼需要兩級轉換呢?這是爲支持虛擬化而設置的,對於虛擬機內的程序一般需要經過兩級轉換才能訪問到主機的物理地址。所以一般地可以認爲,對於主機上跑的應用程序只需要一級轉換,而在虛擬機中的程序要經過兩級轉換。那怎樣控制這些內存轉換機制呢?

控制虛擬內存轉換的接口就是一系列寄存器,主要有:SCTLR_EL1,TCR_EL1, TCR_EL2, HCR_EL2,TTBR0_EL1, TTBR1_EL1, VTTBR_EL2。下面分別介紹一下。

SCTLR_EL1:頂級系統控制寄存器,其中Mbit控制MMU 對EL0和EL1的stage 1的使能,一旦置位1,第一級虛擬內存轉換就啓動了。次要一點的EEbit用來控制大小端控制。

SCTLR_EL2: Mbit控制MMU對EL2的stage1使能。

HCR_EL2: VMbit控制MMU對EL0和EL1的stage2轉換使能。

TCR_EL1: 轉換控制寄存器。 這個寄存器直接控制EL0和EL1的第一級虛擬內存轉換。

        TG1, 控制TTBR1_EL1的轉換顆粒大小, 也就是頁大小(page size)

        TG0: 控制TTBR0_EL1的轉換顆粒大小

        T0SZ: TTBR0_EL1的轉換內存區域的總位數爲2^(64-T0SZ),對於64位系統一般用到的地址不會是64位而是少於64位,             一 般是48位,比如T0SZ爲16,說明需要轉換的地址是48位。

        T1SZ: 控制TTBR1_EL1

VTCR_EL2: 虛擬化轉換控制寄存器,控制stage2的轉換。

        PS: 控制物理地址的大小,經過第二級轉換得到的地址一定是物理地址,這一項控制輸出的地址位數。

        TG0: 控制VTTBR_EL2的轉換顆粒大小。

        T0SZ: VTTBR_EL2的轉換地址的位數。

        SL0: 開始轉換的級數,這一位比較複雜,以後再講。

TTBR0_EL1,TTBR1_EL1存放EL1的第一層轉換頁表的起始地址, VTTBR_EL2存放第二曾轉換的頁表其實地址。當程序要訪問地址時MMU就會開始轉換,第一步就是從某一TTBR系列寄存器中查詢轉換頁面的起始地址。那麼TTRBx_EL1到底怎麼區分呢?請看下圖:

 

 

使用某個TTBRx_EL1的原則是需要轉換的地址落在哪個區域,從上圖看,對於64位系統,cpu的整個地址空間分爲三個部分,高地址低地址和空洞,落在低地址區域就用TTBR0_EL1,落在高地址區就使用TTBR1_EL1。高地址區的下限是2^(64-TCR_EL1.T1SZ),低地址的上限是2^(64-TCR_EL1.T0SZ)

stage1具體轉換的過程如下:

 

stage2的轉換:

 

上圖可以看SL0的作用,制定起始轉換層。地址轉換流程不是唯一的,原始地址的位數,中間地址位數,最終的物理地址位數,頁大小,幾層頁錶轉換,幾級轉換都是可以改變的,他們之間相互關係比較複雜。比如地址位數可以是48,40位,中間地址位數可以是44,42,40,頁大小有4k,16k,64k,這些又會影響到頁表層數。有興趣的可以看看文檔。

這裏記錄一個容易搞錯的問題:如果在一個虛擬機中需要使用兩級內存轉換,那麼對於第一次訪問的內存需要進行多少次轉換呢?假設兩級級轉換都是是四層。如果你的答案是4+4=8那麼恭喜你,你要漲知識了。實際是(4+1)*(4+1)-1=24.怎麼會是乘法呢?這裏就有一個容易忽略的陷阱,當MMU去訪問TTBR找到頁表存放的地址時他會發現這個地址並非真實的物理地址而是一箇中間地址IPA,MMU可不認識IPA他沒辦法找到這個IPA的位置,只能求助於stage2的轉換,拿到返回的物理地址去找stage1的0級頁表,接着0級頁表又給MMU一個IPA,MMU又得去求助stage2,於是每一次stage1的轉換都會進行全部的stage2轉換,最終轉換的次數就變成了乘法,至於公式爲啥長這樣就需要你仔細推敲一下了。這說明對於首次訪問地地址,arm的效率低的出奇,連內存訪問都這麼慢的的arm的虛擬化性能豈不是大打折扣。還好有TLB的幫助,若非如此恐怕arm的虛擬化可以消失了。

TLB確實是個好東西,他是MMU的緩存也就是把之前訪問過的從VA到PA的轉換結果給記錄下來方便下次再用,於是對於第二次訪問的內存就無需那麼多次轉換了,一次就可以得到PA。而且爲了提高訪問效率,arm也做了一番優化。一般TLB時很小的,那麼多的虛機那麼多的程序都要用TLB,一般的架構會在程序被調度後很可能改變TLB的內容,那麼以前用過的數據就沒了,比如程序1使用VA1->PA1,程序2使用VA1->PA2,那麼原來的那條就得改了,下次程序再執行的時候就得重新MMU了。但是arm可以避免這種情況,他再每個TLB前加了一個tag:ASID,用來標識每個程序,這樣因爲兩個程序的tag不一樣就不會產生衝突了。但是對虛擬情況又有不同,可能兩個虛機的裏面的程序擁有同樣的ASID那還得衝突,於是arm有加上一個VMID,用來標識每個虛機,於是VMID,ASID就能保證不同虛機同時利用TLB。這的確可以大大減少MMU的轉換次數,也就相應的提高了內存訪問的性能。

關於緩存部分暫時沒看到太重要的,頁表的屬性部分也是對內存轉換相當重要的,還有很多沒太注意的部分,比如內存的類型,留待以後再看。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章