Mctrain's Blog

What I learned in IT, as well as thought about life

Intel中断虚拟化中的posted Interrupt处理

| Comments

这篇博文中我介绍了“中断处理的那些事儿”,其中有简单地提到“中断虚拟化”的一些概念,同时介绍了虚拟化层如何模拟虚拟机对APIC控制寄存器的读写操作,以及对中断的delivery步骤。

在这篇文章中,我们主要介绍中断虚拟化中的另外一个特性:posted interrupt (PI)。

这篇文章主要参考了Intel文档第三册的第29.6章节,以及Intel 2016年6月份发布的文档Intel® Virtualization Technology for Directed I/O中的第5.2章节。

Interrupt remapping

Interrupt remapping是硬件提供的一套机制,它使得虚拟化层能够通过配置对I/O设备产生的外部中断进行remapping和routing,从而对不同设备产生的不同中断进行相应的重映射,并且控制该中断请求相应的属性(如destination CPU,interrupt vector,delivery mode等)。

而interrupt remapping table (IRT)就是用于控制该中断重映射的数据结构。

一般来说,设备产生中断的方法是往一个0xFEEX_XXXXh地址进行一次写操作,而低地址的那些bits则记录了相应的控制信息,比如,对于一个传统的中断,其中断请求的格式如下:

Compatibility Format Interrupt Request

它直接在中断请求中定义了包括Destination ID,Vector,Delivery Mode等在内的信息。也就是说每当设备产生该中断时,就决定了该中断以怎样的vector和delivery mode被传送到哪个相应的目标核中。

而在remapping的模式下,中断请求的格式如下:

Remappable Format Interrupt Request

在该格式下,中断请求本身并没有定义该中断的控制信息,它只是定义了一个handle和一个subhandle号,通过它们会得到一个interrupt_index,它定义了在IRT中该重映射的中断所对应的entry的index,计算方法如下:

IRTE calculation

可以看到,区别compatibility和remappable格式的中断的方法是通过第4个bit(interrupt format bit),即如果该bit为0,则为compatibility中断,否则,则是remappable中断。

在得到interrupt_index之后,我们可以从IRT中得到相应的IRTE(interrupt remapping table entry)。事实上,可重映射的中断也分为两种格式,一种被称为remapped interrupt,另一种被称为posted interrupt。而IRTE也会根据这两种中断类型定义不同的格式,在本文中,我们主要关注第二种posted interrupt,其IRTE格式如下:

IRTE Format for Posted Interrupts

可以看出IRTE是一个128bits的数据结构,里面主要包含了以下几个关键的信息:

  • Posted Descriptor Address High (96:127)和Posted Descriptor Address Low (38:64):定义了posted descriptor address,通过它可以得到相应的一个posted descriptor在内存中的地址。
  • Vector (16:23):定义了该IRTE对应的中断的中断号。
  • Urgent (14):定义了该IRTE对应的interrupt是否需要马上处理,1表示需要马上处理,0表示可延迟处理。
  • P (0):表示该IRTE是否存在且合法,1表示可用,0表示不可用。

至于其它的几个bits,在这里可以先不考虑。

另外,posted descriptor的格式如下:

Posted Interrupt Descriptor Format

其包含如下几个信息:

  • NDST (Notification Destination):定义了目标地址,其计算方法如下:

NDST

  • NV (Notification Vector):表示用于notification event对应的physical vector,会在之后进行解释。
  • SN (Suppress Notification):表示对于non_urgent的中断是否需要发送。如果该中断是non-urgent(即IRTE中的urgent bit为0),而SN bit为1,则不触发该中断的posting。
  • ON (Outstanding Notification):表示是否有pending的中断正在被相应的CPU处理。
  • PIR (Posted Interrupt Requsts):它是一个256bits的域,每个bit表示对应的vector,也就是说,IRTE中的vector会将对应的bit设上,表示该中断需要被处理。

Posted interrupt processing

在了解了所有的数据结构之后,我们来看看PI是如何被处理的。

一般情况下,如果VMCS中的VM-execution controlexternal-interrupt exiting被设为1,则任何unmasked的外部中断都会引发虚拟机下陷(VM exit),除非VM-execution control中的process posted interrupts也被设为1。这个时候,处理器处理该中断的步骤如下:

  1. 相应处理器的本地APIC会得到一个相应的中断向量(interrupt vector)。
  2. 如果该中断向量等于VMCS中posted-interrupt notification vector域中的值,则表示该中断是一个posted interrupt,进入第三步,否则表示该中断是一个普通的外部中断,发生虚拟机下陷。
  3. 处理器将posted-interrupt descriptor中的ON bit清零。
  4. 处理器将本地APIC中的EOI写零。
  5. 处理器将VIRR和PIR进行逻辑或(logical-OR)操作,并且将PIR清零。
  6. 处理器将RVI设置成相应的值(即RVI原本的值和PIR最高位中的最大值)。
  7. 处理器对pending virtual interrupts进行evaluation(参阅这篇博文)。

在这个步骤中,最关键的点在于处理器是如何接收到和VMCS中posted-interrupt notification vector域相同的中断向量的。这就要回到之前提到的posted interrupt descriptor了。

我们知道,虚拟化层在配置posted interrupt descriptor时,会填入一个NV值,该值表示当设备产生的中断被重定向到相应posted interrupt的时候,会向目标APIC发送的physical vector。也就是说,如果我们希望该posted interrupt被发送给相应虚拟机正在运行的逻辑核的话,那么在虚拟化层对该虚拟机进行调度的时候,就将相应的posted interrupt descriptor中的NV设置成相应的notification vector。那么每当该中断被发送到该逻辑核,就会触发之前的步骤,而不用发生虚拟机下陷了。

最后我们来整理一下,看看整个流程是怎么样的吧。

首先是虚拟化层软件(VMM)对posted interrupt进行配置:

  • 对于虚拟机中的每一个virtual processor,VMM都会分配一个独立的posted interrupt descriptor。
  • VMM也会准备两个physical interrupt vectors:其中一个被称为Active Notification Vector (ANV),用于向正在运行的VM进行post;另一个被称为Wake-up Notification Vector (WNV),用于向暂停的VM进行post。
  • 当guest VM对相应的interrupt source进行配置的时候,VMM会对该配置过程进行拦截,并且为其分配一个相应的IRTE,其中,IRTE中的vector field被配置成相应的vector值,IRTE中的posted descriptor address field被配置成相应posted descriptor的地址,并且根据guest VM提供的信息决定是否设置urgent bit。
  • 最后,VMM使能APIC virtualization,即开启VMCS中相应的virtual-interrupt deliveryprocess posted interruptsbit。

之后,当VMM中的调度器对virtual processor进行调度的时候,VMM会进行以下相应的处理:

  • 如果该virtual processor被选择为可执行,表示该virtual processor的状态被设置成active,VMM则会将其相对应的posted interrupt descriptor中的NV设置成ANV,则每当该posted interrupt产生的时候,硬件会向相应的逻辑核发送vector为ANV的中断,从而不会发生虚拟机下陷;
  • 如果该virtual processor被抢占或者被终止,则VMM会将posted interrupt descriptor中的SN设为1,表示任何non-urgent的中断都不会发送相应的notification interrupt,同时将NV设置成WNV,表示其它urgent的中断会发送vector为WNV的中断,发生虚拟机下陷,而VMM则可以根据该中断向量号进行相应的处理。

当然,以上所描述的都是基于VT-d的interrupt remapping机制。如果没有vt-d设备,CPU本身也支持posted interrupt机制。该过程发生在VMM向虚拟机inject virtual interrupt的时候,在这个过程中,VMM会向posted interrupt descriptor中写入相应的值(主要是PIR),然后通过IPI向相应的逻辑核发送特定的notification event。这个时候,该IPI也不会引发虚拟机下陷。整个过程如下图所示:

CPU-based posted interrupt

Comments