Changeset 54252 in vbox for trunk/src/VBox/HostDrivers/Support/SUPDrv.c
- Timestamp:
- Feb 17, 2015 7:24:45 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 98319
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrv.c
r54224 r54252 124 124 /** The TSC-refinement interval in seconds. */ 125 125 #define GIP_TSC_REFINE_INTERVAL 5 126 /** The TSC-delta threshold (in ticks) for whether it's worth applying them or 127 * not for performance reasons, see @bugref{6710} comment #124. */ 128 #define GIP_TSC_DELTA_APPLY_THRESHOLD 384 126 /** The TSC-delta threshold for the SUPGIPUSETSCDELTA_PRACTICALLY_ZERO rating */ 127 #define GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO 24 128 /** The TSC-delta threshold for the SUPGIPUSETSCDELTA_ROUGHLY_ZERO rating */ 129 #define GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO 384 129 130 130 131 AssertCompile(GIP_TSC_DELTA_PRIMER_LOOPS < GIP_TSC_DELTA_READ_TIME_LOOPS); … … 163 164 static int supdrvIOCtl_LoggerSettings(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLOGGERSETTINGS pReq); 164 165 static int supdrvIOCtl_MsrProber(PSUPDRVDEVEXT pDevExt, PSUPMSRPROBER pReq); 165 static int supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUP TSCDELTAMEASURE pReq);166 static int supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCDELTAMEASURE pReq); 166 167 static int supdrvIOCtl_TscRead(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCREAD pReq); 167 168 static int supdrvGipCreate(PSUPDRVDEVEXT pDevExt); 168 169 static void supdrvGipDestroy(PSUPDRVDEVEXT pDevExt); 169 static DECLCALLBACK(void) supdrvGipSync Timer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);170 static DECLCALLBACK(void) supdrvGipSyncAndInvariantTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick); 170 171 static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick); 171 172 static DECLCALLBACK(void) supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser); … … 2252 2253 REQ_CHECK_SIZES(SUP_IOCTL_TSC_DELTA_MEASURE); 2253 2254 2254 pReqHdr->rc = supdrvIOCtl_TscDeltaMeasure(pDevExt, p Req);2255 pReqHdr->rc = supdrvIOCtl_TscDeltaMeasure(pDevExt, pSession, pReq); 2255 2256 return 0; 2256 2257 } … … 4031 4032 4032 4033 /** 4034 * State structure for supdrvGipDetectGetGipCpuCallback. 4035 */ 4036 typedef struct SUPDRVGIPDETECTGETCPU 4037 { 4038 /** Bitmap of APIC IDs that has been seen (initialized to zero). 4039 * Used to detect duplicate APIC IDs (paranoia). */ 4040 uint8_t volatile bmApicId[256 / 8]; 4041 /** Mask of supported GIP CPU getter methods (SUPGIPGETCPU_XXX) (all bits set 4042 * initially). The callback clears the methods not detected. */ 4043 uint32_t volatile fSupported; 4044 /** The first callback detecting any kind of range issues (initializsed to 4045 * NIL_RTCPUID). */ 4046 RTCPUID volatile idCpuProblem; 4047 } SUPDRVGIPDETECTGETCPU; 4048 /** Pointer to state structure for supdrvGipDetectGetGipCpuCallback. */ 4049 typedef SUPDRVGIPDETECTGETCPU *PSUPDRVGIPDETECTGETCPU; 4050 4051 4052 /** 4053 * Checks for alternative ways of getting the CPU ID. 4054 * 4055 * This also checks the APIC ID, CPU ID and CPU set index values against the 4056 * GIP tables. 4057 * 4058 * @param idCpu The CPU ID. Unused - we have to use the APIC ID. 4059 * @param pvUser1 Pointer to the state structure. 4060 * @param pvUser2 Pointer to the GIP. 4061 */ 4062 static DECLCALLBACK(void) supdrvGipDetectGetGipCpuCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2) 4063 { 4064 PSUPDRVGIPDETECTGETCPU pState = (PSUPDRVGIPDETECTGETCPU)pvUser1; 4065 PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser2; 4066 uint32_t fSupported = 0; 4067 uint16_t idApic; 4068 int iCpuSet; 4069 4070 AssertMsg(idCpu == RTMpCpuId(), ("idCpu=%#x RTMpCpuId()=%#x\n", idCpu, RTMpCpuId())); /* paranoia^3 */ 4071 4072 /* 4073 * Check that the CPU ID and CPU set index are interchangable. 4074 */ 4075 iCpuSet = RTMpCpuIdToSetIndex(idCpu); 4076 if ((RTCPUID)iCpuSet == idCpu) 4077 { 4078 AssertCompile(RT_IS_POWER_OF_TWO(RTCPUSET_MAX_CPUS)); 4079 if ( iCpuSet >= 0 4080 && iCpuSet < RTCPUSET_MAX_CPUS 4081 && RT_IS_POWER_OF_TWO(RTCPUSET_MAX_CPUS)) 4082 { 4083 /* 4084 * Check whether the IDTR.LIMIT contains a CPU number. 4085 */ 4086 #ifdef RT_ARCH_X86 4087 uint16_t const cbIdt = sizeof(X86DESC64SYSTEM); 4088 #else 4089 uint16_t const cbIdt = sizeof(X86DESCGATE); 4090 #endif 4091 RTIDTR Idtr; 4092 ASMGetIDTR(&Idtr); 4093 if (Idtr.cbIdt >= cbIdt) 4094 { 4095 uint32_t uTmp = Idtr.cbIdt - cbIdt; 4096 uTmp &= RTCPUSET_MAX_CPUS - 1; 4097 if (uTmp == idCpu) 4098 { 4099 RTIDTR Idtr2; 4100 ASMGetIDTR(&Idtr2); 4101 if (Idtr2.cbIdt == Idtr.cbIdt) 4102 fSupported |= SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS; 4103 } 4104 } 4105 4106 /* 4107 * Check whether RDTSCP is an option. 4108 */ 4109 if (ASMHasCpuId()) 4110 { 4111 if ( ASMIsValidExtRange(ASMCpuId_EAX(UINT32_C(0x80000000))) 4112 && (ASMCpuId_EDX(UINT32_C(0x80000001)) & X86_CPUID_EXT_FEATURE_EDX_RDTSCP) ) 4113 { 4114 uint32_t uAux; 4115 ASMReadTscWithAux(&uAux); 4116 if ((uAux & (RTCPUSET_MAX_CPUS - 1)) == idCpu) 4117 { 4118 ASMNopPause(); 4119 ASMReadTscWithAux(&uAux); 4120 if ((uAux & (RTCPUSET_MAX_CPUS - 1)) == idCpu) 4121 fSupported |= SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS; 4122 } 4123 } 4124 } 4125 } 4126 } 4127 4128 /* 4129 * Check that the APIC ID is unique. 4130 */ 4131 idApic = ASMGetApicId(); 4132 if (RT_LIKELY( idApic < RT_ELEMENTS(pGip->aiCpuFromApicId) 4133 && !ASMAtomicBitTestAndSet(pState->bmApicId, idApic))) 4134 fSupported |= SUPGIPGETCPU_APIC_ID; 4135 else 4136 { 4137 AssertCompile(sizeof(pState->bmApicId) * 8 == RT_ELEMENTS(pGip->aiCpuFromApicId)); 4138 ASMAtomicCmpXchgU32(&pState->idCpuProblem, idCpu, NIL_RTCPUID); 4139 LogRel(("supdrvGipDetectGetGipCpuCallback: idCpu=%#x iCpuSet=%d idApic=%#x - duplicate APIC ID.\n", 4140 idCpu, iCpuSet, idApic)); 4141 } 4142 4143 /* 4144 * Check that the iCpuSet is within the expected range. 4145 */ 4146 if (RT_UNLIKELY( iCpuSet < 0 4147 || iCpuSet >= RTCPUSET_MAX_CPUS 4148 || iCpuSet >= RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) 4149 { 4150 ASMAtomicCmpXchgU32(&pState->idCpuProblem, idCpu, NIL_RTCPUID); 4151 LogRel(("supdrvGipDetectGetGipCpuCallback: idCpu=%#x iCpuSet=%d idApic=%#x - CPU set index is out of range.\n", 4152 idCpu, iCpuSet, idApic)); 4153 } 4154 else 4155 { 4156 RTCPUID idCpu2 = RTMpCpuIdFromSetIndex(iCpuSet); 4157 if (RT_UNLIKELY(idCpu2 != idCpu)) 4158 { 4159 ASMAtomicCmpXchgU32(&pState->idCpuProblem, idCpu, NIL_RTCPUID); 4160 LogRel(("supdrvGipDetectGetGipCpuCallback: idCpu=%#x iCpuSet=%d idApic=%#x - CPU id/index roundtrip problem: %#x\n", 4161 idCpu, iCpuSet, idApic, idCpu2)); 4162 } 4163 } 4164 4165 /* 4166 * Update the supported feature mask before we return. 4167 */ 4168 ASMAtomicAndU32(&pState->fSupported, fSupported); 4169 4170 NOREF(pvUser2); 4171 } 4172 4173 4174 /** 4033 4175 * Increase the timer freqency on hosts where this is possible (NT). 4034 4176 * … … 4138 4280 uint64_t u64NanoTS; 4139 4281 4282 /* 4283 * GIP starts/resumes updating again. On windows we bump the 4284 * host timer frequency to make sure we don't get stuck in guest 4285 * mode and to get better timer (and possibly clock) accuracy. 4286 */ 4140 4287 LogFlow(("SUPR0GipMap: Resumes GIP updating\n")); 4141 4288 4142 4289 supdrvGipRequestHigherTimerFrequencyFromSystem(pDevExt); 4143 4290 4291 /* 4292 * document me 4293 */ 4144 4294 if (pGipR0->aCPUs[0].u32TransactionId != 2 /* not the first time */) 4145 4295 { … … 4152 4302 } 4153 4303 4304 /* 4305 * document me 4306 */ 4154 4307 u64NanoTS = RTTimeSystemNanoTS() - pGipR0->u32UpdateIntervalNS; 4155 4308 if ( pGipR0->u32Mode == SUPGIPMODE_INVARIANT_TSC … … 4160 4313 RTMpOnAll(supdrvGipReInitCpuCallback, pGipR0, &u64NanoTS); 4161 4314 4315 /* 4316 * Detect alternative ways to figure the CPU ID in ring-3 and 4317 * raw-mode context. Check the sanity of the APIC IDs, CPU IDs, 4318 * and CPU set indexes while we're at it. 4319 */ 4320 if (RT_SUCCESS(rc)) 4321 { 4322 SUPDRVGIPDETECTGETCPU DetectState; 4323 RT_ZERO(DetectState.bmApicId); 4324 DetectState.fSupported = UINT32_MAX; 4325 DetectState.idCpuProblem = NIL_RTCPUID; 4326 rc = RTMpOnAll(supdrvGipDetectGetGipCpuCallback, &DetectState, pGipR0); 4327 if (DetectState.idCpuProblem == NIL_RTCPUID) 4328 { 4329 if ( DetectState.fSupported != UINT32_MAX 4330 && DetectState.fSupported != 0) 4331 { 4332 if (pGipR0->fGetGipCpu != DetectState.fSupported) 4333 { 4334 pGipR0->fGetGipCpu = DetectState.fSupported; 4335 LogRel(("SUPR0GipMap: fGetGipCpu=%#x\n", DetectState.fSupported)); 4336 } 4337 } 4338 else 4339 { 4340 LogRel(("SUPR0GipMap: No supported ways of getting the APIC ID or CPU number in ring-3! (%#x)\n", 4341 DetectState.fSupported)); 4342 rc = VERR_UNSUPPORTED_CPU; 4343 } 4344 } 4345 else 4346 { 4347 LogRel(("SUPR0GipMap: APIC ID, CPU ID or CPU set index problem detected on CPU #%u (%#x)!\n", 4348 DetectState.idCpuProblem, DetectState.idCpuProblem)); 4349 rc = VERR_INVALID_CPU_ID; 4350 } 4351 } 4352 4353 /* 4354 * Start the GIP timer if all is well.. 4355 */ 4356 if (RT_SUCCESS(rc)) 4357 { 4162 4358 #ifndef DO_NOT_START_GIP 4163 rc = RTTimerStart(pDevExt->pGipTimer, 0 /* fire ASAP */); AssertRC(rc);4359 rc = RTTimerStart(pDevExt->pGipTimer, 0 /* fire ASAP */); AssertRC(rc); 4164 4360 #endif 4165 rc = VINF_SUCCESS; 4361 rc = VINF_SUCCESS; 4362 } 4363 4364 /* 4365 * Bail out on error. 4366 */ 4367 if (RT_FAILURE(rc)) 4368 { 4369 LogRel(("SUPR0GipMap: failed rc=%Rrc\n", rc)); 4370 pDevExt->cGipUsers = 0; 4371 pSession->fGipReferenced = 0; 4372 if (pSession->GipMapObjR3 != NIL_RTR0MEMOBJ) 4373 { 4374 int rc2 = RTR0MemObjFree(pSession->GipMapObjR3, false); AssertRC(rc2); 4375 if (RT_SUCCESS(rc2)) 4376 pSession->GipMapObjR3 = NIL_RTR0MEMOBJ; 4377 } 4378 HCPhys = NIL_RTHCPHYS; 4379 pGipR3 = NIL_RTR3PTR; 4380 } 4166 4381 } 4167 4382 } … … 5781 5996 } 5782 5997 5783 5784 5998 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 5999 5785 6000 /** 5786 6001 * Switches the TSC-delta measurement thread into the butchered state. … … 6035 6250 static int supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt) 6036 6251 { 6037 Assert( GIP_ARE_TSC_DELTAS_APPLICABLE(pDevExt->pGip));6252 Assert(pDevExt->pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); 6038 6253 6039 6254 int rc = RTSpinlockCreate(&pDevExt->hTscDeltaSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "VBoxTscSpnLck"); … … 6136 6351 return VERR_TIMEOUT; 6137 6352 } 6353 6138 6354 #endif /* SUPDRV_USE_TSC_DELTA_THREAD */ 6139 6140 6355 6141 6356 /** … … 6164 6379 AssertPtr(puTsc); 6165 6380 AssertPtr(pGip); 6166 Assert( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));6381 Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); 6167 6382 6168 6383 /* … … 6284 6499 ASMSetFlags(uFlags); 6285 6500 6286 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6501 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 6287 6502 { 6288 6503 int rc; … … 6362 6577 u64NanoTS = RTTimeSystemNanoTS(); 6363 6578 ASMSetFlags(uFlags); 6364 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6579 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 6365 6580 supdrvTscDeltaApply(pGip, &u64Tsc, idApic, &fDeltaApplied); 6366 6581 u64DeltaNanoTS = u64NanoTS - pDevExt->u64NanoTSAnchor; … … 6381 6596 else 6382 6597 { 6383 #if 16384 6598 RTUINT128U CpuHz, Tmp, Divisor; 6385 6599 CpuHz.s.Lo = CpuHz.s.Hi = 0; … … 6387 6601 RTUInt128Div(&CpuHz, &Tmp, RTUInt128AssignU64(&Divisor, u64DeltaNanoTS)); 6388 6602 pGip->u64CpuHz = CpuHz.s.Lo; 6389 #else6390 /** @todo remove later */6391 /* Try not to lose precision, the larger the interval the more likely we overflow. */6392 if ( u64DeltaTsc < UINT64_MAX / RT_NS_100MS6393 && u64DeltaNanoTS / 10 < UINT32_MAX)6394 pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_100MS, (uint32_t)(u64DeltaNanoTS / 10));6395 else if ( u64DeltaTsc < UINT64_MAX / RT_NS_10MS6396 && u64DeltaNanoTS / 100 < UINT32_MAX)6397 pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_10MS, (uint32_t)(u64DeltaNanoTS / 100));6398 else if ( u64DeltaTsc < UINT64_MAX / RT_NS_1MS6399 && u64DeltaNanoTS / 1000 < UINT32_MAX)6400 pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_1MS, (uint32_t)(u64DeltaNanoTS / 1000));6401 else /* Screw it. */6402 pGip->u64CpuHz = u64DeltaTsc / (u64DeltaNanoTS / RT_NS_1SEC_64);6403 #endif6404 6603 } 6405 6604 … … 6428 6627 Assert(pDevExt->pGip); 6429 6628 6629 /* 6630 * <Insert missing comment [it's not "Validate.", I think...]> 6631 */ 6430 6632 pGip = pDevExt->pGip; 6431 6633 u64NanoTS = RTTimeSystemNanoTS(); … … 6437 6639 pDevExt->u64NanoTSAnchor = RTTimeSystemNanoTS(); 6438 6640 ASMSetFlags(uFlags); 6439 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6641 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 6440 6642 supdrvTscDeltaApply(pGip, &pDevExt->u64TscAnchor, idApic, &fDeltaApplied); 6441 6643 6442 6644 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 6645 /* 6646 * <Explain yourself> 6647 */ 6648 /** @todo r=bird: This is (and was) bogus on systems where we don't need to 6649 * apply any delta (not used on windows doesn't stick without comments). 6650 * What is the logic you want here exactly? */ 6443 6651 if ( pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC 6444 6652 && !fDeltaApplied) … … 6541 6749 supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), RT_NS_1SEC / u32Interval /*=Hz*/, u32Interval, cCpus); 6542 6750 6543 if (RT_UNLIKELY( pGip-> fOsTscDeltasInSync6751 if (RT_UNLIKELY( pGip->enmUseTscDelta == SUPGIPUSETSCDELTA_ZERO_CLAIMED 6544 6752 && pGip->u32Mode == SUPGIPMODE_ASYNC_TSC 6545 6753 && !supdrvOSGetForcedAsyncTscMode(pDevExt))) … … 6551 6759 6552 6760 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 6553 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6761 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 6554 6762 { 6555 6763 /* Initialize TSC-delta measurement thread before executing any Mp event callbacks. */ … … 6567 6775 uint16_t iCpu; 6568 6776 #ifndef SUPDRV_USE_TSC_DELTA_THREAD 6569 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6777 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 6570 6778 { 6571 6779 /* … … 6608 6816 } 6609 6817 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 6610 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0 /* fFlags */, supdrvGipSyncTimer, pDevExt); 6818 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0 /* fFlags */, 6819 supdrvGipSyncAndInvariantTimer, pDevExt); 6611 6820 if (RT_SUCCESS(rc)) 6612 6821 { … … 6722 6931 6723 6932 /** 6724 * Timer callback function sync GIP mode. 6933 * Timer callback function for the sync and invariant GIP modes. 6934 * 6725 6935 * @param pTimer The timer. 6726 6936 * @param pvUser Opaque pointer to the device extension. 6727 6937 * @param iTick The timer tick. 6728 6938 */ 6729 static DECLCALLBACK(void) supdrvGipSync Timer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)6939 static DECLCALLBACK(void) supdrvGipSyncAndInvariantTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick) 6730 6940 { 6731 6941 RTCCUINTREG uFlags; … … 6739 6949 u64NanoTS = RTTimeSystemNanoTS(); 6740 6950 6741 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6951 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 6742 6952 { 6743 6953 /* … … 6747 6957 * rescheduling the tick to be delivered on the right CPU or missing the tick entirely. 6748 6958 * 6749 * The likely hood of this happening is really low. On Windows, Linux timers 6750 * fire on the CPU they were registered/started on. Darwin, Solaris need verification. 6959 * The likely hood of this happening is really low. On Windows, Linux, and Solaris 6960 * timers fire on the CPU they were registered/started on. Darwin timers doesn't 6961 * necessarily (they are high priority threads waiting). 6751 6962 */ 6752 6963 Assert(!ASMIntAreEnabled()); … … 6884 7095 * update the state and it'll get serviced when the thread's listening interval times out. 6885 7096 */ 6886 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))7097 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 6887 7098 { 6888 7099 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); … … 6943 7154 6944 7155 /* Reset the TSC delta, we will recalculate it lazily. */ 6945 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))7156 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 6946 7157 ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX); 6947 7158 … … 7172 7383 7173 7384 while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) == GIP_TSC_DELTA_SYNC_START) 7174 ;7385 { /* nothing */ } 7175 7386 7176 7387 do … … 7183 7394 7184 7395 while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) != GIP_TSC_DELTA_SYNC_WORKER_DONE) 7185 ;7396 { /* nothing */ } 7186 7397 7187 7398 if (i > GIP_TSC_DELTA_PRIMER_LOOPS + GIP_TSC_DELTA_READ_TIME_LOOPS) … … 7209 7420 ASMAtomicReadU64(&pGipCpuMaster->u64TSCSample); /* Warm the cache line. */ 7210 7421 while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) != GIP_TSC_DELTA_SYNC_START) 7211 ;7422 { /* nothing */ } 7212 7423 Assert(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD); 7213 7424 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_WORKER_READY); … … 7307 7518 pGipCpuWorker = &pGip->aCPUs[idxWorker]; 7308 7519 7309 Assert( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));7520 Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); 7310 7521 7311 7522 if (pGipCpuWorker->idCpu == idMaster) … … 7316 7527 7317 7528 /* Set the master TSC as the initiator. */ 7318 while ( ASMAtomicCmpXchgU32(&pDevExt->idTscDeltaInitiator, idMaster, NIL_RTCPUID) == false)7529 while (!ASMAtomicCmpXchgU32(&pDevExt->idTscDeltaInitiator, idMaster, NIL_RTCPUID)) 7319 7530 { 7320 7531 /* … … 7333 7544 if (RT_SUCCESS(rc)) 7334 7545 { 7335 if (RT_UNLIKELY(pGipCpuWorker->i64TSCDelta == INT64_MAX)) 7546 if (RT_LIKELY(pGipCpuWorker->i64TSCDelta != INT64_MAX)) 7547 { 7548 /* 7549 * Work the TSC delta applicability rating. It starts 7550 * optimistic in supdrvGipInit, we downgrade it here. 7551 */ 7552 SUPGIPUSETSCDELTA enmRating; 7553 if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO 7554 || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO) 7555 enmRating = SUPGIPUSETSCDELTA_NOT_ZERO; 7556 else if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO 7557 || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO) 7558 enmRating = SUPGIPUSETSCDELTA_ROUGHLY_ZERO; 7559 else 7560 enmRating = SUPGIPUSETSCDELTA_PRACTICALLY_ZERO; 7561 if (pGip->enmUseTscDelta < enmRating) 7562 { 7563 AssertCompile(sizeof(pGip->enmUseTscDelta) == sizeof(uint32_t)); 7564 ASMAtomicWriteU32((uint32_t volatile *)&pGip->enmUseTscDelta, enmRating); 7565 } 7566 } 7567 else 7336 7568 rc = VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED; 7337 else if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_APPLY_THRESHOLD7338 || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_APPLY_THRESHOLD)7339 {7340 pGip->fTscDeltasRoughlyInSync = false;7341 }7342 7569 } 7343 7570 } … … 7373 7600 uint32_t cOnlineCpus = pGip->cOnlineCpus; 7374 7601 7375 Assert( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));7602 Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); 7376 7603 7377 7604 /* … … 7621 7848 pCpu->u64TSC = ASMReadTSC(); 7622 7849 pCpu->u64TSCSample = GIP_TSC_DELTA_RSVD; 7623 pCpu->i64TSCDelta = GIP_ARE_TSC_DELTAS_APPLICABLE(pGip)? INT64_MAX : 0;7850 pCpu->i64TSCDelta = pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED ? INT64_MAX : 0; 7624 7851 7625 7852 ASMAtomicWriteSize(&pCpu->enmState, SUPGIPCPUSTATE_INVALID); … … 7674 7901 memset(pGip, 0, cbGip); 7675 7902 7676 /*7677 * Record whether the host OS has already normalized inter-CPU deltas for the hardware TSC.7678 * We only bother with TSC-deltas on invariant CPUs for now.7679 */7680 pGip->fOsTscDeltasInSync = supdrvIsInvariantTsc() && supdrvOSAreTscDeltasInSync();7681 7682 pGip->fTscDeltasRoughlyInSync = true;7683 7903 pGip->u32Magic = SUPGLOBALINFOPAGE_MAGIC; 7684 7904 pGip->u32Version = SUPGLOBALINFOPAGE_VERSION; 7685 7905 pGip->u32Mode = supdrvGipDetermineTscMode(pDevExt); 7906 if ( pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC 7907 /*|| pGip->u32Mode == SUPGIPMODE_SYNC_TSC */) 7908 pGip->enmUseTscDelta = supdrvIsInvariantTsc() && supdrvOSAreTscDeltasInSync() /* Allow OS override (windows). */ 7909 ? SUPGIPUSETSCDELTA_ZERO_CLAIMED : SUPGIPUSETSCDELTA_PRACTICALLY_ZERO /* downgrade later */; 7910 else 7911 pGip->enmUseTscDelta = SUPGIPUSETSCDELTA_NOT_APPLICABLE; 7686 7912 pGip->cCpus = (uint16_t)cCpus; 7687 7913 pGip->cPages = (uint16_t)(cbGip / PAGE_SIZE); 7688 7914 pGip->u32UpdateHz = uUpdateHz; 7689 7915 pGip->u32UpdateIntervalNS = uUpdateIntervalNS; 7916 pGip->fGetGipCpu = SUPGIPGETCPU_APIC_ID; 7690 7917 RTCpuSetEmpty(&pGip->OnlineCpuSet); 7691 7918 RTCpuSetEmpty(&pGip->PresentCpuSet); … … 7699 7926 for (i = 0; i < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx); i++) 7700 7927 pGip->aiCpuFromCpuSetIdx[i] = UINT16_MAX; 7701 7702 7928 for (i = 0; i < cCpus; i++) 7703 7929 supdrvGipInitCpu(pDevExt, pGip, &pGip->aCPUs[i], u64NanoTS); … … 8066 8292 * 8067 8293 * @returns VBox status code. 8068 * @param pDevExt Pointer to the device instance data. 8069 * @param pReq Pointer to the TSC-delta measurement request. 8070 */ 8071 static int supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUPTSCDELTAMEASURE pReq) 8294 * @param pDevExt Pointer to the device instance data. 8295 * @param pSession The support driver session. 8296 * @param pReq Pointer to the TSC-delta measurement request. 8297 */ 8298 static int supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCDELTAMEASURE pReq) 8072 8299 { 8073 8300 PSUPGLOBALINFOPAGE pGip; 8074 8301 RTCPUID idCpuWorker; 8075 int rc = VERR_CPU_NOT_FOUND;8302 int rc; 8076 8303 int16_t cTries; 8077 8304 RTMSINTERVAL cMsWaitRetry; … … 8081 8308 * Validate. 8082 8309 */ 8083 AssertReturn(pDevExt, VERR_INVALID_PARAMETER); 8084 AssertReturn(pReq, VERR_INVALID_PARAMETER); 8085 AssertReturn(pDevExt->pGip, VERR_INVALID_PARAMETER); 8310 AssertPtr(pDevExt); AssertPtr(pSession); AssertPtr(pReq); /* paranoia^2 */ 8311 if (pSession->GipMapObjR3 == NIL_RTR0MEMOBJ) 8312 return VERR_WRONG_ORDER; 8313 pGip = pDevExt->pGip; 8314 AssertReturn(pGip, VERR_INTERNAL_ERROR_2); 8315 8086 8316 idCpuWorker = pReq->u.In.idCpu; 8087 8317 if (idCpuWorker == NIL_RTCPUID) 8088 8318 return VERR_INVALID_CPU_ID; 8089 8090 8319 cTries = RT_MAX(pReq->u.In.cRetries + 1, 10); 8091 8320 cMsWaitRetry = RT_MAX(pReq->u.In.cMsWaitRetry, 5); 8321 8322 /* 8323 * The request is a noop if the TSC delta isn't being used. 8324 */ 8092 8325 pGip = pDevExt->pGip; 8093 8094 if (!GIP_ARE_TSC_DELTAS_APPLICABLE(pGip)) 8326 if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED) 8095 8327 return VINF_SUCCESS; 8096 8328 8329 rc = VERR_CPU_NOT_FOUND; 8097 8330 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 8098 8331 { … … 8174 8407 * upset if the GIP is some different mode. 8175 8408 */ 8176 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))8409 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 8177 8410 { 8178 8411 uint32_t cTries = 0;
Note:
See TracChangeset
for help on using the changeset viewer.