Changeset 81156 in vbox
- Timestamp:
- Oct 8, 2019 2:58:45 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
- 1 copied
-
include/VBox/vmm/iom.h (modified) (4 diffs)
-
src/VBox/VMM/Makefile.kmk (modified) (1 diff)
-
src/VBox/VMM/VMMR3/IOM.cpp (modified) (6 diffs)
-
src/VBox/VMM/VMMR3/IOMR3IoPort.cpp (copied) (copied from trunk/src/VBox/VMM/VMMR3/IOM.cpp ) (10 diffs)
-
src/VBox/VMM/VMMR3/PDMDevHlp.cpp (modified) (4 diffs)
-
src/VBox/VMM/include/IOMInternal.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vmm/iom.h
r81136 r81156 390 390 typedef FNIOMMMIOFILL *PFNIOMMMIOFILL; 391 391 392 393 /** 394 * Memory mapped I/O Handler for read operations. 395 * 396 * @returns Strict VBox status code. 397 * 398 * @param pDevIns The device instance. 399 * @param pvUser User argument. 400 * @param off Offset into the mapping of the read, 401 * or the physical address if IOM_MMIO_F_ABS is active. 402 * @param pv Where to store the result. 403 * @param cb Number of bytes read. 404 * @remarks Caller enters the device critical section. 405 */ 406 typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMMMIONEWREAD(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, uint32_t cb); 407 /** Pointer to a FNIOMMMIONEWREAD(). */ 408 typedef FNIOMMMIONEWREAD *PFNIOMMMIONEWREAD; 409 410 /** 411 * Memory mapped I/O Handler for write operations. 412 * 413 * @returns Strict VBox status code. 414 * 415 * @param pDevIns The device instance. 416 * @param pvUser User argument. 417 * @param off Offset into the mapping of the write, 418 * or the physical address if IOM_MMIO_F_ABS is active. 419 * @param pv Where to fetch the result. 420 * @param cb Number of bytes to write. 421 * @remarks Caller enters the device critical section. 422 */ 423 typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMMMIONEWWRITE(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, uint32_t cb); 424 /** Pointer to a FNIOMMMIONEWWRITE(). */ 425 typedef FNIOMMMIONEWWRITE *PFNIOMMMIONEWWRITE; 426 427 /** 428 * Memory mapped I/O Handler for memset operations, actually for REP STOS* instructions handling. 429 * 430 * @returns Strict VBox status code. 431 * 432 * @param pDevIns The device instance. 433 * @param pvUser User argument. 434 * @param off Offset into the mapping of the fill, 435 * or the physical address if IOM_MMIO_F_ABS is active. 436 * @param u32Item Byte/Word/Dword data to fill. 437 * @param cbItem Size of data in u32Item parameter, restricted to 1/2/4 bytes. 438 * @param cItems Number of iterations. 439 * @remarks Caller enters the device critical section. 440 */ 441 typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMMMIONEWFILL(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, 442 uint32_t u32Item, uint32_t cbItem, uint32_t cItems); 443 /** Pointer to a FNIOMMMIONEWFILL(). */ 444 typedef FNIOMMMIONEWFILL *PFNIOMMMIONEWFILL; 445 392 446 VMMDECL(VBOXSTRICTRC) IOMIOPortRead(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue); 393 447 VMMDECL(VBOXSTRICTRC) IOMIOPortWrite(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue); … … 412 466 /** @} */ 413 467 468 /** @name IOM_MMIO_F_XXX - Flags for IOMR3MmioCreate() and PDMDevHlpMmioCreateEx(). 469 * @{ */ 470 /** Pass the absolute physical address (GC) to the callback rather than the 471 * relative one. */ 472 #define IOM_MMIO_F_ABS RT_BIT_32(0) 473 /** Valid flags for IOMR3IoPortCreate(). */ 474 #define IOM_MMIO_F_VALID_MASK UINT32_C(0x00000001) 475 /** @} */ 476 414 477 #ifdef IN_RING3 415 478 /** @defgroup grp_iom_r3 The IOM Host Context Ring-3 API … … 429 492 VMMR3_INT_DECL(int) IOMR3IoPortUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts); 430 493 494 VMMR3_INT_DECL(int) IOMR3MmioCreate(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS cbRegion, uint32_t fFlags, PPDMPCIDEV pPciDev, 495 uint32_t iPciRegion, PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, 496 PFNIOMMMIONEWFILL pfnFill, void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion); 497 VMMR3_INT_DECL(int) IOMR3MmioMap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys); 498 VMMR3_INT_DECL(int) IOMR3MmioUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); 499 VMMR3_INT_DECL(int) IOMR3MmioReduce(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion); 500 501 /** @name obsolete 502 * @deprecated 503 * @{ */ 431 504 VMMR3_INT_DECL(int) IOMR3IOPortRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTHCPTR pvUser, 432 505 R3PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, R3PTRTYPE(PFNIOMIOPORTIN) pfnInCallback, … … 479 552 VMMR3_INT_DECL(void) IOMR3MmioExNotifyDeregistered(PVM pVM, void *pvUser); 480 553 554 /** @} */ 555 481 556 VMMR3_INT_DECL(VBOXSTRICTRC) IOMR3ProcessForceFlag(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict); 482 557 -
trunk/src/VBox/VMM/Makefile.kmk
r81153 r81156 120 120 VMMR3/IEMR3.cpp \ 121 121 VMMR3/IOM.cpp \ 122 VMMR3/IOMR3IoPort.cpp \ 122 123 VMMR3/GMM.cpp \ 123 124 VMMR3/MM.cpp \ -
trunk/src/VBox/VMM/VMMR3/IOM.cpp
r81136 r81156 138 138 static DECLCALLBACK(int) iomR3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser); 139 139 #endif 140 #ifdef VBOX_WITH_STATISTICS141 static void iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry);142 static void iomR3IoPortDeregStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry, unsigned uPort);143 #endif144 static DECLCALLBACK(void) iomR3IOPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);145 140 static DECLCALLBACK(void) iomR3MMIOInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs); 146 141 static FNIOMIOPORTIN iomR3IOPortDummyIn; … … 148 143 static FNIOMIOPORTINSTRING iomR3IOPortDummyInStr; 149 144 static FNIOMIOPORTOUTSTRING iomR3IOPortDummyOutStr; 150 static FNIOMIOPORTNEWIN iomR3IOPortDummyNewIn;151 static FNIOMIOPORTNEWOUT iomR3IOPortDummyNewOut;152 static FNIOMIOPORTNEWINSTRING iomR3IOPortDummyNewInStr;153 static FNIOMIOPORTNEWOUTSTRING iomR3IOPortDummyNewOutStr;154 145 155 146 #ifdef VBOX_WITH_STATISTICS … … 208 199 * Info. 209 200 */ 210 DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3I OPortInfo);201 DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IoPortInfo); 211 202 DBGFR3InfoRegisterInternal(pVM, "mmio", "Dumps all MMIO ranges. No arguments.", &iomR3MMIOInfo); 212 203 … … 452 443 453 444 454 /**455 * Worker for PDMDEVHLPR3::pfnIoPortCreateEx.456 */457 VMMR3_INT_DECL(int) IOMR3IoPortCreate(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev,458 uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn,459 PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, RTR3PTR pvUser,460 const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts)461 {462 /*463 * Validate input.464 */465 AssertPtrReturn(phIoPorts, VERR_INVALID_POINTER);466 *phIoPorts = UINT32_MAX;467 VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);468 VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);469 470 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);471 472 AssertMsgReturn(cPorts > 0 && cPorts <= _8K, ("cPorts=%s\n", cPorts), VERR_OUT_OF_RANGE);473 AssertReturn(!(fFlags & ~IOM_IOPORT_F_VALID_MASK), VERR_INVALID_FLAGS);474 475 AssertReturn(pfnOut || pfnIn || pfnOutStr || pfnInStr, VERR_INVALID_PARAMETER);476 AssertPtrNullReturn(pfnOut, VERR_INVALID_POINTER);477 AssertPtrNullReturn(pfnIn, VERR_INVALID_POINTER);478 AssertPtrNullReturn(pfnOutStr, VERR_INVALID_POINTER);479 AssertPtrNullReturn(pfnInStr, VERR_INVALID_POINTER);480 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);481 AssertReturn(*pszDesc != '\0', VERR_INVALID_POINTER);482 AssertReturn(strlen(pszDesc) < 128, VERR_INVALID_POINTER);483 if (paExtDescs)484 {485 AssertPtrReturn(paExtDescs, VERR_INVALID_POINTER);486 for (size_t i = 0;; i++)487 {488 const char *pszIn = paExtDescs[i].pszIn;489 const char *pszOut = paExtDescs[i].pszIn;490 if (!pszIn && !pszOut)491 break;492 AssertReturn(i < _8K, VERR_OUT_OF_RANGE);493 AssertReturn(!pszIn || strlen(pszIn) < 128, VERR_INVALID_POINTER);494 AssertReturn(!pszOut || strlen(pszOut) < 128, VERR_INVALID_POINTER);495 }496 }497 498 /*499 * Ensure that we've got table space for it.500 */501 #ifndef VBOX_WITH_STATISTICS502 uint16_t const idxStats = UINT16_MAX;503 #else504 uint32_t const idxStats = pVM->iom.s.cIoPortStats;505 uint32_t const cNewIoPortStats = idxStats + cPorts;506 AssertReturn(cNewIoPortStats <= _64K, VERR_IOM_TOO_MANY_IOPORT_REGISTRATIONS);507 if (cNewIoPortStats > pVM->iom.s.cIoPortStatsAllocation)508 {509 int rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_IOM_GROW_IO_PORT_STATS, cNewIoPortStats, NULL);510 AssertLogRelRCReturn(rc, rc);511 AssertReturn(idxStats == pVM->iom.s.cIoPortStats, VERR_IOM_IOPORT_IPE_1);512 AssertReturn(cNewIoPortStats <= pVM->iom.s.cIoPortStatsAllocation, VERR_IOM_IOPORT_IPE_2);513 }514 #endif515 516 uint32_t idx = pVM->iom.s.cIoPortRegs;517 if (idx >= pVM->iom.s.cIoPortAlloc)518 {519 int rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_IOM_GROW_IO_PORTS, pVM->iom.s.cIoPortAlloc + 1, NULL);520 AssertLogRelRCReturn(rc, rc);521 AssertReturn(idx == pVM->iom.s.cIoPortRegs, VERR_IOM_IOPORT_IPE_1);522 AssertReturn(idx < pVM->iom.s.cIoPortAlloc, VERR_IOM_IOPORT_IPE_2);523 }524 525 /*526 * Enter it.527 */528 pVM->iom.s.paIoPortRegs[idx].pvUser = pvUser;529 pVM->iom.s.paIoPortRegs[idx].pDevIns = pDevIns;530 pVM->iom.s.paIoPortRegs[idx].pfnOutCallback = pfnOut ? pfnOut : iomR3IOPortDummyNewOut;531 pVM->iom.s.paIoPortRegs[idx].pfnInCallback = pfnIn ? pfnIn : iomR3IOPortDummyNewIn;532 pVM->iom.s.paIoPortRegs[idx].pfnOutStrCallback = pfnOutStr ? pfnOutStr : iomR3IOPortDummyNewOutStr;533 pVM->iom.s.paIoPortRegs[idx].pfnInStrCallback = pfnInStr ? pfnInStr : iomR3IOPortDummyNewInStr;534 pVM->iom.s.paIoPortRegs[idx].pszDesc = pszDesc;535 pVM->iom.s.paIoPortRegs[idx].paExtDescs = paExtDescs;536 pVM->iom.s.paIoPortRegs[idx].pPciDev = pPciDev;537 pVM->iom.s.paIoPortRegs[idx].iPciRegion = iPciRegion;538 pVM->iom.s.paIoPortRegs[idx].cPorts = cPorts;539 pVM->iom.s.paIoPortRegs[idx].uPort = UINT16_MAX;540 pVM->iom.s.paIoPortRegs[idx].idxStats = (uint16_t)idxStats;541 pVM->iom.s.paIoPortRegs[idx].fMapped = false;542 pVM->iom.s.paIoPortRegs[idx].fFlags = (uint8_t)fFlags;543 pVM->iom.s.paIoPortRegs[idx].idxSelf = idx;544 545 pVM->iom.s.cIoPortRegs = idx + 1;546 *phIoPorts = idx;547 return VINF_SUCCESS;548 }549 550 551 /**552 * Worker for PDMDEVHLPR3::pfnIoPortMap.553 */554 VMMR3_INT_DECL(int) IOMR3IoPortMap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT uPort)555 {556 /*557 * Validate input and state.558 */559 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);560 AssertReturn(hIoPorts < pVM->iom.s.cIoPortRegs, VERR_IOM_INVALID_IOPORT_HANDLE);561 PIOMIOPORTENTRYR3 const pRegEntry = &pVM->iom.s.paIoPortRegs[hIoPorts];562 AssertReturn(pRegEntry->pDevIns == pDevIns, VERR_IOM_INVALID_IOPORT_HANDLE);563 564 RTIOPORT const cPorts = pRegEntry->cPorts;565 AssertMsgReturn(cPorts > 0 && cPorts <= _8K, ("cPorts=%s\n", cPorts), VERR_IOM_IOPORT_IPE_1);566 AssertReturn((uint32_t)uPort + cPorts <= _64K, VERR_OUT_OF_RANGE);567 RTIOPORT const uLastPort = uPort + cPorts - 1;568 569 /*570 * Do the mapping.571 */572 int rc = VINF_SUCCESS;573 IOM_LOCK_EXCL(pVM);574 575 if (!pRegEntry->fMapped)576 {577 uint32_t const cEntries = RT_MIN(pVM->iom.s.cIoPortLookupEntries, pVM->iom.s.cIoPortRegs);578 Assert(pVM->iom.s.cIoPortLookupEntries == cEntries);579 580 PIOMIOPORTLOOKUPENTRY paEntries = pVM->iom.s.paIoPortLookup;581 PIOMIOPORTLOOKUPENTRY pEntry;582 if (cEntries > 0)583 {584 uint32_t iFirst = 0;585 uint32_t iEnd = cEntries;586 uint32_t i = cEntries / 2;587 for (;;)588 {589 pEntry = &paEntries[i];590 if (pEntry->uLastPort < uPort)591 {592 i += 1;593 if (i < iEnd)594 iFirst = i;595 else596 {597 /* Insert after the entry we just considered: */598 pEntry += 1;599 if (i < cEntries)600 memmove(pEntry + 1, pEntry, sizeof(*pEntry) * (cEntries - i));601 break;602 }603 }604 else if (pEntry->uFirstPort > uLastPort)605 {606 if (i > iFirst)607 iEnd = i;608 else609 {610 /* Insert at the entry we just considered: */611 if (i < cEntries)612 memmove(pEntry + 1, pEntry, sizeof(*pEntry) * (cEntries - i));613 break;614 }615 }616 else617 {618 /* Oops! We've got a conflict. */619 AssertLogRelMsgFailed(("%u..%u (%s) conflicts with existing mapping %u..%u (%s)\n",620 uPort, uLastPort, pRegEntry->pszDesc,621 pEntry->uFirstPort, pEntry->uLastPort, pVM->iom.s.paIoPortRegs[pEntry->idx].pszDesc));622 IOM_UNLOCK_EXCL(pVM);623 return VERR_IOM_IOPORT_RANGE_CONFLICT;624 }625 626 i = iFirst + (iEnd - iFirst) / 2;627 }628 }629 else630 pEntry = paEntries;631 632 /*633 * Fill in the entry and bump the table size.634 */635 pEntry->idx = hIoPorts;636 pEntry->uFirstPort = uPort;637 pEntry->uLastPort = uLastPort;638 pVM->iom.s.cIoPortLookupEntries = cEntries + 1;639 640 pRegEntry->uPort = uPort;641 pRegEntry->fMapped = true;642 643 #ifdef VBOX_WITH_STATISTICS644 /* Don't register stats here when we're creating the VM as the645 statistics table may still be reallocated. */646 if (pVM->enmVMState >= VMSTATE_CREATED)647 iomR3IoPortRegStats(pVM, pRegEntry);648 #endif649 650 #ifdef VBOX_STRICT651 /*652 * Assert table sanity.653 */654 AssertMsg(paEntries[0].uLastPort >= paEntries[0].uFirstPort, ("%#x %#x\n", paEntries[0].uLastPort, paEntries[0].uFirstPort));655 AssertMsg(paEntries[0].idx < pVM->iom.s.cIoPortRegs, ("%#x %#x\n", paEntries[0].idx, pVM->iom.s.cIoPortRegs));656 657 RTIOPORT uPortPrev = paEntries[0].uLastPort;658 for (size_t i = 1; i <= cEntries; i++)659 {660 AssertMsg(paEntries[i].uLastPort >= paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, paEntries[i].uLastPort, paEntries[i].uFirstPort));661 AssertMsg(paEntries[i].idx < pVM->iom.s.cIoPortRegs, ("%u: %#x %#x\n", i, paEntries[i].idx, pVM->iom.s.cIoPortRegs));662 AssertMsg(uPortPrev < paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, uPortPrev, paEntries[i].uFirstPort));663 uPortPrev = paEntries[i].uLastPort;664 }665 #endif666 }667 else668 {669 AssertFailed();670 rc = VERR_IOM_IOPORTS_ALREADY_MAPPED;671 }672 673 IOM_UNLOCK_EXCL(pVM);674 return rc;675 }676 677 678 /**679 * Worker for PDMDEVHLPR3::pfnIoPortUnmap.680 */681 VMMR3_INT_DECL(int) IOMR3IoPortUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts)682 {683 /*684 * Validate input and state.685 */686 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);687 AssertReturn(hIoPorts < pVM->iom.s.cIoPortRegs, VERR_IOM_INVALID_IOPORT_HANDLE);688 PIOMIOPORTENTRYR3 const pRegEntry = &pVM->iom.s.paIoPortRegs[hIoPorts];689 AssertReturn(pRegEntry->pDevIns == pDevIns, VERR_IOM_INVALID_IOPORT_HANDLE);690 691 /*692 * Do the mapping.693 */694 int rc;695 IOM_LOCK_EXCL(pVM);696 697 if (pRegEntry->fMapped)698 {699 RTIOPORT const uPort = pRegEntry->uPort;700 RTIOPORT const uLastPort = uPort + pRegEntry->cPorts - 1;701 uint32_t const cEntries = RT_MIN(pVM->iom.s.cIoPortLookupEntries, pVM->iom.s.cIoPortRegs);702 Assert(pVM->iom.s.cIoPortLookupEntries == cEntries);703 Assert(cEntries > 0);704 705 PIOMIOPORTLOOKUPENTRY paEntries = pVM->iom.s.paIoPortLookup;706 uint32_t iFirst = 0;707 uint32_t iEnd = cEntries;708 uint32_t i = cEntries / 2;709 for (;;)710 {711 PIOMIOPORTLOOKUPENTRY pEntry = &paEntries[i];712 if (pEntry->uLastPort < uPort)713 {714 i += 1;715 if (i < iEnd)716 iFirst = i;717 else718 {719 rc = VERR_IOM_IOPORT_IPE_1;720 AssertLogRelMsgFailedBreak(("%u..%u (%s) not found!\n", uPort, uLastPort, pRegEntry->pszDesc));721 }722 }723 else if (pEntry->uFirstPort > uLastPort)724 {725 if (i > iFirst)726 iEnd = i;727 else728 {729 rc = VERR_IOM_IOPORT_IPE_1;730 AssertLogRelMsgFailedBreak(("%u..%u (%s) not found!\n", uPort, uLastPort, pRegEntry->pszDesc));731 }732 }733 else if (pEntry->idx == hIoPorts)734 {735 Assert(pEntry->uFirstPort == uPort);736 Assert(pEntry->uLastPort == uLastPort);737 #ifdef VBOX_WITH_STATISTICS738 iomR3IoPortDeregStats(pVM, pRegEntry, uPort);739 #endif740 if (i + 1 < cEntries)741 memmove(pEntry, pEntry + 1, sizeof(*pEntry) * (cEntries - i - 1));742 pVM->iom.s.cIoPortLookupEntries = cEntries - 1;743 pRegEntry->uPort = UINT16_MAX;744 pRegEntry->fMapped = false;745 rc = VINF_SUCCESS;746 break;747 }748 else749 {750 AssertLogRelMsgFailed(("Lookig for %u..%u (%s), found %u..%u (%s) instead!\n",751 uPort, uLastPort, pRegEntry->pszDesc,752 pEntry->uFirstPort, pEntry->uLastPort, pVM->iom.s.paIoPortRegs[pEntry->idx].pszDesc));753 rc = VERR_IOM_IOPORT_IPE_1;754 break;755 }756 757 i = iFirst + (iEnd - iFirst) / 2;758 }759 760 #ifdef VBOX_STRICT761 /*762 * Assert table sanity.763 */764 AssertMsg(paEntries[0].uLastPort >= paEntries[0].uFirstPort, ("%#x %#x\n", paEntries[0].uLastPort, paEntries[0].uFirstPort));765 AssertMsg(paEntries[0].idx < pVM->iom.s.cIoPortRegs, ("%#x %#x\n", paEntries[0].idx, pVM->iom.s.cIoPortRegs));766 767 RTIOPORT uPortPrev = paEntries[0].uLastPort;768 for (i = 1; i < cEntries - 1; i++)769 {770 AssertMsg(paEntries[i].uLastPort >= paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, paEntries[i].uLastPort, paEntries[i].uFirstPort));771 AssertMsg(paEntries[i].idx < pVM->iom.s.cIoPortRegs, ("%u: %#x %#x\n", i, paEntries[i].idx, pVM->iom.s.cIoPortRegs));772 AssertMsg(uPortPrev < paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, uPortPrev, paEntries[i].uFirstPort));773 uPortPrev = paEntries[i].uLastPort;774 }775 #endif776 }777 else778 {779 AssertFailed();780 rc = VERR_IOM_IOPORTS_NOT_MAPPED;781 }782 783 IOM_UNLOCK_EXCL(pVM);784 return rc;785 }786 787 #ifdef VBOX_WITH_STATISTICS788 789 /**790 * Register statistics for an I/O port entry.791 */792 static void iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry)793 {794 PIOMIOPORTSTATSENTRY pStats = &pVM->iom.s.paIoPortStats[pRegEntry->idxStats];795 PCIOMIOPORTDESC pExtDesc = pRegEntry->paExtDescs;796 unsigned uPort = pRegEntry->uPort;797 unsigned const uFirstPort = uPort;798 unsigned const uEndPort = uPort + pRegEntry->cPorts;799 800 /* Register a dummy statistics for the prefix. */801 char szName[80];802 size_t cchPrefix;803 if (uFirstPort < uEndPort - 1)804 cchPrefix = RTStrPrintf(szName, sizeof(szName), "/IOM/NewPorts/%04x-%04x", uFirstPort, uEndPort - 1);805 else806 cchPrefix = RTStrPrintf(szName, sizeof(szName), "/IOM/NewPorts/%04x", uPort);807 int rc = STAMR3Register(pVM, &pRegEntry->idxSelf, STAMTYPE_U16, STAMVISIBILITY_ALWAYS, szName,808 STAMUNIT_NONE, pRegEntry->pszDesc);809 AssertRC(rc);810 811 812 /* Register stats for each port under it */813 do814 {815 size_t cchBaseNm;816 if (uFirstPort < uEndPort - 1)817 cchBaseNm = cchPrefix + RTStrPrintf(&szName[cchPrefix], sizeof(szName) - cchPrefix, "/%04x-", uPort);818 else819 {820 szName[cchPrefix] = '/';821 cchBaseNm = cchPrefix + 1;822 }823 824 # define SET_NM_SUFFIX(a_sz) memcpy(&szName[cchBaseNm], a_sz, sizeof(a_sz));825 const char * const pszInDesc = pExtDesc ? pExtDesc->pszIn : NULL;826 const char * const pszOutDesc = pExtDesc ? pExtDesc->pszOut : NULL;827 828 /* register the statistics counters. */829 SET_NM_SUFFIX("In-R3");830 rc = STAMR3Register(pVM, &pStats->InR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszInDesc); AssertRC(rc);831 SET_NM_SUFFIX("Out-R3");832 rc = STAMR3Register(pVM, &pStats->OutR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszOutDesc); AssertRC(rc);833 SET_NM_SUFFIX("In-RZ");834 rc = STAMR3Register(pVM, &pStats->InRZ, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszInDesc); AssertRC(rc);835 SET_NM_SUFFIX("Out-RZ");836 rc = STAMR3Register(pVM, &pStats->OutRZ, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszOutDesc); AssertRC(rc);837 SET_NM_SUFFIX("In-RZtoR3");838 rc = STAMR3Register(pVM, &pStats->InRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc);839 SET_NM_SUFFIX("Out-RZtoR3");840 rc = STAMR3Register(pVM, &pStats->OutRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc);841 842 /* Profiling */843 SET_NM_SUFFIX("In-R3-Prof");844 rc = STAMR3Register(pVM, &pStats->ProfInR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszInDesc); AssertRC(rc);845 SET_NM_SUFFIX("Out-R3-Prof");846 rc = STAMR3Register(pVM, &pStats->ProfOutR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszOutDesc); AssertRC(rc);847 SET_NM_SUFFIX("In-RZ-Prof");848 rc = STAMR3Register(pVM, &pStats->ProfInRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszInDesc); AssertRC(rc);849 SET_NM_SUFFIX("Out-RZ-Prof");850 rc = STAMR3Register(pVM, &pStats->ProfOutRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszOutDesc); AssertRC(rc);851 852 pStats++;853 uPort++;854 if (pExtDesc)855 pExtDesc = pszInDesc || pszOutDesc ? pExtDesc + 1 : NULL;856 } while (uPort < uEndPort);857 }858 859 860 /**861 * Deregister statistics for an I/O port entry.862 */863 static void iomR3IoPortDeregStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry, unsigned uPort)864 {865 char szPrefix[80];866 size_t cchPrefix;867 if (pRegEntry->cPorts > 1)868 cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x-%04x/", uPort, uPort + pRegEntry->cPorts - 1);869 else870 cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x/", uPort);871 STAMR3DeregisterByPrefix(pVM->pUVM, szPrefix);872 }873 874 #endif /* VBOX_WITH_STATISTICS */875 445 #ifdef VBOX_WITH_STATISTICS 876 446 … … 1701 1271 1702 1272 1703 /**1704 * @callback_method_impl{FNIOMIOPORTNEWIN,1705 * Dummy Port I/O Handler for IN operations.}1706 */1707 static DECLCALLBACK(VBOXSTRICTRC)1708 iomR3IOPortDummyNewIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)1709 {1710 NOREF(pDevIns); NOREF(pvUser); NOREF(Port);1711 switch (cb)1712 {1713 case 1: *pu32 = 0xff; break;1714 case 2: *pu32 = 0xffff; break;1715 case 4: *pu32 = UINT32_C(0xffffffff); break;1716 default:1717 AssertReleaseMsgFailed(("cb=%d\n", cb));1718 return VERR_IOM_IOPORT_IPE_2;1719 }1720 return VINF_SUCCESS;1721 }1722 1723 1724 /**1725 * @callback_method_impl{FNIOMIOPORTNEWINSTRING,1726 * Dummy Port I/O Handler for string IN operations.}1727 */1728 static DECLCALLBACK(VBOXSTRICTRC)1729 iomR3IOPortDummyNewInStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t *pbDst, uint32_t *pcTransfer, unsigned cb)1730 {1731 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbDst); NOREF(pcTransfer); NOREF(cb);1732 return VINF_SUCCESS;1733 }1734 1735 1736 /**1737 * @callback_method_impl{FNIOMIOPORTNEWOUT,1738 * Dummy Port I/O Handler for OUT operations.}1739 */1740 static DECLCALLBACK(VBOXSTRICTRC)1741 iomR3IOPortDummyNewOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)1742 {1743 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(u32); NOREF(cb);1744 return VINF_SUCCESS;1745 }1746 1747 1748 /**1749 * @callback_method_impl{FNIOMIOPORTNEWOUTSTRING,1750 * Dummy Port I/O Handler for string OUT operations.}1751 */1752 static DECLCALLBACK(VBOXSTRICTRC)1753 iomR3IOPortDummyNewOutStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t const *pbSrc, uint32_t *pcTransfer, unsigned cb)1754 {1755 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbSrc); NOREF(pcTransfer); NOREF(cb);1756 return VINF_SUCCESS;1757 }1758 1759 1760 /**1761 * Display a single I/O port ring-3 range.1762 *1763 * @returns 01764 * @param pNode Pointer to I/O port HC range.1765 * @param pvUser Pointer to info output callback structure.1766 */1767 static DECLCALLBACK(int) iomR3IOPortInfoOneR3(PAVLROIOPORTNODECORE pNode, void *pvUser)1768 {1769 PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)pNode;1770 PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;1771 pHlp->pfnPrintf(pHlp,1772 "%04x-%04x %p %p %p %p %s\n",1773 pRange->Core.Key,1774 pRange->Core.KeyLast,1775 pRange->pDevIns,1776 pRange->pfnInCallback,1777 pRange->pfnOutCallback,1778 pRange->pvUser,1779 pRange->pszDesc);1780 return 0;1781 }1782 1783 1784 #if 01785 /**1786 * Display a single I/O port GC range.1787 *1788 * @returns 01789 * @param pNode Pointer to IOPORT GC range.1790 * @param pvUser Pointer to info output callback structure.1791 */1792 static DECLCALLBACK(int) iomR3IOPortInfoOneRC(PAVLROIOPORTNODECORE pNode, void *pvUser)1793 {1794 PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)pNode;1795 PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;1796 pHlp->pfnPrintf(pHlp,1797 "%04x-%04x %RRv %RRv %RRv %RRv %s\n",1798 pRange->Core.Key,1799 pRange->Core.KeyLast,1800 pRange->pDevIns,1801 pRange->pfnInCallback,1802 pRange->pfnOutCallback,1803 pRange->pvUser,1804 pRange->pszDesc);1805 return 0;1806 }1807 #endif1808 1809 1810 /**1811 * Display all registered I/O port ranges.1812 *1813 * @param pVM The cross context VM structure.1814 * @param pHlp The info helpers.1815 * @param pszArgs Arguments, ignored.1816 */1817 static DECLCALLBACK(void) iomR3IOPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)1818 {1819 /* No locking needed here as registerations are only happening during VMSTATE_CREATING. */1820 pHlp->pfnPrintf(pHlp,1821 "I/O port registrations: %u (%u allocated)\n"1822 " ## Ctx Ports Mapping PCI Description\n",1823 pVM->iom.s.cIoPortRegs, pVM->iom.s.cIoPortAlloc);1824 PIOMIOPORTENTRYR3 paRegs = pVM->iom.s.paIoPortRegs;1825 for (uint32_t i = 0; i < pVM->iom.s.cIoPortRegs; i++)1826 {1827 const char * const pszRing = paRegs[i].fRing0 ? paRegs[i].fRawMode ? "+0+C" : "+0 "1828 : paRegs[i].fRawMode ? "+C " : " ";1829 if (paRegs[i].fMapped && paRegs[i].pPciDev)1830 pHlp->pfnPrintf(pHlp, "%3u R3%s %04x %04x-%04x pci%u/%u %s\n", paRegs[i].idxSelf, pszRing, paRegs[i].cPorts,1831 paRegs[i].uPort, paRegs[i].uPort + paRegs[i].cPorts - 1,1832 paRegs[i].pPciDev->idxSubDev, paRegs[i].iPciRegion, paRegs[i].pszDesc);1833 else if (paRegs[i].fMapped && !paRegs[i].pPciDev)1834 pHlp->pfnPrintf(pHlp, "%3u R3%s %04x %04x-%04x %s\n", paRegs[i].idxSelf, pszRing, paRegs[i].cPorts,1835 paRegs[i].uPort, paRegs[i].uPort + paRegs[i].cPorts - 1, paRegs[i].pszDesc);1836 else if (paRegs[i].pPciDev)1837 pHlp->pfnPrintf(pHlp, "%3u R3%s %04x unmapped pci%u/%u %s\n", paRegs[i].idxSelf, pszRing, paRegs[i].cPorts,1838 paRegs[i].pPciDev->idxSubDev, paRegs[i].iPciRegion, paRegs[i].pszDesc);1839 else1840 pHlp->pfnPrintf(pHlp, "%3u R3%s %04x unmapped %s\n",1841 paRegs[i].idxSelf, pszRing, paRegs[i].cPorts, paRegs[i].pszDesc);1842 }1843 1844 /* Legacy registration: */1845 NOREF(pszArgs);1846 pHlp->pfnPrintf(pHlp,1847 "I/O Port R3 ranges (pVM=%p)\n"1848 "Range %.*s %.*s %.*s %.*s Description\n",1849 pVM,1850 sizeof(RTHCPTR) * 2, "pDevIns ",1851 sizeof(RTHCPTR) * 2, "In ",1852 sizeof(RTHCPTR) * 2, "Out ",1853 sizeof(RTHCPTR) * 2, "pvUser ");1854 IOM_LOCK_SHARED(pVM);1855 RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeR3, true, iomR3IOPortInfoOneR3, (void *)pHlp);1856 IOM_UNLOCK_SHARED(pVM);1857 1858 pHlp->pfnPrintf(pHlp,1859 "I/O Port R0 ranges (pVM=%p)\n"1860 "Range %.*s %.*s %.*s %.*s Description\n",1861 pVM,1862 sizeof(RTHCPTR) * 2, "pDevIns ",1863 sizeof(RTHCPTR) * 2, "In ",1864 sizeof(RTHCPTR) * 2, "Out ",1865 sizeof(RTHCPTR) * 2, "pvUser ");1866 IOM_LOCK_SHARED(pVM);1867 RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeR0, true, iomR3IOPortInfoOneR3, (void *)pHlp);1868 IOM_UNLOCK_SHARED(pVM);1869 }1870 1871 1273 1872 1274 /** … … 2925 2327 #endif /* VBOX_WITH_STATISTICS */ 2926 2328 2329 2330 VMMR3_INT_DECL(int) IOMR3MmioCreate(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS cbRegion, uint32_t fFlags, PPDMPCIDEV pPciDev, 2331 uint32_t iPciRegion, PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, 2332 PFNIOMMMIONEWFILL pfnFill, void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion) 2333 { 2334 RT_NOREF(pVM, pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion); 2335 return VERR_NOT_IMPLEMENTED; 2336 } 2337 2338 VMMR3_INT_DECL(int) IOMR3MmioMap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys) 2339 { 2340 RT_NOREF(pVM, pDevIns, hRegion, GCPhys); 2341 return VERR_NOT_IMPLEMENTED; 2342 } 2343 2344 VMMR3_INT_DECL(int) IOMR3MmioUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) 2345 { 2346 RT_NOREF(pVM, pDevIns, hRegion); 2347 return VERR_NOT_IMPLEMENTED; 2348 } 2349 2350 VMMR3_INT_DECL(int) IOMR3MmioReduce(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion) 2351 { 2352 RT_NOREF(pVM, pDevIns, hRegion, cbRegion); 2353 return VERR_NOT_IMPLEMENTED; 2354 } 2355 -
trunk/src/VBox/VMM/VMMR3/IOMR3IoPort.cpp
r81153 r81156 1 1 /* $Id$ */ 2 2 /** @file 3 * IOM - Input / Output Monitor .3 * IOM - Input / Output Monitor, I/O port related APIs. 4 4 */ 5 5 … … 17 17 18 18 19 /** @page pg_iom IOM - The Input / Output Monitor20 *21 * The input/output monitor will handle I/O exceptions routing them to the22 * appropriate device. It implements an API to register and deregister virtual23 * I/0 port handlers and memory mapped I/O handlers. A handler is PDM devices24 * and a set of callback functions.25 *26 * @see grp_iom27 *28 *29 * @section sec_iom_rawmode Raw-Mode30 *31 * In raw-mode I/O port access is trapped (\#GP(0)) by ensuring that the actual32 * IOPL is 0 regardless of what the guest IOPL is. The \#GP handler use the33 * disassembler (DIS) to figure which instruction caused it (there are a number34 * of instructions in addition to the I/O ones) and if it's an I/O port access35 * it will hand it to IOMRCIOPortHandler (via EMInterpretPortIO).36 * IOMRCIOPortHandler will lookup the port in the AVL tree of registered37 * handlers. If found, the handler will be called otherwise default action is38 * taken. (Default action is to write into the void and read all set bits.)39 *40 * Memory Mapped I/O (MMIO) is implemented as a slightly special case of PGM41 * access handlers. An MMIO range is registered with IOM which then registers it42 * with the PGM access handler sub-system. The access handler catches all43 * access and will be called in the context of a \#PF handler. In RC and R0 this44 * handler is iomMmioPfHandler while in ring-3 it's iomR3MmioHandler (although45 * in ring-3 there can be alternative ways). iomMmioPfHandler will attempt to46 * emulate the instruction that is doing the access and pass the corresponding47 * reads / writes to the device.48 *49 * Emulating I/O port access is less complex and should be slightly faster than50 * emulating MMIO, so in most cases we should encourage the OS to use port I/O.51 * Devices which are frequently accessed should register GC handlers to speed up52 * execution.53 *54 *55 * @section sec_iom_hm Hardware Assisted Virtualization Mode56 *57 * When running in hardware assisted virtualization mode we'll be doing much the58 * same things as in raw-mode. The main difference is that we're running in the59 * host ring-0 context and that we don't get faults (\#GP(0) and \#PG) but60 * exits.61 *62 *63 * @section sec_iom_rem Recompiled Execution Mode64 *65 * When running in the recompiler things are different. I/O port access is66 * handled by calling IOMIOPortRead and IOMIOPortWrite directly. While MMIO can67 * be handled in one of two ways. The normal way is that we have a registered a68 * special RAM range with the recompiler and in the three callbacks (for byte,69 * word and dword access) we call IOMMMIORead and IOMMMIOWrite directly. The70 * alternative ways that the physical memory access which goes via PGM will take71 * care of it by calling iomR3MmioHandler via the PGM access handler machinery72 * - this shouldn't happen but it is an alternative...73 *74 *75 * @section sec_iom_other Other Accesses76 *77 * I/O ports aren't really exposed in any other way, unless you count the78 * instruction interpreter in EM, but that's just what we're doing in the79 * raw-mode \#GP(0) case really. Now, it's possible to call IOMIOPortRead and80 * IOMIOPortWrite directly to talk to a device, but this is really bad behavior81 * and should only be done as temporary hacks (the PC BIOS device used to setup82 * the CMOS this way back in the dark ages).83 *84 * MMIO has similar direct routes as the I/O ports and these shouldn't be used85 * for the same reasons and with the same restrictions. OTOH since MMIO is86 * mapped into the physical memory address space, it can be accessed in a number87 * of ways thru PGM.88 *89 *90 * @section sec_iom_logging Logging Levels91 *92 * Following assignments:93 * - Level 5 is used for defering I/O port and MMIO writes to ring-3.94 *95 */96 97 /** @todo MMIO - simplifying the device end.98 * - Add a return status for doing DBGFSTOP on access where there are no known99 * registers.100 * -101 *102 * */103 104 105 19 /********************************************************************************************************************************* 106 20 * Header Files * … … 108 22 #define LOG_GROUP LOG_GROUP_IOM 109 23 #include <VBox/vmm/iom.h> 110 #include <VBox/vmm/cpum.h>111 #include <VBox/vmm/pgm.h>112 24 #include <VBox/sup.h> 113 #include <VBox/vmm/hm.h>114 25 #include <VBox/vmm/mm.h> 115 26 #include <VBox/vmm/stam.h> … … 122 33 #include <VBox/param.h> 123 34 #include <iprt/assert.h> 124 #include <iprt/alloc.h>125 35 #include <iprt/string.h> 126 36 #include <VBox/log.h> … … 130 40 131 41 132 /*********************************************************************************************************************************133 * Internal Functions *134 *********************************************************************************************************************************/135 static void iomR3FlushCache(PVM pVM);136 #if 0137 static DECLCALLBACK(int) iomR3RelocateIOPortCallback(PAVLROIOPORTNODECORE pNode, void *pvUser);138 static DECLCALLBACK(int) iomR3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser);139 #endif140 42 #ifdef VBOX_WITH_STATISTICS 141 static void iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry); 142 static void iomR3IoPortDeregStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry, unsigned uPort); 143 #endif 144 static DECLCALLBACK(void) iomR3IOPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs); 145 static DECLCALLBACK(void) iomR3MMIOInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs); 146 static FNIOMIOPORTIN iomR3IOPortDummyIn; 147 static FNIOMIOPORTOUT iomR3IOPortDummyOut; 148 static FNIOMIOPORTINSTRING iomR3IOPortDummyInStr; 149 static FNIOMIOPORTOUTSTRING iomR3IOPortDummyOutStr; 150 static FNIOMIOPORTNEWIN iomR3IOPortDummyNewIn; 151 static FNIOMIOPORTNEWOUT iomR3IOPortDummyNewOut; 152 static FNIOMIOPORTNEWINSTRING iomR3IOPortDummyNewInStr; 153 static FNIOMIOPORTNEWOUTSTRING iomR3IOPortDummyNewOutStr; 154 155 #ifdef VBOX_WITH_STATISTICS 156 static const char *iomR3IOPortGetStandardName(RTIOPORT Port); 157 #endif 158 159 160 /** 161 * Initializes the IOM. 162 * 163 * @returns VBox status code. 164 * @param pVM The cross context VM structure. 165 */ 166 VMMR3_INT_DECL(int) IOMR3Init(PVM pVM) 167 { 168 LogFlow(("IOMR3Init:\n")); 169 170 /* 171 * Assert alignment and sizes. 172 */ 173 AssertCompileMemberAlignment(VM, iom.s, 32); 174 AssertCompile(sizeof(pVM->iom.s) <= sizeof(pVM->iom.padding)); 175 AssertCompileMemberAlignment(IOM, CritSect, sizeof(uintptr_t)); 176 177 /* 178 * Initialize the REM critical section. 179 */ 180 #ifdef IOM_WITH_CRIT_SECT_RW 181 int rc = PDMR3CritSectRwInit(pVM, &pVM->iom.s.CritSect, RT_SRC_POS, "IOM Lock"); 182 #else 183 int rc = PDMR3CritSectInit(pVM, &pVM->iom.s.CritSect, RT_SRC_POS, "IOM Lock"); 184 #endif 185 AssertRCReturn(rc, rc); 186 187 /* 188 * Allocate the trees structure. 189 */ 190 rc = MMHyperAlloc(pVM, sizeof(*pVM->iom.s.pTreesR3), 0, MM_TAG_IOM, (void **)&pVM->iom.s.pTreesR3); 191 if (RT_SUCCESS(rc)) 192 { 193 pVM->iom.s.pTreesR0 = MMHyperR3ToR0(pVM, pVM->iom.s.pTreesR3); 194 195 /* 196 * Register the MMIO access handler type. 197 */ 198 rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_MMIO, 199 iomMmioHandler, 200 NULL, "iomMmioHandler", "iomMmioPfHandler", 201 NULL, "iomMmioHandler", "iomMmioPfHandler", 202 "MMIO", &pVM->iom.s.hMmioHandlerType); 203 AssertRC(rc); 204 if (RT_SUCCESS(rc)) 43 44 /** 45 * Register statistics for an I/O port entry. 46 */ 47 void iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry) 48 { 49 PIOMIOPORTSTATSENTRY pStats = &pVM->iom.s.paIoPortStats[pRegEntry->idxStats]; 50 PCIOMIOPORTDESC pExtDesc = pRegEntry->paExtDescs; 51 unsigned uPort = pRegEntry->uPort; 52 unsigned const uFirstPort = uPort; 53 unsigned const uEndPort = uPort + pRegEntry->cPorts; 54 55 /* Register a dummy statistics for the prefix. */ 56 char szName[80]; 57 size_t cchPrefix; 58 if (uFirstPort < uEndPort - 1) 59 cchPrefix = RTStrPrintf(szName, sizeof(szName), "/IOM/NewPorts/%04x-%04x", uFirstPort, uEndPort - 1); 60 else 61 cchPrefix = RTStrPrintf(szName, sizeof(szName), "/IOM/NewPorts/%04x", uPort); 62 const char *pszDesc = pRegEntry->pszDesc; 63 char *pszFreeDesc = NULL; 64 if (pRegEntry->pDevIns && pRegEntry->pDevIns->iInstance > 0 && pszDesc) 65 pszDesc = pszFreeDesc = RTStrAPrintf2("%u / %s", pRegEntry->pDevIns->iInstance, pszDesc); 66 int rc = STAMR3Register(pVM, &pRegEntry->idxSelf, STAMTYPE_U16, STAMVISIBILITY_ALWAYS, szName, 67 STAMUNIT_NONE, pRegEntry->pszDesc); 68 AssertRC(rc); 69 RTStrFree(pszFreeDesc); 70 71 /* Register stats for each port under it */ 72 do 73 { 74 size_t cchBaseNm; 75 if (uFirstPort < uEndPort - 1) 76 cchBaseNm = cchPrefix + RTStrPrintf(&szName[cchPrefix], sizeof(szName) - cchPrefix, "/%04x-", uPort); 77 else 205 78 { 206 207 /* 208 * Info. 209 */ 210 DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IOPortInfo); 211 DBGFR3InfoRegisterInternal(pVM, "mmio", "Dumps all MMIO ranges. No arguments.", &iomR3MMIOInfo); 212 213 /* 214 * Statistics. 215 */ 216 STAM_REG(pVM, &pVM->iom.s.StatRZMMIOHandler, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler", STAMUNIT_TICKS_PER_CALL, "Profiling of the iomMmioPfHandler() body, only success calls."); 217 STAM_REG(pVM, &pVM->iom.s.StatRZMMIO1Byte, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access1", STAMUNIT_OCCURENCES, "MMIO access by 1 byte counter."); 218 STAM_REG(pVM, &pVM->iom.s.StatRZMMIO2Bytes, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access2", STAMUNIT_OCCURENCES, "MMIO access by 2 bytes counter."); 219 STAM_REG(pVM, &pVM->iom.s.StatRZMMIO4Bytes, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access4", STAMUNIT_OCCURENCES, "MMIO access by 4 bytes counter."); 220 STAM_REG(pVM, &pVM->iom.s.StatRZMMIO8Bytes, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access8", STAMUNIT_OCCURENCES, "MMIO access by 8 bytes counter."); 221 STAM_REG(pVM, &pVM->iom.s.StatRZMMIOFailures, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/MMIOFailures", STAMUNIT_OCCURENCES, "Number of times iomMmioPfHandler() didn't service the request."); 222 STAM_REG(pVM, &pVM->iom.s.StatRZInstMov, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOV", STAMUNIT_TICKS_PER_CALL, "Profiling of the MOV instruction emulation."); 223 STAM_REG(pVM, &pVM->iom.s.StatRZInstCmp, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/CMP", STAMUNIT_TICKS_PER_CALL, "Profiling of the CMP instruction emulation."); 224 STAM_REG(pVM, &pVM->iom.s.StatRZInstAnd, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/AND", STAMUNIT_TICKS_PER_CALL, "Profiling of the AND instruction emulation."); 225 STAM_REG(pVM, &pVM->iom.s.StatRZInstOr, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/OR", STAMUNIT_TICKS_PER_CALL, "Profiling of the OR instruction emulation."); 226 STAM_REG(pVM, &pVM->iom.s.StatRZInstXor, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/XOR", STAMUNIT_TICKS_PER_CALL, "Profiling of the XOR instruction emulation."); 227 STAM_REG(pVM, &pVM->iom.s.StatRZInstBt, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/BT", STAMUNIT_TICKS_PER_CALL, "Profiling of the BT instruction emulation."); 228 STAM_REG(pVM, &pVM->iom.s.StatRZInstTest, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/TEST", STAMUNIT_TICKS_PER_CALL, "Profiling of the TEST instruction emulation."); 229 STAM_REG(pVM, &pVM->iom.s.StatRZInstXchg, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/XCHG", STAMUNIT_TICKS_PER_CALL, "Profiling of the XCHG instruction emulation."); 230 STAM_REG(pVM, &pVM->iom.s.StatRZInstStos, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/STOS", STAMUNIT_TICKS_PER_CALL, "Profiling of the STOS instruction emulation."); 231 STAM_REG(pVM, &pVM->iom.s.StatRZInstLods, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/LODS", STAMUNIT_TICKS_PER_CALL, "Profiling of the LODS instruction emulation."); 232 #ifdef IOM_WITH_MOVS_SUPPORT 233 STAM_REG(pVM, &pVM->iom.s.StatRZInstMovs, STAMTYPE_PROFILE_ADV, "/IOM/RZ-MMIOHandler/Inst/MOVS", STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation."); 234 STAM_REG(pVM, &pVM->iom.s.StatRZInstMovsToMMIO, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOVS/ToMMIO", STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation - Mem2MMIO."); 235 STAM_REG(pVM, &pVM->iom.s.StatRZInstMovsFromMMIO, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOVS/FromMMIO", STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation - MMIO2Mem."); 236 STAM_REG(pVM, &pVM->iom.s.StatRZInstMovsMMIO, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOVS/MMIO2MMIO", STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation - MMIO2MMIO."); 237 #endif 238 STAM_REG(pVM, &pVM->iom.s.StatRZInstOther, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Inst/Other", STAMUNIT_OCCURENCES, "Other instructions counter."); 239 STAM_REG(pVM, &pVM->iom.s.StatR3MMIOHandler, STAMTYPE_COUNTER, "/IOM/R3-MMIOHandler", STAMUNIT_OCCURENCES, "Number of calls to iomR3MmioHandler."); 240 #if 0 /* unused */ 241 STAM_REG(pVM, &pVM->iom.s.StatInstIn, STAMTYPE_COUNTER, "/IOM/IOWork/In", STAMUNIT_OCCURENCES, "Counter of any IN instructions."); 242 STAM_REG(pVM, &pVM->iom.s.StatInstOut, STAMTYPE_COUNTER, "/IOM/IOWork/Out", STAMUNIT_OCCURENCES, "Counter of any OUT instructions."); 243 STAM_REG(pVM, &pVM->iom.s.StatInstIns, STAMTYPE_COUNTER, "/IOM/IOWork/Ins", STAMUNIT_OCCURENCES, "Counter of any INS instructions."); 244 STAM_REG(pVM, &pVM->iom.s.StatInstOuts, STAMTYPE_COUNTER, "/IOM/IOWork/Outs", STAMUNIT_OCCURENCES, "Counter of any OUTS instructions."); 245 #endif 79 szName[cchPrefix] = '/'; 80 cchBaseNm = cchPrefix + 1; 246 81 } 247 } 248 249 /* Redundant, but just in case we change something in the future */ 250 iomR3FlushCache(pVM); 251 252 LogFlow(("IOMR3Init: returns %Rrc\n", rc)); 253 return rc; 254 } 255 256 257 /** 258 * Called when a VM initialization stage is completed. 259 * 260 * @returns VBox status code. 261 * @param pVM The cross context VM structure. 262 * @param enmWhat The initialization state that was completed. 263 */ 264 VMMR3_INT_DECL(int) IOMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat) 265 { 266 #ifdef VBOX_WITH_STATISTICS 267 if (enmWhat == VMINITCOMPLETED_RING3) 268 { 269 for (uint32_t i = 0; i < pVM->iom.s.cIoPortRegs; i++) 270 { 271 PIOMIOPORTENTRYR3 pRegEntry = &pVM->iom.s.paIoPortRegs[i]; 272 if ( pRegEntry->fMapped 273 && pRegEntry->idxStats != UINT16_MAX) 274 iomR3IoPortRegStats(pVM, pRegEntry); 275 } 276 } 277 #else 278 RT_NOREF(pVM, enmWhat); 279 #endif 82 83 # define SET_NM_SUFFIX(a_sz) memcpy(&szName[cchBaseNm], a_sz, sizeof(a_sz)); 84 const char * const pszInDesc = pExtDesc ? pExtDesc->pszIn : NULL; 85 const char * const pszOutDesc = pExtDesc ? pExtDesc->pszOut : NULL; 86 87 /* register the statistics counters. */ 88 SET_NM_SUFFIX("In-R3"); 89 rc = STAMR3Register(pVM, &pStats->InR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszInDesc); AssertRC(rc); 90 SET_NM_SUFFIX("Out-R3"); 91 rc = STAMR3Register(pVM, &pStats->OutR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszOutDesc); AssertRC(rc); 92 SET_NM_SUFFIX("In-RZ"); 93 rc = STAMR3Register(pVM, &pStats->InRZ, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszInDesc); AssertRC(rc); 94 SET_NM_SUFFIX("Out-RZ"); 95 rc = STAMR3Register(pVM, &pStats->OutRZ, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszOutDesc); AssertRC(rc); 96 SET_NM_SUFFIX("In-RZtoR3"); 97 rc = STAMR3Register(pVM, &pStats->InRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc); 98 SET_NM_SUFFIX("Out-RZtoR3"); 99 rc = STAMR3Register(pVM, &pStats->OutRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc); 100 101 /* Profiling */ 102 SET_NM_SUFFIX("In-R3-Prof"); 103 rc = STAMR3Register(pVM, &pStats->ProfInR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszInDesc); AssertRC(rc); 104 SET_NM_SUFFIX("Out-R3-Prof"); 105 rc = STAMR3Register(pVM, &pStats->ProfOutR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszOutDesc); AssertRC(rc); 106 SET_NM_SUFFIX("In-RZ-Prof"); 107 rc = STAMR3Register(pVM, &pStats->ProfInRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszInDesc); AssertRC(rc); 108 SET_NM_SUFFIX("Out-RZ-Prof"); 109 rc = STAMR3Register(pVM, &pStats->ProfOutRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszOutDesc); AssertRC(rc); 110 111 pStats++; 112 uPort++; 113 if (pExtDesc) 114 pExtDesc = pszInDesc || pszOutDesc ? pExtDesc + 1 : NULL; 115 } while (uPort < uEndPort); 116 } 117 118 119 /** 120 * Deregister statistics for an I/O port entry. 121 */ 122 static void iomR3IoPortDeregStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry, unsigned uPort) 123 { 124 char szPrefix[80]; 125 size_t cchPrefix; 126 if (pRegEntry->cPorts > 1) 127 cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x-%04x/", uPort, uPort + pRegEntry->cPorts - 1); 128 else 129 cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x/", uPort); 130 STAMR3DeregisterByPrefix(pVM->pUVM, szPrefix); 131 } 132 133 #endif /* VBOX_WITH_STATISTICS */ 134 135 136 /** 137 * @callback_method_impl{FNIOMIOPORTNEWIN, 138 * Dummy Port I/O Handler for IN operations.} 139 */ 140 static DECLCALLBACK(VBOXSTRICTRC) 141 iomR3IOPortDummyNewIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb) 142 { 143 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); 144 switch (cb) 145 { 146 case 1: *pu32 = 0xff; break; 147 case 2: *pu32 = 0xffff; break; 148 case 4: *pu32 = UINT32_C(0xffffffff); break; 149 default: 150 AssertReleaseMsgFailed(("cb=%d\n", cb)); 151 return VERR_IOM_IOPORT_IPE_2; 152 } 280 153 return VINF_SUCCESS; 281 154 } … … 283 156 284 157 /** 285 * Flushes the IOM port & statistics lookup cache 286 * 287 * @param pVM The cross context VM structure. 288 */ 289 static void iomR3FlushCache(PVM pVM) 290 { 291 /* 292 * Since all relevant (1) cache use requires at least read access to the 293 * critical section, we can exclude all other EMTs by grabbing exclusive 294 * access to the critical section and then safely update the caches of 295 * other EMTs. 296 * (1) The irrelvant access not holding the lock is in assertion code. 297 */ 298 IOM_LOCK_EXCL(pVM); 299 VMCPUID idCpu = pVM->cCpus; 300 while (idCpu-- > 0) 301 { 302 PVMCPU pVCpu = pVM->apCpusR3[idCpu]; 303 pVCpu->iom.s.pRangeLastReadR0 = NIL_RTR0PTR; 304 pVCpu->iom.s.pRangeLastWriteR0 = NIL_RTR0PTR; 305 pVCpu->iom.s.pStatsLastReadR0 = NIL_RTR0PTR; 306 pVCpu->iom.s.pStatsLastWriteR0 = NIL_RTR0PTR; 307 pVCpu->iom.s.pMMIORangeLastR0 = NIL_RTR0PTR; 308 pVCpu->iom.s.pMMIOStatsLastR0 = NIL_RTR0PTR; 309 310 pVCpu->iom.s.pRangeLastReadR3 = NULL; 311 pVCpu->iom.s.pRangeLastWriteR3 = NULL; 312 pVCpu->iom.s.pStatsLastReadR3 = NULL; 313 pVCpu->iom.s.pStatsLastWriteR3 = NULL; 314 pVCpu->iom.s.pMMIORangeLastR3 = NULL; 315 pVCpu->iom.s.pMMIOStatsLastR3 = NULL; 316 } 317 318 IOM_UNLOCK_EXCL(pVM); 319 } 320 321 322 /** 323 * The VM is being reset. 324 * 325 * @param pVM The cross context VM structure. 326 */ 327 VMMR3_INT_DECL(void) IOMR3Reset(PVM pVM) 328 { 329 iomR3FlushCache(pVM); 330 } 331 332 333 /** 334 * Applies relocations to data and code managed by this 335 * component. This function will be called at init and 336 * whenever the VMM need to relocate it self inside the GC. 337 * 338 * The IOM will update the addresses used by the switcher. 339 * 340 * @param pVM The cross context VM structure. 341 * @param offDelta Relocation delta relative to old location. 342 */ 343 VMMR3_INT_DECL(void) IOMR3Relocate(PVM pVM, RTGCINTPTR offDelta) 344 { 345 #if 0 346 LogFlow(("IOMR3Relocate: offDelta=%d\n", offDelta)); 347 348 /* 349 * Apply relocations to the GC callbacks. 350 */ 351 pVM->iom.s.pTreesRC = MMHyperR3ToRC(pVM, pVM->iom.s.pTreesR3); 352 RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeRC, true, iomR3RelocateIOPortCallback, &offDelta); 353 RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesR3->MMIOTree, true, iomR3RelocateMMIOCallback, &offDelta); 354 355 /* 356 * Reset the raw-mode cache (don't bother relocating it). 357 */ 358 VMCPUID idCpu = pVM->cCpus; 359 while (idCpu-- > 0) 360 { 361 PVMCPU pVCpu = pVM->apCpusR3[idCpu]; 362 pVCpu->iom.s.pRangeLastReadRC = NIL_RTRCPTR; 363 pVCpu->iom.s.pRangeLastWriteRC = NIL_RTRCPTR; 364 pVCpu->iom.s.pStatsLastReadRC = NIL_RTRCPTR; 365 pVCpu->iom.s.pStatsLastWriteRC = NIL_RTRCPTR; 366 pVCpu->iom.s.pMMIORangeLastRC = NIL_RTRCPTR; 367 pVCpu->iom.s.pMMIOStatsLastRC = NIL_RTRCPTR; 368 } 369 #else 370 RT_NOREF(pVM, offDelta); 371 #endif 372 } 373 374 #if 0 375 376 /** 377 * Callback function for relocating a I/O port range. 378 * 379 * @returns 0 (continue enum) 380 * @param pNode Pointer to a IOMIOPORTRANGERC node. 381 * @param pvUser Pointer to the offDelta. This is a pointer to the delta since we're 382 * not certain the delta will fit in a void pointer for all possible configs. 383 */ 384 static DECLCALLBACK(int) iomR3RelocateIOPortCallback(PAVLROIOPORTNODECORE pNode, void *pvUser) 385 { 386 PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)pNode; 387 RTGCINTPTR offDelta = *(PRTGCINTPTR)pvUser; 388 389 Assert(pRange->pDevIns); 390 pRange->pDevIns += offDelta; 391 if (pRange->pfnOutCallback) 392 pRange->pfnOutCallback += offDelta; 393 if (pRange->pfnInCallback) 394 pRange->pfnInCallback += offDelta; 395 if (pRange->pfnOutStrCallback) 396 pRange->pfnOutStrCallback += offDelta; 397 if (pRange->pfnInStrCallback) 398 pRange->pfnInStrCallback += offDelta; 399 if (pRange->pvUser > _64K) 400 pRange->pvUser += offDelta; 401 return 0; 402 } 403 404 405 /** 406 * Callback function for relocating a MMIO range. 407 * 408 * @returns 0 (continue enum) 409 * @param pNode Pointer to a IOMMMIORANGE node. 410 * @param pvUser Pointer to the offDelta. This is a pointer to the delta since we're 411 * not certain the delta will fit in a void pointer for all possible configs. 412 */ 413 static DECLCALLBACK(int) iomR3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser) 414 { 415 PIOMMMIORANGE pRange = (PIOMMMIORANGE)pNode; 416 RTGCINTPTR offDelta = *(PRTGCINTPTR)pvUser; 417 418 if (pRange->pDevInsRC) 419 pRange->pDevInsRC += offDelta; 420 if (pRange->pfnWriteCallbackRC) 421 pRange->pfnWriteCallbackRC += offDelta; 422 if (pRange->pfnReadCallbackRC) 423 pRange->pfnReadCallbackRC += offDelta; 424 if (pRange->pfnFillCallbackRC) 425 pRange->pfnFillCallbackRC += offDelta; 426 if (pRange->pvUserRC > _64K) 427 pRange->pvUserRC += offDelta; 428 429 return 0; 430 } 431 432 #endif 433 434 /** 435 * Terminates the IOM. 436 * 437 * Termination means cleaning up and freeing all resources, 438 * the VM it self is at this point powered off or suspended. 439 * 440 * @returns VBox status code. 441 * @param pVM The cross context VM structure. 442 */ 443 VMMR3_INT_DECL(int) IOMR3Term(PVM pVM) 444 { 445 /* 446 * IOM is not owning anything but automatically freed resources, 447 * so there's nothing to do here. 448 */ 449 NOREF(pVM); 158 * @callback_method_impl{FNIOMIOPORTNEWINSTRING, 159 * Dummy Port I/O Handler for string IN operations.} 160 */ 161 static DECLCALLBACK(VBOXSTRICTRC) 162 iomR3IOPortDummyNewInStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t *pbDst, uint32_t *pcTransfer, unsigned cb) 163 { 164 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbDst); NOREF(pcTransfer); NOREF(cb); 450 165 return VINF_SUCCESS; 451 166 } 167 168 169 /** 170 * @callback_method_impl{FNIOMIOPORTNEWOUT, 171 * Dummy Port I/O Handler for OUT operations.} 172 */ 173 static DECLCALLBACK(VBOXSTRICTRC) 174 iomR3IOPortDummyNewOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb) 175 { 176 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(u32); NOREF(cb); 177 return VINF_SUCCESS; 178 } 179 180 181 /** 182 * @callback_method_impl{FNIOMIOPORTNEWOUTSTRING, 183 * Dummy Port I/O Handler for string OUT operations.} 184 */ 185 static DECLCALLBACK(VBOXSTRICTRC) 186 iomR3IOPortDummyNewOutStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t const *pbSrc, uint32_t *pcTransfer, unsigned cb) 187 { 188 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbSrc); NOREF(pcTransfer); NOREF(cb); 189 return VINF_SUCCESS; 190 } 191 452 192 453 193 … … 785 525 } 786 526 787 #ifdef VBOX_WITH_STATISTICS788 789 /**790 * Register statistics for an I/O port entry.791 */792 static void iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry)793 {794 PIOMIOPORTSTATSENTRY pStats = &pVM->iom.s.paIoPortStats[pRegEntry->idxStats];795 PCIOMIOPORTDESC pExtDesc = pRegEntry->paExtDescs;796 unsigned uPort = pRegEntry->uPort;797 unsigned const uFirstPort = uPort;798 unsigned const uEndPort = uPort + pRegEntry->cPorts;799 800 /* Register a dummy statistics for the prefix. */801 char szName[80];802 size_t cchPrefix;803 if (uFirstPort < uEndPort - 1)804 cchPrefix = RTStrPrintf(szName, sizeof(szName), "/IOM/NewPorts/%04x-%04x", uFirstPort, uEndPort - 1);805 else806 cchPrefix = RTStrPrintf(szName, sizeof(szName), "/IOM/NewPorts/%04x", uPort);807 int rc = STAMR3Register(pVM, &pRegEntry->idxSelf, STAMTYPE_U16, STAMVISIBILITY_ALWAYS, szName,808 STAMUNIT_NONE, pRegEntry->pszDesc);809 AssertRC(rc);810 811 812 /* Register stats for each port under it */813 do814 {815 size_t cchBaseNm;816 if (uFirstPort < uEndPort - 1)817 cchBaseNm = cchPrefix + RTStrPrintf(&szName[cchPrefix], sizeof(szName) - cchPrefix, "/%04x-", uPort);818 else819 {820 szName[cchPrefix] = '/';821 cchBaseNm = cchPrefix + 1;822 }823 824 # define SET_NM_SUFFIX(a_sz) memcpy(&szName[cchBaseNm], a_sz, sizeof(a_sz));825 const char * const pszInDesc = pExtDesc ? pExtDesc->pszIn : NULL;826 const char * const pszOutDesc = pExtDesc ? pExtDesc->pszOut : NULL;827 828 /* register the statistics counters. */829 SET_NM_SUFFIX("In-R3");830 rc = STAMR3Register(pVM, &pStats->InR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszInDesc); AssertRC(rc);831 SET_NM_SUFFIX("Out-R3");832 rc = STAMR3Register(pVM, &pStats->OutR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszOutDesc); AssertRC(rc);833 SET_NM_SUFFIX("In-RZ");834 rc = STAMR3Register(pVM, &pStats->InRZ, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszInDesc); AssertRC(rc);835 SET_NM_SUFFIX("Out-RZ");836 rc = STAMR3Register(pVM, &pStats->OutRZ, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszOutDesc); AssertRC(rc);837 SET_NM_SUFFIX("In-RZtoR3");838 rc = STAMR3Register(pVM, &pStats->InRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc);839 SET_NM_SUFFIX("Out-RZtoR3");840 rc = STAMR3Register(pVM, &pStats->OutRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc);841 842 /* Profiling */843 SET_NM_SUFFIX("In-R3-Prof");844 rc = STAMR3Register(pVM, &pStats->ProfInR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszInDesc); AssertRC(rc);845 SET_NM_SUFFIX("Out-R3-Prof");846 rc = STAMR3Register(pVM, &pStats->ProfOutR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszOutDesc); AssertRC(rc);847 SET_NM_SUFFIX("In-RZ-Prof");848 rc = STAMR3Register(pVM, &pStats->ProfInRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszInDesc); AssertRC(rc);849 SET_NM_SUFFIX("Out-RZ-Prof");850 rc = STAMR3Register(pVM, &pStats->ProfOutRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszOutDesc); AssertRC(rc);851 852 pStats++;853 uPort++;854 if (pExtDesc)855 pExtDesc = pszInDesc || pszOutDesc ? pExtDesc + 1 : NULL;856 } while (uPort < uEndPort);857 }858 859 860 /**861 * Deregister statistics for an I/O port entry.862 */863 static void iomR3IoPortDeregStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry, unsigned uPort)864 {865 char szPrefix[80];866 size_t cchPrefix;867 if (pRegEntry->cPorts > 1)868 cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x-%04x/", uPort, uPort + pRegEntry->cPorts - 1);869 else870 cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x/", uPort);871 STAMR3DeregisterByPrefix(pVM->pUVM, szPrefix);872 }873 874 #endif /* VBOX_WITH_STATISTICS */875 #ifdef VBOX_WITH_STATISTICS876 877 /**878 * Create the statistics node for an I/O port.879 *880 * @returns Pointer to new stats node.881 *882 * @param pVM The cross context VM structure.883 * @param Port Port.884 * @param pszDesc Description.885 */886 static PIOMIOPORTSTATS iomR3IOPortStatsCreate(PVM pVM, RTIOPORT Port, const char *pszDesc)887 {888 IOM_LOCK_EXCL(pVM);889 890 /* check if it already exists. */891 PIOMIOPORTSTATS pPort = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.pTreesR3->IOPortStatTree, Port);892 if (pPort)893 {894 IOM_UNLOCK_EXCL(pVM);895 return pPort;896 }897 898 /* allocate stats node. */899 int rc = MMHyperAlloc(pVM, sizeof(*pPort), 0, MM_TAG_IOM_STATS, (void **)&pPort);900 AssertRC(rc);901 if (RT_SUCCESS(rc))902 {903 /* insert into the tree. */904 pPort->Core.Key = Port;905 if (RTAvloIOPortInsert(&pVM->iom.s.pTreesR3->IOPortStatTree, &pPort->Core))906 {907 IOM_UNLOCK_EXCL(pVM);908 909 /* put a name on common ports. */910 if (!pszDesc)911 pszDesc = iomR3IOPortGetStandardName(Port);912 913 /* register the statistics counters. */914 rc = STAMR3RegisterF(pVM, &pPort->InR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/Ports/%04x-In-R3", Port); AssertRC(rc);915 rc = STAMR3RegisterF(pVM, &pPort->OutR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/Ports/%04x-Out-R3", Port); AssertRC(rc);916 rc = STAMR3RegisterF(pVM, &pPort->InRZ, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/Ports/%04x-In-RZ", Port); AssertRC(rc);917 rc = STAMR3RegisterF(pVM, &pPort->OutRZ, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/Ports/%04x-Out-RZ", Port); AssertRC(rc);918 rc = STAMR3RegisterF(pVM, &pPort->InRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/Ports/%04x-In-RZtoR3", Port); AssertRC(rc);919 rc = STAMR3RegisterF(pVM, &pPort->OutRZToR3,STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/Ports/%04x-Out-RZtoR3", Port); AssertRC(rc);920 921 /* Profiling */922 rc = STAMR3RegisterF(pVM, &pPort->ProfInR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc,"/IOM/Ports/%04x-In-R3/Prof", Port); AssertRC(rc);923 rc = STAMR3RegisterF(pVM, &pPort->ProfOutR3,STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc,"/IOM/Ports/%04x-Out-R3/Prof", Port); AssertRC(rc);924 rc = STAMR3RegisterF(pVM, &pPort->ProfInRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc,"/IOM/Ports/%04x-In-RZ/Prof", Port); AssertRC(rc);925 rc = STAMR3RegisterF(pVM, &pPort->ProfOutRZ,STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc,"/IOM/Ports/%04x-Out-RZ/Prof", Port); AssertRC(rc);926 927 return pPort;928 }929 930 AssertMsgFailed(("what! Port=%d\n", Port));931 MMHyperFree(pVM, pPort);932 }933 IOM_UNLOCK_EXCL(pVM);934 return NULL;935 }936 937 938 /**939 * Create the statistics node for an MMIO address.940 *941 * @returns Pointer to new stats node.942 *943 * @param pVM The cross context VM structure.944 * @param GCPhys The address.945 * @param pszDesc Description.946 */947 PIOMMMIOSTATS iomR3MMIOStatsCreate(PVM pVM, RTGCPHYS GCPhys, const char *pszDesc)948 {949 IOM_LOCK_EXCL(pVM);950 951 /* check if it already exists. */952 PIOMMMIOSTATS pStats = (PIOMMMIOSTATS)RTAvloGCPhysGet(&pVM->iom.s.pTreesR3->MmioStatTree, GCPhys);953 if (pStats)954 {955 IOM_UNLOCK_EXCL(pVM);956 return pStats;957 }958 959 /* allocate stats node. */960 int rc = MMHyperAlloc(pVM, sizeof(*pStats), 0, MM_TAG_IOM_STATS, (void **)&pStats);961 AssertRC(rc);962 if (RT_SUCCESS(rc))963 {964 /* insert into the tree. */965 pStats->Core.Key = GCPhys;966 if (RTAvloGCPhysInsert(&pVM->iom.s.pTreesR3->MmioStatTree, &pStats->Core))967 {968 IOM_UNLOCK_EXCL(pVM);969 970 rc = STAMR3RegisterF(pVM, &pStats->Accesses, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp", GCPhys); AssertRC(rc);971 rc = STAMR3RegisterF(pVM, &pStats->ProfReadR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Read-R3", GCPhys); AssertRC(rc);972 rc = STAMR3RegisterF(pVM, &pStats->ProfWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Write-R3", GCPhys); AssertRC(rc);973 rc = STAMR3RegisterF(pVM, &pStats->ProfReadRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Read-RZ", GCPhys); AssertRC(rc);974 rc = STAMR3RegisterF(pVM, &pStats->ProfWriteRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Write-RZ", GCPhys); AssertRC(rc);975 rc = STAMR3RegisterF(pVM, &pStats->ReadRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp/Read-RZtoR3", GCPhys); AssertRC(rc);976 rc = STAMR3RegisterF(pVM, &pStats->WriteRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp/Write-RZtoR3", GCPhys); AssertRC(rc);977 978 return pStats;979 }980 AssertMsgFailed(("what! GCPhys=%RGp\n", GCPhys));981 MMHyperFree(pVM, pStats);982 }983 IOM_UNLOCK_EXCL(pVM);984 return NULL;985 }986 987 #endif /* VBOX_WITH_STATISTICS */988 989 /**990 * Registers a I/O port ring-3 handler.991 *992 * This API is called by PDM on behalf of a device. Devices must first register993 * ring-3 ranges before any GC and R0 ranges can be registered using IOMR3IOPortRegisterRC()994 * and IOMR3IOPortRegisterR0().995 *996 *997 * @returns VBox status code.998 *999 * @param pVM The cross context VM structure.1000 * @param pDevIns PDM device instance owning the port range.1001 * @param PortStart First port number in the range.1002 * @param cPorts Number of ports to register.1003 * @param pvUser User argument for the callbacks.1004 * @param pfnOutCallback Pointer to function which is gonna handle OUT operations in R3.1005 * @param pfnInCallback Pointer to function which is gonna handle IN operations in R3.1006 * @param pfnOutStrCallback Pointer to function which is gonna handle string OUT operations in R3.1007 * @param pfnInStrCallback Pointer to function which is gonna handle string IN operations in R3.1008 * @param pszDesc Pointer to description string. This must not be freed.1009 */1010 VMMR3_INT_DECL(int) IOMR3IOPortRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTHCPTR pvUser,1011 R3PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, R3PTRTYPE(PFNIOMIOPORTIN) pfnInCallback,1012 R3PTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback, R3PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback, const char *pszDesc)1013 {1014 LogFlow(("IOMR3IOPortRegisterR3: pDevIns=%p PortStart=%#x cPorts=%#x pvUser=%RHv pfnOutCallback=%#x pfnInCallback=%#x pfnOutStrCallback=%#x pfnInStrCallback=%#x pszDesc=%s\n",1015 pDevIns, PortStart, cPorts, pvUser, pfnOutCallback, pfnInCallback, pfnOutStrCallback, pfnInStrCallback, pszDesc));1016 1017 /*1018 * Validate input.1019 */1020 if ( (RTUINT)PortStart + cPorts <= (RTUINT)PortStart1021 || (RTUINT)PortStart + cPorts > 0x10000)1022 {1023 AssertMsgFailed(("Invalid port range %#x-%#x (inclusive)! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));1024 return VERR_IOM_INVALID_IOPORT_RANGE;1025 }1026 if (!pfnOutCallback && !pfnInCallback)1027 {1028 AssertMsgFailed(("no handlers specfied for %#x-%#x (inclusive)! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));1029 return VERR_INVALID_PARAMETER;1030 }1031 if (!pfnOutCallback)1032 pfnOutCallback = iomR3IOPortDummyOut;1033 if (!pfnInCallback)1034 pfnInCallback = iomR3IOPortDummyIn;1035 if (!pfnOutStrCallback)1036 pfnOutStrCallback = iomR3IOPortDummyOutStr;1037 if (!pfnInStrCallback)1038 pfnInStrCallback = iomR3IOPortDummyInStr;1039 1040 /* Flush the IO port lookup cache */1041 iomR3FlushCache(pVM);1042 1043 /*1044 * Allocate new range record and initialize it.1045 */1046 PIOMIOPORTRANGER3 pRange;1047 int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);1048 if (RT_SUCCESS(rc))1049 {1050 pRange->Core.Key = PortStart;1051 pRange->Core.KeyLast = PortStart + (cPorts - 1);1052 pRange->Port = PortStart;1053 pRange->cPorts = cPorts;1054 pRange->pvUser = pvUser;1055 pRange->pDevIns = pDevIns;1056 pRange->pfnOutCallback = pfnOutCallback;1057 pRange->pfnInCallback = pfnInCallback;1058 pRange->pfnOutStrCallback = pfnOutStrCallback;1059 pRange->pfnInStrCallback = pfnInStrCallback;1060 pRange->pszDesc = pszDesc;1061 1062 /*1063 * Try Insert it.1064 */1065 IOM_LOCK_EXCL(pVM);1066 if (RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeR3, &pRange->Core))1067 {1068 #ifdef VBOX_WITH_STATISTICS1069 for (unsigned iPort = 0; iPort < cPorts; iPort++)1070 iomR3IOPortStatsCreate(pVM, PortStart + iPort, pszDesc);1071 #endif1072 IOM_UNLOCK_EXCL(pVM);1073 return VINF_SUCCESS;1074 }1075 IOM_UNLOCK_EXCL(pVM);1076 1077 /* conflict. */1078 DBGFR3Info(pVM->pUVM, "ioport", NULL, NULL);1079 AssertMsgFailed(("Port range %#x-%#x (%s) conflicts with existing range(s)!\n", PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));1080 MMHyperFree(pVM, pRange);1081 rc = VERR_IOM_IOPORT_RANGE_CONFLICT;1082 }1083 1084 return rc;1085 }1086 1087 1088 #if 01089 /**1090 * Registers a I/O port RC handler.1091 *1092 * This API is called by PDM on behalf of a device. Devices must first register ring-3 ranges1093 * using IOMIOPortRegisterR3() before calling this function.1094 *1095 *1096 * @returns VBox status code.1097 *1098 * @param pVM The cross context VM structure.1099 * @param pDevIns PDM device instance owning the port range.1100 * @param PortStart First port number in the range.1101 * @param cPorts Number of ports to register.1102 * @param pvUser User argument for the callbacks.1103 * @param pfnOutCallback Pointer to function which is gonna handle OUT operations in GC.1104 * @param pfnInCallback Pointer to function which is gonna handle IN operations in GC.1105 * @param pfnOutStrCallback Pointer to function which is gonna handle string OUT operations in GC.1106 * @param pfnInStrCallback Pointer to function which is gonna handle string IN operations in GC.1107 * @param pszDesc Pointer to description string. This must not be freed.1108 */1109 VMMR3_INT_DECL(int) IOMR3IOPortRegisterRC(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTRCPTR pvUser,1110 RCPTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, RCPTRTYPE(PFNIOMIOPORTIN) pfnInCallback,1111 RCPTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback, RCPTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback, const char *pszDesc)1112 {1113 LogFlow(("IOMR3IOPortRegisterRC: pDevIns=%p PortStart=%#x cPorts=%#x pvUser=%RRv pfnOutCallback=%RRv pfnInCallback=%RRv pfnOutStrCallback=%RRv pfnInStrCallback=%RRv pszDesc=%s\n",1114 pDevIns, PortStart, cPorts, pvUser, pfnOutCallback, pfnInCallback, pfnOutStrCallback, pfnInStrCallback, pszDesc));1115 AssertReturn(VM_IS_RAW_MODE_ENABLED(pVM), VERR_IOM_HM_IPE);1116 1117 /*1118 * Validate input.1119 */1120 if ( (RTUINT)PortStart + cPorts <= (RTUINT)PortStart1121 || (RTUINT)PortStart + cPorts > 0x10000)1122 {1123 AssertMsgFailed(("Invalid port range %#x-%#x! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));1124 return VERR_IOM_INVALID_IOPORT_RANGE;1125 }1126 RTIOPORT PortLast = PortStart + (cPorts - 1);1127 if (!pfnOutCallback && !pfnInCallback)1128 {1129 AssertMsgFailed(("Invalid port range %#x-%#x! No callbacks! (%s)\n", PortStart, PortLast, pszDesc));1130 return VERR_INVALID_PARAMETER;1131 }1132 1133 IOM_LOCK_EXCL(pVM);1134 1135 /*1136 * Validate that there are ring-3 ranges for the ports.1137 */1138 RTIOPORT Port = PortStart;1139 while (Port <= PortLast && Port >= PortStart)1140 {1141 PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR3, Port);1142 if (!pRange)1143 {1144 AssertMsgFailed(("No R3! Port=%#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));1145 IOM_UNLOCK_EXCL(pVM);1146 return VERR_IOM_NO_R3_IOPORT_RANGE;1147 }1148 #ifndef IOM_NO_PDMINS_CHECKS1149 if (pRange->pDevIns != pDevIns)1150 {1151 AssertMsgFailed(("Not owner! Port=%#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));1152 IOM_UNLOCK_EXCL(pVM);1153 return VERR_IOM_NOT_IOPORT_RANGE_OWNER;1154 }1155 #endif1156 Port = pRange->Core.KeyLast + 1;1157 }1158 1159 /* Flush the IO port lookup cache */1160 iomR3FlushCache(pVM);1161 1162 /*1163 * Allocate new range record and initialize it.1164 */1165 PIOMIOPORTRANGERC pRange;1166 int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);1167 if (RT_SUCCESS(rc))1168 {1169 pRange->Core.Key = PortStart;1170 pRange->Core.KeyLast = PortLast;1171 pRange->Port = PortStart;1172 pRange->cPorts = cPorts;1173 pRange->pvUser = pvUser;1174 pRange->pfnOutCallback = pfnOutCallback;1175 pRange->pfnInCallback = pfnInCallback;1176 pRange->pfnOutStrCallback = pfnOutStrCallback;1177 pRange->pfnInStrCallback = pfnInStrCallback;1178 pRange->pDevIns = pDevIns->pDevInsForRC;1179 pRange->pszDesc = pszDesc;1180 1181 /*1182 * Insert it.1183 */1184 if (RTAvlroIOPortInsert(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeRC, &pRange->Core))1185 {1186 IOM_UNLOCK_EXCL(pVM);1187 return VINF_SUCCESS;1188 }1189 1190 /* conflict. */1191 AssertMsgFailed(("Port range %#x-%#x (%s) conflicts with existing range(s)!\n", PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));1192 MMHyperFree(pVM, pRange);1193 rc = VERR_IOM_IOPORT_RANGE_CONFLICT;1194 }1195 IOM_UNLOCK_EXCL(pVM);1196 return rc;1197 }1198 #endif1199 1200 1201 /**1202 * Registers a Port IO R0 handler.1203 *1204 * This API is called by PDM on behalf of a device. Devices must first register ring-3 ranges1205 * using IOMR3IOPortRegisterR3() before calling this function.1206 *1207 *1208 * @returns VBox status code.1209 *1210 * @param pVM The cross context VM structure.1211 * @param pDevIns PDM device instance owning the port range.1212 * @param PortStart First port number in the range.1213 * @param cPorts Number of ports to register.1214 * @param pvUser User argument for the callbacks.1215 * @param pfnOutCallback Pointer to function which is gonna handle OUT operations in GC.1216 * @param pfnInCallback Pointer to function which is gonna handle IN operations in GC.1217 * @param pfnOutStrCallback Pointer to function which is gonna handle OUT operations in GC.1218 * @param pfnInStrCallback Pointer to function which is gonna handle IN operations in GC.1219 * @param pszDesc Pointer to description string. This must not be freed.1220 */1221 VMMR3_INT_DECL(int) IOMR3IOPortRegisterR0(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTR0PTR pvUser,1222 R0PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, R0PTRTYPE(PFNIOMIOPORTIN) pfnInCallback,1223 R0PTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback, R0PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback,1224 const char *pszDesc)1225 {1226 LogFlow(("IOMR3IOPortRegisterR0: pDevIns=%p PortStart=%#x cPorts=%#x pvUser=%RHv pfnOutCallback=%RHv pfnInCallback=%RHv pfnOutStrCallback=%RHv pfnInStrCallback=%RHv pszDesc=%s\n",1227 pDevIns, PortStart, cPorts, pvUser, pfnOutCallback, pfnInCallback, pfnOutStrCallback, pfnInStrCallback, pszDesc));1228 1229 /*1230 * Validate input.1231 */1232 if ( (RTUINT)PortStart + cPorts <= (RTUINT)PortStart1233 || (RTUINT)PortStart + cPorts > 0x10000)1234 {1235 AssertMsgFailed(("Invalid port range %#x-%#x! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));1236 return VERR_IOM_INVALID_IOPORT_RANGE;1237 }1238 RTIOPORT PortLast = PortStart + (cPorts - 1);1239 if (!pfnOutCallback && !pfnInCallback)1240 {1241 AssertMsgFailed(("Invalid port range %#x-%#x! No callbacks! (%s)\n", PortStart, PortLast, pszDesc));1242 return VERR_INVALID_PARAMETER;1243 }1244 1245 IOM_LOCK_EXCL(pVM);1246 1247 /*1248 * Validate that there are ring-3 ranges for the ports.1249 */1250 RTIOPORT Port = PortStart;1251 while (Port <= PortLast && Port >= PortStart)1252 {1253 PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR3, Port);1254 if (!pRange)1255 {1256 AssertMsgFailed(("No R3! Port=%#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));1257 IOM_UNLOCK_EXCL(pVM);1258 return VERR_IOM_NO_R3_IOPORT_RANGE;1259 }1260 #ifndef IOM_NO_PDMINS_CHECKS1261 if (pRange->pDevIns != pDevIns)1262 {1263 AssertMsgFailed(("Not owner! Port=%#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));1264 IOM_UNLOCK_EXCL(pVM);1265 return VERR_IOM_NOT_IOPORT_RANGE_OWNER;1266 }1267 #endif1268 Port = pRange->Core.KeyLast + 1;1269 }1270 1271 /* Flush the IO port lookup cache */1272 iomR3FlushCache(pVM);1273 1274 /*1275 * Allocate new range record and initialize it.1276 */1277 PIOMIOPORTRANGER0 pRange;1278 int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);1279 if (RT_SUCCESS(rc))1280 {1281 pRange->Core.Key = PortStart;1282 pRange->Core.KeyLast = PortLast;1283 pRange->Port = PortStart;1284 pRange->cPorts = cPorts;1285 pRange->pvUser = pvUser;1286 pRange->pfnOutCallback = pfnOutCallback;1287 pRange->pfnInCallback = pfnInCallback;1288 pRange->pfnOutStrCallback = pfnOutStrCallback;1289 pRange->pfnInStrCallback = pfnInStrCallback;1290 pRange->pDevIns = PDMDEVINS_2_R0PTR(pDevIns);1291 pRange->pszDesc = pszDesc;1292 1293 /*1294 * Insert it.1295 */1296 if (RTAvlroIOPortInsert(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR0, &pRange->Core))1297 {1298 IOM_UNLOCK_EXCL(pVM);1299 return VINF_SUCCESS;1300 }1301 1302 /* conflict. */1303 AssertMsgFailed(("Port range %#x-%#x (%s) conflicts with existing range(s)!\n", PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));1304 MMHyperFree(pVM, pRange);1305 rc = VERR_IOM_IOPORT_RANGE_CONFLICT;1306 }1307 IOM_UNLOCK_EXCL(pVM);1308 return rc;1309 }1310 1311 1312 /**1313 * Deregisters a I/O Port range.1314 *1315 * The specified range must be registered using IOMR3IOPortRegister previous to1316 * this call. The range does can be a smaller part of the range specified to1317 * IOMR3IOPortRegister, but it can never be larger.1318 *1319 * This function will remove GC, R0 and R3 context port handlers for this range.1320 *1321 * @returns VBox status code.1322 *1323 * @param pVM The cross context VM structure.1324 * @param pDevIns The device instance associated with the range.1325 * @param PortStart First port number in the range.1326 * @param cPorts Number of ports to remove starting at PortStart.1327 *1328 * @remark This function mainly for PCI PnP Config and will not do1329 * all the checks you might expect it to do.1330 */1331 VMMR3_INT_DECL(int) IOMR3IOPortDeregister(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts)1332 {1333 LogFlow(("IOMR3IOPortDeregister: pDevIns=%p PortStart=%#x cPorts=%#x\n", pDevIns, PortStart, cPorts));1334 1335 /*1336 * Validate input.1337 */1338 if ( (RTUINT)PortStart + cPorts < (RTUINT)PortStart1339 || (RTUINT)PortStart + cPorts > 0x10000)1340 {1341 AssertMsgFailed(("Invalid port range %#x-%#x!\n", PortStart, (unsigned)PortStart + cPorts - 1));1342 return VERR_IOM_INVALID_IOPORT_RANGE;1343 }1344 1345 IOM_LOCK_EXCL(pVM);1346 1347 /* Flush the IO port lookup cache */1348 iomR3FlushCache(pVM);1349 1350 /*1351 * Check ownership.1352 */1353 RTIOPORT PortLast = PortStart + (cPorts - 1);1354 RTIOPORT Port = PortStart;1355 while (Port <= PortLast && Port >= PortStart)1356 {1357 PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeR3, Port);1358 if (pRange)1359 {1360 Assert(Port <= pRange->Core.KeyLast);1361 #ifndef IOM_NO_PDMINS_CHECKS1362 if (pRange->pDevIns != pDevIns)1363 {1364 AssertMsgFailed(("Removal of ports in range %#x-%#x rejected because not owner of %#x-%#x (%s)\n",1365 PortStart, PortLast, pRange->Core.Key, pRange->Core.KeyLast, pRange->pszDesc));1366 IOM_UNLOCK_EXCL(pVM);1367 return VERR_IOM_NOT_IOPORT_RANGE_OWNER;1368 }1369 #else /* IOM_NO_PDMINS_CHECKS */1370 RT_NOREF_PV(pDevIns);1371 #endif /* IOM_NO_PDMINS_CHECKS */1372 Port = pRange->Core.KeyLast;1373 }1374 Port++;1375 }1376 1377 #if 01378 /*1379 * Remove any RC ranges first.1380 */1381 int rc = VINF_SUCCESS;1382 Port = PortStart;1383 while (Port <= PortLast && Port >= PortStart)1384 {1385 /*1386 * Try find range.1387 */1388 PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeRC, Port);1389 if (pRange)1390 {1391 if ( pRange->Core.Key == Port1392 && pRange->Core.KeyLast <= PortLast)1393 {1394 /*1395 * Kick out the entire range.1396 */1397 void *pv = RTAvlroIOPortRemove(&pVM->iom.s.pTreesR3->IOPortTreeRC, Port);1398 Assert(pv == (void *)pRange); NOREF(pv);1399 Port += pRange->cPorts;1400 MMHyperFree(pVM, pRange);1401 }1402 else if (pRange->Core.Key == Port)1403 {1404 /*1405 * Cut of the head of the range, done.1406 */1407 pRange->cPorts -= Port - pRange->Port;1408 pRange->Core.Key = Port;1409 pRange->Port = Port;1410 break;1411 }1412 else if (pRange->Core.KeyLast <= PortLast)1413 {1414 /*1415 * Just cut of the tail.1416 */1417 unsigned c = pRange->Core.KeyLast - Port + 1;1418 pRange->Core.KeyLast -= c;1419 pRange->cPorts -= c;1420 Port += c;1421 }1422 else1423 {1424 /*1425 * Split the range, done.1426 */1427 Assert(pRange->Core.KeyLast > PortLast && pRange->Core.Key < Port);1428 /* create tail. */1429 PIOMIOPORTRANGERC pRangeNew;1430 int rc2 = MMHyperAlloc(pVM, sizeof(*pRangeNew), 0, MM_TAG_IOM, (void **)&pRangeNew);1431 if (RT_FAILURE(rc2))1432 {1433 IOM_UNLOCK_EXCL(pVM);1434 return rc2;1435 }1436 *pRangeNew = *pRange;1437 pRangeNew->Core.Key = PortLast;1438 pRangeNew->Port = PortLast;1439 pRangeNew->cPorts = pRangeNew->Core.KeyLast - PortLast + 1;1440 1441 LogFlow(("IOMR3IOPortDeregister (rc): split the range; new %x\n", pRangeNew->Core.Key));1442 1443 /* adjust head */1444 pRange->Core.KeyLast = Port - 1;1445 pRange->cPorts = Port - pRange->Port;1446 1447 /* insert */1448 if (!RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeRC, &pRangeNew->Core))1449 {1450 AssertMsgFailed(("This cannot happen!\n"));1451 MMHyperFree(pVM, pRangeNew);1452 rc = VERR_IOM_IOPORT_IPE_1;1453 }1454 break;1455 }1456 }1457 else /* next port */1458 Port++;1459 } /* for all ports - RC. */1460 #else1461 int rc = VINF_SUCCESS;1462 #endif1463 1464 /*1465 * Remove any R0 ranges.1466 */1467 Port = PortStart;1468 while (Port <= PortLast && Port >= PortStart)1469 {1470 /*1471 * Try find range.1472 */1473 PIOMIOPORTRANGER0 pRange = (PIOMIOPORTRANGER0)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeR0, Port);1474 if (pRange)1475 {1476 if ( pRange->Core.Key == Port1477 && pRange->Core.KeyLast <= PortLast)1478 {1479 /*1480 * Kick out the entire range.1481 */1482 void *pv = RTAvlroIOPortRemove(&pVM->iom.s.pTreesR3->IOPortTreeR0, Port);1483 Assert(pv == (void *)pRange); NOREF(pv);1484 Port += pRange->cPorts;1485 MMHyperFree(pVM, pRange);1486 }1487 else if (pRange->Core.Key == Port)1488 {1489 /*1490 * Cut of the head of the range, done.1491 */1492 pRange->cPorts -= Port - pRange->Port;1493 pRange->Core.Key = Port;1494 pRange->Port = Port;1495 break;1496 }1497 else if (pRange->Core.KeyLast <= PortLast)1498 {1499 /*1500 * Just cut of the tail.1501 */1502 unsigned c = pRange->Core.KeyLast - Port + 1;1503 pRange->Core.KeyLast -= c;1504 pRange->cPorts -= c;1505 Port += c;1506 }1507 else1508 {1509 /*1510 * Split the range, done.1511 */1512 Assert(pRange->Core.KeyLast > PortLast && pRange->Core.Key < Port);1513 /* create tail. */1514 PIOMIOPORTRANGER0 pRangeNew;1515 int rc2 = MMHyperAlloc(pVM, sizeof(*pRangeNew), 0, MM_TAG_IOM, (void **)&pRangeNew);1516 if (RT_FAILURE(rc2))1517 {1518 IOM_UNLOCK_EXCL(pVM);1519 return rc2;1520 }1521 *pRangeNew = *pRange;1522 pRangeNew->Core.Key = PortLast;1523 pRangeNew->Port = PortLast;1524 pRangeNew->cPorts = pRangeNew->Core.KeyLast - PortLast + 1;1525 1526 LogFlow(("IOMR3IOPortDeregister (r0): split the range; new %x\n", pRangeNew->Core.Key));1527 1528 /* adjust head */1529 pRange->Core.KeyLast = Port - 1;1530 pRange->cPorts = Port - pRange->Port;1531 1532 /* insert */1533 if (!RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeR0, &pRangeNew->Core))1534 {1535 AssertMsgFailed(("This cannot happen!\n"));1536 MMHyperFree(pVM, pRangeNew);1537 rc = VERR_IOM_IOPORT_IPE_1;1538 }1539 break;1540 }1541 }1542 else /* next port */1543 Port++;1544 } /* for all ports - R0. */1545 1546 /*1547 * And the same procedure for ring-3 ranges.1548 */1549 Port = PortStart;1550 while (Port <= PortLast && Port >= PortStart)1551 {1552 /*1553 * Try find range.1554 */1555 PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeR3, Port);1556 if (pRange)1557 {1558 if ( pRange->Core.Key == Port1559 && pRange->Core.KeyLast <= PortLast)1560 {1561 /*1562 * Kick out the entire range.1563 */1564 void *pv = RTAvlroIOPortRemove(&pVM->iom.s.pTreesR3->IOPortTreeR3, Port);1565 Assert(pv == (void *)pRange); NOREF(pv);1566 Port += pRange->cPorts;1567 MMHyperFree(pVM, pRange);1568 }1569 else if (pRange->Core.Key == Port)1570 {1571 /*1572 * Cut of the head of the range, done.1573 */1574 pRange->cPorts -= Port - pRange->Port;1575 pRange->Core.Key = Port;1576 pRange->Port = Port;1577 break;1578 }1579 else if (pRange->Core.KeyLast <= PortLast)1580 {1581 /*1582 * Just cut of the tail.1583 */1584 unsigned c = pRange->Core.KeyLast - Port + 1;1585 pRange->Core.KeyLast -= c;1586 pRange->cPorts -= c;1587 Port += c;1588 }1589 else1590 {1591 /*1592 * Split the range, done.1593 */1594 Assert(pRange->Core.KeyLast > PortLast && pRange->Core.Key < Port);1595 /* create tail. */1596 PIOMIOPORTRANGER3 pRangeNew;1597 int rc2 = MMHyperAlloc(pVM, sizeof(*pRangeNew), 0, MM_TAG_IOM, (void **)&pRangeNew);1598 if (RT_FAILURE(rc2))1599 {1600 IOM_UNLOCK_EXCL(pVM);1601 return rc2;1602 }1603 *pRangeNew = *pRange;1604 pRangeNew->Core.Key = PortLast;1605 pRangeNew->Port = PortLast;1606 pRangeNew->cPorts = pRangeNew->Core.KeyLast - PortLast + 1;1607 1608 LogFlow(("IOMR3IOPortDeregister (r3): split the range; new %x\n", pRangeNew->Core.Key));1609 1610 /* adjust head */1611 pRange->Core.KeyLast = Port - 1;1612 pRange->cPorts = Port - pRange->Port;1613 1614 /* insert */1615 if (!RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeR3, &pRangeNew->Core))1616 {1617 AssertMsgFailed(("This cannot happen!\n"));1618 MMHyperFree(pVM, pRangeNew);1619 rc = VERR_IOM_IOPORT_IPE_1;1620 }1621 break;1622 }1623 }1624 else /* next port */1625 Port++;1626 } /* for all ports - ring-3. */1627 1628 /* done */1629 IOM_UNLOCK_EXCL(pVM);1630 return rc;1631 }1632 1633 1634 /**1635 * Dummy Port I/O Handler for IN operations.1636 *1637 * @returns VBox status code.1638 *1639 * @param pDevIns The device instance.1640 * @param pvUser User argument.1641 * @param Port Port number used for the IN operation.1642 * @param pu32 Where to store the result.1643 * @param cb Number of bytes read.1644 */1645 static DECLCALLBACK(int) iomR3IOPortDummyIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)1646 {1647 NOREF(pDevIns); NOREF(pvUser); NOREF(Port);1648 switch (cb)1649 {1650 case 1: *pu32 = 0xff; break;1651 case 2: *pu32 = 0xffff; break;1652 case 4: *pu32 = UINT32_C(0xffffffff); break;1653 default:1654 AssertReleaseMsgFailed(("cb=%d\n", cb));1655 return VERR_IOM_IOPORT_IPE_2;1656 }1657 return VINF_SUCCESS;1658 }1659 1660 1661 /**1662 * @callback_method_impl{FNIOMIOPORTINSTRING,1663 * Dummy Port I/O Handler for string IN operations.}1664 */1665 static DECLCALLBACK(int) iomR3IOPortDummyInStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t *pbDst,1666 uint32_t *pcTransfer, unsigned cb)1667 {1668 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbDst); NOREF(pcTransfer); NOREF(cb);1669 return VINF_SUCCESS;1670 }1671 1672 1673 /**1674 * Dummy Port I/O Handler for OUT operations.1675 *1676 * @returns VBox status code.1677 *1678 * @param pDevIns The device instance.1679 * @param pvUser User argument.1680 * @param Port Port number used for the OUT operation.1681 * @param u32 The value to output.1682 * @param cb The value size in bytes.1683 */1684 static DECLCALLBACK(int) iomR3IOPortDummyOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)1685 {1686 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(u32); NOREF(cb);1687 return VINF_SUCCESS;1688 }1689 1690 1691 /**1692 * @callback_method_impl{FNIOMIOPORTOUTSTRING,1693 * Dummy Port I/O Handler for string OUT operations.}1694 */1695 static DECLCALLBACK(int) iomR3IOPortDummyOutStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t const *pbSrc,1696 uint32_t *pcTransfer, unsigned cb)1697 {1698 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbSrc); NOREF(pcTransfer); NOREF(cb);1699 return VINF_SUCCESS;1700 }1701 1702 1703 /**1704 * @callback_method_impl{FNIOMIOPORTNEWIN,1705 * Dummy Port I/O Handler for IN operations.}1706 */1707 static DECLCALLBACK(VBOXSTRICTRC)1708 iomR3IOPortDummyNewIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)1709 {1710 NOREF(pDevIns); NOREF(pvUser); NOREF(Port);1711 switch (cb)1712 {1713 case 1: *pu32 = 0xff; break;1714 case 2: *pu32 = 0xffff; break;1715 case 4: *pu32 = UINT32_C(0xffffffff); break;1716 default:1717 AssertReleaseMsgFailed(("cb=%d\n", cb));1718 return VERR_IOM_IOPORT_IPE_2;1719 }1720 return VINF_SUCCESS;1721 }1722 1723 1724 /**1725 * @callback_method_impl{FNIOMIOPORTNEWINSTRING,1726 * Dummy Port I/O Handler for string IN operations.}1727 */1728 static DECLCALLBACK(VBOXSTRICTRC)1729 iomR3IOPortDummyNewInStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t *pbDst, uint32_t *pcTransfer, unsigned cb)1730 {1731 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbDst); NOREF(pcTransfer); NOREF(cb);1732 return VINF_SUCCESS;1733 }1734 1735 1736 /**1737 * @callback_method_impl{FNIOMIOPORTNEWOUT,1738 * Dummy Port I/O Handler for OUT operations.}1739 */1740 static DECLCALLBACK(VBOXSTRICTRC)1741 iomR3IOPortDummyNewOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)1742 {1743 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(u32); NOREF(cb);1744 return VINF_SUCCESS;1745 }1746 1747 1748 /**1749 * @callback_method_impl{FNIOMIOPORTNEWOUTSTRING,1750 * Dummy Port I/O Handler for string OUT operations.}1751 */1752 static DECLCALLBACK(VBOXSTRICTRC)1753 iomR3IOPortDummyNewOutStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t const *pbSrc, uint32_t *pcTransfer, unsigned cb)1754 {1755 NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbSrc); NOREF(pcTransfer); NOREF(cb);1756 return VINF_SUCCESS;1757 }1758 1759 527 1760 528 /** … … 1782 550 1783 551 1784 #if 01785 /**1786 * Display a single I/O port GC range.1787 *1788 * @returns 01789 * @param pNode Pointer to IOPORT GC range.1790 * @param pvUser Pointer to info output callback structure.1791 */1792 static DECLCALLBACK(int) iomR3IOPortInfoOneRC(PAVLROIOPORTNODECORE pNode, void *pvUser)1793 {1794 PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)pNode;1795 PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;1796 pHlp->pfnPrintf(pHlp,1797 "%04x-%04x %RRv %RRv %RRv %RRv %s\n",1798 pRange->Core.Key,1799 pRange->Core.KeyLast,1800 pRange->pDevIns,1801 pRange->pfnInCallback,1802 pRange->pfnOutCallback,1803 pRange->pvUser,1804 pRange->pszDesc);1805 return 0;1806 }1807 #endif1808 1809 1810 552 /** 1811 553 * Display all registered I/O port ranges. … … 1815 557 * @param pszArgs Arguments, ignored. 1816 558 */ 1817 static DECLCALLBACK(void) iomR3IOPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)559 DECLCALLBACK(void) iomR3IoPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs) 1818 560 { 1819 561 /* No locking needed here as registerations are only happening during VMSTATE_CREATING. */ … … 1869 611 } 1870 612 1871 1872 /**1873 * Registers a Memory Mapped I/O R3 handler.1874 *1875 * This API is called by PDM on behalf of a device. Devices must register ring-3 ranges1876 * before any GC and R0 ranges can be registered using IOMR3MMIORegisterRC() and IOMR3MMIORegisterR0().1877 *1878 * @returns VBox status code.1879 *1880 * @param pVM The cross context VM structure.1881 * @param pDevIns PDM device instance owning the MMIO range.1882 * @param GCPhysStart First physical address in the range.1883 * @param cbRange The size of the range (in bytes).1884 * @param pvUser User argument for the callbacks.1885 * @param pfnWriteCallback Pointer to function which is gonna handle Write operations.1886 * @param pfnReadCallback Pointer to function which is gonna handle Read operations.1887 * @param pfnFillCallback Pointer to function which is gonna handle Fill/memset operations.1888 * @param fFlags Flags, see IOMMMIO_FLAGS_XXX.1889 * @param pszDesc Pointer to description string. This must not be freed.1890 */1891 VMMR3_INT_DECL(int)1892 IOMR3MmioRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange, RTHCPTR pvUser,1893 R3PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback, R3PTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,1894 R3PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback, uint32_t fFlags, const char *pszDesc)1895 {1896 LogFlow(("IOMR3MmioRegisterR3: pDevIns=%p GCPhysStart=%RGp cbRange=%RGp pvUser=%RHv pfnWriteCallback=%#x pfnReadCallback=%#x pfnFillCallback=%#x fFlags=%#x pszDesc=%s\n",1897 pDevIns, GCPhysStart, cbRange, pvUser, pfnWriteCallback, pfnReadCallback, pfnFillCallback, fFlags, pszDesc));1898 int rc;1899 1900 /*1901 * Validate input.1902 */1903 AssertMsgReturn(GCPhysStart + (cbRange - 1) >= GCPhysStart,("Wrapped! %RGp LB %RGp\n", GCPhysStart, cbRange),1904 VERR_IOM_INVALID_MMIO_RANGE);1905 AssertMsgReturn( !(fFlags & ~IOMMMIO_FLAGS_VALID_MASK)1906 && (fFlags & IOMMMIO_FLAGS_READ_MODE) <= IOMMMIO_FLAGS_READ_DWORD_QWORD1907 && (fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD,1908 ("%#x\n", fFlags),1909 VERR_INVALID_PARAMETER);1910 1911 /*1912 * Allocate new range record and initialize it.1913 */1914 PIOMMMIORANGE pRange;1915 rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);1916 if (RT_SUCCESS(rc))1917 {1918 pRange->Core.Key = GCPhysStart;1919 pRange->Core.KeyLast = GCPhysStart + (cbRange - 1);1920 pRange->GCPhys = GCPhysStart;1921 pRange->cb = cbRange;1922 pRange->cRefs = 1; /* The tree reference. */1923 pRange->pszDesc = pszDesc;1924 1925 //pRange->pvUserR0 = NIL_RTR0PTR;1926 //pRange->pDevInsR0 = NIL_RTR0PTR;1927 //pRange->pfnReadCallbackR0 = NIL_RTR0PTR;1928 //pRange->pfnWriteCallbackR0 = NIL_RTR0PTR;1929 //pRange->pfnFillCallbackR0 = NIL_RTR0PTR;1930 1931 //pRange->pvUserRC = NIL_RTRCPTR;1932 //pRange->pDevInsRC = NIL_RTRCPTR;1933 //pRange->pfnReadCallbackRC = NIL_RTRCPTR;1934 //pRange->pfnWriteCallbackRC = NIL_RTRCPTR;1935 //pRange->pfnFillCallbackRC = NIL_RTRCPTR;1936 1937 pRange->fFlags = fFlags;1938 1939 pRange->pvUserR3 = pvUser;1940 pRange->pDevInsR3 = pDevIns;1941 pRange->pfnReadCallbackR3 = pfnReadCallback;1942 pRange->pfnWriteCallbackR3 = pfnWriteCallback;1943 pRange->pfnFillCallbackR3 = pfnFillCallback;1944 1945 /*1946 * Try register it with PGM and then insert it into the tree.1947 */1948 rc = PGMR3PhysMMIORegister(pVM, GCPhysStart, cbRange, pVM->iom.s.hMmioHandlerType,1949 pRange, MMHyperR3ToR0(pVM, pRange), MMHyperR3ToRC(pVM, pRange), pszDesc);1950 if (RT_SUCCESS(rc))1951 {1952 IOM_LOCK_EXCL(pVM);1953 if (RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRange->Core))1954 {1955 iomR3FlushCache(pVM);1956 IOM_UNLOCK_EXCL(pVM);1957 return VINF_SUCCESS;1958 }1959 1960 /* bail out */1961 IOM_UNLOCK_EXCL(pVM);1962 DBGFR3Info(pVM->pUVM, "mmio", NULL, NULL);1963 AssertMsgFailed(("This cannot happen!\n"));1964 rc = VERR_IOM_IOPORT_IPE_3;1965 }1966 1967 MMHyperFree(pVM, pRange);1968 }1969 if (pDevIns->iInstance > 0)1970 MMR3HeapFree((void *)pszDesc);1971 return rc;1972 }1973 1974 1975 #if 01976 /**1977 * Registers a Memory Mapped I/O RC handler range.1978 *1979 * This API is called by PDM on behalf of a device. Devices must first register ring-3 ranges1980 * using IOMMMIORegisterR3() before calling this function.1981 *1982 *1983 * @returns VBox status code.1984 *1985 * @param pVM The cross context VM structure.1986 * @param pDevIns PDM device instance owning the MMIO range.1987 * @param GCPhysStart First physical address in the range.1988 * @param cbRange The size of the range (in bytes).1989 * @param pvUser User argument for the callbacks.1990 * @param pfnWriteCallback Pointer to function which is gonna handle Write operations.1991 * @param pfnReadCallback Pointer to function which is gonna handle Read operations.1992 * @param pfnFillCallback Pointer to function which is gonna handle Fill/memset operations.1993 * @thread EMT1994 */1995 VMMR3_INT_DECL(int)1996 IOMR3MmioRegisterRC(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange, RTGCPTR pvUser,1997 RCPTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback, RCPTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,1998 RCPTRTYPE(PFNIOMMMIOFILL) pfnFillCallback)1999 {2000 LogFlow(("IOMR3MmioRegisterRC: pDevIns=%p GCPhysStart=%RGp cbRange=%RGp pvUser=%RGv pfnWriteCallback=%#x pfnReadCallback=%#x pfnFillCallback=%#x\n",2001 pDevIns, GCPhysStart, cbRange, pvUser, pfnWriteCallback, pfnReadCallback, pfnFillCallback));2002 AssertReturn(VM_IS_RAW_MODE_ENABLED(pVM), VERR_IOM_HM_IPE);2003 2004 /*2005 * Validate input.2006 */2007 if (!pfnWriteCallback && !pfnReadCallback)2008 {2009 AssertMsgFailed(("No callbacks! %RGp LB %RGp\n", GCPhysStart, cbRange));2010 return VERR_INVALID_PARAMETER;2011 }2012 PVMCPU pVCpu = VMMGetCpu(pVM); Assert(pVCpu);2013 2014 /*2015 * Find the MMIO range and check that the input matches.2016 */2017 IOM_LOCK_EXCL(pVM);2018 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhysStart);2019 AssertReturnStmt(pRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);2020 AssertReturnStmt(pRange->pDevInsR3 == pDevIns, IOM_UNLOCK_EXCL(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);2021 AssertReturnStmt(pRange->GCPhys == GCPhysStart, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);2022 AssertReturnStmt(pRange->cb == cbRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);2023 2024 pRange->pvUserRC = pvUser;2025 pRange->pfnReadCallbackRC = pfnReadCallback;2026 pRange->pfnWriteCallbackRC= pfnWriteCallback;2027 pRange->pfnFillCallbackRC = pfnFillCallback;2028 pRange->pDevInsRC = pDevIns->pDevInsForRC;2029 IOM_UNLOCK_EXCL(pVM);2030 2031 return VINF_SUCCESS;2032 }2033 #endif2034 2035 2036 /**2037 * Registers a Memory Mapped I/O R0 handler range.2038 *2039 * This API is called by PDM on behalf of a device. Devices must first register ring-3 ranges2040 * using IOMMR3MIORegisterHC() before calling this function.2041 *2042 *2043 * @returns VBox status code.2044 *2045 * @param pVM The cross context VM structure.2046 * @param pDevIns PDM device instance owning the MMIO range.2047 * @param GCPhysStart First physical address in the range.2048 * @param cbRange The size of the range (in bytes).2049 * @param pvUser User argument for the callbacks.2050 * @param pfnWriteCallback Pointer to function which is gonna handle Write operations.2051 * @param pfnReadCallback Pointer to function which is gonna handle Read operations.2052 * @param pfnFillCallback Pointer to function which is gonna handle Fill/memset operations.2053 * @thread EMT2054 */2055 VMMR3_INT_DECL(int)2056 IOMR3MmioRegisterR0(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange, RTR0PTR pvUser,2057 R0PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback,2058 R0PTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,2059 R0PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback)2060 {2061 LogFlow(("IOMR3MmioRegisterR0: pDevIns=%p GCPhysStart=%RGp cbRange=%RGp pvUser=%RHv pfnWriteCallback=%#x pfnReadCallback=%#x pfnFillCallback=%#x\n",2062 pDevIns, GCPhysStart, cbRange, pvUser, pfnWriteCallback, pfnReadCallback, pfnFillCallback));2063 2064 /*2065 * Validate input.2066 */2067 if (!pfnWriteCallback && !pfnReadCallback)2068 {2069 AssertMsgFailed(("No callbacks! %RGp LB %RGp\n", GCPhysStart, cbRange));2070 return VERR_INVALID_PARAMETER;2071 }2072 PVMCPU pVCpu = VMMGetCpu(pVM); Assert(pVCpu);2073 2074 /*2075 * Find the MMIO range and check that the input matches.2076 */2077 IOM_LOCK_EXCL(pVM);2078 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhysStart);2079 AssertReturnStmt(pRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);2080 AssertReturnStmt(pRange->pDevInsR3 == pDevIns, IOM_UNLOCK_EXCL(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);2081 AssertReturnStmt(pRange->GCPhys == GCPhysStart, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);2082 AssertReturnStmt(pRange->cb == cbRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);2083 2084 pRange->pvUserR0 = pvUser;2085 pRange->pfnReadCallbackR0 = pfnReadCallback;2086 pRange->pfnWriteCallbackR0= pfnWriteCallback;2087 pRange->pfnFillCallbackR0 = pfnFillCallback;2088 pRange->pDevInsR0 = pDevIns->pDevInsR0RemoveMe;2089 IOM_UNLOCK_EXCL(pVM);2090 2091 return VINF_SUCCESS;2092 }2093 2094 2095 /**2096 * Deregisters a Memory Mapped I/O handler range.2097 *2098 * Registered GC, R0, and R3 ranges are affected.2099 *2100 * @returns VBox status code.2101 *2102 * @param pVM The cross context VM structure.2103 * @param pDevIns Device instance which the MMIO region is registered.2104 * @param GCPhysStart First physical address (GC) in the range.2105 * @param cbRange Number of bytes to deregister.2106 *2107 * @remark This function mainly for PCI PnP Config and will not do2108 * all the checks you might expect it to do.2109 */2110 VMMR3_INT_DECL(int) IOMR3MmioDeregister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange)2111 {2112 LogFlow(("IOMR3MmioDeregister: pDevIns=%p GCPhysStart=%RGp cbRange=%RGp\n", pDevIns, GCPhysStart, cbRange));2113 2114 /*2115 * Validate input.2116 */2117 RTGCPHYS GCPhysLast = GCPhysStart + (cbRange - 1);2118 if (GCPhysLast < GCPhysStart)2119 {2120 AssertMsgFailed(("Wrapped! %#x LB %RGp\n", GCPhysStart, cbRange));2121 return VERR_IOM_INVALID_MMIO_RANGE;2122 }2123 PVMCPU pVCpu = VMMGetCpu(pVM); Assert(pVCpu);2124 2125 IOM_LOCK_EXCL(pVM);2126 2127 /*2128 * Check ownership and such for the entire area.2129 */2130 RTGCPHYS GCPhys = GCPhysStart;2131 while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)2132 {2133 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhys);2134 if (!pRange)2135 {2136 IOM_UNLOCK_EXCL(pVM);2137 return VERR_IOM_MMIO_RANGE_NOT_FOUND;2138 }2139 AssertMsgReturnStmt(pRange->pDevInsR3 == pDevIns,2140 ("Not owner! GCPhys=%RGp %RGp LB %RGp %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),2141 IOM_UNLOCK_EXCL(pVM),2142 VERR_IOM_NOT_MMIO_RANGE_OWNER);2143 AssertMsgReturnStmt(pRange->Core.KeyLast <= GCPhysLast,2144 ("Incomplete R3 range! GCPhys=%RGp %RGp LB %RGp %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),2145 IOM_UNLOCK_EXCL(pVM),2146 VERR_IOM_INCOMPLETE_MMIO_RANGE);2147 2148 /* next */2149 Assert(GCPhys <= pRange->Core.KeyLast);2150 GCPhys = pRange->Core.KeyLast + 1;2151 }2152 2153 /*2154 * Do the actual removing of the MMIO ranges.2155 */2156 GCPhys = GCPhysStart;2157 while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)2158 {2159 iomR3FlushCache(pVM);2160 2161 PIOMMMIORANGE pRange = (PIOMMMIORANGE)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesR3->MMIOTree, GCPhys);2162 Assert(pRange);2163 Assert(pRange->Core.Key == GCPhys && pRange->Core.KeyLast <= GCPhysLast);2164 IOM_UNLOCK_EXCL(pVM); /* Lock order fun. */2165 2166 /* remove it from PGM */2167 int rc = PGMR3PhysMMIODeregister(pVM, GCPhys, pRange->cb);2168 AssertRC(rc);2169 2170 IOM_LOCK_EXCL(pVM);2171 2172 /* advance and free. */2173 GCPhys = pRange->Core.KeyLast + 1;2174 if (pDevIns->iInstance > 0)2175 {2176 void *pvDesc = ASMAtomicXchgPtr((void * volatile *)&pRange->pszDesc, NULL);2177 MMR3HeapFree(pvDesc);2178 }2179 iomMmioReleaseRange(pVM, pRange);2180 }2181 2182 IOM_UNLOCK_EXCL(pVM);2183 return VINF_SUCCESS;2184 }2185 2186 2187 /**2188 * Pre-Registers a MMIO region.2189 *2190 * The rest of of the manipulation of this region goes thru the PGMPhysMMIOEx*2191 * APIs: PGMR3PhysMMIOExMap, PGMR3PhysMMIOExUnmap, PGMR3PhysMMIOExDeregister2192 *2193 * @returns VBox status code.2194 * @param pVM Pointer to the cross context VM structure.2195 * @param pDevIns The device.2196 * @param iSubDev The sub-device number.2197 * @param iRegion The region number.2198 * @param cbRegion The size of the MMIO region. Must be a multiple2199 * of X86_PAGE_SIZE2200 * @param fFlags Flags, see IOMMMIO_FLAGS_XXX.2201 * @param pszDesc Pointer to description string. This must not be2202 * freed.2203 * @param pvUserR3 Ring-3 user pointer.2204 * @param pfnWriteCallbackR3 Callback for handling writes, ring-3. Mandatory.2205 * @param pfnReadCallbackR3 Callback for handling reads, ring-3. Mandatory.2206 * @param pfnFillCallbackR3 Callback for handling fills, ring-3. Optional.2207 * @param pvUserR0 Ring-0 user pointer.2208 * @param pfnWriteCallbackR0 Callback for handling writes, ring-0. Optional.2209 * @param pfnReadCallbackR0 Callback for handling reads, ring-0. Optional.2210 * @param pfnFillCallbackR0 Callback for handling fills, ring-0. Optional.2211 * @param pvUserRC Raw-mode context user pointer. This will be2212 * relocated with the hypervisor guest mapping if2213 * the unsigned integer value is 0x10000 or above.2214 * @param pfnWriteCallbackRC Callback for handling writes, RC. Optional.2215 * @param pfnReadCallbackRC Callback for handling reads, RC. Optional.2216 * @param pfnFillCallbackRC Callback for handling fills, RC. Optional.2217 */2218 VMMR3_INT_DECL(int) IOMR3MmioExPreRegister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cbRegion,2219 uint32_t fFlags, const char *pszDesc,2220 RTR3PTR pvUserR3,2221 R3PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackR3,2222 R3PTRTYPE(PFNIOMMMIOREAD) pfnReadCallbackR3,2223 R3PTRTYPE(PFNIOMMMIOFILL) pfnFillCallbackR3,2224 RTR0PTR pvUserR0,2225 R0PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackR0,2226 R0PTRTYPE(PFNIOMMMIOREAD) pfnReadCallbackR0,2227 R0PTRTYPE(PFNIOMMMIOFILL) pfnFillCallbackR0,2228 RTRCPTR pvUserRC,2229 RCPTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackRC,2230 RCPTRTYPE(PFNIOMMMIOREAD) pfnReadCallbackRC,2231 RCPTRTYPE(PFNIOMMMIOFILL) pfnFillCallbackRC)2232 {2233 LogFlow(("IOMR3MmioExPreRegister: pDevIns=%p iSubDev=%u iRegion=%u cbRegion=%RGp fFlags=%#x pszDesc=%s\n"2234 " pvUserR3=%RHv pfnWriteCallbackR3=%RHv pfnReadCallbackR3=%RHv pfnFillCallbackR3=%RHv\n"2235 " pvUserR0=%RHv pfnWriteCallbackR0=%RHv pfnReadCallbackR0=%RHv pfnFillCallbackR0=%RHv\n"2236 " pvUserRC=%RRv pfnWriteCallbackRC=%RRv pfnReadCallbackRC=%RRv pfnFillCallbackRC=%RRv\n",2237 pDevIns, iSubDev, iRegion, cbRegion, fFlags, pszDesc,2238 pvUserR3, pfnWriteCallbackR3, pfnReadCallbackR3, pfnFillCallbackR3,2239 pvUserR0, pfnWriteCallbackR0, pfnReadCallbackR0, pfnFillCallbackR0,2240 pvUserRC, pfnWriteCallbackRC, pfnReadCallbackRC, pfnFillCallbackRC));2241 2242 /*2243 * Validate input.2244 */2245 AssertReturn(cbRegion > 0, VERR_INVALID_PARAMETER);2246 AssertReturn(RT_ALIGN_T(cbRegion, X86_PAGE_SIZE, RTGCPHYS), VERR_INVALID_PARAMETER);2247 AssertMsgReturn( !(fFlags & ~IOMMMIO_FLAGS_VALID_MASK)2248 && (fFlags & IOMMMIO_FLAGS_READ_MODE) <= IOMMMIO_FLAGS_READ_DWORD_QWORD2249 && (fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD,2250 ("%#x\n", fFlags),2251 VERR_INVALID_PARAMETER);2252 AssertPtrReturn(pfnWriteCallbackR3, VERR_INVALID_POINTER);2253 AssertPtrReturn(pfnReadCallbackR3, VERR_INVALID_POINTER);2254 2255 /*2256 * Allocate new range record and initialize it.2257 */2258 PIOMMMIORANGE pRange;2259 int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);2260 if (RT_SUCCESS(rc))2261 {2262 pRange->Core.Key = NIL_RTGCPHYS;2263 pRange->Core.KeyLast = NIL_RTGCPHYS;2264 pRange->GCPhys = NIL_RTGCPHYS;2265 pRange->cb = cbRegion;2266 pRange->cRefs = 1; /* The PGM reference. */2267 pRange->fFlags = fFlags;2268 2269 pRange->pvUserR3 = pvUserR3;2270 pRange->pDevInsR3 = pDevIns;2271 pRange->pfnReadCallbackR3 = pfnReadCallbackR3;2272 pRange->pfnWriteCallbackR3 = pfnWriteCallbackR3;2273 pRange->pfnFillCallbackR3 = pfnFillCallbackR3;2274 pRange->pszDesc = pszDesc;2275 2276 if (pfnReadCallbackR0 || pfnWriteCallbackR0 || pfnFillCallbackR0)2277 {2278 pRange->pvUserR0 = pvUserR0;2279 pRange->pDevInsR0 = pDevIns->pDevInsR0RemoveMe;2280 pRange->pfnReadCallbackR0 = pfnReadCallbackR0;2281 pRange->pfnWriteCallbackR0 = pfnWriteCallbackR0;2282 pRange->pfnFillCallbackR0 = pfnFillCallbackR0;2283 }2284 2285 #if 02286 if (pfnReadCallbackRC || pfnWriteCallbackRC || pfnFillCallbackRC)2287 {2288 pRange->pvUserRC = pvUserRC;2289 pRange->pDevInsRC = pDevIns->pDevInsForRC;2290 pRange->pfnReadCallbackRC = pfnReadCallbackRC;2291 pRange->pfnWriteCallbackRC = pfnWriteCallbackRC;2292 pRange->pfnFillCallbackRC = pfnFillCallbackRC;2293 }2294 #else2295 RT_NOREF(pfnReadCallbackRC, pfnWriteCallbackRC, pfnFillCallbackRC, pvUserRC);2296 #endif2297 2298 /*2299 * Try register it with PGM. PGM will call us back when it's mapped in2300 * and out of the guest address space, and once it's destroyed.2301 */2302 rc = PGMR3PhysMMIOExPreRegister(pVM, pDevIns, iSubDev, iRegion, cbRegion, pVM->iom.s.hMmioHandlerType,2303 pRange, MMHyperR3ToR0(pVM, pRange), MMHyperR3ToRC(pVM, pRange), pszDesc);2304 if (RT_SUCCESS(rc))2305 return VINF_SUCCESS;2306 2307 MMHyperFree(pVM, pRange);2308 }2309 if (pDevIns->iInstance > 0)2310 MMR3HeapFree((void *)pszDesc);2311 return rc;2312 2313 }2314 2315 2316 /**2317 * Notfication from PGM that the pre-registered MMIO region has been mapped into2318 * user address space.2319 *2320 * @returns VBox status code.2321 * @param pVM Pointer to the cross context VM structure.2322 * @param pvUser The pvUserR3 argument of PGMR3PhysMMIOExPreRegister.2323 * @param GCPhys The mapping address.2324 * @remarks Called while owning the PGM lock.2325 */2326 VMMR3_INT_DECL(int) IOMR3MmioExNotifyMapped(PVM pVM, void *pvUser, RTGCPHYS GCPhys)2327 {2328 PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;2329 AssertReturn(pRange->GCPhys == NIL_RTGCPHYS, VERR_IOM_MMIO_IPE_1);2330 2331 IOM_LOCK_EXCL(pVM);2332 Assert(pRange->GCPhys == NIL_RTGCPHYS);2333 pRange->GCPhys = GCPhys;2334 pRange->Core.Key = GCPhys;2335 pRange->Core.KeyLast = GCPhys + pRange->cb - 1;2336 if (RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRange->Core))2337 {2338 iomR3FlushCache(pVM);2339 IOM_UNLOCK_EXCL(pVM);2340 return VINF_SUCCESS;2341 }2342 IOM_UNLOCK_EXCL(pVM);2343 2344 AssertLogRelMsgFailed(("RTAvlroGCPhysInsert failed on %RGp..%RGp - %s\n", pRange->Core.Key, pRange->Core.KeyLast, pRange->pszDesc));2345 pRange->GCPhys = NIL_RTGCPHYS;2346 pRange->Core.Key = NIL_RTGCPHYS;2347 pRange->Core.KeyLast = NIL_RTGCPHYS;2348 return VERR_IOM_MMIO_IPE_2;2349 }2350 2351 2352 /**2353 * Notfication from PGM that the pre-registered MMIO region has been unmapped2354 * from user address space.2355 *2356 * @param pVM Pointer to the cross context VM structure.2357 * @param pvUser The pvUserR3 argument of PGMR3PhysMMIOExPreRegister.2358 * @param GCPhys The mapping address.2359 * @remarks Called while owning the PGM lock.2360 */2361 VMMR3_INT_DECL(void) IOMR3MmioExNotifyUnmapped(PVM pVM, void *pvUser, RTGCPHYS GCPhys)2362 {2363 PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;2364 AssertLogRelReturnVoid(pRange->GCPhys == GCPhys);2365 2366 IOM_LOCK_EXCL(pVM);2367 Assert(pRange->GCPhys == GCPhys);2368 PIOMMMIORANGE pRemoved = (PIOMMMIORANGE)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesR3->MMIOTree, GCPhys);2369 if (pRemoved == pRange)2370 {2371 pRange->GCPhys = NIL_RTGCPHYS;2372 pRange->Core.Key = NIL_RTGCPHYS;2373 pRange->Core.KeyLast = NIL_RTGCPHYS;2374 iomR3FlushCache(pVM);2375 IOM_UNLOCK_EXCL(pVM);2376 }2377 else2378 {2379 if (pRemoved)2380 RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRemoved->Core);2381 IOM_UNLOCK_EXCL(pVM);2382 AssertLogRelMsgFailed(("RTAvlroGCPhysRemove returned %p instead of %p for %RGp (%s)\n",2383 pRemoved, pRange, GCPhys, pRange->pszDesc));2384 }2385 }2386 2387 2388 /**2389 * Notfication from PGM that the pre-registered MMIO region has been mapped into2390 * user address space.2391 *2392 * @param pVM Pointer to the cross context VM structure.2393 * @param pvUser The pvUserR3 argument of PGMR3PhysMMIOExPreRegister.2394 * @remarks Called while owning the PGM lock.2395 */2396 VMMR3_INT_DECL(void) IOMR3MmioExNotifyDeregistered(PVM pVM, void *pvUser)2397 {2398 PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;2399 AssertLogRelReturnVoid(pRange->GCPhys == NIL_RTGCPHYS);2400 iomMmioReleaseRange(pVM, pRange);2401 }2402 2403 2404 /**2405 * Handles the unlikely and probably fatal merge cases.2406 *2407 * @returns Merged status code.2408 * @param rcStrict Current EM status code.2409 * @param rcStrictCommit The IOM I/O or MMIO write commit status to merge2410 * with @a rcStrict.2411 * @param rcIom For logging purposes only.2412 * @param pVCpu The cross context virtual CPU structure of the2413 * calling EMT. For logging purposes.2414 */2415 DECL_NO_INLINE(static, VBOXSTRICTRC) iomR3MergeStatusSlow(VBOXSTRICTRC rcStrict, VBOXSTRICTRC rcStrictCommit,2416 int rcIom, PVMCPU pVCpu)2417 {2418 if (RT_FAILURE_NP(rcStrict))2419 return rcStrict;2420 2421 if (RT_FAILURE_NP(rcStrictCommit))2422 return rcStrictCommit;2423 2424 if (rcStrict == rcStrictCommit)2425 return rcStrictCommit;2426 2427 AssertLogRelMsgFailed(("rcStrictCommit=%Rrc rcStrict=%Rrc IOPort={%#06x<-%#xx/%u} MMIO={%RGp<-%.*Rhxs} (rcIom=%Rrc)\n",2428 VBOXSTRICTRC_VAL(rcStrictCommit), VBOXSTRICTRC_VAL(rcStrict),2429 pVCpu->iom.s.PendingIOPortWrite.IOPort,2430 pVCpu->iom.s.PendingIOPortWrite.u32Value, pVCpu->iom.s.PendingIOPortWrite.cbValue,2431 pVCpu->iom.s.PendingMmioWrite.GCPhys,2432 pVCpu->iom.s.PendingMmioWrite.cbValue, &pVCpu->iom.s.PendingMmioWrite.abValue[0], rcIom));2433 return VERR_IOM_FF_STATUS_IPE;2434 }2435 2436 2437 /**2438 * Helper for IOMR3ProcessForceFlag.2439 *2440 * @returns Merged status code.2441 * @param rcStrict Current EM status code.2442 * @param rcStrictCommit The IOM I/O or MMIO write commit status to merge2443 * with @a rcStrict.2444 * @param rcIom Either VINF_IOM_R3_IOPORT_COMMIT_WRITE or2445 * VINF_IOM_R3_MMIO_COMMIT_WRITE.2446 * @param pVCpu The cross context virtual CPU structure of the2447 * calling EMT.2448 */2449 DECLINLINE(VBOXSTRICTRC) iomR3MergeStatus(VBOXSTRICTRC rcStrict, VBOXSTRICTRC rcStrictCommit, int rcIom, PVMCPU pVCpu)2450 {2451 /* Simple. */2452 if (RT_LIKELY(rcStrict == rcIom || rcStrict == VINF_EM_RAW_TO_R3 || rcStrict == VINF_SUCCESS))2453 return rcStrictCommit;2454 2455 if (RT_LIKELY(rcStrictCommit == VINF_SUCCESS))2456 return rcStrict;2457 2458 /* EM scheduling status codes. */2459 if (RT_LIKELY( rcStrict >= VINF_EM_FIRST2460 && rcStrict <= VINF_EM_LAST))2461 {2462 if (RT_LIKELY( rcStrictCommit >= VINF_EM_FIRST2463 && rcStrictCommit <= VINF_EM_LAST))2464 return rcStrict < rcStrictCommit ? rcStrict : rcStrictCommit;2465 }2466 2467 /* Unlikely */2468 return iomR3MergeStatusSlow(rcStrict, rcStrictCommit, rcIom, pVCpu);2469 }2470 2471 2472 /**2473 * Called by force-flag handling code when VMCPU_FF_IOM is set.2474 *2475 * @returns Merge between @a rcStrict and what the commit operation returned.2476 * @param pVM The cross context VM structure.2477 * @param pVCpu The cross context virtual CPU structure of the calling EMT.2478 * @param rcStrict The status code returned by ring-0 or raw-mode.2479 * @thread EMT(pVCpu)2480 *2481 * @remarks The VMCPU_FF_IOM flag is handled before the status codes by EM, so2482 * we're very likely to see @a rcStrict set to2483 * VINF_IOM_R3_IOPORT_COMMIT_WRITE and VINF_IOM_R3_MMIO_COMMIT_WRITE2484 * here.2485 */2486 VMMR3_INT_DECL(VBOXSTRICTRC) IOMR3ProcessForceFlag(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict)2487 {2488 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_IOM);2489 Assert(pVCpu->iom.s.PendingIOPortWrite.cbValue || pVCpu->iom.s.PendingMmioWrite.cbValue);2490 2491 if (pVCpu->iom.s.PendingIOPortWrite.cbValue)2492 {2493 Log5(("IOM: Dispatching pending I/O port write: %#x LB %u -> %RTiop\n", pVCpu->iom.s.PendingIOPortWrite.u32Value,2494 pVCpu->iom.s.PendingIOPortWrite.cbValue, pVCpu->iom.s.PendingIOPortWrite.IOPort));2495 VBOXSTRICTRC rcStrictCommit = IOMIOPortWrite(pVM, pVCpu, pVCpu->iom.s.PendingIOPortWrite.IOPort,2496 pVCpu->iom.s.PendingIOPortWrite.u32Value,2497 pVCpu->iom.s.PendingIOPortWrite.cbValue);2498 pVCpu->iom.s.PendingIOPortWrite.cbValue = 0;2499 rcStrict = iomR3MergeStatus(rcStrict, rcStrictCommit, VINF_IOM_R3_IOPORT_COMMIT_WRITE, pVCpu);2500 }2501 2502 2503 if (pVCpu->iom.s.PendingMmioWrite.cbValue)2504 {2505 Log5(("IOM: Dispatching pending MMIO write: %RGp LB %#x\n",2506 pVCpu->iom.s.PendingMmioWrite.GCPhys, pVCpu->iom.s.PendingMmioWrite.cbValue));2507 /** @todo Try optimize this some day? Currently easier and correcter to2508 * involve PGM here since we never know if the MMIO area is still mapped2509 * to the same location as when we wrote to it in RC/R0 context. */2510 VBOXSTRICTRC rcStrictCommit = PGMPhysWrite(pVM, pVCpu->iom.s.PendingMmioWrite.GCPhys,2511 pVCpu->iom.s.PendingMmioWrite.abValue, pVCpu->iom.s.PendingMmioWrite.cbValue,2512 PGMACCESSORIGIN_IOM);2513 pVCpu->iom.s.PendingMmioWrite.cbValue = 0;2514 rcStrict = iomR3MergeStatus(rcStrict, rcStrictCommit, VINF_IOM_R3_MMIO_COMMIT_WRITE, pVCpu);2515 }2516 2517 return rcStrict;2518 }2519 2520 2521 /**2522 * Notification from DBGF that the number of active I/O port or MMIO2523 * breakpoints has change.2524 *2525 * For performance reasons, IOM will only call DBGF before doing I/O and MMIO2526 * accesses where there are armed breakpoints.2527 *2528 * @param pVM The cross context VM structure.2529 * @param fPortIo True if there are armed I/O port breakpoints.2530 * @param fMmio True if there are armed MMIO breakpoints.2531 */2532 VMMR3_INT_DECL(void) IOMR3NotifyBreakpointCountChange(PVM pVM, bool fPortIo, bool fMmio)2533 {2534 /** @todo I/O breakpoints. */2535 RT_NOREF3(pVM, fPortIo, fMmio);2536 }2537 2538 2539 /**2540 * Notification from DBGF that an event has been enabled or disabled.2541 *2542 * For performance reasons, IOM may cache the state of events it implements.2543 *2544 * @param pVM The cross context VM structure.2545 * @param enmEvent The event.2546 * @param fEnabled The new state.2547 */2548 VMMR3_INT_DECL(void) IOMR3NotifyDebugEventChange(PVM pVM, DBGFEVENT enmEvent, bool fEnabled)2549 {2550 /** @todo IOM debug events. */2551 RT_NOREF3(pVM, enmEvent, fEnabled);2552 }2553 2554 2555 /**2556 * Display a single MMIO range.2557 *2558 * @returns 02559 * @param pNode Pointer to MMIO R3 range.2560 * @param pvUser Pointer to info output callback structure.2561 */2562 static DECLCALLBACK(int) iomR3MMIOInfoOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)2563 {2564 PIOMMMIORANGE pRange = (PIOMMMIORANGE)pNode;2565 PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;2566 pHlp->pfnPrintf(pHlp,2567 "%RGp-%RGp %RHv %RHv %RHv %RHv %RHv %s\n",2568 pRange->Core.Key,2569 pRange->Core.KeyLast,2570 pRange->pDevInsR3,2571 pRange->pfnReadCallbackR3,2572 pRange->pfnWriteCallbackR3,2573 pRange->pfnFillCallbackR3,2574 pRange->pvUserR3,2575 pRange->pszDesc);2576 pHlp->pfnPrintf(pHlp,2577 "%*s %RHv %RHv %RHv %RHv %RHv\n",2578 sizeof(RTGCPHYS) * 2 * 2 + 1, "R0",2579 pRange->pDevInsR0,2580 pRange->pfnReadCallbackR0,2581 pRange->pfnWriteCallbackR0,2582 pRange->pfnFillCallbackR0,2583 pRange->pvUserR0);2584 #if 02585 pHlp->pfnPrintf(pHlp,2586 "%*s %RRv %RRv %RRv %RRv %RRv\n",2587 sizeof(RTGCPHYS) * 2 * 2 + 1, "RC",2588 pRange->pDevInsRC,2589 pRange->pfnReadCallbackRC,2590 pRange->pfnWriteCallbackRC,2591 pRange->pfnFillCallbackRC,2592 pRange->pvUserRC);2593 #endif2594 return 0;2595 }2596 2597 2598 /**2599 * Display registered MMIO ranges to the log.2600 *2601 * @param pVM The cross context VM structure.2602 * @param pHlp The info helpers.2603 * @param pszArgs Arguments, ignored.2604 */2605 static DECLCALLBACK(void) iomR3MMIOInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)2606 {2607 NOREF(pszArgs);2608 pHlp->pfnPrintf(pHlp,2609 "MMIO ranges (pVM=%p)\n"2610 "%.*s %.*s %.*s %.*s %.*s %.*s %s\n",2611 pVM,2612 sizeof(RTGCPHYS) * 4 + 1, "GC Phys Range ",2613 sizeof(RTHCPTR) * 2, "pDevIns ",2614 sizeof(RTHCPTR) * 2, "Read ",2615 sizeof(RTHCPTR) * 2, "Write ",2616 sizeof(RTHCPTR) * 2, "Fill ",2617 sizeof(RTHCPTR) * 2, "pvUser ",2618 "Description");2619 RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesR3->MMIOTree, true, iomR3MMIOInfoOne, (void *)pHlp);2620 }2621 2622 2623 #ifdef VBOX_WITH_STATISTICS2624 /**2625 * Tries to come up with the standard name for a port.2626 *2627 * @returns Pointer to readonly string if known.2628 * @returns NULL if unknown port number.2629 *2630 * @param Port The port to name.2631 */2632 static const char *iomR3IOPortGetStandardName(RTIOPORT Port)2633 {2634 switch (Port)2635 {2636 case 0x00: case 0x10: case 0x20: case 0x30: case 0x40: case 0x50: case 0x70:2637 case 0x01: case 0x11: case 0x21: case 0x31: case 0x41: case 0x51: case 0x61: case 0x71:2638 case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: case 0x62: case 0x72:2639 case 0x03: case 0x13: case 0x23: case 0x33: case 0x43: case 0x53: case 0x63: case 0x73:2640 case 0x04: case 0x14: case 0x24: case 0x34: case 0x44: case 0x54: case 0x74:2641 case 0x05: case 0x15: case 0x25: case 0x35: case 0x45: case 0x55: case 0x65: case 0x75:2642 case 0x06: case 0x16: case 0x26: case 0x36: case 0x46: case 0x56: case 0x66: case 0x76:2643 case 0x07: case 0x17: case 0x27: case 0x37: case 0x47: case 0x57: case 0x67: case 0x77:2644 case 0x08: case 0x18: case 0x28: case 0x38: case 0x48: case 0x58: case 0x68: case 0x78:2645 case 0x09: case 0x19: case 0x29: case 0x39: case 0x49: case 0x59: case 0x69: case 0x79:2646 case 0x0a: case 0x1a: case 0x2a: case 0x3a: case 0x4a: case 0x5a: case 0x6a: case 0x7a:2647 case 0x0b: case 0x1b: case 0x2b: case 0x3b: case 0x4b: case 0x5b: case 0x6b: case 0x7b:2648 case 0x0c: case 0x1c: case 0x2c: case 0x3c: case 0x4c: case 0x5c: case 0x6c: case 0x7c:2649 case 0x0d: case 0x1d: case 0x2d: case 0x3d: case 0x4d: case 0x5d: case 0x6d: case 0x7d:2650 case 0x0e: case 0x1e: case 0x2e: case 0x3e: case 0x4e: case 0x5e: case 0x6e: case 0x7e:2651 case 0x0f: case 0x1f: case 0x2f: case 0x3f: case 0x4f: case 0x5f: case 0x6f: case 0x7f:2652 2653 case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xc0: case 0xd0: case 0xe0: case 0xf0:2654 case 0x81: case 0x91: case 0xa1: case 0xb1: case 0xc1: case 0xd1: case 0xe1: case 0xf1:2655 case 0x82: case 0x92: case 0xa2: case 0xb2: case 0xc2: case 0xd2: case 0xe2: case 0xf2:2656 case 0x83: case 0x93: case 0xa3: case 0xb3: case 0xc3: case 0xd3: case 0xe3: case 0xf3:2657 case 0x84: case 0x94: case 0xa4: case 0xb4: case 0xc4: case 0xd4: case 0xe4: case 0xf4:2658 case 0x85: case 0x95: case 0xa5: case 0xb5: case 0xc5: case 0xd5: case 0xe5: case 0xf5:2659 case 0x86: case 0x96: case 0xa6: case 0xb6: case 0xc6: case 0xd6: case 0xe6: case 0xf6:2660 case 0x87: case 0x97: case 0xa7: case 0xb7: case 0xc7: case 0xd7: case 0xe7: case 0xf7:2661 case 0x88: case 0x98: case 0xa8: case 0xb8: case 0xc8: case 0xd8: case 0xe8: case 0xf8:2662 case 0x89: case 0x99: case 0xa9: case 0xb9: case 0xc9: case 0xd9: case 0xe9: case 0xf9:2663 case 0x8a: case 0x9a: case 0xaa: case 0xba: case 0xca: case 0xda: case 0xea: case 0xfa:2664 case 0x8b: case 0x9b: case 0xab: case 0xbb: case 0xcb: case 0xdb: case 0xeb: case 0xfb:2665 case 0x8c: case 0x9c: case 0xac: case 0xbc: case 0xcc: case 0xdc: case 0xec: case 0xfc:2666 case 0x8d: case 0x9d: case 0xad: case 0xbd: case 0xcd: case 0xdd: case 0xed: case 0xfd:2667 case 0x8e: case 0x9e: case 0xae: case 0xbe: case 0xce: case 0xde: case 0xee: case 0xfe:2668 case 0x8f: case 0x9f: case 0xaf: case 0xbf: case 0xcf: case 0xdf: case 0xef: case 0xff:2669 return "System Reserved";2670 2671 case 0x60:2672 case 0x64:2673 return "Keyboard & Mouse";2674 2675 case 0x378:2676 case 0x379:2677 case 0x37a:2678 case 0x37b:2679 case 0x37c:2680 case 0x37d:2681 case 0x37e:2682 case 0x37f:2683 case 0x3bc:2684 case 0x3bd:2685 case 0x3be:2686 case 0x3bf:2687 case 0x278:2688 case 0x279:2689 case 0x27a:2690 case 0x27b:2691 case 0x27c:2692 case 0x27d:2693 case 0x27e:2694 case 0x27f:2695 return "LPT1/2/3";2696 2697 case 0x3f8:2698 case 0x3f9:2699 case 0x3fa:2700 case 0x3fb:2701 case 0x3fc:2702 case 0x3fd:2703 case 0x3fe:2704 case 0x3ff:2705 return "COM1";2706 2707 case 0x2f8:2708 case 0x2f9:2709 case 0x2fa:2710 case 0x2fb:2711 case 0x2fc:2712 case 0x2fd:2713 case 0x2fe:2714 case 0x2ff:2715 return "COM2";2716 2717 case 0x3e8:2718 case 0x3e9:2719 case 0x3ea:2720 case 0x3eb:2721 case 0x3ec:2722 case 0x3ed:2723 case 0x3ee:2724 case 0x3ef:2725 return "COM3";2726 2727 case 0x2e8:2728 case 0x2e9:2729 case 0x2ea:2730 case 0x2eb:2731 case 0x2ec:2732 case 0x2ed:2733 case 0x2ee:2734 case 0x2ef:2735 return "COM4";2736 2737 case 0x200:2738 case 0x201:2739 case 0x202:2740 case 0x203:2741 case 0x204:2742 case 0x205:2743 case 0x206:2744 case 0x207:2745 return "Joystick";2746 2747 case 0x3f0:2748 case 0x3f1:2749 case 0x3f2:2750 case 0x3f3:2751 case 0x3f4:2752 case 0x3f5:2753 case 0x3f6:2754 case 0x3f7:2755 return "Floppy";2756 2757 case 0x1f0:2758 case 0x1f1:2759 case 0x1f2:2760 case 0x1f3:2761 case 0x1f4:2762 case 0x1f5:2763 case 0x1f6:2764 case 0x1f7:2765 //case 0x3f6:2766 //case 0x3f7:2767 return "IDE 1st";2768 2769 case 0x170:2770 case 0x171:2771 case 0x172:2772 case 0x173:2773 case 0x174:2774 case 0x175:2775 case 0x176:2776 case 0x177:2777 case 0x376:2778 case 0x377:2779 return "IDE 2nd";2780 2781 case 0x1e0:2782 case 0x1e1:2783 case 0x1e2:2784 case 0x1e3:2785 case 0x1e4:2786 case 0x1e5:2787 case 0x1e6:2788 case 0x1e7:2789 case 0x3e6:2790 case 0x3e7:2791 return "IDE 3rd";2792 2793 case 0x160:2794 case 0x161:2795 case 0x162:2796 case 0x163:2797 case 0x164:2798 case 0x165:2799 case 0x166:2800 case 0x167:2801 case 0x366:2802 case 0x367:2803 return "IDE 4th";2804 2805 case 0x130: case 0x140: case 0x150:2806 case 0x131: case 0x141: case 0x151:2807 case 0x132: case 0x142: case 0x152:2808 case 0x133: case 0x143: case 0x153:2809 case 0x134: case 0x144: case 0x154:2810 case 0x135: case 0x145: case 0x155:2811 case 0x136: case 0x146: case 0x156:2812 case 0x137: case 0x147: case 0x157:2813 case 0x138: case 0x148: case 0x158:2814 case 0x139: case 0x149: case 0x159:2815 case 0x13a: case 0x14a: case 0x15a:2816 case 0x13b: case 0x14b: case 0x15b:2817 case 0x13c: case 0x14c: case 0x15c:2818 case 0x13d: case 0x14d: case 0x15d:2819 case 0x13e: case 0x14e: case 0x15e:2820 case 0x13f: case 0x14f: case 0x15f:2821 case 0x220: case 0x230:2822 case 0x221: case 0x231:2823 case 0x222: case 0x232:2824 case 0x223: case 0x233:2825 case 0x224: case 0x234:2826 case 0x225: case 0x235:2827 case 0x226: case 0x236:2828 case 0x227: case 0x237:2829 case 0x228: case 0x238:2830 case 0x229: case 0x239:2831 case 0x22a: case 0x23a:2832 case 0x22b: case 0x23b:2833 case 0x22c: case 0x23c:2834 case 0x22d: case 0x23d:2835 case 0x22e: case 0x23e:2836 case 0x22f: case 0x23f:2837 case 0x330: case 0x340: case 0x350:2838 case 0x331: case 0x341: case 0x351:2839 case 0x332: case 0x342: case 0x352:2840 case 0x333: case 0x343: case 0x353:2841 case 0x334: case 0x344: case 0x354:2842 case 0x335: case 0x345: case 0x355:2843 case 0x336: case 0x346: case 0x356:2844 case 0x337: case 0x347: case 0x357:2845 case 0x338: case 0x348: case 0x358:2846 case 0x339: case 0x349: case 0x359:2847 case 0x33a: case 0x34a: case 0x35a:2848 case 0x33b: case 0x34b: case 0x35b:2849 case 0x33c: case 0x34c: case 0x35c:2850 case 0x33d: case 0x34d: case 0x35d:2851 case 0x33e: case 0x34e: case 0x35e:2852 case 0x33f: case 0x34f: case 0x35f:2853 return "SCSI (typically)";2854 2855 case 0x320:2856 case 0x321:2857 case 0x322:2858 case 0x323:2859 case 0x324:2860 case 0x325:2861 case 0x326:2862 case 0x327:2863 return "XT HD";2864 2865 case 0x3b0:2866 case 0x3b1:2867 case 0x3b2:2868 case 0x3b3:2869 case 0x3b4:2870 case 0x3b5:2871 case 0x3b6:2872 case 0x3b7:2873 case 0x3b8:2874 case 0x3b9:2875 case 0x3ba:2876 case 0x3bb:2877 return "VGA";2878 2879 case 0x3c0: case 0x3d0:2880 case 0x3c1: case 0x3d1:2881 case 0x3c2: case 0x3d2:2882 case 0x3c3: case 0x3d3:2883 case 0x3c4: case 0x3d4:2884 case 0x3c5: case 0x3d5:2885 case 0x3c6: case 0x3d6:2886 case 0x3c7: case 0x3d7:2887 case 0x3c8: case 0x3d8:2888 case 0x3c9: case 0x3d9:2889 case 0x3ca: case 0x3da:2890 case 0x3cb: case 0x3db:2891 case 0x3cc: case 0x3dc:2892 case 0x3cd: case 0x3dd:2893 case 0x3ce: case 0x3de:2894 case 0x3cf: case 0x3df:2895 return "VGA/EGA";2896 2897 case 0x240: case 0x260: case 0x280:2898 case 0x241: case 0x261: case 0x281:2899 case 0x242: case 0x262: case 0x282:2900 case 0x243: case 0x263: case 0x283:2901 case 0x244: case 0x264: case 0x284:2902 case 0x245: case 0x265: case 0x285:2903 case 0x246: case 0x266: case 0x286:2904 case 0x247: case 0x267: case 0x287:2905 case 0x248: case 0x268: case 0x288:2906 case 0x249: case 0x269: case 0x289:2907 case 0x24a: case 0x26a: case 0x28a:2908 case 0x24b: case 0x26b: case 0x28b:2909 case 0x24c: case 0x26c: case 0x28c:2910 case 0x24d: case 0x26d: case 0x28d:2911 case 0x24e: case 0x26e: case 0x28e:2912 case 0x24f: case 0x26f: case 0x28f:2913 case 0x300:2914 case 0x301:2915 case 0x388:2916 case 0x389:2917 case 0x38a:2918 case 0x38b:2919 return "Sound Card (typically)";2920 2921 default:2922 return NULL;2923 }2924 }2925 #endif /* VBOX_WITH_STATISTICS */2926 -
trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp
r81153 r81156 333 333 static DECLCALLBACK(int) pdmR3DevHlp_MmioCreateEx(PPDMDEVINS pDevIns, RTGCPHYS cbRegion, 334 334 uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion, 335 PFNIOMMMIO WRITE pfnWrite, PFNIOMMMIOREAD pfnRead, PFNIOMMMIOFILL pfnFill,335 PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, 336 336 void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion) 337 337 { 338 RT_NOREF(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion); 339 return VERR_NOT_IMPLEMENTED; 338 PDMDEV_ASSERT_DEVINS(pDevIns); 339 LogFlow(("pdmR3DevHlp_MmioCreateEx: caller='%s'/%d: cbRegion=%#RGp fFlags=%#x pPciDev=%p iPciRegion=%#x pfnWrite=%p pfnRead=%p pfnFill=%p pvUser=%p pszDesc=%p:{%s} phRegion=%p\n", 340 pDevIns->pReg->szName, pDevIns->iInstance, cbRegion, fFlags, pPciDev, iPciRegion, pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion)); 341 PVM pVM = pDevIns->Internal.s.pVMR3; 342 VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); 343 VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE); 344 345 int rc = IOMR3MmioCreate(pVM, pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, 346 pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion); 347 348 LogFlow(("pdmR3DevHlp_MmioCreateEx: caller='%s'/%d: returns %Rrc (*phRegion=%#x)\n", 349 pDevIns->pReg->szName, pDevIns->iInstance, rc, *phRegion)); 350 return rc; 340 351 } 341 352 … … 344 355 static DECLCALLBACK(int) pdmR3DevHlp_MmioMap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys) 345 356 { 346 RT_NOREF(pDevIns, hRegion, GCPhys); 347 return VERR_NOT_IMPLEMENTED; 357 PDMDEV_ASSERT_DEVINS(pDevIns); 358 LogFlow(("pdmR3DevHlp_MmioMap: caller='%s'/%d: hRegion=%#x GCPhys=%#RGp\n", pDevIns->pReg->szName, pDevIns->iInstance, hRegion, GCPhys)); 359 PVM pVM = pDevIns->Internal.s.pVMR3; 360 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); 361 362 int rc = IOMR3MmioMap(pVM, pDevIns, hRegion, GCPhys); 363 364 LogFlow(("pdmR3DevHlp_MmioMap: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc)); 365 return rc; 348 366 } 349 367 … … 352 370 static DECLCALLBACK(int) pdmR3DevHlp_MmioUnmap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) 353 371 { 354 RT_NOREF(pDevIns, hRegion); 355 return VERR_NOT_IMPLEMENTED; 372 PDMDEV_ASSERT_DEVINS(pDevIns); 373 LogFlow(("pdmR3DevHlp_MmioUnmap: caller='%s'/%d: hRegion=%#x\n", pDevIns->pReg->szName, pDevIns->iInstance, hRegion)); 374 PVM pVM = pDevIns->Internal.s.pVMR3; 375 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); 376 377 int rc = IOMR3MmioUnmap(pVM, pDevIns, hRegion); 378 379 LogFlow(("pdmR3DevHlp_MmioUnmap: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc)); 380 return rc; 356 381 } 357 382 … … 360 385 static DECLCALLBACK(int) pdmR3DevHlp_MmioReduce(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion) 361 386 { 362 RT_NOREF(pDevIns, hRegion, cbRegion); 363 return VERR_NOT_IMPLEMENTED; 387 PDMDEV_ASSERT_DEVINS(pDevIns); 388 LogFlow(("pdmR3DevHlp_MmioReduce: caller='%s'/%d: hRegion=%#x cbRegion=%#RGp\n", pDevIns->pReg->szName, pDevIns->iInstance, hRegion, cbRegion)); 389 PVM pVM = pDevIns->Internal.s.pVMR3; 390 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); 391 VM_ASSERT_STATE_RETURN(pVM, VMSTATE_LOADING, VERR_VM_INVALID_VM_STATE); 392 393 int rc = IOMR3MmioReduce(pVM, pDevIns, hRegion, cbRegion); 394 395 LogFlow(("pdmR3DevHlp_MmioReduce: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc)); 396 return rc; 364 397 } 365 398 -
trunk/src/VBox/VMM/include/IOMInternal.h
r81136 r81156 657 657 #ifdef IN_RING3 658 658 PIOMMMIOSTATS iomR3MMIOStatsCreate(PVM pVM, RTGCPHYS GCPhys, const char *pszDesc); 659 DECLCALLBACK(void) iomR3IoPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs); 660 void iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry); 659 661 #endif /* IN_RING3 */ 660 662
Note:
See TracChangeset
for help on using the changeset viewer.

