Changeset 81660 in vbox
- Timestamp:
- Nov 4, 2019 9:46:54 PM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 134420
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp
r81658 r81660 81 81 82 82 #define VIRTIOSCSI_REQ_QUEUE_CNT 1 /**< T.B.D. Consider increasing */ 83 #define VIRTIOSCSI_QUEUE_CNT VIRTIOSCSI_REQ_QUEUE_CNT + 283 #define VIRTIOSCSI_QUEUE_CNT (VIRTIOSCSI_REQ_QUEUE_CNT + 2) 84 84 #define VIRTIOSCSI_MAX_LUN 256 /**< VirtIO specification, section 5.6.4 */ 85 85 #define VIRTIOSCSI_MAX_COMMANDS_PER_LUN 128 /**< T.B.D. What is a good value for this? */ … … 394 394 } VIRTIOSCSITARGET, *PVIRTIOSCSITARGET; 395 395 396 397 /** Why we're quiescing. */ 398 typedef enum VIRTIOSCSIQUIESCINGFOR 399 { 400 kvirtIoScsiQuiescingForInvalid = 0, 401 kvirtIoScsiQuiescingForReset, 402 kvirtIoScsiQuiescingForSuspend, 403 kvirtIoScsiQuiescingForPowerOff, 404 kvirtIoScsiQuiescingFor32BitHack = 0x7fffffff 405 } VIRTIOSCSIQUIESCINGFOR; 406 407 396 408 /** 397 409 * PDM instance data (state) for VirtIO Host SCSI device … … 492 504 /** True if in the process of quiescing I/O */ 493 505 uint32_t fQuiescing; 506 /** For which purpose we're quiescing. */ 507 VIRTIOSCSIQUIESCINGFOR enmQuiescingFor; 494 508 495 509 } VIRTIOSCSI, *PVIRTIOSCSI; … … 663 677 664 678 PVIRTIO_DESC_CHAIN_T pDescChain; 665 virtio QueueGet(&pThis->Virtio, EVENTQ_IDX, &pDescChain, true);679 virtioR3QueueGet(&pThis->Virtio, EVENTQ_IDX, &pDescChain, true); 666 680 667 681 RTSGBUF reqSegBuf; … … 669 683 RTSgBufInit(&reqSegBuf, aReqSegs, RT_ELEMENTS(aReqSegs)); 670 684 671 virtio QueuePut( &pThis->Virtio, EVENTQ_IDX, &reqSegBuf, pDescChain, true);685 virtioR3QueuePut( &pThis->Virtio, EVENTQ_IDX, &reqSegBuf, pDescChain, true); 672 686 virtioQueueSync(&pThis->Virtio, EVENTQ_IDX); 673 687 … … 719 733 pRespHdr->uResponse = VIRTIOSCSI_S_RESET; 720 734 721 virtio QueuePut(&pThis->Virtio, qIdx, &reqSegBuf, pDescChain, true /* fFence */);735 virtioR3QueuePut(&pThis->Virtio, qIdx, &reqSegBuf, pDescChain, true /* fFence */); 722 736 virtioQueueSync(&pThis->Virtio, qIdx); 723 737 … … 875 889 876 890 877 virtio QueuePut(&pThis->Virtio, pReq->qIdx, &reqSegBuf, pReq->pDescChain, true /* fFence TBD */);891 virtioR3QueuePut(&pThis->Virtio, pReq->qIdx, &reqSegBuf, pReq->pDescChain, true /* fFence TBD */); 878 892 virtioQueueSync(&pThis->Virtio, pReq->qIdx); 879 893 … … 1417 1431 1418 1432 LogFunc(("Response code: %s\n", virtioGetReqRespText(bResponse))); 1419 virtio QueuePut( &pThis->Virtio, qIdx, &reqSegBuf, pDescChain, true);1433 virtioR3QueuePut( &pThis->Virtio, qIdx, &reqSegBuf, pDescChain, true); 1420 1434 virtioQueueSync(&pThis->Virtio, qIdx); 1421 1435 … … 1476 1490 Log6Func(("fetching next descriptor chain from %s\n", QUEUENAME(qIdx))); 1477 1491 PVIRTIO_DESC_CHAIN_T pDescChain; 1478 int rc = virtio QueueGet(&pThis->Virtio, qIdx, &pDescChain, true);1492 int rc = virtioR3QueueGet(&pThis->Virtio, qIdx, &pDescChain, true); 1479 1493 if (rc == VERR_NOT_AVAILABLE) 1480 1494 { … … 2056 2070 static DECLCALLBACK(bool) virtioScsiR3DeviceQuiesced(PPDMDEVINS pDevIns) 2057 2071 { 2058 LogFunc(("Device I/O activity quiesced.\n"));2059 2072 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; 2061 2080 pThis->fQuiescing = false; 2062 2063 2081 return true; 2064 2082 } … … 2067 2085 * Worker for virtioScsiR3Reset() and virtioScsiR3SuspendOrPowerOff(). 2068 2086 */ 2069 static void virtioScsiR3QuiesceDevice(PPDMDEVINS pDevIns )2087 static void virtioScsiR3QuiesceDevice(PPDMDEVINS pDevIns, VIRTIOSCSIQUIESCINGFOR enmQuiscingFor) 2070 2088 { 2071 2089 PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI); … … 2073 2091 /* Prevent worker threads from removing/processing elements from virtq's */ 2074 2092 pThis->fQuiescing = true; 2093 pThis->enmQuiescingFor = enmQuiscingFor; 2075 2094 2076 2095 PDMDevHlpSetAsyncNotification(pDevIns, virtioScsiR3DeviceQuiesced); … … 2082 2101 2083 2102 /** 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 */ 2105 static void virtioScsiR3SuspendOrPowerOff(PPDMDEVINS pDevIns, VIRTIOSCSIQUIESCINGFOR enmQuiscingFor) 2106 { 2090 2107 PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI); 2091 2108 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 2124 2111 2125 2112 /* VM is halted, thus no new I/O being dumped into queues by the guest. … … 2139 2126 2140 2127 /** 2128 * @interface_method_impl{PDMDEVREGR3,pfnPowerOff} 2129 */ 2130 static DECLCALLBACK(void) virtioScsiR3PowerOff(PPDMDEVINS pDevIns) 2131 { 2132 LogFunc(("\n")); 2133 virtioScsiR3SuspendOrPowerOff(pDevIns, kvirtIoScsiQuiescingForPowerOff); 2134 } 2135 2136 /** 2137 * @interface_method_impl{PDMDEVREGR3,pfnSuspend} 2138 */ 2139 static DECLCALLBACK(void) virtioScsiR3Suspend(PPDMDEVINS pDevIns) 2140 { 2141 LogFunc(("\n")); 2142 virtioScsiR3SuspendOrPowerOff(pDevIns, kvirtIoScsiQuiescingForSuspend); 2143 } 2144 2145 /** 2146 * @interface_method_impl{PDMDEVREGR3,pfnResume} 2147 */ 2148 static 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 /** 2141 2176 * @interface_method_impl{PDMDEVREGR3,pfnReset} 2142 2177 */ … … 2146 2181 PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI); 2147 2182 pThis->fResetting = true; 2148 virtioScsiR3QuiesceDevice(pDevIns); 2183 virtioScsiR3QuiesceDevice(pDevIns, kvirtIoScsiQuiescingForReset); 2184 2185 /** @todo r=bird: Shouldn't you reset the device here?!? */ 2149 2186 } 2150 2187 … … 2154 2191 static DECLCALLBACK(int) virtioScsiR3Destruct(PPDMDEVINS pDevIns) 2155 2192 { 2156 /*2157 * Check the versions here as well since the destructor is *always* called.2158 */2159 2160 2193 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); 2161 2162 PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI); 2194 PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI); 2163 2195 2164 2196 RTMemFree(pThis->paTargetInstances); … … 2173 2205 } 2174 2206 } 2175 return VINF_SUCCESS; 2207 2208 virtioR3Term(&pThis->Virtio, pDevIns); 2209 return VINF_SUCCESS; 2176 2210 } 2177 2211 … … 2265 2299 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi: failed to initialize VirtIO")); 2266 2300 2301 /* Name the queues: */ 2267 2302 RTStrCopy(pThis->aszQueueNames[CONTROLQ_IDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq"); 2268 2303 RTStrCopy(pThis->aszQueueNames[EVENTQ_IDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "eventq"); … … 2271 2306 "requestq<%d>", qIdx - VIRTQ_REQ_BASE); 2272 2307 2308 /* Attach the queues and create worker threads for them: */ 2273 2309 for (uint16_t qIdx = 0; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++) 2274 2310 { 2275 rc = virtio QueueAttach(&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. */ 2277 2313 2278 2314 if (qIdx == CONTROLQ_IDX || IS_REQ_QUEUE(qIdx)) … … 2437 2473 /* .pfnPowerOn = */ NULL, 2438 2474 /* .pfnReset = */ virtioScsiR3Reset, 2439 /* .pfnSuspend = */ virtioScsiR3Suspend OrPowerOff,2475 /* .pfnSuspend = */ virtioScsiR3Suspend, 2440 2476 /* .pfnResume = */ virtioScsiR3Resume, 2441 2477 /* .pfnAttach = */ virtioScsiR3Attach, … … 2443 2479 /* .pfnQueryInterface = */ NULL, 2444 2480 /* .pfnInitComplete = */ NULL, 2445 /* .pfnPowerOff = */ virtioScsiR3 SuspendOrPowerOff,2481 /* .pfnPowerOff = */ virtioScsiR3PowerOff, 2446 2482 /* .pfnSoftReset = */ NULL, 2447 2483 /* .pfnReserved0 = */ NULL, -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp
r81659 r81660 275 275 /** @} */ 276 276 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 */ 289 void 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 */ 332 void 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 */ 277 377 278 378 /** … … 302 402 } 303 403 404 #ifdef IN_RING3 304 405 /** 305 406 * Allocate client context for client to work with VirtIO-provided with queue … … 311 412 * @returns VBox status code. 312 413 */ 313 int virtio QueueAttach(PVIRTIOSTATE pVirtio, uint16_t idxQueue, const char *pcszName)414 int virtioR3QueueAttach(PVIRTIOSTATE pVirtio, uint16_t idxQueue, const char *pcszName) 314 415 { 315 416 LogFunc(("%s\n", pcszName)); … … 321 422 return VINF_SUCCESS; 322 423 } 424 #endif /* IN_RING3 */ 323 425 324 426 #if 0 /** @todo r=bird: no prototype or docs for this one */ … … 360 462 } 361 463 464 #ifdef IN_RING3 465 362 466 /** 363 467 * Removes descriptor chain from avail ring of indicated queue and converts the descriptor … … 366 470 * Additionally it converts the OUT desc chain data to a contiguous virtual 367 471 * memory buffer for easy consumption by the caller. The caller must return the 368 * descriptor chain pointer via virtio QueuePut() and then call virtioQueueSync()472 * descriptor chain pointer via virtioR3QueuePut() and then call virtioQueueSync() 369 473 * at some point to return the data to the guest and complete the transaction. 370 474 * … … 380 484 * @retval VERR_NOT_AVAILABLE If the queue is empty. 381 485 */ 382 int virtio QueueGet(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove)486 int virtioR3QueueGet(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove) 383 487 { 384 488 AssertReturn(ppDescChain, VERR_INVALID_PARAMETER); … … 512 616 * @retval VERR_NOT_AVAILABLE Queue is empty 513 617 */ 514 int virtio QueuePut(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn,515 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence)618 int virtioR3QueuePut(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn, 619 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence) 516 620 { 517 621 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState)); … … 578 682 } 579 683 684 #endif /* IN_RING3 */ 685 580 686 /** 581 687 * Updates the indicated virtq's "used ring" descriptor index to match the 582 688 * current write-head index, thus exposing the data added to the used ring by all 583 * virtio QueuePut() calls since the last sync. This should be called after one or689 * virtioR3QueuePut() calls since the last sync. This should be called after one or 584 690 * more virtQueuePut() calls to inform the guest driver there is data in the queue. 585 691 * Explicit notifications (e.g. interrupt or MSI-X) will be sent to the guest, … … 612 718 } 613 719 614 /** 615 */ 616 static void virtioQueueNotified(PVIRTIOSTATE pVirtio, uint16_t idxQueue, uint16_t uNotifyIdx) 720 #ifdef IN_RING3 721 /** 722 */ 723 static void virtior3QueueNotified(PVIRTIOSTATE pVirtio, uint16_t idxQueue, uint16_t uNotifyIdx) 617 724 { 618 725 /* See VirtIO 1.0, section 4.1.5.2 It implies that idxQueue and uNotifyIdx should match. … … 636 743 pVirtio->Callbacks.pfnQueueNotified(pVirtio, idxQueue); 637 744 } 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 */ 651 746 652 747 /** … … 703 798 static int virtioKick(PVIRTIOSTATE pVirtio, uint8_t uCause, uint16_t uMsixVector, bool fForce) 704 799 { 705 706 800 if (fForce) 707 801 Log6Func(("reason: resumed after suspend\n")); … … 770 864 } 771 865 866 #if 0 /** @todo r=bird: Probably not needed. */ 772 867 /** 773 868 * Enable or disable queue … … 784 879 pVirtio->uQueueSize[idxQueue] = 0; 785 880 } 786 881 #endif 882 883 #if 0 /** @todo r=bird: This isn't invoked by anyone. Why? */ 787 884 /** 788 885 * Initiate orderly reset procedure. … … 799 896 } 800 897 } 801 898 #endif 899 900 #ifdef IN_RING3 802 901 /** 803 902 * Invoked by this implementation when guest driver resets the device. 804 903 * The driver itself will not until the device has read the status change. 805 904 */ 806 static void virtioGuestR esetted(PVIRTIOSTATE pVirtio)905 static void virtioGuestR3Resetted(PVIRTIOSTATE pVirtio) 807 906 { 808 907 LogFunc(("Guest reset the device\n")); … … 812 911 virtioResetDevice(pVirtio); 813 912 } 913 #endif /* IN_RING3 */ 814 914 815 915 /** … … 824 924 * @param pv Pointer to location to write to or read from 825 925 */ 826 static int virtioCommonCfgAccessed(PVIRTIOSTATE pVirtio, int fWrite, off_t offCfg, unsigned cb, void const*pv)926 static int virtioCommonCfgAccessed(PVIRTIOSTATE pVirtio, int fWrite, off_t offCfg, unsigned cb, void *pv) 827 927 { 828 928 /** … … 845 945 && cb == RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member)) ) 846 946 847 #define LOG_COMMON_CFG_ACCESS(member) \ 947 #ifdef LOG_ENABLED 948 # define LOG_COMMON_CFG_ACCESS(member, a_offIntra) \ 848 949 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) \ 852 952 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 854 958 855 959 #define COMMON_CFG_ACCESSOR(member) \ 856 960 do \ 857 961 { \ 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); \ 859 963 if (fWrite) \ 860 memcpy(( (char *)&pVirtio->member) + uIntraOff, (const char *)pv, cb); \964 memcpy((char *)&pVirtio->member + offIntra, (const char *)pv, cb); \ 861 965 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); \ 864 968 } while(0) 865 969 … … 867 971 do \ 868 972 { \ 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); \ 870 974 if (fWrite) \ 871 memcpy(((char *)(pVirtio->member + idx)) + uIntraOff, (const char *)pv, cb); \975 memcpy(((char *)(pVirtio->member + idx)) + offIntra, (const char *)pv, cb); \ 872 976 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); \ 875 979 } while(0) 876 980 … … 878 982 do \ 879 983 { \ 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); \ 881 985 if (fWrite) \ 882 986 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s\n", #member)); \ 883 987 else \ 884 988 { \ 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); \ 887 991 } \ 888 992 } while(0) … … 891 995 do \ 892 996 { \ 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); \ 894 998 if (fWrite) \ 895 999 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s[%d]\n", #member, idx)); \ 896 1000 else \ 897 1001 { \ 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); \ 900 1004 } \ 901 1005 } while(0) … … 913 1017 else /* Guest READ pCommonCfg->uDeviceFeatures */ 914 1018 { 915 uint32_t uIntraOff = offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDeviceFeatures);916 1019 switch (pVirtio->uDeviceFeaturesSelect) 917 1020 { 918 1021 case 0: 919 1022 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)); 922 1025 break; 923 1026 case 1: 924 1027 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); 928 1030 break; 929 1031 default: … … 938 1040 if (fWrite) /* Guest WRITE pCommonCfg->udriverFeatures */ 939 1041 { 940 uint32_t uIntraOff = offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures);941 1042 switch (pVirtio->uDriverFeaturesSelect) 942 1043 { 943 1044 case 0: 944 1045 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)); 946 1047 break; 947 1048 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); 951 1051 break; 952 1052 default: … … 958 1058 else /* Guest READ pCommonCfg->udriverFeatures */ 959 1059 { 960 uint32_t uIntraOff = offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures);961 1060 switch (pVirtio->uDriverFeaturesSelect) 962 1061 { 963 1062 case 0: 964 1063 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)); 967 1066 break; 968 1067 case 1: 969 1068 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); 973 1071 break; 974 1072 default: … … 988 1086 else 989 1087 { 990 uint32_t uIntraOff = 0;991 1088 *(uint16_t *)pv = VIRTQ_MAX_CNT; 992 LOG_COMMON_CFG_ACCESS(uNumQueues );1089 LOG_COMMON_CFG_ACCESS(uNumQueues, 0); 993 1090 } 994 1091 } … … 1002 1099 Log6((")\n")); 1003 1100 if (pVirtio->uDeviceStatus == 0) 1004 virtioGuestR esetted(pVirtio);1005 /* *1101 virtioGuestR3Resetted(pVirtio); 1102 /* 1006 1103 * Notify client only if status actually changed from last time. 1007 1104 */ 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); 1013 1109 pVirtio->uPrevDeviceStatus = pVirtio->uDeviceStatus; 1014 1110 } … … 1016 1112 { 1017 1113 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? */ 1019 1115 virtioLogDeviceStatus(pVirtio->uDeviceStatus); 1020 1116 Log6((")\n")); … … 1127 1223 { 1128 1224 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); 1130 1226 } 1131 1227 else … … 1180 1276 { 1181 1277 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); 1183 1279 } 1184 1280 else … … 1199 1295 uint16_t uAvailDescIdx = *(uint16_t *)pv; 1200 1296 1201 virtio QueueNotified(pVirtio, idxQueue, uAvailDescIdx);1297 virtior3QueueNotified(pVirtio, idxQueue, uAvailDescIdx); 1202 1298 } 1203 1299 else … … 1209 1305 return VINF_SUCCESS; 1210 1306 } 1307 1308 #ifdef IN_RING3 1211 1309 1212 1310 /** … … 1322 1420 } 1323 1421 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. 1341 1433 * @returns VBox status code. 1342 * @param pState The device state structure. 1343 */ 1344 int virtioDestruct(PVIRTIOSTATE pVirtio) 1345 { 1434 */ 1435 int 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 */ 1478 int 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 */ 1547 void virtioR3PropagateResetNotification(PVIRTIOSTATE pVirtio) 1548 { 1549 /** @todo r=bird: You probably need to do something here. See 1550 * virtioScsiR3Reset. */ 1346 1551 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 */ 1563 void 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. 1353 1571 * 1354 1572 * @param pVirtio Pointer to the virtio state. … … 1365 1583 } 1366 1584 1585 1367 1586 /** 1368 1587 * Setup PCI device controller and Virtio state 1588 * 1589 * This should be called from PDMDEVREGR3::pfnConstruct. 1369 1590 * 1370 1591 * @param pVirtio Pointer to the virtio state. This must be … … 1570 1791 } 1571 1792 1572 #ifdef IN_RING31573 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 to1686 * control enabling of logging efficiently.1687 *1688 * @param pv pointer to buffer to dump contents of1689 * @param cb count of characters to dump from buffer1690 * @param uBase base address of per-row address prefixing of hex output1691 * @param pszTitle Optional title. If present displays title that lists1692 * 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 else1707 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 assumptions1722 * (e.g. implicitly derive MACRO parameters from the invoking function). It is exposed1723 * for the VirtIO client doing the device-specific implementation in order to log in a1724 * similar fashion accesses to the device-specific MMIO configuration structure. Macros1725 * that leverage this function are found in virtioCommonCfgAccessed() and can be1726 * used as an example of how to use this effectively for the device-specific1727 * code.1728 *1729 * @param pszFunc To avoid displaying this function's name via __FUNCTION__ or LogFunc()1730 * @param pszMember Name of struct member1731 * @param pv pointer to value1732 * @param cb size of value1733 * @param uOffset offset into member where value starts1734 * @param fWrite True if write I/O1735 * @param fHasIndex True if the member is indexed1736 * @param idx The index if fHasIndex1737 */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 641749 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 else1764 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 1782 1793 #endif /* IN_RING3 */ -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
r81658 r81660 41 41 #define VIRTIO_REGION_MSIX_CAP 0 /**< Bar for MSI-X handling */ 42 42 43 #define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) \ 43 #ifdef LOG_ENABLED 44 # define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) \ 44 45 do { \ 45 46 if (LogIsItEnabled(logLevel, LOG_GROUP)) \ 46 47 virtioHexDump((pv), (cb), (base), (title)); \ 47 48 } while (0) 49 #else 50 # define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) do { } while (0) 51 #endif 48 52 49 53 … … 59 63 * 60 64 * 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 virtio QueueGet(), processes the65 * next one of these descriptor chain structs off the queue using virtioR3QueueGet(), processes the 62 66 * virtual memory buffer pVirtSrc, produces result data to pass back to the guest driver and calls 63 * virtio QueuePut() to return the result data to the client.67 * virtioR3QueuePut() to return the result data to the client. 64 68 */ 65 69 typedef struct VIRTIO_DESC_CHAIN … … 307 311 * @{ */ 308 312 309 int virtio QueueAttach(PVIRTIOSTATE pVirtio, uint16_t idxQueue, const char *pcszName);313 int virtioR3QueueAttach(PVIRTIOSTATE pVirtio, uint16_t idxQueue, const char *pcszName); 310 314 #if 0 /* no such function */ 311 315 /** … … 317 321 int virtioQueueDetach(PVIRTIOSTATE pVirtio, uint16_t idxQueue); 318 322 #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);323 int virtioR3QueueGet(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove); 324 int virtioR3QueuePut(PVIRTIOSTATE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn, 325 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence); 322 326 323 327 int virtioQueueSync(PVIRTIOSTATE pVirtio, uint16_t idxQueue); … … 326 330 void virtioQueueEnable(PVIRTIOSTATE pVirtio, uint16_t idxQueue, bool fEnabled); 327 331 void virtioResetAll(PVIRTIOSTATE pVirtio); 328 void virtioPropagateResumeNotification(PVIRTIOSTATE pVirtio);329 332 330 333 /** … … 343 346 344 347 /** 345 * Get name of queue, by idxQueue, assigned at virtio QueueAttach()348 * Get name of queue, by idxQueue, assigned at virtioR3QueueAttach() 346 349 * 347 350 * @param pVirtio Pointer to the virtio state. … … 366 369 } 367 370 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 */ 378 DECLINLINE(uint64_t) virtioGetAcceptedFeatures(PVIRTIOSTATE pVirtio) 379 { 380 return pVirtio->uDriverFeatures; 381 } 382 383 368 384 int virtioR3SaveExec(PVIRTIOSTATE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM); 369 385 int virtioR3LoadExec(PVIRTIOSTATE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM); 386 void virtioR3PropagateResetNotification(PVIRTIOSTATE pVirtio); 387 void virtioR3PropagateResumeNotification(PVIRTIOSTATE pVirtio); 370 388 void virtioR3Term(PVIRTIOSTATE pVirtio, PPDMDEVINS pDevIns); 371 389 int virtioR3Init(PVIRTIOSTATE pVirtio, PPDMDEVINS pDevIns, PVIRTIOPCIPARAMS pPciParams, const char *pcszInstance,
Note:
See TracChangeset
for help on using the changeset viewer.