QEMU 是否模拟 TLB?

Does QEMU emulate TLB?

我有一个很简单的问题,QEMU 是否模拟 TLB?当客户 linux 系统执行 "invlpg" 指令时会发生什么,因为它是为了使 TLB 条目无效。我知道 QEMU 有 softmmu link 用于将来宾虚拟地址转换为主机虚拟地址,但 QEMU 是否模拟实际的 TLB,以及 "invlpg" 指令的作用是什么。还是 QEMU 会直接忽略这条指令?

does QEMU emulate TLB?

是。


QEMU 监控控制台提供了一个 info tlb 命令,它将

list the TLB (Translation Lookaside Buffer), i.e. mappings between physical memory and virtual memory


CPU emulation documentation 有一个部分说

The page cache is called the "TLB" in the QEMU sources.


在源码中,即target-i386/cpu.c,我们看到与TLB相关的定义如下:

/* TLB definitions: */

#define L1_DTLB_2M_ASSOC       1
#define L1_DTLB_2M_ENTRIES   255
#define L1_DTLB_4K_ASSOC       1
#define L1_DTLB_4K_ENTRIES   255

#define L1_ITLB_2M_ASSOC       1
#define L1_ITLB_2M_ENTRIES   255
#define L1_ITLB_4K_ASSOC       1
#define L1_ITLB_4K_ENTRIES   255

#define L2_DTLB_2M_ASSOC       0 /* disabled */
#define L2_DTLB_2M_ENTRIES     0 /* disabled */
#define L2_DTLB_4K_ASSOC       4
#define L2_DTLB_4K_ENTRIES   512

#define L2_ITLB_2M_ASSOC       0 /* disabled */
#define L2_ITLB_2M_ENTRIES     0 /* disabled */
#define L2_ITLB_4K_ASSOC       4
#define L2_ITLB_4K_ENTRIES   512

target-i386/translate.c中,我们看到以下代码处理INVLPG指令:

    case 7:
        if (mod != 3) { /* invlpg */
            if (s->cpl != 0) { 
                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
            } else {
                gen_update_cc_op(s);
                gen_jmp_im(pc_start - s->cs_base);
                gen_lea_modrm(env, s, modrm);
                gen_helper_invlpg(cpu_env, cpu_A0);
                gen_jmp_im(s->pc - s->cs_base);
                gen_eob(s);
            }
        }

gen_helper_invlpg 实现在 target-i386/misc_helper.c:

void helper_invlpg(CPUX86State *env, target_ulong addr)
{
    X86CPU *cpu = x86_env_get_cpu(env);

    cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0); 
    tlb_flush_page(CPU(cpu), addr);
}

它调用tlb_flush_page的地方,它在cputlb.c中实现。


所以你可以看到INVLPG指令为一个地址刷新TLB

答案介于 "yes" 和 "no" 之间。 QEMU 不会尝试模拟实际访客 CPU 的 TLB(这是一种硬件,可加速从访客虚拟地址到访客物理地址的查找)。然而,它确实实现了自己非常相似的数据结构,它称之为 TLB——这加速了从客户虚拟地址直接查找到 RAM 的主机虚拟地址,或者从客户虚拟地址到仿真设备的 read/write 函数的查找。

由于CPU TLB和QEMU的TLB有相似之处,我们可以使用guest指令使TLB失效或以其他方式操作TLB作为执行QEMU TLB失效的触发器(这就是tlb_flush_page() 调用 helper_invlpg() 正在做);所以这些指令不是简单的空操作。如果来宾使用查询缓存和 TLB 信息的 cpuid 指令,我们也会对来宾撒谎并告诉它有关其 TLB 大小的合理信息。但我们实际上并没有对访客 TLB 进行建模——因此您不会看到围绕访客 TLB 大小的性能变化,并且您无法记录有关访客 TLB 命中和未命中的信息,并且我们没有实施 TLB 锁定在 CPU 个具有它的架构上。

最后,monitor "info tlb" 命令的名字有点不对,因为它实际上显示的是访客页面 table 设置的信息,与 TLB 状态无关。