VirtualBox

Changeset 81660 in vbox


Ignore:
Timestamp:
Nov 4, 2019 9:46:54 PM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
134420
Message:

Virtio_1_0,DevVirtioScsi: More common virtio code cleanups. bugref:9218 bugref:9440

Location:
trunk/src/VBox/Devices
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp

    r81658 r81660  
    8181
    8282#define VIRTIOSCSI_REQ_QUEUE_CNT                    1           /**< T.B.D. Consider increasing                      */
    83 #define VIRTIOSCSI_QUEUE_CNT                        VIRTIOSCSI_REQ_QUEUE_CNT + 2
     83#define VIRTIOSCSI_QUEUE_CNT                        (VIRTIOSCSI_REQ_QUEUE_CNT + 2)
    8484#define VIRTIOSCSI_MAX_LUN                          256         /**< VirtIO specification, section 5.6.4             */
    8585#define VIRTIOSCSI_MAX_COMMANDS_PER_LUN             128         /**< T.B.D. What is a good value for this?           */
     
    394394} VIRTIOSCSITARGET, *PVIRTIOSCSITARGET;
    395395
     396
     397/** Why we're quiescing. */
     398typedef enum VIRTIOSCSIQUIESCINGFOR
     399{
     400    kvirtIoScsiQuiescingForInvalid = 0,
     401    kvirtIoScsiQuiescingForReset,
     402    kvirtIoScsiQuiescingForSuspend,
     403    kvirtIoScsiQuiescingForPowerOff,
     404    kvirtIoScsiQuiescingFor32BitHack = 0x7fffffff
     405} VIRTIOSCSIQUIESCINGFOR;
     406
     407
    396408/**
    397409 * PDM instance data (state) for VirtIO Host SCSI device
     
    492504    /** True if in the process of quiescing I/O */
    493505    uint32_t                        fQuiescing;
     506    /** For which purpose we're quiescing. */
     507    VIRTIOSCSIQUIESCINGFOR          enmQuiescingFor;
    494508
    495509} VIRTIOSCSI, *PVIRTIOSCSI;
     
    663677
    664678    PVIRTIO_DESC_CHAIN_T pDescChain;
    665     virtioQueueGet(&pThis->Virtio, EVENTQ_IDX, &pDescChain, true);
     679    virtioR3QueueGet(&pThis->Virtio, EVENTQ_IDX, &pDescChain, true);
    666680
    667681    RTSGBUF reqSegBuf;
     
    669683    RTSgBufInit(&reqSegBuf, aReqSegs, RT_ELEMENTS(aReqSegs));
    670684
    671     virtioQueuePut( &pThis->Virtio, EVENTQ_IDX, &reqSegBuf, pDescChain, true);
     685    virtioR3QueuePut( &pThis->Virtio, EVENTQ_IDX, &reqSegBuf, pDescChain, true);
    672686    virtioQueueSync(&pThis->Virtio, EVENTQ_IDX);
    673687
     
    719733        pRespHdr->uResponse = VIRTIOSCSI_S_RESET;
    720734
    721     virtioQueuePut(&pThis->Virtio, qIdx, &reqSegBuf, pDescChain, true /* fFence */);
     735    virtioR3QueuePut(&pThis->Virtio, qIdx, &reqSegBuf, pDescChain, true /* fFence */);
    722736    virtioQueueSync(&pThis->Virtio, qIdx);
    723737
     
    875889
    876890
    877         virtioQueuePut(&pThis->Virtio, pReq->qIdx, &reqSegBuf, pReq->pDescChain, true /* fFence TBD */);
     891        virtioR3QueuePut(&pThis->Virtio, pReq->qIdx, &reqSegBuf, pReq->pDescChain, true /* fFence TBD */);
    878892        virtioQueueSync(&pThis->Virtio, pReq->qIdx);
    879893
     
    14171431
    14181432    LogFunc(("Response code: %s\n", virtioGetReqRespText(bResponse)));
    1419     virtioQueuePut( &pThis->Virtio, qIdx, &reqSegBuf, pDescChain, true);
     1433    virtioR3QueuePut( &pThis->Virtio, qIdx, &reqSegBuf, pDescChain, true);
    14201434    virtioQueueSync(&pThis->Virtio, qIdx);
    14211435
     
    14761490             Log6Func(("fetching next descriptor chain from %s\n", QUEUENAME(qIdx)));
    14771491             PVIRTIO_DESC_CHAIN_T pDescChain;
    1478              int rc = virtioQueueGet(&pThis->Virtio, qIdx, &pDescChain, true);
     1492             int rc = virtioR3QueueGet(&pThis->Virtio, qIdx, &pDescChain, true);
    14791493             if (rc == VERR_NOT_AVAILABLE)
    14801494             {
     
    20562070static DECLCALLBACK(bool) virtioScsiR3DeviceQuiesced(PPDMDEVINS pDevIns)
    20572071{
    2058     LogFunc(("Device I/O activity quiesced.\n"));
    20592072    PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI);
    2060 
     2073    LogFunc(("Device I/O activity quiesced: enmQuiescingFor=%d\n", pThis->enmQuiescingFor));
     2074
     2075    if (pThis->enmQuiescingFor == kvirtIoScsiQuiescingForReset)
     2076        virtioR3PropagateResetNotification(&pThis->Virtio);
     2077    /** @todo r=bird: Do we need other notifications here for suspend and/or poweroff? */
     2078
     2079    pThis->enmQuiescingFor = kvirtIoScsiQuiescingForInvalid;
    20612080    pThis->fQuiescing = false;
    2062 
    20632081    return true;
    20642082}
     
    20672085 * Worker for virtioScsiR3Reset() and virtioScsiR3SuspendOrPowerOff().
    20682086 */
    2069 static void virtioScsiR3QuiesceDevice(PPDMDEVINS pDevIns)
     2087static void virtioScsiR3QuiesceDevice(PPDMDEVINS pDevIns, VIRTIOSCSIQUIESCINGFOR enmQuiscingFor)
    20702088{
    20712089    PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI);
     
    20732091    /* Prevent worker threads from removing/processing elements from virtq's */
    20742092    pThis->fQuiescing = true;
     2093    pThis->enmQuiescingFor = enmQuiscingFor;
    20752094
    20762095    PDMDevHlpSetAsyncNotification(pDevIns, virtioScsiR3DeviceQuiesced);
     
    20822101
    20832102/**
    2084  * @interface_method_impl{PDMDEVREGR3,pfnResume}
    2085  */
    2086 static DECLCALLBACK(void) virtioScsiR3Resume(PPDMDEVINS pDevIns)
    2087 {
    2088     LogFunc(("\n"));
    2089 
     2103 * Common worker for suspend and power off.
     2104 */
     2105static void virtioScsiR3SuspendOrPowerOff(PPDMDEVINS pDevIns, VIRTIOSCSIQUIESCINGFOR enmQuiscingFor)
     2106{
    20902107    PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI);
    20912108
    2092     pThis->fQuiescing = false;
    2093 
    2094     /* Wake worker threads flagged to skip pulling queue entries during quiesce
    2095      * to ensure they re-check their queues. Active request queues may already
    2096      * be awake due to new reqs coming in.
    2097      */
    2098     for (uint16_t qIdx = 0; qIdx < VIRTIOSCSI_REQ_QUEUE_CNT; qIdx++)
    2099     {
    2100         PVIRTIOSCSIWORKER pWorker = &pThis->aWorkers[qIdx];
    2101 
    2102         if (ASMAtomicReadBool(&pWorker->fSleeping))
    2103         {
    2104             Log6Func(("waking %s worker.\n", QUEUENAME(qIdx)));
    2105             int rc = SUPSemEventSignal(pThis->pSupDrvSession, pWorker->hEvtProcess);
    2106             AssertRC(rc);
    2107         }
    2108     }
    2109 
    2110     /* Ensure guest is working the queues too. */
    2111     virtioPropagateResumeNotification(&pThis->Virtio);
    2112 }
    2113 
    2114 /**
    2115  * @interface_method_impl{PDMDEVREGR3,pfnSuspend}
    2116  */
    2117 static DECLCALLBACK(void) virtioScsiR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
    2118 {
    2119     LogFunc(("\n"));
    2120 
    2121     virtioScsiR3QuiesceDevice(pDevIns);
    2122 
    2123     PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI);
     2109    virtioScsiR3QuiesceDevice(pDevIns, enmQuiscingFor);
     2110
    21242111
    21252112    /* VM is halted, thus no new I/O being dumped into queues by the guest.
     
    21392126
    21402127/**
     2128 * @interface_method_impl{PDMDEVREGR3,pfnPowerOff}
     2129 */
     2130static DECLCALLBACK(void) virtioScsiR3PowerOff(PPDMDEVINS pDevIns)
     2131{
     2132    LogFunc(("\n"));
     2133    virtioScsiR3SuspendOrPowerOff(pDevIns, kvirtIoScsiQuiescingForPowerOff);
     2134}
     2135
     2136/**
     2137 * @interface_method_impl{PDMDEVREGR3,pfnSuspend}
     2138 */
     2139static DECLCALLBACK(void) virtioScsiR3Suspend(PPDMDEVINS pDevIns)
     2140{
     2141    LogFunc(("\n"));
     2142    virtioScsiR3SuspendOrPowerOff(pDevIns, kvirtIoScsiQuiescingForSuspend);
     2143}
     2144
     2145/**
     2146 * @interface_method_impl{PDMDEVREGR3,pfnResume}
     2147 */
     2148static DECLCALLBACK(void) virtioScsiR3Resume(PPDMDEVINS pDevIns)
     2149{
     2150    PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI);
     2151    LogFunc(("\n"));
     2152
     2153    pThis->fQuiescing = false;
     2154
     2155    /* Wake worker threads flagged to skip pulling queue entries during quiesce
     2156     * to ensure they re-check their queues. Active request queues may already
     2157     * be awake due to new reqs coming in.
     2158     */
     2159    for (uint16_t qIdx = 0; qIdx < VIRTIOSCSI_REQ_QUEUE_CNT; qIdx++)
     2160    {
     2161        PVIRTIOSCSIWORKER pWorker = &pThis->aWorkers[qIdx];
     2162
     2163        if (ASMAtomicReadBool(&pWorker->fSleeping))
     2164        {
     2165            Log6Func(("waking %s worker.\n", QUEUENAME(qIdx)));
     2166            int rc = SUPSemEventSignal(pThis->pSupDrvSession, pWorker->hEvtProcess);
     2167            AssertRC(rc);
     2168        }
     2169    }
     2170
     2171    /* Ensure guest is working the queues too. */
     2172    virtioR3PropagateResumeNotification(&pThis->Virtio);
     2173}
     2174
     2175/**
    21412176 * @interface_method_impl{PDMDEVREGR3,pfnReset}
    21422177 */
     
    21462181    PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI);
    21472182    pThis->fResetting = true;
    2148     virtioScsiR3QuiesceDevice(pDevIns);
     2183    virtioScsiR3QuiesceDevice(pDevIns, kvirtIoScsiQuiescingForReset);
     2184
     2185    /** @todo r=bird: Shouldn't you reset the device here?!? */
    21492186}
    21502187
     
    21542191static DECLCALLBACK(int) virtioScsiR3Destruct(PPDMDEVINS pDevIns)
    21552192{
    2156     /*
    2157      * Check the versions here as well since the destructor is *always* called.
    2158      */
    2159 
    21602193    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
    2161 
    2162     PVIRTIOSCSI  pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI);
     2194    PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI);
    21632195
    21642196    RTMemFree(pThis->paTargetInstances);
     
    21732205        }
    21742206    }
    2175      return VINF_SUCCESS;
     2207
     2208    virtioR3Term(&pThis->Virtio, pDevIns);
     2209    return VINF_SUCCESS;
    21762210}
    21772211
     
    22652299        return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi: failed to initialize VirtIO"));
    22662300
     2301    /* Name the queues: */
    22672302    RTStrCopy(pThis->aszQueueNames[CONTROLQ_IDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq");
    22682303    RTStrCopy(pThis->aszQueueNames[EVENTQ_IDX],   VIRTIO_MAX_QUEUE_NAME_SIZE, "eventq");
     
    22712306                    "requestq<%d>", qIdx - VIRTQ_REQ_BASE);
    22722307
     2308    /* Attach the queues and create worker threads for them: */
    22732309    for (uint16_t qIdx = 0; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++)
    22742310    {
    2275         rc = virtioQueueAttach(&pThis->Virtio, qIdx, QUEUENAME(qIdx));
    2276         pThis->afQueueAttached[qIdx] = (rc == VINF_SUCCESS);
     2311        rc = virtioR3QueueAttach(&pThis->Virtio, qIdx, QUEUENAME(qIdx));
     2312        pThis->afQueueAttached[qIdx] = (rc == VINF_SUCCESS); /** @todo r=bird: This looks a bit fishy, esp. giving the following. */
    22772313
    22782314        if (qIdx == CONTROLQ_IDX || IS_REQ_QUEUE(qIdx))
     
    24372473    /* .pfnPowerOn = */             NULL,
    24382474    /* .pfnReset = */               virtioScsiR3Reset,
    2439     /* .pfnSuspend = */             virtioScsiR3SuspendOrPowerOff,
     2475    /* .pfnSuspend = */             virtioScsiR3Suspend,
    24402476    /* .pfnResume = */              virtioScsiR3Resume,
    24412477    /* .pfnAttach = */              virtioScsiR3Attach,
     
    24432479    /* .pfnQueryInterface = */      NULL,
    24442480    /* .pfnInitComplete = */        NULL,
    2445     /* .pfnPowerOff = */            virtioScsiR3SuspendOrPowerOff,
     2481    /* .pfnPowerOff = */            virtioScsiR3PowerOff,
    24462482    /* .pfnSoftReset = */           NULL,
    24472483    /* .pfnReserved0 = */           NULL,
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp

    r81659 r81660  
    275275/** @} */
    276276
     277#ifdef LOG_ENABLED
     278
     279/**
     280 * Does a formatted hex dump using Log(()), recommend using VIRTIO_HEX_DUMP() macro to
     281 * control enabling of logging efficiently.
     282 *
     283 * @param   pv          pointer to buffer to dump contents of
     284 * @param   cb          count of characters to dump from buffer
     285 * @param   uBase       base address of per-row address prefixing of hex output
     286 * @param   pszTitle    Optional title. If present displays title that lists
     287 *                      provided text with value of cb to indicate size next to it.
     288 */
     289void virtioHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle)
     290{
     291    if (pszTitle)
     292        Log(("%s [%d bytes]:\n", pszTitle, cb));
     293    for (uint32_t row = 0; row < RT_MAX(1, (cb / 16) + 1) && row * 16 < cb; row++)
     294    {
     295        Log(("%04x: ", row * 16 + uBase)); /* line address */
     296        for (uint8_t col = 0; col < 16; col++)
     297        {
     298           uint32_t idx = row * 16 + col;
     299           if (idx >= cb)
     300               Log(("-- %s", (col + 1) % 8 ? "" : "  "));
     301           else
     302               Log(("%02x %s", pv[idx], (col + 1) % 8 ? "" : "  "));
     303        }
     304        for (uint32_t idx = row * 16; idx < row * 16 + 16; idx++)
     305           Log(("%c", (idx >= cb) ? ' ' : (pv[idx] >= 0x20 && pv[idx] <= 0x7e ? pv[idx] : '.')));
     306        Log(("\n"));
     307    }
     308    Log(("\n"));
     309    RT_NOREF2(uBase, pv);
     310}
     311
     312/**
     313 * Log memory-mapped I/O input or output value.
     314 *
     315 * This is designed to be invoked by macros that can make contextual assumptions
     316 * (e.g. implicitly derive MACRO parameters from the invoking function). It is exposed
     317 * for the VirtIO client doing the device-specific implementation in order to log in a
     318 * similar fashion accesses to the device-specific MMIO configuration structure. Macros
     319 * that leverage this function are found in virtioCommonCfgAccessed() and can be
     320 * used as an example of how to use this effectively for the device-specific
     321 * code.
     322 *
     323 * @param   pszFunc     To avoid displaying this function's name via __FUNCTION__ or LogFunc()
     324 * @param   pszMember   Name of struct member
     325 * @param   pv          pointer to value
     326 * @param   cb          size of value
     327 * @param   uOffset     offset into member where value starts
     328 * @param   fWrite      True if write I/O
     329 * @param   fHasIndex   True if the member is indexed
     330 * @param   idx         The index if fHasIndex
     331 */
     332void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize,
     333                            const void *pv, uint32_t cb, uint32_t uOffset, int fWrite,
     334                            int fHasIndex, uint32_t idx)
     335{
     336
     337#define FMTHEX(fmtout, val, cNybbles) \
     338    fmtout[cNybbles] = '\0'; \
     339    for (uint8_t i = 0; i < cNybbles; i++) \
     340        fmtout[(cNybbles - i) - 1] = "0123456789abcdef"[(val >> (i * 4)) & 0xf];
     341
     342#define MAX_STRING   64
     343    char pszIdx[MAX_STRING] = { 0 };
     344    char pszDepiction[MAX_STRING] = { 0 };
     345    char pszFormattedVal[MAX_STRING] = { 0 };
     346    if (fHasIndex)
     347        RTStrPrintf(pszIdx, sizeof(pszIdx), "[%d]", idx);
     348    if (cb == 1 || cb == 2 || cb == 4 || cb == 8)
     349    {
     350        /* manually padding with 0's instead of \b due to different impl of %x precision than printf() */
     351        uint64_t val = 0;
     352        memcpy((char *)&val, pv, cb);
     353        FMTHEX(pszFormattedVal, val, cb * 2);
     354        if (uOffset != 0 || cb != uMemberSize) /* display bounds if partial member access */
     355            RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s[%d:%d]",
     356                        pszMember, pszIdx, uOffset, uOffset + cb - 1);
     357        else
     358            RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s", pszMember, pszIdx);
     359        RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%-30s", pszDepiction);
     360        uint32_t first = 0;
     361        for (uint8_t i = 0; i < sizeof(pszDepiction); i++)
     362            if (pszDepiction[i] == ' ' && first++)
     363                pszDepiction[i] = '.';
     364        Log6Func(("%s: Guest %s %s 0x%s\n",
     365                  pszFunc, fWrite ? "wrote" : "read ", pszDepiction, pszFormattedVal));
     366    }
     367    else /* odd number or oversized access, ... log inline hex-dump style */
     368    {
     369        Log6Func(("%s: Guest %s %s%s[%d:%d]: %.*Rhxs\n",
     370                  pszFunc, fWrite ? "wrote" : "read ", pszMember,
     371                  pszIdx, uOffset, uOffset + cb, cb, pv));
     372    }
     373    RT_NOREF2(fWrite, pszFunc);
     374}
     375
     376#endif /* LOG_ENABLED */
    277377
    278378/**
     
    302402}
    303403
     404#ifdef IN_RING3
    304405/**
    305406 * Allocate client context for client to work with VirtIO-provided with queue
     
    311412 * @returns VBox status code.
    312413 */
    313 int virtioQueueAttach(PVIRTIOSTATE pVirtio, uint16_t idxQueue, const char *pcszName)
     414int virtioR3QueueAttach(PVIRTIOSTATE pVirtio, uint16_t idxQueue, const char *pcszName)
    314415{
    315416    LogFunc(("%s\n", pcszName));
     
    321422    return VINF_SUCCESS;
    322423}
     424#endif /* IN_RING3 */
    323425
    324426#if 0 /** @todo r=bird: no prototype or docs for this one  */
     
    360462}
    361463
     464#ifdef IN_RING3
     465
    362466/**
    363467 * Removes descriptor chain from avail ring of indicated queue and converts the descriptor
     
    366470 * Additionally it converts the OUT desc chain data to a contiguous virtual
    367471 * memory buffer for easy consumption by the caller. The caller must return the
    368  * descriptor chain pointer via virtioQueuePut() and then call virtioQueueSync()
     472 * descriptor chain pointer via virtioR3QueuePut() and then call virtioQueueSync()
    369473 * at some point to return the data to the guest and complete the transaction.
    370474 *
     
    380484 * @retval  VERR_NOT_AVAILABLE   If the queue is empty.
    381485 */
    382 int virtioQueueGet(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PPVIRTIO_DESC_CHAIN_T ppDescChain,  bool fRemove)
     486int virtioR3QueueGet(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PPVIRTIO_DESC_CHAIN_T ppDescChain,  bool fRemove)
    383487{
    384488    AssertReturn(ppDescChain, VERR_INVALID_PARAMETER);
     
    512616 * @retval  VERR_NOT_AVAILABLE Queue is empty
    513617 */
    514 int virtioQueuePut(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn,
    515                    PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence)
     618int virtioR3QueuePut(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn,
     619                     PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence)
    516620{
    517621    Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));
     
    578682}
    579683
     684#endif /* IN_RING3 */
     685
    580686/**
    581687 * Updates the indicated virtq's "used ring" descriptor index to match the
    582688 * current write-head index, thus exposing the data added to the used ring by all
    583  * virtioQueuePut() calls since the last sync. This should be called after one or
     689 * virtioR3QueuePut() calls since the last sync. This should be called after one or
    584690 * more virtQueuePut() calls to inform the guest driver there is data in the queue.
    585691 * Explicit notifications (e.g. interrupt or MSI-X) will be sent to the guest,
     
    612718}
    613719
    614 /**
    615  */
    616 static void virtioQueueNotified(PVIRTIOSTATE pVirtio, uint16_t idxQueue, uint16_t uNotifyIdx)
     720#ifdef IN_RING3
     721/**
     722 */
     723static void virtior3QueueNotified(PVIRTIOSTATE pVirtio, uint16_t idxQueue, uint16_t uNotifyIdx)
    617724{
    618725    /* See VirtIO 1.0, section 4.1.5.2 It implies that idxQueue and uNotifyIdx should match.
     
    636743    pVirtio->Callbacks.pfnQueueNotified(pVirtio, idxQueue);
    637744}
    638 
    639 /**
    640  * This sends notification ('kicks') guest driver to check queues for any new
    641  * elements in the used queue to process.
    642  *
    643  * It should be called after resuming in case anything was added to the queues
    644  * during suspend/quiescing and a notification was missed, to prevent the guest
    645  * from stalling after suspend.
    646  */
    647 void virtioPropagateResumeNotification(PVIRTIOSTATE pVirtio)
    648 {
    649     virtioNotifyGuestDriver(pVirtio, (uint16_t)0 /* idxQueue */, true /* fForce */);
    650 }
     745#endif /* IN_RING3 */
    651746
    652747/**
     
    703798static int virtioKick(PVIRTIOSTATE pVirtio, uint8_t uCause, uint16_t uMsixVector, bool fForce)
    704799{
    705 
    706800   if (fForce)
    707801       Log6Func(("reason: resumed after suspend\n"));
     
    770864}
    771865
     866#if 0 /** @todo r=bird: Probably not needed. */
    772867/**
    773868 * Enable or disable queue
     
    784879        pVirtio->uQueueSize[idxQueue] = 0;
    785880}
    786 
     881#endif
     882
     883#if 0 /** @todo r=bird: This isn't invoked by anyone. Why? */
    787884/**
    788885 * Initiate orderly reset procedure.
     
    799896    }
    800897}
    801 
     898#endif
     899
     900#ifdef IN_RING3
    802901/**
    803902 * Invoked by this implementation when guest driver resets the device.
    804903 * The driver itself will not  until the device has read the status change.
    805904 */
    806 static void virtioGuestResetted(PVIRTIOSTATE pVirtio)
     905static void virtioGuestR3Resetted(PVIRTIOSTATE pVirtio)
    807906{
    808907    LogFunc(("Guest reset the device\n"));
     
    812911    virtioResetDevice(pVirtio);
    813912}
     913#endif /* IN_RING3 */
    814914
    815915/**
     
    824924 * @param   pv          Pointer to location to write to or read from
    825925 */
    826 static int virtioCommonCfgAccessed(PVIRTIOSTATE pVirtio, int fWrite, off_t offCfg, unsigned cb, void const *pv)
     926static int virtioCommonCfgAccessed(PVIRTIOSTATE pVirtio, int fWrite, off_t offCfg, unsigned cb, void *pv)
    827927{
    828928/**
     
    845945         && cb == RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member)) )
    846946
    847 #define LOG_COMMON_CFG_ACCESS(member) \
     947#ifdef LOG_ENABLED
     948# define LOG_COMMON_CFG_ACCESS(member, a_offIntra) \
    848949    virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \
    849                            pv, cb, uIntraOff, fWrite, false, 0);
    850 
    851 #define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx) \
     950                           pv, cb, a_offIntra, fWrite, false, 0);
     951# define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, a_offIntra) \
    852952    virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \
    853                            pv, cb, uIntraOff, fWrite, true, idx);
     953                           pv, cb, a_offIntra, fWrite, true, idx);
     954#else
     955# define LOG_COMMON_CFG_ACCESS(member, a_offIntra)              do { } while (0)
     956# define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, a_offIntra) do { } while (0)
     957#endif
    854958
    855959#define COMMON_CFG_ACCESSOR(member) \
    856960    do \
    857961    { \
    858         uint32_t uIntraOff = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
     962        uint32_t offIntra = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
    859963        if (fWrite) \
    860             memcpy(((char *)&pVirtio->member) + uIntraOff, (const char *)pv, cb); \
     964            memcpy((char *)&pVirtio->member + offIntra, (const char *)pv, cb); \
    861965        else \
    862             memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + uIntraOff), cb); \
    863         LOG_COMMON_CFG_ACCESS(member); \
     966            memcpy(pv, (const char *)&pVirtio->member + offIntra, cb); \
     967        LOG_COMMON_CFG_ACCESS(member, offIntra); \
    864968    } while(0)
    865969
     
    867971    do \
    868972    { \
    869         uint32_t uIntraOff = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
     973        uint32_t offIntra = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
    870974        if (fWrite) \
    871             memcpy(((char *)(pVirtio->member + idx)) + uIntraOff, (const char *)pv, cb); \
     975            memcpy(((char *)(pVirtio->member + idx)) + offIntra, (const char *)pv, cb); \
    872976        else \
    873             memcpy((char *)pv, (const char *)(((char *)(pVirtio->member + idx)) + uIntraOff), cb); \
    874         LOG_COMMON_CFG_ACCESS_INDEXED(member, idx); \
     977            memcpy((char *)pv, (const char *)(((char *)(pVirtio->member + idx)) + offIntra), cb); \
     978        LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, offIntra); \
    875979    } while(0)
    876980
     
    878982    do \
    879983    { \
    880         uint32_t uIntraOff = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
     984        uint32_t offIntra = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
    881985        if (fWrite) \
    882986            LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s\n", #member)); \
    883987        else \
    884988        { \
    885             memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + uIntraOff), cb); \
    886             LOG_COMMON_CFG_ACCESS(member); \
     989            memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + offIntra), cb); \
     990            LOG_COMMON_CFG_ACCESS(member, offIntra); \
    887991        } \
    888992    } while(0)
     
    891995    do \
    892996    { \
    893         uint32_t uIntraOff = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
     997        uint32_t offIntra = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
    894998        if (fWrite) \
    895999            LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s[%d]\n", #member, idx)); \
    8961000        else \
    8971001        { \
    898             memcpy((char *)pv, ((char *)(pVirtio->member + idx)) + uIntraOff, cb); \
    899             LOG_COMMON_CFG_ACCESS_INDEXED(member, idx); \
     1002            memcpy((char *)pv, ((char *)(pVirtio->member + idx)) + offIntra, cb); \
     1003            LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, offIntra); \
    9001004        } \
    9011005    } while(0)
     
    9131017        else /* Guest READ pCommonCfg->uDeviceFeatures */
    9141018        {
    915             uint32_t uIntraOff = offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDeviceFeatures);
    9161019            switch (pVirtio->uDeviceFeaturesSelect)
    9171020            {
    9181021                case 0:
    9191022                    val = pVirtio->uDeviceFeatures & UINT32_C(0xffffffff);
    920                     memcpy((void *)pv, (const void *)&val, cb);
    921                     LOG_COMMON_CFG_ACCESS(uDeviceFeatures);
     1023                    memcpy(pv, &val, cb);
     1024                    LOG_COMMON_CFG_ACCESS(uDeviceFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDeviceFeatures));
    9221025                    break;
    9231026                case 1:
    9241027                    val = pVirtio->uDeviceFeatures >> 32;
    925                     uIntraOff += 4;
    926                     memcpy((void *)pv, (const void *)&val, cb);
    927                     LOG_COMMON_CFG_ACCESS(uDeviceFeatures);
     1028                    memcpy(pv, &val, cb);
     1029                    LOG_COMMON_CFG_ACCESS(uDeviceFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDeviceFeatures) + 4);
    9281030                    break;
    9291031                default:
     
    9381040        if (fWrite) /* Guest WRITE pCommonCfg->udriverFeatures */
    9391041        {
    940             uint32_t uIntraOff = offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures);
    9411042            switch (pVirtio->uDriverFeaturesSelect)
    9421043            {
    9431044                case 0:
    9441045                    memcpy(&pVirtio->uDriverFeatures, pv, cb);
    945                     LOG_COMMON_CFG_ACCESS(uDriverFeatures);
     1046                    LOG_COMMON_CFG_ACCESS(uDriverFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures));
    9461047                    break;
    9471048                case 1:
    948                     memcpy(((char *)&pVirtio->uDriverFeatures) + sizeof(uint32_t), pv, cb);
    949                     uIntraOff += 4;
    950                     LOG_COMMON_CFG_ACCESS(uDriverFeatures);
     1049                    memcpy((char *)&pVirtio->uDriverFeatures + sizeof(uint32_t), pv, cb);
     1050                    LOG_COMMON_CFG_ACCESS(uDriverFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures) + 4);
    9511051                    break;
    9521052                default:
     
    9581058        else /* Guest READ pCommonCfg->udriverFeatures */
    9591059        {
    960             uint32_t uIntraOff = offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures);
    9611060            switch (pVirtio->uDriverFeaturesSelect)
    9621061            {
    9631062                case 0:
    9641063                    val = pVirtio->uDriverFeatures & 0xffffffff;
    965                     memcpy((void *)pv, (const void *)&val, cb);
    966                     LOG_COMMON_CFG_ACCESS(uDriverFeatures);
     1064                    memcpy(pv, &val, cb);
     1065                    LOG_COMMON_CFG_ACCESS(uDriverFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures));
    9671066                    break;
    9681067                case 1:
    9691068                    val = (pVirtio->uDriverFeatures >> 32) & 0xffffffff;
    970                     uIntraOff += 4;
    971                     memcpy((void *)pv, (const void *)&val, cb);
    972                     LOG_COMMON_CFG_ACCESS(uDriverFeatures);
     1069                    memcpy(pv, &val, cb);
     1070                    LOG_COMMON_CFG_ACCESS(uDriverFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures) + 4);
    9731071                    break;
    9741072                default:
     
    9881086        else
    9891087        {
    990             uint32_t uIntraOff = 0;
    9911088            *(uint16_t *)pv = VIRTQ_MAX_CNT;
    992             LOG_COMMON_CFG_ACCESS(uNumQueues);
     1089            LOG_COMMON_CFG_ACCESS(uNumQueues, 0);
    9931090        }
    9941091    }
     
    10021099            Log6((")\n"));
    10031100            if (pVirtio->uDeviceStatus == 0)
    1004                 virtioGuestResetted(pVirtio);
    1005             /**
     1101                virtioGuestR3Resetted(pVirtio);
     1102            /*
    10061103             * Notify client only if status actually changed from last time.
    10071104             */
    1008             uint32_t fOkayNow = pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK;
    1009             uint32_t fWasOkay = pVirtio->uPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK;
    1010             uint32_t fDrvOk = pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK;
    1011             if ((fOkayNow && !fWasOkay) || (!fOkayNow && fWasOkay))
    1012                 pVirtio->Callbacks.pfnStatusChanged(pVirtio, fDrvOk);
     1105            uint32_t const fOkayNow = pVirtio->uDeviceStatus     & VIRTIO_STATUS_DRIVER_OK;
     1106            uint32_t const fWasOkay = pVirtio->uPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK;
     1107            if (fOkayNow != fWasOkay)
     1108                pVirtio->Callbacks.pfnStatusChanged(pVirtio, fOkayNow);
    10131109            pVirtio->uPrevDeviceStatus = pVirtio->uDeviceStatus;
    10141110        }
     
    10161112        {
    10171113            Log6Func(("Guest read  uDeviceStatus ................ ("));
    1018             *(uint32_t *)pv = pVirtio->uDeviceStatus;
     1114            *(uint32_t *)pv = pVirtio->uDeviceStatus;   /** @todo r=bird: Why 32-bit write here, the field is 8-bit? */
    10191115            virtioLogDeviceStatus(pVirtio->uDeviceStatus);
    10201116            Log6((")\n"));
     
    11271223    {
    11281224        uint32_t uOffset = GCPhysAddr - pVirtio->GCPhysCommonCfg;
    1129         rc = virtioCommonCfgAccessed(pVirtio, false /* fWrite */, uOffset, cb, (void const *)pv);
     1225        rc = virtioCommonCfgAccessed(pVirtio, false /* fWrite */, uOffset, cb, pv);
    11301226    }
    11311227    else
     
    11801276    {
    11811277        uint32_t uOffset = GCPhysAddr - pVirtio->GCPhysCommonCfg;
    1182         (void)virtioCommonCfgAccessed(pVirtio, true /* fWrite */, uOffset, cb, pv);
     1278        (void)virtioCommonCfgAccessed(pVirtio, true /* fWrite */, uOffset, cb, (void *)pv);
    11831279    }
    11841280    else
     
    11991295        uint16_t uAvailDescIdx = *(uint16_t *)pv;
    12001296
    1201         virtioQueueNotified(pVirtio, idxQueue, uAvailDescIdx);
     1297        virtior3QueueNotified(pVirtio, idxQueue, uAvailDescIdx);
    12021298    }
    12031299    else
     
    12091305    return VINF_SUCCESS;
    12101306}
     1307
     1308#ifdef IN_RING3
    12111309
    12121310/**
     
    13221420}
    13231421
    1324 /**
    1325  * Get VirtIO accepted host-side features
    1326  *
    1327  * @returns feature bits selected or 0 if selector out of range.
    1328  *
    1329  * @param   pState          Virtio state
    1330  */
    1331 uint64_t virtioGetAcceptedFeatures(PVIRTIOSTATE pVirtio)
    1332 {
    1333     return pVirtio->uDriverFeatures;
    1334 }
    1335 
    1336 /**
    1337  * Destruct PCI-related part of device.
    1338  *
    1339  * We need to free non-VM resources only.
    1340  *
     1422
     1423/*********************************************************************************************************************************
     1424*   Saved state.                                                                                                                 *
     1425*********************************************************************************************************************************/
     1426
     1427/**
     1428 * Called from the FNSSMDEVSAVEEXEC function of the device.
     1429 *
     1430 * @param   pVirtio     Pointer to the virtio state.
     1431 * @param   pHlp        The ring-3 device helpers.
     1432 * @param   pSSM        The saved state handle.
    13411433 * @returns VBox status code.
    1342  * @param   pState      The device state structure.
    1343  */
    1344 int virtioDestruct(PVIRTIOSTATE pVirtio)
    1345 {
     1434 */
     1435int virtioR3SaveExec(PVIRTIOSTATE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
     1436{
     1437    pHlp->pfnSSMPutU64(pSSM, VIRTIO_SAVEDSTATE_MARKER);
     1438    pHlp->pfnSSMPutU32(pSSM, VIRTIO_SAVEDSTATE_VERSION);
     1439
     1440    pHlp->pfnSSMPutBool(pSSM,   pVirtio->fGenUpdatePending);
     1441    pHlp->pfnSSMPutU8(pSSM,     pVirtio->uDeviceStatus);
     1442    pHlp->pfnSSMPutU8(pSSM,     pVirtio->uConfigGeneration);
     1443    pHlp->pfnSSMPutU8(pSSM,     pVirtio->uPciCfgDataOff);
     1444    pHlp->pfnSSMPutU8(pSSM,     pVirtio->uISR);
     1445    pHlp->pfnSSMPutU16(pSSM,    pVirtio->uQueueSelect);
     1446    pHlp->pfnSSMPutU32(pSSM,    pVirtio->uDeviceFeaturesSelect);
     1447    pHlp->pfnSSMPutU32(pSSM,    pVirtio->uDriverFeaturesSelect);
     1448    pHlp->pfnSSMPutU64(pSSM,    pVirtio->uDriverFeatures);
     1449    Assert(pVirtio->uNumQueues == VIRTQ_MAX_CNT); /** @todo r=bird: See todo in struct & virtioR3LoadExec. */
     1450    pHlp->pfnSSMPutU32(pSSM,    pVirtio->uNumQueues);
     1451
     1452    for (uint32_t i = 0; i < pVirtio->uNumQueues; i++)
     1453    {
     1454        pHlp->pfnSSMPutGCPhys64(pSSM, pVirtio->aGCPhysQueueDesc[i]);
     1455        pHlp->pfnSSMPutGCPhys64(pSSM, pVirtio->aGCPhysQueueAvail[i]);
     1456        pHlp->pfnSSMPutGCPhys64(pSSM, pVirtio->aGCPhysQueueUsed[i]);
     1457        pHlp->pfnSSMPutU16(pSSM,      pVirtio->uQueueNotifyOff[i]);
     1458        pHlp->pfnSSMPutU16(pSSM,      pVirtio->uQueueMsixVector[i]);
     1459        pHlp->pfnSSMPutU16(pSSM,      pVirtio->uQueueEnable[i]);
     1460        pHlp->pfnSSMPutU16(pSSM,      pVirtio->uQueueSize[i]);
     1461        pHlp->pfnSSMPutU16(pSSM,      pVirtio->virtqState[i].uAvailIdx);
     1462        pHlp->pfnSSMPutU16(pSSM,      pVirtio->virtqState[i].uUsedIdx);
     1463        int rc = pHlp->pfnSSMPutMem(pSSM, pVirtio->virtqState[i].szVirtqName, 32);
     1464        AssertRCReturn(rc, rc);
     1465    }
     1466
     1467    return VINF_SUCCESS;
     1468}
     1469
     1470/**
     1471 * Called from the FNSSMDEVLOADEXEC function of the device.
     1472 *
     1473 * @param   pVirtio     Pointer to the virtio state.
     1474 * @param   pHlp        The ring-3 device helpers.
     1475 * @param   pSSM        The saved state handle.
     1476 * @returns VBox status code.
     1477 */
     1478int virtioR3LoadExec(PVIRTIOSTATE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
     1479{
     1480    /*
     1481     * Check the marker and (embedded) version number.
     1482     */
     1483    uint64_t uMarker = 0;
     1484    int rc = pHlp->pfnSSMGetU64(pSSM, &uMarker);
     1485    AssertRCReturn(rc, rc);
     1486    if (uMarker != VIRTIO_SAVEDSTATE_MARKER)
     1487        return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
     1488                                        N_("Expected marker value %#RX64 found %#RX64 instead"),
     1489                                        VIRTIO_SAVEDSTATE_MARKER, uMarker);
     1490    uint32_t uVersion = 0;
     1491    rc = pHlp->pfnSSMGetU32(pSSM, &uVersion);
     1492    AssertRCReturn(rc, rc);
     1493    if (uVersion != VIRTIO_SAVEDSTATE_VERSION)
     1494        return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
     1495                                        N_("Unsupported virtio version: %u"), uVersion);
     1496
     1497    /*
     1498     * Load the state.
     1499     */
     1500    pHlp->pfnSSMGetBool(pSSM, &pVirtio->fGenUpdatePending);
     1501    pHlp->pfnSSMGetU8(pSSM,   &pVirtio->uDeviceStatus);
     1502    pHlp->pfnSSMGetU8(pSSM,   &pVirtio->uConfigGeneration);
     1503    pHlp->pfnSSMGetU8(pSSM,   &pVirtio->uPciCfgDataOff);
     1504    pHlp->pfnSSMGetU8(pSSM,   &pVirtio->uISR);
     1505    pHlp->pfnSSMGetU16(pSSM,  &pVirtio->uQueueSelect);
     1506    pHlp->pfnSSMGetU32(pSSM,  &pVirtio->uDeviceFeaturesSelect);
     1507    pHlp->pfnSSMGetU32(pSSM,  &pVirtio->uDriverFeaturesSelect);
     1508    pHlp->pfnSSMGetU64(pSSM,  &pVirtio->uDriverFeatures);
     1509
     1510    /* Make sure the queue count is within expectations. */
     1511    /** @todo r=bird: Turns out the expectations are exactly VIRTQ_MAX_CNT, bug? */
     1512    rc = pHlp->pfnSSMGetU32(pSSM, &pVirtio->uNumQueues);
     1513    AssertRCReturn(rc, rc);
     1514    AssertReturn(pVirtio->uNumQueues == VIRTQ_MAX_CNT,
     1515                 pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
     1516                                          N_("Saved queue count %u, expected %u"), uVersion, VIRTQ_MAX_CNT));
     1517    AssertCompile(RT_ELEMENTS(pVirtio->virtqState) == VIRTQ_MAX_CNT);
     1518    AssertCompile(RT_ELEMENTS(pVirtio->aGCPhysQueueDesc) == VIRTQ_MAX_CNT);
     1519
     1520    for (uint32_t idxQueue = 0; idxQueue < pVirtio->uNumQueues; idxQueue++)
     1521    {
     1522        pHlp->pfnSSMGetGCPhys64(pSSM, &pVirtio->aGCPhysQueueDesc[idxQueue]);
     1523        pHlp->pfnSSMGetGCPhys64(pSSM, &pVirtio->aGCPhysQueueAvail[idxQueue]);
     1524        pHlp->pfnSSMGetGCPhys64(pSSM, &pVirtio->aGCPhysQueueUsed[idxQueue]);
     1525        pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueNotifyOff[idxQueue]);
     1526        pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueMsixVector[idxQueue]);
     1527        pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueEnable[idxQueue]);
     1528        pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueSize[idxQueue]);
     1529        pHlp->pfnSSMGetU16(pSSM, &pVirtio->virtqState[idxQueue].uAvailIdx);
     1530        pHlp->pfnSSMGetU16(pSSM, &pVirtio->virtqState[idxQueue].uUsedIdx);
     1531        pHlp->pfnSSMGetMem(pSSM,  pVirtio->virtqState[idxQueue].szVirtqName, sizeof(pVirtio->virtqState[idxQueue].szVirtqName));
     1532    }
     1533
     1534    return VINF_SUCCESS;
     1535}
     1536
     1537
     1538/*********************************************************************************************************************************
     1539*   Device Level                                                                                                                 *
     1540*********************************************************************************************************************************/
     1541
     1542/**
     1543 * This should be called from PDMDEVREGR3::pfnReset.
     1544 *
     1545 * @param   pVirtio     Pointer to the virtio state.
     1546 */
     1547void virtioR3PropagateResetNotification(PVIRTIOSTATE pVirtio)
     1548{
     1549    /** @todo r=bird: You probably need to do something here.  See
     1550     *        virtioScsiR3Reset. */
    13461551    RT_NOREF(pVirtio);
    1347     Log(("%s Destroying PCI instance\n", INSTANCE(pVirtio)));
    1348     return VINF_SUCCESS;
    1349 }
    1350 
    1351 /**
    1352  * Called by device destructor.
     1552}
     1553
     1554
     1555/**
     1556 * This sends notification ('kicks') guest driver to check queues for any new
     1557 * elements in the used queue to process.
     1558 *
     1559 * It should be called after resuming in case anything was added to the queues
     1560 * during suspend/quiescing and a notification was missed, to prevent the guest
     1561 * from stalling after suspend.
     1562 */
     1563void virtioR3PropagateResumeNotification(PVIRTIOSTATE pVirtio)
     1564{
     1565    virtioNotifyGuestDriver(pVirtio, (uint16_t)0 /* idxQueue */, true /* fForce */);
     1566}
     1567
     1568
     1569/**
     1570 * This should be called from PDMDEVREGR3::pfnDestruct.
    13531571 *
    13541572 * @param   pVirtio     Pointer to the virtio state.
     
    13651583}
    13661584
     1585
    13671586/**
    13681587 * Setup PCI device controller and Virtio state
     1588 *
     1589 * This should be called from PDMDEVREGR3::pfnConstruct.
    13691590 *
    13701591 * @param   pVirtio                 Pointer to the virtio state.  This must be
     
    15701791}
    15711792
    1572 #ifdef IN_RING3
    1573 
    1574 /**
    1575  * Called from the FNSSMDEVSAVEEXEC function of the device.
    1576  *
    1577  * @param   pVirtio     Pointer to the virtio state.
    1578  * @param   pHlp        The ring-3 device helpers.
    1579  * @param   pSSM        The saved state handle.
    1580  * @returns VBox status code.
    1581  */
    1582 int virtioR3SaveExec(PVIRTIOSTATE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
    1583 {
    1584     pHlp->pfnSSMPutU64(pSSM, VIRTIO_SAVEDSTATE_MARKER);
    1585     pHlp->pfnSSMPutU32(pSSM, VIRTIO_SAVEDSTATE_VERSION);
    1586 
    1587     pHlp->pfnSSMPutBool(pSSM,   pVirtio->fGenUpdatePending);
    1588     pHlp->pfnSSMPutU8(pSSM,     pVirtio->uDeviceStatus);
    1589     pHlp->pfnSSMPutU8(pSSM,     pVirtio->uConfigGeneration);
    1590     pHlp->pfnSSMPutU8(pSSM,     pVirtio->uPciCfgDataOff);
    1591     pHlp->pfnSSMPutU8(pSSM,     pVirtio->uISR);
    1592     pHlp->pfnSSMPutU16(pSSM,    pVirtio->uQueueSelect);
    1593     pHlp->pfnSSMPutU32(pSSM,    pVirtio->uDeviceFeaturesSelect);
    1594     pHlp->pfnSSMPutU32(pSSM,    pVirtio->uDriverFeaturesSelect);
    1595     pHlp->pfnSSMPutU64(pSSM,    pVirtio->uDriverFeatures);
    1596     Assert(pVirtio->uNumQueues == VIRTQ_MAX_CNT); /** @todo r=bird: See todo in struct & virtioR3LoadExec. */
    1597     pHlp->pfnSSMPutU32(pSSM,    pVirtio->uNumQueues);
    1598 
    1599     for (uint32_t i = 0; i < pVirtio->uNumQueues; i++)
    1600     {
    1601         pHlp->pfnSSMPutGCPhys64(pSSM, pVirtio->aGCPhysQueueDesc[i]);
    1602         pHlp->pfnSSMPutGCPhys64(pSSM, pVirtio->aGCPhysQueueAvail[i]);
    1603         pHlp->pfnSSMPutGCPhys64(pSSM, pVirtio->aGCPhysQueueUsed[i]);
    1604         pHlp->pfnSSMPutU16(pSSM,      pVirtio->uQueueNotifyOff[i]);
    1605         pHlp->pfnSSMPutU16(pSSM,      pVirtio->uQueueMsixVector[i]);
    1606         pHlp->pfnSSMPutU16(pSSM,      pVirtio->uQueueEnable[i]);
    1607         pHlp->pfnSSMPutU16(pSSM,      pVirtio->uQueueSize[i]);
    1608         pHlp->pfnSSMPutU16(pSSM,      pVirtio->virtqState[i].uAvailIdx);
    1609         pHlp->pfnSSMPutU16(pSSM,      pVirtio->virtqState[i].uUsedIdx);
    1610         int rc = pHlp->pfnSSMPutMem(pSSM, pVirtio->virtqState[i].szVirtqName, 32);
    1611         AssertRCReturn(rc, rc);
    1612     }
    1613 
    1614     return VINF_SUCCESS;
    1615 }
    1616 
    1617 /**
    1618  * Called from the FNSSMDEVLOADEXEC function of the device.
    1619  *
    1620  * @param   pVirtio     Pointer to the virtio state.
    1621  * @param   pHlp        The ring-3 device helpers.
    1622  * @param   pSSM        The saved state handle.
    1623  * @returns VBox status code.
    1624  */
    1625 int virtioR3LoadExec(PVIRTIOSTATE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
    1626 {
    1627     /*
    1628      * Check the marker and (embedded) version number.
    1629      */
    1630     uint64_t uMarker = 0;
    1631     int rc = pHlp->pfnSSMGetU64(pSSM, &uMarker);
    1632     AssertRCReturn(rc, rc);
    1633     if (uMarker != VIRTIO_SAVEDSTATE_MARKER)
    1634         return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
    1635                                         N_("Expected marker value %#RX64 found %#RX64 instead"),
    1636                                         VIRTIO_SAVEDSTATE_MARKER, uMarker);
    1637     uint32_t uVersion = 0;
    1638     rc = pHlp->pfnSSMGetU32(pSSM, &uVersion);
    1639     AssertRCReturn(rc, rc);
    1640     if (uVersion != VIRTIO_SAVEDSTATE_VERSION)
    1641         return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
    1642                                         N_("Unsupported virtio version: %u"), uVersion);
    1643 
    1644     /*
    1645      * Load the state.
    1646      */
    1647     pHlp->pfnSSMGetBool(pSSM, &pVirtio->fGenUpdatePending);
    1648     pHlp->pfnSSMGetU8(pSSM,   &pVirtio->uDeviceStatus);
    1649     pHlp->pfnSSMGetU8(pSSM,   &pVirtio->uConfigGeneration);
    1650     pHlp->pfnSSMGetU8(pSSM,   &pVirtio->uPciCfgDataOff);
    1651     pHlp->pfnSSMGetU8(pSSM,   &pVirtio->uISR);
    1652     pHlp->pfnSSMGetU16(pSSM,  &pVirtio->uQueueSelect);
    1653     pHlp->pfnSSMGetU32(pSSM,  &pVirtio->uDeviceFeaturesSelect);
    1654     pHlp->pfnSSMGetU32(pSSM,  &pVirtio->uDriverFeaturesSelect);
    1655     pHlp->pfnSSMGetU64(pSSM,  &pVirtio->uDriverFeatures);
    1656 
    1657     /* Make sure the queue count is within expectations. */
    1658     /** @todo r=bird: Turns out the expectations are exactly VIRTQ_MAX_CNT, bug? */
    1659     rc = pHlp->pfnSSMGetU32(pSSM, &pVirtio->uNumQueues);
    1660     AssertRCReturn(rc, rc);
    1661     AssertReturn(pVirtio->uNumQueues == VIRTQ_MAX_CNT,
    1662                  pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
    1663                                           N_("Saved queue count %u, expected %u"), uVersion, VIRTQ_MAX_CNT));
    1664     AssertCompile(RT_ELEMENTS(pVirtio->virtqState) == VIRTQ_MAX_CNT);
    1665     AssertCompile(RT_ELEMENTS(pVirtio->aGCPhysQueueDesc) == VIRTQ_MAX_CNT);
    1666 
    1667     for (uint32_t idxQueue = 0; idxQueue < pVirtio->uNumQueues; idxQueue++)
    1668     {
    1669         pHlp->pfnSSMGetGCPhys64(pSSM, &pVirtio->aGCPhysQueueDesc[idxQueue]);
    1670         pHlp->pfnSSMGetGCPhys64(pSSM, &pVirtio->aGCPhysQueueAvail[idxQueue]);
    1671         pHlp->pfnSSMGetGCPhys64(pSSM, &pVirtio->aGCPhysQueueUsed[idxQueue]);
    1672         pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueNotifyOff[idxQueue]);
    1673         pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueMsixVector[idxQueue]);
    1674         pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueEnable[idxQueue]);
    1675         pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueSize[idxQueue]);
    1676         pHlp->pfnSSMGetU16(pSSM, &pVirtio->virtqState[idxQueue].uAvailIdx);
    1677         pHlp->pfnSSMGetU16(pSSM, &pVirtio->virtqState[idxQueue].uUsedIdx);
    1678         pHlp->pfnSSMGetMem(pSSM,  pVirtio->virtqState[idxQueue].szVirtqName, sizeof(pVirtio->virtqState[idxQueue].szVirtqName));
    1679     }
    1680 
    1681     return VINF_SUCCESS;
    1682 }
    1683 
    1684 /**
    1685  * Does a formatted hex dump using Log(()), recommend using VIRTIO_HEX_DUMP() macro to
    1686  * control enabling of logging efficiently.
    1687  *
    1688  * @param   pv          pointer to buffer to dump contents of
    1689  * @param   cb          count of characters to dump from buffer
    1690  * @param   uBase       base address of per-row address prefixing of hex output
    1691  * @param   pszTitle    Optional title. If present displays title that lists
    1692  *                      provided text with value of cb to indicate size next to it.
    1693  */
    1694 void virtioHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle)
    1695 {
    1696     if (pszTitle)
    1697         Log(("%s [%d bytes]:\n", pszTitle, cb));
    1698     for (uint32_t row = 0; row < RT_MAX(1, (cb / 16) + 1) && row * 16 < cb; row++)
    1699     {
    1700         Log(("%04x: ", row * 16 + uBase)); /* line address */
    1701         for (uint8_t col = 0; col < 16; col++)
    1702         {
    1703            uint32_t idx = row * 16 + col;
    1704            if (idx >= cb)
    1705                Log(("-- %s", (col + 1) % 8 ? "" : "  "));
    1706            else
    1707                Log(("%02x %s", pv[idx], (col + 1) % 8 ? "" : "  "));
    1708         }
    1709         for (uint32_t idx = row * 16; idx < row * 16 + 16; idx++)
    1710            Log(("%c", (idx >= cb) ? ' ' : (pv[idx] >= 0x20 && pv[idx] <= 0x7e ? pv[idx] : '.')));
    1711         Log(("\n"));
    1712     }
    1713     Log(("\n"));
    1714     RT_NOREF2(uBase, pv);
    1715 }
    1716 
    1717 
    1718 /**
    1719  * Log memory-mapped I/O input or output value.
    1720  *
    1721  * This is designed to be invoked by macros that can make contextual assumptions
    1722  * (e.g. implicitly derive MACRO parameters from the invoking function). It is exposed
    1723  * for the VirtIO client doing the device-specific implementation in order to log in a
    1724  * similar fashion accesses to the device-specific MMIO configuration structure. Macros
    1725  * that leverage this function are found in virtioCommonCfgAccessed() and can be
    1726  * used as an example of how to use this effectively for the device-specific
    1727  * code.
    1728  *
    1729  * @param   pszFunc     To avoid displaying this function's name via __FUNCTION__ or LogFunc()
    1730  * @param   pszMember   Name of struct member
    1731  * @param   pv          pointer to value
    1732  * @param   cb          size of value
    1733  * @param   uOffset     offset into member where value starts
    1734  * @param   fWrite      True if write I/O
    1735  * @param   fHasIndex   True if the member is indexed
    1736  * @param   idx         The index if fHasIndex
    1737  */
    1738 void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize,
    1739                             const void *pv, uint32_t cb, uint32_t uOffset, int fWrite,
    1740                             int fHasIndex, uint32_t idx)
    1741 {
    1742 
    1743 #define FMTHEX(fmtout, val, cNybbles) \
    1744     fmtout[cNybbles] = '\0'; \
    1745     for (uint8_t i = 0; i < cNybbles; i++) \
    1746         fmtout[(cNybbles - i) - 1] = "0123456789abcdef"[(val >> (i * 4)) & 0xf];
    1747 
    1748 #define MAX_STRING   64
    1749     char pszIdx[MAX_STRING] = { 0 };
    1750     char pszDepiction[MAX_STRING] = { 0 };
    1751     char pszFormattedVal[MAX_STRING] = { 0 };
    1752     if (fHasIndex)
    1753         RTStrPrintf(pszIdx, sizeof(pszIdx), "[%d]", idx);
    1754     if (cb == 1 || cb == 2 || cb == 4 || cb == 8)
    1755     {
    1756         /* manually padding with 0's instead of \b due to different impl of %x precision than printf() */
    1757         uint64_t val = 0;
    1758         memcpy((char *)&val, pv, cb);
    1759         FMTHEX(pszFormattedVal, val, cb * 2);
    1760         if (uOffset != 0 || cb != uMemberSize) /* display bounds if partial member access */
    1761             RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s[%d:%d]",
    1762                         pszMember, pszIdx, uOffset, uOffset + cb - 1);
    1763         else
    1764             RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s", pszMember, pszIdx);
    1765         RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%-30s", pszDepiction);
    1766         uint32_t first = 0;
    1767         for (uint8_t i = 0; i < sizeof(pszDepiction); i++)
    1768             if (pszDepiction[i] == ' ' && first++)
    1769                 pszDepiction[i] = '.';
    1770         Log6Func(("%s: Guest %s %s 0x%s\n",
    1771                   pszFunc, fWrite ? "wrote" : "read ", pszDepiction, pszFormattedVal));
    1772     }
    1773     else /* odd number or oversized access, ... log inline hex-dump style */
    1774     {
    1775         Log6Func(("%s: Guest %s %s%s[%d:%d]: %.*Rhxs\n",
    1776                   pszFunc, fWrite ? "wrote" : "read ", pszMember,
    1777                   pszIdx, uOffset, uOffset + cb, cb, pv));
    1778     }
    1779     RT_NOREF2(fWrite, pszFunc);
    1780 }
    1781 
    17821793#endif /* IN_RING3 */
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h

    r81658 r81660  
    4141#define VIRTIO_REGION_MSIX_CAP              0                    /**< Bar for MSI-X handling                   */
    4242
    43 #define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) \
     43#ifdef LOG_ENABLED
     44# define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) \
    4445    do { \
    4546        if (LogIsItEnabled(logLevel, LOG_GROUP)) \
    4647            virtioHexDump((pv), (cb), (base), (title)); \
    4748    } while (0)
     49#else
     50# define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) do { } while (0)
     51#endif
    4852
    4953
     
    5963 *
    6064 * Typical use is, When the client (worker thread) detects available data on the queue, it pulls the
    61  * next one of these descriptor chain structs off the queue using virtioQueueGet(), processes the
     65 * next one of these descriptor chain structs off the queue using virtioR3QueueGet(), processes the
    6266 * virtual memory buffer pVirtSrc, produces result data to pass back to the guest driver and calls
    63  * virtioQueuePut() to return the result data to the client.
     67 * virtioR3QueuePut() to return the result data to the client.
    6468 */
    6569typedef struct VIRTIO_DESC_CHAIN
     
    307311 * @{ */
    308312
    309 int virtioQueueAttach(PVIRTIOSTATE pVirtio, uint16_t idxQueue, const char *pcszName);
     313int virtioR3QueueAttach(PVIRTIOSTATE pVirtio, uint16_t idxQueue, const char *pcszName);
    310314#if 0 /* no such function */
    311315/**
     
    317321int virtioQueueDetach(PVIRTIOSTATE pVirtio, uint16_t idxQueue);
    318322#endif
    319 int virtioQueueGet(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove);
    320 int virtioQueuePut(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn,
    321                    PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence);
     323int  virtioR3QueueGet(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove);
     324int  virtioR3QueuePut(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn,
     325                      PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence);
    322326
    323327int virtioQueueSync(PVIRTIOSTATE pVirtio, uint16_t idxQueue);
     
    326330void virtioQueueEnable(PVIRTIOSTATE pVirtio, uint16_t idxQueue, bool fEnabled);
    327331void virtioResetAll(PVIRTIOSTATE pVirtio);
    328 void virtioPropagateResumeNotification(PVIRTIOSTATE pVirtio);
    329332
    330333/**
     
    343346
    344347/**
    345  * Get name of queue, by idxQueue, assigned at virtioQueueAttach()
     348 * Get name of queue, by idxQueue, assigned at virtioR3QueueAttach()
    346349 *
    347350 * @param   pVirtio     Pointer to the virtio state.
     
    366369}
    367370
     371/**
     372 * Get VirtIO accepted host-side features
     373 *
     374 * @returns feature bits selected or 0 if selector out of range.
     375 *
     376 * @param   pState          Virtio state
     377 */
     378DECLINLINE(uint64_t) virtioGetAcceptedFeatures(PVIRTIOSTATE pVirtio)
     379{
     380    return pVirtio->uDriverFeatures;
     381}
     382
     383
    368384int  virtioR3SaveExec(PVIRTIOSTATE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM);
    369385int  virtioR3LoadExec(PVIRTIOSTATE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM);
     386void virtioR3PropagateResetNotification(PVIRTIOSTATE pVirtio);
     387void virtioR3PropagateResumeNotification(PVIRTIOSTATE pVirtio);
    370388void virtioR3Term(PVIRTIOSTATE pVirtio, PPDMDEVINS pDevIns);
    371389int  virtioR3Init(PVIRTIOSTATE pVirtio, PPDMDEVINS pDevIns, PVIRTIOPCIPARAMS pPciParams, const char *pcszInstance,
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