-
Notifications
You must be signed in to change notification settings - Fork 43
KVM internals
Zhuocheng Ding edited this page Mar 24, 2017
·
1 revision
- 通过文件系统暴露接口,分为system level、vm level和vcpu level三级API
- 具备extension机制,基本功能记作basic,扩展功能通过
KVM_CAP_xyz表示 - KVM子系统的入口点在
/dev/kvm文件,它是一个miscdevice,通过misc_register()函数注册到内核,而misc设备本身又是char设备的一种 - KVM子系统编译成kernel module,不同的arch会编译成不同的ko文件,如Intel VT-x使用
arch/x86/kvm/vmx.c定义kernel module,其中module_init(vmx_init)确定了module的初始化函数,类似的AMD SVM使用arch/x86/kvm/svm.c定义kernel module
- 首先调用
kvm_arch_init,以下为x86-VMX实现- 检查CPU是否支持VMX以及是否被BIOS禁用
- alloc
struct kvm_shared_msrs数组 - 初始化mmu(
kvm_mmu_module_init,kvm_set_mmio_spte_mask,kvm_mmu_set_mask_ptes)
- 文件上的
file_operations定义在kvm_chardev_ops变量,其中open由misc设备默认实现(misc_open),提供了unlocked_ioctl和compat_ioctl,由kvm_dev_ioctl实现-
unlocked_ioctl是为了解决原始的ioctl必须加BKL(Big Kernel Lock)的问题而引入的过渡方案,过渡时期原本的ioctl可以加锁运行,并逐步迁移到不加锁的unlocked_ioctl(需要driver开发者自己加锁) -
compat_ioctl是为了解决32位系统调用64位内核的问题,参数都是32位的,需要根据每个驱动的业务逻辑进行转换
-
- ioctl APIs
-
KVM_GET_API_VERSION- 参数:无
- 从linux kernel 2.6开始KVM就已经稳定,版本号不再变更,故永远返回12
-
KVM_CREATE_VM- 参数:machine type identifier (
KVM_VM_*) - 返回值:一个VM fd,用于控制新建的VM,返回的VM没有对应的virtual cpus也没有内存
- 创建的fd设置了close-on-exec
- 通过
kvm_dev_ioctl_create_vm(type)实现,步骤如下- 用
kvm_create_vm(type)创建一个struct kvm - Optional 若开启了Coalesced MMIO,则进行相关数据结构的初始化
- 创建一个文件并返回其fd,
struct kvm存放于该文件的file->private_data中- 创建文件的步骤是先获取一个空闲的fd(通过
get_unused_fd_flags),再创建struct file(通过anon_inode_getfile),最后向fdtable注册(通过fd_install)
- 创建文件的步骤是先获取一个空闲的fd(通过
- 用
- 参数:machine type identifier (
-
KVM_GET_MSR_INDEX_LIST(throughkvm_dev_ioctl->kvm_arch_dev_ioctl)- 参数:
struct kvm_msr_list (in/out) - 该struct是一个数组,其中存放MSR index,具体实现中分成
msrs_to_save和emulated_msrs两个数组(在内核态)分别存储,并在返回用户态时合并起来。两者区别是前者不涉及虚拟化而后者涉及虚拟化
- 参数:
-
KVM_CHECK_EXTENSION- 参数:
KVM_CAP_* - 返回0表示不支持,1(或其它正数)表示支持
- vm level也支持该操作,事实上不同的VM可以开启不同的extension
- 参数:
-
KVM_GET_VCPU_MMAP_SIZE- 参数:无
-
KVM_RUN与用户态通过一块mmap的共享内存沟通,此调用返回这块内存的大小
-
- ioctl APIs
-
KVM_CREATE_VCPU- 参数:vCPU ID(在x86上是APIC ID)
- 返回值:一个vCPU fd,用于控制一个vCPU,
- 创建的fd设置了close-on-exec
- 实现:
- 通过
kvm_arch_vcpu_create创建struct kvm_vcpu- 在x86上是调用
kvm_x86_ops->vcpu_create,下面考察vmx_create_vcpu
- 在x86上是调用
- 如果有preempt notifier,对它进行初始化
- 通过
kvm_arch_vcpu_setup初始化struct kvm_vcpu - 通过
anon_inode_getfd创建vcpu对应的fd - 最后执行
kvm_arch_vcpu_postcreate
- 通过
-
- 每个VM实例对应一个
struct kvm
-
struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]-
KVM_MAX_VCPUS是最大允许的vCPU数目,可以通过KVM_CAP_MAX_VCPUS查询 -
KVM_SOFT_MAX_VCPUS是推荐的最大vCPU数目,可以通过KVM_CAP_NR_VCPUS查询 -
KVM_MAX_VCPU_ID是vCPU ID的最大允许值,可以通过KVM_CAP_MAX_VCPU_ID查询
-
-
atomic_t online_vcpus- 直接通过原子指令操作,直到将
kvm_vcpu结构放入vcpus后才加1
- 直接通过原子指令操作,直到将
-
int created_vcpus- 通过
kvm->lock保护对其的操作,在KVM_CREATE_VCPU时加1
- 通过
int last_boosted_vcpustruct list_head vm_liststruct mutex lock
-
atomic_t users_count- 指向该struct的指针是引用计数的,通过
kvm_get_kvm进行retain,通过kvm_put_kvm进行release
- 指向该struct的指针是引用计数的,通过
struct kvm_vcpu vcpu
-
int vpid:由enable_vpid这个module param控制是否启用 bool emulation_required