KVM中断虚拟化【转】

中断虚拟化,有两方面:

  1. 如何保证物理中断只有host来处理;
  2. host如何将一个虚拟中断注入到guest中。

首先看物理中断情况;在没有guest情况下,一旦CPU检测到中断信号,将在下一条指令之前响应中断,根据中断号从host OS IDT中取到对应的中断向量,然后调用interrupt handler。但是,假如guest vcpu正在执行中来了物理中断,此时的物理IDTR指向的是guest OS的IDT。原则上肯定不能是由guest handler去处理物理中断,所以必须通过某种机制来处理,这个机制由两部分配合:

  1. 首先是vmx规定,只要此虚拟机vmcs的"VM-Execution control field"中的"External -interrupt exiting"位设置为1,物理中断将导致VMExit(vmcs的配置可以参考“IA32 Intel Architecture Software Developer’s Manual Volume 3B System Programming Guide”)。
  2. 知道了1. 后,我就想过,物理中断不是应该立刻由硬件来响应么,那么是响应中断在前,还是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来提供设备模拟,与物理设备一样,模拟的设备也可以发出中断信号,但是这个中断信号是软件虚拟的,那么这个虚拟中断是怎样注入到虚拟机中去的呢?这个又要分两种情况:

  1. 此时guest vcpu正在执行;
  2. guest vcpu刚到用户模式执行完IO指令模拟操作,还没有开始VMEntry。

对于2. 情况,可以参考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中去了。

对于1. 情况,暂时也还不知道KVM具体是如何实现的。不过vmx倒也是支持这种注入操作。只要vmcs的"VM-Execution control field"中的"Interrupt-window exiting"位设置为1,只要guest IF=1,在下一条任意指令前,会发生VMExit,就像普通情况下发生了一次中断一样。也就是说,kvm应该可以通过设置"Interrupt-window exiting"中断guest vcpu的执行,然后像后一种情况一样,把虚拟中断注入到虚拟机中。

你可能感兴趣的:(#,虚拟化技术)