本文以Cortex-A53處理器為例,通過訪問 處理器中的 內(nèi)部存儲單元 (tag RAM和dirty RAM),來讀取cache line 中的MOESI信息。
Cortex-A53提供了一種通過讀取一些系統(tǒng)寄存器,來訪問Cache 和 TLB使用的一些內(nèi)部存儲單元的機(jī)制。這個功能可以探查出當(dāng)緩存中的數(shù)據(jù)與主存中的數(shù)據(jù)不一致時(shí)存在的問題。
此外,A64模式和A32模式的讀取方式不同:
當(dāng)處理器處于A64模式時(shí),先通過一些只寫(write-only)寄存器來選擇具體的cache line和內(nèi)存地址,然后通過只讀寄存器來讀取具體的tag信息。下圖為相關(guān)寄存器以及相關(guān)操作指令,需要注意的是,這些操作只在EL3時(shí)可用,如果在其他模式下使用這些指令,將會進(jìn)入U(xiǎn)ndefined Instruction 異常。
當(dāng)處理器處于A32模式下時(shí),先通過一些只寫(write-only)CP15寄存器來選擇具體的cache line和內(nèi)存地址,然后通過只讀CP15寄存器來讀取具體的tag信息。下圖為相關(guān)寄存器以及相關(guān)操作指令,需要注意的是,這些操作只在EL3時(shí)可用,如果在其他模式下使用這些CP15指令,將會進(jìn)入U(xiǎn)ndefined Instruction 異常。
接下來,本文以Cortex-A53的Data cache為例,讀取其某個cache line的tag信息,其具體的步驟很簡單,分為兩步:
- 寫入Data Cache Tag Read Operation Register,寫入的內(nèi)容為具體的Set和way信息,通過way index和set index來定位到想要讀取的cache line。
- 讀取相應(yīng)的 Data Register 0 和 Data Register 1寄存器,通過對Data Register寄存器里面的數(shù)據(jù)進(jìn)行解碼,來獲取tag 信息。其他信息,比如Data cache 的data信息,Instruction Cache的data或者tag信息,以及TLB的data信息,都可以用這種方式讀取得到。
Step1:將Set/way信息寫入Data Cache Tag Read Operation Register
首先,我們需要從一個虛擬地址(VA)中解析出Set index信息。
下圖為Cortex-A57的4-way組相連的32KB大小的data cache結(jié)構(gòu),其cache line大小也為64 bytes,從圖中可知,一個VA可以被分成幾個部分:Tag,Set index,word index以及byte index。其中Set index = VA[13:6]。
在另一個實(shí)例中,32KB大小的4-way組相連data cache,cache line大小為32 bytes,其Set index = VA[12:5]:
Cortex-A53的Data cache為4-way 組相連結(jié)構(gòu)。假設(shè)其為32KB,一個cache line的大小為64 bytes,我們就可以求出該data cache中有 32 KB / 64 B / 4 = 2^7 = 128個set(組),也就是說至少需要7個bit才能完整解析出具體的set index。如下圖所示,可以通過公式:
S = log2(Data cache size / 4).
來計(jì)算出Set index的范圍:Set index = VA[12:6]。
由于是4-way 組相連結(jié)構(gòu),cache line 可以存在與任意一個way中,所以我們的cache way可能為0,1,2,3中任意一個數(shù)字。
求得了set和way的index后,需要對其進(jìn)行編碼,然后寫入到Data Cache Tag Read Operation Register寄存器中。其編碼規(guī)則如下圖所示,只需將Set和way的值寫入對應(yīng)的bit中即可,其中Rd[5:3]為cahche double word數(shù)據(jù)的偏移量,由于本次示例是讀取tag信息,所以Rd[5:3]為0即可。
所以我們要寫入Data Cache Tag Read Operation Register的Rd的值可以通過以下代碼獲?。?/p>
unsigned int get_Rd_data(int * VA, way_num)
{
unsigned int set_way_index = VA | 0x1FC0; //get way index, VA[12:6]
set_way_index |= way_num < 30; //way_num could be 0,1,2,3
return set_way_index;
}
Rd中除了Set和way信息,其他值均為0,0x1FC0為VA[12:6]全為1的情況:
然后我們使用CP15寄存器將Rd的值寫入,假設(shè)Rd為R0:
MCR p15, 3, r0, c15, c2, 0 ; r0 = get_Rd_data(VA,way_num)
Step2:讀取Data Register 1和Data Register 0數(shù)據(jù)并解碼
將Set/way信息寫入Data Cache Tag Read Operation Register 后,相當(dāng)于選擇了想要操作的cache line,接下來我們將讀取Data Register 1和Data Register 0的數(shù)據(jù)來獲取該cache line里的tag信息,除了tag信息外,我們還可以從Data Register 1和Data Register 0兩個寄存器中獲?。?/p>
- MOESI 狀態(tài)信息
- outer內(nèi)存屬性
- valid 信息
可獲得的信息具體見下圖:
需要注意的是,如果是想獲取MOESI狀態(tài)信息,則需要兩個寄存器配合使用,即讀取Data Register 0 [1:0]以及Data Register 1 [30:29] ,Data Register 0 [1:0]里的為來自Dirty RAM的部分狀態(tài)信息,Data Register 1 [30:29]里的為來自tag RAM的部分MOESI信息,
其具體的組合見下圖:
比如讀取到的Data Register 0 [1:0]為1,以及Data Register 1 [30:29]也為1,根據(jù)上圖的組合關(guān)系,可知當(dāng)前cache line的MOESI狀態(tài)為 SharedDirty(O)。
示例代碼如下:
; step 1: write set index and way num into Data Cache Tag Read Operation Register
MCR p15, 3, r0, c15, c2, 0 ; r0 = get_Rd_data(VA,way_num)
; step 2: read Data Register 1 and Data Register 0
MCR p15, 3, r1, c15, c0, 0 ;r1 = Data Register 0
MCR p15, 3, r2, c15, c0, 1 ;r2 = Data Register 1
評論