x86: Virtualize IOAPIC redir table for interrupt remapping support

Handover the IOAPIC on hypervisor setup by first masking all pins, then
requesting interrupt remapping from VT-d and finally reprogramming them
according to the index that VT-d reported. If vtd_map_interrupt returns
-ENOSYS, unconditionally right now due to a missing implementation,
later on when running in QEMU, we continue to write the redirection
table entry unmodified.

As we may lose edge-triggered interrupts while they are makes, we inject
them unconditionally into the target CPU. This may cause one spurious
interrupt per handover to/from the hypervisor, but Linux can deal with
that.

Whenever a cell is added or removed, we rewrite all root cell IOAPIC
redir table entries in order to validate them regarding the target CPU
masks.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core: Virtualize legacy MSI for interrupt remapping support

Analogously to edge-triggered IOAPIC interrupts, handover all legacy
MSIs by disabling them first, programming the VT-d remapping table and
then writing remappable parameters into the MSI capability registers.
An additional triggering of active vectors ensures that we do not lose
events during handover.

Disabling is done on x86 via a trick: we program an empty CPU mask in
logical destination mode.

MSI-X remains on the to-do list. Thus, once enabling interrupt
remapping, systems that use MSI-X will become unsupported for the time
being.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core: Pack jailhouse_system::platform_info

Better safe than sorry: the packed attribute does not apply on nested
structs and unions.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
x86: Perform VT-d interrupt remapping table programming

This fills vtd_map_interrupt with the missing logic to set entries in
the interrupt remapping table and programs the hardware to use that
table, blocking all non-remappable interrupts.

vtd_map_interrupt performs the required entry validation and rejects any
improper settings. There is one exception: CPU masks in logical
destination mode will silently be adjusted instead of failing the
service call. The reason is that Linux may have these masks set for
practically inactive interrupt vectors programmed  (e.g. enabled MSI
vectors of PCIe ports without any port service using them) and will only
update them when they may be used again. Failing such settings would
stop Linux prematurely.

We reserve remapping table entries for the IOAPIC upon cell creation. We
also reserve as many entries as MSI vectors are reported for each PCI
device of a cell. IOAPIC reservation happens only once, and the region
is kept over the lifetime of the hypervisor as the IOAPIC may be shared
between cells (though this is not recommended). PCI device reservations
are released again when the device is removed from its owning cell.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
configs/x86: Add check for VT-d existence

Add a check that validates the existence of configured VT-d units.
Require that every config contains at least one unit. Experimental VT-d
emulation, including interrupt remapping support, is now available for
QEMU. So we can set the config fields accordingly. If VT-d is disabled
or a QEMU version without that support is used, the hypervisor continues
to ignore this error.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
configs/tools: Provide MSI-X parameters via config

It is simpler to calculate and validate these offline than to do it
during hypervisor setup.

Add the new information to the QEMU config file.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
configs/tools: Exclude MSI-X table from memory regions

We need to virtualize the access to the MSI-X table, thus we have to
prevent that the cells access them directly. As the table may be
embedded into a larger BAR, specifically followed by the PBA, split up
the BAR region as required.

Update the QEMU config accordingly - currently the only config with
MSI-X devices.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
x86: Factor out pci_get_x86_msi_remap_address

Will be reused for MSI-X support

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core: Add MAX macro

To be used by VT-d code.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core: Virtualize MSI-X for interrupt remapping support

Similar to MSI support, this adds virtualization of MSI-X in order to
remap those interrupts via VT-d.

We have to intercept the MMIO access to the MSI-X tables of PCI devices
for this. Finding the corresponding device is done via a separate
per-cell list of all MSI-X capable PCI devices a cell contains. It is
built during cell creation, i.e. when devices are added, and it shrinks
again when devices are removed from a cell.

MSI-X device handover from/to Linux is simpler as we can centrally mask
all MSI-X vectors of a device.

As we may intercept more than the MSI-X table, accesses beyond it have
to be processed as well. Writes to the PBA are not allowed, reads from
anything after the table are simply performed on behalf of the cell.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
x86: Consolidate VT-d unit initialization

Move TE and IRE setting into vtd_init_unit and call that services only
when we perform the initial configuration commit. This will also help
with handing over VT-d to Jailhouse in case we take over interrupt
remapping and queued invalidation from Linux.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
x86: Simplify DMAR unit discovery

Perform counting and resource allocation before iterating over all
units. This not only allows to drop some code but also removes the
restrictive allocation pattern for the unit MMIO and invalidation queue
pages.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core/configs/tools: Report IOMMU association of devices via config file

We will need this information for emulating VT-d for the root cell:

Add an iommu field to the PCI device config structure and encode the
unit number in the id field of the IOAPIC's irqchip structure.
The config generator fills the fields according to the DMAR ACPI table.
However, we do not yet understand all exotic forms of Device Scope
structures.

If it turns out that there are PCI devices without any IOMMU
association, refuse to generate a config file - such systems are
unsupported.

Update the h87i config accordingly. QEMU currently only exposes a single
DMAR unit, thus the implicit zero-initialization is fine. As the IOMMU
number is only used in the context of the root cell, ioapic-demo and
pci-demo require no updates as well.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core: Reorder CPU initialization during setup

Make sure all CPUs are initialized prior to running the late setup. On
x86, we need the APIC map to be fully populated before performing the
VT-d handover.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core: Let arch_init_late decide when to map memory regions

When VT-d emulation is used on x86, will have to access the root cell's
memory during interrupt handover. This requires us to map the memory
regions right after vtd_init.

To enable this, move the decision when to map the regions into the hands
of arch_init_late. We provide map_root_memory_regions for this.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
x86: Introduce x2apic_filter_logical_dest

This helper matches a logical destination mask, redirection hint
enabled, against a cell CPU set and removes all the CPUs from the mask
that are not part of the cell. This can be used to filter/validate IRTE
parameters before programming them.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core: Introduce accessors for current per_cpu fields

Reserve a register for a quick lookup of fields in the current per_cpu
data structure and enable the address, cpu_id and cell for such direct
access. The accessors are named this_<field>().

This will allow us to avoid passing context references around to deeply
nested users.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core: Enhance page_map_get_guest_page(s)

Generalize page_map_get_guest_page to map multiple pages in a single
run. Moreover, accept both guest-physical and guest-virtual addresses as
input: if pg_structs is NULL, a physical address is provided.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core: Remove cpu_data parameter from page_map_get_guest_pages

page_map_get_guest_pages is only allowed to work against the current
CPU. Now that we have this_cpu_data(), we can remove that parameter
from page_map_get_guest_pages to encode this in the API.

This also affects some (indirect) callers positively.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
core: Switch cell_create to page_map_get_guest_pages

This consolidates the code and provides us guest address validation. The
latter is not yet critical as the configuration file may mess up much
more, but it's nice to have and may be beneficial once we can validate
configurations in some Linux-independent way.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>