VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPLibAll.cpp@ 54257

Last change on this file since 54257 was 54257, checked in by vboxsync, 10 years ago

SUPReadTscWithDelta: Optimized via fGetGipCpu and more.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 5.8 KB
Line 
1/* $Id: SUPLibAll.cpp 54257 2015-02-17 23:24:45Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - All Contexts Code.
4 */
5
6/*
7 * Copyright (C) 2006-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#include <VBox/sup.h>
31#ifdef IN_RC
32# include <VBox/vmm/vm.h>
33# include <VBox/vmm/vmm.h>
34#endif
35#ifdef IN_RING0
36# include <iprt/mp.h>
37#endif
38#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
39# include <iprt/asm-amd64-x86.h>
40#endif
41
42
43#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
44
45/**
46 * The slow case for SUPReadTsc where we need to apply deltas.
47 *
48 * Must only be called when deltas are applicable, so please do not call it
49 * directly.
50 *
51 * @returns TSC with delta applied.
52 *
53 * @remarks May be called with interrupts disabled in ring-0! This is why the
54 * ring-0 code doesn't attempt to figure the delta.
55 *
56 * @internal
57 */
58SUPDECL(uint64_t) SUPReadTscWithDelta(void)
59{
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);
65 Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));
66
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;
159
160# ifdef IN_RING3
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 */
170 }
171
172 /*
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.
175 */
176 AssertMsgFailed(("iGipCpu=%d (%#x) cCpus=%d fGetGipCpu=%#x\n", iGipCpu, iGipCpu, pGip->cCpus, pGip->fGetGipCpu));
177 return uTsc;
178}
179
180#endif /* RT_ARCH_AMD64 || RT_ARCH_X86 */
181
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette