VirtualBox

Changeset 81156 in vbox


Ignore:
Timestamp:
Oct 8, 2019 2:58:45 PM (5 years ago)
Author:
vboxsync
Message:

IOM,PDMDevHlp: Started implementing new MMIO registration APIs. Splitting up IOM.cpp into I/O port and MMIO source files. bugref:9218

Location:
trunk
Files:
5 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/iom.h

    r81136 r81156  
    390390typedef FNIOMMMIOFILL *PFNIOMMMIOFILL;
    391391
     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 */
     406typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMMMIONEWREAD(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, uint32_t cb);
     407/** Pointer to a FNIOMMMIONEWREAD(). */
     408typedef 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 */
     423typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMMMIONEWWRITE(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, uint32_t cb);
     424/** Pointer to a FNIOMMMIONEWWRITE(). */
     425typedef 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 */
     441typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMMMIONEWFILL(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off,
     442                                                    uint32_t u32Item, uint32_t cbItem, uint32_t cItems);
     443/** Pointer to a FNIOMMMIONEWFILL(). */
     444typedef FNIOMMMIONEWFILL *PFNIOMMMIONEWFILL;
     445
    392446VMMDECL(VBOXSTRICTRC)   IOMIOPortRead(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue);
    393447VMMDECL(VBOXSTRICTRC)   IOMIOPortWrite(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue);
     
    412466/** @} */
    413467
     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
    414477#ifdef IN_RING3
    415478/** @defgroup grp_iom_r3    The IOM Host Context Ring-3 API
     
    429492VMMR3_INT_DECL(int)  IOMR3IoPortUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts);
    430493
     494VMMR3_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);
     497VMMR3_INT_DECL(int)  IOMR3MmioMap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys);
     498VMMR3_INT_DECL(int)  IOMR3MmioUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion);
     499VMMR3_INT_DECL(int)  IOMR3MmioReduce(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion);
     500
     501/** @name obsolete
     502 * @deprecated
     503 * @{ */
    431504VMMR3_INT_DECL(int)  IOMR3IOPortRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTHCPTR pvUser,
    432505                                           R3PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, R3PTRTYPE(PFNIOMIOPORTIN) pfnInCallback,
     
    479552VMMR3_INT_DECL(void) IOMR3MmioExNotifyDeregistered(PVM pVM, void *pvUser);
    480553
     554/** @} */
     555
    481556VMMR3_INT_DECL(VBOXSTRICTRC) IOMR3ProcessForceFlag(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict);
    482557
  • trunk/src/VBox/VMM/Makefile.kmk

    r81153 r81156  
    120120        VMMR3/IEMR3.cpp \
    121121        VMMR3/IOM.cpp \
     122        VMMR3/IOMR3IoPort.cpp \
    122123        VMMR3/GMM.cpp \
    123124        VMMR3/MM.cpp \
  • trunk/src/VBox/VMM/VMMR3/IOM.cpp

    r81136 r81156  
    138138static DECLCALLBACK(int) iomR3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser);
    139139#endif
    140 #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);
    145140static DECLCALLBACK(void) iomR3MMIOInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
    146141static FNIOMIOPORTIN        iomR3IOPortDummyIn;
     
    148143static FNIOMIOPORTINSTRING  iomR3IOPortDummyInStr;
    149144static FNIOMIOPORTOUTSTRING iomR3IOPortDummyOutStr;
    150 static FNIOMIOPORTNEWIN        iomR3IOPortDummyNewIn;
    151 static FNIOMIOPORTNEWOUT       iomR3IOPortDummyNewOut;
    152 static FNIOMIOPORTNEWINSTRING  iomR3IOPortDummyNewInStr;
    153 static FNIOMIOPORTNEWOUTSTRING iomR3IOPortDummyNewOutStr;
    154145
    155146#ifdef VBOX_WITH_STATISTICS
     
    208199             * Info.
    209200             */
    210             DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IOPortInfo);
     201            DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IoPortInfo);
    211202            DBGFR3InfoRegisterInternal(pVM, "mmio", "Dumps all MMIO ranges. No arguments.", &iomR3MMIOInfo);
    212203
     
    452443
    453444
    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_STATISTICS
    502     uint16_t const idxStats        = UINT16_MAX;
    503 #else
    504     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 #endif
    515 
    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                     else
    596                     {
    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                     else
    609                     {
    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                 else
    617                 {
    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         else
    630             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_STATISTICS
    644         /* Don't register stats here when we're creating the VM as the
    645            statistics table may still be reallocated. */
    646         if (pVM->enmVMState >= VMSTATE_CREATED)
    647             iomR3IoPortRegStats(pVM, pRegEntry);
    648 #endif
    649 
    650 #ifdef VBOX_STRICT
    651         /*
    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 #endif
    666     }
    667     else
    668     {
    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                 else
    718                 {
    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                 else
    728                 {
    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_STATISTICS
    738                 iomR3IoPortDeregStats(pVM, pRegEntry, uPort);
    739 #endif
    740                 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             else
    749             {
    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_STRICT
    761         /*
    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 #endif
    776     }
    777     else
    778     {
    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_STATISTICS
    788 
    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     else
    806         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     do
    814     {
    815         size_t cchBaseNm;
    816         if (uFirstPort < uEndPort - 1)
    817             cchBaseNm = cchPrefix + RTStrPrintf(&szName[cchPrefix], sizeof(szName) - cchPrefix, "/%04x-", uPort);
    818         else
    819         {
    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     else
    870         cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x/", uPort);
    871     STAMR3DeregisterByPrefix(pVM->pUVM, szPrefix);
    872 }
    873 
    874 #endif /* VBOX_WITH_STATISTICS */
    875445#ifdef VBOX_WITH_STATISTICS
    876446
     
    17011271
    17021272
    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 0
    1764  * @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 0
    1785 /**
    1786  * Display a single I/O port GC range.
    1787  *
    1788  * @returns 0
    1789  * @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 #endif
    1808 
    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         else
    1840             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 
    18711273
    18721274/**
     
    29252327#endif /* VBOX_WITH_STATISTICS */
    29262328
     2329
     2330VMMR3_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
     2338VMMR3_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
     2344VMMR3_INT_DECL(int)  IOMR3MmioUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)
     2345{
     2346    RT_NOREF(pVM, pDevIns, hRegion);
     2347    return VERR_NOT_IMPLEMENTED;
     2348}
     2349
     2350VMMR3_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  
    11/* $Id$ */
    22/** @file
    3  * IOM - Input / Output Monitor.
     3 * IOM - Input / Output Monitor, I/O port related APIs.
    44 */
    55
     
    1717
    1818
    19 /** @page pg_iom        IOM - The Input / Output Monitor
    20  *
    21  * The input/output monitor will handle I/O exceptions routing them to the
    22  * appropriate device. It implements an API to register and deregister virtual
    23  * I/0 port handlers and memory mapped I/O handlers. A handler is PDM devices
    24  * and a set of callback functions.
    25  *
    26  * @see grp_iom
    27  *
    28  *
    29  * @section sec_iom_rawmode     Raw-Mode
    30  *
    31  * In raw-mode I/O port access is trapped (\#GP(0)) by ensuring that the actual
    32  * IOPL is 0 regardless of what the guest IOPL is. The \#GP handler use the
    33  * disassembler (DIS) to figure which instruction caused it (there are a number
    34  * of instructions in addition to the I/O ones) and if it's an I/O port access
    35  * it will hand it to IOMRCIOPortHandler (via EMInterpretPortIO).
    36  * IOMRCIOPortHandler will lookup the port in the AVL tree of registered
    37  * handlers. If found, the handler will be called otherwise default action is
    38  * 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 PGM
    41  * access handlers. An MMIO range is registered with IOM which then registers it
    42  * with the PGM access handler sub-system. The access handler catches all
    43  * access and will be called in the context of a \#PF handler. In RC and R0 this
    44  * handler is iomMmioPfHandler while in ring-3 it's iomR3MmioHandler (although
    45  * in ring-3 there can be alternative ways). iomMmioPfHandler will attempt to
    46  * emulate the instruction that is doing the access and pass the corresponding
    47  * reads / writes to the device.
    48  *
    49  * Emulating I/O port access is less complex and should be slightly faster than
    50  * 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 up
    52  * execution.
    53  *
    54  *
    55  * @section sec_iom_hm     Hardware Assisted Virtualization Mode
    56  *
    57  * When running in hardware assisted virtualization mode we'll be doing much the
    58  * same things as in raw-mode. The main difference is that we're running in the
    59  * host ring-0 context and that we don't get faults (\#GP(0) and \#PG) but
    60  * exits.
    61  *
    62  *
    63  * @section sec_iom_rem         Recompiled Execution Mode
    64  *
    65  * When running in the recompiler things are different. I/O port access is
    66  * handled by calling IOMIOPortRead and IOMIOPortWrite directly. While MMIO can
    67  * be handled in one of two ways. The normal way is that we have a registered a
    68  * special RAM range with the recompiler and in the three callbacks (for byte,
    69  * word and dword access) we call IOMMMIORead and IOMMMIOWrite directly. The
    70  * alternative ways that the physical memory access which goes via PGM will take
    71  * care of it by calling iomR3MmioHandler via the PGM access handler machinery
    72  * - this shouldn't happen but it is an alternative...
    73  *
    74  *
    75  * @section sec_iom_other       Other Accesses
    76  *
    77  * I/O ports aren't really exposed in any other way, unless you count the
    78  * instruction interpreter in EM, but that's just what we're doing in the
    79  * raw-mode \#GP(0) case really. Now, it's possible to call IOMIOPortRead and
    80  * IOMIOPortWrite directly to talk to a device, but this is really bad behavior
    81  * and should only be done as temporary hacks (the PC BIOS device used to setup
    82  * 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 used
    85  * for the same reasons and with the same restrictions. OTOH since MMIO is
    86  * mapped into the physical memory address space, it can be accessed in a number
    87  * of ways thru PGM.
    88  *
    89  *
    90  * @section sec_iom_logging     Logging Levels
    91  *
    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 known
    99  *   registers.
    100  * -
    101  *
    102  *   */
    103 
    104 
    10519/*********************************************************************************************************************************
    10620*   Header Files                                                                                                                 *
     
    10822#define LOG_GROUP LOG_GROUP_IOM
    10923#include <VBox/vmm/iom.h>
    110 #include <VBox/vmm/cpum.h>
    111 #include <VBox/vmm/pgm.h>
    11224#include <VBox/sup.h>
    113 #include <VBox/vmm/hm.h>
    11425#include <VBox/vmm/mm.h>
    11526#include <VBox/vmm/stam.h>
     
    12233#include <VBox/param.h>
    12334#include <iprt/assert.h>
    124 #include <iprt/alloc.h>
    12535#include <iprt/string.h>
    12636#include <VBox/log.h>
     
    13040
    13141
    132 /*********************************************************************************************************************************
    133 *   Internal Functions                                                                                                           *
    134 *********************************************************************************************************************************/
    135 static void iomR3FlushCache(PVM pVM);
    136 #if 0
    137 static DECLCALLBACK(int) iomR3RelocateIOPortCallback(PAVLROIOPORTNODECORE pNode, void *pvUser);
    138 static DECLCALLBACK(int) iomR3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser);
    139 #endif
    14042#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 */
     47void 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
    20578        {
    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;
    24681        }
    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 */
     122static 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 */
     140static DECLCALLBACK(VBOXSTRICTRC)
     141iomR3IOPortDummyNewIn(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    }
    280153    return VINF_SUCCESS;
    281154}
     
    283156
    284157/**
    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 */
     161static DECLCALLBACK(VBOXSTRICTRC)
     162iomR3IOPortDummyNewInStr(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);
    450165    return VINF_SUCCESS;
    451166}
     167
     168
     169/**
     170 * @callback_method_impl{FNIOMIOPORTNEWOUT,
     171 *      Dummy Port I/O Handler for OUT operations.}
     172 */
     173static DECLCALLBACK(VBOXSTRICTRC)
     174iomR3IOPortDummyNewOut(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 */
     185static DECLCALLBACK(VBOXSTRICTRC)
     186iomR3IOPortDummyNewOutStr(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
    452192
    453193
     
    785525}
    786526
    787 #ifdef VBOX_WITH_STATISTICS
    788 
    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     else
    806         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     do
    814     {
    815         size_t cchBaseNm;
    816         if (uFirstPort < uEndPort - 1)
    817             cchBaseNm = cchPrefix + RTStrPrintf(&szName[cchPrefix], sizeof(szName) - cchPrefix, "/%04x-", uPort);
    818         else
    819         {
    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     else
    870         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_STATISTICS
    876 
    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 register
    993  * 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)PortStart
    1021         ||  (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_STATISTICS
    1069             for (unsigned iPort = 0; iPort < cPorts; iPort++)
    1070                 iomR3IOPortStatsCreate(pVM, PortStart + iPort, pszDesc);
    1071 #endif
    1072             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 0
    1089 /**
    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 ranges
    1093  * 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)PortStart
    1121         ||  (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_CHECKS
    1149         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 #endif
    1156         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 #endif
    1199 
    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 ranges
    1205  * 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)PortStart
    1233         ||  (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_CHECKS
    1261         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 #endif
    1268         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 to
    1316  * this call. The range does can be a smaller part of the range specified to
    1317  * 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 do
    1329  *          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)PortStart
    1339         ||  (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_CHECKS
    1362             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 0
    1378     /*
    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     == Port
    1392                 && 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             else
    1423             {
    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 #else
    1461     int rc = VINF_SUCCESS;
    1462 #endif
    1463 
    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     == Port
    1477                 && 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             else
    1508             {
    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     == Port
    1559                 && 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             else
    1590             {
    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 
    1759527
    1760528/**
     
    1782550
    1783551
    1784 #if 0
    1785 /**
    1786  * Display a single I/O port GC range.
    1787  *
    1788  * @returns 0
    1789  * @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 #endif
    1808 
    1809 
    1810552/**
    1811553 * Display all registered I/O port ranges.
     
    1815557 * @param   pszArgs     Arguments, ignored.
    1816558 */
    1817 static DECLCALLBACK(void) iomR3IOPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
     559DECLCALLBACK(void) iomR3IoPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
    1818560{
    1819561    /* No locking needed here as registerations are only happening during VMSTATE_CREATING. */
     
    1869611}
    1870612
    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 ranges
    1876  * 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_QWORD
    1907                     && (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 0
    1976 /**
    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 ranges
    1980  * 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  EMT
    1994  */
    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 #endif
    2034 
    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 ranges
    2040  * 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  EMT
    2054  */
    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 do
    2108  *          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, PGMR3PhysMMIOExDeregister
    2192  *
    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 multiple
    2199  *                              of X86_PAGE_SIZE
    2200  * @param   fFlags              Flags, see IOMMMIO_FLAGS_XXX.
    2201  * @param   pszDesc             Pointer to description string. This must not be
    2202  *                              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 be
    2212  *                              relocated with the hypervisor guest mapping if
    2213  *                              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_QWORD
    2249                     && (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 0
    2286         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 #else
    2295         RT_NOREF(pfnReadCallbackRC, pfnWriteCallbackRC, pfnFillCallbackRC, pvUserRC);
    2296 #endif
    2297 
    2298         /*
    2299          * Try register it with PGM.  PGM will call us back when it's mapped in
    2300          * 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 into
    2318  * 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 unmapped
    2354  * 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     else
    2378     {
    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 into
    2390  * 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 merge
    2410  *                          with @a rcStrict.
    2411  * @param   rcIom           For logging purposes only.
    2412  * @param   pVCpu           The cross context virtual CPU structure of the
    2413  *                          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 merge
    2443  *                          with @a rcStrict.
    2444  * @param   rcIom           Either VINF_IOM_R3_IOPORT_COMMIT_WRITE or
    2445  *                          VINF_IOM_R3_MMIO_COMMIT_WRITE.
    2446  * @param   pVCpu           The cross context virtual CPU structure of the
    2447  *                          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_FIRST
    2460                   && rcStrict <= VINF_EM_LAST))
    2461     {
    2462         if (RT_LIKELY(   rcStrictCommit >= VINF_EM_FIRST
    2463                       && 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, so
    2482  *          we're very likely to see @a rcStrict set to
    2483  *          VINF_IOM_R3_IOPORT_COMMIT_WRITE and VINF_IOM_R3_MMIO_COMMIT_WRITE
    2484  *          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 to
    2508          *        involve PGM here since we never know if the MMIO area is still mapped
    2509          *        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 MMIO
    2523  * breakpoints has change.
    2524  *
    2525  * For performance reasons, IOM will only call DBGF before doing I/O and MMIO
    2526  * 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 0
    2559  * @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 0
    2585     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 #endif
    2594     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_STATISTICS
    2624 /**
    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  
    333333static DECLCALLBACK(int) pdmR3DevHlp_MmioCreateEx(PPDMDEVINS pDevIns, RTGCPHYS cbRegion,
    334334                                                  uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion,
    335                                                   PFNIOMMMIOWRITE pfnWrite, PFNIOMMMIOREAD pfnRead, PFNIOMMMIOFILL pfnFill,
     335                                                  PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill,
    336336                                                  void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion)
    337337{
    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;
    340351}
    341352
     
    344355static DECLCALLBACK(int) pdmR3DevHlp_MmioMap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys)
    345356{
    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;
    348366}
    349367
     
    352370static DECLCALLBACK(int) pdmR3DevHlp_MmioUnmap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)
    353371{
    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;
    356381}
    357382
     
    360385static DECLCALLBACK(int) pdmR3DevHlp_MmioReduce(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion)
    361386{
    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;
    364397}
    365398
  • trunk/src/VBox/VMM/include/IOMInternal.h

    r81136 r81156  
    657657#ifdef IN_RING3
    658658PIOMMMIOSTATS       iomR3MMIOStatsCreate(PVM pVM, RTGCPHYS GCPhys, const char *pszDesc);
     659DECLCALLBACK(void)  iomR3IoPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
     660void                iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry);
    659661#endif /* IN_RING3 */
    660662
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette