@@ -14,6 +14,7 @@
#include "qemu/module.h"
#include "cpu.h"
#include "hw/i386/apic_internal.h"
+#include "hw/i386/apic-msidef.h"
#include "hw/pci/msi.h"
#include "sysemu/hw_accel.h"
#include "sysemu/kvm.h"
@@ -183,6 +184,13 @@ static void kvm_send_msi(MSIMessage *msg)
{
int ret;
+ /*
+ * The message has already passed through interrupt remapping if enabled,
+ * but the legacy extended destination ID in low bits still needs to be
+ * handled.
+ */
+ msg->address = apic_convert_ext_dest_id(msg->address);
+
ret = kvm_irqchip_send_msi(kvm_state, *msg);
if (ret < 0) {
fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n",
@@ -807,7 +807,7 @@ void pc_machine_done(Notifier *notifier, void *data)
fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
}
- if (x86ms->apic_id_limit > 255 && !xen_enabled()) {
+ if (0 && x86ms->apic_id_limit > 255 && !xen_enabled()) {
IntelIOMMUState *iommu = INTEL_IOMMU_DEVICE(x86_iommu_get_default());
if (!iommu || !x86_iommu_ir_supported(X86_IOMMU_DEVICE(iommu)) ||
@@ -28,4 +28,20 @@
#define MSI_ADDR_DEST_IDX_SHIFT 4
#define MSI_ADDR_DEST_ID_MASK 0x000ff000
+static inline uint64_t apic_convert_ext_dest_id(uint64_t address)
+{
+ uint64_t ext_id = address & (0xff << MSI_ADDR_DEST_IDX_SHIFT);
+ /*
+ * If the remappable format bit is set, or the upper bits are
+ * already set in address_hi, or the low extended bits aren't
+ * there anyway, do nothing.
+ */
+ if (!ext_id || (ext_id & (1 << MSI_ADDR_DEST_IDX_SHIFT)) ||
+ (address >> 32))
+ return address;
+
+ address &= ~ext_id;
+ address |= ext_id << 35;
+ return address;
+}
#endif /* HW_APIC_MSIDEF_H */
@@ -4589,13 +4589,11 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
X86IOMMUState *iommu = x86_iommu_get_default();
if (iommu) {
- int ret;
- MSIMessage src, dst;
X86IOMMUClass *class = X86_IOMMU_DEVICE_GET_CLASS(iommu);
- if (!class->int_remap) {
- return 0;
- }
+ if (class->int_remap) {
+ int ret;
+ MSIMessage src, dst;
src.address = route->u.msi.address_hi;
src.address <<= VTD_MSI_ADDR_HI_SHIFT;
@@ -4610,11 +4608,21 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
return 1;
}
+ /*
+ * Handled untranslated compatibilty format interrupt with
+ * extended destination ID in the low bits 11-5. */
+ dst.address = apic_convert_ext_dest_id(dst.address);
+
route->u.msi.address_hi = dst.address >> VTD_MSI_ADDR_HI_SHIFT;
route->u.msi.address_lo = dst.address & VTD_MSI_ADDR_LO_MASK;
route->u.msi.data = dst.data;
+ return 0;
+ }
}
+ address = apic_convert_ext_dest_id(address);
+ route->u.msi.address_hi = address >> VTD_MSI_ADDR_HI_SHIFT;
+ route->u.msi.address_lo = address & VTD_MSI_ADDR_LO_MASK;
return 0;
}