vhost收到 VHOST_SET_MEM_TABLE 后,设置guest内存空间布局,用于映射 guest 物理内存与 host 虚拟内存。
KVMTOOL SETUP
struct vhost_memory *mem;
list_for_each_entry(bank, &kvm->mem_banks, list) {
mem->regions[i] = (struct vhost_memory_region) {
//guest 物理内存与 host 用户态虚拟内存的1:1映射
.guest_phys_addr = bank->guest_phys_addr,
.memory_size = bank->size,
.userspace_addr = (unsignedlong)bank->host_addr,
};
i++;
}
mem->nregions = i;
r = ioctl(vdev->vhost_fd, VHOST_SET_MEM_TABLE, mem);
if (r != 0)
die_perror("VHOST_SET_MEM_TABLE failed");
KERNEL SETUP
vhost_dev_ioctl
vhost_set_memory
vhost_iotlb_add_range(newumem,
region->guest_phys_addr,
region->guest_phys_addr + region->memory_size - 1,
region->userspace_addr,
VHOST_MAP_RW)
int vhost_iotlb_add_range(struct vhost_iotlb *iotlb, u64 start,
u64 last, u64 addr, unsignedint perm)
{
struct vhost_iotlb_map *map;
map = kmalloc(sizeof(*map), GFP_ATOMIC);
map->start = start; //guest_phys_addr start
map->size = last - start + 1;
map->last = last; //guest_phys_addr end
map->addr = addr; //userspace_addr start
map->perm = perm;
iotlb->nmaps++;
vhost_iotlb_itree_insert(map, &iotlb->root);//map信息插入到rb tree
INIT_LIST_HEAD(&map->link);
list_add_tail(&map->link, &iotlb->list);
return0;
}
KERNEL USESAGE
tx kick func(receive guest message)
vhost_get_vq_desc
translate_desc
static int translate_desc(struct vhost_virtqueue *vq, u64 addr,
u32 len, struct iovec iov[], int
iov_size, int access)
{
const struct vhost_iotlb_map *map;
map = vhost_iotlb_itree_first(umem, addr, addr + len - 1);
//addr是virtio前端驱动填充到vring desc中的
//guest物理物址
size = map->size - addr + map->start;
//= map->size - offset (addr - map->start)
_iov->iov_len = min((u64)len - s, size);
//host 用户态虚拟地址 = host 用户态起始虚拟地址 + offset(guest 物理地址 - guest 物
理起始地址)
_iov->iov_base = (void __user *)(unsigned long)(map->addr + addr -
map->start);
}