Changeset 58159 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Oct 9, 2015 5:31:28 PM (9 years ago)
- svn:sync-xref-src-repo-rev:
- 103267
- Location:
- trunk/src/VBox/Devices/VMMDev
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/VMMDev/VMMDev.cpp
r58156 r58159 14 14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the 15 15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 16 */ 17 18 /** @page pg_vmmdev The VMM Device. 19 * 20 * The VMM device is a custom hardware device emulation for communicating with 21 * the guest additions. 22 * 23 * Whenever host wants to inform guest about something an IRQ notification will 24 * be raised. 25 * 26 * VMMDev PDM interface will contain the guest notification method. 27 * 28 * There is a 32 bit event mask which will be read by guest on an interrupt. A 29 * non zero bit in the mask means that the specific event occurred and requires 30 * processing on guest side. 31 * 32 * After reading the event mask guest must issue a generic request 33 * AcknowlegdeEvents. 34 * 35 * IRQ line is set to 1 (request) if there are unprocessed events, that is the 36 * event mask is not zero. 37 * 38 * After receiving an interrupt and checking event mask, the guest must process 39 * events using the event specific mechanism. 40 * 41 * That is if mouse capabilities were changed, guest will use 42 * VMMDev_GetMouseStatus generic request. 43 * 44 * Event mask is only a set of flags indicating that guest must proceed with a 45 * procedure. 46 * 47 * Unsupported events are therefore ignored. The guest additions must inform 48 * host which events they want to receive, to avoid unnecessary IRQ processing. 49 * By default no events are signalled to guest. 50 * 51 * This seems to be fast method. It requires only one context switch for an 52 * event processing. 53 * 16 54 */ 17 55 … … 60 98 * Defined Constants And Macros * 61 99 *********************************************************************************************************************************/ 62 #define V BOX_GUEST_INTERFACE_VERSION_1_03(s) \100 #define VMMDEV_INTERFACE_VERSION_IS_1_03(s) \ 63 101 ( RT_HIWORD((s)->guestInfo.interfaceVersion) == 1 \ 64 102 && RT_LOWORD((s)->guestInfo.interfaceVersion) == 3 ) 65 103 66 #define V BOX_GUEST_INTERFACE_VERSION_OK(additionsVersion) \104 #define VMMDEV_INTERFACE_VERSION_IS_OK(additionsVersion) \ 67 105 ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \ 68 106 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) ) 69 107 70 #define V BOX_GUEST_INTERFACE_VERSION_OLD(additionsVersion) \108 #define VMMDEV_INTERFACE_VERSION_IS_OLD(additionsVersion) \ 71 109 ( (RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) \ 72 110 || ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \ 73 111 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) ) ) 74 112 75 #define V BOX_GUEST_INTERFACE_VERSION_TOO_OLD(additionsVersion) \113 #define VMMDEV_INTERFACE_VERSION_IS_TOO_OLD(additionsVersion) \ 76 114 ( RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) ) 77 115 78 #define V BOX_GUEST_INTERFACE_VERSION_NEW(additionsVersion) \116 #define VMMDEV_INTERFACE_VERSION_IS_NEW(additionsVersion) \ 79 117 ( RT_HIWORD(additionsVersion) > RT_HIWORD(VMMDEV_VERSION) \ 80 118 || ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \ … … 93 131 * Used when no HeartbeatInterval is set in CFGM and for setting 94 132 * HB check timer if the guest's heartbeat frequency is less than 1Hz. */ 95 #define HEARTBEAT_DEFAULT_INTERVAL UINT64_C(2000000000)133 #define VMMDEV_HEARTBEAT_DEFAULT_INTERVAL (2U*RT_NS_1SEC_64) 96 134 97 135 98 136 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 99 137 100 /** @page pg_vmmdev VMMDev101 *102 * Whenever host wants to inform guest about something an IRQ notification will103 * be raised.104 *105 * VMMDev PDM interface will contain the guest notification method.106 *107 * There is a 32 bit event mask which will be read by guest on an interrupt. A108 * non zero bit in the mask means that the specific event occurred and requires109 * processing on guest side.110 *111 * After reading the event mask guest must issue a generic request112 * AcknowlegdeEvents.113 *114 * IRQ line is set to 1 (request) if there are unprocessed events, that is the115 * event mask is not zero.116 *117 * After receiving an interrupt and checking event mask, the guest must process118 * events using the event specific mechanism.119 *120 * That is if mouse capabilities were changed, guest will use121 * VMMDev_GetMouseStatus generic request.122 *123 * Event mask is only a set of flags indicating that guest must proceed with a124 * procedure.125 *126 * Unsupported events are therefore ignored. The guest additions must inform127 * host which events they want to receive, to avoid unnecessary IRQ processing.128 * By default no events are signalled to guest.129 *130 * This seems to be fast method. It requires only one context switch for an131 * event processing.132 *133 */134 135 136 138 /* -=-=-=-=- Misc Helpers -=-=-=-=- */ 137 139 … … 143 145 static void vmmdevLogGuestOsInfo(VBoxGuestInfo *pGuestInfo) 144 146 { 145 const char *p cszOs;147 const char *pszOs; 146 148 switch (pGuestInfo->osType & ~VBOXOSTYPE_x64) 147 149 { 148 case VBOXOSTYPE_DOS: p cszOs = "DOS"; break;149 case VBOXOSTYPE_Win31: p cszOs = "Windows 3.1"; break;150 case VBOXOSTYPE_Win9x: p cszOs = "Windows 9x"; break;151 case VBOXOSTYPE_Win95: p cszOs = "Windows 95"; break;152 case VBOXOSTYPE_Win98: p cszOs = "Windows 98"; break;153 case VBOXOSTYPE_WinMe: p cszOs = "Windows Me"; break;154 case VBOXOSTYPE_WinNT: p cszOs = "Windows NT"; break;155 case VBOXOSTYPE_WinNT4: p cszOs = "Windows NT4"; break;156 case VBOXOSTYPE_Win2k: p cszOs = "Windows 2k"; break;157 case VBOXOSTYPE_WinXP: p cszOs = "Windows XP"; break;158 case VBOXOSTYPE_Win2k3: p cszOs = "Windows 2k3"; break;159 case VBOXOSTYPE_WinVista: p cszOs = "Windows Vista"; break;160 case VBOXOSTYPE_Win2k8: p cszOs = "Windows 2k8"; break;161 case VBOXOSTYPE_Win7: p cszOs = "Windows 7"; break;162 case VBOXOSTYPE_Win8: p cszOs = "Windows 8"; break;163 case VBOXOSTYPE_Win2k12_x64 & ~VBOXOSTYPE_x64: p cszOs = "Windows 2k12"; break;164 case VBOXOSTYPE_Win81: p cszOs = "Windows 8.1"; break;165 case VBOXOSTYPE_Win10: p cszOs = "Windows 10"; break;166 case VBOXOSTYPE_OS2: p cszOs = "OS/2"; break;167 case VBOXOSTYPE_OS2Warp3: p cszOs = "OS/2 Warp 3"; break;168 case VBOXOSTYPE_OS2Warp4: p cszOs = "OS/2 Warp 4"; break;169 case VBOXOSTYPE_OS2Warp45: p cszOs = "OS/2 Warp 4.5"; break;170 case VBOXOSTYPE_ECS: p cszOs = "OS/2 ECS"; break;171 case VBOXOSTYPE_OS21x: p cszOs = "OS/2 2.1x"; break;172 case VBOXOSTYPE_Linux: p cszOs = "Linux"; break;173 case VBOXOSTYPE_Linux22: p cszOs = "Linux 2.2"; break;174 case VBOXOSTYPE_Linux24: p cszOs = "Linux 2.4"; break;175 case VBOXOSTYPE_Linux26: p cszOs = "Linux >= 2.6"; break;176 case VBOXOSTYPE_ArchLinux: p cszOs = "ArchLinux"; break;177 case VBOXOSTYPE_Debian: p cszOs = "Debian"; break;178 case VBOXOSTYPE_OpenSUSE: p cszOs = "openSUSE"; break;179 case VBOXOSTYPE_FedoraCore: p cszOs = "Fedora"; break;180 case VBOXOSTYPE_Gentoo: p cszOs = "Gentoo"; break;181 case VBOXOSTYPE_Mandriva: p cszOs = "Mandriva"; break;182 case VBOXOSTYPE_RedHat: p cszOs = "RedHat"; break;183 case VBOXOSTYPE_Turbolinux: p cszOs = "TurboLinux"; break;184 case VBOXOSTYPE_Ubuntu: p cszOs = "Ubuntu"; break;185 case VBOXOSTYPE_Xandros: p cszOs = "Xandros"; break;186 case VBOXOSTYPE_Oracle: p cszOs = "Oracle Linux"; break;187 case VBOXOSTYPE_FreeBSD: p cszOs = "FreeBSD"; break;188 case VBOXOSTYPE_OpenBSD: p cszOs = "OpenBSD"; break;189 case VBOXOSTYPE_NetBSD: p cszOs = "NetBSD"; break;190 case VBOXOSTYPE_Netware: p cszOs = "Netware"; break;191 case VBOXOSTYPE_Solaris: p cszOs = "Solaris"; break;192 case VBOXOSTYPE_OpenSolaris: p cszOs = "OpenSolaris"; break;193 case VBOXOSTYPE_Solaris11_x64 & ~VBOXOSTYPE_x64: p cszOs = "Solaris 11"; break;194 case VBOXOSTYPE_MacOS: p cszOs = "Mac OS X"; break;195 case VBOXOSTYPE_MacOS106: p cszOs = "Mac OS X 10.6"; break;196 case VBOXOSTYPE_MacOS107_x64 & ~VBOXOSTYPE_x64: p cszOs = "Mac OS X 10.7"; break;197 case VBOXOSTYPE_MacOS108_x64 & ~VBOXOSTYPE_x64: p cszOs = "Mac OS X 10.8"; break;198 case VBOXOSTYPE_MacOS109_x64 & ~VBOXOSTYPE_x64: p cszOs = "Mac OS X 10.9"; break;199 case VBOXOSTYPE_MacOS1010_x64 & ~VBOXOSTYPE_x64: p cszOs = "Mac OS X 10.10"; break;200 case VBOXOSTYPE_MacOS1011_x64 & ~VBOXOSTYPE_x64: p cszOs = "Mac OS X 10.11"; break;201 case VBOXOSTYPE_Haiku: p cszOs = "Haiku"; break;202 default: p cszOs = "unknown"; break;150 case VBOXOSTYPE_DOS: pszOs = "DOS"; break; 151 case VBOXOSTYPE_Win31: pszOs = "Windows 3.1"; break; 152 case VBOXOSTYPE_Win9x: pszOs = "Windows 9x"; break; 153 case VBOXOSTYPE_Win95: pszOs = "Windows 95"; break; 154 case VBOXOSTYPE_Win98: pszOs = "Windows 98"; break; 155 case VBOXOSTYPE_WinMe: pszOs = "Windows Me"; break; 156 case VBOXOSTYPE_WinNT: pszOs = "Windows NT"; break; 157 case VBOXOSTYPE_WinNT4: pszOs = "Windows NT4"; break; 158 case VBOXOSTYPE_Win2k: pszOs = "Windows 2k"; break; 159 case VBOXOSTYPE_WinXP: pszOs = "Windows XP"; break; 160 case VBOXOSTYPE_Win2k3: pszOs = "Windows 2k3"; break; 161 case VBOXOSTYPE_WinVista: pszOs = "Windows Vista"; break; 162 case VBOXOSTYPE_Win2k8: pszOs = "Windows 2k8"; break; 163 case VBOXOSTYPE_Win7: pszOs = "Windows 7"; break; 164 case VBOXOSTYPE_Win8: pszOs = "Windows 8"; break; 165 case VBOXOSTYPE_Win2k12_x64 & ~VBOXOSTYPE_x64: pszOs = "Windows 2k12"; break; 166 case VBOXOSTYPE_Win81: pszOs = "Windows 8.1"; break; 167 case VBOXOSTYPE_Win10: pszOs = "Windows 10"; break; 168 case VBOXOSTYPE_OS2: pszOs = "OS/2"; break; 169 case VBOXOSTYPE_OS2Warp3: pszOs = "OS/2 Warp 3"; break; 170 case VBOXOSTYPE_OS2Warp4: pszOs = "OS/2 Warp 4"; break; 171 case VBOXOSTYPE_OS2Warp45: pszOs = "OS/2 Warp 4.5"; break; 172 case VBOXOSTYPE_ECS: pszOs = "OS/2 ECS"; break; 173 case VBOXOSTYPE_OS21x: pszOs = "OS/2 2.1x"; break; 174 case VBOXOSTYPE_Linux: pszOs = "Linux"; break; 175 case VBOXOSTYPE_Linux22: pszOs = "Linux 2.2"; break; 176 case VBOXOSTYPE_Linux24: pszOs = "Linux 2.4"; break; 177 case VBOXOSTYPE_Linux26: pszOs = "Linux >= 2.6"; break; 178 case VBOXOSTYPE_ArchLinux: pszOs = "ArchLinux"; break; 179 case VBOXOSTYPE_Debian: pszOs = "Debian"; break; 180 case VBOXOSTYPE_OpenSUSE: pszOs = "openSUSE"; break; 181 case VBOXOSTYPE_FedoraCore: pszOs = "Fedora"; break; 182 case VBOXOSTYPE_Gentoo: pszOs = "Gentoo"; break; 183 case VBOXOSTYPE_Mandriva: pszOs = "Mandriva"; break; 184 case VBOXOSTYPE_RedHat: pszOs = "RedHat"; break; 185 case VBOXOSTYPE_Turbolinux: pszOs = "TurboLinux"; break; 186 case VBOXOSTYPE_Ubuntu: pszOs = "Ubuntu"; break; 187 case VBOXOSTYPE_Xandros: pszOs = "Xandros"; break; 188 case VBOXOSTYPE_Oracle: pszOs = "Oracle Linux"; break; 189 case VBOXOSTYPE_FreeBSD: pszOs = "FreeBSD"; break; 190 case VBOXOSTYPE_OpenBSD: pszOs = "OpenBSD"; break; 191 case VBOXOSTYPE_NetBSD: pszOs = "NetBSD"; break; 192 case VBOXOSTYPE_Netware: pszOs = "Netware"; break; 193 case VBOXOSTYPE_Solaris: pszOs = "Solaris"; break; 194 case VBOXOSTYPE_OpenSolaris: pszOs = "OpenSolaris"; break; 195 case VBOXOSTYPE_Solaris11_x64 & ~VBOXOSTYPE_x64: pszOs = "Solaris 11"; break; 196 case VBOXOSTYPE_MacOS: pszOs = "Mac OS X"; break; 197 case VBOXOSTYPE_MacOS106: pszOs = "Mac OS X 10.6"; break; 198 case VBOXOSTYPE_MacOS107_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.7"; break; 199 case VBOXOSTYPE_MacOS108_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.8"; break; 200 case VBOXOSTYPE_MacOS109_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.9"; break; 201 case VBOXOSTYPE_MacOS1010_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.10"; break; 202 case VBOXOSTYPE_MacOS1011_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.11"; break; 203 case VBOXOSTYPE_Haiku: pszOs = "Haiku"; break; 204 default: pszOs = "unknown"; break; 203 205 } 204 206 LogRel(("VMMDev: Guest Additions information report: Interface = 0x%08X osType = 0x%08X (%s, %u-bit)\n", 205 pGuestInfo->interfaceVersion, pGuestInfo->osType, p cszOs,207 pGuestInfo->interfaceVersion, pGuestInfo->osType, pszOs, 206 208 pGuestInfo->osType & VBOXOSTYPE_x64 ? 64 : 32)); 207 209 } … … 216 218 static void vmmdevSetIRQ_Legacy(PVMMDEV pThis) 217 219 { 218 if (!pThis->fu32AdditionsOk) 219 { 220 if (pThis->fu32AdditionsOk) 221 { 222 /* Filter unsupported events */ 223 uint32_t fEvents = pThis->u32HostEventFlags & pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask; 224 225 Log(("vmmdevSetIRQ: fEvents=%#010x, u32HostEventFlags=%#010x, u32GuestEventMask=%#010x.\n", 226 fEvents, pThis->u32HostEventFlags, pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask)); 227 228 /* Move event flags to VMMDev RAM */ 229 pThis->pVMMDevRAMR3->V.V1_03.u32HostEvents = fEvents; 230 231 uint32_t uIRQLevel = 0; 232 if (fEvents) 233 { 234 /* Clear host flags which will be delivered to guest. */ 235 pThis->u32HostEventFlags &= ~fEvents; 236 Log(("vmmdevSetIRQ: u32HostEventFlags=%#010x\n", pThis->u32HostEventFlags)); 237 uIRQLevel = 1; 238 } 239 240 /* Set IRQ level for pin 0 (see NoWait comment in vmmdevMaybeSetIRQ). */ 241 /** @todo make IRQ pin configurable, at least a symbolic constant */ 242 PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, uIRQLevel); 243 Log(("vmmdevSetIRQ: IRQ set %d\n", uIRQLevel)); 244 } 245 else 220 246 Log(("vmmdevSetIRQ: IRQ is not generated, guest has not yet reported to us.\n")); 221 return;222 }223 224 /* Filter unsupported events */225 uint32_t u32EventFlags = pThis->u32HostEventFlags226 & pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask;227 228 Log(("vmmdevSetIRQ: u32EventFlags=%#010x, u32HostEventFlags=%#010x, u32GuestEventMask=%#010x.\n",229 u32EventFlags, pThis->u32HostEventFlags, pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask));230 231 /* Move event flags to VMMDev RAM */232 pThis->pVMMDevRAMR3->V.V1_03.u32HostEvents = u32EventFlags;233 234 uint32_t u32IRQLevel = 0;235 if (u32EventFlags)236 {237 /* Clear host flags which will be delivered to guest. */238 pThis->u32HostEventFlags &= ~u32EventFlags;239 Log(("vmmdevSetIRQ: u32HostEventFlags=%#010x\n", pThis->u32HostEventFlags));240 u32IRQLevel = 1;241 }242 243 /* Set IRQ level for pin 0 (see NoWait comment in vmmdevMaybeSetIRQ). */244 /** @todo make IRQ pin configurable, at least a symbolic constant */245 PPDMDEVINS pDevIns = pThis->pDevIns;246 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, u32IRQLevel);247 Log(("vmmdevSetIRQ: IRQ set %d\n", u32IRQLevel));248 247 } 249 248 … … 286 285 Assert(PDMCritSectIsOwner(&pThis->CritSect)); 287 286 288 if (VBOX_GUEST_INTERFACE_VERSION_1_03(pThis)) 287 if (!VMMDEV_INTERFACE_VERSION_IS_1_03(pThis)) 288 { 289 Log3(("vmmdevNotifyGuestWorker: New additions detected.\n")); 290 291 if (pThis->fu32AdditionsOk) 292 { 293 const bool fHadEvents = (pThis->u32HostEventFlags & pThis->u32GuestFilterMask) != 0; 294 295 Log3(("vmmdevNotifyGuestWorker: fHadEvents=%d, u32HostEventFlags=%#010x, u32GuestFilterMask=%#010x.\n", 296 fHadEvents, pThis->u32HostEventFlags, pThis->u32GuestFilterMask)); 297 298 pThis->u32HostEventFlags |= fAddEvents; 299 300 if (!fHadEvents) 301 vmmdevMaybeSetIRQ(pThis); 302 } 303 else 304 { 305 pThis->u32HostEventFlags |= fAddEvents; 306 Log(("vmmdevNotifyGuestWorker: IRQ is not generated, guest has not yet reported to us.\n")); 307 } 308 } 309 else 289 310 { 290 311 Log3(("vmmdevNotifyGuestWorker: Old additions detected.\n")); … … 292 313 pThis->u32HostEventFlags |= fAddEvents; 293 314 vmmdevSetIRQ_Legacy(pThis); 294 }295 else296 {297 Log3(("vmmdevNotifyGuestWorker: New additions detected.\n"));298 299 if (!pThis->fu32AdditionsOk)300 {301 pThis->u32HostEventFlags |= fAddEvents;302 Log(("vmmdevNotifyGuestWorker: IRQ is not generated, guest has not yet reported to us.\n"));303 return;304 }305 306 const bool fHadEvents = (pThis->u32HostEventFlags & pThis->u32GuestFilterMask) != 0;307 308 Log3(("vmmdevNotifyGuestWorker: fHadEvents=%d, u32HostEventFlags=%#010x, u32GuestFilterMask=%#010x.\n",309 fHadEvents, pThis->u32HostEventFlags, pThis->u32GuestFilterMask));310 311 pThis->u32HostEventFlags |= fAddEvents;312 313 if (!fHadEvents)314 vmmdevMaybeSetIRQ(pThis);315 315 } 316 316 } … … 334 334 335 335 /* 336 * Drop notifications if the VM is not running yet/anymore.336 * Only notify the VM when it's running. 337 337 */ 338 338 VMSTATE enmVMState = PDMDevHlpVMState(pThis->pDevIns); 339 if ( enmVMState != VMSTATE_RUNNING 340 && enmVMState != VMSTATE_RUNNING_LS) 341 return; 342 343 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED); 344 vmmdevNotifyGuestWorker(pThis, fAddEvents); 345 PDMCritSectLeave(&pThis->CritSect); 339 /** @todo r=bird: Shouldn't there be more states here? Wouldn't we drop 340 * notifications now when we're in the process of suspending or 341 * similar? */ 342 if ( enmVMState == VMSTATE_RUNNING 343 || enmVMState == VMSTATE_RUNNING_LS) 344 { 345 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED); 346 vmmdevNotifyGuestWorker(pThis, fAddEvents); 347 PDMCritSectLeave(&pThis->CritSect); 348 } 346 349 } 347 350 … … 408 411 409 412 /* Check additions interface version. */ 410 pThis->fu32AdditionsOk = V BOX_GUEST_INTERFACE_VERSION_OK(pThis->guestInfo.interfaceVersion);413 pThis->fu32AdditionsOk = VMMDEV_INTERFACE_VERSION_IS_OK(pThis->guestInfo.interfaceVersion); 411 414 412 415 vmmdevLogGuestOsInfo(&pThis->guestInfo); … … 427 430 428 431 /** 429 * Resets heartbeat timer. 430 * 431 * @param pThis The VMMDev state. 432 * @returns VBox status code. 433 */ 434 static int vmmDevHeartbeatTimerReset(PVMMDEV pThis) 435 { 432 * Handles VMMDevReq_GuestHeartbeat. 433 * 434 * @returns VBox status code that the guest should see. 435 * @param pThis The VMMDev instance data. 436 */ 437 static int vmmDevReqHandler_GuestHeartbeat(PVMMDEV pThis) 438 { 439 int rc; 436 440 if (pThis->fHBCheckEnabled) 437 return TMTimerSetNano(pThis->pHBCheckTimer, pThis->u64HeartbeatTimeout); 438 439 return VINF_SUCCESS; 440 } 441 442 443 /** 444 * Handles VMMDevReq_GuestHeartbeat. 445 * 446 * @returns VBox status code that the guest should see. 447 * @param pThis The VMMDev instance data. 448 */ 449 static int vmmDevReqHandler_GuestHeartbeat(PVMMDEV pThis) 450 { 451 int rc = VINF_SUCCESS; 452 441 { 442 uint64_t const nsNowTS = TMTimerGetNano(pThis->pHearbeatFlatlinedTimer); 443 if (!pThis->fHasMissedHB) 444 { /* likely */ } 445 else 446 { 447 LogRel(("VMMDev: GuestHeartBeat: Guest is alive (gone %'llu ns)\n", nsNowTS - pThis->nsLastHeartbeatTS)); 448 ASMAtomicWriteBool(&pThis->fHasMissedHB, false); 449 } 450 ASMAtomicWriteU64(&pThis->nsLastHeartbeatTS, nsNowTS); 451 452 /* Postpone (or restart if we missed a beat) the timeout timer. */ 453 rc = TMTimerSetNano(pThis->pHearbeatFlatlinedTimer, pThis->cNsHeartbeatTimeout); 454 } 455 else 456 rc = VINF_SUCCESS; 457 return rc; 458 } 459 460 461 /** 462 * Timer that fires when where have been no heartbeats for a given time. 463 * 464 * @remarks Does not take the VMMDev critsect. 465 */ 466 static DECLCALLBACK(void) vmmDevHeartbeatFlatlinedTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 467 { 468 PVMMDEV pThis = (PVMMDEV)pvUser; 453 469 if (pThis->fHBCheckEnabled) 454 470 { 455 ASMAtomicWriteU64(&pThis->uLastHBTime, TMTimerGetNano(pThis->pHBCheckTimer)); 456 if (pThis->fHasMissedHB) 457 { 458 LogRel(("VMMDev: GuestHeartBeat: Guest is alive\n")); 459 ASMAtomicWriteBool(&pThis->fHasMissedHB, false); 460 } 461 rc = vmmDevHeartbeatTimerReset(pThis); 462 } 463 return rc; 464 } 465 466 467 /** 468 * Guest heartbeat check timer. Fires if there are no heartbeats for certain time. 469 * Timer is set in vmmDevHeartbeatTimerReset. 470 */ 471 static DECLCALLBACK(void) vmmDevHeartBeatCheckTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 472 { 473 PVMMDEV pThis = (PVMMDEV) pvUser; 474 if (pThis->fHBCheckEnabled) 475 { 476 uint64_t uIntervalNs = TMTimerGetNano(pTimer) - pThis->uLastHBTime; 477 if (!pThis->fHasMissedHB && uIntervalNs >= pThis->u64HeartbeatInterval) 478 { 479 LogRel(("VMMDev: HeartBeatCheckTimer: Guest seems to be unresponsive. Last heartbeat received %RU64 seconds ago\n", 480 uIntervalNs / RT_NS_1SEC_64)); 471 uint64_t cNsElapsed = TMTimerGetNano(pTimer) - pThis->nsLastHeartbeatTS; 472 if ( !pThis->fHasMissedHB 473 && cNsElapsed >= pThis->cNsHeartbeatInterval) 474 { 475 LogRel(("VMMDev: vmmDevHeartbeatFlatlinedTimer: Guest seems to be unresponsive. Last heartbeat received %RU64 seconds ago\n", 476 cNsElapsed / RT_NS_1SEC)); 481 477 ASMAtomicWriteBool(&pThis->fHasMissedHB, true); 482 478 } … … 498 494 int rc; 499 495 500 pReq->cNsInterval = pThis-> u64HeartbeatInterval;496 pReq->cNsInterval = pThis->cNsHeartbeatInterval; 501 497 502 498 if (pReq->fEnabled != pThis->fHBCheckEnabled) … … 505 501 if (pReq->fEnabled) 506 502 { 507 /* set first timer explicitly*/508 rc = vmmDevHeartbeatTimerReset(pThis);503 /* Start the countdown. */ 504 rc = TMTimerSetNano(pThis->pHearbeatFlatlinedTimer, pThis->cNsHeartbeatTimeout); 509 505 if (RT_SUCCESS(rc)) 510 506 LogRel(("VMMDev: Heartbeat checking timer set to trigger every %RU64 milliseconds\n", 511 pThis-> u64HeartbeatTimeout / RT_NS_1MS));507 pThis->cNsHeartbeatTimeout / RT_NS_1MS)); 512 508 else 513 509 LogRel(("VMMDev: Cannot create heartbeat check timer, rc=%Rrc\n", rc)); … … 515 511 else 516 512 { 517 rc = TMTimerStop(pThis->pH BCheckTimer);513 rc = TMTimerStop(pThis->pHearbeatFlatlinedTimer); 518 514 LogRel(("VMMDev: Heartbeat checking timer has been stopped, rc=%Rrc\n", rc)); 519 515 } … … 1576 1572 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER); 1577 1573 1578 if (V BOX_GUEST_INTERFACE_VERSION_1_03(pThis))1574 if (VMMDEV_INTERFACE_VERSION_IS_1_03(pThis)) 1579 1575 { 1580 1576 vmmdevSetIRQ_Legacy(pThis); … … 4004 4000 N_("Configuration error: Failed querying \"GuestCoreDumpCount\" as a 32-bit unsigned integer")); 4005 4001 4006 rc = CFGMR3QueryU64Def(pCfg, "HeartbeatInterval", &pThis-> u64HeartbeatInterval,HEARTBEAT_DEFAULT_INTERVAL);4002 rc = CFGMR3QueryU64Def(pCfg, "HeartbeatInterval", &pThis->cNsHeartbeatInterval, VMMDEV_HEARTBEAT_DEFAULT_INTERVAL); 4007 4003 if (RT_FAILURE(rc)) 4008 4004 return PDMDEV_SET_ERROR(pDevIns, rc, 4009 4005 N_("Configuration error: Failed querying \"HeartbeatInterval\" as a 64-bit unsigned integer")); 4010 if (pThis-> u64HeartbeatInterval < RT_NS_100MS/2)4006 if (pThis->cNsHeartbeatInterval < RT_NS_100MS / 2) 4011 4007 return PDMDEV_SET_ERROR(pDevIns, rc, 4012 4008 N_("Configuration error: Heartbeat interval \"HeartbeatInterval\" too small")); 4013 4009 4014 rc = CFGMR3QueryU64Def(pCfg, "HeartbeatTimeout", &pThis-> u64HeartbeatTimeout, pThis->u64HeartbeatInterval * 2);4010 rc = CFGMR3QueryU64Def(pCfg, "HeartbeatTimeout", &pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval * 2); 4015 4011 if (RT_FAILURE(rc)) 4016 4012 return PDMDEV_SET_ERROR(pDevIns, rc, 4017 4013 N_("Configuration error: Failed querying \"HeartbeatTimeout\" as a 64-bit unsigned integer")); 4018 if (pThis-> u64HeartbeatTimeout < RT_NS_100MS)4014 if (pThis->cNsHeartbeatTimeout < RT_NS_100MS) 4019 4015 return PDMDEV_SET_ERROR(pDevIns, rc, 4020 N_("Configuration error: Heartbeat timeout timer interval \"HeartbeatTimeout\" too small")); 4016 N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" too small")); 4017 if (pThis->cNsHeartbeatTimeout <= pThis->cNsHeartbeatInterval + RT_NS_10MS) 4018 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 4019 N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" value (%'ull ns) is too close to the interval (%'ull ns)"), 4020 pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval); 4021 4021 4022 4022 #ifndef VBOX_WITHOUT_TESTING_FEATURES … … 4169 4169 * Create heartbeat checking timer. 4170 4170 */ 4171 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vmmDevHeart BeatCheckTimer, pThis,4172 TMTIMER_FLAGS_NO_CRIT_SECT, "HB Check Timer", &pThis->pHBCheckTimer);4171 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vmmDevHeartbeatFlatlinedTimer, pThis, 4172 TMTIMER_FLAGS_NO_CRIT_SECT, "Heartbeat flatlined", &pThis->pHearbeatFlatlinedTimer); 4173 4173 AssertRCReturn(rc, rc); 4174 4174 -
trunk/src/VBox/Devices/VMMDev/VMMDevState.h
r56292 r58159 361 361 362 362 /** Timestamp of the last heartbeat from guest in nanosec. */ 363 uint64_t volatile uLastHBTime;363 uint64_t volatile nsLastHeartbeatTS; 364 364 /** Indicates whether we missed HB from guest on last check. */ 365 365 bool volatile fHasMissedHB; … … 368 368 /** Alignment padding. */ 369 369 bool afAlignment8[6]; 370 /** Guest heartbeat interval in nanoseconds. */ 371 uint64_t u64HeartbeatInterval; 372 /** Guest heartbeat timeout in nanoseconds. */ 373 uint64_t u64HeartbeatTimeout; 374 /** Timer for checking guest heart beat. */ 375 PTMTIMERR3 pHBCheckTimer; 370 /** Guest heartbeat interval in nanoseconds. 371 * This is the interval the guest is told to produce heartbeats at. */ 372 uint64_t cNsHeartbeatInterval; 373 /** The amount of time without a heartbeat (nanoseconds) before we 374 * conclude the guest is doing a Dixie Flatline (Neuromancer) impression. */ 375 uint64_t cNsHeartbeatTimeout; 376 /** Timer for signalling a flatlined guest. */ 377 PTMTIMERR3 pHearbeatFlatlinedTimer; 376 378 } VMMDevState; 377 379 typedef VMMDevState VMMDEV;
Note:
See TracChangeset
for help on using the changeset viewer.