KVM虚拟化源代码详解.docx

上传人:b****7 文档编号:25432900 上传时间:2023-06-08 格式:DOCX 页数:18 大小:25.98KB
下载 相关 举报
KVM虚拟化源代码详解.docx_第1页
第1页 / 共18页
KVM虚拟化源代码详解.docx_第2页
第2页 / 共18页
KVM虚拟化源代码详解.docx_第3页
第3页 / 共18页
KVM虚拟化源代码详解.docx_第4页
第4页 / 共18页
KVM虚拟化源代码详解.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

KVM虚拟化源代码详解.docx

《KVM虚拟化源代码详解.docx》由会员分享,可在线阅读,更多相关《KVM虚拟化源代码详解.docx(18页珍藏版)》请在冰豆网上搜索。

KVM虚拟化源代码详解.docx

KVM虚拟化源代码详解

KVM虚拟机源代码分析

1,KVM构造及工作原理

1.1KVM构造

KVM根本构造有两局部组成。

一个是KVMDriver,已经成为Linux核的一个模块。

负责虚拟机的创立,虚拟存的分配,虚拟CPU存放器的读写以及虚拟CPU的运行等。

另外一个是稍微修改正的Qemu,用于模拟PC硬件的用户空间组件,提供I/O设备模型以及访问外设的途径。

图1KVM根本构造

KVM根本构造如图1所示。

其中KVM参加到标准的Linux核中,被组织成Linux中标准的字符设备(/dev/kvm)。

Qemu通KVM提供的LibKvm应用程序接口,通过ioctl系统调用创立和运行虚拟机。

KVMDriver使得整个Linux成为一个虚拟机监控器。

并且在原有的Linux两种执行模式(核模式和用户模式)的根底上,新增加了客户模式,客户模式拥有自己的核模式和用户模式。

在虚拟机运行下,三种模式的分工如下:

客户模式:

执行非I/O的客户代码。

虚拟机运行在客户模式下。

核模式:

实现到客户模式的切换。

处理因为I/O或者其它指令引起的从客户模式的退出。

KVMDriver工作在这种模式下。

用户模式:

代表客户执行I/O指令Qemu运行在这种模式下。

在KVM模型中,每一个GuestOS都作为一个标准的Linux进程,可以使用Linux的进程管理指令管理。

在图1中./dev/kvm在核中创立的标准字符设备,通过ioctl系统调用来访问核虚拟机,进展虚拟机的创立和初始化;kvm_vmfd是创立的指向特定虚拟机实例的文件描述符,通过这个文件描述符对特定虚拟机进展访问控制;kvm_vcpufd指向为虚拟机创立的虚拟处理器的文件描述符,通过该描述符使用ioctl系统调用设置和调度虚拟处理器的运行。

1.2KVM工作原理

KVM的根本工作原理:

用户模式的Qemu利用接口libkvm通过ioctl系统调用进入核模式。

KVMDriver为虚拟机创立虚拟存和虚拟CPU后执行VMLAUCH指令进入客户模式。

装载GuestOS执行。

如果GuestOS发生外部中断或者影子页表缺页之类的事件,暂停GuestOS的执行,退出客户模式进展一些必要的处理。

然后重新进入客户模式,执行客户代码。

如果发生I/O事件或者信号队列中有信号到达,就会进入用户模式处理。

KVM采用全虚拟化技术。

客户机不用修改就可以运行。

图2KVM工作根本原理

2,相关技术-处理器管理和硬件辅助虚拟化技术

Intel在2006年发布了硬件虚拟化技术。

其中支持X86体系构造的称为IntelVT-x技术。

ADM称为SVM技术。

VT-x引入了一种新的处理器操作,叫做VMX〔VirtualMachineExtension〕,提供了两种处理器的工作环境。

VMCS构造实现两种环境之间的切换。

VMEntry使虚拟机进去客户模式,VMExit使虚拟机退出客户模式。

2.1KVM中GuestOS的调度执行

VMM调度GuestOS执行时,Qemu通过ioctl系统调用进入核模式,在KVMDriver过get_cpu获得当前物理CPU的引用。

之后将Guest状态从VMCS中读出。

并装入物理CPU中。

执行VMLAUCH指令使得物理处理器进入非根操作环境,运行客户代码。

当GuestOS执行一些特权指令或者外部事件时,比方I/O访问,对控制存放器的操作,MSR的读写数据包到达等。

都会导致物理CPU发生VMExit,停顿运行GuestOS。

将GuestOS保存到VMCS中,Host状态装入物理处理器中,处理器进入根操作环境,KVM取得控制权,通过读取VMCS中VM_EXIT_REASON字段得到引起VMExit的原因。

从而调用kvm_exit_handler处理函数。

如果由于I/O获得信号到达,那么退出到用户模式的Qemu处理。

处理完毕后,重新进入客户模式运行虚拟CPU。

如果是因为外部中断,那么在LibKVM中做一些必要的处理,重新进入客户模式执行客户代码。

2.2KVM中存管理

KVM使用影子页表实现客户物理地址到主机物理地址的转换。

初始为空,随着虚拟机页访问实效的增加,影子页表被逐渐建立起来,并随着客户机页表的更新而更新。

在KVM中提供了一个哈希列表和哈希函数,以客户机页表项中的虚拟页号和该页表项所在页表的级别作为键值,通过该键值查询,如不为空,那么表示该对应的影子页表项中的物理页号已经存在并且所指向的影子页表已经生成。

如为空,那么需新生成一影子页表,KVM将获取指向该影子页表的主机物理页号填充到相应的影子页表项的容中,同时以客户机页表虚拟页号和表所在的级别生成键值,在代表该键值的哈希桶中填入主机物理页号,以备查询。

但是一旦GuestOS中出现进程切换,会把整个影子页表全部删除重建,而刚被删掉的页表可能很快又被客户机使用,如果只更新相应的影子页表的表项,旧的影子页表就可以重用。

因此在KVM中采用将影子页表中对应主机物理页的客户虚拟页写保护并且维护一影子页表的逆向映射表,即从主机物理地址到客户虚拟地址之间的转换表,这样VM对页表或页目录的修改就可以触发一个缺页异常,从而被KVM捕获,对客户页表或页目录项的修改就可以同样作用于影子页表,通过这种方式实现影子页表与客户机页表保持同步。

2.3KVM中设备管理

一个机器只有一套I/o地址和设备。

设备的管理和访问是操作系统中的突出问题、同样也是虚拟机实现的难题,另外还要提供虚拟设备供各个VM使用。

在KVM过移植Qemu中的设备模型(DeviceModel)进展设备的管理和访问。

操作系统中,软件使用可编程I/O〔PIO〕和存映射I/O〔MMIO〕与硬件交互。

而且硬件可以发出中断请求,由操作系统处理。

在有虚拟机的情况下,虚拟机必须要捕获并且模拟PIO和MMIO的请求,模拟虚拟硬件中断。

捕获PIO:

由硬件直接提供。

当VM发出PIO指令时,导致VMExit然后硬件会将VMExit原因及对应的指令写入VMCS控制构造中,这样KVM就会模拟PIO指令。

MMIO捕获:

对MMIO页的访问导致缺页异常,被KVM捕获,通过X86模拟器模拟执行MMIO指令。

KVM中的I/O虚拟化都是用户空间的Qemu实现的。

所有PIO和MMIO的访问都是被转发到Qemu的。

Qemu模拟硬件设备提供应虚拟机使用。

KVM通过异步通知机制以及I/O指令的模拟来完成设备访问,这些通知包括:

虚拟中断请求,信号驱动机制以及VM间的通信。

以虚拟机接收数据包来说明虚拟机和设备的交互。

图3I/O分析

(1)当数据包到达主机的物理网卡后,调用物理网卡的驱动程序,在其中利用Linux核中的软件网桥,实现数据的转发。

(2)在软件网挢这一层,会判断数据包是发往那个设备的,同时调用网桥的发送函数,向对应的端口发送数据包。

(3)假设数据包是发往虚拟机的,那么要通过tap设备进展转发,tap设备由两局部组成,网络设备和字符设备。

网络设备负责接收和发送数据包,字符设备负责将数据包往核空间和用户空间进展转发。

Tap网络局部收到数据包后,将其设备文件符置位,同时向正在运行VM的进程发出I/O可用信号,引起VMExit,停顿VM运行,进入根操作状态。

KVM根据KVM_EXIT_REASON判断原因,模拟I/O指令的执行,将中断注入到VM的中断向量表中。

(4)返回用户模式的Qemu中,执行设备模型。

返回到kvm_mainloop中,执行Kvm—main—loop—wait,之后进入main_loopwait中,在这个函数里收集对应设备的设备文件描述符的状态,此时tap设备文件描述符的状态同样被集到fdset。

(5)Kvmmain—loop不停地循环,通过select系统调用判断哪螋文件描述符的状态发生变化,相应的调用对应的处理函数。

对予tap来说,就会通过Qemu—send_packet将数据发往rtl8139一do—receiver,在这个函数中完成相当于硬件RTL8139网卡的逻辑操作。

KVM通过模拟I/O指令操作虚拟RTL8139将数据拷贝到用户地址空间,放在相应的I/O地址。

用户模式处理完毕后返回核模式,而后进入客户模式,VM被再次执行,继续收发数据包。

3,KVM源代码分析-虚拟机创立和运行流程代码分析

3.1KVM创立和运行虚拟机流程

KVM虚拟机创立和运行虚拟机分为用户态和核心态两个局部,用户态主要提供应用程序接口,为虚拟机创立虚拟机上下文环境,在libkvm中提供访问核字符设备/dev/kvm的接口;核态为添加到核中的字符设备/dev/kvm,模块加载进核后即可进展接口用户空间调用创立虚拟机。

在创立虚拟机过程中,kvm字符设备主要为客户机创立kvm数据机构,创立该虚拟机的虚拟机文件描述符及其相应的数据构造以及创立虚拟处理器及其相应的数据构造。

Kvm创立虚拟机的流程如图4所示。

首先申明一个kvm_context_t变量用以描述用户态虚拟机上下文信息,然后调用kvm_init()函数初始化虚拟机上下文信息;函数kvm_create()创立虚拟机实例,该函数通过ioctl系统调用创立虚拟机相关的核数据构造并且返回虚拟机文件描述符给用户态kvm_context_t数据构造;创立完核虚拟机数据构造后,再创立核pit以及mmio等根本外设模拟设备,然后调用kvm_create_vcpu()函数来创立虚拟处理器,kvm_create_vcpu()函数通过ioctl()系统调用向由vm_fd文件描述符指向的虚拟文件调用创立虚拟处理器,并将虚拟处理器的文件描述符返回给用户态程序,用以以后的调度使用;创立完虚拟处理器后,由用户态的QEMU程序申请客户机用户空间,用以加载和运行客户机代码;为了使得客户虚拟机正确执行,必须要在核中为客户机建立正确的存映射关系,即影子页表信息。

因此,申请客户机存地址空间后,调用函数kvm_create_phys_mem()创立客户机存映射关系,该函数主要通过ioctl系统调用向vm_fd指向的虚拟文件调用设置核数据构造中客户机存域相关信息,主要建立影子页表信息;当创立好虚拟处理器和影子页表后,即可读取客户机到指定分配的空间中,然后调度虚拟处理器运行。

调度虚拟机的函数为kvm_run(),该函数通过ioctl系统调用调用由虚拟处理器文件描述符指向的虚拟文件调度处理函数kvm_run()调度虚拟处理器的执行,该系统调用将虚拟处理器vcpu信息加载到物理处理器中,通过vm_entry执行进入客户机执行。

在客户机正常运行期间kvm_run()函数不返回,只有发生以下两种情况时,函数返回:

1,发生了I/O事件,如客户机发出读写I/O的指令;2,产生了客户机和核KVM都无法处理的异常。

I/O事件处理完毕后,通过重新调用KVM_RUN()函数继续调度客户机的执行。

图4KVM虚拟机创立流程

3.2虚拟机创立和运行主要函数分析

1,函数kvm_init():

该函数在用户态创立一个虚拟机上下文,用以在用户态保存根本的虚拟机信息,这个函数是创立虚拟机第一个需要调用的函数,函数返回一个kvm_context_t构造体。

该函数原型为:

Kvm_context_tkvm_init(structkvm_callbacks*callbacks,void*opaque);

参数:

callbacks为构造体kvm_callbacks变量,该构造体包含指向函数的一组指针,用于在客户机执行过程中因为I/O事件退出到用户态的时候处理的回调函数(后面会分析)。

参数opaque一般未使用。

函数执行根本过程:

翻开字符设备dev/kvm,申请虚拟机上下文变量kvm_context_t空间,初始化上下文的根本信息:

设置fd文件描述符指向/dev/kvm、禁用虚拟机文件描述符vm_fd(-1)

设置I/O事件回调函数构造体,设置IRQ和PIT的标志位以及存页面记录的标志位。

主要相关数据构造:

虚拟机上下文structkvm_context_t,用户态数据构造,用以描述虚拟机实例的用户态上下文信息。

Structkvm_context:

该构造体用于表示一个虚拟机上下文。

主要包含的数据域为:

Intfd:

指向核标准字符设备/dev/kvm的文件描述符。

Intvm_fd:

指向所创立的核虚拟机数据构造相关文件的文件描述符。

Intvcpu_fd[MAX_VCPUS]:

指向虚拟机所有的虚拟处理器的文件描述符数组。

Structkvm_run*run[MAX_VCPUS]:

指向虚拟机运行环境上下文的指针数组。

Structkvm_callbacks*call_backs:

回调函数构造体指针,该构造体用于处理用户态I/O事件。

Void*opaque:

指针(还未弄清楚)

Intdirty_page_log_all:

设置是否记录脏页面的标志。

Intno_ira_creation:

用于设置是否再kernel里设置irq芯片。

Int_irqchip_in_kernel:

核中irqchip的状态

Intirqchip_inject_ioctl:

用于拦截中断的iotcl系统调用

Intno_pit_creation:

设置是否再核中设置陷阱

intpit_in_kernel:

PIT状态

intcoalesced_mmio:

kernel中mmio

structkvm_irq_routing*irq_routes:

KVM中中断处理的路由构造指针。

intnr_allocated_irq_routes:

分配给该虚拟机的中断路由数目。

intmax_used_gsi:

使用的最大的gsi(")。

用户态I/O处理函数构造体structkvm_callbacks,该构造体指向一组函数,主要用于处理客户机因为I/O事件退出而执行的过程。

structkvm_callbacks:

该构造体用于在用户态中处理I/O事件,在KVM中调用KVM_QEMU实现。

主要包含的数据域为:

int(*inb)(void*opaque,uint16_taddr,uint8_t*data):

用于模拟客户机执行8位的inb指令。

int(*inw)(void*opaque,uint16_taddr,uint16_t*data):

用于模拟客户机执行16位的inw指令。

int(*inl)(void*opaque,uint16_taddr,uint32_t*data):

用于模拟客户机执行32位的inl指令。

int(*outb)(void*opaque,uint16_taddr,uint8_tdata):

用于模拟客户机执行8位的outb指令。

int(*outw)(void*opaque,uint16_taddr,uint16_tdata):

用于模拟客户机执行16位的outw指令。

int(*outl)(void*opaque,uint16_taddr,uint32_tdata):

用于模拟客户机执行32位的outl指令。

int(*mmio_read)(void*opaque,uint64_taddr,uint8_t*data,intlen):

用于模拟客户机执行mmio读指令。

int(*mmio_write)(void*opaque,uint64_taddr,uint8_t*data,intlen):

用于模拟客户机执行mmio写指令。

int(*debug)(void*opaque,void*env,structkvm_debug_exit_arch*arch_info):

用户客户机调试的回调函数。

int(*halt)(void*opaque,intvcpu):

用于客户机执行halt指令的响应。

int(*shutdown)(void*opaque,void*env):

用于客户机执行shutdown指令的响应。

int(*io_window)(void*opaque):

用于获得客户机io_windows。

int(*try_push_interrupts)(void*opaque):

用于注入中断的回调函数。

void(*push_nmi)(void*opaque):

用于注入nmi中断的函数。

void(*post_kvm_run)(void*opaque,void*env);用户得到kvm运行状态函数。

int(*pre_kvm_run)(void*opaque,void*env);用于获得kvm之前运行状态的函数

int(*tpr_access)(void*opaque,intvcpu,uint64_trip,intis_write);获得tpr访问处理函数

int(*powerpc_dcr_read)(intvcpu,uint32_tdcrn,uint32_t*data);用于powerpc的dcr读操作

nt(*powerpc_dcr_write)(intvcpu,uint32_tdcrn,uint32_tdata);用于powerpc的dcr写操作

int(*s390_handle_intercept)(kvm_context_tcontext,intvcpu,structkvm_run*run);用于s390的中断处理。

int(*s390_handle_reset)(kvm_context_tcontext,intvcpu,structkvm_run*run);用于s390的重设处理。

}

当客户机执行I/O事件或者停机操作等事件时,KVM会交给用户态的QEMU模拟外部I/O事件,调用这个构造体指向的相关的函数进展处理。

Structkvm_run:

用于KVM运行时一些的一些状态信息。

主要包含的数据域为:

__u8request_interrupt_window;

__u8padding1[7];

__u32exit_reason;

__u8ready_for_interrupt_injection;

__u8if_flag;

__u8padding2[2];

/*in(pre_kvm_run),out(post_kvm_run)*/

__u64cr8;

__u64apic_base;

union{

/*KVM_EXIT_UNKNOWN*/

struct{

__u64hardware_exit_reason;记录退出原因

}hw;

/*KVM_EXIT_FAIL_ENTRY*/客户机执行过程中执行VM_ENTRY失败。

struct{

__u64hardware_entry_failure_reason;

}fail_entry;

/*KVM_EXIT_EXCEPTION*/客户机因为异常退出

struct{

__u32exception;

__u32error_code;

}ex;

/*KVM_EXIT_IO*/客户机因为IO事件退出。

structkvm_io{

*defineKVM_EXIT_IO_IN0

*defineKVM_EXIT_IO_OUT1

__u8direction;

__u8size;/*bytes*/

__u16port;

__u32count;

__u64data_offset;/*relativetokvm_runstart*/

}io;

struct{

structkvm_debug_exit_archarch;

}debug;

/*KVM_EXIT_MMIO*/客户机因为MMIO退出

struct{

__u64phys_addr;

__u8data[8];

__u32len;

__u8is_write;

}mmio;

/*KVM_EXIT_HYPERCALL*/客户机退出的超调用参数。

struct{

__u64nr;

__u64args[6];

__u64ret;

__u32longmode;

__u32pad;

}hypercall;

/*KVM_EXIT_TPR_ACCESS*/客户机退出访问TPR参数

struct{

__u64rip;

__u32is_write;

__u32pad;

}tpr_access;

/*KVM_EXIT_S390_SIEIC*/和S390相关数据

struct{

__u8icptcode;

__u64mask;/*pswupperhalf*/

__u64addr;/*pswlowerhalf*/

__u16ipa;

__u32ipb;

}s390_sieic;

/*KVM_EXIT_S390_RESET*/

*defineKVM_S390_RESET_POR1

*defineKVM_S390_RESET_CLEAR2

*defineKVM_S390_RESET_SUBSYSTEM4

*defineKVM_S390_RESET_CPU_INIT8

*defineKVM_S390_RESET_IPL16

__u64s390_reset_flags;

/*KVM_EXIT_DCR*/

struct{

__u32dcrn;

__u32data;

__u8is_write;

}dcr;

/*Fixthesizeoftheunion.*/

charpadding[256];

2,函数kvm_create():

该函数主要用于创立一个虚拟机核环境。

该函数原型为:

intkvm_create(kvm_context_tkvm,unsignedlongphys_mem_bytes,void**phys_mem);

参数:

kvm_context_t表示传递的用户态虚拟机上下文环境,phys_mem_bytes表示需要创立的物理存的大小,phys_mem表示创立虚拟机的首地址。

这个函数首先调用kvm_create_vm()分配IRQ并且初始化为0,设置vcpu[0]的值为-1,即不允许调度虚拟机执行。

然后调用ioctl系统调用ioctl(fd,KVM_CREATE_VM,0)来创立虚拟机核数据构造structkvm。

3,系统调用函数ioctl(fd,KVM_CREATE_VM,0),用于在核中创立和虚拟机相关的数据构造。

该函数原型为:

Staticlongkvm_dev_ioctl(structfile*filp,unsignedintioctl,unsignedlongarg);其中ioctl表示命令。

这个函数调用kvm_dev_ioctl_create_vm()创立虚拟机实例核相关数据构造。

该函数首先通过核中kvm_create_vm()函数创立核中kvm上下文structkvm,然后通过函数

Anno_inode_getfd("kvm_vm〞,&kvm_vm_fops,kvm,0)返回该虚拟机的文件描述符,返回给用户调用函数,由2中描述的函数赋值给用户态虚拟机上下文变量中的虚拟机描述符kvm_vm_fd。

4,核创立虚拟机kvm对象后,接着调用kvm_arch_create函数用于创立一些体系构造相关的信息,主要包括kvm_init_ts

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > 其它考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1