Cache Behaviour in Linux -- Cache Policy识别情景分析
Linux在boot的过程中判断cache policy的入口是cacheid_init().
297 static void __init cacheid_init(void)
298 {
299 unsigned int cachetype = read_cpuid_cachetype();
300 unsigned int arch = cpu_architecture();
301
302 if (arch >= CPU_ARCH_ARMv6) {
303 if ((cachetype & (7 << 29)) == 4 << 29) {
304 /* ARMv7 register format */
305 arch = CPU_ARCH_ARMv7;
306 cacheid = CACHEID_VIPT_NONALIASING;
307 switch (cachetype & (3 << 14)) {
308 case (1 << 14):
309 cacheid |= CACHEID_ASID_TAGGED;
310 break;
311 case (3 << 14):
312 cacheid |= CACHEID_PIPT;
313 break;
314 }
315 } else {
316 arch = CPU_ARCH_ARMv6;
317 if (cachetype & (1 << 23))
318 cacheid = CACHEID_VIPT_ALIASING;
319 else
320 cacheid = CACHEID_VIPT_NONALIASING;
321 }
322 if (cpu_has_aliasing_icache(arch))
323 cacheid |= CACHEID_VIPT_I_ALIASING;
324 } else {
325 cacheid = CACHEID_VIVT;
326 }
303行,根据cache type register的第31位判断是否为ARMV7. 31-29位是100:代表ARM v7;000代表ARMV6.
判断ARMV7的ICache的Policy呢?307~313行便是做这部分工作。
307行,比较cache type register中的第14和15位(0 based)。在V7的spec(P)中,该位写死了,其值为:10. 在PJ4C的spec中,其值是11,代表PIPT。(official v7 spec估计是笔误。)
Level 1 instruction cache policy. Indicates the indexing and tagging policy for the L1 instruction cache.00 Reserved01 ASID-tagged Virtual Index, Virtual Tag (AIVIVT)10 Virtual Index, Physical Tag (VIPT)11 Physical Index, Physical Tag (PIPT)
引用自:DDI0406B.P1358.
315~320是ARMv6的代码。根据其代码,可以看到V6的Dcache全部都是VIPT。那么,到底是否存在cache aliasing问题呢?看317行。
315~320是ARMv6的代码。根据其代码,可以看到V6的Dcache全部都是VIPT。那么,到底是否存在cache aliasing问题呢?看317行。
317行根据第23位(0 based),来判断是否存在cache aliasing问题。
如果存在cache aliasing问题,那么cacheid的值为CACHEID_VIPT_ALIASING. 若Cache存在aliasing问题,则会产生很多异常。例如:VA1和VA2同时mapping到PA上,VA1通过VIPT的policy到cache中的某些连续的sets中去hit页,VA2也通过VIPT的policy到cache中的某些连续的sets中去hit页,如果VA1和VA2在cache中的mapping不一样,就会造成:同一份物理页在cache中有两份copy的问题,这个问题造成的直接后果是:进程通过VA1修改的数据后,通过VA2并不能立即得到最新的数据。
v6是如何解决这种问题的呢:
- If multiple virtual addresses are mapped onto the same physical addresses, then for all mappings bits [13:12] of the virtual address must be equal, and must also be equal to bits [13:12] of the physical address. The same physical address can be mapped by TLB entries of different page sizes. These can be 4KB, 64KB, or sections.
- If all mappings to a physical address are of a page size equal to 4KB, the restriction that bits [13:12] of the virtual address must equal bits [13:12] of the physical address is not required. Bits [13:12] of all virtual address aliases must still be equal.
引用自:DDI0406B.P1985.
即,v6的spec.要求映射同一块物理地址的虚拟地址,第13,12位必须相同(相同的page colour),这样,就保证了VA1和VA2在cache中的mapping是一样的。
322行是判断ICache是否具有aliasing,其代码如下:
264 static int cpu_has_aliasing_icache(unsigned int arch)
265 {
266 int aliasing_icache;
267 unsigned int id_reg, num_sets, line_size;
268
269 /* PIPT caches never alias. */
270 if (icache_is_pipt())
271 return 0;
272
273 /* arch specifies the register format */
274 switch (arch) {
275 case CPU_ARCH_ARMv7:
276 asm("mcr p15, 2, %0, c0, c0, 0 @ set CSSELR"
277 : /* No output operands */
278 : "r" (1));
279 isb();
280 asm("mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR"
281 : "=r" (id_reg));
282 line_size = 4 << ((id_reg & 0x7) + 2);
283 num_sets = ((id_reg >> 13) & 0x7fff) + 1;
284 aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
285 break;
286 case CPU_ARCH_ARMv6:
287 aliasing_icache = read_cpuid_cachetype() & (1 << 11);
288 break;
289 default:
290 /* I-cache aliases will be handled by D-cache aliasing code */
291 aliasing_icache = 0;
292 }
293
294 return aliasing_icache;
295 }
判断V6的ICache是否具有cache alias的方法和判断DCache的方法是一样的。不同的是Dcache取决于CTR(Cache Type Register)的第23位, ICache取决于CTR的第11位(286~289行)。
在cacheid_init()函数中,判断了ARMV7是PIPT还是VIPT还是其他,那么如何判断其是否具有Alias问题呢?就要看“log2(Way_Size) > log2(PAGE_SIZE)”的值了(284行)。
以上,主要分析了ARM V7的Icache的Cache Policy以及是否存在Alias在Linux的识别过程。
ARM V7的Dcache的Cache Policy是怎样的呢?cacheid_init()函数的306行已经写死了。其值是CACHEID_VIPT_NOALIASING的。
即,Linux认为对于V7来说,DCache一定是VIPT with no alias或者PIPT,ICache可能是VIPT with alias或者PIPT或者ASID Taged的VIVT。对于VIPT,是否具有alias问题呢,要看log2(Way_size)与log2(PAGE_SIZE)的比较结果了。
评论
发表评论