VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/VMMAll.cpp@ 77807

Last change on this file since 77807 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 10.8 KB
Line 
1/* $Id: VMMAll.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VMM All Contexts.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_VMM
23#include <VBox/vmm/vmm.h>
24#include "VMMInternal.h"
25#include <VBox/vmm/vm.h>
26#include <VBox/vmm/hm.h>
27#include <VBox/vmm/vmcpuset.h>
28#include <VBox/param.h>
29#include <iprt/thread.h>
30#include <iprt/mp.h>
31
32
33/*********************************************************************************************************************************
34* Global Variables *
35*********************************************************************************************************************************/
36/** User counter for the vmmInitFormatTypes function (pro forma). */
37static volatile uint32_t g_cFormatTypeUsers = 0;
38
39
40/**
41 * Helper that formats a decimal number in the range 0..9999.
42 *
43 * @returns The length of the formatted number.
44 * @param pszBuf Output buffer with sufficient space.
45 * @param uNumber The number to format.
46 */
47static unsigned vmmFormatTypeShortNumber(char *pszBuf, uint32_t uNumber)
48{
49 unsigned off = 0;
50 if (uNumber >= 10)
51 {
52 if (uNumber >= 100)
53 {
54 if (uNumber >= 1000)
55 pszBuf[off++] = ((uNumber / 1000) % 10) + '0';
56 pszBuf[off++] = ((uNumber / 100) % 10) + '0';
57 }
58 pszBuf[off++] = ((uNumber / 10) % 10) + '0';
59 }
60 pszBuf[off++] = (uNumber % 10) + '0';
61 pszBuf[off] = '\0';
62 return off;
63}
64
65
66/**
67 * @callback_method_impl{FNRTSTRFORMATTYPE, vmsetcpu}
68 */
69static DECLCALLBACK(size_t) vmmFormatTypeVmCpuSet(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
70 const char *pszType, void const *pvValue,
71 int cchWidth, int cchPrecision, unsigned fFlags,
72 void *pvUser)
73{
74 NOREF(pszType); NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags);
75
76 PCVMCPUSET pSet = (PCVMCPUSET)pvValue;
77 uint32_t cCpus = 0;
78 uint32_t iCpu = RT_ELEMENTS(pSet->au32Bitmap) * 32;
79 while (iCpu--)
80 if (VMCPUSET_IS_PRESENT(pSet, iCpu))
81 cCpus++;
82
83 char szTmp[32];
84 AssertCompile(RT_ELEMENTS(pSet->au32Bitmap) * 32 < 999);
85 if (cCpus == 1)
86 {
87 iCpu = RT_ELEMENTS(pSet->au32Bitmap) * 32;
88 while (iCpu--)
89 if (VMCPUSET_IS_PRESENT(pSet, iCpu))
90 {
91 szTmp[0] = 'c';
92 szTmp[1] = 'p';
93 szTmp[2] = 'u';
94 return pfnOutput(pvArgOutput, szTmp, 3 + vmmFormatTypeShortNumber(&szTmp[3], iCpu));
95 }
96 cCpus = 0;
97 }
98 if (cCpus == 0)
99 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<empty>"));
100 if (cCpus == RT_ELEMENTS(pSet->au32Bitmap) * 32)
101 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<full>"));
102
103 /*
104 * Print cpus that are present: {1,2,7,9 ... }
105 */
106 size_t cchRet = pfnOutput(pvArgOutput, "{", 1);
107
108 cCpus = 0;
109 iCpu = 0;
110 while (iCpu < RT_ELEMENTS(pSet->au32Bitmap) * 32)
111 {
112 if (VMCPUSET_IS_PRESENT(pSet, iCpu))
113 {
114 /* Output the first cpu number. */
115 int off = 0;
116 if (cCpus != 0)
117 szTmp[off++] = ',';
118 cCpus++;
119 off += vmmFormatTypeShortNumber(&szTmp[off], iCpu);
120
121 /* Check for sequence. */
122 uint32_t const iStart = ++iCpu;
123 while ( iCpu < RT_ELEMENTS(pSet->au32Bitmap) * 32
124 && VMCPUSET_IS_PRESENT(pSet, iCpu))
125 {
126 iCpu++;
127 cCpus++;
128 }
129 if (iCpu != iStart)
130 {
131 szTmp[off++] = '-';
132 off += vmmFormatTypeShortNumber(&szTmp[off], iCpu);
133 }
134
135 /* Terminate and output. */
136 szTmp[off] = '\0';
137 cchRet += pfnOutput(pvArgOutput, szTmp, off);
138 }
139 iCpu++;
140 }
141
142 cchRet += pfnOutput(pvArgOutput, "}", 1);
143 NOREF(pvUser);
144 return cchRet;
145}
146
147
148/**
149 * Registers the VMM wide format types.
150 *
151 * Called by VMMR3Init, VMMR0Init and VMMRCInit.
152 */
153int vmmInitFormatTypes(void)
154{
155 int rc = VINF_SUCCESS;
156 if (ASMAtomicIncU32(&g_cFormatTypeUsers) == 1)
157 rc = RTStrFormatTypeRegister("vmcpuset", vmmFormatTypeVmCpuSet, NULL);
158 return rc;
159}
160
161
162#ifndef IN_RC
163/**
164 * Counterpart to vmmInitFormatTypes, called by VMMR3Term and VMMR0Term.
165 */
166void vmmTermFormatTypes(void)
167{
168 if (ASMAtomicDecU32(&g_cFormatTypeUsers) == 0)
169 RTStrFormatTypeDeregister("vmcpuset");
170}
171#endif
172
173
174/**
175 * Gets the bottom of the hypervisor stack - RC Ptr.
176 *
177 * (The returned address is not actually writable, only after it's decremented
178 * by a push/ret/whatever does it become writable.)
179 *
180 * @returns bottom of the stack.
181 * @param pVCpu The cross context virtual CPU structure.
182 */
183VMM_INT_DECL(RTRCPTR) VMMGetStackRC(PVMCPU pVCpu)
184{
185 return (RTRCPTR)pVCpu->vmm.s.pbEMTStackBottomRC;
186}
187
188
189/**
190 * Gets the ID of the virtual CPU associated with the calling thread.
191 *
192 * @returns The CPU ID. NIL_VMCPUID if the thread isn't an EMT.
193 *
194 * @param pVM The cross context VM structure.
195 * @internal
196 */
197VMMDECL(VMCPUID) VMMGetCpuId(PVM pVM)
198{
199#if defined(IN_RING3)
200 return VMR3GetVMCPUId(pVM);
201
202#elif defined(IN_RING0)
203 if (pVM->cCpus == 1)
204 return 0;
205
206 /* Search first by host cpu id (most common case)
207 * and then by native thread id (page fusion case).
208 */
209 if (!RTThreadPreemptIsEnabled(NIL_RTTHREAD))
210 {
211 /** @todo r=ramshankar: This doesn't buy us anything in terms of performance
212 * leaving it here for hysterical raisins and as a reference if we
213 * implemented a hashing approach in the future. */
214 RTCPUID idHostCpu = RTMpCpuId();
215
216 /** @todo optimize for large number of VCPUs when that becomes more common. */
217 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
218 {
219 PVMCPU pVCpu = &pVM->aCpus[idCpu];
220
221 if (pVCpu->idHostCpu == idHostCpu)
222 return pVCpu->idCpu;
223 }
224 }
225
226 /* RTThreadGetNativeSelf had better be cheap. */
227 RTNATIVETHREAD hThread = RTThreadNativeSelf();
228
229 /** @todo optimize for large number of VCPUs when that becomes more common. */
230 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
231 {
232 PVMCPU pVCpu = &pVM->aCpus[idCpu];
233
234 if (pVCpu->hNativeThreadR0 == hThread)
235 return pVCpu->idCpu;
236 }
237 return NIL_VMCPUID;
238
239#else /* RC: Always EMT(0) */
240 NOREF(pVM);
241 return 0;
242#endif
243}
244
245
246/**
247 * Returns the VMCPU of the calling EMT.
248 *
249 * @returns The VMCPU pointer. NULL if not an EMT.
250 *
251 * @param pVM The cross context VM structure.
252 * @internal
253 */
254VMMDECL(PVMCPU) VMMGetCpu(PVM pVM)
255{
256#ifdef IN_RING3
257 VMCPUID idCpu = VMR3GetVMCPUId(pVM);
258 if (idCpu == NIL_VMCPUID)
259 return NULL;
260 Assert(idCpu < pVM->cCpus);
261 return &pVM->aCpus[idCpu];
262
263#elif defined(IN_RING0)
264 if (pVM->cCpus == 1)
265 return &pVM->aCpus[0];
266
267 /*
268 * Search first by host cpu id (most common case)
269 * and then by native thread id (page fusion case).
270 */
271 if (!RTThreadPreemptIsEnabled(NIL_RTTHREAD))
272 {
273 /** @todo r=ramshankar: This doesn't buy us anything in terms of performance
274 * leaving it here for hysterical raisins and as a reference if we
275 * implemented a hashing approach in the future. */
276 RTCPUID idHostCpu = RTMpCpuId();
277
278 /** @todo optimize for large number of VCPUs when that becomes more common. */
279 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
280 {
281 PVMCPU pVCpu = &pVM->aCpus[idCpu];
282
283 if (pVCpu->idHostCpu == idHostCpu)
284 return pVCpu;
285 }
286 }
287
288 /* RTThreadGetNativeSelf had better be cheap. */
289 RTNATIVETHREAD hThread = RTThreadNativeSelf();
290
291 /** @todo optimize for large number of VCPUs when that becomes more common.
292 * Use a map like GIP does that's indexed by the host CPU index. */
293 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
294 {
295 PVMCPU pVCpu = &pVM->aCpus[idCpu];
296
297 if (pVCpu->hNativeThreadR0 == hThread)
298 return pVCpu;
299 }
300 return NULL;
301
302#else /* RC: Always EMT(0) */
303 return &pVM->aCpus[0];
304#endif /* IN_RING0 */
305}
306
307
308/**
309 * Returns the VMCPU of the first EMT thread.
310 *
311 * @returns The VMCPU pointer.
312 * @param pVM The cross context VM structure.
313 * @internal
314 */
315VMMDECL(PVMCPU) VMMGetCpu0(PVM pVM)
316{
317 Assert(pVM->cCpus == 1);
318 return &pVM->aCpus[0];
319}
320
321
322/**
323 * Returns the VMCPU of the specified virtual CPU.
324 *
325 * @returns The VMCPU pointer. NULL if idCpu is invalid.
326 *
327 * @param pVM The cross context VM structure.
328 * @param idCpu The ID of the virtual CPU.
329 * @internal
330 */
331VMMDECL(PVMCPU) VMMGetCpuById(PVM pVM, RTCPUID idCpu)
332{
333 AssertReturn(idCpu < pVM->cCpus, NULL);
334 return &pVM->aCpus[idCpu];
335}
336
337
338/**
339 * Gets the VBOX_SVN_REV.
340 *
341 * This is just to avoid having to compile a bunch of big files
342 * and requires less Makefile mess.
343 *
344 * @returns VBOX_SVN_REV.
345 */
346VMM_INT_DECL(uint32_t) VMMGetSvnRev(void)
347{
348 return VBOX_SVN_REV;
349}
350
351
352/**
353 * Queries the current switcher
354 *
355 * @returns active switcher
356 * @param pVM The cross context VM structure.
357 */
358VMM_INT_DECL(VMMSWITCHER) VMMGetSwitcher(PVM pVM)
359{
360 return pVM->vmm.s.enmSwitcher;
361}
362
363
364/**
365 * Checks whether we're in a ring-3 call or not.
366 *
367 * @returns true / false.
368 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
369 * @thread EMT
370 */
371VMM_INT_DECL(bool) VMMIsInRing3Call(PVMCPU pVCpu)
372{
373#ifdef RT_ARCH_X86
374 return pVCpu->vmm.s.CallRing3JmpBufR0.fInRing3Call;
375#else
376 return pVCpu->vmm.s.CallRing3JmpBufR0.fInRing3Call;
377#endif
378}
379
380
381/**
382 * Returns the build type for matching components.
383 *
384 * @returns Build type value.
385 */
386uint32_t vmmGetBuildType(void)
387{
388 uint32_t uRet = 0xbeef0000;
389#ifdef DEBUG
390 uRet |= RT_BIT_32(0);
391#endif
392#ifdef VBOX_WITH_STATISTICS
393 uRet |= RT_BIT_32(1);
394#endif
395 return uRet;
396}
397
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