2018-10-27 07:40:48 +08:00
|
|
|
.. _virtual-interrupt-hld:
|
|
|
|
|
|
|
|
Virtual Interrupt
|
|
|
|
#################
|
|
|
|
|
2019-11-08 07:24:31 +08:00
|
|
|
This section introduces the ACRN guest virtual interrupt
|
2018-10-27 07:40:48 +08:00
|
|
|
management, which includes:
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
- vCPU request for virtual interrupt kickoff
|
|
|
|
- vPIC, vIOAPIC, and vLAPIC for virtual interrupt injection interfaces
|
|
|
|
- physical-to-virtual interrupt mapping for a passthrough device
|
|
|
|
- the process of VMX interrupt and exception injection
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
A standard VM never owns any physical interrupts. All interrupts received by the
|
|
|
|
guest OS come from a virtual interrupt injected by vLAPIC, vIOAPIC, or
|
2020-06-19 02:38:09 +08:00
|
|
|
vPIC. Such virtual interrupts are triggered either from a passthrough
|
2019-11-08 07:24:31 +08:00
|
|
|
device or from I/O mediators in the Service VM via hypercalls. The
|
2022-02-26 08:48:16 +08:00
|
|
|
:ref:`interrupt-remapping` section describes how the hypervisor manages
|
2020-06-19 02:38:09 +08:00
|
|
|
the mapping between physical and virtual interrupts for passthrough
|
2022-02-26 08:48:16 +08:00
|
|
|
devices. However, a hard RTVM with LAPIC passthrough does own the physical
|
2019-10-21 09:49:55 +08:00
|
|
|
maskable external interrupts. On its physical CPUs, interrupts are disabled
|
2022-02-26 08:48:16 +08:00
|
|
|
in VMX root mode. While in VMX non-root mode, physical interrupts are
|
|
|
|
delivered to the RTVM directly.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
Devices are emulated inside the Service VM Device Model, i.e.,
|
|
|
|
``acrn-dm``. However, for performance consideration, vLAPIC, vIOAPIC, and vPIC
|
|
|
|
are emulated inside the hypervisor directly.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2019-11-08 07:24:31 +08:00
|
|
|
From the guest OS point of view, vPIC is Virtual Wire Mode via vIOAPIC. The
|
2018-10-27 07:40:48 +08:00
|
|
|
symmetric I/O Mode is shown in :numref:`pending-virt-interrupt` later in
|
|
|
|
this section.
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
The following command-line options to a Linux guest affect whether it uses PIC
|
|
|
|
or IOAPIC:
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
- **Kernel boot parameter with vPIC**: Add ``maxcpu=0``. The guest OS will use
|
|
|
|
PIC.
|
|
|
|
- **Kernel boot parameter with vIOAPIC**: Add ``maxcpu=1`` (as long as not
|
|
|
|
"0"). The guest OS will use IOAPIC and keep IOAPIC pin 2 as the source of
|
|
|
|
PIC.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2019-08-25 07:47:33 +08:00
|
|
|
.. _vcpu-request-interrupt-injection:
|
|
|
|
|
2018-10-27 07:40:48 +08:00
|
|
|
vCPU Request for Interrupt Injection
|
|
|
|
************************************
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
The vCPU request mechanism (described in :ref:`pending-request-handlers`) is
|
|
|
|
used to inject interrupts to a certain vCPU. As mentioned in
|
|
|
|
:ref:`ipi-management`, physical vector 0xF0 is used to kick the vCPU out of its
|
|
|
|
VMX non-root mode. Physical vector 0xF0 is also used to make a request for
|
|
|
|
virtual interrupt injection or other requests such as flush EPT.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
.. note:: The IPI-based vCPU request mechanism doesn't work for the hard RTVM.
|
2019-10-21 09:49:55 +08:00
|
|
|
|
2018-10-27 07:40:48 +08:00
|
|
|
The eventid supported for virtual interrupt injection includes:
|
|
|
|
|
2019-05-07 16:52:39 +08:00
|
|
|
.. doxygengroup:: virt_int_injection
|
|
|
|
:project: Project ACRN
|
|
|
|
:content-only:
|
2018-10-27 07:40:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
The *vcpu_make_request* is necessary for a virtual interrupt
|
|
|
|
injection. If the target vCPU is running under VMX non-root mode, it
|
2022-02-26 08:48:16 +08:00
|
|
|
sends an IPI to kick it out, which leads to an external-interrupt
|
|
|
|
VM-Exit. In some cases, there is no need to send an IPI when making a request,
|
|
|
|
because the CPU making the request itself is the target vCPU. For
|
2018-10-27 07:40:48 +08:00
|
|
|
example, the #GP exception request always happens on the current CPU when it
|
2020-06-19 02:38:09 +08:00
|
|
|
finds an invalid emulation has happened. An external interrupt for a passthrough
|
2022-02-26 08:48:16 +08:00
|
|
|
device always happens on the vCPUs of the VM that the device belongs to.
|
|
|
|
After it triggers an external-interrupt VM-Exit, the current CPU is the
|
|
|
|
target vCPU.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
|
|
|
Virtual LAPIC
|
|
|
|
*************
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
LAPIC is virtualized for all guest types: Service VM and User VMs. Given support
|
|
|
|
by the physical processor, APICv virtual interrupt delivery (VID) is enabled
|
|
|
|
and supports the Posted-Interrupt feature. Otherwise, it falls back to
|
2019-11-08 07:24:31 +08:00
|
|
|
the legacy virtual interrupt injection mode.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
|
|
|
vLAPIC provides the same features as the native LAPIC:
|
|
|
|
|
|
|
|
- Vector mask/unmask
|
|
|
|
- Virtual vector injections (Level or Edge trigger mode) to vCPU
|
|
|
|
- vIOAPIC notification of EOI processing
|
|
|
|
- TSC Timer service
|
|
|
|
- vLAPIC support CR8 to update TPR
|
|
|
|
- INIT/STARTUP handling
|
|
|
|
|
|
|
|
vLAPIC APIs
|
|
|
|
===========
|
|
|
|
|
2019-10-21 09:49:55 +08:00
|
|
|
APIs are invoked when an interrupt source from vLAPIC needs to inject
|
2018-10-27 07:40:48 +08:00
|
|
|
an interrupt, for example:
|
|
|
|
|
|
|
|
- from LVT like LAPIC timer
|
2020-06-19 02:38:09 +08:00
|
|
|
- from vIOAPIC for a passthrough device interrupt
|
2022-02-26 08:48:16 +08:00
|
|
|
- from an emulated device for an MSI
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
These APIs finish by making a vCPU request.
|
2019-10-30 08:04:53 +08:00
|
|
|
|
2019-10-21 09:49:55 +08:00
|
|
|
.. doxygenfunction:: vlapic_inject_intr
|
|
|
|
:project: Project ACRN
|
|
|
|
|
|
|
|
.. doxygenfunction:: vlapic_set_intr
|
|
|
|
:project: Project ACRN
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2018-11-01 22:30:47 +08:00
|
|
|
.. doxygenfunction:: vlapic_set_local_intr
|
|
|
|
:project: Project ACRN
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2020-10-23 15:26:34 +08:00
|
|
|
.. doxygenfunction:: vlapic_inject_msi
|
2018-11-01 22:30:47 +08:00
|
|
|
:project: Project ACRN
|
|
|
|
|
2019-10-21 09:49:55 +08:00
|
|
|
.. doxygenfunction:: vlapic_receive_intr
|
2018-11-01 22:30:47 +08:00
|
|
|
:project: Project ACRN
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2021-02-13 08:27:24 +08:00
|
|
|
EOI Processing
|
2018-10-27 07:40:48 +08:00
|
|
|
==============
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
If APICv virtual interrupt delivery is supported, EOI virtualization is enabled.
|
|
|
|
Except for level triggered interrupts, the VM will not exit in case of EOI.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
If APICv virtual interrupt delivery is not supported, vLAPIC requires
|
|
|
|
EOI from the guest OS whenever a vector is acknowledged and processed by the
|
|
|
|
guest. vLAPIC behavior is the same as hardware LAPIC. Once an EOI is received,
|
2019-10-21 09:49:55 +08:00
|
|
|
it clears the highest priority vector in ISR, and updates PPR
|
2022-02-26 08:48:16 +08:00
|
|
|
status. vLAPIC sends an EOI message to vIOAPIC if the TMR bit is set to
|
2019-10-21 09:49:55 +08:00
|
|
|
indicate that is a level triggered interrupt.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2019-10-18 14:15:46 +08:00
|
|
|
.. _lapic_passthru:
|
|
|
|
|
2021-02-13 08:27:24 +08:00
|
|
|
LAPIC Passthrough Based on vLAPIC
|
2019-01-24 20:04:33 +08:00
|
|
|
=================================
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
LAPIC passthrough is supported based on vLAPIC. The guest OS first boots with
|
2019-10-21 09:49:55 +08:00
|
|
|
vLAPIC in xAPIC mode and then switches to x2APIC mode to enable the LAPIC
|
2020-06-19 02:38:09 +08:00
|
|
|
passthrough.
|
2019-10-21 09:49:55 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
If LAPIC passthrough is based on vLAPIC, the system has the
|
|
|
|
following characteristics:
|
2019-01-24 20:04:33 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
* IRQs received by the LAPIC can be handled by the guest VM without ``vmexit``.
|
|
|
|
* Guest VM always sees virtual LAPIC IDs for security consideration.
|
|
|
|
* Most MSRs are directly accessible from the guest VM except for ``XAPICID``,
|
|
|
|
``LDR``, and ``ICR``. Write operations to ``ICR`` are trapped to avoid
|
|
|
|
malicious IPIs. Read operations to ``XAPIC`` and ``LDR`` are trapped,
|
|
|
|
so that the guest VM always sees the virtual LAPIC IDs instead of the
|
2019-01-24 20:04:33 +08:00
|
|
|
physical ones.
|
|
|
|
|
2018-10-27 07:40:48 +08:00
|
|
|
Virtual IOAPIC
|
|
|
|
**************
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
The hypervisor emulates vIOAPIC when the guest accesses the MMIO GPA range:
|
|
|
|
0xFEC00000-0xFEC01000. vIOAPIC for the Service VM should match the native
|
|
|
|
hardware IOAPIC pin numbers. vIOAPIC for a guest VM provides 48 pins. As the
|
|
|
|
vIOAPIC is always associated with vLAPIC, the virtual interrupt injection from
|
|
|
|
vIOAPIC triggers a request for a vLAPIC event by calling vLAPIC APIs.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
|
|
|
**Supported APIs:**
|
|
|
|
|
2019-01-07 11:39:15 +08:00
|
|
|
.. doxygenfunction:: vioapic_set_irqline_lock
|
2018-11-01 22:30:47 +08:00
|
|
|
:project: Project ACRN
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2019-01-07 11:39:15 +08:00
|
|
|
.. doxygenfunction:: vioapic_set_irqline_nolock
|
2018-11-01 22:30:47 +08:00
|
|
|
:project: Project ACRN
|
2018-10-27 07:40:48 +08:00
|
|
|
|
|
|
|
Virtual PIC
|
|
|
|
***********
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
vPIC is required for TSC calculation. Normally the guest OS boots with
|
2019-10-21 09:49:55 +08:00
|
|
|
vIOAPIC and vPIC as the source of external interrupts. On every
|
2022-02-26 08:48:16 +08:00
|
|
|
VM Exit, the hypervisor checks for pending external PIC interrupts.
|
|
|
|
Usage of vPIC APIs is similar to that of vIOAPIC.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
ACRN hypervisor emulates a vPIC for each VM based on I/O range 0x20~0x21,
|
|
|
|
0xa0~0xa1, and 0x4d0~0x4d1.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
If an interrupt source from vPIC needs to inject an interrupt, the
|
2018-10-27 07:40:48 +08:00
|
|
|
following APIs need be called, which will finally make a request for
|
2022-02-26 08:48:16 +08:00
|
|
|
``ACRN_REQUEST_EXTINT`` or ``ACRN_REQUEST_EVENT``:
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2019-01-07 11:39:15 +08:00
|
|
|
.. doxygenfunction:: vpic_set_irqline
|
2018-11-01 22:30:47 +08:00
|
|
|
:project: Project ACRN
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
The following APIs are used to query the vector that needs to be injected and
|
|
|
|
ACK the service (move the interrupt from request service - IRR to in
|
2018-10-27 07:40:48 +08:00
|
|
|
service - ISR):
|
|
|
|
|
2018-11-01 22:30:47 +08:00
|
|
|
.. doxygenfunction:: vpic_pending_intr
|
|
|
|
:project: Project ACRN
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2018-11-01 22:30:47 +08:00
|
|
|
.. doxygenfunction:: vpic_intr_accepted
|
|
|
|
:project: Project ACRN
|
2018-10-27 07:40:48 +08:00
|
|
|
|
|
|
|
Virtual Exception
|
|
|
|
*****************
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
When doing emulation, an exception may need to be triggered in the
|
|
|
|
hypervisor for these reasons:
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
- The guest accesses an invalid vMSR register.
|
|
|
|
- The hypervisor needs to inject a #GP.
|
|
|
|
- The hypervisor needs to inject a #PF when an instruction accesses a
|
|
|
|
non-existent page from ``rip_gva`` during instruction emulation.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
|
|
|
ACRN hypervisor implements virtual exception injection using these APIs:
|
|
|
|
|
2018-11-01 22:30:47 +08:00
|
|
|
.. doxygenfunction:: vcpu_queue_exception
|
|
|
|
:project: Project ACRN
|
|
|
|
|
|
|
|
.. doxygenfunction:: vcpu_inject_gp
|
|
|
|
:project: Project ACRN
|
|
|
|
|
|
|
|
.. doxygenfunction:: vcpu_inject_pf
|
|
|
|
:project: Project ACRN
|
|
|
|
|
|
|
|
.. doxygenfunction:: vcpu_inject_ud
|
|
|
|
:project: Project ACRN
|
|
|
|
|
|
|
|
.. doxygenfunction:: vcpu_inject_ss
|
|
|
|
:project: Project ACRN
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
ACRN hypervisor uses the ``vcpu_inject_gp`` and ``vcpu_inject_pf`` functions to
|
|
|
|
queue an exception request. The hypervisor follows `Intel® 64 and IA-32 Architectures Software Developer's Manual <https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html>`__, Volume 3, Section 6.15, Table 6-5, to
|
|
|
|
generate a double fault if the condition is met.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
ACRN hypervisor can inject ``extint`` and ``nmi`` using similar vCPU APIs:
|
2019-10-21 09:49:55 +08:00
|
|
|
|
|
|
|
.. doxygenfunction:: vcpu_inject_extint
|
|
|
|
:project: Project ACRN
|
|
|
|
|
|
|
|
.. doxygenfunction:: vcpu_inject_nmi
|
|
|
|
:project: Project ACRN
|
|
|
|
|
|
|
|
|
2019-08-25 07:47:33 +08:00
|
|
|
.. _virt-interrupt-injection:
|
|
|
|
|
2018-10-27 07:40:48 +08:00
|
|
|
Virtual Interrupt Injection
|
|
|
|
***************************
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
Virtual interrupts come from the DM or assigned
|
2018-10-27 07:40:48 +08:00
|
|
|
devices.
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
- **For Service VM assigned devices**: Whenever a physical interrupt
|
|
|
|
is from an assigned
|
|
|
|
device, the corresponding virtual interrupt is injected to the Service
|
2019-10-21 09:49:55 +08:00
|
|
|
VM via vLAPIC/vIOAPIC. See :ref:`device-assignment`.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
- **For User VM assigned devices**: Only PCI devices can be assigned to
|
|
|
|
User VMs. For the standard VM and soft RTVM, the virtual interrupt
|
|
|
|
injection process is the same way as for the Service VM. A virtual interrupt
|
|
|
|
injection
|
2019-10-21 09:49:55 +08:00
|
|
|
operation is triggered when a device's physical interrupt occurs. For the
|
2022-02-26 08:48:16 +08:00
|
|
|
hard RTVM, the physical interrupts are delivered to the VM directly without
|
2019-10-21 09:49:55 +08:00
|
|
|
causing VM-exit.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
- **For User VM emulated devices**: DM manages the interrupt lifecycle of
|
|
|
|
emulated devices. DM knows when
|
|
|
|
an emulated device needs to assert a virtual IOAPIC/PIC pin or
|
|
|
|
needs to send a virtual MSI vector to the guest. The logic is
|
|
|
|
entirely handled by DM. Hard RTVMs should not have
|
2019-10-21 09:49:55 +08:00
|
|
|
emulated devices.
|
2018-10-27 07:40:48 +08:00
|
|
|
|
|
|
|
.. figure:: images/virtint-image64.png
|
|
|
|
:align: center
|
|
|
|
:name: pending-virt-interrupt
|
|
|
|
|
|
|
|
Handle pending virtual interrupt
|
|
|
|
|
|
|
|
Before APICv virtual interrupt delivery, a virtual interrupt can be
|
2022-02-26 08:48:16 +08:00
|
|
|
injected only if the guest interrupt is allowed. In many cases,
|
|
|
|
the guest ``RFLAGS.IF`` gets cleared and does not accept any further
|
|
|
|
interrupts. The hypervisor checks for the available guest IRQ windows before
|
2018-10-27 07:40:48 +08:00
|
|
|
injection.
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
NMI is an unmaskable interrupt and its injection is always allowed
|
|
|
|
regardless of the guest IRQ window status. If the current IRQ
|
|
|
|
window is not present, the hypervisor enables
|
2018-10-27 07:40:48 +08:00
|
|
|
``MSR_IA32_VMX_PROCBASED_CTLS_IRQ_WIN (PROCBASED_CTRL.bit[2])`` and
|
2022-02-26 08:48:16 +08:00
|
|
|
VM Enter directly. The injection will be done on the next VM Exit once the guest
|
2018-10-27 07:40:48 +08:00
|
|
|
issues ``STI (GuestRFLAG.IF=1)``.
|
|
|
|
|
2021-02-13 08:27:24 +08:00
|
|
|
Data Structures and Interfaces
|
2018-10-27 07:40:48 +08:00
|
|
|
******************************
|
|
|
|
|
2022-02-26 08:48:16 +08:00
|
|
|
No data structure is exported to the other components in the
|
2018-10-27 07:40:48 +08:00
|
|
|
hypervisor for virtual interrupts. The APIs listed in the previous
|
|
|
|
sections are meant to be called whenever a virtual interrupt should be
|
|
|
|
injected or acknowledged.
|