Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1360058
  • 博文数量: 488
  • 博客积分: 161
  • 博客等级: 入伍新兵
  • 技术积分: 5064
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-01 07:37
个人简介

只有偏执狂才能生存

文章分类

全部博文(488)

文章存档

2016年(10)

2015年(112)

2014年(66)

2013年(272)

2012年(28)

分类: LINUX

2013-06-09 23:18:21

在"kvm:the Linux Virtual Machine Monitor"论文中提到,IO虚拟化中有两个重要部分:"Virtualizing Guest-Initiated IO Instructions" and "Host-Initiated Virtual Interrupts"。
  Guest-Initiated IO Instructions Virtualization
 对于guest发起的IO指令的虚拟是比较直接的:当guest OS在guest mode中执行时,支持vmx的物理CPU实际上是在vmx non-root operation模式中。虚拟机的VMCS中的设置可以控制一旦执行某个IO指令,立刻发生VMExit。函数路径如下所示,VMExit后返回到vcpu_enter_guest,这个函数接着调用vmx_handle_exit对VMExit进行处理。如果此IO指令可以在内核模式就模拟出来(比如内核模拟PIT和PIC),kernel_pio返回真,就不用切换到用户模式,模拟完成后重新调用vcpu_enter_guest;如果不能在内核空间模拟,就一路返回,直到切换到用户模式,在qemu-kvm的kvm_run函数中调用kvm_handle_io进行IO指令模拟,完成后再次用ioctl(KVM_RUN)请求恢复guest运行。

handle guest io instructions code path:
vcpu_enter_guest  
           |                vmexit
kvm_x86_ops->run ---> kvm_x86_ops->handle_exit(vmx_handle_exit)
                                                     |
                    kvm_vmx_exit_handlers[exit_reason](handle_io in vmc.c)
                                                     |
                                      kvm_emulate_pio (x86.c)
                                                     |                       
                                                  /      \      
                                         return 0    kernel_pio(x86.c) --> complete_io
                                               |                         |
                           return (userspace)     vcpu_enter_guest
                                      | mode switch@ qemu-kvm
                        kvm_handle_io (kvm_run() kvm_all.c)
                                      |
                           ioctl(KVM_RUN)
      Interrupt Virtualization
     中断虚拟化,有两方面:一是如何保证物理中断只有host来处理;二是host如何将一个虚拟中断注入到guest中。
      首先看物理中断情况;在没有guest情况下,一旦CPU检测到中断信号,将在下一条指令之前响应中断,根据中断号从host OS IDT中取到对应的中断向量,然后调用interrupt handler。但是,假如guest vcpu正在执行中来了物理中断,此时的物理IDTR指向的是guest OS的IDT。原则上肯定不能是由guest handler去处理物理中断,所以必须通过某种机制来处理,这个机制由两部分配合:
       a. 首先是vmx规定,只要此虚拟机vmcs的"VM-Execution control field"中的"External -interrupt exiting"位设置为1,物理中断将导致VMExit(vmcs的配置可以参考“IA32 Intel Architecture Software Developer's Manual Volume 3B System Programming Guide”)。
       b. 知道了a后,我就想过,物理中断不是应该立刻由硬件来响应么,那么是响应中断在前,还是VMExit在前呢?如果响应在前,此时IDTR还没有恢复为host的,将导致取guest IDT,所以显然不行,只能是VMExit在前,但是VMExit过程中硬件只能恢复host的非通用寄存器,通用寄存器还得由软件来恢复(vmx_vcpu_run函数代码),物理中断却要在恢复通用寄存器之间了,显然也不行。后来才发现,原来在进入guest执行前,kvm是关中断的,在VMExit完全恢复了host上下文后,才开中断——关中断是vcpu_enter _guest函数中调用了local_irq_disable,开中断是在这个函数从kvm_x86_ops->run返回后(即VMExit后)调用local_irq_enable。现在一切都明白了:guest vcpu执行时,物理中断来了,它可以导致VMExit,但是此时是关中断,所以硬件不会响应中断,中断处于pending,在中断开后,硬件发现pending中断并开始响应,此时已经是在host上下文中,IDTR已经指向host的IDT,因此物理中断实际上是由host handler来处理了。
      再来看虚拟中断的情况;KVM用QEMU来提供设备模拟,与物理设备一样,模拟的设备也可以发出中断信号,但是这个中断信号是软件虚拟的,那么这个虚拟中断是怎样注入到虚拟机中去的呢?这个又要分两种情况:一种是此时guest vcpu正在执行,另一种是guest vcpu刚到用户模式执行完IO指令模拟操作,还没有开始VMEntry。
      对于后一种情况,可以参考vmx_inject_irq和vmx_inject_nmi(vmx.c),可以发现,kvm是利用vmx支持这种注入操作的特性:vmcs中有"VM-Entry control fields",其中又包含"VM-entry interruption-information field",可以将中断类型和中断号记录到其中,在VMEntry过程中,硬件会自动检测这个信息域,如果有效,就会在真正执行任何guest指令之前,像原来硬件一样响应此中断(包括压IP,CS,FLAGS;从IDT中取interrupt vector等),注意此操作是在恢复了guest上下文之后,所以物理IDTR已经是指向guest OS IDT了,因此这个虚拟中断就由guest handler来处理了。
补充上段:假如在guest运行期间发生了一个物理中断,kvm是如何截获进入将其注入到guest中去的呢?有两个步骤:
1. 在vmx_vcpu_run中,从guest mode返回后会调用complete_interrupt函数。因为硬件会将中断类型和那个中断号写入到VMCS中,所以complete_interrupt的任务就是从VMCS中取出中断信息,然后写入vcpu的控制块中去,使得这个中断变成一种pending event。
2. 在vcpu_enter_guest中,在进入guest mode前会调用inject_pending_event。inject_pending_event发现vcpu控制块中有pending的中断信息,就调用vmx_inject_irq将其写入VMCS中去,就相当于将中断注入到guest中去了。
       对于前一种情况,暂时也还不知道KVM具体是如何实现的。不过vmx倒也是支持这种注入操作。只要vmcs的"VM-Execution control field"中的"Interrupt-window exiting"位设置为1,只要guest IF=1,在下一条任意指令前,会发生VMExit,就像普通情况下发生了一次中断一样。也就是说,kvm应该可以通过设置"Interrupt-window exiting"中断guest vcpu的执行,然后像后一种情况一样,把虚拟中断注入到虚拟机中。
阅读(1687) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册