mark下ivshmem相关笔记。

ivshmem是QEMU提供的一种宿主机与虚拟机之间或多个虚拟机之间共享内存的特殊设备。它有两种形式:

  • ivshmem-plain: 简单的共享内存区域
  • ivshmem-doorbel: 除了共享内存,还能提供基于中断的通信机制

这种设备在虚拟机内部表现为PCI设备,共享的内存区域则以PCI BAR的形式存在。ivshmem PCI设备提供3个BAR:

  • BAR0: 设备寄存器
  • BAR1: MSI-X表
  • BAR2: 共享内存区域

简单的共享内存场景只使用BAR2。如果需要基于中断实现额外通信,需要用到BAR0和BAR1。

只考虑共享内存这个场景,是如何做到内存共享的呢?在不同的虚拟机(这些虚拟机会共享内存)内,ivshmem device的BAR2地址(GPA)可能不同,但是对应的HPA是一样的,hypervisor会为不同虚拟机的ivshmem device的BAR2内存区域建立EPT映射,因此就达到共享内存的目的!
即:

  • GPA1->HPA1
  • GPA2->HPA1

Evidence on ACRN hypervisor:

1
2
3
4
5
6
7
8
9
10
11
12
13
// hypervisor code
static void ivshmem_vbar_map(struct pci_vdev *vdev, uint32_t idx)
{
struct acrn_vm *vm = vpci2vm(vdev->vpci);
struct pci_vbar *vbar = &vdev->vbars[idx];
struct ivshmem_device *ivs_dev = (struct ivshmem_device *) vdev->priv_data;

if ((idx == IVSHMEM_SHM_BAR) && (vbar->base_hpa != INVALID_HPA) && (vbar->base_gpa != 0UL)) {
//ept_add_mr is called to build EPT mapping for ivshmem BAR2!
ept_add_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, vbar->base_hpa,
vbar->base_gpa, vbar->size, EPT_RD | EPT_WR | EPT_WB | EPT_IGNORE_PAT);
...
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//device model code
create_ivshmem_from_dm(struct vmctx *ctx, struct pci_vdev *vdev,
const char *name, uint32_t size)
{
...
addr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
bar_addr = pci_get_cfgdata32(vdev, PCIR_BAR(IVSHMEM_MEM_BAR));
bar_addr |= ((uint64_t)pci_get_cfgdata32(vdev, PCIR_BAR(IVSHMEM_MEM_BAR + 1)) << 32);
bar_addr &= PCIM_BAR_MEM_BASE;
pr_dbg("shm configuration, vma 0x%lx, ivshmem bar 0x%lx, size 0x%x\n",
(uint64_t)addr, bar_addr, size);
//vm_map_memseg_vma is called to build EPT mapping for ivshmem BAR2!
if (!addr || vm_map_memseg_vma(ctx, size, bar_addr,
(uint64_t)addr, PROT_RW) < 0) {
pr_warn("failed to map shared memory\n");
goto err;
}
...
}

参考资料: