Changeset 54224 in vbox for trunk/src/VBox/HostDrivers/Support/SUPDrv.c
- Timestamp:
- Feb 16, 2015 10:41:32 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 98289
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrv.c
r54214 r54224 164 164 static int supdrvIOCtl_MsrProber(PSUPDRVDEVEXT pDevExt, PSUPMSRPROBER pReq); 165 165 static int supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUPTSCDELTAMEASURE pReq); 166 static int supdrvIOCtl_TscRead(PSUPDRVDEVEXT pDevExt, PSUP TSCREAD pReq);166 static int supdrvIOCtl_TscRead(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCREAD pReq); 167 167 static int supdrvGipCreate(PSUPDRVDEVEXT pDevExt); 168 168 static void supdrvGipDestroy(PSUPDRVDEVEXT pDevExt); … … 2262 2262 REQ_CHECK_SIZES(SUP_IOCTL_TSC_READ); 2263 2263 2264 pReqHdr->rc = supdrvIOCtl_TscRead(pDevExt, p Req);2264 pReqHdr->rc = supdrvIOCtl_TscRead(pDevExt, pSession, pReq); 2265 2265 return 0; 2266 2266 } … … 6140 6140 6141 6141 /** 6142 * Applies the TSC delta to the supplied raw TSC value. 6143 * 6144 * @returns VBox status code. (Ignored by all users, just FYI.) 6145 * @param pGip Pointer to the GIP. 6146 * @param puTsc Pointer to a valid TSC value before the TSC delta has been applied. 6147 * @param idApic The APIC ID of the CPU @c puTsc corresponds to. 6148 * @param fDeltaApplied Where to store whether the TSC delta was succesfully 6149 * applied or not (optional, can be NULL). 6150 * 6151 * @remarks Maybe called with interrupts disabled in ring-0! 6152 * 6153 * @note Don't you dare change the delta calculation. If you really do, make 6154 * sure you update all places where it's used (IPRT, SUPLibAll.cpp, 6155 * SUPDrv.c, supdrvGipMpEvent, and more). 6156 */ 6157 DECLINLINE(int) supdrvTscDeltaApply(PSUPGLOBALINFOPAGE pGip, uint64_t *puTsc, uint16_t idApic, bool *pfDeltaApplied) 6158 { 6159 int rc; 6160 6161 /* 6162 * Validate input. 6163 */ 6164 AssertPtr(puTsc); 6165 AssertPtr(pGip); 6166 Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip)); 6167 6168 /* 6169 * Carefully convert the idApic into a GIPCPU entry. 6170 */ 6171 if (RT_LIKELY(idApic < RT_ELEMENTS(pGip->aiCpuFromApicId))) 6172 { 6173 uint16_t iCpu = pGip->aiCpuFromApicId[idApic]; 6174 if (RT_LIKELY(iCpu < pGip->cCpus)) 6175 { 6176 PSUPGIPCPU pGipCpu = &pGip->aCPUs[iCpu]; 6177 6178 /* 6179 * Apply the delta if valid. 6180 */ 6181 if (RT_LIKELY(pGipCpu->i64TSCDelta != INT64_MAX)) 6182 { 6183 *puTsc -= pGipCpu->i64TSCDelta; 6184 if (pfDeltaApplied) 6185 *pfDeltaApplied = true; 6186 return VINF_SUCCESS; 6187 } 6188 6189 rc = VINF_SUCCESS; 6190 } 6191 else 6192 { 6193 AssertMsgFailed(("iCpu=%u cCpus=%u\n", iCpu, pGip->cCpus)); 6194 rc = VERR_INVALID_CPU_INDEX; 6195 } 6196 } 6197 else 6198 { 6199 AssertMsgFailed(("idApic=%u\n", idApic)); 6200 rc = VERR_INVALID_CPU_ID; 6201 } 6202 if (pfDeltaApplied) 6203 *pfDeltaApplied = false; 6204 return rc; 6205 } 6206 6207 6208 /** 6142 6209 * Measures the TSC frequency of the system. 6143 6210 * … … 6222 6289 bool fAppliedBefore; 6223 6290 bool fAppliedAfter; 6224 rc = SUPTscDeltaApply(pGip, &u64TscBefore, idApicBefore, &fAppliedBefore); AssertRCReturn(rc, rc);6225 rc = SUPTscDeltaApply(pGip, &u64TscAfter, idApicAfter, &fAppliedAfter); AssertRCReturn(rc, rc);6291 rc = supdrvTscDeltaApply(pGip, &u64TscBefore, idApicBefore, &fAppliedBefore); AssertRCReturn(rc, rc); 6292 rc = supdrvTscDeltaApply(pGip, &u64TscAfter, idApicAfter, &fAppliedAfter); AssertRCReturn(rc, rc); 6226 6293 6227 6294 if ( !fAppliedBefore … … 6296 6363 ASMSetFlags(uFlags); 6297 6364 if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip)) 6298 SUPTscDeltaApply(pGip, &u64Tsc, idApic, &fDeltaApplied);6365 supdrvTscDeltaApply(pGip, &u64Tsc, idApic, &fDeltaApplied); 6299 6366 u64DeltaNanoTS = u64NanoTS - pDevExt->u64NanoTSAnchor; 6300 6367 u64DeltaTsc = u64Tsc - pDevExt->u64TscAnchor; … … 6371 6438 ASMSetFlags(uFlags); 6372 6439 if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip)) 6373 SUPTscDeltaApply(pGip, &pDevExt->u64TscAnchor, idApic, &fDeltaApplied);6440 supdrvTscDeltaApply(pGip, &pDevExt->u64TscAnchor, idApic, &fDeltaApplied); 6374 6441 6375 6442 #ifdef SUPDRV_USE_TSC_DELTA_THREAD … … 6684 6751 */ 6685 6752 Assert(!ASMIntAreEnabled()); 6686 SUPTscDeltaApply(pGip, &u64TSC, ASMGetApicId(), NULL /* pfDeltaApplied */);6753 supdrvTscDeltaApply(pGip, &u64TSC, ASMGetApicId(), NULL /* pfDeltaApplied */); 6687 6754 } 6688 6755 … … 8077 8144 8078 8145 /** 8079 * Reads the TSC and TSC-delta atomically, applies the TSC delta. 8146 * Reads TSC with delta applied. 8147 * 8148 * Will try to resolve delta value INT64_MAX before applying it. This is the 8149 * main purpose of this function, to handle the case where the delta needs to be 8150 * determined. 8080 8151 * 8081 8152 * @returns VBox status code. 8082 8153 * @param pDevExt Pointer to the device instance data. 8154 * @param pSession The support driver session. 8083 8155 * @param pReq Pointer to the TSC-read request. 8084 8156 */ 8085 static int supdrvIOCtl_TscRead(PSUPDRVDEVEXT pDevExt, PSUPTSCREAD pReq) 8086 { 8087 uint64_t uTsc; 8088 uint16_t idApic; 8089 int16_t cTries; 8157 static int supdrvIOCtl_TscRead(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCREAD pReq) 8158 { 8090 8159 PSUPGLOBALINFOPAGE pGip; 8091 8160 int rc; 8092 8161 8093 8162 /* 8094 * Validate. 8095 * /8096 AssertReturn(pDevExt, VERR_INVALID_PARAMETER);8097 Assert Return(pReq, VERR_INVALID_PARAMETER);8098 AssertReturn(pDevExt->pGip, VERR_INVALID_PARAMETER);8099 8163 * Validate. We require the client to have mapped GIP (no asserting on 8164 * ring-3 preconditions). 8165 */ 8166 AssertPtr(pDevExt); AssertPtr(pReq); AssertPtr(pSession); /* paranoia^2 */ 8167 if (pSession->GipMapObjR3 == NIL_RTR0MEMOBJ) 8168 return VERR_WRONG_ORDER; 8100 8169 pGip = pDevExt->pGip; 8101 Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip)); 8102 8103 cTries = 4; 8104 while (cTries-- > 0) 8105 { 8106 int rc2; 8107 uint16_t iCpu; 8108 8109 rc = SUPGetTsc(&uTsc, &idApic); 8110 if (RT_SUCCESS(rc)) 8111 { 8112 pReq->u.Out.u64AdjustedTsc = uTsc; 8113 pReq->u.Out.idApic = idApic; 8114 return VINF_SUCCESS; 8115 } 8116 8117 /* If we failed to have a TSC-delta, measurement the TSC-delta and retry. */ 8118 AssertMsgReturn(idApic < RT_ELEMENTS(pGip->aiCpuFromApicId), 8119 ("idApic=%u ArraySize=%u\n", idApic, RT_ELEMENTS(pGip->aiCpuFromApicId)), VERR_INVALID_CPU_INDEX); 8120 iCpu = pGip->aiCpuFromApicId[idApic]; 8121 AssertMsgReturn(iCpu < pGip->cCpus, ("iCpu=%u cCpus=%u\n", iCpu, pGip->cCpus), VERR_INVALID_CPU_INDEX); 8122 8123 rc2 = supdrvMeasureTscDeltaOne(pDevExt, iCpu); 8124 if (RT_SUCCESS(rc2)) 8125 AssertReturn(pGip->aCPUs[iCpu].i64TSCDelta != INT64_MAX, VERR_INTERNAL_ERROR_2); 8170 AssertReturn(pGip, VERR_INTERNAL_ERROR_2); 8171 8172 /* 8173 * We're usually here because we need to apply delta, but we shouldn't be 8174 * upset if the GIP is some different mode. 8175 */ 8176 if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip)) 8177 { 8178 uint32_t cTries = 0; 8179 for (;;) 8180 { 8181 /* 8182 * Start by gathering the data, using CLI for disabling preemption 8183 * while we do that. 8184 */ 8185 RTCCUINTREG uFlags = ASMIntDisableFlags(); 8186 int iCpuSet = RTMpCpuIdToSetIndex(RTMpCpuId()); 8187 int iGipCpu; 8188 if (RT_LIKELY( (unsigned)iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx) 8189 && (iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]) < pGip->cCpus )) 8190 { 8191 int64_t i64Delta = pGip->aCPUs[iGipCpu].i64TSCDelta; 8192 pReq->u.Out.idApic = pGip->aCPUs[iGipCpu].idApic; 8193 pReq->u.Out.u64AdjustedTsc = ASMReadTSC(); 8194 ASMSetFlags(uFlags); 8195 8196 /* 8197 * If we're lucky we've got a delta, but no predicitions here 8198 * as this I/O control is normally only used when the TSC delta 8199 * is set to INT64_MAX. 8200 */ 8201 if (i64Delta != INT64_MAX) 8202 { 8203 pReq->u.Out.u64AdjustedTsc -= i64Delta; 8204 rc = VINF_SUCCESS; 8205 break; 8206 } 8207 8208 /* Give up after a few times. */ 8209 if (cTries >= 4) 8210 { 8211 rc = VERR_INTERNAL_ERROR_3; /** @todo change to warning. */ 8212 break; 8213 } 8214 8215 /* Need to measure the delta an try again. */ 8216 rc = supdrvMeasureTscDeltaOne(pDevExt, iGipCpu); 8217 Assert(pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX || RT_FAILURE_NP(rc)); 8218 } 8219 else 8220 { 8221 /* This really shouldn't happen. */ 8222 AssertMsgFailed(("idCpu=%#x iCpuSet=%#x (%d)\n", RTMpCpuId(), iCpuSet, iCpuSet)); 8223 pReq->u.Out.idApic = ASMGetApicId(); 8224 pReq->u.Out.u64AdjustedTsc = ASMReadTSC(); 8225 ASMSetFlags(uFlags); 8226 rc = VERR_INTERNAL_ERROR_5; /** @todo change to warning. */ 8227 break; 8228 } 8229 } 8230 } 8231 else 8232 { 8233 /* 8234 * No delta to apply. Easy. Deal with preemption the lazy way. 8235 */ 8236 RTCCUINTREG uFlags = ASMIntDisableFlags(); 8237 int iCpuSet = RTMpCpuIdToSetIndex(RTMpCpuId()); 8238 int iGipCpu; 8239 if (RT_LIKELY( (unsigned)iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx) 8240 && (iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]) < pGip->cCpus )) 8241 pReq->u.Out.idApic = pGip->aCPUs[iGipCpu].idApic; 8242 else 8243 pReq->u.Out.idApic = ASMGetApicId(); 8244 pReq->u.Out.u64AdjustedTsc = ASMReadTSC(); 8245 ASMSetFlags(uFlags); 8246 rc = VINF_SUCCESS; 8126 8247 } 8127 8248
Note:
See TracChangeset
for help on using the changeset viewer.