Changeset 1027 in vbox
- Timestamp:
- Feb 22, 2007 8:29:35 PM (18 years ago)
- svn:sync-xref-src-repo-rev:
- 18886
- Location:
- trunk
- Files:
-
- 1 deleted
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/sup.h
r914 r1027 24 24 #include <VBox/cdefs.h> 25 25 #include <VBox/types.h> 26 #include <iprt/assert.h> 27 #include <iprt/asm.h> 26 28 27 29 __BEGIN_DECLS … … 74 76 75 77 76 #pragma pack(1) 77 /** 78 * Global Information Page. 79 * 80 * This page contains useful information and can be mapped into any 81 * process or VM. It can be accessed thru the g_pSUPGlobalInfoPage 82 * pointer when a session is open. 83 * 84 * How to read data from this structure: 85 * 86 * @code 87 * PSUPGLOBALINFOPAGE pGIP; 88 * uint32_t u32TransactionId; 89 * do 90 * { 91 * pGIP = g_pSUPGlobalInfoPage; 92 * if (!pGIP) 93 * return VERR_GIP_NOT_PRESENT; 94 * u32TransactionId = pGIP->u32TransactionId; 95 * ... read stuff to local variables ... 96 * } while ( pGIP->u32TransactionId != u32TransactionId 97 * || (u32TransactionId & 1)); 98 * @endcode 99 * 100 * @remark This is currently an optional feature. 101 */ 102 typedef struct SUPGLOBALINFOPAGE 103 { 104 /** Magic (SUPGLOBALINFOPAGE_MAGIC). */ 105 uint32_t u32Magic; 106 107 /** The update frequency of the of the NanoTS. */ 108 volatile uint32_t u32UpdateHz; 109 /** The update interval in nanoseconds. (10^9 / u32UpdateHz) */ 110 volatile uint32_t u32UpdateIntervalNS; 111 112 /** Padding / reserved space for future const variables. */ 113 uint32_t au32Padding0[5]; 114 78 #pragma pack(1) /* paranoia */ 79 80 /** 81 * Per CPU data. 82 * This is only used when 83 */ 84 typedef struct SUPGIPCPU 85 { 115 86 /** Update transaction number. 116 87 * This number is incremented at the start and end of each update. It follows 117 88 * thusly that odd numbers indicates update in progress, while even numbers 118 89 * indicate stable data. Use this to make sure that the data items you fetch 119 * are consistent. 120 */ 90 * are consistent. */ 121 91 volatile uint32_t u32TransactionId; 122 92 /** The interval in TSC ticks between two NanoTS updates. 123 93 * This is the average interval over the last 2, 4 or 8 updates + a little slack. 124 94 * The slack makes the time go a tiny tiny bit slower and extends the interval enough 125 * to avoid gettingending up with too many 1ns increments. */95 * to avoid ending up with too many 1ns increments. */ 126 96 volatile uint32_t u32UpdateIntervalTSC; 127 97 /** Current nanosecond timestamp. */ … … 141 111 */ 142 112 volatile uint32_t au32TSCHistory[8]; 113 /** Reserved for future per processor data. */ 114 volatile uint32_t au32Reserved[6]; 115 } SUPGIPCPU; 116 AssertCompileSize(SUPGIPCPU, 96); 117 /*AssertCompileMemberAlignment(SUPGIPCPU, u64TSC, 8); -fixme */ 118 119 /** Pointer to per cpu data. */ 120 typedef SUPGIPCPU *PSUPGIPCPU; 121 /** Pointer to const per cpu data. */ 122 typedef const SUPGIPCPU *PCSUPGIPCPU; 123 124 /** 125 * Global Information Page. 126 * 127 * This page contains useful information and can be mapped into any 128 * process or VM. It can be accessed thru the g_pSUPGlobalInfoPage 129 * pointer when a session is open. 130 */ 131 typedef struct SUPGLOBALINFOPAGE 132 { 133 /** Magic (SUPGLOBALINFOPAGE_MAGIC). */ 134 uint32_t u32Magic; 135 136 /** The GIP update mode, see SUPGIPMODE. */ 137 uint32_t u32Mode; 138 139 /** The update frequency of the of the NanoTS. */ 140 volatile uint32_t u32UpdateHz; 141 /** The update interval in nanoseconds. (10^9 / u32UpdateHz) */ 142 volatile uint32_t u32UpdateIntervalNS; 143 143 /** The timestamp of the last time we update the update frequency. */ 144 144 volatile uint64_t u64NanoTSLastUpdateHz; 145 146 /** Padding / reserved space for future data. */ 147 uint32_t au32Padding0[10]; 148 149 /** Array of per-cpu data. 150 * If u32Mode == SUPGIPMODE_SYNC_TSC then only the first entry is used. 151 * If u32Mode == SUPGIPMODE_ASYNC_TSC then the CPU ACPI ID is used as an 152 * index into the array. */ 153 SUPGIPCPU aCPUs[32]; 145 154 } SUPGLOBALINFOPAGE; 146 #pragma pack() 155 AssertCompile(sizeof(SUPGLOBALINFOPAGE) <= 0x1000); 156 /* AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, aCPU, 32); - fixme */ 157 147 158 /** Pointer to the global info page. */ 148 159 typedef SUPGLOBALINFOPAGE *PSUPGLOBALINFOPAGE; … … 150 161 typedef const SUPGLOBALINFOPAGE *PCSUPGLOBALINFOPAGE; 151 162 152 /** Current value of the SUPGLOBALINFOPAGE::u32Magic field. */ 153 #define SUPGLOBALINFOPAGE_MAGIC (0xbeef0001) 163 #pragma pack() /* end of paranoia */ 164 165 /** The value of the SUPGLOBALINFOPAGE::u32Magic field. (Soryo Fuyumi) */ 166 #define SUPGLOBALINFOPAGE_MAGIC 0x19590106 167 168 /** 169 * SUPGLOBALINFOPAGE::u32Mode values. 170 */ 171 typedef enum SUPGIPMODE 172 { 173 /** The usual invalid null entry. */ 174 SUPGIPMODE_INVALID = 0, 175 /** The TSC of the cores and cpus in the system is in sync. */ 176 SUPGIPMODE_SYNC_TSC, 177 /** Each core has it's own TSC. */ 178 SUPGIPMODE_ASYNC_TSC, 179 /** The usual 32-bit hack. */ 180 SUPGIPMODE_32BIT_HACK = 0x7fffffff 181 } SUPGIPMODE; 154 182 155 183 /** Pointer to the Global Information Page. … … 182 210 183 211 212 /** 213 * Gets the TSC frequency of the calling CPU. 214 * 215 * @returns TSC frequency. 216 * @param pGip The GIP pointer. 217 */ 218 DECLINLINE(uint64_t) SUPGetCpuHzFromGIP(PCSUPGLOBALINFOPAGE pGip) 219 { 220 unsigned iCpu; 221 222 if (RT_UNLIKELY(!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC)) 223 return ~(uint64_t)0; 224 225 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 226 iCpu = 0; 227 else 228 { 229 iCpu = ASMGetApicId(); 230 if (RT_UNLIKELY(iCpu >= RT_ELEMENTS(pGip->aCPUs))) 231 return ~(uint64_t)0; 232 } 233 234 return pGip->aCPUs[iCpu].u64CpuHz; 235 } 236 184 237 185 238 #ifdef IN_RING3 -
trunk/include/iprt/asm.h
r654 r1027 763 763 764 764 /** 765 * Gets the APIC ID of the current CPU. 766 * 767 * @returns the APIC ID. 768 */ 769 #if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN 770 DECLASM(uint8_t) ASMGetApicId(void); 771 #else 772 DECLINLINE(uint8_t) ASMGetApicId(void) 773 { 774 RTCCUINTREG xBX; 775 # if RT_INLINE_ASM_GNU_STYLE 776 # ifdef __AMD64__ 777 RTCCUINTREG uSpill; 778 __asm__ ("cpuid" 779 : "=a" (uSpill), 780 "=b" (xBX) 781 : "0" (1) 782 : "rcx", "rdx"); 783 # elif (defined(PIC) || defined(__DARWIN__)) && defined(__i386__) 784 RTCCUINTREG uSpill; 785 __asm__ ("push %%ebx\n\t" 786 "cpuid\n\t" 787 "xchgl %%ebx, %%ecx\n\t" 788 "pop %%ebx\n\t" 789 : "=a" (uSpill), 790 "=c" (xBX) 791 : "0" (1) 792 : "edx"); 793 # else 794 RTCCUINTREG uSpill; 795 __asm__ ("cpuid" 796 : "=a" (uSpill), 797 "=b" (xBX) 798 : "0" (1) 799 : "ecx", "edx"); 800 # endif 801 802 # elif RT_INLINE_ASM_USES_INTRIN 803 int aInfo[4]; 804 __cpuid(aInfo, 1); 805 xBX = aInfo[1]; 806 807 # else 808 __asm 809 { 810 push ebx 811 mov eax, 1 812 cpuid 813 mov [xBX], ebx 814 pop ebx 815 } 816 # endif 817 return (uint8_t)(xBX >> 24); 818 } 819 #endif 820 821 /** 765 822 * Get cr0. 766 823 * @returns cr0. -
trunk/src/VBox/HostDrivers/Support/SUPDRV.h
r679 r1027 617 617 /** The GIP DPC object associated with GipTimer. */ 618 618 KDPC GipDpc; 619 /** The GIP DPC objects for updating per-cpu data. */ 620 KDPC aGipCpuDpcs[32]; 619 621 /** Pointer to the MDL for the pGip page. */ 620 622 PMDL pGipMdl; … … 626 628 unsigned long ulLastJiffies; 627 629 /** The last mono time stamp. */ 628 uint64_t 630 uint64_t volatile u64LastMonotime; 629 631 #endif 630 632 } SUPDRVDEVEXT; … … 652 654 void VBOXCALL supdrvOSGipResume(PSUPDRVDEVEXT pDevExt); 653 655 void VBOXCALL supdrvOSGipSuspend(PSUPDRVDEVEXT pDevExt); 656 unsigned VBOXCALL supdrvOSGetCPUCount(void); 654 657 #endif 655 658 … … 671 674 void VBOXCALL supdrvGipTerm(PSUPGLOBALINFOPAGE pGip); 672 675 void VBOXCALL supdrvGipUpdate(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS); 676 void VBOXCALL supdrvGipUpdatePerCpu(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS, unsigned iCpu); 673 677 674 678 __END_DECLS -
trunk/src/VBox/HostDrivers/Support/SUPDRVIOC.h
r914 r1027 176 176 #define SUPCOOKIE_MAGIC "The Magic Word!" 177 177 /** Current interface version. */ 178 #define SUPDRVIOC_VERSION 0x000 30002178 #define SUPDRVIOC_VERSION 0x00040000 179 179 180 180 /** SUP_IOCTL_COOKIE Output. */ -
trunk/src/VBox/HostDrivers/Support/SUPDRVShared.c
r982 r1027 2288 2288 if (pDevExt->cGipUsers == 1) 2289 2289 { 2290 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 2291 unsigned i; 2292 2290 2293 dprintf(("SUPR0GipMap: Resumes GIP updating\n")); 2291 ASMAtomicXchgU32(&pDevExt->pGip->u32TransactionId, 2292 pDevExt->pGip->u32TransactionId & ~(GIP_UPDATEHZ_RECALC_FREQ * 2 - 1)); 2293 ASMAtomicXchgU64(&pDevExt->pGip->u64NanoTSLastUpdateHz, 0); 2294 2295 for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++) 2296 ASMAtomicXchgU32(&pGip->aCPUs[i].u32TransactionId, pGip->aCPUs[i].u32TransactionId & ~(GIP_UPDATEHZ_RECALC_FREQ * 2 - 1)); 2297 ASMAtomicXchgU64(&pGip->u64NanoTSLastUpdateHz, 0); 2298 2294 2299 #ifdef USE_NEW_OS_INTERFACE 2295 rc = RTTimerStart(pDevExt->pGipTimer, 0); AssertRC(rc); rc = 0; 2300 rc = RTTimerStart(pDevExt->pGipTimer, 0); 2301 AssertRC(rc); rc = 0; 2296 2302 #else 2297 2303 supdrvOSGipResume(pDevExt); … … 4005 4011 int VBOXCALL supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys, uint64_t u64NanoTS, unsigned uUpdateHz) 4006 4012 { 4013 unsigned i; 4007 4014 dprintf(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz)); 4008 4015 4016 /* 4017 * Initialize the structure. 4018 */ 4009 4019 memset(pGip, 0, PAGE_SIZE); 4010 4020 pGip->u32Magic = SUPGLOBALINFOPAGE_MAGIC; 4021 pGip->u32Mode = SUPGIPMODE_SYNC_TSC; 4011 4022 pGip->u32UpdateHz = uUpdateHz; 4012 4023 pGip->u32UpdateIntervalNS = 1000000000 / uUpdateHz; 4013 pGip->u32TransactionId = 2;4014 pGip->u64NanoTS = u64NanoTS;4015 4024 pGip->u64NanoTSLastUpdateHz = u64NanoTS; 4016 pGip->u64TSC = ASMReadTSC(); 4017 4018 /* 4019 * We don't know the following values until we've executed updates. 4020 * So, we'll just insert very high values. 4021 */ 4022 pGip->u64CpuHz = _4G + 1; 4023 pGip->u32UpdateIntervalTSC = _2G / 4; 4024 pGip->au32TSCHistory[0] = _2G / 4; 4025 pGip->au32TSCHistory[1] = _2G / 4; 4026 pGip->au32TSCHistory[2] = _2G / 4; 4027 pGip->au32TSCHistory[3] = _2G / 4; 4028 pGip->au32TSCHistory[4] = _2G / 4; 4029 pGip->au32TSCHistory[5] = _2G / 4; 4030 pGip->au32TSCHistory[6] = _2G / 4; 4031 pGip->au32TSCHistory[7] = _2G / 4; 4025 4026 for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++) 4027 { 4028 pGip->aCPUs[i].u32TransactionId = 2; 4029 pGip->aCPUs[i].u64NanoTS = u64NanoTS; 4030 pGip->aCPUs[i].u64TSC = ASMReadTSC(); 4031 4032 /* 4033 * We don't know the following values until we've executed updates. 4034 * So, we'll just insert very high values. 4035 */ 4036 pGip->aCPUs[i].u64CpuHz = _4G + 1; 4037 pGip->aCPUs[i].u32UpdateIntervalTSC = _2G / 4; 4038 pGip->aCPUs[i].au32TSCHistory[0] = _2G / 4; 4039 pGip->aCPUs[i].au32TSCHistory[1] = _2G / 4; 4040 pGip->aCPUs[i].au32TSCHistory[2] = _2G / 4; 4041 pGip->aCPUs[i].au32TSCHistory[3] = _2G / 4; 4042 pGip->aCPUs[i].au32TSCHistory[4] = _2G / 4; 4043 pGip->aCPUs[i].au32TSCHistory[5] = _2G / 4; 4044 pGip->aCPUs[i].au32TSCHistory[6] = _2G / 4; 4045 pGip->aCPUs[i].au32TSCHistory[7] = _2G / 4; 4046 } 4032 4047 4033 4048 /* … … 4038 4053 pDevExt->cGipUsers = 0; 4039 4054 4055 /* 4056 * Check if we should switch to async TSC mode. 4057 */ 4058 #if 0 4059 if (supdrvOSGetCPUCount() > 1) 4060 { 4061 ASMCpuId(0, 4062 } 4063 #endif 4064 4040 4065 return 0; 4041 4066 } … … 4049 4074 void VBOXCALL supdrvGipTerm(PSUPGLOBALINFOPAGE pGip) 4050 4075 { 4051 pGip->iTSCHistoryHead = ~0; 4052 pGip->u64NanoTS = 0; 4053 pGip->u64TSC = 0; 4076 unsigned i; 4054 4077 pGip->u32Magic = 0; 4055 pGip->iTSCHistoryHead = 0; 4056 } 4057 4058 4059 /** 4060 * Updates the GIP. 4061 * 4062 * @param pGip Pointer to the GIP. 4063 * @param u64NanoTS The current nanosecond timesamp. 4064 */ 4065 void VBOXCALL supdrvGipUpdate(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS) 4078 for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++) 4079 { 4080 pGip->aCPUs[i].u64NanoTS = 0; 4081 pGip->aCPUs[i].u64TSC = 0; 4082 pGip->aCPUs[i].iTSCHistoryHead = 0; 4083 } 4084 } 4085 4086 4087 /** 4088 * Worker routine for supdrvGipUpdate and supdrvGipUpdatePerCpu that 4089 * updates all the per cpu data except the transaction id. 4090 * 4091 * @param pGip The GIP. 4092 * @param pGipCpu Pointer to the per cpu data. 4093 * @param u64NanoTS The current time stamp. 4094 */ 4095 static void supdrvGipDoUpdateCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu, uint64_t u64NanoTS) 4066 4096 { 4067 4097 uint64_t u64TSC; … … 4073 4103 4074 4104 /* 4105 * Update the NanoTS. 4106 */ 4107 ASMAtomicXchgU64(&pGipCpu->u64NanoTS, u64NanoTS); 4108 4109 /* 4110 * Calc TSC delta. 4111 */ 4112 /** @todo validate the NanoTS delta, don't trust the OS to call us when it should... */ 4113 u64TSC = ASMReadTSC(); 4114 u64TSCDelta = u64TSC - pGipCpu->u64TSC; 4115 ASMAtomicXchgU64(&pGipCpu->u64TSC, u64TSC); 4116 4117 if (u64TSCDelta >> 32) 4118 { 4119 u64TSCDelta = pGipCpu->u32UpdateIntervalTSC; 4120 pGipCpu->cErrors++; 4121 } 4122 4123 /* 4124 * TSC History. 4125 */ 4126 Assert(ELEMENTS(pGipCpu->au32TSCHistory) == 8); 4127 4128 iTSCHistoryHead = (pGipCpu->iTSCHistoryHead + 1) & 7; 4129 ASMAtomicXchgU32(&pGipCpu->iTSCHistoryHead, iTSCHistoryHead); 4130 ASMAtomicXchgU32(&pGipCpu->au32TSCHistory[iTSCHistoryHead], (uint32_t)u64TSCDelta); 4131 4132 /* 4133 * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ. 4134 */ 4135 if (pGip->u32UpdateHz >= 1000) 4136 { 4137 uint32_t u32; 4138 u32 = pGipCpu->au32TSCHistory[0]; 4139 u32 += pGipCpu->au32TSCHistory[1]; 4140 u32 += pGipCpu->au32TSCHistory[2]; 4141 u32 += pGipCpu->au32TSCHistory[3]; 4142 u32 >>= 2; 4143 u32UpdateIntervalTSC = pGipCpu->au32TSCHistory[4]; 4144 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[5]; 4145 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[6]; 4146 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[7]; 4147 u32UpdateIntervalTSC >>= 2; 4148 u32UpdateIntervalTSC += u32; 4149 u32UpdateIntervalTSC >>= 1; 4150 4151 /* Value choosen for a 2GHz Athlon64 running linux 2.6.10/11, . */ 4152 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 14; 4153 } 4154 else if (pGip->u32UpdateHz >= 90) 4155 { 4156 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta; 4157 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[(iTSCHistoryHead - 1) & 7]; 4158 u32UpdateIntervalTSC >>= 1; 4159 4160 /* value choosen on a 2GHz thinkpad running windows */ 4161 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 7; 4162 } 4163 else 4164 { 4165 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta; 4166 4167 /* This value hasn't be checked yet.. waiting for OS/2 and 33Hz timers.. :-) */ 4168 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6; 4169 } 4170 ASMAtomicXchgU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack); 4171 4172 /* 4173 * CpuHz. 4174 */ 4175 u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, pGip->u32UpdateHz); 4176 ASMAtomicXchgU64(&pGipCpu->u64CpuHz, u64CpuHz); 4177 } 4178 4179 4180 /** 4181 * Updates the GIP. 4182 * 4183 * @param pGip Pointer to the GIP. 4184 * @param u64NanoTS The current nanosecond timesamp. 4185 */ 4186 void VBOXCALL supdrvGipUpdate(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS) 4187 { 4188 /* 4189 * Determin the relevant CPU data. 4190 */ 4191 PSUPGIPCPU pGipCpu; 4192 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 4193 pGipCpu = &pGip->aCPUs[0]; 4194 else 4195 { 4196 unsigned iCpu = ASMGetApicId(); 4197 if (RT_LIKELY(iCpu >= RT_ELEMENTS(pGip->aCPUs))) 4198 return; 4199 pGipCpu = &pGip->aCPUs[iCpu]; 4200 } 4201 4202 /* 4075 4203 * Start update transaction. 4076 4204 */ 4077 if (!(ASMAtomicIncU32(&pGip ->u32TransactionId) & 1))4205 if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1)) 4078 4206 { 4079 4207 /* this can happen on win32 if we're taking to long and there are more CPUs around. shouldn't happen though. */ 4080 AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGip ->u32TransactionId));4081 ASMAtomicIncU32(&pGip ->u32TransactionId);4082 pGip ->cErrors++;4208 AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId)); 4209 ASMAtomicIncU32(&pGipCpu->u32TransactionId); 4210 pGipCpu->cErrors++; 4083 4211 return; 4084 4212 } 4085 4213 4086 ASMAtomicXchgU64(&pGip->u64NanoTS, u64NanoTS);4087 4088 4214 /* 4089 4215 * Recalc the update frequency every 0x800th time. 4090 4216 */ 4091 if (!(pGip ->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))4217 if (!(pGipCpu->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2))) 4092 4218 { 4093 4219 if (pGip->u64NanoTSLastUpdateHz) … … 4107 4233 4108 4234 /* 4109 * Calc TSC delta. 4110 */ 4111 /** @todo validate the NanoTS delta, don't trust the OS to call us when it should... */ 4112 u64TSC = ASMReadTSC(); 4113 u64TSCDelta = u64TSC - pGip->u64TSC; 4114 ASMAtomicXchgU64(&pGip->u64TSC, u64TSC); 4115 4116 if (u64TSCDelta >> 32) 4117 { 4118 u64TSCDelta = pGip->u32UpdateIntervalTSC; 4119 pGip->cErrors++; 4120 } 4121 4122 /* 4123 * TSC History. 4124 */ 4125 Assert(ELEMENTS(pGip->au32TSCHistory) == 8); 4126 4127 iTSCHistoryHead = (pGip->iTSCHistoryHead + 1) & 7; 4128 ASMAtomicXchgU32(&pGip->iTSCHistoryHead, iTSCHistoryHead); 4129 ASMAtomicXchgU32(&pGip->au32TSCHistory[iTSCHistoryHead], (uint32_t)u64TSCDelta); 4130 4131 /* 4132 * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ. 4133 */ 4134 if (pGip->u32UpdateHz >= 1000) 4135 { 4136 uint32_t u32; 4137 u32 = pGip->au32TSCHistory[0]; 4138 u32 += pGip->au32TSCHistory[1]; 4139 u32 += pGip->au32TSCHistory[2]; 4140 u32 += pGip->au32TSCHistory[3]; 4141 u32 >>= 2; 4142 u32UpdateIntervalTSC = pGip->au32TSCHistory[4]; 4143 u32UpdateIntervalTSC += pGip->au32TSCHistory[5]; 4144 u32UpdateIntervalTSC += pGip->au32TSCHistory[6]; 4145 u32UpdateIntervalTSC += pGip->au32TSCHistory[7]; 4146 u32UpdateIntervalTSC >>= 2; 4147 u32UpdateIntervalTSC += u32; 4148 u32UpdateIntervalTSC >>= 1; 4149 4150 /* Value choosen for a 2GHz Athlon64 running linux 2.6.10/11, . */ 4151 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 14; 4152 } 4153 else if (pGip->u32UpdateHz >= 90) 4154 { 4155 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta; 4156 u32UpdateIntervalTSC += pGip->au32TSCHistory[(iTSCHistoryHead - 1) & 7]; 4157 u32UpdateIntervalTSC >>= 1; 4158 4159 /* value choosen on a 2GHz thinkpad running windows */ 4160 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 7; 4161 } 4162 else 4163 { 4164 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta; 4165 4166 /* This value hasn't be checked yet.. waiting for OS/2 and 33Hz timers.. :-) */ 4167 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6; 4168 } 4169 ASMAtomicXchgU32(&pGip->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack); 4170 4171 /* 4172 * CpuHz. 4173 */ 4174 u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, pGip->u32UpdateHz); 4175 ASMAtomicXchgU64(&pGip->u64CpuHz, u64CpuHz); 4235 * Update the data. 4236 */ 4237 supdrvGipDoUpdateCpu(pGip, pGipCpu, u64NanoTS); 4176 4238 4177 4239 /* 4178 4240 * Complete transaction. 4179 4241 */ 4180 ASMAtomicIncU32(&pGip->u32TransactionId); 4242 ASMAtomicIncU32(&pGipCpu->u32TransactionId); 4243 } 4244 4245 4246 /** 4247 * Updates the per cpu GIP data for the calling cpu. 4248 * 4249 * @param pGip Pointer to the GIP. 4250 * @param u64NanoTS The current nanosecond timesamp. 4251 * @param iCpu The CPU index. 4252 */ 4253 void VBOXCALL supdrvGipUpdatePerCpu(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS, unsigned iCpu) 4254 { 4255 PSUPGIPCPU pGipCpu; 4256 4257 if (RT_LIKELY(iCpu <= RT_ELEMENTS(pGip->aCPUs))) 4258 { 4259 pGipCpu = &pGip->aCPUs[iCpu]; 4260 4261 /* 4262 * Start update transaction. 4263 */ 4264 if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1)) 4265 { 4266 AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId)); 4267 ASMAtomicIncU32(&pGipCpu->u32TransactionId); 4268 pGipCpu->cErrors++; 4269 return; 4270 } 4271 4272 /* 4273 * Update the data. 4274 */ 4275 supdrvGipDoUpdateCpu(pGip, pGipCpu, u64NanoTS); 4276 4277 /* 4278 * Complete transaction. 4279 */ 4280 ASMAtomicIncU32(&pGipCpu->u32TransactionId); 4281 } 4181 4282 } 4182 4283 -
trunk/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c
r876 r1027 1361 1361 { 1362 1362 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)ulUser; 1363 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 1363 1364 unsigned long ulNow = jiffies; 1364 1365 unsigned long ulDiff = ulNow - pDevExt->ulLastJiffies; 1366 uint64_t u64Monotime; 1365 1367 pDevExt->ulLastJiffies = ulNow; 1366 1368 #ifdef TICK_NSEC 1367 pDevExt->u64LastMonotime +=ulDiff * TICK_NSEC;1369 u64Monotime = pDevExt->u64LastMonotime + ulDiff * TICK_NSEC; 1368 1370 #else 1369 pDevExt->u64LastMonotime += ulDiff * (1000000 / HZ); 1370 #endif 1371 supdrvGipUpdate(pDevExt->pGip, pDevExt->u64LastMonotime); 1371 u64Monotime = pDevExt->u64LastMonotime + ulDiff * (1000000 / HZ); 1372 #endif 1373 ASMAtomicXchgU64(&pDevExt->u64LastMonotime, u64Monotime); 1374 if (RT_LIKELY(pGip)) 1375 { 1376 #ifdef CONFIG_SMP 1377 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 1378 #endif 1379 supdrvGipUpdate(pDevExt->pGip, u64Monotime); 1380 #ifdef CONFIG_SMP 1381 else 1382 { 1383 smp_call_function(VBoxSupDrvGipPerCpu, pDevExt, 0 /* don't retry? */, 0 /* don't wait */); 1384 supdrvGipUpdate(pDevExt->pGip, u64Monotime); 1385 } 1386 #endif 1387 } 1372 1388 mod_timer(&g_GipTimer, jiffies + (HZ <= 1000 ? 0 : ONE_MSEC_IN_JIFFIES)); 1373 1389 } 1390 1391 1392 #ifdef CONFIG_SMP 1393 /** 1394 * smp_call_function callback. 1395 * This is invoked on all the other CPUs. 1396 * 1397 * @param pvUser Pointer to the device extension. 1398 */ 1399 static void VBoxSupDrvGipPerCpu(void *pvUser) 1400 { 1401 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)ulUser; 1402 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 1403 supdrvGipUpdatePerCpu(pGip, pDevExt->u64LastMonotime, ASMGetApicId()); 1404 } 1405 #endif /* CONFIG_SMP */ 1374 1406 1375 1407 … … 1493 1525 if (timer_pending(&g_GipTimer)) 1494 1526 del_timer(&g_GipTimer); 1527 } 1528 1529 1530 /** 1531 * Get the current CPU count. 1532 * @returns Number of cpus. 1533 */ 1534 unsigned VBOXCALL supdrvOSGetCPUCount(void) 1535 { 1536 #ifdef CONFIG_SMP 1537 # ifdef num_present_cpus 1538 return num_present_cpus(); 1539 # else 1540 return smp_num_cpus; 1541 # endif 1542 #else 1543 return 1; 1544 #endif 1495 1545 } 1496 1546 -
trunk/src/VBox/HostDrivers/Support/testcase/Makefile
r1 r1027 65 65 tstPage_SOURCES = $(VBOX_PATH_SUPPORT)/testcase/tstPage.cpp 66 66 67 tstGIP-1_TEMPLATE = VBOXR3TSTEXE68 tstGIP-1_SOURCES = $(VBOX_PATH_SUPPORT)/testcase/tstGIP-1.c69 70 67 tstGIP-2_TEMPLATE = VBOXR3TSTEXE 71 68 tstGIP-2_SOURCES = $(VBOX_PATH_SUPPORT)/testcase/tstGIP-2.cpp -
trunk/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp
r1 r1027 57 57 RTPrintf("tstGIP-2: %2d: %016llx %016llx %08x %d %08x %15llu %08x %08x %08x %08x %08x %08x %08x %08x\n", 58 58 i, 59 g_pSUPGlobalInfoPage-> u64NanoTS,60 g_pSUPGlobalInfoPage-> u64TSC,61 g_pSUPGlobalInfoPage-> u32UpdateIntervalTSC,62 g_pSUPGlobalInfoPage-> iTSCHistoryHead,63 g_pSUPGlobalInfoPage-> u32TransactionId,64 g_pSUPGlobalInfoPage-> u64CpuHz,65 g_pSUPGlobalInfoPage->a u32TSCHistory[0],66 g_pSUPGlobalInfoPage->a u32TSCHistory[1],67 g_pSUPGlobalInfoPage->a u32TSCHistory[2],68 g_pSUPGlobalInfoPage->a u32TSCHistory[3],69 g_pSUPGlobalInfoPage->a u32TSCHistory[4],70 g_pSUPGlobalInfoPage->a u32TSCHistory[5],71 g_pSUPGlobalInfoPage->a u32TSCHistory[6],72 g_pSUPGlobalInfoPage->a u32TSCHistory[7]);59 g_pSUPGlobalInfoPage->aCPUs[0].u64NanoTS, 60 g_pSUPGlobalInfoPage->aCPUs[0].u64TSC, 61 g_pSUPGlobalInfoPage->aCPUs[0].u32UpdateIntervalTSC, 62 g_pSUPGlobalInfoPage->aCPUs[0].iTSCHistoryHead, 63 g_pSUPGlobalInfoPage->aCPUs[0].u32TransactionId, 64 g_pSUPGlobalInfoPage->aCPUs[0].u64CpuHz, 65 g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[0], 66 g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[1], 67 g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[2], 68 g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[3], 69 g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[4], 70 g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[5], 71 g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[6], 72 g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[7]); 73 73 RTThreadSleep(9); 74 74 } -
trunk/src/VBox/HostDrivers/Support/win32/SUPDrv-win32.cpp
r390 r1027 70 70 static void VBoxSupDrvGipTerm(PSUPDRVDEVEXT pDevExt); 71 71 static void _stdcall VBoxSupDrvGipTimer(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2); 72 static void _stdcall VBoxSupDrvGipPerCpuDpc(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2); 72 73 73 74 … … 789 790 */ 790 791 KeInitializeTimerEx(&pDevExt->GipTimer, SynchronizationTimer); 791 KeInitializeDpc(&pDevExt->GipDpc, VBoxSupDrvGipTimer, pGip); 792 KeInitializeDpc(&pDevExt->GipDpc, VBoxSupDrvGipTimer, pDevExt); 793 794 /* 795 * Initialize the DPCs we're using to update the per-cpu GIP data. 796 * (Not sure if we need to be this careful with KeSetTargetProcessorDpc...) 797 */ 798 UNICODE_STRING RoutineName; 799 RtlInitUnicodeString(&RoutineName, L"KeSetTargetProcessorDpc"); 800 VOID (*pfnKeSetTargetProcessorDpc)(IN PRKDPC, IN CCHAR) = (VOID (*)(IN PRKDPC, IN CCHAR))MmGetSystemRoutineAddress(&RoutineName); 801 802 for (unsigned i = 0; i < RT_ELEMENTS(pDevExt->aGipCpuDpcs); i++) 803 { 804 KeInitializeDpc(&pDevExt->aGipCpuDpcs[i], VBoxSupDrvGipPerCpuDpc, pGip); 805 KeSetImportanceDpc(&pDevExt->aGipCpuDpcs[i], HighImportance); 806 if (pfnKeSetTargetProcessorDpc) 807 pfnKeSetTargetProcessorDpc(&pDevExt->aGipCpuDpcs[i], i); 808 } 809 792 810 dprintf(("VBoxSupDrvGipInit: ulClockFreq=%ld ulClockInterval=%ld ulClockIntervalActual=%ld Phys=%x%08x\n", 793 811 ulClockFreq, ulClockInterval, ulClockIntervalActual, Phys.HighPart, Phys.LowPart)); 794 812 return STATUS_SUCCESS; 795 813 } 796 else 797 { 798 dprintf(("VBoxSupDrvInitGip: IoAllocateMdl failed for %p/PAGE_SIZE\n", pGip)); 799 rc = STATUS_NO_MEMORY; 800 } 814 815 dprintf(("VBoxSupDrvInitGip: IoAllocateMdl failed for %p/PAGE_SIZE\n", pGip)); 816 rc = STATUS_NO_MEMORY; 801 817 } 802 818 else … … 863 879 /** 864 880 * Timer callback function. 865 * The ulUser parameter is the GIP pointer. 866 */ 867 static void __stdcall VBoxSupDrvGipTimer(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2) 881 * The pvUser parameter is the pDevExt pointer. 882 */ 883 static void _stdcall VBoxSupDrvGipTimer(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2) 884 { 885 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser; 886 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 887 if (pGip) 888 { 889 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 890 supdrvGipUpdate(pGip, supdrvOSMonotime()); 891 else 892 { 893 RTCCUINTREG xFL = ASMGetFlags(); 894 ASMIntDisable(); 895 896 /* 897 * We cannot do other than assume a 1:1 relation ship between the 898 * affinity mask and the process despite the warnings in the docs. 899 * If someone knows a better way to get this done, please let bird know. 900 */ 901 unsigned iSelf = KeGetCurrentProcessorNumber(); 902 KAFFINITY Mask = KeQueryActiveProcessors(); 903 904 for (unsigned i = 0; i < RT_ELEMENTS(pDevExt->aGipCpuDpcs); i++) 905 { 906 if ( i != iSelf 907 && (Mask & (1 << i))) 908 KeInsertQueueDpc(&pDevExt->aGipCpuDpcs[i], 0, 0); 909 } 910 911 /* Run the normal update. */ 912 supdrvGipUpdate(pGip, supdrvOSMonotime()); 913 914 ASMSetFlags(xFL); 915 } 916 } 917 } 918 919 920 /** 921 * Per cpu callback callback function. 922 * The pvUser parameter is the pGip pointer. 923 */ 924 static void _stdcall VBoxSupDrvGipPerCpuDpc(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2) 868 925 { 869 926 PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser; 870 supdrvGipUpdate (pGip, supdrvOSMonotime());927 supdrvGipUpdatePerCpu(pGip, supdrvOSMonotime(), ASMGetApicId()); 871 928 } 872 929 -
trunk/src/VBox/Runtime/timesup.cpp
r656 r1027 75 75 * Read the data. 76 76 */ 77 do77 for (;;) 78 78 { 79 79 pGip = g_pSUPGlobalInfoPage; … … 82 82 return RTTimeSystemNanoTS(); 83 83 #endif 84 u32TransactionId = pGip->u32TransactionId; 84 85 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 86 { 87 u32TransactionId = pGip->aCPUs[0].u32TransactionId; 85 88 #ifdef __L4__ 86 Assert((u32TransactionId & 1) == 0); 87 #endif 88 u32UpdateIntervalTSC = pGip->u32UpdateIntervalTSC; 89 u64NanoTS = pGip->u64NanoTS; 90 u64TSC = pGip->u64TSC; 91 u32NanoTSFactor0 = pGip->u32UpdateIntervalNS; 92 u64Delta = ASMReadTSC(); 93 } while ( pGip->u32TransactionId != u32TransactionId 94 || (u32TransactionId & 1)); 89 Assert((u32TransactionId & 1) == 0); 90 #endif 91 u32UpdateIntervalTSC = pGip->aCPUs[0].u32UpdateIntervalTSC; 92 u64NanoTS = pGip->aCPUs[0].u64NanoTS; 93 u64TSC = pGip->aCPUs[0].u64TSC; 94 u32NanoTSFactor0 = pGip->u32UpdateIntervalNS; 95 u64Delta = ASMReadTSC(); 96 if (RT_UNLIKELY( pGip->aCPUs[0].u32TransactionId != u32TransactionId 97 || (u32TransactionId & 1))) 98 continue; 99 } 100 else 101 { 102 /* SUPGIPMODE_ASYNC_TSC */ 103 PCSUPGIPCPU pGipCpu; 104 105 uint8_t u8ApicId = ASMGetApicId(); 106 if (RT_LIKELY(u8ApicId < RT_ELEMENTS(pGip->aCPUs))) 107 pGipCpu = &pGip->aCPUs[u8ApicId]; 108 else 109 { 110 AssertMsgFailed(("%x\n", u8ApicId)); 111 pGipCpu = &pGip->aCPUs[0]; 112 } 113 114 u32TransactionId = pGipCpu->u32TransactionId; 115 #ifdef __L4__ 116 Assert((u32TransactionId & 1) == 0); 117 #endif 118 u32UpdateIntervalTSC = pGipCpu->u32UpdateIntervalTSC; 119 u64NanoTS = pGipCpu->u64NanoTS; 120 u64TSC = pGipCpu->u64TSC; 121 u32NanoTSFactor0 = pGip->u32UpdateIntervalNS; 122 u64Delta = ASMReadTSC(); 123 if (RT_UNLIKELY(u8ApicId != ASMGetApicId())) 124 continue; 125 if (RT_UNLIKELY( pGipCpu->u32TransactionId != u32TransactionId 126 || (u32TransactionId & 1))) 127 continue; 128 } 129 break; 130 } 95 131 96 132 /* -
trunk/src/VBox/VMM/TM.cpp
r443 r1027 289 289 uint64_t u64Hz; 290 290 PCSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; 291 if (pGip && (u64Hz = pGip->u64CpuHz) && u64Hz != ~(uint64_t)0) 292 { 293 RTThreadSleep(32); /* To preserve old behaviour and to get a good CpuHz at startup. */ 294 pGip = g_pSUPGlobalInfoPage; 295 if (pGip && (u64Hz = pGip->u64CpuHz) && u64Hz != ~(uint64_t)0) 296 return u64Hz; 291 if ( pGip 292 && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC) 293 { 294 unsigned iCpu = pGip->u32Mode != SUPGIPMODE_ASYNC_TSC ? 0 : ASMGetApicId(); 295 if (iCpu >= RT_ELEMENTS(pGip->aCPUs)) 296 AssertReleaseMsgFailed(("iCpu=%d - the ApicId is too high. send VBox.log and hardware specs!\n", iCpu)); 297 else 298 { 299 RTThreadSleep(32); /* To preserve old behaviour and to get a good CpuHz at startup. */ 300 pGip = g_pSUPGlobalInfoPage; 301 if ( pGip 302 && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC 303 && (u64Hz = pGip->aCPUs[iCpu].u64CpuHz) 304 && u64Hz != ~(uint64_t)0) 305 return u64Hz; 306 } 297 307 } 298 308 -
trunk/src/VBox/VMM/VMM.cpp
r988 r1027 2804 2804 } 2805 2805 uint64_t Ticks = ASMReadTSC() - StartTick; 2806 if (Ticks < ( g_pSUPGlobalInfoPage->u64CpuHz/ 10000))2807 RTPrintf("Warning: Ticks=%RU64 (< %RU64)\n", Ticks, g_pSUPGlobalInfoPage->u64CpuHz/ 10000);2806 if (Ticks < (SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) / 10000)) 2807 RTPrintf("Warning: Ticks=%RU64 (< %RU64)\n", Ticks, SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) / 10000); 2808 2808 } 2809 2809 -
trunk/src/VBox/VMM/VMMAll/TMAll.cpp
r23 r1027 612 612 PCSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; 613 613 if (pGip) 614 return pGip->u64CpuHz;614 return SUPGetCpuHzFromGIP(pGip) ; 615 615 return pTimer->CTXALLSUFF(pVM)->tm.s.cTSCTicksPerSecond; 616 616 } -
trunk/src/VBox/VMM/VMMGC/VMMGC.cpp
r988 r1027 102 102 case VMMGC_DO_TESTCASE_INTERRUPT_MASKING: 103 103 { 104 uint64_t u64MaxTicks = (g_pSUPGlobalInfoPage ? g_pSUPGlobalInfoPage->u64CpuHz : _2G) / 10000; 104 uint64_t u64MaxTicks = (SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) != ~(uint64_t)0 105 ? SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) 106 : _2G) 107 / 10000; 105 108 uint64_t u64StartTSC = ASMReadTSC(); 106 109 uint64_t u64TicksNow;
Note:
See TracChangeset
for help on using the changeset viewer.