KVM在和用户态程序进行交互的过程中,主要通过/dev/kvm设备文件进行通信。从后文的KVM的初始化过程中可以得知,/dev/kvm是一个字符型设备,通过符合Linux标准的一系列结构体进行支撑,主要是kvm_chardev_ops、kvm_vm_fops、kvm_vcpu_fops,分别对应字符型设备、VM文件描述符和VCPU文件描述符的三种操作。
kvm_chardev_ops的定义在virt/kvm/kvm_main.c中,代码如下:
代码5-4 kvm_chardev_ops
(1913) static struct file_operations kvm_chardev_ops = {
(1914) .unlocked_ioctl = kvm_dev_ioctl,
(1915) .compat_ioctl = kvm_dev_ioctl,
(1916) .llseek = noop_llseek,
(1917) };
kvm_chardev_ops为一个标准的file_operations结构体,但是只包含了ioctl函数,read、open、write等常见的系统调用均采用默认实现。因此,就只能在用户态通过ioctl函数进行操作。
如前文所述,通过KVM_CREATE_VM之后可以获得一个fd文件描述符,代表该VM,该fd文件描述符在KVM子模块内部操作实际上对应着kvm_vm_ fops结构体,其主要内容如下。
代码5-5 kvm_vm_fops结构体
(1815) static struct file_operations kvm_vm_fops = {
(1816) .release = kvm_vm_release,
(1817) .unlocked_ioctl = kvm_vm_ioctl,
(1818) #ifdef CONFIG_COMPAT
(1819) .compat_ioctl = kvm_vm_compat_ioctl,
(1820) #endif
(1821) .mmap = kvm_vm_mmap,
(1822) .llseek = noop_llseek,
(1823) };
针对VM的文件操作中,提供了ioctl和mmap两个操作函数,其中mmap对应着GUEST OS的物理地址,可以直接对GUEST OS的地址空间进行读/写,ioctl则用于发送KVM的控制字。
针对KVM的fd,通过KVM_CREATE_VCPU指令字可以创建KVM的VCPU,并且获得该vcpu_fd,在KVM子模块中的操作对应着该结构体。vcpu_fd的操作主要包含在kvm_vcpu_fops中,其主要定义如下。
代码5-6 kvm_vcpu_fops结构体
(1348) static struct file_operations kvm_vcpu_fops = {
(1349) .release = kvm_vcpu_release,
(1350) .unlocked_ioctl = kvm_vcpu_ioctl,
(1351) .compat_ioctl = kvm_vcpu_ioctl,
(1352) .mmap = kvm_vcpu_mmap,
(1353) .llseek = noop_llseek,
(1354) };
在ioctl中,通过发送ioctl,即可对VCPU进行控制。通过mmap,则可以访问kvm_run结构体,在这个结构体中保存了VCPU运行和控制的信息,并且可以对其运行参数进行设置。