Changeset 84530 in vbox for trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
- Timestamp:
- May 26, 2020 9:38:30 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r84515 r84530 669 669 #define IOMMU_DTE_QWORD_3_VALID_MASK UINT64_C(0xffc0000000000000) 670 670 671 /* Mask of the interrupt table root pointer. */ 672 #define IOMMU_DTE_IRTE_ROOT_PTR_MASK UINT64_C(0x000fffffffffff80) 673 671 674 /** 672 675 * I/O Page Translation Entry. … … 775 778 } IRTE_T; 776 779 AssertCompileSize(IRTE_T, 4); 780 /** The number of bits to shift the IRTE offset to get the IRTE. */ 781 #define IOMMU_IRTE_SIZE_SHIFT (2) 777 782 /** Pointer to an IRTE_T struct. */ 778 783 typedef IRTE_T *PIRTE_T; … … 1810 1815 } MSI_DATA_T; 1811 1816 AssertCompileSize(MSI_DATA_T, 4); 1812 #define IOMMU_MSI_DATA_VALID_MASK UINT64_C(0x000000000000ffff) 1817 #define IOMMU_MSI_DATA_VALID_MASK UINT64_C(0x000000000000ffff) 1818 /** The IRTE offset corresponds directly to bits 10:0 of the originating MSI 1819 * interrupt message. See AMD IOMMU spec. 2.2.5 "Interrupt Remapping Tables". */ 1820 #define IOMMU_MSI_DATA_IRTE_OFFSET_MASK UINT32_C(0x000007ff) 1821 1813 1822 /** Pointer to an MSI data register. */ 1814 1823 typedef MSI_DATA_T *PMSI_DATA_T; … … 2188 2197 { 2189 2198 kIllegalDteType_RsvdNotZero = 0, 2190 kIllegalDteType_RsvdIntTab ,2199 kIllegalDteType_RsvdIntTabLen, 2191 2200 kIllegalDteType_RsvdIoCtl, 2192 2201 kIllegalDteType_RsvdIntCtl … … 4135 4144 } 4136 4145 4146 4137 4147 return rc; 4138 4148 } … … 4172 4182 * the DTE) return the state computed so far and raises an I/O page fault. So 4173 4183 * returning an invalid translation rather than skipping translation. */ 4184 Log((IOMMU_LOG_PFX ": Translation valid bit not set -> IOPF")); 4174 4185 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 4175 4186 iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, false /* fPresent */, false /* fRsvdNotZero */, … … 4206 4217 * raising an ILLEGAL_DEV_TABLE_ENTRY event or an IO_PAGE_FAULT event here. 4207 4218 * I'm just going with I/O page fault. */ 4219 Log((IOMMU_LOG_PFX ": Invalid root page table level %#x -> IOPF", uMaxLevel)); 4208 4220 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 4209 4221 iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, … … 4220 4232 else 4221 4233 { 4234 Log((IOMMU_LOG_PFX ": Permission denied (fAccess=%#x fPtePerm=%#x) -> IOPF", fAccess, fPtePerm)); 4222 4235 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 4223 4236 iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, … … 4277 4290 else 4278 4291 { 4292 Log((IOMMU_LOG_PFX ": Page table entry not present -> IOPF", fAccess, fPtePerm)); 4279 4293 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 4280 4294 iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, false /* fPresent */, false /* fRsvdNotZero */, … … 4290 4304 else 4291 4305 { 4306 Log((IOMMU_LOG_PFX ": Page table entry permission denied (fAccess=%#x fPtePerm=%#x) -> IOPF", fAccess, fPtePerm)); 4292 4307 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 4293 4308 iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, … … 4326 4341 } 4327 4342 4343 Log((IOMMU_LOG_PFX ": Page size invalid cShift=%#x -> IOPF", cShift)); 4328 4344 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 4329 4345 iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, … … 4340 4356 else 4341 4357 { 4358 Log((IOMMU_LOG_PFX ": Next level of PDE invalid uNextLevel=%#x -> IOPF", uNextLevel)); 4342 4359 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 4343 4360 iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, … … 4356 4373 else 4357 4374 { 4375 Log((IOMMU_LOG_PFX ": Next level (%#x) must be less than the current level (%#x) -> IOPF", uNextLevel, uLevel)); 4358 4376 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 4359 4377 iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, … … 4373 4391 else 4374 4392 { 4393 Log((IOMMU_LOG_PFX ": IOVA of skipped levels are not zero %#RX64 (SkipMask=%#RX64) -> IOPF", uIova, uIovaSkipMask)); 4375 4394 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 4376 4395 iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, … … 4578 4597 * @returns VBox status code. 4579 4598 * @param pDevIns The IOMMU device instance. 4599 * @param uDevId The device ID. 4580 4600 * @param pDte The device table entry. 4601 * @param GCPhysIn The source MSI address. 4602 * @param uDataIn The source MSI data. 4581 4603 * @param enmOp The IOMMU operation being performed. 4582 4604 * @param pIrte Where to store the interrupt remapping table entry. … … 4584 4606 * @thread Any. 4585 4607 */ 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. 4608 static int iommuAmdReadIrte(PPDMDEVINS pDevIns, uint16_t uDevId, PCDTE_T pDte, RTGCPHYS GCPhysIn, uint32_t uDataIn, 4609 IOMMUOP enmOp, PIRTE_T pIrte) 4610 { 4611 RTGCPHYS const GCPhysIntrTable = pDte->au64[2] & IOMMU_DTE_IRTE_ROOT_PTR_MASK; 4612 uint16_t const offIrte = (uDataIn & IOMMU_MSI_DATA_IRTE_OFFSET_MASK) << IOMMU_IRTE_SIZE_SHIFT; 4613 RTGCPHYS const GCPhysIrte = GCPhysIntrTable + offIrte; 4614 4615 /* Ensure the IRTE offset is within the specified table size. */ 4616 Assert(pDte->n.u4IntrTableLength < 12); 4617 if (offIrte < (1 << pDte->n.u4IntrTableLength) << IOMMU_IRTE_SIZE_SHIFT) 4618 { /* likely */ } 4619 else 4620 { 4621 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 4622 iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, GCPhysIn, false /* fPresent */, false /* fRsvdNotZero */, 4623 false /* fPermDenied */, enmOp, &EvtIoPageFault); 4624 iommuAmdRaiseIoPageFaultEvent(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault, 4625 kIoPageFaultType_IrteAddrInvalid); 4626 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 4627 } 4628 4629 /* Read the IRTE from memory. */ 4630 Assert(!(GCPhysIrte & 3)); 4631 int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhysIrte, pIrte, sizeof(*pIrte)); 4632 if (RT_SUCCESS(rc)) 4633 return VINF_SUCCESS; 4634 4635 /** @todo r=ramshankar: The IOMMU spec. does not tell what kind of error is 4636 * reported in this situation. Is it an I/O page fault or a device table 4637 * hardware error? There's no interrupt table hardware error event, but 4638 * it's unclear what we should do here. */ 4639 Log((IOMMU_LOG_PFX ": Failed to read interrupt table entry at %#RGp. rc=%Rrc -> ???\n", GCPhysIrte, rc)); 4640 return VERR_IOMMU_IPE_4; 4641 } 4642 4643 4644 /** 4645 * Remap the interrupt using the interrupt remapping table. 4595 4646 * 4596 4647 * @returns VBox status code. 4597 4648 * @param pDevIns The IOMMU instance data. 4649 * @param uDevId The device ID. 4650 * @param pDte The device table entry. 4598 4651 * @param GCPhysIn The source MSI address. 4599 4652 * @param uDataIn The source MSI data. … … 4604 4657 * @thread Any. 4605 4658 */ 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; 4659 static int iommuAmdRemapIntr(PPDMDEVINS pDevIns, uint16_t uDevId, PCDTE_T pDte, RTGCPHYS GCPhysIn, uint32_t uDataIn, 4660 IOMMUOP enmOp, PRTGCPHYS pGCPhysOut, uint32_t *puDataOut) 4661 { 4662 Assert(pDte->n.u2IntrCtrl == IOMMU_INTR_CTRL_REMAP); 4663 4664 IRTE_T Irte; 4665 int rc = iommuAmdReadIrte(pDevIns, uDevId, pDte, GCPhysIn, uDataIn, enmOp, &Irte); 4666 if (RT_SUCCESS(rc)) 4667 { 4668 /** @todo Remap. */ 4669 return VERR_NOT_IMPLEMENTED; 4670 } 4671 4672 RT_NOREF(pGCPhysOut, puDataOut); 4673 return rc; 4611 4674 } 4612 4675 … … 4701 4764 if (uIntrCtrl == IOMMU_INTR_CTRL_REMAP) 4702 4765 { 4766 /* Validate the encoded interrupt table length when IntCtl specifies remapping. */ 4767 uint32_t const uIntTabLen = Dte.n.u4IntrTableLength; 4768 if (Dte.n.u4IntrTableLength < 12) 4769 { /* likely */ } 4770 else 4771 { 4772 Log((IOMMU_LOG_PFX ": Invalid interrupt table length %#x -> Illegal DTE\n", uIntTabLen)); 4773 EVT_ILLEGAL_DTE_T Event; 4774 iommuAmdInitIllegalDteEvent(uDevId, GCPhysIn, false /* fRsvdNotZero */, enmOp, &Event); 4775 iommuAmdRaiseIllegalDteEvent(pDevIns, enmOp, &Event, kIllegalDteType_RsvdIntTabLen); 4776 return VERR_IOMMU_INTR_REMAP_FAILED; 4777 } 4778 4703 4779 /* 4704 4780 * We don't support guest interrupt remapping yet. When we do, we'll need to … … 4712 4788 NOREF(pThis); 4713 4789 4714 return iommuAmdRemapIntr(pDevIns, GCPhysIn, uDataIn, enmOp, pGCPhysOut, puDataOut);4790 return iommuAmdRemapIntr(pDevIns, uDevId, &Dte, GCPhysIn, uDataIn, enmOp, pGCPhysOut, puDataOut); 4715 4791 } 4716 4792
Note:
See TracChangeset
for help on using the changeset viewer.