已经介绍过了native下的Memory Type,那么,虚拟化下的Memory Type又是何般境地呢?

1. History

前辈们在影子页表时代探索过Memory Type的虚拟化。可以参考Maintaining cache coherencyDisheng Su: Cache Attribute Virtualization in Xen。我也看不明白细节,但是,需要知道的是:在影子页表时代,Memory Type的虚拟化需要软件做很多事情。当来到EPT页表时代,软件需要做的事情就没有那么多了。

2. 第一性原理

在native下,EMT(Effective Memory Type)由页表的PAT与MTRR设置的物理地址区间memory type来共同决定。在虚拟化下,EMT又是怎样的呢?

  1. 对于PAT,可以由guest的页表来设置
  2. MTRR的MSR肯定是不能pass-thru给guest的
    • MTRR的功能是设置物理地址区间的memory type
    • native下MTRR MSR设置的是HPA的属性,一般由bios来设置
    • 在虚拟化场景下,当seabios或者OVMF设置MTRR时,会操作MTRR MSR,此时会发生VM Exit
    • 所以hypervisor是可以感知guest设置的GPA区间的memory type的

如何模拟guest GPA区间中设置的memory type(guest 在MTRR设置的memory type)呢?EPT页表会将GPA转化为HPA的,将guest MTRR设置的memory type,在EPT memory type设置下即可完成guest GPA区间中设置的memory type的模拟。在Non-root mode下,EMT由guest page table的PAT与EPT的memory type共同决定,此时物理MTRR完全不起作用,这样可以做到guest与host的EMT的隔离性!

经过上述分析可以知道,在虚拟化的场景下,EPT memory type承接了MTRR的工作。当guest设置MTRR的memory type时,都会发生VM Exit,此时hypervisor将GPA区间的memory type设置在EPT memory type即可!

3. EPT and Memory Typing

EPT中的Memory Type在SDM Vol3的28.3.7 EPT and Memory Typing有详细的介绍。

中文翻译转载自Intel SDM Chapter 28: VMX Support for Address Translation

涉及EPT的Memory Type有两个,首先是walk EPT时,访问EPT各级页表项所采用的Memory Type:

  • CR0.CD = 0,则采用的Memory Type由EPTP的第0-2位决定,取0表示UC,取6表示WB
  • CR0.CD = 1,则采用的Memory Type为UC

其次是Guest访问内存时,采用的Memory Type,它由两个因素决定:

  • EPT Memory Type:即EPT中最后一级页表项的第3-5位,起相当于MTRR的作用
    • 取0表示UC,取1表示WC,取4表示WT,取5表示WP,取6表示WB,这与MTRR中Type的含义相同
    • 此时MTRR完全不起作用
  • PAT Memory Type:
    • CR0.PG = 0,则PAT Memory Type为WB
    • CR0.PG = 1,则PAT Memory Type为Guest页表翻译时根据MSR[IA32_PAT]确定的PAT Memory Type

最终产生的Memory Type如下:

  • CR0.CD = 0
    • 若末级页表项的IPAT = 0,则Memory Type就是将EPT Memory Type当做MTRR Memory Type和PAT Memory Type合并后的结果
    • 若末级页表项的IPAT = 1,则Memory Type就是EPT Memory Type
  • CR0.CD = 1,则Memory Type为UC

IPAT即Ignore PAT(末级页表项的第6位),如下图标注所示:

EPT Memory Type(MTRR Memory Type)和PAT Memory Type合并后的结果: