- Timestamp:
- May 13, 2020 12:59:23 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r84242 r84285 486 486 487 487 /** 488 * Acquires the IOMMU PDM lock or returns @a a_rcBusy if it's busy. 489 */ 490 #define IOMMU_LOCK_RET(a_pDevIns, a_pThis, a_rcBusy) \ 488 * Acquires the IOMMU PDM lock. 489 * This will make a long jump to ring-3 to acquire the lock if necessary. 490 */ 491 #define IOMMU_LOCK(a_pDevIns, a_pThis) \ 491 492 do { \ 492 493 NOREF(pThis); \ 493 int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), (a_pDevIns)->CTX_SUFF(pCritSectRo), (a_rcBusy)); \494 int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), (a_pDevIns)->CTX_SUFF(pCritSectRo), VINF_SUCCESS); \ 494 495 if (RT_LIKELY(rcLock == VINF_SUCCESS)) \ 495 496 { /* likely */ } \ … … 512 513 do { \ 513 514 Assert(PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo))); \ 515 } while (0) 516 517 /** 518 * Asserts that the critsect is not owned by this thread. 519 */ 520 #define IOMMU_ASSERT_NOT_LOCKED(a_pDevIns) \ 521 do { \ 522 Assert(!PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo))); \ 514 523 } while (0) 515 524 … … 757 766 } CMD_GENERIC_T; 758 767 AssertCompileSize(CMD_GENERIC_T, 16); 768 /** Pointer to a generic command buffer entry. */ 769 typedef CMD_GENERIC_T *PCMD_GENERIC_T; 770 /** Pointer to a const generic command buffer entry. */ 771 typedef CMD_GENERIC_T const *PCCMD_GENERIC_T; 772 759 773 /** Number of bits to shift the byte offset of a command in the command buffer to 760 774 * get its index. */ … … 1372 1386 } IOMMU_CTRL_T; 1373 1387 AssertCompileSize(IOMMU_CTRL_T, 8); 1374 #define IOMMU_CTRL_VALID_MASK UINT64_C(0x004defffffffffff) 1388 #define IOMMU_CTRL_VALID_MASK UINT64_C(0x004defffffffffff) 1389 #define IOMMU_CTRL_CMD_BUF_EN_MASK UINT64_C(0x0000000000001001) 1375 1390 1376 1391 /** … … 2254 2269 /** Alignment padding. */ 2255 2270 uint32_t uPadding0; 2271 2272 /** Whether the command thread is sleeping. */ 2273 bool volatile fCmdThreadSleeping; 2274 /** Alignment padding. */ 2275 uint8_t afPadding0[3]; 2276 /** Whether the command thread has been signaled for wake up. */ 2277 bool volatile fCmdThreadSignaled; 2278 /** Alignment padding. */ 2279 uint8_t afPadding1[3]; 2280 2256 2281 /** The event semaphore the command thread waits on. */ 2257 2282 SUPSEMEVENT hEvtCmdThread; … … 2383 2408 /** Pointer to the const IOMMU device state. */ 2384 2409 typedef const struct IOMMU *PCIOMMU; 2410 AssertCompileMemberAlignment(IOMMU, fCmdThreadSleeping, 4); 2411 AssertCompileMemberAlignment(IOMMU, fCmdThreadSignaled, 4); 2385 2412 AssertCompileMemberAlignment(IOMMU, hEvtCmdThread, 8); 2386 2413 AssertCompileMemberAlignment(IOMMU, hMmio, 8); … … 2393 2420 { 2394 2421 /** Device instance. */ 2395 PPDMDEVINSR3 pDevInsR3;2422 PPDMDEVINSR3 pDevInsR3; 2396 2423 /** The IOMMU helpers. */ 2397 PCPDMIOMMUHLPR3 pIommuHlpR3;2424 PCPDMIOMMUHLPR3 pIommuHlpR3; 2398 2425 /** The command thread handle. */ 2399 R3PTRTYPE(PPDMTHREAD) pCmdThread;2426 R3PTRTYPE(PPDMTHREAD) pCmdThread; 2400 2427 } IOMMUR3; 2401 2428 /** Pointer to the ring-3 IOMMU device state. */ … … 2408 2435 { 2409 2436 /** Device instance. */ 2410 PPDMDEVINSR0 pDevInsR0;2437 PPDMDEVINSR0 pDevInsR0; 2411 2438 /** The IOMMU helpers. */ 2412 PCPDMIOMMUHLPR0 pIommuHlpR0;2439 PCPDMIOMMUHLPR0 pIommuHlpR0; 2413 2440 } IOMMUR0; 2414 2441 /** Pointer to the ring-0 IOMMU device state. */ … … 2421 2448 { 2422 2449 /** Device instance. */ 2423 PPDMDEVINSR0 pDevInsRC;2450 PPDMDEVINSR0 pDevInsRC; 2424 2451 /** The IOMMU helpers. */ 2425 PCPDMIOMMUHLPRC pIommuHlpRC;2452 PCPDMIOMMUHLPRC pIommuHlpRC; 2426 2453 } IOMMURC; 2427 2454 /** Pointer to the raw-mode IOMMU device state. */ … … 2524 2551 return idxTail - idxHead; 2525 2552 2526 uint32_t const cMax Evts = iommuAmdGetBufMaxEntries(pThis->CmdBufBaseAddr.n.u4Len);2527 return cMax Evts - idxHead + idxTail;2553 uint32_t const cMaxCmds = iommuAmdGetBufMaxEntries(pThis->CmdBufBaseAddr.n.u4Len); 2554 return cMaxCmds - idxHead + idxTail; 2528 2555 } 2529 2556 … … 2575 2602 2576 2603 /** 2577 * The IOMMU command thread. 2604 * Wakes up the command thread if there are commands to be processed or if 2605 * processing is requested to be stopped by software. 2578 2606 * 2579 * @returns VBox status code.2580 2607 * @param pDevIns The IOMMU device instance. 2581 * @param pThread The command thread. 2582 */ 2583 static DECLCALLBACK(int) iommuAmdR3CmdThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 2584 { 2585 RT_NOREF(pDevIns, pThread); 2586 } 2587 2588 2589 /** 2590 * Unblocks the command thread so it can respond to a state change. 2591 * 2592 * @returns VBox status code. 2593 * @param pDevIns The IOMMU device instance. 2594 * @param pThread The command thread. 2595 */ 2596 static DECLCALLBACK(int) iommuAmdR3CmdThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 2597 { 2598 RT_NOREF(pThread); 2608 */ 2609 static void iommuAmdCmdThreadWakeUpIfNeeded(PPDMDEVINS pDevIns) 2610 { 2611 IOMMU_ASSERT_LOCKED(pDevIns); 2612 2599 2613 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 2600 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtCmdThread); 2614 if ( !ASMAtomicXchgBool(&pThis->fCmdThreadSignaled, true) 2615 && ASMAtomicReadBool(&pThis->fCmdThreadSleeping)) 2616 PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtCmdThread); 2601 2617 } 2602 2618 … … 2730 2746 NewCtrl.u64 = u64Value; 2731 2747 2748 /* Update the register. */ 2749 ASMAtomicWriteU64(&pThis->Ctrl.u64, NewCtrl.u64); 2750 2732 2751 /* Enable or disable event logging when the bit transitions. */ 2733 if (OldCtrl.n.u1EvtLogEn != NewCtrl.n.u1EvtLogEn) 2734 { 2735 if (NewCtrl.n.u1EvtLogEn) 2752 bool const fNewIommuEn = NewCtrl.n.u1IommuEn; 2753 bool const fOldEvtLogEn = OldCtrl.n.u1EvtLogEn; 2754 bool const fNewEvtLogEn = NewCtrl.n.u1EvtLogEn; 2755 if (fOldEvtLogEn != fNewEvtLogEn) 2756 { 2757 if ( fNewIommuEn 2758 && fNewEvtLogEn) 2736 2759 { 2737 2760 ASMAtomicAndU64(&pThis->Status.u64, ~IOMMU_STATUS_EVT_LOG_OVERFLOW); … … 2742 2765 } 2743 2766 2744 /* Update the register. */2745 ASMAtomicWriteU64(&pThis->Ctrl.u64, NewCtrl.u64);2746 2747 2767 /* Enable or disable command buffer processing when the bit transitions. */ 2748 if (OldCtrl.n.u1CmdBufEn != NewCtrl.n.u1CmdBufEn) 2749 { 2750 if (NewCtrl.n.u1CmdBufEn) 2751 { 2768 bool const fOldCmdBufEn = OldCtrl.n.u1CmdBufEn; 2769 bool const fNewCmdBufEn = NewCtrl.n.u1CmdBufEn; 2770 if (fOldCmdBufEn != fNewCmdBufEn) 2771 { 2772 if ( fNewIommuEn 2773 && fNewCmdBufEn) 2752 2774 ASMAtomicOrU64(&pThis->Status.u64, IOMMU_STATUS_CMD_BUF_RUNNING); 2753 2754 /* If the command buffer isn't empty, kick the command thread to start processing commands. */2755 if (pThis->CmdBufTailPtr.n.off != pThis->CmdBufHeadPtr.n.off)2756 PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtCmdThread);2757 }2758 2775 else 2759 {2760 2776 ASMAtomicAndU64(&pThis->Status.u64, ~IOMMU_STATUS_CMD_BUF_RUNNING); 2761 /* Kick the command thread to stop processing commands. */ 2762 PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtCmdThread);2763 }2777 2778 /* Wake up the command thread to start or stop processing commands. */ 2779 iommuAmdCmdThreadWakeUpIfNeeded(pDevIns); 2764 2780 } 2765 2781 } … … 2970 2986 pThis->CmdBufHeadPtr.au32[0] = offBuf; 2971 2987 2988 iommuAmdCmdThreadWakeUpIfNeeded(pDevIns); 2989 2972 2990 LogFlow((IOMMU_LOG_PFX ": Set CmdBufHeadPtr to %#RX32\n", offBuf)); 2973 2991 return VINF_SUCCESS; … … 3009 3027 */ 3010 3028 pThis->CmdBufTailPtr.au32[0] = offBuf; 3029 3030 iommuAmdCmdThreadWakeUpIfNeeded(pDevIns); 3011 3031 3012 3032 LogFlow((IOMMU_LOG_PFX ": Set CmdBufTailPtr to %#RX32\n", offBuf)); … … 3482 3502 { 3483 3503 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 3504 3505 IOMMU_LOCK(pDevIns, pThis); 3506 3507 /* Check if event logging is active and the log has not overflowed. */ 3484 3508 IOMMU_STATUS_T const Status = iommuAmdGetStatus(pThis); 3485 3486 /** @todo IOMMU: Consider locking here. */3487 3488 /* Check if event logging is active and the log has not overflowed. */3489 3509 if ( Status.n.u1EvtLogRunning 3490 3510 && !Status.n.u1EvtOverflow) … … 3531 3551 } 3532 3552 } 3553 3554 IOMMU_UNLOCK(pDevIns, pThis); 3533 3555 } 3534 3556 … … 4444 4466 4445 4467 # ifdef IN_RING3 4468 4469 /** 4470 * Processes an IOMMU command. 4471 * 4472 * @returns VBox status code. 4473 * @param pDevIns The IOMMU device instance. 4474 * @param pCmd The command to process. 4475 */ 4476 static int iommuAmdR3ProcessCmd(PPDMDEVINS pDevIns, PCCMD_GENERIC_T pCmd) 4477 { 4478 IOMMU_ASSERT_NOT_LOCKED(pDevIns); 4479 4480 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 4481 uint8_t const bCmd = pCmd->n.u4Opcode; 4482 switch (bCmd) 4483 { 4484 case IOMMU_CMD_COMPLETION_WAIT: 4485 case IOMMU_CMD_INV_DEV_TAB_ENTRY: 4486 case IOMMU_CMD_INV_IOMMU_PAGES: 4487 case IOMMU_CMD_INV_IOTLB_PAGES: 4488 case IOMMU_CMD_INV_INTR_TABLE: 4489 case IOMMU_CMD_PREFETCH_IOMMU_PAGES: 4490 case IOMMU_CMD_COMPLETE_PPR_REQ: 4491 case IOMMU_CMD_INV_IOMMU_ALL: 4492 { 4493 NOREF(pThis); 4494 return VERR_NOT_IMPLEMENTED; 4495 } 4496 4497 default: 4498 break; 4499 } 4500 4501 Log((IOMMU_LOG_PFX ": Invalid/Unrecognized command opcode %u (%#x)\n", bCmd, bCmd)); 4502 return VERR_INVALID_FUNCTION; 4503 } 4504 4505 4506 /** 4507 * The IOMMU command thread. 4508 * 4509 * @returns VBox status code. 4510 * @param pDevIns The IOMMU device instance. 4511 * @param pThread The command thread. 4512 */ 4513 static DECLCALLBACK(int) iommuAmdR3CmdThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 4514 { 4515 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 4516 4517 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 4518 return VINF_SUCCESS; 4519 4520 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 4521 { 4522 /* 4523 * Sleep perpetually until we are woken up to process commands. 4524 */ 4525 { 4526 ASMAtomicWriteBool(&pThis->fCmdThreadSleeping, true); 4527 bool fSignaled = ASMAtomicXchgBool(&pThis->fCmdThreadSignaled, false); 4528 if (!fSignaled) 4529 { 4530 Assert(ASMAtomicReadBool(&pThis->fCmdThreadSleeping)); 4531 int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtCmdThread, RT_INDEFINITE_WAIT); 4532 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc); 4533 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING)) 4534 break; 4535 LogFlowFunc(("Woken up with rc=%Rrc\n", rc)); 4536 ASMAtomicWriteBool(&pThis->fCmdThreadSignaled, false); 4537 } 4538 ASMAtomicWriteBool(&pThis->fCmdThreadSleeping, false); 4539 } 4540 4541 /* 4542 * Fetch and process IOMMU commands. 4543 */ 4544 /** @todo r=ramshankar: This employs a simplistic method of fetching commands (one 4545 * at a time) and is expensive due to calls to PGM for fetching guest memory. 4546 * We could optimize by fetching a bunch of commands at a time reducing 4547 * number of calls to PGM. In the longer run we could lock the memory and 4548 * mappings and accessing them directly. */ 4549 IOMMU_STATUS_T Status = iommuAmdGetStatus(pThis); 4550 if (Status.n.u1CmdBufRunning) 4551 { 4552 IOMMU_LOCK(pDevIns, pThis); 4553 4554 uint32_t const cbCmdBuf = iommuAmdGetBufLength(pThis->CmdBufBaseAddr.n.u4Len); 4555 uint32_t offHead = pThis->CmdBufHeadPtr.n.off; 4556 Assert(!(offHead & ~IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK)); 4557 while (offHead != pThis->CmdBufTailPtr.n.off) 4558 { 4559 /* Fetch the command from guest memory. */ 4560 CMD_GENERIC_T Cmd; 4561 RTGCPHYS const GCPhysCmd = (pThis->CmdBufBaseAddr.n.u40Base << X86_PAGE_4K_SHIFT) + offHead; 4562 int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhysCmd, &Cmd, sizeof(Cmd)); 4563 if (RT_SUCCESS(rc)) 4564 { 4565 /* Increment the command buffer head pointer. */ 4566 offHead = (offHead + sizeof(CMD_GENERIC_T)) % cbCmdBuf; 4567 pThis->CmdBufHeadPtr.n.off = offHead; 4568 4569 /* Process the fetched command. */ 4570 IOMMU_UNLOCK(pDevIns, pThis); 4571 rc = iommuAmdR3ProcessCmd(pDevIns, &Cmd); 4572 IOMMU_LOCK(pDevIns, pThis); 4573 if (RT_SUCCESS(rc)) 4574 { /* likely */ } 4575 else 4576 { 4577 /** @todo IOMMU: Raise illegal command error. */ 4578 /* Stop command processing. */ 4579 ASMAtomicAndU64(&pThis->Status.u64, ~IOMMU_STATUS_CMD_BUF_RUNNING); 4580 break; 4581 } 4582 } 4583 else 4584 { 4585 /** @todo IOMMU: Raise command hardware error. */ 4586 /* Stop command processing. */ 4587 ASMAtomicAndU64(&pThis->Status.u64, ~IOMMU_STATUS_CMD_BUF_RUNNING); 4588 break; 4589 } 4590 } 4591 4592 IOMMU_UNLOCK(pDevIns, pThis); 4593 } 4594 } 4595 } 4596 4597 4598 /** 4599 * Wakes up the command thread so it can respond to a state change. 4600 * 4601 * @returns VBox status code. 4602 * @param pDevIns The IOMMU device instance. 4603 * @param pThread The command thread. 4604 */ 4605 static DECLCALLBACK(int) iommuAmdR3CmdThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 4606 { 4607 RT_NOREF(pThread); 4608 4609 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 4610 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtCmdThread); 4611 } 4612 4613 4446 4614 /** 4447 4615 * @callback_method_impl{FNPCICONFIGREAD} … … 4483 4651 } 4484 4652 4485 IOMMU_LOCK _RET(pDevIns, pThis, VERR_IGNORED);4653 IOMMU_LOCK(pDevIns, pThis); 4486 4654 4487 4655 VBOXSTRICTRC rcStrict; … … 4527 4695 RT_FALL_THRU(); 4528 4696 } 4529 4530 4697 default: 4531 4698 {
Note:
See TracChangeset
for help on using the changeset viewer.