捉虫日记 0003: MIPS Cache 操作时的奇怪现象

来自Jack's Lab
跳转到: 导航, 搜索

现象

本意想用如下的函数人为地将 Cache 的某个组的所有行的Tag 强制写为相同的值,然后访问一个索引到这个组的地址,人造一个多命中的情况 ;)

static void sysrq_handle_comcat(int key, struct tty_struct *tty)
{
    const u32 addr_cool = 0x80400000;
    const u32 ws_inc = 1UL << current_cpu_data.dcache.waybit;
    const u32 ws_end = current_cpu_data.dcache.ways << current_cpu_data.dcache.waybit;

    int i = 0;
    u32 taglo = 0;

    /* dump all line's tag in set 0*/
    printk("<0>----------------------- Before invalidated ---------------------- \n");
    do {
        asm (
            "lui    $3, 0x8040\n\t"
            "addu    $8, $3, %1\n\t"    
            "cache    0x05, 0($8)\n\t"
            "mfc0    %0, $28, 2\n\t"
            : "=r"(taglo)
            : "r"(i)
            : "$8", "$3"
        );

        printk("<0> taglo_%d = 0x%08x\n", i/ws_inc, taglo);
        i += ws_inc;

    } while (i < ws_end);

    printk("<0> -------------- Invalidated all lines in set_0 ------------------ \n");

    asm ("mtc0    $0, $28, 2\n\t");    // set TagLo to zero
    /* clear all line's tag in set 0 */
    do {
        asm (
            "lui    $8, 0x8040\n\t"
            "mtc0    $0, $28, 2\n\t"
            "addu    $3, $8, %0\n\t"    
            //"cache 0x01, 0($3)\n\t"        /* invalidate write-back a line */
            "cache 0x09, 0($3)\n\t"        /* clear this line's tag to zero */
            :
            : "r"(i)
            : "$8", "$3"
        );

        i += ws_inc;

    } while (i < ws_end);

    /* dump all line's tag in set 0*/
    i = 0;
    do {
        asm (
            "lui    $3, 0x8040\n\t"
            "addu    $8, $3, %1\n\t"    
            "cache    0x05, 0($8)\n\t"
            "mfc0    %0, $28, 2\n\t"
            : "=r"(taglo)
            : "r"(i)
            : "$8", "$3"
        );

        printk("<0> taglo_%d = 0x%08x\n", i/ws_inc, taglo);
        i += ws_inc;

    } while (i < ws_end);

    printk("<0> ----------------- Cache a line into set 0 ---------------------- \n");
   
    /* cache a line into set 0 */
    u32 tmp = *(u32 *) addr_cool;
    printk("<0> *(u32 *)0x%08x = 0x%08x\n", addr_cool, tmp);

    /* dump all line's tag in set 0*/
    i = 0;
    do {
        asm (
            "lui    $3, 0x8040\n\t"
            "addu    $8, $3, %1\n\t"    
            "cache    0x05, 0($8)\n\t"
            "mfc0    %0, $28, 2\n\t"
            : "=r"(taglo)
            : "r"(i)
            : "$8", "$3"
        );

        printk("<0> taglo_%d = 0x%08x\n", i/ws_inc, taglo);
        i += ws_inc;

    } while (i < ws_end);

    printk("<0> -- Get a validated line, read its Tag, write it to all lines -- \n");

    /* find a validated line, read its tag */
    i = 0;
    do {
        asm (
            "lui    $3, 0x8040\n\t"
            "addu    $8, $3, %1\n\t"    
            "cache    0x05, 0($8)\n\t"
            "mfc0    %0, $28, 2\n\t"
            : "=r"(taglo)
            : "r"(i)
            : "$8", "$3"
        );

        printk("<0> taglo = 0x%08x\n", taglo);
        i += ws_inc;

    } while ((((taglo >> 6) & 3) == 0) && i < ws_end);    /* cache line is invalide */

    /* set all other line's tag to the validated line's tag */
    do {
        asm (
            "lui    $8, 0x8040\n\t"
            "addu    $3, $8, %0\n\t"    
            "cache 0x09, 0($3)\n\t"        /* store tag */
            :
            : "r" (i)
            : "$8", "$3"
        );

        i += ws_inc;

    } while (i < ws_end);

    /* dump all line's tag in set 0*/
    i = 0;
    do {
        asm (
            "lui    $3, 0x8040\n\t"
            "addu    $8, $3, %1\n\t"    
            "cache    0x05, 0($8)\n\t"
            "mfc0    %0, $28, 2\n\t"
            : "=r"(taglo)
            : "r"(i)
            : "$8", "$3"
        );

        printk("<0> taglo_%d = 0x%08x\n", i/ws_inc, taglo);
        i += ws_inc;

    } while (i < ws_end);

    /* multi-hit cache line */
    printk("<0> --------------------- Multi-Hit cache line --------------------- \n");
    tmp = *(u32 *) addr_cool;
    printk("<0> *(u32 *)0x%08x = 0x%08x\n\n", addr_cool, tmp);

    printk("<0> ------------------------ After Multi-Hit ----------------------- \n");
    /* dump all line's tag in set 0*/
    i = 0;
    do {
        asm (
            "lui    $3, 0x8040\n\t"
            "addu    $8, $3, %1\n\t"    
            "cache    0x05, 0($8)\n\t"
            "mfc0    %0, $28, 2\n\t"
            : "=r"(taglo)
            : "r"(i)
            : "$8", "$3"
        );

        printk("<0> taglo_%d = 0x%08x\n", i/ws_inc, taglo);
        i += ws_inc;

    } while (i < ws_end);
    printk("<0> ---------------------------------------------------------------- \n\n");
}

static struct sysrq_key_op sysrq_jack_op = {
    .handler    = sysrq_handle_jack,
    .help_msg    = "Jack's Debug",
    .action_msg    = "Jack's Debug",
    .enable_mask    = SYSRQ_ENABLE_DUMP,
};


将这个函数映射到 sysrq 的 j 键方便操作。

哪知在多个 MIPS 平台上,第二步将组内所用行的 Tag 置为 0 的操作总是有一行不为所动 :( ,一下是一些 log:


4KEc 平台,8KB, 2-way, linesize 16 bytes L1 DCache:

telnet> send brk
SysRq : Jack's Debug
----------------------- Before invalidated ----------------------
taglo_0 = 0x003260c0
taglo_1 = 0x002b4080

-------------- Invalidated all lines in set_0 ------------------
taglo_0 = 0x00000000
taglo_1 = 0x002b4080

----------------- Cache a line into set 0 ----------------------
*(u32 *)0x80000000 = 0x3c1b802f
taglo_0 = 0x00000080
taglo_1 = 0x002b4080

-- Get a validated line, read its Tag, write it to all lines --
taglo = 0x00000080
taglo_0 = 0x00000080
taglo_1 = 0x00000080

--------------------- Multi-Hit cache line ---------------------
*(u32 *)0x80000000 = 0x802b6188

------------------------ After Multi-Hit -----------------------
taglo_0 = 0x002b4080
taglo_1 = 0x00000080
----------------------------------------------------------------


下面的这次,因为残留的一行有效,且在目标行的前面,所以这次造多命中失败了:(

telnet> send brk
SysRq : Jack's Debug
----------------------- Before invalidated ----------------------
taglo_0 = 0x002b4080
taglo_1 = 0x003260c0

-------------- Invalidated all lines in set_0 ------------------
taglo_0 = 0x00000000
taglo_1 = 0x003260c0

----------------- Cache a line into set 0 ----------------------
*(u32 *)0x80000000 = 0x3c1b802f
taglo_0 = 0x002b4080
taglo_1 = 0x00000080

-- Get a validated line, read its Tag, write it to all lines --
taglo = 0x002b4080
taglo_0 = 0x002b4080
taglo_1 = 0x002b4080

--------------------- Multi-Hit cache line ---------------------
*(u32 *)0x80000000 = 0x3c1b802f

------------------------ After Multi-Hit -----------------------
taglo_0 = 0x002b4080
taglo_1 = 0x00000080
----------------------------------------------------------------


VR5500 平台,64kB, 4-way, linesize 32 bytes L1 DCache:

----------------------- Before invalidated ----------------------
taglo_0 = 0x000458c0
taglo_1 = 0x0004a481
taglo_2 = 0x0004e8c1
taglo_3 = 0x0014dcc1
-------------- Invalidated all lines in set_0 ------------------
taglo_0 = 0x00000000
taglo_1 = 0x00000000
taglo_2 = 0x00000000
taglo_3 = 0x000458c0

----------------- Cache a line into set 0 ----------------------
*(u32 *)0x80000000 = 0x3c1b804b
taglo_0 = 0x00000000
taglo_1 = 0x00000000
taglo_2 = 0x00000081
taglo_3 = 0x000458c0

-- Get a validated line, read its Tag, write it to all lines --
taglo = 0x00000000
taglo = 0x00000000
taglo = 0x00000081

taglo_0 = 0x00000081
taglo_1 = 0x000458c0
taglo_2 = 0x00000081
taglo_3 = 0x00000081

--------------------- Multi-Hit cache line ---------------------
*(u32 *)0x80000000 = 0x8045a188

------------------------ After Multi-Hit -----------------------
taglo_0 = 0x00000081
taglo_1 = 0x000458c0
taglo_2 = 0x00000081
taglo_3 = 0x00000081
----------------------------------------------------------------

多次测试表明,似乎每次顽强生存着的 Tag 值皆一样,但位置可能会改变。这真是个诡异的现象,不知是不是 Cache lock 的原因。





























个人工具
名字空间

变换
操作
导航
工具箱