- Timestamp:
- May 25, 2020 4:06:07 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r84432 r84515 441 441 #define SYSMGTTYPE_MSG_INT_ALLOW (2) 442 442 #define SYSMGTTYPE_DMA_ALLOW (3) 443 /** @} */ 444 445 /** @name IOMMU_INTR_CTRL_XX: DTE::IntCtl field values. 446 * These are control bits for handling fixed and arbitrated interrupts. 447 * In accordance with the AMD spec. 448 * @{ */ 449 #define IOMMU_INTR_CTRL_TARGET_ABORT (0) 450 #define IOMMU_INTR_CTRL_FWD_UNMAPPED (1) 451 #define IOMMU_INTR_CTRL_REMAP (2) 452 #define IOMMU_INTR_CTRL_RSVD (3) 443 453 /** @} */ 444 454 … … 1771 1781 * really support a 64-bit MSI address? */ 1772 1782 #define IOMMU_MSI_ADDR_VALID_MASK UINT64_C(0xfffffffffffffffc) 1783 #define IOMMU_MSI_ADDR_ADDR_MASK UINT64_C(0x00000000fff00000) 1773 1784 /** Pointer to an MSI address register. */ 1774 1785 typedef MSI_ADDR_T *PMSI_ADDR_T; … … 4563 4574 4564 4575 /** 4576 * Reads an interrupt remapping table entry from guest memory given its DTE. 4577 * 4578 * @returns VBox status code. 4579 * @param pDevIns The IOMMU device instance. 4580 * @param pDte The device table entry. 4581 * @param enmOp The IOMMU operation being performed. 4582 * @param pIrte Where to store the interrupt remapping table entry. 4583 * 4584 * @thread Any. 4585 */ 4586 static int iommuAmdReadIrte(PPDMDEVINS pDevIns, PCDTE_T pDte, IOMMUOP enmOp, IRTE_T pIrte) 4587 { 4588 RT_NOREF(pDevIns, pDte, enmOp, pIrte); 4589 return VERR_NOT_IMPLEMENTED; 4590 } 4591 4592 4593 /** 4594 * Remap the interrupt from the appropriate IRTE. 4595 * 4596 * @returns VBox status code. 4597 * @param pDevIns The IOMMU instance data. 4598 * @param GCPhysIn The source MSI address. 4599 * @param uDataIn The source MSI data. 4600 * @param enmOp The IOMMU operation being performed. 4601 * @param pGCPhysOut Where to store the remapped MSI address. 4602 * @param puDataOut Where to store the remapped MSI data. 4603 * 4604 * @thread Any. 4605 */ 4606 static int iommuAmdRemapIntr(PPDMDEVINS pDevIns, RTGCPHYS GCPhysIn, uint32_t uDataIn, IOMMUOP enmOp, 4607 PRTGCPHYS pGCPhysOut, uint32_t *puDataOut) 4608 { 4609 RT_NOREF(pDevIns, GCPhysIn, uDataIn, enmOp, pGCPhysOut, puDataOut); 4610 return VERR_NOT_IMPLEMENTED; 4611 } 4612 4613 4614 /** 4615 * Looks up an MSI interrupt from the interrupt remapping table. 4616 * 4617 * @returns VBox status code. 4618 * @param pDevIns The IOMMU instance data. 4619 * @param uDevId The device ID. 4620 * @param GCPhysIn The source MSI address. 4621 * @param uDataIn The source MSI data. 4622 * @param enmOp The IOMMU operation being performed. 4623 * @param pGCPhysOut Where to store the remapped MSI address. 4624 * @param puDataOut Where to store the remapped MSI data. 4625 * 4626 * @thread Any. 4627 */ 4628 static int iommuAmdLookupIntrTable(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysIn, uint32_t uDataIn, IOMMUOP enmOp, 4629 PRTGCPHYS pGCPhysOut, uint32_t *puDataOut) 4630 { 4631 /* Read the device table entry from memory. */ 4632 DTE_T Dte; 4633 int rc = iommuAmdReadDte(pDevIns, uDevId, enmOp, &Dte); 4634 if (RT_SUCCESS(rc)) 4635 { 4636 /* If the DTE is not valid, all interrupts are forwarded without remapping. */ 4637 if (Dte.n.u1IntrMapValid) 4638 { 4639 /* Validate bits 255:128 of the device table entry when DTE.IV is 1. */ 4640 uint64_t const fRsvd0 = Dte.au64[2] & ~IOMMU_DTE_QWORD_2_VALID_MASK; 4641 uint64_t const fRsvd1 = Dte.au64[3] & ~IOMMU_DTE_QWORD_3_VALID_MASK; 4642 if (RT_LIKELY( !fRsvd0 4643 && !fRsvd1)) 4644 { /* likely */ } 4645 else 4646 { 4647 Log((IOMMU_LOG_PFX ": Invalid reserved bits in DTE (u64[2]=%#RX64 u64[3]=%#RX64) -> Illegal DTE\n", fRsvd0, 4648 fRsvd1)); 4649 EVT_ILLEGAL_DTE_T Event; 4650 iommuAmdInitIllegalDteEvent(uDevId, GCPhysIn, true /* fRsvdNotZero */, enmOp, &Event); 4651 iommuAmdRaiseIllegalDteEvent(pDevIns, enmOp, &Event, kIllegalDteType_RsvdNotZero); 4652 return VERR_IOMMU_INTR_REMAP_FAILED; 4653 } 4654 4655 /** @todo IOMMU: Figure out how we'll redirect LINT0 and LINT1 legacy PIC 4656 * interrupts here. */ 4657 4658 /* 4659 * Validate the MSI source address. 4660 * 4661 * 64-bit MSIs are supported by the PCI and AMD IOMMU spec. However as far as the 4662 * CPU is concerned, the MSI region is fixed and we must ensure no other device 4663 * claims the region as I/O space. 4664 * 4665 * See PCI spec. 6.1.4. "Message Signaled Interrupt (MSI) Support". 4666 * See AMD IOMMU spec. 2.8 "IOMMU Interrupt Support". 4667 * See Intel spec. 10.11.1 "Message Address Register Format". 4668 */ 4669 MSI_ADDR_T MsiAddrIn; 4670 MsiAddrIn.u64 = GCPhysIn; 4671 if ((MsiAddrIn.u64 & IOMMU_MSI_ADDR_ADDR_MASK) == VBOX_MSI_ADDR_BASE) 4672 { 4673 MSI_DATA_T MsiDataIn; 4674 MsiDataIn.u32 = uDataIn; 4675 4676 /* 4677 * The IOMMU remaps fixed and arbitrated interrupts using the IRTE. 4678 * See AMD IOMMU spec. "2.2.5.1 Interrupt Remapping Tables, Guest Virtual APIC Not Enabled". 4679 */ 4680 uint8_t const u8DeliveryMode = MsiDataIn.n.u3DeliveryMode; 4681 bool fPassThru = false; 4682 switch (u8DeliveryMode) 4683 { 4684 case VBOX_MSI_DELIVERY_MODE_FIXED: 4685 case VBOX_MSI_DELIVERY_MODE_LOWEST_PRIO: 4686 { 4687 uint8_t const uIntrCtrl = Dte.n.u2IntrCtrl; 4688 if (uIntrCtrl == IOMMU_INTR_CTRL_TARGET_ABORT) 4689 { 4690 Log((IOMMU_LOG_PFX ": IntCtl=0: Target aborting fixed/arbitrated interrupt -> Target abort\n")); 4691 iommuAmdSetPciTargetAbort(pDevIns); 4692 return VINF_SUCCESS; 4693 } 4694 4695 if (uIntrCtrl == IOMMU_INTR_CTRL_FWD_UNMAPPED) 4696 { 4697 fPassThru = true; 4698 break; 4699 } 4700 4701 if (uIntrCtrl == IOMMU_INTR_CTRL_REMAP) 4702 { 4703 /* 4704 * We don't support guest interrupt remapping yet. When we do, we'll need to 4705 * check Ctrl.u1GstVirtApicEn and use the guest Virtual APIC Table Root Pointer 4706 * in the DTE rather than the Interrupt Root Table Pointer. Since the caller 4707 * already reads the control register, add that as a parameter when we eventually 4708 * support guest interrupt remapping. For now, just assert. 4709 */ 4710 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 4711 Assert(!pThis->ExtFeat.n.u1GstVirtApicSup); 4712 NOREF(pThis); 4713 4714 return iommuAmdRemapIntr(pDevIns, GCPhysIn, uDataIn, enmOp, pGCPhysOut, puDataOut); 4715 } 4716 4717 /* Paranoia. */ 4718 Assert(uIntrCtrl == IOMMU_INTR_CTRL_RSVD); 4719 4720 Log((IOMMU_LOG_PFX ":IntCtl mode invalid %#x -> Illegal DTE", uIntrCtrl)); 4721 EVT_ILLEGAL_DTE_T Event; 4722 iommuAmdInitIllegalDteEvent(uDevId, GCPhysIn, true /* fRsvdNotZero */, enmOp, &Event); 4723 iommuAmdRaiseIllegalDteEvent(pDevIns, enmOp, &Event, kIllegalDteType_RsvdIntCtl); 4724 return VERR_IOMMU_INTR_REMAP_FAILED; 4725 } 4726 4727 /* SMIs are passed through unmapped. We don't implement SMI filters. */ 4728 case VBOX_MSI_DELIVERY_MODE_SMI: fPassThru = true; break; 4729 case VBOX_MSI_DELIVERY_MODE_NMI: fPassThru = Dte.n.u1NmiPassthru; break; 4730 case VBOX_MSI_DELIVERY_MODE_INIT: fPassThru = Dte.n.u1InitPassthru; break; 4731 case VBOX_MSI_DELIVERY_MODE_EXT_INT: fPassThru = Dte.n.u1ExtIntPassthru; break; 4732 default: 4733 { 4734 Log((IOMMU_LOG_PFX ":MSI data delivery mode invalid %#x -> Target abort", u8DeliveryMode)); 4735 iommuAmdSetPciTargetAbort(pDevIns); 4736 return VERR_IOMMU_INTR_REMAP_FAILED; 4737 } 4738 } 4739 4740 if (fPassThru) 4741 { 4742 *pGCPhysOut = GCPhysIn; 4743 *puDataOut = uDataIn; 4744 return VINF_SUCCESS; 4745 } 4746 4747 iommuAmdSetPciTargetAbort(pDevIns); 4748 return VERR_IOMMU_INTR_REMAP_FAILED; 4749 } 4750 else 4751 { 4752 Log((IOMMU_LOG_PFX ":MSI address region invalid %#RX64.", MsiAddrIn.u64)); 4753 return VERR_IOMMU_INTR_REMAP_FAILED; 4754 } 4755 } 4756 else 4757 { 4758 /** @todo IOMMU: Add to interrupt remapping cache. */ 4759 *pGCPhysOut = GCPhysIn; 4760 *puDataOut = uDataIn; 4761 return VINF_SUCCESS; 4762 } 4763 } 4764 4765 Log((IOMMU_LOG_PFX ": Failed to read device table entry. uDevId=%#x rc=%Rrc\n", uDevId, rc)); 4766 return VERR_IOMMU_INTR_REMAP_FAILED; 4767 } 4768 4769 4770 /** 4565 4771 * Interrupt remap request from a device. 4566 4772 * … … 4590 4796 if (Ctrl.n.u1IommuEn) 4591 4797 { 4592 /** @todo IOMMU: iommuAmdLookupIntrTable. */ 4798 /** @todo Cache? */ 4799 4800 return iommuAmdLookupIntrTable(pDevIns, uDevId, GCPhysIn, uDataIn, IOMMUOP_INTR_REQ, pGCPhysOut, puDataOut); 4593 4801 } 4594 4802
Note:
See TracChangeset
for help on using the changeset viewer.