VT-x中VPID vs ARM虚拟化中的VMID(Virtual Machine Identifier)。

该文介绍过PCID与VPID相关知识点。VMID的概念:8-bit value stored in VTTBR_EL2,标识某个VM,可以用于区分不同VM的TLB表项。

Intel中的PCID类似于ARM中的ASID(Address Space Identifier),Intel中的VPID类似于ARM中的VMID。这些都很容易理解,但是,在 具体实现中,却有着一个显著的差异:VMID标识的是VM,而VPID标识的却是vCPU。

以KVM的实现作为佐证,代码如下:

1
2
3
4
5
6
7
// https://elixir.bootlin.com/linux/v5.17/source/arch/x86/kvm/vmx/vmx.c#L7002
static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
{
...
vmx->vpid = allocate_vpid();
...
}

问题1
为什么VT-x中,VPID标识的是vCPU,而非VM呢?

首先考虑如下case:
在同一个物理CPU上,首先运行的是VM A的vCPU1,接着运行的是VM A的vCPU2,同时,vCPU1与vCPU2上运行的是虚拟机的不同进程。

如果VPID标识的是vCPU,那么,在由vCPU1切换到vCPU2时,vCPU2并不能使用vCPU1之前缓存的TLB entry。但是,如果VPID标识的是VM,那么,在由vCPU1切换到vCPU2时,vCPU2可以直接使用vCPU1之前缓存的TLB entry。

从直觉上来说,用VPID标识VM的话,效率是不是更高呢?

但在VT-x中,如果使用VPID标识VM的话,却存在着问题:

  • 当guest使用PCID的话,使用VPID标识VM没有任何问题,(VM的id,PCID,virtual address)这个三元组是唯一的
  • 但是,当guest不使用PCID的话,上述case中,当由vCPU1切换到vCPU2时,(VM的id,virtual address)这个二元组并不唯一,就会产生错误(虚拟机上的进程a用了进程b的TLB entry了,当然会出错!)

问题2
经过以上的分析可知:VPID标识VM会存在问题,因此需要使用VPID来标识vCPU。那么ARM下,为什么可以使用VMID来标识VM,而非vCPU呢?

答案:ARM中,无法disable ASID,ASID是必须要enabled的一个feature。而在Intel的CPU上,是可以disable PCID的。所以,在ARM中,虚拟机必须enable ASID,否则就是guest OS的bug了。因此,使用VMID标识VM没有任何问题,因为(VMID,ASID,virtual address)这个三元组是唯一的!