Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解

 Cache Maintenance-关于cache 清除(invalidate)和清理(clean)操作的基础知识

 对于cache清理清除操作不熟悉的同学可以先看看上面相关的基础知识。

目录

1,代码解析

2,代码逐行详解

通过CLIDR_EL1获取可操作的缓存级别数

 CLIDR_EL1寄存器

 通过CSSELR_EL1来指定需要操作的cache level和type

 通过CCSIDR_EL1获取缓存的way 和 set 数量

将level number 、way number以及set number融合到一个寄存器

 使用循环和递减操作进行逐个way、逐个set和逐个level的清理清除缓存

3,附加内容

ARMv7中关于Cache Maintenance操作的CP15指令

CLZ指令


代码为官方文档中示例代码:

DEN0024A_v8_architecture_PG.pdf

先直接上代码:

MRS X0, CLIDR_EL1 
AND W3, W0, #0x07000000 // Get 2 x Level of Coherence 
LSR W3, W3, #23 
CBZ W3, Finished 
MOV W10, #0              // W10 = 2 x cache level 
MOV W8, #1               // W8 = constant 0b1
Loop1: 
ADD W2, W10, W10, LSR #1 // Calculate 3 x cache level 
LSR W1, W0, W2           // extract 3-bit cache type for this level
AND W1, W1, #0x7 
CMP W1, #2 
B.LT Skip                // No data or unified cache at this level
MSR CSSELR_EL1, X10      // Select this cache level 
ISB                      // Synchronize change of CSSELR
MRS X1, CCSIDR_EL1       // Read CCSIDR
ADD W2, W2, #4           // W2 = log2(linelen)-4 
AND W2, W1, #7           // W2 = log2(linelen)
                               
UBFX W4, W1, #3, #10     // W4 = max way number, right aligned 
CLZ W5, W4               /* W5 = 32-log2(ways), bit position of way in DC operand */
LSL W9, W4, W5           /* W9 = max way number, aligned to position in DC operand */
LSL W16, W8, W5          // W16 = amount to decrement way number per iteration
Loop2: 
UBFX W7, W1, #13, #15    // W7 = max set number, right aligned 
LSL W7, W7, W2           /* W7 = max set number, aligned to position in DC operand */
LSL W17, W8, W2          // W17 = amount to decrement set number per iteration 
Loop3: 
ORR W11, W10, W9         // W11 = combine way number and cache number
ORR W11, W11, W7         // and set number for DC operand
DC CSW, X11              // Do data cache clean by set and way
SUBS W7, W7, W17         // Decrement set number
B.GE Loop3
SUBS X9, X9, X16         // Decrement way number
B.GE Loop2
Skip: 
ADD W10, W10, #2         // Increment 2 x cache level
CMP W3, W10 
DSB                      /* Ensure completion of previous cache maintenance operation */
B.GT Loop1

Finished:

一,代码解析

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第1张图片

 整个程序的流程总结如下:

  1. 读取CLIDR_EL1寄存器,获取缓存级别数(level number),也就是可以操作的缓存总共有多少个级别
  2. 写入CSSELR_EL1寄存器,选择需要操作的寄存器级别以及类型
  3. 读取CCSIDR_EL1寄存器,获取对应寄存器的way number 和 set number
  4. 根据获取的level number,way number以及set number,使用循环,逐个level,逐个way以及逐个way对cache line进行清理清除操作

要获取指定缓存的level number,way number以及set number等信息,依赖于对CLIDR、CSSELR以及CCSIDR三个寄存器的读写操作。

相关寄存器的详解参考文章:

关于cache maintenance 操作的四个寄存器(CTR,CLIDR,CSSELR,CCSIDR)解析

二,代码逐行详解

1,通过CLIDR_EL1获取可操作的缓存级别数

MRS X0, CLIDR_EL1            //读取CLIDR_EL1的数据到X0
AND W3, W0, #0x07000000 // 读取X0的[26:24]字段到W3,此字段为LoC,表示可操作的总的级别数 
LSR W3, W3, #23                 // 算术右移23位,注意不是24位,所以此时W3中保存的结果应该是cache level number 的2倍
CBZ W3, Finished                // 如果可操作的cache level数为0,说明没有需要清理清除的cache,直接跳转到程序结束
MOV W10, #0              // W10为cache level 的步进值 
MOV W8, #1               // W8为常数1 

 0x07000000的二级制编码

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第2张图片

 CLIDR_EL1寄存器:Get cache level and type

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第3张图片

  •  LoCthe last level of cache that must be cleaned or invalidated
  •  Ctype字段解析

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第4张图片

 2,通过CSSELR_EL1来指定需要操作的cache level和type

 Loop1: 
ADD W2, W10, W10, LSR #1           // W2 = W10 + W10 / 2,联系上下文可知:W10的取值为:0,2,4,...,所以W2的取值为0,3,6,...,
LSR W1, W0, W2           // W2为3的倍数,是为了方便取对应level的Ctype
AND W1, W1, #0x7        // 取出对应的Ctype,Ctype字段为3位
CMP W1, #2                   // 与2作比较,通过上面的Ctype字段解析可知,Ctype小于2时,只有指令缓存或者无缓存
B.LT Skip                        // 如果此level中没有数据缓存或者统一缓存,直接跳过,检查next level的缓存
MSR CSSELR_EL1, X10      // 使用X10(将W10扩充到64位)来选择需要操作的cache level和type,X10的取值为:0b0000,0b0010,0b0100,...,通过bit[0]来选择cache type,bits[3:1]来选择cache level

CSSELR_EL1寄存器:

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第5张图片

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第6张图片

 由于X10的取值为:0b0000,0b0010,0b0100,...。

所以InD字段始终为0,始终指定数据缓存或统一缓存为操作对象。

X10的[3:1]表示指定的cache level,右上可知,每次选择的cache level 为:0b000,0b001,0b010。从Level 1逐级递增。

 3,通过CCSIDR_EL1获取缓存的 way 和 set 数量

ISB                                       // 数据屏障,同步上下文
MRS X1, CCSIDR_EL1       // 读取CCSIDR到X1
ADD W2, W2, #4                 // W2 = log2(linelen)-4 
AND W2, W1, #7                 // W2 = log2(linelen),获取cache line size                          
UBFX W4, W1, #3, #10       // 抽取W1的[12:3],保存到W4,W4 = max way number, right aligned 
CLZ W5, W4                       // CLZ计算出需要左移的位数,使得W9的最高位为1,有效位为[31:22]
LSL W9, W4, W5           /* W9 = max way number, aligned to position in DC operand */
LSL W16, W8, W5          // W16 = 移位后的每次迭代中way递减的数值,该数值本来为1,由于原数值W4左移了W5位,所以递减的步进值也要左移W5位
Loop2: 
UBFX W7, W1, #13, #15    // W7 = max set number, right aligned ,抽取W1的[27:13],表示最大的set number

//原数值W7左移W2位,W2为line size,所以递减的步进值也需要左移W2位
LSL W7, W7, W2           /* W7 = max set number, aligned to position in DC operand */
LSL W17, W8, W2          // W17 = amount to decrement set number per iteration 

Get way and set number - 寄存器示例:

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第7张图片

此时的CCSIDR_EL1的值为0x7007E03A,对应的二进制编码:

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第8张图片

 CCSIDR_EL1的字段解析:

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第9张图片

由上可知:Level 1缓存的Data 缓存和Unified缓存中有0x40(64)个set,0x8(8)个way,每个cache line的大小为16个字(word)= 64 个字节(byte)

4,将level number 、way number以及set number融合到一个寄存器

Loop3: 
ORR W11, W10, W9         // W10中保存的是当前level number乘以2的值,W9中保存的是经过移位后的way number,通过“或”运算,将两个值融合到W11中
ORR W11, W11, W7         // 再将移位后的set numbe放入W11中

 W11此时包含了level number 、way number以及set number等三个数据,示意图如下:

在一个处理L1 Data Cache的示例中,cacheline size = 64 bytes,set number=128,way number=4 ,将这三个数据融合得到的寄存器值为:

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第10张图片

 使用clean或者invalidate指令对该寄存器的值进行操作,将会把在L1 Data Cacheway3,set127处的cache line进行clean或者invalidate。

在下一个小循环中,set number将会自减1,从127变成126:

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第11张图片

 同理,使用该寄存器值进行clean或invalidate,将会把L1 Data Cacheway3,set126处的cache line进行clean或者invalidate。

 5,使用循环和递减操作进行逐个way、逐个set和逐个level的清理清除缓存:

DC CSW, X11                    // 通过传入set number和way number 进行 data cache 的clean操作
SUBS W7, W7, W17         // 对 set number递减
B.GE Loop3                      // 确保当前way下的所有的set都被clean一遍
SUBS X9, X9, X16         // 对way number递减
B.GE Loop2                    // 确保所有的way都被clean一遍
Skip: 
ADD W10, W10, #2         // 对cache level递增,开始操作下一级cache
CMP W3, W10                //是否所有可用的cache都clean了一遍
DSB                                /* 数据缓存 */
B.GT Loop1                     //如果当前还有其他等级的cache未清理,继续跳转

以上循环的伪代码如下:

for(l = 1; l <= Levels; l++)

      for(w = Ways; w>0; w--)

          for(s = Sets; s >0; s--)

                 clean( level(l) + set(s) + way(w) )

经过这三个for循环,就可以遍历所有级别、所有way、以及所有set中的cache line。注意,无论是基于VA还是基于way和set的清理清除操作,操作对象的最小单位都是cache line。

  • The cache maintenance instructions by set/way can clean or invalidate, or both, the entirety of one or more levels of cache attached to a PE
  • Since the set/way instructions are performed only locally, there is no guarantee of the atomicity of cache maintenance between different PEs,even if those different PEs are each executing the same cache maintenance instructions at the same time.
  • Arm strongly discourages the use of set/way instructions to manage coherency in coherent systems,Arm强烈反对使用set/way指令来管理一致性系统中的一致性

  • maintenance by set/way does not happen on multiple PEs,

  • cannot be made to happen atomically for each address on each PE.set/way维护不会发生在多个PE上,也不能对每个PE上的每个地址进行原子化维护。

三,附加内容

ARMv7 / ARMv8 AArch32版本

MRC p15, 1, R0, c0, c0, 1 ; Read CLIDR into R0
ANDS R3, R0, #0x07000000
MOV R3, R3, LSR #23 ; Cache level value (naturally aligned)
BEQ Finished
MOV R10, #0
Loop1
ADD R2, R10, R10, LSR #1 ; Work out 3 x cache level
MOV R1, R0, LSR R2 ; bottom 3 bits are the Cache type for this level
AND R1, R1, #7 ; get those 3 bits alone
CMP R1, #2
BLT Skip ; no cache or only instruction cache at this level
MCR p15, 2, R10, c0, c0, 0 ; write CSSELR from R10
ISB ; ISB to sync the change to the CCSIDR
MRC p15, 1, R1, c0, c0, 0 ; read current CCSIDR to R1
AND R2, R1, #7 ; extract the line length field
ADD R2, R2, #4 ; add 4 for the line length offset (log2 16 bytes)
LDR R4, =0x3FF
ANDS R4, R4, R1, LSR #3 ; R4 is the max number on the way size (right aligned)
CLZ R5, R4 ; R5 is the bit position of the way size increment
MOV R9, R4 ; R9 working copy of the max way size (right aligned)
Loop2
LDR R7, =0x00007FFF
ANDS R7, R7, R1, LSR #13 ; R7 is the max num of the index size (right aligned)
Loop3
ORR R11, R10, R9, LSL R5 ; factor in the way number and cache number into R11
ORR R11, R11, R7, LSL R2 ; factor in the index number
MCR p15, 0, R11, c7, c10, 2 ; DCCSW, clean by set/way
SUBS R7, R7, #1 ; decrement the index
BGE Loop3
SUBS R9, R9, #1 ; decrement the way number
BGE Loop2
Skip
ADD R10, R10, #2 ; increment the cache number
CMP R3, R10
BGT Loop1
DSB
Finished

代码解析:

 Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第12张图片

 Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第13张图片

Cache clean 或 invalidate C语言版本 

仔细阅读代码可以发现,通过set/way来clean或者invalidate cache,只不过是在三重for循环下不断地执行同一条指令:

MCR p15, 0, R11, c7, c10, 2 

 因此我们可以直接用C语言写出这个for循环,在C语言中直接调用该指令即可:

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第14张图片

ARMv7中关于Cache Maintenance操作的CP15指令

ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第15张图片

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第16张图片 

 

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第17张图片 ARMv8中对应的指令ARM Cortex-A Series Programmer's Guide for ARMv8-A

 

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第18张图片 Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第19张图片

CLZ指令

Count Leading Zeros counts the number of binary zero bits before the first binary one bit in the value of the source register, and writes the result to the destination register.

统计源寄存器中第一次出现1 bit时,该位置之前0出现的次数,比如在32位寄存器下:

CLZ , 

比如R4 = 0x3:

Cache Maintenance-通过set/way对cache进行clean和invalidate操作-汇编代码详解_第20张图片

 从左至右,首次出现1之前,有30个0,所以R5 = 0x1E=30.

你可能感兴趣的:(ARM,缓存,ARM)