Changeset 54257 in vbox
- Timestamp:
- Feb 17, 2015 11:24:45 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPLibAll.cpp
r54226 r54257 29 29 *******************************************************************************/ 30 30 #include <VBox/sup.h> 31 #ifdef IN_RC 32 # include <VBox/vmm/vm.h> 33 # include <VBox/vmm/vmm.h> 34 #endif 31 35 #ifdef IN_RING0 32 36 # include <iprt/mp.h> … … 54 58 SUPDECL(uint64_t) SUPReadTscWithDelta(void) 55 59 { 56 PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; 60 PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; 61 uint64_t uTsc; 62 uint16_t iGipCpu; 63 AssertCompile(RT_IS_POWER_OF_TWO(RTCPUSET_MAX_CPUS)); 64 AssertCompile(RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx) >= RTCPUSET_MAX_CPUS); 57 65 Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip)); 58 66 59 /** @todo Check out the rdtscp optimization, ASMGetApicId is very expensive. */ 67 /* 68 * Read the TSC and get the corresponding aCPUs index. 69 */ 70 if (pGip->fGetGipCpu & SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS) 71 { 72 /* RDTSCP gives us all we need, no loops/cli. */ 73 uint32_t iCpuSet; 74 uTsc = ASMReadTscWithAux(&iCpuSet); 75 iCpuSet &= RTCPUSET_MAX_CPUS - 1; 76 iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; 77 } 78 # ifndef IN_RING0 79 else if (pGip->fGetGipCpu & SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS) 80 { 81 /* Storing the IDTR is normally very quick, but we need to loop. */ 82 uint32_t cTries = 0; 83 for (;;) 84 { 85 uint16_t cbLim = ASMGetIdtrLimit(); 86 uTsc = ASMReadTSC(); 87 if (RT_LIKELY(ASMGetIdtrLimit() == cbLim)) 88 { 89 uint16_t iCpuSet = cbLim - 256 * (ARCH_BITS == 64 ? 16 : 8); 90 iCpuSet &= RTCPUSET_MAX_CPUS - 1; 91 iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; 92 break; 93 } 94 if (cTries >= 16) 95 { 96 iGipCpu = UINT16_MAX; 97 break; 98 } 99 cTries++; 100 } 101 } 102 # endif /* !IN_RING0 */ 103 else 104 { 105 # ifdef IN_RING3 106 /* Ring-3: Get APIC ID via the slow CPUID instruction, requires looping. */ 107 uint32_t cTries = 0; 108 for (;;) 109 { 110 uint8_t idApic = ASMGetApicId(); 111 uTsc = ASMReadTSC(); 112 if (RT_LIKELY(ASMGetApicId() == idApic)) 113 { 114 iGipCpu = pGip->aiCpuFromApicId[idApic]; 115 break; 116 } 117 if (cTries >= 16) 118 { 119 iGipCpu = UINT16_MAX; 120 break; 121 } 122 cTries++; 123 } 124 125 # elif defined(IN_RING0) 126 /* Ring-0: Use use RTMpCpuId(), no loops. */ 127 RTCCUINTREG uFlags = ASMIntDisableFlags(); 128 int iCpuSet = RTMpCpuIdToSetIndex(RTMpCpuId()); 129 if (RT_LIKELY((unsigned)iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) 130 iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; 131 else 132 iGipCpu = UINT16_MAX; 133 uTsc = ASMReadTSC(); 134 ASMSetFlags(uFlags); 135 136 # elif defined(IN_RC) 137 /* Raw-mode context: We can get the host CPU set index via VMCPU, no loops. */ 138 RTCCUINTREG uFlags = ASMIntDisableFlags(); /* Are already disable, but play safe. */ 139 uint32_t iCpuSet = VMMGetCpu(&g_VM)->iHostCpuSet; 140 if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) 141 iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; 142 else 143 iGipCpu = UINT16_MAX; 144 uTsc = ASMReadTSC(); 145 ASMSetFlags(uFlags); 146 # else 147 # error "IN_RING3, IN_RC or IN_RING0 must be defined!" 148 # endif 149 } 150 151 /* 152 * If the delta is valid, apply it. 153 */ 154 if (RT_LIKELY(iGipCpu < pGip->cCpus)) 155 { 156 int64_t iTscDelta = pGip->aCPUs[iGipCpu].i64TSCDelta; 157 if (RT_LIKELY(iTscDelta != INT64_MAX)) 158 return uTsc + iTscDelta; 60 159 61 160 # ifdef IN_RING3 62 /* 63 * Read the TSC and delta. 64 */ 65 uint32_t cTries = 0; 66 for (;;) 67 { 68 uint8_t idApic = ASMGetApicId(); 69 uint64_t uTsc = ASMReadTSC(); 70 int64_t iTscDelta = pGip->aCPUs[pGip->aiCpuFromApicId[idApic]].i64TSCDelta; 71 if (RT_LIKELY( idApic == ASMGetApicId() 72 || cTries >= 10)) 73 { 74 /* 75 * If the delta is valid, apply it. 76 */ 77 if (RT_LIKELY(iTscDelta != INT64_MAX)) 78 return uTsc - iTscDelta; 79 80 /* 81 * The delta needs calculating, call supdrv to get the TSC. 82 */ 83 int rc = SUPR3ReadTsc(&uTsc, NULL); 84 if (RT_SUCCESS(rc)) 85 return uTsc; 86 AssertMsgFailed(("SUPR3ReadTsc -> %Rrc\n", rc)); 87 88 /* That didn't work, just return something half useful... */ 89 return ASMReadTSC(); 90 } 91 cTries++; 161 /* 162 * The delta needs calculating, call supdrv to get the TSC. 163 */ 164 int rc = SUPR3ReadTsc(&uTsc, NULL); 165 if (RT_SUCCESS(rc)) 166 return uTsc; 167 AssertMsgFailed(("SUPR3ReadTsc -> %Rrc\n", rc)); 168 uTsc = ASMReadTSC(); 169 # endif /* IN_RING3 */ 92 170 } 93 # else94 /*95 * Read the TSC and delta.96 */97 RTCCUINTREG uFlags = ASMIntDisableFlags();98 # ifdef IN_RING099 int iCpuSet = RTMpCpuIdToSetIndex(RTMpCpuId());100 uint16_t iGipCpu = (unsigned)iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)101 ? pGip->aiCpuFromCpuSetIdx[iCpuSet] : UINT16_MAX;102 # else103 uint16_t idApic = ASMGetApicId(); /** @todo this could probably be eliminated in RC if we really wanted to... */104 uint16_t iGipCpu = (unsigned)idApic < RT_ELEMENTS(pGip->aiCpuFromApicId) /* for the future */105 ? pGip->aiCpuFromApicId[idApic] : UINT16_MAX;106 # endif107 int64_t iTscDelta = (unsigned)iGipCpu < pGip->cCpus ? pGip->aCPUs[iGipCpu].i64TSCDelta : INT64_MAX;108 uint64_t uTsc = ASMReadTSC();109 ASMSetFlags(uFlags);110 171 111 172 /* 112 * If the delta is valid, apply it, otherwise ignore it (really shouldn't113 * happen in these contexts!).173 * This shouldn't happen, especially not in ring-3 and raw-mode context. 174 * But if it does, return something that's half useful. 114 175 */ 115 if (RT_LIKELY(iTscDelta != INT64_MAX)) 116 return uTsc - iTscDelta; 117 # ifdef IN_RING0 118 AssertMsgFailed(("iCpuSet=%d (%#x) iGipCpu=%#x\n", iCpuSet, iCpuSet, iGipCpu)); 119 # else 120 AssertMsgFailed(("idApic=%#x iGipCpu=%#x\n", idApic, iGipCpu)); 121 # endif 176 AssertMsgFailed(("iGipCpu=%d (%#x) cCpus=%d fGetGipCpu=%#x\n", iGipCpu, iGipCpu, pGip->cCpus, pGip->fGetGipCpu)); 122 177 return uTsc; 123 # endif124 178 } 125 179
Note:
See TracChangeset
for help on using the changeset viewer.