本文以Cortex-A53处理器为例,通过访问 处理器中的内部存储单元(tag RAM和dirty RAM),来读取cache line 中的MOESI信息。
Cortex-A53提供了一种通过读取一些系统寄存器,来访问Cache 和 TLB使用的一些内部存储单元的机制。这个功能可以探查出当缓存中的数据与主存中的数据不一致时存在的问题。
此外,A64模式和A32模式的读取方式不同:
当处理器处于A64模式时,先通过一些只写(write-only)寄存器来选择具体的cache line和内存地址,然后通过只读寄存器来读取具体的tag信息。下图为相关寄存器以及相关操作指令,需要注意的是,这些操作只在EL3时可用,如果在其他模式下使用这些指令,将会进入Undefined Instruction 异常。
当处理器处于A32模式下时,先通过一些只写(write-only)CP15寄存器来选择具体的cache line和内存地址,然后通过只读CP15寄存器来读取具体的tag信息。下图为相关寄存器以及相关操作指令,需要注意的是,这些操作只在EL3时可用,如果在其他模式下使用这些CP15指令,将会进入Undefined Instruction 异常。
接下来,本文以Cortex-A53的Data cache为例,读取其某个cache line的tag信息,其具体的步骤很简单,分为两步:
- 写入Data Cache Tag Read Operation Register,写入的内容为具体的Set和way信息,通过way index和set index来定位到想要读取的cache line。
- 读取相应的 Data Register 0 和 Data Register 1寄存器,通过对Data Register寄存器里面的数据进行解码,来获取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结构,其cache line大小也为64 bytes,从图中可知,一个VA可以被分成几个部分:Tag,Set index,word index以及byte index。其中Set index = VA[13:6]。
在另一个实例中,32KB大小的4-way组相连data cache,cache line大小为32 bytes,其Set index = VA[12:5]:
Cortex-A53的Data cache为4-way 组相连结构。假设其为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).
来计算出Set index的范围:Set index = VA[12:6]。
由于是4-way 组相连结构,cache line 可以存在与任意一个way中,所以我们的cache way可能为0,1,2,3中任意一个数字。
求得了set和way的index后,需要对其进行编码,然后写入到Data Cache Tag Read Operation Register寄存器中。其编码规则如下图所示,只需将Set和way的值写入对应的bit中即可,其中Rd[5:3]为cahche double word数据的偏移量,由于本次示例是读取tag信息,所以Rd[5:3]为0即可。
所以我们要写入Data Cache Tag Read Operation Register的Rd的值可以通过以下代码获取:
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的值写入,假设Rd为R0:
MCR p15, 3, r0, c15, c2, 0 ; r0 = get_Rd_data(VA,way_num)
Step2:读取Data Register 1和Data Register 0数据并解码
将Set/way信息写入Data Cache Tag Read Operation Register 后,相当于选择了想要操作的cache line,接下来我们将读取Data Register 1和Data Register 0的数据来获取该cache line里的tag信息,除了tag信息外,我们还可以从Data Register 1和Data Register 0两个寄存器中获取:
- MOESI 状态信息
- outer内存属性
- valid 信息
可获得的信息具体见下图:
需要注意的是,如果是想获取MOESI状态信息,则需要两个寄存器配合使用,即读取Data Register 0 [1:0]以及Data Register 1 [30:29] ,Data Register 0 [1:0]里的为来自Dirty RAM的部分状态信息,Data Register 1 [30:29]里的为来自tag RAM的部分MOESI信息,
其具体的组合见下图:
比如读取到的Data Register 0 [1:0]为1,以及Data Register 1 [30:29]也为1,根据上图的组合关系,可知当前cache line的MOESI状态为 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
作者:lvy
文章来源:Arm精选
推荐阅读
欢迎关注ARM精选专栏, 欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。