MIPS 使用 synci 指令刷新 Cache

MIPS 是一个缓存不透明的架构设计,通常设计存在两个 Cache,即 指令 Cache 与 数据 Cache。在装载完代码执行前(一般仅应用程序动态生成的代码需要,如 JIT)一定要刷新指令 Cache,确保 Cache 中指令与写入的一致。这个过程分两个步骤:1. 是将数据 Cache 中的数据写回 RAM。2. 将 RAM 中的数据装载到指令 Cache。

较早的实现依赖于 cache 指令,但 cache 指令是个特权指令,事实上并不是需要做这件事的程序都是特权程序,所以普通应用程序在 Linux 平台上可以调用系统调用 cacheflush,进入特权模式完整刷新操作。

上述方法虽然可行,但如果频繁的执行系统调用效率较低,所以在 MIPS r2 的 ISA 中增加了一条常规特权下的 synci 指令,专门用于做这件事。它的用法是:

synci offset(base)

要求对每个 Cache Line 执行一次 synci 操作。

例程

void
cache_flush (void *code, size_t size)
{
       long start, end, line_size, mask;
 
       __asm__ volatile (
               ".set  push                             \t\n"
               ".set  noreorder                        \t\n"
               "rdhwr %[line_size], $1                 \t\n"
               "addu  %[end], %[code], %[size]         \t\n"
               "subu  %[mask], $0, %[line_size]        \t\n"
               "and   %[end], %[end], %[mask]          \t\n"
               "and   %[start], %[code], %[mask]       \t\n"
               "addu  %[end], %[end], %[line_size]     \t\n"
               "1:                                     \t\n"
               "subu  %[end], %[end], %[line_size]     \t\n"
               "bne   %[start], %[end], 1b             \t\n"
               "synci 0(%[end])                        \t\n"
               ".set  pop                              \t\n"
               :[start]"=&r"(start), [end]"=&r"(end),
                [line_size]"=&r"(line_size), [mask]"=&r"(mask)
               :[code]"r"(code), [size]"r"(size)
       );
}

Over!

Leave a Reply

Your email address will not be published. Required fields are marked *