x86intelinterruptvirtualizationhypervisor

Intel VT-x: How do I trigger posted interrupt processing on the same core?


I'm struggling to fully understand the posted interrupt processing feature in Intel VT-x. Ignoring VT-d for the moment, as a first baby step I am just trying to get CPU based posted interrupt delivery working in our VMM on a single core.

With the guest running on the same physical core as the VMM, when an external interrupt arrives, it causes a VM-exit. As I understand it, the hypervisor is then responsible for setting the corresponding bits in the posted interrupt descriptor (PID) PIR field and setting the Outstanding Notification (ON) flag. The posted interrupt processing is supposed to be responsible for synchronizing the PIR with the IRR and then setting the ISR and selecting RVI automatically to enable the virtual interrupt delivery.

As an intermediate step, I tested the virtual interrupt delivery to make sure the EOI/PPR virtualization worked as expected and had no problems. If I manually set the RVI of the guest interrupt status VMCS field the interrupt is delivered to the guest after executing VMRESUME and EOI virtualization works as described in the Intel SDM. Where I get lost is in the triggering of posted interrupt processing when running in the hypervisor thread where the guest VM-exit has already occurred.

The SDM chapter 31.6 says this:

If the “external-interrupt exiting” VM-execution control is 1, any unmasked external interrupt causes a VM exit (see Section 27.2). If the “process posted interrupts” VM-execution control is also 1, this behavior is changed and the processor handles an external interrupt as follows:

  1. The local APIC is acknowledged; this provides the processor core with an interrupt vector, called here the physical vector.
  2. If the physical vector equals the posted-interrupt notification vector, the logical processor continues to the next step. Otherwise, a VM exit occurs as it would normally due to an external interrupt; the vector is saved in the VM-exit interruption-information field.

That point 2 seems to be the key. In the scenario I have described, an external interrupt has already caused a VM-exit from the guest for which I want to inject the interrupt via posted interrupt processing. My understanding of the notification vector is that its purpose is to signal a remote vcore that there may be pending interrupts in its PID->PIR in order for those interrupts to be processed ideally without causing a VM-exit. But in my case, everything is running on the same core and the VM-exit has already occurred. So I guess with all of that background, my main questions are:

In my attempts so far, it seems pretty clear that the VM entry alone does not trigger posted interrupt processing - that is, despite the PID having been updated during the VM-exit to set the PIR and ON bits, I see no changes to the virtual APIC IRR/ISR - the interrupt is not delivered to the guest. I feel like there is something fundamental that I'm still not understanding with respect to the NV. Any help would be appreciated.

EDIT: Or perhaps my misunderstanding is even more basic: Is posted interrupt processing intended exclusively to handle interrupt posting to a remote core? If everything is running on the same physical core, maybe posted interrupt processing is irrelevant and all I can/should be doing is directly setting RVI in VMM software?


Solution

  • Posted interrupt processing is designed to support the following: a physical interrupt comes into the IOMMU, the virtual interrupt is posted in the PID by the IOMMU, and then the physical notification interrupt is delivered from the IOMMU to the CPU.

    The Posted Interrupt Processing section in the SDM (vol 3, 31.6) describes the steps the CPU performs when an external interrupt is received that matches the posted interrupt notification vector.

    If you aren't using the IOMMU to generate the notification interrupt, then you need to emulate that behavior in software.

    After you have emulated the steps of posted interrupt processing, then you can trigger delivery of the virtual interrupt as described in 31.2. This part is easy: VM entry causes evaluation of pending virtual interrupts if the virtual interrupt delivery execution control is 1.