VirtualBox

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

Last change on this file since 71586 was 70948, checked in by vboxsync, 7 years ago

VMM: Added a bMainExecutionEngine member to the VM structure for use instead of fHMEnabled and fNEMEnabled. Changed a lot of HMIsEnabled invocations to use the new macros VM_IS_RAW_MODE_ENABLED and VM_IS_HM_OR_NEM_ENABLED. Eliminated fHMEnabledFixed. Fixed inverted test for raw-mode debug register sanity checking. Some other minor cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.3 KB
Line 
1/* $Id: VMMAll.cpp 70948 2018-02-10 15:38:12Z vboxsync $ */
2/** @file
3 * VMM All Contexts.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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
398
399/**
400 * Patches the instructions necessary for making a hypercall to the hypervisor.
401 * Used by GIM.
402 *
403 * @returns VBox status code.
404 * @param pVM The cross context VM structure.
405 * @param pvBuf The buffer in the hypercall page(s) to be patched.
406 * @param cbBuf The size of the buffer.
407 * @param pcbWritten Where to store the number of bytes patched. This
408 * is reliably updated only when this function returns
409 * VINF_SUCCESS.
410 */
411VMM_INT_DECL(int) VMMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
412{
413 AssertReturn(pvBuf, VERR_INVALID_POINTER);
414 AssertReturn(pcbWritten, VERR_INVALID_POINTER);
415
416 CPUMCPUVENDOR enmHostCpu = CPUMGetHostCpuVendor(pVM);
417 switch (enmHostCpu)
418 {
419 case CPUMCPUVENDOR_AMD:
420 {
421 uint8_t abHypercall[] = { 0x0F, 0x01, 0xD9 }; /* VMMCALL */
422 if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
423 {
424 memcpy(pvBuf, abHypercall, sizeof(abHypercall));
425 *pcbWritten = sizeof(abHypercall);
426 return VINF_SUCCESS;
427 }
428 return VERR_BUFFER_OVERFLOW;
429 }
430
431 case CPUMCPUVENDOR_INTEL:
432 case CPUMCPUVENDOR_VIA:
433 {
434 uint8_t abHypercall[] = { 0x0F, 0x01, 0xC1 }; /* VMCALL */
435 if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
436 {
437 memcpy(pvBuf, abHypercall, sizeof(abHypercall));
438 *pcbWritten = sizeof(abHypercall);
439 return VINF_SUCCESS;
440 }
441 return VERR_BUFFER_OVERFLOW;
442 }
443
444 default:
445 AssertFailed();
446 return VERR_UNSUPPORTED_CPU;
447 }
448}
449
450
451/**
452 * Notifies VMM that paravirtualized hypercalls are now enabled.
453 *
454 * @param pVCpu The cross context virtual CPU structure.
455 */
456VMM_INT_DECL(void) VMMHypercallsEnable(PVMCPU pVCpu)
457{
458 /* If there is anything to do for raw-mode, do it here. */
459/** @todo NEM: Hypercalls. */
460#ifndef IN_RC
461 if (HMIsEnabled(pVCpu->CTX_SUFF(pVM)))
462 HMHypercallsEnable(pVCpu);
463#else
464 RT_NOREF_PV(pVCpu);
465#endif
466}
467
468
469/**
470 * Notifies VMM that paravirtualized hypercalls are now disabled.
471 *
472 * @param pVCpu The cross context virtual CPU structure.
473 */
474VMM_INT_DECL(void) VMMHypercallsDisable(PVMCPU pVCpu)
475{
476 /* If there is anything to do for raw-mode, do it here. */
477/** @todo NEM: Hypercalls. */
478#ifndef IN_RC
479 if (HMIsEnabled(pVCpu->CTX_SUFF(pVM)))
480 HMHypercallsDisable(pVCpu);
481#else
482 RT_NOREF_PV(pVCpu);
483#endif
484}
485
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