VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/VMM.cpp@ 70944

Last change on this file since 70944 was 70941, checked in by vboxsync, 7 years ago

VMM: Don't assert on VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 112.0 KB
Line 
1/* $Id: VMM.cpp 70941 2018-02-09 19:41:03Z vboxsync $ */
2/** @file
3 * VMM - The Virtual Machine Monitor Core.
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//#define NO_SUPCALLR0VMM
19
20/** @page pg_vmm VMM - The Virtual Machine Monitor
21 *
22 * The VMM component is two things at the moment, it's a component doing a few
23 * management and routing tasks, and it's the whole virtual machine monitor
24 * thing. For hysterical reasons, it is not doing all the management that one
25 * would expect, this is instead done by @ref pg_vm. We'll address this
26 * misdesign eventually, maybe.
27 *
28 * VMM is made up of these components:
29 * - @subpage pg_cfgm
30 * - @subpage pg_cpum
31 * - @subpage pg_csam
32 * - @subpage pg_dbgf
33 * - @subpage pg_em
34 * - @subpage pg_gim
35 * - @subpage pg_gmm
36 * - @subpage pg_gvmm
37 * - @subpage pg_hm
38 * - @subpage pg_iem
39 * - @subpage pg_iom
40 * - @subpage pg_mm
41 * - @subpage pg_patm
42 * - @subpage pg_pdm
43 * - @subpage pg_pgm
44 * - @subpage pg_rem
45 * - @subpage pg_selm
46 * - @subpage pg_ssm
47 * - @subpage pg_stam
48 * - @subpage pg_tm
49 * - @subpage pg_trpm
50 * - @subpage pg_vm
51 *
52 *
53 * @see @ref grp_vmm @ref grp_vm @subpage pg_vmm_guideline @subpage pg_raw
54 *
55 *
56 * @section sec_vmmstate VMM State
57 *
58 * @image html VM_Statechart_Diagram.gif
59 *
60 * To be written.
61 *
62 *
63 * @subsection subsec_vmm_init VMM Initialization
64 *
65 * To be written.
66 *
67 *
68 * @subsection subsec_vmm_term VMM Termination
69 *
70 * To be written.
71 *
72 *
73 * @section sec_vmm_limits VMM Limits
74 *
75 * There are various resource limits imposed by the VMM and it's
76 * sub-components. We'll list some of them here.
77 *
78 * On 64-bit hosts:
79 * - Max 8191 VMs. Imposed by GVMM's handle allocation (GVMM_MAX_HANDLES),
80 * can be increased up to 64K - 1.
81 * - Max 16TB - 64KB of the host memory can be used for backing VM RAM and
82 * ROM pages. The limit is imposed by the 32-bit page ID used by GMM.
83 * - A VM can be assigned all the memory we can use (16TB), however, the
84 * Main API will restrict this to 2TB (MM_RAM_MAX_IN_MB).
85 * - Max 32 virtual CPUs (VMM_MAX_CPU_COUNT).
86 *
87 * On 32-bit hosts:
88 * - Max 127 VMs. Imposed by GMM's per page structure.
89 * - Max 64GB - 64KB of the host memory can be used for backing VM RAM and
90 * ROM pages. The limit is imposed by the 28-bit page ID used
91 * internally in GMM. It is also limited by PAE.
92 * - A VM can be assigned all the memory GMM can allocate, however, the
93 * Main API will restrict this to 3584MB (MM_RAM_MAX_IN_MB).
94 * - Max 32 virtual CPUs (VMM_MAX_CPU_COUNT).
95 *
96 */
97
98
99/*********************************************************************************************************************************
100* Header Files *
101*********************************************************************************************************************************/
102#define LOG_GROUP LOG_GROUP_VMM
103#include <VBox/vmm/vmm.h>
104#include <VBox/vmm/vmapi.h>
105#include <VBox/vmm/pgm.h>
106#include <VBox/vmm/cfgm.h>
107#include <VBox/vmm/pdmqueue.h>
108#include <VBox/vmm/pdmcritsect.h>
109#include <VBox/vmm/pdmcritsectrw.h>
110#include <VBox/vmm/pdmapi.h>
111#include <VBox/vmm/cpum.h>
112#include <VBox/vmm/gim.h>
113#include <VBox/vmm/mm.h>
114#include <VBox/vmm/nem.h>
115#include <VBox/vmm/iom.h>
116#include <VBox/vmm/trpm.h>
117#include <VBox/vmm/selm.h>
118#include <VBox/vmm/em.h>
119#include <VBox/sup.h>
120#include <VBox/vmm/dbgf.h>
121#include <VBox/vmm/csam.h>
122#include <VBox/vmm/patm.h>
123#include <VBox/vmm/apic.h>
124#ifdef VBOX_WITH_REM
125# include <VBox/vmm/rem.h>
126#endif
127#include <VBox/vmm/ssm.h>
128#include <VBox/vmm/ftm.h>
129#include <VBox/vmm/tm.h>
130#include "VMMInternal.h"
131#include "VMMSwitcher.h"
132#include <VBox/vmm/vm.h>
133#include <VBox/vmm/uvm.h>
134
135#include <VBox/err.h>
136#include <VBox/param.h>
137#include <VBox/version.h>
138#include <VBox/vmm/hm.h>
139#include <iprt/assert.h>
140#include <iprt/alloc.h>
141#include <iprt/asm.h>
142#include <iprt/time.h>
143#include <iprt/semaphore.h>
144#include <iprt/stream.h>
145#include <iprt/string.h>
146#include <iprt/stdarg.h>
147#include <iprt/ctype.h>
148#include <iprt/x86.h>
149
150
151/*********************************************************************************************************************************
152* Defined Constants And Macros *
153*********************************************************************************************************************************/
154/** The saved state version. */
155#define VMM_SAVED_STATE_VERSION 4
156/** The saved state version used by v3.0 and earlier. (Teleportation) */
157#define VMM_SAVED_STATE_VERSION_3_0 3
158
159
160/*********************************************************************************************************************************
161* Internal Functions *
162*********************************************************************************************************************************/
163static int vmmR3InitStacks(PVM pVM);
164static int vmmR3InitLoggers(PVM pVM);
165static void vmmR3InitRegisterStats(PVM pVM);
166static DECLCALLBACK(int) vmmR3Save(PVM pVM, PSSMHANDLE pSSM);
167static DECLCALLBACK(int) vmmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
168static DECLCALLBACK(void) vmmR3YieldEMT(PVM pVM, PTMTIMER pTimer, void *pvUser);
169static VBOXSTRICTRC vmmR3EmtRendezvousCommon(PVM pVM, PVMCPU pVCpu, bool fIsCaller,
170 uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser);
171static int vmmR3ServiceCallRing3Request(PVM pVM, PVMCPU pVCpu);
172static DECLCALLBACK(void) vmmR3InfoFF(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
173
174
175/**
176 * Initializes the VMM.
177 *
178 * @returns VBox status code.
179 * @param pVM The cross context VM structure.
180 */
181VMMR3_INT_DECL(int) VMMR3Init(PVM pVM)
182{
183 LogFlow(("VMMR3Init\n"));
184
185 /*
186 * Assert alignment, sizes and order.
187 */
188 AssertMsg(pVM->vmm.s.offVM == 0, ("Already initialized!\n"));
189 AssertCompile(sizeof(pVM->vmm.s) <= sizeof(pVM->vmm.padding));
190 AssertCompile(sizeof(pVM->aCpus[0].vmm.s) <= sizeof(pVM->aCpus[0].vmm.padding));
191
192 /*
193 * Init basic VM VMM members.
194 */
195 pVM->vmm.s.offVM = RT_OFFSETOF(VM, vmm);
196 pVM->vmm.s.pahEvtRendezvousEnterOrdered = NULL;
197 pVM->vmm.s.hEvtRendezvousEnterOneByOne = NIL_RTSEMEVENT;
198 pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce = NIL_RTSEMEVENTMULTI;
199 pVM->vmm.s.hEvtMulRendezvousDone = NIL_RTSEMEVENTMULTI;
200 pVM->vmm.s.hEvtRendezvousDoneCaller = NIL_RTSEMEVENT;
201 pVM->vmm.s.hEvtMulRendezvousRecursionPush = NIL_RTSEMEVENTMULTI;
202 pVM->vmm.s.hEvtMulRendezvousRecursionPop = NIL_RTSEMEVENTMULTI;
203 pVM->vmm.s.hEvtRendezvousRecursionPushCaller = NIL_RTSEMEVENT;
204 pVM->vmm.s.hEvtRendezvousRecursionPopCaller = NIL_RTSEMEVENT;
205
206 /** @cfgm{/YieldEMTInterval, uint32_t, 1, UINT32_MAX, 23, ms}
207 * The EMT yield interval. The EMT yielding is a hack we employ to play a
208 * bit nicer with the rest of the system (like for instance the GUI).
209 */
210 int rc = CFGMR3QueryU32Def(CFGMR3GetRoot(pVM), "YieldEMTInterval", &pVM->vmm.s.cYieldEveryMillies,
211 23 /* Value arrived at after experimenting with the grub boot prompt. */);
212 AssertMsgRCReturn(rc, ("Configuration error. Failed to query \"YieldEMTInterval\", rc=%Rrc\n", rc), rc);
213
214
215 /** @cfgm{/VMM/UsePeriodicPreemptionTimers, boolean, true}
216 * Controls whether we employ per-cpu preemption timers to limit the time
217 * spent executing guest code. This option is not available on all
218 * platforms and we will silently ignore this setting then. If we are
219 * running in VT-x mode, we will use the VMX-preemption timer instead of
220 * this one when possible.
221 */
222 PCFGMNODE pCfgVMM = CFGMR3GetChild(CFGMR3GetRoot(pVM), "VMM");
223 rc = CFGMR3QueryBoolDef(pCfgVMM, "UsePeriodicPreemptionTimers", &pVM->vmm.s.fUsePeriodicPreemptionTimers, true);
224 AssertMsgRCReturn(rc, ("Configuration error. Failed to query \"VMM/UsePeriodicPreemptionTimers\", rc=%Rrc\n", rc), rc);
225
226 /*
227 * Initialize the VMM rendezvous semaphores.
228 */
229 pVM->vmm.s.pahEvtRendezvousEnterOrdered = (PRTSEMEVENT)MMR3HeapAlloc(pVM, MM_TAG_VMM, sizeof(RTSEMEVENT) * pVM->cCpus);
230 if (!pVM->vmm.s.pahEvtRendezvousEnterOrdered)
231 return VERR_NO_MEMORY;
232 for (VMCPUID i = 0; i < pVM->cCpus; i++)
233 pVM->vmm.s.pahEvtRendezvousEnterOrdered[i] = NIL_RTSEMEVENT;
234 for (VMCPUID i = 0; i < pVM->cCpus; i++)
235 {
236 rc = RTSemEventCreate(&pVM->vmm.s.pahEvtRendezvousEnterOrdered[i]);
237 AssertRCReturn(rc, rc);
238 }
239 rc = RTSemEventCreate(&pVM->vmm.s.hEvtRendezvousEnterOneByOne);
240 AssertRCReturn(rc, rc);
241 rc = RTSemEventMultiCreate(&pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);
242 AssertRCReturn(rc, rc);
243 rc = RTSemEventMultiCreate(&pVM->vmm.s.hEvtMulRendezvousDone);
244 AssertRCReturn(rc, rc);
245 rc = RTSemEventCreate(&pVM->vmm.s.hEvtRendezvousDoneCaller);
246 AssertRCReturn(rc, rc);
247 rc = RTSemEventMultiCreate(&pVM->vmm.s.hEvtMulRendezvousRecursionPush);
248 AssertRCReturn(rc, rc);
249 rc = RTSemEventMultiCreate(&pVM->vmm.s.hEvtMulRendezvousRecursionPop);
250 AssertRCReturn(rc, rc);
251 rc = RTSemEventCreate(&pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
252 AssertRCReturn(rc, rc);
253 rc = RTSemEventCreate(&pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
254 AssertRCReturn(rc, rc);
255
256 /*
257 * Register the saved state data unit.
258 */
259 rc = SSMR3RegisterInternal(pVM, "vmm", 1, VMM_SAVED_STATE_VERSION, VMM_STACK_SIZE + sizeof(RTGCPTR),
260 NULL, NULL, NULL,
261 NULL, vmmR3Save, NULL,
262 NULL, vmmR3Load, NULL);
263 if (RT_FAILURE(rc))
264 return rc;
265
266 /*
267 * Register the Ring-0 VM handle with the session for fast ioctl calls.
268 */
269 rc = SUPR3SetVMForFastIOCtl(pVM->pVMR0);
270 if (RT_FAILURE(rc))
271 return rc;
272
273 /*
274 * Init various sub-components.
275 */
276 rc = vmmR3SwitcherInit(pVM);
277 if (RT_SUCCESS(rc))
278 {
279 rc = vmmR3InitStacks(pVM);
280 if (RT_SUCCESS(rc))
281 {
282 rc = vmmR3InitLoggers(pVM);
283
284#ifdef VBOX_WITH_NMI
285 /*
286 * Allocate mapping for the host APIC.
287 */
288 if (RT_SUCCESS(rc))
289 {
290 rc = MMR3HyperReserve(pVM, PAGE_SIZE, "Host APIC", &pVM->vmm.s.GCPtrApicBase);
291 AssertRC(rc);
292 }
293#endif
294 if (RT_SUCCESS(rc))
295 {
296 /*
297 * Debug info and statistics.
298 */
299 DBGFR3InfoRegisterInternal(pVM, "fflags", "Displays the current Forced actions Flags.", vmmR3InfoFF);
300 vmmR3InitRegisterStats(pVM);
301 vmmInitFormatTypes();
302
303 return VINF_SUCCESS;
304 }
305 }
306 /** @todo Need failure cleanup. */
307
308 //more todo in here?
309 //if (RT_SUCCESS(rc))
310 //{
311 //}
312 //int rc2 = vmmR3TermCoreCode(pVM);
313 //AssertRC(rc2));
314 }
315
316 return rc;
317}
318
319
320/**
321 * Allocate & setup the VMM RC stack(s) (for EMTs).
322 *
323 * The stacks are also used for long jumps in Ring-0.
324 *
325 * @returns VBox status code.
326 * @param pVM The cross context VM structure.
327 *
328 * @remarks The optional guard page gets it protection setup up during R3 init
329 * completion because of init order issues.
330 */
331static int vmmR3InitStacks(PVM pVM)
332{
333 int rc = VINF_SUCCESS;
334#ifdef VMM_R0_SWITCH_STACK
335 uint32_t fFlags = MMHYPER_AONR_FLAGS_KERNEL_MAPPING;
336#else
337 uint32_t fFlags = 0;
338#endif
339
340 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
341 {
342 PVMCPU pVCpu = &pVM->aCpus[idCpu];
343
344#ifdef VBOX_STRICT_VMM_STACK
345 rc = MMR3HyperAllocOnceNoRelEx(pVM, PAGE_SIZE + VMM_STACK_SIZE + PAGE_SIZE,
346#else
347 rc = MMR3HyperAllocOnceNoRelEx(pVM, VMM_STACK_SIZE,
348#endif
349 PAGE_SIZE, MM_TAG_VMM, fFlags, (void **)&pVCpu->vmm.s.pbEMTStackR3);
350 if (RT_SUCCESS(rc))
351 {
352#ifdef VBOX_STRICT_VMM_STACK
353 pVCpu->vmm.s.pbEMTStackR3 += PAGE_SIZE;
354#endif
355#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
356 /* MMHyperR3ToR0 returns R3 when not doing hardware assisted virtualization. */
357 if (!HMIsEnabled(pVM))
358 pVCpu->vmm.s.CallRing3JmpBufR0.pvSavedStack = NIL_RTR0PTR;
359 else
360#endif
361 pVCpu->vmm.s.CallRing3JmpBufR0.pvSavedStack = MMHyperR3ToR0(pVM, pVCpu->vmm.s.pbEMTStackR3);
362 pVCpu->vmm.s.pbEMTStackRC = MMHyperR3ToRC(pVM, pVCpu->vmm.s.pbEMTStackR3);
363 pVCpu->vmm.s.pbEMTStackBottomRC = pVCpu->vmm.s.pbEMTStackRC + VMM_STACK_SIZE;
364 AssertRelease(pVCpu->vmm.s.pbEMTStackRC);
365
366 CPUMSetHyperESP(pVCpu, pVCpu->vmm.s.pbEMTStackBottomRC);
367 }
368 }
369
370 return rc;
371}
372
373
374/**
375 * Initialize the loggers.
376 *
377 * @returns VBox status code.
378 * @param pVM The cross context VM structure.
379 */
380static int vmmR3InitLoggers(PVM pVM)
381{
382 int rc;
383#define RTLogCalcSizeForR0(cGroups, fFlags) (RT_OFFSETOF(VMMR0LOGGER, Logger.afGroups[cGroups]) + PAGE_SIZE)
384
385 /*
386 * Allocate RC & R0 Logger instances (they are finalized in the relocator).
387 */
388#ifdef LOG_ENABLED
389 PRTLOGGER pLogger = RTLogDefaultInstance();
390 if (pLogger)
391 {
392 if (!HMIsEnabled(pVM))
393 {
394 pVM->vmm.s.cbRCLogger = RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]);
395 rc = MMR3HyperAllocOnceNoRel(pVM, pVM->vmm.s.cbRCLogger, 0, MM_TAG_VMM, (void **)&pVM->vmm.s.pRCLoggerR3);
396 if (RT_FAILURE(rc))
397 return rc;
398 pVM->vmm.s.pRCLoggerRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pRCLoggerR3);
399 }
400
401# ifdef VBOX_WITH_R0_LOGGING
402 size_t const cbLogger = RTLogCalcSizeForR0(pLogger->cGroups, 0);
403 for (VMCPUID i = 0; i < pVM->cCpus; i++)
404 {
405 PVMCPU pVCpu = &pVM->aCpus[i];
406 rc = MMR3HyperAllocOnceNoRelEx(pVM, cbLogger, PAGE_SIZE, MM_TAG_VMM, MMHYPER_AONR_FLAGS_KERNEL_MAPPING,
407 (void **)&pVCpu->vmm.s.pR0LoggerR3);
408 if (RT_FAILURE(rc))
409 return rc;
410 pVCpu->vmm.s.pR0LoggerR3->pVM = pVM->pVMR0;
411 //pVCpu->vmm.s.pR0LoggerR3->fCreated = false;
412 pVCpu->vmm.s.pR0LoggerR3->cbLogger = (uint32_t)cbLogger;
413 pVCpu->vmm.s.pR0LoggerR0 = MMHyperR3ToR0(pVM, pVCpu->vmm.s.pR0LoggerR3);
414 }
415# endif
416 }
417#endif /* LOG_ENABLED */
418
419#ifdef VBOX_WITH_RC_RELEASE_LOGGING
420 /*
421 * Allocate RC release logger instances (finalized in the relocator).
422 */
423 if (!HMIsEnabled(pVM))
424 {
425 PRTLOGGER pRelLogger = RTLogRelGetDefaultInstance();
426 if (pRelLogger)
427 {
428 pVM->vmm.s.cbRCRelLogger = RT_OFFSETOF(RTLOGGERRC, afGroups[pRelLogger->cGroups]);
429 rc = MMR3HyperAllocOnceNoRel(pVM, pVM->vmm.s.cbRCRelLogger, 0, MM_TAG_VMM, (void **)&pVM->vmm.s.pRCRelLoggerR3);
430 if (RT_FAILURE(rc))
431 return rc;
432 pVM->vmm.s.pRCRelLoggerRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pRCRelLoggerR3);
433 }
434 }
435#endif /* VBOX_WITH_RC_RELEASE_LOGGING */
436 return VINF_SUCCESS;
437}
438
439
440/**
441 * VMMR3Init worker that register the statistics with STAM.
442 *
443 * @param pVM The cross context VM structure.
444 */
445static void vmmR3InitRegisterStats(PVM pVM)
446{
447 RT_NOREF_PV(pVM);
448
449 /*
450 * Statistics.
451 */
452 STAM_REG(pVM, &pVM->vmm.s.StatRunRC, STAMTYPE_COUNTER, "/VMM/RunRC", STAMUNIT_OCCURENCES, "Number of context switches.");
453 STAM_REG(pVM, &pVM->vmm.s.StatRZRetNormal, STAMTYPE_COUNTER, "/VMM/RZRet/Normal", STAMUNIT_OCCURENCES, "Number of VINF_SUCCESS returns.");
454 STAM_REG(pVM, &pVM->vmm.s.StatRZRetInterrupt, STAMTYPE_COUNTER, "/VMM/RZRet/Interrupt", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_INTERRUPT returns.");
455 STAM_REG(pVM, &pVM->vmm.s.StatRZRetInterruptHyper, STAMTYPE_COUNTER, "/VMM/RZRet/InterruptHyper", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_INTERRUPT_HYPER returns.");
456 STAM_REG(pVM, &pVM->vmm.s.StatRZRetGuestTrap, STAMTYPE_COUNTER, "/VMM/RZRet/GuestTrap", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_GUEST_TRAP returns.");
457 STAM_REG(pVM, &pVM->vmm.s.StatRZRetRingSwitch, STAMTYPE_COUNTER, "/VMM/RZRet/RingSwitch", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_RING_SWITCH returns.");
458 STAM_REG(pVM, &pVM->vmm.s.StatRZRetRingSwitchInt, STAMTYPE_COUNTER, "/VMM/RZRet/RingSwitchInt", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_RING_SWITCH_INT returns.");
459 STAM_REG(pVM, &pVM->vmm.s.StatRZRetStaleSelector, STAMTYPE_COUNTER, "/VMM/RZRet/StaleSelector", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_STALE_SELECTOR returns.");
460 STAM_REG(pVM, &pVM->vmm.s.StatRZRetIRETTrap, STAMTYPE_COUNTER, "/VMM/RZRet/IRETTrap", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_IRET_TRAP returns.");
461 STAM_REG(pVM, &pVM->vmm.s.StatRZRetEmulate, STAMTYPE_COUNTER, "/VMM/RZRet/Emulate", STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION returns.");
462 STAM_REG(pVM, &pVM->vmm.s.StatRZRetIOBlockEmulate, STAMTYPE_COUNTER, "/VMM/RZRet/EmulateIOBlock", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_EMULATE_IO_BLOCK returns.");
463 STAM_REG(pVM, &pVM->vmm.s.StatRZRetPatchEmulate, STAMTYPE_COUNTER, "/VMM/RZRet/PatchEmulate", STAMUNIT_OCCURENCES, "Number of VINF_PATCH_EMULATE_INSTR returns.");
464 STAM_REG(pVM, &pVM->vmm.s.StatRZRetIORead, STAMTYPE_COUNTER, "/VMM/RZRet/IORead", STAMUNIT_OCCURENCES, "Number of VINF_IOM_R3_IOPORT_READ returns.");
465 STAM_REG(pVM, &pVM->vmm.s.StatRZRetIOWrite, STAMTYPE_COUNTER, "/VMM/RZRet/IOWrite", STAMUNIT_OCCURENCES, "Number of VINF_IOM_R3_IOPORT_WRITE returns.");
466 STAM_REG(pVM, &pVM->vmm.s.StatRZRetIOCommitWrite, STAMTYPE_COUNTER, "/VMM/RZRet/IOCommitWrite", STAMUNIT_OCCURENCES, "Number of VINF_IOM_R3_IOPORT_COMMIT_WRITE returns.");
467 STAM_REG(pVM, &pVM->vmm.s.StatRZRetMMIORead, STAMTYPE_COUNTER, "/VMM/RZRet/MMIORead", STAMUNIT_OCCURENCES, "Number of VINF_IOM_R3_MMIO_READ returns.");
468 STAM_REG(pVM, &pVM->vmm.s.StatRZRetMMIOWrite, STAMTYPE_COUNTER, "/VMM/RZRet/MMIOWrite", STAMUNIT_OCCURENCES, "Number of VINF_IOM_R3_MMIO_WRITE returns.");
469 STAM_REG(pVM, &pVM->vmm.s.StatRZRetMMIOCommitWrite, STAMTYPE_COUNTER, "/VMM/RZRet/MMIOCommitWrite", STAMUNIT_OCCURENCES, "Number of VINF_IOM_R3_MMIO_COMMIT_WRITE returns.");
470 STAM_REG(pVM, &pVM->vmm.s.StatRZRetMMIOReadWrite, STAMTYPE_COUNTER, "/VMM/RZRet/MMIOReadWrite", STAMUNIT_OCCURENCES, "Number of VINF_IOM_R3_MMIO_READ_WRITE returns.");
471 STAM_REG(pVM, &pVM->vmm.s.StatRZRetMMIOPatchRead, STAMTYPE_COUNTER, "/VMM/RZRet/MMIOPatchRead", STAMUNIT_OCCURENCES, "Number of VINF_IOM_HC_MMIO_PATCH_READ returns.");
472 STAM_REG(pVM, &pVM->vmm.s.StatRZRetMMIOPatchWrite, STAMTYPE_COUNTER, "/VMM/RZRet/MMIOPatchWrite", STAMUNIT_OCCURENCES, "Number of VINF_IOM_HC_MMIO_PATCH_WRITE returns.");
473 STAM_REG(pVM, &pVM->vmm.s.StatRZRetMSRRead, STAMTYPE_COUNTER, "/VMM/RZRet/MSRRead", STAMUNIT_OCCURENCES, "Number of VINF_CPUM_R3_MSR_READ returns.");
474 STAM_REG(pVM, &pVM->vmm.s.StatRZRetMSRWrite, STAMTYPE_COUNTER, "/VMM/RZRet/MSRWrite", STAMUNIT_OCCURENCES, "Number of VINF_CPUM_R3_MSR_WRITE returns.");
475 STAM_REG(pVM, &pVM->vmm.s.StatRZRetLDTFault, STAMTYPE_COUNTER, "/VMM/RZRet/LDTFault", STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION_GDT_FAULT returns.");
476 STAM_REG(pVM, &pVM->vmm.s.StatRZRetGDTFault, STAMTYPE_COUNTER, "/VMM/RZRet/GDTFault", STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION_LDT_FAULT returns.");
477 STAM_REG(pVM, &pVM->vmm.s.StatRZRetIDTFault, STAMTYPE_COUNTER, "/VMM/RZRet/IDTFault", STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION_IDT_FAULT returns.");
478 STAM_REG(pVM, &pVM->vmm.s.StatRZRetTSSFault, STAMTYPE_COUNTER, "/VMM/RZRet/TSSFault", STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION_TSS_FAULT returns.");
479 STAM_REG(pVM, &pVM->vmm.s.StatRZRetCSAMTask, STAMTYPE_COUNTER, "/VMM/RZRet/CSAMTask", STAMUNIT_OCCURENCES, "Number of VINF_CSAM_PENDING_ACTION returns.");
480 STAM_REG(pVM, &pVM->vmm.s.StatRZRetSyncCR3, STAMTYPE_COUNTER, "/VMM/RZRet/SyncCR", STAMUNIT_OCCURENCES, "Number of VINF_PGM_SYNC_CR3 returns.");
481 STAM_REG(pVM, &pVM->vmm.s.StatRZRetMisc, STAMTYPE_COUNTER, "/VMM/RZRet/Misc", STAMUNIT_OCCURENCES, "Number of misc returns.");
482 STAM_REG(pVM, &pVM->vmm.s.StatRZRetPatchInt3, STAMTYPE_COUNTER, "/VMM/RZRet/PatchInt3", STAMUNIT_OCCURENCES, "Number of VINF_PATM_PATCH_INT3 returns.");
483 STAM_REG(pVM, &pVM->vmm.s.StatRZRetPatchPF, STAMTYPE_COUNTER, "/VMM/RZRet/PatchPF", STAMUNIT_OCCURENCES, "Number of VINF_PATM_PATCH_TRAP_PF returns.");
484 STAM_REG(pVM, &pVM->vmm.s.StatRZRetPatchGP, STAMTYPE_COUNTER, "/VMM/RZRet/PatchGP", STAMUNIT_OCCURENCES, "Number of VINF_PATM_PATCH_TRAP_GP returns.");
485 STAM_REG(pVM, &pVM->vmm.s.StatRZRetPatchIretIRQ, STAMTYPE_COUNTER, "/VMM/RZRet/PatchIret", STAMUNIT_OCCURENCES, "Number of VINF_PATM_PENDING_IRQ_AFTER_IRET returns.");
486 STAM_REG(pVM, &pVM->vmm.s.StatRZRetRescheduleREM, STAMTYPE_COUNTER, "/VMM/RZRet/ScheduleREM", STAMUNIT_OCCURENCES, "Number of VINF_EM_RESCHEDULE_REM returns.");
487 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3Total, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns.");
488 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3Unknown, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/Unknown", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns without responsible force flag.");
489 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3FF, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/ToR3", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns with VMCPU_FF_TO_R3.");
490 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3TMVirt, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/TMVirt", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns with VM_FF_TM_VIRTUAL_SYNC.");
491 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3HandyPages, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/Handy", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns with VM_FF_PGM_NEED_HANDY_PAGES.");
492 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3PDMQueues, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/PDMQueue", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns with VM_FF_PDM_QUEUES.");
493 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3Rendezvous, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/Rendezvous", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns with VM_FF_EMT_RENDEZVOUS.");
494 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3Timer, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/Timer", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns with VMCPU_FF_TIMER.");
495 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3DMA, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/DMA", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns with VM_FF_PDM_DMA.");
496 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3CritSect, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/CritSect", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns with VMCPU_FF_PDM_CRITSECT.");
497 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3Iem, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/IEM", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns with VMCPU_FF_IEM.");
498 STAM_REG(pVM, &pVM->vmm.s.StatRZRetToR3Iom, STAMTYPE_COUNTER, "/VMM/RZRet/ToR3/IOM", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns with VMCPU_FF_IOM.");
499 STAM_REG(pVM, &pVM->vmm.s.StatRZRetTimerPending, STAMTYPE_COUNTER, "/VMM/RZRet/TimerPending", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TIMER_PENDING returns.");
500 STAM_REG(pVM, &pVM->vmm.s.StatRZRetInterruptPending, STAMTYPE_COUNTER, "/VMM/RZRet/InterruptPending", STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_INTERRUPT_PENDING returns.");
501 STAM_REG(pVM, &pVM->vmm.s.StatRZRetPATMDuplicateFn, STAMTYPE_COUNTER, "/VMM/RZRet/PATMDuplicateFn", STAMUNIT_OCCURENCES, "Number of VINF_PATM_DUPLICATE_FUNCTION returns.");
502 STAM_REG(pVM, &pVM->vmm.s.StatRZRetPGMChangeMode, STAMTYPE_COUNTER, "/VMM/RZRet/PGMChangeMode", STAMUNIT_OCCURENCES, "Number of VINF_PGM_CHANGE_MODE returns.");
503 STAM_REG(pVM, &pVM->vmm.s.StatRZRetPGMFlushPending, STAMTYPE_COUNTER, "/VMM/RZRet/PGMFlushPending", STAMUNIT_OCCURENCES, "Number of VINF_PGM_POOL_FLUSH_PENDING returns.");
504 STAM_REG(pVM, &pVM->vmm.s.StatRZRetPendingRequest, STAMTYPE_COUNTER, "/VMM/RZRet/PendingRequest", STAMUNIT_OCCURENCES, "Number of VINF_EM_PENDING_REQUEST returns.");
505 STAM_REG(pVM, &pVM->vmm.s.StatRZRetPatchTPR, STAMTYPE_COUNTER, "/VMM/RZRet/PatchTPR", STAMUNIT_OCCURENCES, "Number of VINF_EM_HM_PATCH_TPR_INSTR returns.");
506 STAM_REG(pVM, &pVM->vmm.s.StatRZRetCallRing3, STAMTYPE_COUNTER, "/VMM/RZCallR3/Misc", STAMUNIT_OCCURENCES, "Number of Other ring-3 calls.");
507 STAM_REG(pVM, &pVM->vmm.s.StatRZCallPDMLock, STAMTYPE_COUNTER, "/VMM/RZCallR3/PDMLock", STAMUNIT_OCCURENCES, "Number of VMMCALLRING3_PDM_LOCK calls.");
508 STAM_REG(pVM, &pVM->vmm.s.StatRZCallPDMCritSectEnter, STAMTYPE_COUNTER, "/VMM/RZCallR3/PDMCritSectEnter", STAMUNIT_OCCURENCES, "Number of VMMCALLRING3_PDM_CRITSECT_ENTER calls.");
509 STAM_REG(pVM, &pVM->vmm.s.StatRZCallPGMLock, STAMTYPE_COUNTER, "/VMM/RZCallR3/PGMLock", STAMUNIT_OCCURENCES, "Number of VMMCALLRING3_PGM_LOCK calls.");
510 STAM_REG(pVM, &pVM->vmm.s.StatRZCallPGMPoolGrow, STAMTYPE_COUNTER, "/VMM/RZCallR3/PGMPoolGrow", STAMUNIT_OCCURENCES, "Number of VMMCALLRING3_PGM_POOL_GROW calls.");
511 STAM_REG(pVM, &pVM->vmm.s.StatRZCallPGMMapChunk, STAMTYPE_COUNTER, "/VMM/RZCallR3/PGMMapChunk", STAMUNIT_OCCURENCES, "Number of VMMCALLRING3_PGM_MAP_CHUNK calls.");
512 STAM_REG(pVM, &pVM->vmm.s.StatRZCallPGMAllocHandy, STAMTYPE_COUNTER, "/VMM/RZCallR3/PGMAllocHandy", STAMUNIT_OCCURENCES, "Number of VMMCALLRING3_PGM_ALLOCATE_HANDY_PAGES calls.");
513 STAM_REG(pVM, &pVM->vmm.s.StatRZCallRemReplay, STAMTYPE_COUNTER, "/VMM/RZCallR3/REMReplay", STAMUNIT_OCCURENCES, "Number of VMMCALLRING3_REM_REPLAY_HANDLER_NOTIFICATIONS calls.");
514 STAM_REG(pVM, &pVM->vmm.s.StatRZCallLogFlush, STAMTYPE_COUNTER, "/VMM/RZCallR3/VMMLogFlush", STAMUNIT_OCCURENCES, "Number of VMMCALLRING3_VMM_LOGGER_FLUSH calls.");
515 STAM_REG(pVM, &pVM->vmm.s.StatRZCallVMSetError, STAMTYPE_COUNTER, "/VMM/RZCallR3/VMSetError", STAMUNIT_OCCURENCES, "Number of VMMCALLRING3_VM_SET_ERROR calls.");
516 STAM_REG(pVM, &pVM->vmm.s.StatRZCallVMSetRuntimeError, STAMTYPE_COUNTER, "/VMM/RZCallR3/VMRuntimeError", STAMUNIT_OCCURENCES, "Number of VMMCALLRING3_VM_SET_RUNTIME_ERROR calls.");
517
518#ifdef VBOX_WITH_STATISTICS
519 for (VMCPUID i = 0; i < pVM->cCpus; i++)
520 {
521 STAMR3RegisterF(pVM, &pVM->aCpus[i].vmm.s.CallRing3JmpBufR0.cbUsedMax, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Max amount of stack used.", "/VMM/Stack/CPU%u/Max", i);
522 STAMR3RegisterF(pVM, &pVM->aCpus[i].vmm.s.CallRing3JmpBufR0.cbUsedAvg, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Average stack usage.", "/VMM/Stack/CPU%u/Avg", i);
523 STAMR3RegisterF(pVM, &pVM->aCpus[i].vmm.s.CallRing3JmpBufR0.cUsedTotal, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of stack usages.", "/VMM/Stack/CPU%u/Uses", i);
524 }
525#endif
526}
527
528
529/**
530 * Initializes the R0 VMM.
531 *
532 * @returns VBox status code.
533 * @param pVM The cross context VM structure.
534 */
535VMMR3_INT_DECL(int) VMMR3InitR0(PVM pVM)
536{
537 int rc;
538 PVMCPU pVCpu = VMMGetCpu(pVM);
539 Assert(pVCpu && pVCpu->idCpu == 0);
540
541#ifdef LOG_ENABLED
542 /*
543 * Initialize the ring-0 logger if we haven't done so yet.
544 */
545 if ( pVCpu->vmm.s.pR0LoggerR3
546 && !pVCpu->vmm.s.pR0LoggerR3->fCreated)
547 {
548 rc = VMMR3UpdateLoggers(pVM);
549 if (RT_FAILURE(rc))
550 return rc;
551 }
552#endif
553
554 /*
555 * Call Ring-0 entry with init code.
556 */
557 for (;;)
558 {
559#ifdef NO_SUPCALLR0VMM
560 //rc = VERR_GENERAL_FAILURE;
561 rc = VINF_SUCCESS;
562#else
563 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, 0 /*idCpu*/, VMMR0_DO_VMMR0_INIT,
564 RT_MAKE_U64(VMMGetSvnRev(), vmmGetBuildType()), NULL);
565#endif
566 /*
567 * Flush the logs.
568 */
569#ifdef LOG_ENABLED
570 if ( pVCpu->vmm.s.pR0LoggerR3
571 && pVCpu->vmm.s.pR0LoggerR3->Logger.offScratch > 0)
572 RTLogFlushR0(NULL, &pVCpu->vmm.s.pR0LoggerR3->Logger);
573#endif
574 if (rc != VINF_VMM_CALL_HOST)
575 break;
576 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
577 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
578 break;
579 /* Resume R0 */
580 }
581
582 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
583 {
584 LogRel(("VMM: R0 init failed, rc=%Rra\n", rc));
585 if (RT_SUCCESS(rc))
586 rc = VERR_IPE_UNEXPECTED_INFO_STATUS;
587 }
588
589 /* Log whether thread-context hooks are used (on Linux this can depend on how the kernel is configured). */
590 if (pVM->aCpus[0].vmm.s.hCtxHook != NIL_RTTHREADCTXHOOK)
591 LogRel(("VMM: Enabled thread-context hooks\n"));
592 else
593 LogRel(("VMM: Thread-context hooks unavailable\n"));
594
595 return rc;
596}
597
598
599#ifdef VBOX_WITH_RAW_MODE
600/**
601 * Initializes the RC VMM.
602 *
603 * @returns VBox status code.
604 * @param pVM The cross context VM structure.
605 */
606VMMR3_INT_DECL(int) VMMR3InitRC(PVM pVM)
607{
608 PVMCPU pVCpu = VMMGetCpu(pVM);
609 Assert(pVCpu && pVCpu->idCpu == 0);
610
611 /* In VMX mode, there's no need to init RC. */
612 if (HMIsEnabled(pVM))
613 return VINF_SUCCESS;
614
615 AssertReturn(pVM->cCpus == 1, VERR_RAW_MODE_INVALID_SMP);
616
617 /*
618 * Call VMMRCInit():
619 * -# resolve the address.
620 * -# setup stackframe and EIP to use the trampoline.
621 * -# do a generic hypervisor call.
622 */
623 RTRCPTR RCPtrEP;
624 int rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "VMMRCEntry", &RCPtrEP);
625 if (RT_SUCCESS(rc))
626 {
627 CPUMSetHyperESP(pVCpu, pVCpu->vmm.s.pbEMTStackBottomRC); /* Clear the stack. */
628 uint64_t u64TS = RTTimeProgramStartNanoTS();
629 CPUMPushHyper(pVCpu, RT_HI_U32(u64TS)); /* Param 4: The program startup TS - Hi. */
630 CPUMPushHyper(pVCpu, RT_LO_U32(u64TS)); /* Param 4: The program startup TS - Lo. */
631 CPUMPushHyper(pVCpu, vmmGetBuildType()); /* Param 3: Version argument. */
632 CPUMPushHyper(pVCpu, VMMGetSvnRev()); /* Param 2: Version argument. */
633 CPUMPushHyper(pVCpu, VMMRC_DO_VMMRC_INIT); /* Param 1: Operation. */
634 CPUMPushHyper(pVCpu, pVM->pVMRC); /* Param 0: pVM */
635 CPUMPushHyper(pVCpu, 6 * sizeof(RTRCPTR)); /* trampoline param: stacksize. */
636 CPUMPushHyper(pVCpu, RCPtrEP); /* Call EIP. */
637 CPUMSetHyperEIP(pVCpu, pVM->vmm.s.pfnCallTrampolineRC);
638 Assert(CPUMGetHyperCR3(pVCpu) && CPUMGetHyperCR3(pVCpu) == PGMGetHyperCR3(pVCpu));
639
640 for (;;)
641 {
642#ifdef NO_SUPCALLR0VMM
643 //rc = VERR_GENERAL_FAILURE;
644 rc = VINF_SUCCESS;
645#else
646 rc = SUPR3CallVMMR0(pVM->pVMR0, 0 /* VCPU 0 */, VMMR0_DO_CALL_HYPERVISOR, NULL);
647#endif
648#ifdef LOG_ENABLED
649 PRTLOGGERRC pLogger = pVM->vmm.s.pRCLoggerR3;
650 if ( pLogger
651 && pLogger->offScratch > 0)
652 RTLogFlushRC(NULL, pLogger);
653#endif
654#ifdef VBOX_WITH_RC_RELEASE_LOGGING
655 PRTLOGGERRC pRelLogger = pVM->vmm.s.pRCRelLoggerR3;
656 if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
657 RTLogFlushRC(RTLogRelGetDefaultInstance(), pRelLogger);
658#endif
659 if (rc != VINF_VMM_CALL_HOST)
660 break;
661 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
662 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
663 break;
664 }
665
666 /* Don't trigger assertions or guru if raw-mode is unavailable. */
667 if (rc != VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT)
668 {
669 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
670 {
671 VMMR3FatalDump(pVM, pVCpu, rc);
672 if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
673 rc = VERR_IPE_UNEXPECTED_INFO_STATUS;
674 }
675 AssertRC(rc);
676 }
677 }
678 return rc;
679}
680#endif /* VBOX_WITH_RAW_MODE */
681
682
683/**
684 * Called when an init phase completes.
685 *
686 * @returns VBox status code.
687 * @param pVM The cross context VM structure.
688 * @param enmWhat Which init phase.
689 */
690VMMR3_INT_DECL(int) VMMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
691{
692 int rc = VINF_SUCCESS;
693
694 switch (enmWhat)
695 {
696 case VMINITCOMPLETED_RING3:
697 {
698 /*
699 * Set page attributes to r/w for stack pages.
700 */
701 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
702 {
703 rc = PGMMapSetPage(pVM, pVM->aCpus[idCpu].vmm.s.pbEMTStackRC, VMM_STACK_SIZE,
704 X86_PTE_P | X86_PTE_A | X86_PTE_D | X86_PTE_RW);
705 AssertRCReturn(rc, rc);
706 }
707
708 /*
709 * Create the EMT yield timer.
710 */
711 rc = TMR3TimerCreateInternal(pVM, TMCLOCK_REAL, vmmR3YieldEMT, NULL, "EMT Yielder", &pVM->vmm.s.pYieldTimer);
712 AssertRCReturn(rc, rc);
713
714 rc = TMTimerSetMillies(pVM->vmm.s.pYieldTimer, pVM->vmm.s.cYieldEveryMillies);
715 AssertRCReturn(rc, rc);
716
717#ifdef VBOX_WITH_NMI
718 /*
719 * Map the host APIC into GC - This is AMD/Intel + Host OS specific!
720 */
721 rc = PGMMap(pVM, pVM->vmm.s.GCPtrApicBase, 0xfee00000, PAGE_SIZE,
722 X86_PTE_P | X86_PTE_RW | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_A | X86_PTE_D);
723 AssertRCReturn(rc, rc);
724#endif
725
726#ifdef VBOX_STRICT_VMM_STACK
727 /*
728 * Setup the stack guard pages: Two inaccessible pages at each sides of the
729 * stack to catch over/under-flows.
730 */
731 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
732 {
733 uint8_t *pbEMTStackR3 = pVM->aCpus[idCpu].vmm.s.pbEMTStackR3;
734
735 memset(pbEMTStackR3 - PAGE_SIZE, 0xcc, PAGE_SIZE);
736 MMR3HyperSetGuard(pVM, pbEMTStackR3 - PAGE_SIZE, PAGE_SIZE, true /*fSet*/);
737
738 memset(pbEMTStackR3 + VMM_STACK_SIZE, 0xcc, PAGE_SIZE);
739 MMR3HyperSetGuard(pVM, pbEMTStackR3 + VMM_STACK_SIZE, PAGE_SIZE, true /*fSet*/);
740 }
741 pVM->vmm.s.fStackGuardsStationed = true;
742#endif
743 break;
744 }
745
746 case VMINITCOMPLETED_HM:
747 {
748 /*
749 * Disable the periodic preemption timers if we can use the
750 * VMX-preemption timer instead.
751 */
752 if ( pVM->vmm.s.fUsePeriodicPreemptionTimers
753 && HMR3IsVmxPreemptionTimerUsed(pVM))
754 pVM->vmm.s.fUsePeriodicPreemptionTimers = false;
755 LogRel(("VMM: fUsePeriodicPreemptionTimers=%RTbool\n", pVM->vmm.s.fUsePeriodicPreemptionTimers));
756
757 /*
758 * Last chance for GIM to update its CPUID leaves if it requires
759 * knowledge/information from HM initialization.
760 */
761 rc = GIMR3InitCompleted(pVM);
762 AssertRCReturn(rc, rc);
763
764 /*
765 * CPUM's post-initialization (print CPUIDs).
766 */
767 CPUMR3LogCpuIds(pVM);
768 break;
769 }
770
771 default: /* shuts up gcc */
772 break;
773 }
774
775 return rc;
776}
777
778
779/**
780 * Terminate the VMM bits.
781 *
782 * @returns VBox status code.
783 * @param pVM The cross context VM structure.
784 */
785VMMR3_INT_DECL(int) VMMR3Term(PVM pVM)
786{
787 PVMCPU pVCpu = VMMGetCpu(pVM);
788 Assert(pVCpu && pVCpu->idCpu == 0);
789
790 /*
791 * Call Ring-0 entry with termination code.
792 */
793 int rc;
794 for (;;)
795 {
796#ifdef NO_SUPCALLR0VMM
797 //rc = VERR_GENERAL_FAILURE;
798 rc = VINF_SUCCESS;
799#else
800 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, 0 /*idCpu*/, VMMR0_DO_VMMR0_TERM, 0, NULL);
801#endif
802 /*
803 * Flush the logs.
804 */
805#ifdef LOG_ENABLED
806 if ( pVCpu->vmm.s.pR0LoggerR3
807 && pVCpu->vmm.s.pR0LoggerR3->Logger.offScratch > 0)
808 RTLogFlushR0(NULL, &pVCpu->vmm.s.pR0LoggerR3->Logger);
809#endif
810 if (rc != VINF_VMM_CALL_HOST)
811 break;
812 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
813 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
814 break;
815 /* Resume R0 */
816 }
817 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
818 {
819 LogRel(("VMM: VMMR3Term: R0 term failed, rc=%Rra. (warning)\n", rc));
820 if (RT_SUCCESS(rc))
821 rc = VERR_IPE_UNEXPECTED_INFO_STATUS;
822 }
823
824 for (VMCPUID i = 0; i < pVM->cCpus; i++)
825 {
826 RTSemEventDestroy(pVM->vmm.s.pahEvtRendezvousEnterOrdered[i]);
827 pVM->vmm.s.pahEvtRendezvousEnterOrdered[i] = NIL_RTSEMEVENT;
828 }
829 RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousEnterOneByOne);
830 pVM->vmm.s.hEvtRendezvousEnterOneByOne = NIL_RTSEMEVENT;
831 RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);
832 pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce = NIL_RTSEMEVENTMULTI;
833 RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousDone);
834 pVM->vmm.s.hEvtMulRendezvousDone = NIL_RTSEMEVENTMULTI;
835 RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousDoneCaller);
836 pVM->vmm.s.hEvtRendezvousDoneCaller = NIL_RTSEMEVENT;
837 RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousRecursionPush);
838 pVM->vmm.s.hEvtMulRendezvousRecursionPush = NIL_RTSEMEVENTMULTI;
839 RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousRecursionPop);
840 pVM->vmm.s.hEvtMulRendezvousRecursionPop = NIL_RTSEMEVENTMULTI;
841 RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
842 pVM->vmm.s.hEvtRendezvousRecursionPushCaller = NIL_RTSEMEVENT;
843 RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
844 pVM->vmm.s.hEvtRendezvousRecursionPopCaller = NIL_RTSEMEVENT;
845
846#ifdef VBOX_STRICT_VMM_STACK
847 /*
848 * Make the two stack guard pages present again.
849 */
850 if (pVM->vmm.s.fStackGuardsStationed)
851 {
852 for (VMCPUID i = 0; i < pVM->cCpus; i++)
853 {
854 uint8_t *pbEMTStackR3 = pVM->aCpus[i].vmm.s.pbEMTStackR3;
855 MMR3HyperSetGuard(pVM, pbEMTStackR3 - PAGE_SIZE, PAGE_SIZE, false /*fSet*/);
856 MMR3HyperSetGuard(pVM, pbEMTStackR3 + VMM_STACK_SIZE, PAGE_SIZE, false /*fSet*/);
857 }
858 pVM->vmm.s.fStackGuardsStationed = false;
859 }
860#endif
861
862 vmmTermFormatTypes();
863 return rc;
864}
865
866
867/**
868 * Applies relocations to data and code managed by this
869 * component. This function will be called at init and
870 * whenever the VMM need to relocate it self inside the GC.
871 *
872 * The VMM will need to apply relocations to the core code.
873 *
874 * @param pVM The cross context VM structure.
875 * @param offDelta The relocation delta.
876 */
877VMMR3_INT_DECL(void) VMMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
878{
879 LogFlow(("VMMR3Relocate: offDelta=%RGv\n", offDelta));
880
881 /*
882 * Recalc the RC address.
883 */
884#ifdef VBOX_WITH_RAW_MODE
885 pVM->vmm.s.pvCoreCodeRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pvCoreCodeR3);
886#endif
887
888 /*
889 * The stack.
890 */
891 for (VMCPUID i = 0; i < pVM->cCpus; i++)
892 {
893 PVMCPU pVCpu = &pVM->aCpus[i];
894
895 CPUMSetHyperESP(pVCpu, CPUMGetHyperESP(pVCpu) + offDelta);
896
897 pVCpu->vmm.s.pbEMTStackRC = MMHyperR3ToRC(pVM, pVCpu->vmm.s.pbEMTStackR3);
898 pVCpu->vmm.s.pbEMTStackBottomRC = pVCpu->vmm.s.pbEMTStackRC + VMM_STACK_SIZE;
899 }
900
901 /*
902 * All the switchers.
903 */
904 vmmR3SwitcherRelocate(pVM, offDelta);
905
906 /*
907 * Get other RC entry points.
908 */
909 if (!HMIsEnabled(pVM))
910 {
911 int rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "CPUMGCResumeGuest", &pVM->vmm.s.pfnCPUMRCResumeGuest);
912 AssertReleaseMsgRC(rc, ("CPUMGCResumeGuest not found! rc=%Rra\n", rc));
913
914 rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "CPUMGCResumeGuestV86", &pVM->vmm.s.pfnCPUMRCResumeGuestV86);
915 AssertReleaseMsgRC(rc, ("CPUMGCResumeGuestV86 not found! rc=%Rra\n", rc));
916 }
917
918 /*
919 * Update the logger.
920 */
921 VMMR3UpdateLoggers(pVM);
922}
923
924
925/**
926 * Updates the settings for the RC and R0 loggers.
927 *
928 * @returns VBox status code.
929 * @param pVM The cross context VM structure.
930 */
931VMMR3_INT_DECL(int) VMMR3UpdateLoggers(PVM pVM)
932{
933 /*
934 * Simply clone the logger instance (for RC).
935 */
936 int rc = VINF_SUCCESS;
937 RTRCPTR RCPtrLoggerFlush = 0;
938
939 if ( pVM->vmm.s.pRCLoggerR3
940#ifdef VBOX_WITH_RC_RELEASE_LOGGING
941 || pVM->vmm.s.pRCRelLoggerR3
942#endif
943 )
944 {
945 Assert(!HMIsEnabled(pVM));
946 rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "vmmGCLoggerFlush", &RCPtrLoggerFlush);
947 AssertReleaseMsgRC(rc, ("vmmGCLoggerFlush not found! rc=%Rra\n", rc));
948 }
949
950 if (pVM->vmm.s.pRCLoggerR3)
951 {
952 Assert(!HMIsEnabled(pVM));
953 RTRCPTR RCPtrLoggerWrapper = 0;
954 rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "vmmGCLoggerWrapper", &RCPtrLoggerWrapper);
955 AssertReleaseMsgRC(rc, ("vmmGCLoggerWrapper not found! rc=%Rra\n", rc));
956
957 pVM->vmm.s.pRCLoggerRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pRCLoggerR3);
958 rc = RTLogCloneRC(NULL /* default */, pVM->vmm.s.pRCLoggerR3, pVM->vmm.s.cbRCLogger,
959 RCPtrLoggerWrapper, RCPtrLoggerFlush, RTLOGFLAGS_BUFFERED);
960 AssertReleaseMsgRC(rc, ("RTLogCloneRC failed! rc=%Rra\n", rc));
961 }
962
963#ifdef VBOX_WITH_RC_RELEASE_LOGGING
964 if (pVM->vmm.s.pRCRelLoggerR3)
965 {
966 Assert(!HMIsEnabled(pVM));
967 RTRCPTR RCPtrLoggerWrapper = 0;
968 rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "vmmGCRelLoggerWrapper", &RCPtrLoggerWrapper);
969 AssertReleaseMsgRC(rc, ("vmmGCRelLoggerWrapper not found! rc=%Rra\n", rc));
970
971 pVM->vmm.s.pRCRelLoggerRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pRCRelLoggerR3);
972 rc = RTLogCloneRC(RTLogRelGetDefaultInstance(), pVM->vmm.s.pRCRelLoggerR3, pVM->vmm.s.cbRCRelLogger,
973 RCPtrLoggerWrapper, RCPtrLoggerFlush, RTLOGFLAGS_BUFFERED);
974 AssertReleaseMsgRC(rc, ("RTLogCloneRC failed! rc=%Rra\n", rc));
975 }
976#endif /* VBOX_WITH_RC_RELEASE_LOGGING */
977
978#ifdef LOG_ENABLED
979 /*
980 * For the ring-0 EMT logger, we use a per-thread logger instance
981 * in ring-0. Only initialize it once.
982 */
983 PRTLOGGER const pDefault = RTLogDefaultInstance();
984 for (VMCPUID i = 0; i < pVM->cCpus; i++)
985 {
986 PVMCPU pVCpu = &pVM->aCpus[i];
987 PVMMR0LOGGER pR0LoggerR3 = pVCpu->vmm.s.pR0LoggerR3;
988 if (pR0LoggerR3)
989 {
990 if (!pR0LoggerR3->fCreated)
991 {
992 RTR0PTR pfnLoggerWrapper = NIL_RTR0PTR;
993 rc = PDMR3LdrGetSymbolR0(pVM, VMMR0_MAIN_MODULE_NAME, "vmmR0LoggerWrapper", &pfnLoggerWrapper);
994 AssertReleaseMsgRCReturn(rc, ("vmmR0LoggerWrapper not found! rc=%Rra\n", rc), rc);
995
996 RTR0PTR pfnLoggerFlush = NIL_RTR0PTR;
997 rc = PDMR3LdrGetSymbolR0(pVM, VMMR0_MAIN_MODULE_NAME, "vmmR0LoggerFlush", &pfnLoggerFlush);
998 AssertReleaseMsgRCReturn(rc, ("vmmR0LoggerFlush not found! rc=%Rra\n", rc), rc);
999
1000 rc = RTLogCreateForR0(&pR0LoggerR3->Logger, pR0LoggerR3->cbLogger,
1001 pVCpu->vmm.s.pR0LoggerR0 + RT_OFFSETOF(VMMR0LOGGER, Logger),
1002 pfnLoggerWrapper, pfnLoggerFlush,
1003 RTLOGFLAGS_BUFFERED, RTLOGDEST_DUMMY);
1004 AssertReleaseMsgRCReturn(rc, ("RTLogCreateForR0 failed! rc=%Rra\n", rc), rc);
1005
1006 RTR0PTR pfnLoggerPrefix = NIL_RTR0PTR;
1007 rc = PDMR3LdrGetSymbolR0(pVM, VMMR0_MAIN_MODULE_NAME, "vmmR0LoggerPrefix", &pfnLoggerPrefix);
1008 AssertReleaseMsgRCReturn(rc, ("vmmR0LoggerPrefix not found! rc=%Rra\n", rc), rc);
1009 rc = RTLogSetCustomPrefixCallbackForR0(&pR0LoggerR3->Logger,
1010 pVCpu->vmm.s.pR0LoggerR0 + RT_OFFSETOF(VMMR0LOGGER, Logger),
1011 pfnLoggerPrefix, NIL_RTR0PTR);
1012 AssertReleaseMsgRCReturn(rc, ("RTLogSetCustomPrefixCallback failed! rc=%Rra\n", rc), rc);
1013
1014 pR0LoggerR3->idCpu = i;
1015 pR0LoggerR3->fCreated = true;
1016 pR0LoggerR3->fFlushingDisabled = false;
1017
1018 }
1019
1020 rc = RTLogCopyGroupsAndFlagsForR0(&pR0LoggerR3->Logger, pVCpu->vmm.s.pR0LoggerR0 + RT_OFFSETOF(VMMR0LOGGER, Logger),
1021 pDefault, RTLOGFLAGS_BUFFERED, UINT32_MAX);
1022 AssertRC(rc);
1023 }
1024 }
1025#endif
1026 return rc;
1027}
1028
1029
1030/**
1031 * Gets the pointer to a buffer containing the R0/RC RTAssertMsg1Weak output.
1032 *
1033 * @returns Pointer to the buffer.
1034 * @param pVM The cross context VM structure.
1035 */
1036VMMR3DECL(const char *) VMMR3GetRZAssertMsg1(PVM pVM)
1037{
1038 if (HMIsEnabled(pVM))
1039 return pVM->vmm.s.szRing0AssertMsg1;
1040
1041 RTRCPTR RCPtr;
1042 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_szRTAssertMsg1", &RCPtr);
1043 if (RT_SUCCESS(rc))
1044 return (const char *)MMHyperRCToR3(pVM, RCPtr);
1045
1046 return NULL;
1047}
1048
1049
1050/**
1051 * Returns the VMCPU of the specified virtual CPU.
1052 *
1053 * @returns The VMCPU pointer. NULL if @a idCpu or @a pUVM is invalid.
1054 *
1055 * @param pUVM The user mode VM handle.
1056 * @param idCpu The ID of the virtual CPU.
1057 */
1058VMMR3DECL(PVMCPU) VMMR3GetCpuByIdU(PUVM pUVM, RTCPUID idCpu)
1059{
1060 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
1061 AssertReturn(idCpu < pUVM->cCpus, NULL);
1062 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
1063 return &pUVM->pVM->aCpus[idCpu];
1064}
1065
1066
1067/**
1068 * Gets the pointer to a buffer containing the R0/RC RTAssertMsg2Weak output.
1069 *
1070 * @returns Pointer to the buffer.
1071 * @param pVM The cross context VM structure.
1072 */
1073VMMR3DECL(const char *) VMMR3GetRZAssertMsg2(PVM pVM)
1074{
1075 if (HMIsEnabled(pVM))
1076 return pVM->vmm.s.szRing0AssertMsg2;
1077
1078 RTRCPTR RCPtr;
1079 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_szRTAssertMsg2", &RCPtr);
1080 if (RT_SUCCESS(rc))
1081 return (const char *)MMHyperRCToR3(pVM, RCPtr);
1082
1083 return NULL;
1084}
1085
1086
1087/**
1088 * Execute state save operation.
1089 *
1090 * @returns VBox status code.
1091 * @param pVM The cross context VM structure.
1092 * @param pSSM SSM operation handle.
1093 */
1094static DECLCALLBACK(int) vmmR3Save(PVM pVM, PSSMHANDLE pSSM)
1095{
1096 LogFlow(("vmmR3Save:\n"));
1097
1098 /*
1099 * Save the started/stopped state of all CPUs except 0 as it will always
1100 * be running. This avoids breaking the saved state version. :-)
1101 */
1102 for (VMCPUID i = 1; i < pVM->cCpus; i++)
1103 SSMR3PutBool(pSSM, VMCPUSTATE_IS_STARTED(VMCPU_GET_STATE(&pVM->aCpus[i])));
1104
1105 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
1106}
1107
1108
1109/**
1110 * Execute state load operation.
1111 *
1112 * @returns VBox status code.
1113 * @param pVM The cross context VM structure.
1114 * @param pSSM SSM operation handle.
1115 * @param uVersion Data layout version.
1116 * @param uPass The data pass.
1117 */
1118static DECLCALLBACK(int) vmmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1119{
1120 LogFlow(("vmmR3Load:\n"));
1121 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1122
1123 /*
1124 * Validate version.
1125 */
1126 if ( uVersion != VMM_SAVED_STATE_VERSION
1127 && uVersion != VMM_SAVED_STATE_VERSION_3_0)
1128 {
1129 AssertMsgFailed(("vmmR3Load: Invalid version uVersion=%u!\n", uVersion));
1130 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1131 }
1132
1133 if (uVersion <= VMM_SAVED_STATE_VERSION_3_0)
1134 {
1135 /* Ignore the stack bottom, stack pointer and stack bits. */
1136 RTRCPTR RCPtrIgnored;
1137 SSMR3GetRCPtr(pSSM, &RCPtrIgnored);
1138 SSMR3GetRCPtr(pSSM, &RCPtrIgnored);
1139#ifdef RT_OS_DARWIN
1140 if ( SSMR3HandleVersion(pSSM) >= VBOX_FULL_VERSION_MAKE(3,0,0)
1141 && SSMR3HandleVersion(pSSM) < VBOX_FULL_VERSION_MAKE(3,1,0)
1142 && SSMR3HandleRevision(pSSM) >= 48858
1143 && ( !strcmp(SSMR3HandleHostOSAndArch(pSSM), "darwin.x86")
1144 || !strcmp(SSMR3HandleHostOSAndArch(pSSM), "") )
1145 )
1146 SSMR3Skip(pSSM, 16384);
1147 else
1148 SSMR3Skip(pSSM, 8192);
1149#else
1150 SSMR3Skip(pSSM, 8192);
1151#endif
1152 }
1153
1154 /*
1155 * Restore the VMCPU states. VCPU 0 is always started.
1156 */
1157 VMCPU_SET_STATE(&pVM->aCpus[0], VMCPUSTATE_STARTED);
1158 for (VMCPUID i = 1; i < pVM->cCpus; i++)
1159 {
1160 bool fStarted;
1161 int rc = SSMR3GetBool(pSSM, &fStarted);
1162 if (RT_FAILURE(rc))
1163 return rc;
1164 VMCPU_SET_STATE(&pVM->aCpus[i], fStarted ? VMCPUSTATE_STARTED : VMCPUSTATE_STOPPED);
1165 }
1166
1167 /* terminator */
1168 uint32_t u32;
1169 int rc = SSMR3GetU32(pSSM, &u32);
1170 if (RT_FAILURE(rc))
1171 return rc;
1172 if (u32 != UINT32_MAX)
1173 {
1174 AssertMsgFailed(("u32=%#x\n", u32));
1175 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1176 }
1177 return VINF_SUCCESS;
1178}
1179
1180
1181#ifdef VBOX_WITH_RAW_MODE
1182/**
1183 * Resolve a builtin RC symbol.
1184 *
1185 * Called by PDM when loading or relocating RC modules.
1186 *
1187 * @returns VBox status
1188 * @param pVM The cross context VM structure.
1189 * @param pszSymbol Symbol to resolve.
1190 * @param pRCPtrValue Where to store the symbol value.
1191 *
1192 * @remark This has to work before VMMR3Relocate() is called.
1193 */
1194VMMR3_INT_DECL(int) VMMR3GetImportRC(PVM pVM, const char *pszSymbol, PRTRCPTR pRCPtrValue)
1195{
1196 if (!strcmp(pszSymbol, "g_Logger"))
1197 {
1198 if (pVM->vmm.s.pRCLoggerR3)
1199 pVM->vmm.s.pRCLoggerRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pRCLoggerR3);
1200 *pRCPtrValue = pVM->vmm.s.pRCLoggerRC;
1201 }
1202 else if (!strcmp(pszSymbol, "g_RelLogger"))
1203 {
1204# ifdef VBOX_WITH_RC_RELEASE_LOGGING
1205 if (pVM->vmm.s.pRCRelLoggerR3)
1206 pVM->vmm.s.pRCRelLoggerRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pRCRelLoggerR3);
1207 *pRCPtrValue = pVM->vmm.s.pRCRelLoggerRC;
1208# else
1209 *pRCPtrValue = NIL_RTRCPTR;
1210# endif
1211 }
1212 else
1213 return VERR_SYMBOL_NOT_FOUND;
1214 return VINF_SUCCESS;
1215}
1216#endif /* VBOX_WITH_RAW_MODE */
1217
1218
1219/**
1220 * Suspends the CPU yielder.
1221 *
1222 * @param pVM The cross context VM structure.
1223 */
1224VMMR3_INT_DECL(void) VMMR3YieldSuspend(PVM pVM)
1225{
1226 VMCPU_ASSERT_EMT(&pVM->aCpus[0]);
1227 if (!pVM->vmm.s.cYieldResumeMillies)
1228 {
1229 uint64_t u64Now = TMTimerGet(pVM->vmm.s.pYieldTimer);
1230 uint64_t u64Expire = TMTimerGetExpire(pVM->vmm.s.pYieldTimer);
1231 if (u64Now >= u64Expire || u64Expire == ~(uint64_t)0)
1232 pVM->vmm.s.cYieldResumeMillies = pVM->vmm.s.cYieldEveryMillies;
1233 else
1234 pVM->vmm.s.cYieldResumeMillies = TMTimerToMilli(pVM->vmm.s.pYieldTimer, u64Expire - u64Now);
1235 TMTimerStop(pVM->vmm.s.pYieldTimer);
1236 }
1237 pVM->vmm.s.u64LastYield = RTTimeNanoTS();
1238}
1239
1240
1241/**
1242 * Stops the CPU yielder.
1243 *
1244 * @param pVM The cross context VM structure.
1245 */
1246VMMR3_INT_DECL(void) VMMR3YieldStop(PVM pVM)
1247{
1248 if (!pVM->vmm.s.cYieldResumeMillies)
1249 TMTimerStop(pVM->vmm.s.pYieldTimer);
1250 pVM->vmm.s.cYieldResumeMillies = pVM->vmm.s.cYieldEveryMillies;
1251 pVM->vmm.s.u64LastYield = RTTimeNanoTS();
1252}
1253
1254
1255/**
1256 * Resumes the CPU yielder when it has been a suspended or stopped.
1257 *
1258 * @param pVM The cross context VM structure.
1259 */
1260VMMR3_INT_DECL(void) VMMR3YieldResume(PVM pVM)
1261{
1262 if (pVM->vmm.s.cYieldResumeMillies)
1263 {
1264 TMTimerSetMillies(pVM->vmm.s.pYieldTimer, pVM->vmm.s.cYieldResumeMillies);
1265 pVM->vmm.s.cYieldResumeMillies = 0;
1266 }
1267}
1268
1269
1270/**
1271 * Internal timer callback function.
1272 *
1273 * @param pVM The cross context VM structure.
1274 * @param pTimer The timer handle.
1275 * @param pvUser User argument specified upon timer creation.
1276 */
1277static DECLCALLBACK(void) vmmR3YieldEMT(PVM pVM, PTMTIMER pTimer, void *pvUser)
1278{
1279 NOREF(pvUser);
1280
1281 /*
1282 * This really needs some careful tuning. While we shouldn't be too greedy since
1283 * that'll cause the rest of the system to stop up, we shouldn't be too nice either
1284 * because that'll cause us to stop up.
1285 *
1286 * The current logic is to use the default interval when there is no lag worth
1287 * mentioning, but when we start accumulating lag we don't bother yielding at all.
1288 *
1289 * (This depends on the TMCLOCK_VIRTUAL_SYNC to be scheduled before TMCLOCK_REAL
1290 * so the lag is up to date.)
1291 */
1292 const uint64_t u64Lag = TMVirtualSyncGetLag(pVM);
1293 if ( u64Lag < 50000000 /* 50ms */
1294 || ( u64Lag < 1000000000 /* 1s */
1295 && RTTimeNanoTS() - pVM->vmm.s.u64LastYield < 500000000 /* 500 ms */)
1296 )
1297 {
1298 uint64_t u64Elapsed = RTTimeNanoTS();
1299 pVM->vmm.s.u64LastYield = u64Elapsed;
1300
1301 RTThreadYield();
1302
1303#ifdef LOG_ENABLED
1304 u64Elapsed = RTTimeNanoTS() - u64Elapsed;
1305 Log(("vmmR3YieldEMT: %RI64 ns\n", u64Elapsed));
1306#endif
1307 }
1308 TMTimerSetMillies(pTimer, pVM->vmm.s.cYieldEveryMillies);
1309}
1310
1311
1312#ifdef VBOX_WITH_RAW_MODE
1313/**
1314 * Executes guest code in the raw-mode context.
1315 *
1316 * @param pVM The cross context VM structure.
1317 * @param pVCpu The cross context virtual CPU structure.
1318 */
1319VMMR3_INT_DECL(int) VMMR3RawRunGC(PVM pVM, PVMCPU pVCpu)
1320{
1321 Log2(("VMMR3RawRunGC: (cs:eip=%04x:%08x)\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
1322
1323 AssertReturn(pVM->cCpus == 1, VERR_RAW_MODE_INVALID_SMP);
1324
1325 /*
1326 * Set the hypervisor to resume executing a CPUM resume function
1327 * in CPUMRCA.asm.
1328 */
1329 CPUMSetHyperState(pVCpu,
1330 CPUMGetGuestEFlags(pVCpu) & X86_EFL_VM
1331 ? pVM->vmm.s.pfnCPUMRCResumeGuestV86
1332 : pVM->vmm.s.pfnCPUMRCResumeGuest, /* eip */
1333 pVCpu->vmm.s.pbEMTStackBottomRC, /* esp */
1334 0, /* eax */
1335 VM_RC_ADDR(pVM, &pVCpu->cpum) /* edx */);
1336
1337 /*
1338 * We hide log flushes (outer) and hypervisor interrupts (inner).
1339 */
1340 for (;;)
1341 {
1342#ifdef VBOX_STRICT
1343 if (RT_UNLIKELY(!CPUMGetHyperCR3(pVCpu) || CPUMGetHyperCR3(pVCpu) != PGMGetHyperCR3(pVCpu)))
1344 EMR3FatalError(pVCpu, VERR_VMM_HYPER_CR3_MISMATCH);
1345 PGMMapCheck(pVM);
1346# ifdef VBOX_WITH_SAFE_STR
1347 SELMR3CheckShadowTR(pVM);
1348# endif
1349#endif
1350 int rc;
1351 do
1352 {
1353#ifdef NO_SUPCALLR0VMM
1354 rc = VERR_GENERAL_FAILURE;
1355#else
1356 rc = SUPR3CallVMMR0Fast(pVM->pVMR0, VMMR0_DO_RAW_RUN, 0);
1357 if (RT_LIKELY(rc == VINF_SUCCESS))
1358 rc = pVCpu->vmm.s.iLastGZRc;
1359#endif
1360 } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
1361
1362 /*
1363 * Flush the logs.
1364 */
1365#ifdef LOG_ENABLED
1366 PRTLOGGERRC pLogger = pVM->vmm.s.pRCLoggerR3;
1367 if ( pLogger
1368 && pLogger->offScratch > 0)
1369 RTLogFlushRC(NULL, pLogger);
1370#endif
1371#ifdef VBOX_WITH_RC_RELEASE_LOGGING
1372 PRTLOGGERRC pRelLogger = pVM->vmm.s.pRCRelLoggerR3;
1373 if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
1374 RTLogFlushRC(RTLogRelGetDefaultInstance(), pRelLogger);
1375#endif
1376 if (rc != VINF_VMM_CALL_HOST)
1377 {
1378 Log2(("VMMR3RawRunGC: returns %Rrc (cs:eip=%04x:%08x)\n", rc, CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
1379 return rc;
1380 }
1381 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
1382 if (RT_FAILURE(rc))
1383 return rc;
1384 /* Resume GC */
1385 }
1386}
1387#endif /* VBOX_WITH_RAW_MODE */
1388
1389
1390/**
1391 * Executes guest code (Intel VT-x and AMD-V).
1392 *
1393 * @param pVM The cross context VM structure.
1394 * @param pVCpu The cross context virtual CPU structure.
1395 */
1396VMMR3_INT_DECL(int) VMMR3HmRunGC(PVM pVM, PVMCPU pVCpu)
1397{
1398 Log2(("VMMR3HmRunGC: (cs:rip=%04x:%RX64)\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu)));
1399
1400 for (;;)
1401 {
1402 int rc;
1403 do
1404 {
1405#ifdef NO_SUPCALLR0VMM
1406 rc = VERR_GENERAL_FAILURE;
1407#else
1408 rc = SUPR3CallVMMR0Fast(pVM->pVMR0, VMMR0_DO_HM_RUN, pVCpu->idCpu);
1409 if (RT_LIKELY(rc == VINF_SUCCESS))
1410 rc = pVCpu->vmm.s.iLastGZRc;
1411#endif
1412 } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
1413
1414#if 0 /** @todo triggers too often */
1415 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TO_R3));
1416#endif
1417
1418#ifdef LOG_ENABLED
1419 /*
1420 * Flush the log
1421 */
1422 PVMMR0LOGGER pR0LoggerR3 = pVCpu->vmm.s.pR0LoggerR3;
1423 if ( pR0LoggerR3
1424 && pR0LoggerR3->Logger.offScratch > 0)
1425 RTLogFlushR0(NULL, &pR0LoggerR3->Logger);
1426#endif /* !LOG_ENABLED */
1427 if (rc != VINF_VMM_CALL_HOST)
1428 {
1429 Log2(("VMMR3HmRunGC: returns %Rrc (cs:rip=%04x:%RX64)\n", rc, CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu)));
1430 return rc;
1431 }
1432 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
1433 if (RT_FAILURE(rc))
1434 return rc;
1435 /* Resume R0 */
1436 }
1437}
1438
1439
1440/**
1441 * VCPU worker for VMMSendStartupIpi.
1442 *
1443 * @param pVM The cross context VM structure.
1444 * @param idCpu Virtual CPU to perform SIPI on.
1445 * @param uVector The SIPI vector.
1446 */
1447static DECLCALLBACK(int) vmmR3SendStarupIpi(PVM pVM, VMCPUID idCpu, uint32_t uVector)
1448{
1449 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
1450 VMCPU_ASSERT_EMT(pVCpu);
1451
1452 /*
1453 * Active, halt and shutdown states of the processor all block SIPIs.
1454 * So we can safely discard the SIPI. See Intel spec. 26.6.2 "Activity State".
1455 */
1456 if (EMGetState(pVCpu) != EMSTATE_WAIT_SIPI)
1457 return VERR_ACCESS_DENIED;
1458
1459
1460 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
1461
1462 pCtx->cs.Sel = uVector << 8;
1463 pCtx->cs.ValidSel = uVector << 8;
1464 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
1465 pCtx->cs.u64Base = uVector << 12;
1466 pCtx->cs.u32Limit = UINT32_C(0x0000ffff);
1467 pCtx->rip = 0;
1468
1469 Log(("vmmR3SendSipi for VCPU %d with vector %x\n", idCpu, uVector));
1470
1471# if 1 /* If we keep the EMSTATE_WAIT_SIPI method, then move this to EM.cpp. */
1472 EMSetState(pVCpu, EMSTATE_HALTED);
1473 return VINF_EM_RESCHEDULE;
1474# else /* And if we go the VMCPU::enmState way it can stay here. */
1475 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STOPPED);
1476 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED);
1477 return VINF_SUCCESS;
1478# endif
1479}
1480
1481
1482static DECLCALLBACK(int) vmmR3SendInitIpi(PVM pVM, VMCPUID idCpu)
1483{
1484 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
1485 VMCPU_ASSERT_EMT(pVCpu);
1486
1487 Log(("vmmR3SendInitIpi for VCPU %d\n", idCpu));
1488
1489 /** @todo Figure out how to handle a nested-guest intercepts here for INIT
1490 * IPI (e.g. SVM_EXIT_INIT). */
1491
1492 PGMR3ResetCpu(pVM, pVCpu);
1493 PDMR3ResetCpu(pVCpu); /* Only clears pending interrupts force flags */
1494 APICR3InitIpi(pVCpu);
1495 TRPMR3ResetCpu(pVCpu);
1496 CPUMR3ResetCpu(pVM, pVCpu);
1497 EMR3ResetCpu(pVCpu);
1498 HMR3ResetCpu(pVCpu);
1499 NEMR3ResetCpu(pVCpu);
1500
1501 /* This will trickle up on the target EMT. */
1502 return VINF_EM_WAIT_SIPI;
1503}
1504
1505
1506/**
1507 * Sends a Startup IPI to the virtual CPU by setting CS:EIP into
1508 * vector-dependent state and unhalting processor.
1509 *
1510 * @param pVM The cross context VM structure.
1511 * @param idCpu Virtual CPU to perform SIPI on.
1512 * @param uVector SIPI vector.
1513 */
1514VMMR3_INT_DECL(void) VMMR3SendStartupIpi(PVM pVM, VMCPUID idCpu, uint32_t uVector)
1515{
1516 AssertReturnVoid(idCpu < pVM->cCpus);
1517
1518 int rc = VMR3ReqCallNoWait(pVM, idCpu, (PFNRT)vmmR3SendStarupIpi, 3, pVM, idCpu, uVector);
1519 AssertRC(rc);
1520}
1521
1522
1523/**
1524 * Sends init IPI to the virtual CPU.
1525 *
1526 * @param pVM The cross context VM structure.
1527 * @param idCpu Virtual CPU to perform int IPI on.
1528 */
1529VMMR3_INT_DECL(void) VMMR3SendInitIpi(PVM pVM, VMCPUID idCpu)
1530{
1531 AssertReturnVoid(idCpu < pVM->cCpus);
1532
1533 int rc = VMR3ReqCallNoWait(pVM, idCpu, (PFNRT)vmmR3SendInitIpi, 2, pVM, idCpu);
1534 AssertRC(rc);
1535}
1536
1537
1538/**
1539 * Registers the guest memory range that can be used for patching.
1540 *
1541 * @returns VBox status code.
1542 * @param pVM The cross context VM structure.
1543 * @param pPatchMem Patch memory range.
1544 * @param cbPatchMem Size of the memory range.
1545 */
1546VMMR3DECL(int) VMMR3RegisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem)
1547{
1548 VM_ASSERT_EMT(pVM);
1549 if (HMIsEnabled(pVM))
1550 return HMR3EnablePatching(pVM, pPatchMem, cbPatchMem);
1551
1552 return VERR_NOT_SUPPORTED;
1553}
1554
1555
1556/**
1557 * Deregisters the guest memory range that can be used for patching.
1558 *
1559 * @returns VBox status code.
1560 * @param pVM The cross context VM structure.
1561 * @param pPatchMem Patch memory range.
1562 * @param cbPatchMem Size of the memory range.
1563 */
1564VMMR3DECL(int) VMMR3DeregisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem)
1565{
1566 if (HMIsEnabled(pVM))
1567 return HMR3DisablePatching(pVM, pPatchMem, cbPatchMem);
1568
1569 return VINF_SUCCESS;
1570}
1571
1572
1573/**
1574 * Common recursion handler for the other EMTs.
1575 *
1576 * @returns Strict VBox status code.
1577 * @param pVM The cross context VM structure.
1578 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1579 * @param rcStrict Current status code to be combined with the one
1580 * from this recursion and returned.
1581 */
1582static VBOXSTRICTRC vmmR3EmtRendezvousCommonRecursion(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict)
1583{
1584 int rc2;
1585
1586 /*
1587 * We wait here while the initiator of this recursion reconfigures
1588 * everything. The last EMT to get in signals the initiator.
1589 */
1590 if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPush) == pVM->cCpus)
1591 {
1592 rc2 = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
1593 AssertLogRelRC(rc2);
1594 }
1595
1596 rc2 = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousRecursionPush, RT_INDEFINITE_WAIT);
1597 AssertLogRelRC(rc2);
1598
1599 /*
1600 * Do the normal rendezvous processing.
1601 */
1602 VBOXSTRICTRC rcStrict2 = vmmR3EmtRendezvousCommon(pVM, pVCpu, false /* fIsCaller */, pVM->vmm.s.fRendezvousFlags,
1603 pVM->vmm.s.pfnRendezvous, pVM->vmm.s.pvRendezvousUser);
1604
1605 /*
1606 * Wait for the initiator to restore everything.
1607 */
1608 rc2 = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousRecursionPop, RT_INDEFINITE_WAIT);
1609 AssertLogRelRC(rc2);
1610
1611 /*
1612 * Last thread out of here signals the initiator.
1613 */
1614 if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPop) == pVM->cCpus)
1615 {
1616 rc2 = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
1617 AssertLogRelRC(rc2);
1618 }
1619
1620 /*
1621 * Merge status codes and return.
1622 */
1623 AssertRC(VBOXSTRICTRC_VAL(rcStrict2));
1624 if ( rcStrict2 != VINF_SUCCESS
1625 && ( rcStrict == VINF_SUCCESS
1626 || rcStrict > rcStrict2))
1627 rcStrict = rcStrict2;
1628 return rcStrict;
1629}
1630
1631
1632/**
1633 * Count returns and have the last non-caller EMT wake up the caller.
1634 *
1635 * @returns VBox strict informational status code for EM scheduling. No failures
1636 * will be returned here, those are for the caller only.
1637 *
1638 * @param pVM The cross context VM structure.
1639 * @param rcStrict The current accumulated recursive status code,
1640 * to be merged with i32RendezvousStatus and
1641 * returned.
1642 */
1643DECL_FORCE_INLINE(VBOXSTRICTRC) vmmR3EmtRendezvousNonCallerReturn(PVM pVM, VBOXSTRICTRC rcStrict)
1644{
1645 VBOXSTRICTRC rcStrict2 = ASMAtomicReadS32(&pVM->vmm.s.i32RendezvousStatus);
1646
1647 uint32_t cReturned = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsReturned);
1648 if (cReturned == pVM->cCpus - 1U)
1649 {
1650 int rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousDoneCaller);
1651 AssertLogRelRC(rc);
1652 }
1653
1654 /*
1655 * Merge the status codes, ignoring error statuses in this code path.
1656 */
1657 AssertLogRelMsgReturn( rcStrict2 <= VINF_SUCCESS
1658 || (rcStrict2 >= VINF_EM_FIRST && rcStrict2 <= VINF_EM_LAST),
1659 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)),
1660 VERR_IPE_UNEXPECTED_INFO_STATUS);
1661
1662 if (RT_SUCCESS(rcStrict2))
1663 {
1664 if ( rcStrict2 != VINF_SUCCESS
1665 && ( rcStrict == VINF_SUCCESS
1666 || rcStrict > rcStrict2))
1667 rcStrict = rcStrict2;
1668 }
1669 return rcStrict;
1670}
1671
1672
1673/**
1674 * Common worker for VMMR3EmtRendezvous and VMMR3EmtRendezvousFF.
1675 *
1676 * @returns VBox strict informational status code for EM scheduling. No failures
1677 * will be returned here, those are for the caller only. When
1678 * fIsCaller is set, VINF_SUCCESS is always returned.
1679 *
1680 * @param pVM The cross context VM structure.
1681 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1682 * @param fIsCaller Whether we're the VMMR3EmtRendezvous caller or
1683 * not.
1684 * @param fFlags The flags.
1685 * @param pfnRendezvous The callback.
1686 * @param pvUser The user argument for the callback.
1687 */
1688static VBOXSTRICTRC vmmR3EmtRendezvousCommon(PVM pVM, PVMCPU pVCpu, bool fIsCaller,
1689 uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
1690{
1691 int rc;
1692 VBOXSTRICTRC rcStrictRecursion = VINF_SUCCESS;
1693
1694 /*
1695 * Enter, the last EMT triggers the next callback phase.
1696 */
1697 uint32_t cEntered = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsEntered);
1698 if (cEntered != pVM->cCpus)
1699 {
1700 if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE)
1701 {
1702 /* Wait for our turn. */
1703 for (;;)
1704 {
1705 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousEnterOneByOne, RT_INDEFINITE_WAIT);
1706 AssertLogRelRC(rc);
1707 if (!pVM->vmm.s.fRendezvousRecursion)
1708 break;
1709 rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
1710 }
1711 }
1712 else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE)
1713 {
1714 /* Wait for the last EMT to arrive and wake everyone up. */
1715 rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce, RT_INDEFINITE_WAIT);
1716 AssertLogRelRC(rc);
1717 Assert(!pVM->vmm.s.fRendezvousRecursion);
1718 }
1719 else if ( (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
1720 || (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING)
1721 {
1722 /* Wait for our turn. */
1723 for (;;)
1724 {
1725 rc = RTSemEventWait(pVM->vmm.s.pahEvtRendezvousEnterOrdered[pVCpu->idCpu], RT_INDEFINITE_WAIT);
1726 AssertLogRelRC(rc);
1727 if (!pVM->vmm.s.fRendezvousRecursion)
1728 break;
1729 rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
1730 }
1731 }
1732 else
1733 {
1734 Assert((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE);
1735
1736 /*
1737 * The execute once is handled specially to optimize the code flow.
1738 *
1739 * The last EMT to arrive will perform the callback and the other
1740 * EMTs will wait on the Done/DoneCaller semaphores (instead of
1741 * the EnterOneByOne/AllAtOnce) in the meanwhile. When the callback
1742 * returns, that EMT will initiate the normal return sequence.
1743 */
1744 if (!fIsCaller)
1745 {
1746 for (;;)
1747 {
1748 rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousDone, RT_INDEFINITE_WAIT);
1749 AssertLogRelRC(rc);
1750 if (!pVM->vmm.s.fRendezvousRecursion)
1751 break;
1752 rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
1753 }
1754
1755 return vmmR3EmtRendezvousNonCallerReturn(pVM, rcStrictRecursion);
1756 }
1757 return VINF_SUCCESS;
1758 }
1759 }
1760 else
1761 {
1762 /*
1763 * All EMTs are waiting, clear the FF and take action according to the
1764 * execution method.
1765 */
1766 VM_FF_CLEAR(pVM, VM_FF_EMT_RENDEZVOUS);
1767
1768 if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE)
1769 {
1770 /* Wake up everyone. */
1771 rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);
1772 AssertLogRelRC(rc);
1773 }
1774 else if ( (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
1775 || (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING)
1776 {
1777 /* Figure out who to wake up and wake it up. If it's ourself, then
1778 it's easy otherwise wait for our turn. */
1779 VMCPUID iFirst = (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
1780 ? 0
1781 : pVM->cCpus - 1U;
1782 if (pVCpu->idCpu != iFirst)
1783 {
1784 rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[iFirst]);
1785 AssertLogRelRC(rc);
1786 for (;;)
1787 {
1788 rc = RTSemEventWait(pVM->vmm.s.pahEvtRendezvousEnterOrdered[pVCpu->idCpu], RT_INDEFINITE_WAIT);
1789 AssertLogRelRC(rc);
1790 if (!pVM->vmm.s.fRendezvousRecursion)
1791 break;
1792 rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
1793 }
1794 }
1795 }
1796 /* else: execute the handler on the current EMT and wake up one or more threads afterwards. */
1797 }
1798
1799
1800 /*
1801 * Do the callback and update the status if necessary.
1802 */
1803 if ( !(fFlags & VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR)
1804 || RT_SUCCESS(ASMAtomicUoReadS32(&pVM->vmm.s.i32RendezvousStatus)) )
1805 {
1806 VBOXSTRICTRC rcStrict2 = pfnRendezvous(pVM, pVCpu, pvUser);
1807 if (rcStrict2 != VINF_SUCCESS)
1808 {
1809 AssertLogRelMsg( rcStrict2 <= VINF_SUCCESS
1810 || (rcStrict2 >= VINF_EM_FIRST && rcStrict2 <= VINF_EM_LAST),
1811 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)));
1812 int32_t i32RendezvousStatus;
1813 do
1814 {
1815 i32RendezvousStatus = ASMAtomicUoReadS32(&pVM->vmm.s.i32RendezvousStatus);
1816 if ( rcStrict2 == i32RendezvousStatus
1817 || RT_FAILURE(i32RendezvousStatus)
1818 || ( i32RendezvousStatus != VINF_SUCCESS
1819 && rcStrict2 > i32RendezvousStatus))
1820 break;
1821 } while (!ASMAtomicCmpXchgS32(&pVM->vmm.s.i32RendezvousStatus, VBOXSTRICTRC_VAL(rcStrict2), i32RendezvousStatus));
1822 }
1823 }
1824
1825 /*
1826 * Increment the done counter and take action depending on whether we're
1827 * the last to finish callback execution.
1828 */
1829 uint32_t cDone = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsDone);
1830 if ( cDone != pVM->cCpus
1831 && (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) != VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE)
1832 {
1833 /* Signal the next EMT? */
1834 if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE)
1835 {
1836 rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousEnterOneByOne);
1837 AssertLogRelRC(rc);
1838 }
1839 else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING)
1840 {
1841 Assert(cDone == pVCpu->idCpu + 1U);
1842 rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[pVCpu->idCpu + 1U]);
1843 AssertLogRelRC(rc);
1844 }
1845 else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING)
1846 {
1847 Assert(pVM->cCpus - cDone == pVCpu->idCpu);
1848 rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[pVM->cCpus - cDone - 1U]);
1849 AssertLogRelRC(rc);
1850 }
1851
1852 /* Wait for the rest to finish (the caller waits on hEvtRendezvousDoneCaller). */
1853 if (!fIsCaller)
1854 {
1855 for (;;)
1856 {
1857 rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousDone, RT_INDEFINITE_WAIT);
1858 AssertLogRelRC(rc);
1859 if (!pVM->vmm.s.fRendezvousRecursion)
1860 break;
1861 rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
1862 }
1863 }
1864 }
1865 else
1866 {
1867 /* Callback execution is all done, tell the rest to return. */
1868 rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousDone);
1869 AssertLogRelRC(rc);
1870 }
1871
1872 if (!fIsCaller)
1873 return vmmR3EmtRendezvousNonCallerReturn(pVM, rcStrictRecursion);
1874 return rcStrictRecursion;
1875}
1876
1877
1878/**
1879 * Called in response to VM_FF_EMT_RENDEZVOUS.
1880 *
1881 * @returns VBox strict status code - EM scheduling. No errors will be returned
1882 * here, nor will any non-EM scheduling status codes be returned.
1883 *
1884 * @param pVM The cross context VM structure.
1885 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1886 *
1887 * @thread EMT
1888 */
1889VMMR3_INT_DECL(int) VMMR3EmtRendezvousFF(PVM pVM, PVMCPU pVCpu)
1890{
1891 Assert(!pVCpu->vmm.s.fInRendezvous);
1892 Log(("VMMR3EmtRendezvousFF: EMT%#u\n", pVCpu->idCpu));
1893 pVCpu->vmm.s.fInRendezvous = true;
1894 VBOXSTRICTRC rcStrict = vmmR3EmtRendezvousCommon(pVM, pVCpu, false /* fIsCaller */, pVM->vmm.s.fRendezvousFlags,
1895 pVM->vmm.s.pfnRendezvous, pVM->vmm.s.pvRendezvousUser);
1896 pVCpu->vmm.s.fInRendezvous = false;
1897 Log(("VMMR3EmtRendezvousFF: EMT%#u returns %Rrc\n", pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict)));
1898 return VBOXSTRICTRC_TODO(rcStrict);
1899}
1900
1901
1902/**
1903 * Helper for resetting an single wakeup event sempahore.
1904 *
1905 * @returns VERR_TIMEOUT on success, RTSemEventWait status otherwise.
1906 * @param hEvt The event semaphore to reset.
1907 */
1908static int vmmR3HlpResetEvent(RTSEMEVENT hEvt)
1909{
1910 for (uint32_t cLoops = 0; ; cLoops++)
1911 {
1912 int rc = RTSemEventWait(hEvt, 0 /*cMsTimeout*/);
1913 if (rc != VINF_SUCCESS || cLoops > _4K)
1914 return rc;
1915 }
1916}
1917
1918
1919/**
1920 * Worker for VMMR3EmtRendezvous that handles recursion.
1921 *
1922 * @returns VBox strict status code. This will be the first error,
1923 * VINF_SUCCESS, or an EM scheduling status code.
1924 *
1925 * @param pVM The cross context VM structure.
1926 * @param pVCpu The cross context virtual CPU structure of the
1927 * calling EMT.
1928 * @param fFlags Flags indicating execution methods. See
1929 * grp_VMMR3EmtRendezvous_fFlags.
1930 * @param pfnRendezvous The callback.
1931 * @param pvUser User argument for the callback.
1932 *
1933 * @thread EMT(pVCpu)
1934 */
1935static VBOXSTRICTRC vmmR3EmtRendezvousRecursive(PVM pVM, PVMCPU pVCpu, uint32_t fFlags,
1936 PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
1937{
1938 Log(("vmmR3EmtRendezvousRecursive: %#x EMT#%u depth=%d\n", fFlags, pVCpu->idCpu, pVM->vmm.s.cRendezvousRecursions));
1939 AssertLogRelReturn(pVM->vmm.s.cRendezvousRecursions < 3, VERR_DEADLOCK);
1940 Assert(pVCpu->vmm.s.fInRendezvous);
1941
1942 /*
1943 * Save the current state.
1944 */
1945 uint32_t const fParentFlags = pVM->vmm.s.fRendezvousFlags;
1946 uint32_t const cParentDone = pVM->vmm.s.cRendezvousEmtsDone;
1947 int32_t const iParentStatus = pVM->vmm.s.i32RendezvousStatus;
1948 PFNVMMEMTRENDEZVOUS const pfnParent = pVM->vmm.s.pfnRendezvous;
1949 void * const pvParentUser = pVM->vmm.s.pvRendezvousUser;
1950
1951 /*
1952 * Check preconditions and save the current state.
1953 */
1954 AssertReturn( (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
1955 || (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING
1956 || (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE
1957 || (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE,
1958 VERR_INTERNAL_ERROR);
1959 AssertReturn(pVM->vmm.s.cRendezvousEmtsEntered == pVM->cCpus, VERR_INTERNAL_ERROR_2);
1960 AssertReturn(pVM->vmm.s.cRendezvousEmtsReturned == 0, VERR_INTERNAL_ERROR_3);
1961
1962 /*
1963 * Reset the recursion prep and pop semaphores.
1964 */
1965 int rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousRecursionPush);
1966 AssertLogRelRCReturn(rc, rc);
1967 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousRecursionPop);
1968 AssertLogRelRCReturn(rc, rc);
1969 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
1970 AssertLogRelMsgReturn(rc == VERR_TIMEOUT, ("%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_IPE_UNEXPECTED_INFO_STATUS);
1971 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
1972 AssertLogRelMsgReturn(rc == VERR_TIMEOUT, ("%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_IPE_UNEXPECTED_INFO_STATUS);
1973
1974 /*
1975 * Usher the other thread into the recursion routine.
1976 */
1977 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsRecursingPush, 0);
1978 ASMAtomicWriteBool(&pVM->vmm.s.fRendezvousRecursion, true);
1979
1980 uint32_t cLeft = pVM->cCpus - (cParentDone + 1U);
1981 if ((fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE)
1982 while (cLeft-- > 0)
1983 {
1984 rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousEnterOneByOne);
1985 AssertLogRelRC(rc);
1986 }
1987 else if ((fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING)
1988 {
1989 Assert(cLeft == pVM->cCpus - (pVCpu->idCpu + 1U));
1990 for (VMCPUID iCpu = pVCpu->idCpu + 1U; iCpu < pVM->cCpus; iCpu++)
1991 {
1992 rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[iCpu]);
1993 AssertLogRelRC(rc);
1994 }
1995 }
1996 else if ((fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING)
1997 {
1998 Assert(cLeft == pVCpu->idCpu);
1999 for (VMCPUID iCpu = pVCpu->idCpu; iCpu > 0; iCpu--)
2000 {
2001 rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[iCpu - 1U]);
2002 AssertLogRelRC(rc);
2003 }
2004 }
2005 else
2006 AssertLogRelReturn((fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE,
2007 VERR_INTERNAL_ERROR_4);
2008
2009 rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousDone);
2010 AssertLogRelRC(rc);
2011 rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousDoneCaller);
2012 AssertLogRelRC(rc);
2013
2014
2015 /*
2016 * Wait for the EMTs to wake up and get out of the parent rendezvous code.
2017 */
2018 if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPush) != pVM->cCpus)
2019 {
2020 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousRecursionPushCaller, RT_INDEFINITE_WAIT);
2021 AssertLogRelRC(rc);
2022 }
2023
2024 ASMAtomicWriteBool(&pVM->vmm.s.fRendezvousRecursion, false);
2025
2026 /*
2027 * Clear the slate and setup the new rendezvous.
2028 */
2029 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2030 {
2031 rc = vmmR3HlpResetEvent(pVM->vmm.s.pahEvtRendezvousEnterOrdered[i]);
2032 AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2033 }
2034 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousEnterOneByOne); AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2035 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce); AssertLogRelRC(rc);
2036 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousDone); AssertLogRelRC(rc);
2037 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousDoneCaller); AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2038
2039 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsEntered, 0);
2040 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsDone, 0);
2041 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsReturned, 0);
2042 ASMAtomicWriteS32(&pVM->vmm.s.i32RendezvousStatus, VINF_SUCCESS);
2043 ASMAtomicWritePtr((void * volatile *)&pVM->vmm.s.pfnRendezvous, (void *)(uintptr_t)pfnRendezvous);
2044 ASMAtomicWritePtr(&pVM->vmm.s.pvRendezvousUser, pvUser);
2045 ASMAtomicWriteU32(&pVM->vmm.s.fRendezvousFlags, fFlags);
2046 ASMAtomicIncU32(&pVM->vmm.s.cRendezvousRecursions);
2047
2048 /*
2049 * We're ready to go now, do normal rendezvous processing.
2050 */
2051 rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousRecursionPush);
2052 AssertLogRelRC(rc);
2053
2054 VBOXSTRICTRC rcStrict = vmmR3EmtRendezvousCommon(pVM, pVCpu, true /*fIsCaller*/, fFlags, pfnRendezvous, pvUser);
2055
2056 /*
2057 * The caller waits for the other EMTs to be done, return and waiting on the
2058 * pop semaphore.
2059 */
2060 for (;;)
2061 {
2062 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, RT_INDEFINITE_WAIT);
2063 AssertLogRelRC(rc);
2064 if (!pVM->vmm.s.fRendezvousRecursion)
2065 break;
2066 rcStrict = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrict);
2067 }
2068
2069 /*
2070 * Get the return code and merge it with the above recursion status.
2071 */
2072 VBOXSTRICTRC rcStrict2 = pVM->vmm.s.i32RendezvousStatus;
2073 if ( rcStrict2 != VINF_SUCCESS
2074 && ( rcStrict == VINF_SUCCESS
2075 || rcStrict > rcStrict2))
2076 rcStrict = rcStrict2;
2077
2078 /*
2079 * Restore the parent rendezvous state.
2080 */
2081 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2082 {
2083 rc = vmmR3HlpResetEvent(pVM->vmm.s.pahEvtRendezvousEnterOrdered[i]);
2084 AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2085 }
2086 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousEnterOneByOne); AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2087 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce); AssertLogRelRC(rc);
2088 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousDone); AssertLogRelRC(rc);
2089 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousDoneCaller); AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2090
2091 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsEntered, pVM->cCpus);
2092 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsReturned, 0);
2093 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsDone, cParentDone);
2094 ASMAtomicWriteS32(&pVM->vmm.s.i32RendezvousStatus, iParentStatus);
2095 ASMAtomicWriteU32(&pVM->vmm.s.fRendezvousFlags, fParentFlags);
2096 ASMAtomicWritePtr(&pVM->vmm.s.pvRendezvousUser, pvParentUser);
2097 ASMAtomicWritePtr((void * volatile *)&pVM->vmm.s.pfnRendezvous, (void *)(uintptr_t)pfnParent);
2098
2099 /*
2100 * Usher the other EMTs back to their parent recursion routine, waiting
2101 * for them to all get there before we return (makes sure they've been
2102 * scheduled and are past the pop event sem, see below).
2103 */
2104 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsRecursingPop, 0);
2105 rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousRecursionPop);
2106 AssertLogRelRC(rc);
2107
2108 if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPop) != pVM->cCpus)
2109 {
2110 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousRecursionPopCaller, RT_INDEFINITE_WAIT);
2111 AssertLogRelRC(rc);
2112 }
2113
2114 /*
2115 * We must reset the pop semaphore on the way out (doing the pop caller too,
2116 * just in case). The parent may be another recursion.
2117 */
2118 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousRecursionPop); AssertLogRelRC(rc);
2119 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousRecursionPopCaller); AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2120
2121 ASMAtomicDecU32(&pVM->vmm.s.cRendezvousRecursions);
2122
2123 Log(("vmmR3EmtRendezvousRecursive: %#x EMT#%u depth=%d returns %Rrc\n",
2124 fFlags, pVCpu->idCpu, pVM->vmm.s.cRendezvousRecursions, VBOXSTRICTRC_VAL(rcStrict)));
2125 return rcStrict;
2126}
2127
2128
2129/**
2130 * EMT rendezvous.
2131 *
2132 * Gathers all the EMTs and execute some code on each of them, either in a one
2133 * by one fashion or all at once.
2134 *
2135 * @returns VBox strict status code. This will be the first error,
2136 * VINF_SUCCESS, or an EM scheduling status code.
2137 *
2138 * @retval VERR_DEADLOCK if recursion is attempted using a rendezvous type that
2139 * doesn't support it or if the recursion is too deep.
2140 *
2141 * @param pVM The cross context VM structure.
2142 * @param fFlags Flags indicating execution methods. See
2143 * grp_VMMR3EmtRendezvous_fFlags. The one-by-one,
2144 * descending and ascending rendezvous types support
2145 * recursion from inside @a pfnRendezvous.
2146 * @param pfnRendezvous The callback.
2147 * @param pvUser User argument for the callback.
2148 *
2149 * @thread Any.
2150 */
2151VMMR3DECL(int) VMMR3EmtRendezvous(PVM pVM, uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
2152{
2153 /*
2154 * Validate input.
2155 */
2156 AssertReturn(pVM, VERR_INVALID_VM_HANDLE);
2157 AssertMsg( (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) != VMMEMTRENDEZVOUS_FLAGS_TYPE_INVALID
2158 && (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) <= VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING
2159 && !(fFlags & ~VMMEMTRENDEZVOUS_FLAGS_VALID_MASK), ("%#x\n", fFlags));
2160 AssertMsg( !(fFlags & VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR)
2161 || ( (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) != VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE
2162 && (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) != VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE),
2163 ("type %u\n", fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK));
2164
2165 VBOXSTRICTRC rcStrict;
2166 PVMCPU pVCpu = VMMGetCpu(pVM);
2167 if (!pVCpu)
2168 {
2169 /*
2170 * Forward the request to an EMT thread.
2171 */
2172 Log(("VMMR3EmtRendezvous: %#x non-EMT\n", fFlags));
2173 if (!(fFlags & VMMEMTRENDEZVOUS_FLAGS_PRIORITY))
2174 rcStrict = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)VMMR3EmtRendezvous, 4, pVM, fFlags, pfnRendezvous, pvUser);
2175 else
2176 rcStrict = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)VMMR3EmtRendezvous, 4, pVM, fFlags, pfnRendezvous, pvUser);
2177 Log(("VMMR3EmtRendezvous: %#x non-EMT returns %Rrc\n", fFlags, VBOXSTRICTRC_VAL(rcStrict)));
2178 }
2179 else if ( pVM->cCpus == 1
2180 || ( pVM->enmVMState == VMSTATE_DESTROYING
2181 && VMR3GetActiveEmts(pVM->pUVM) < pVM->cCpus ) )
2182 {
2183 /*
2184 * Shortcut for the single EMT case.
2185 *
2186 * We also ends up here if EMT(0) (or others) tries to issue a rendezvous
2187 * during vmR3Destroy after other emulation threads have started terminating.
2188 */
2189 if (!pVCpu->vmm.s.fInRendezvous)
2190 {
2191 Log(("VMMR3EmtRendezvous: %#x EMT (uni)\n", fFlags));
2192 pVCpu->vmm.s.fInRendezvous = true;
2193 pVM->vmm.s.fRendezvousFlags = fFlags;
2194 rcStrict = pfnRendezvous(pVM, pVCpu, pvUser);
2195 pVCpu->vmm.s.fInRendezvous = false;
2196 }
2197 else
2198 {
2199 /* Recursion. Do the same checks as in the SMP case. */
2200 Log(("VMMR3EmtRendezvous: %#x EMT (uni), recursion depth=%d\n", fFlags, pVM->vmm.s.cRendezvousRecursions));
2201 uint32_t fType = pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK;
2202 AssertLogRelReturn( !pVCpu->vmm.s.fInRendezvous
2203 || fType == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
2204 || fType == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING
2205 || fType == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE
2206 || fType == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE
2207 , VERR_DEADLOCK);
2208
2209 AssertLogRelReturn(pVM->vmm.s.cRendezvousRecursions < 3, VERR_DEADLOCK);
2210 pVM->vmm.s.cRendezvousRecursions++;
2211 uint32_t const fParentFlags = pVM->vmm.s.fRendezvousFlags;
2212 pVM->vmm.s.fRendezvousFlags = fFlags;
2213
2214 rcStrict = pfnRendezvous(pVM, pVCpu, pvUser);
2215
2216 pVM->vmm.s.fRendezvousFlags = fParentFlags;
2217 pVM->vmm.s.cRendezvousRecursions--;
2218 }
2219 Log(("VMMR3EmtRendezvous: %#x EMT (uni) returns %Rrc\n", fFlags, VBOXSTRICTRC_VAL(rcStrict)));
2220 }
2221 else
2222 {
2223 /*
2224 * Spin lock. If busy, check for recursion, if not recursing wait for
2225 * the other EMT to finish while keeping a lookout for the RENDEZVOUS FF.
2226 */
2227 int rc;
2228 rcStrict = VINF_SUCCESS;
2229 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pVM->vmm.s.u32RendezvousLock, 0x77778888, 0)))
2230 {
2231 /* Allow recursion in some cases. */
2232 if ( pVCpu->vmm.s.fInRendezvous
2233 && ( (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
2234 || (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING
2235 || (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE
2236 || (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE
2237 ))
2238 return VBOXSTRICTRC_TODO(vmmR3EmtRendezvousRecursive(pVM, pVCpu, fFlags, pfnRendezvous, pvUser));
2239
2240 AssertLogRelMsgReturn(!pVCpu->vmm.s.fInRendezvous, ("fRendezvousFlags=%#x\n", pVM->vmm.s.fRendezvousFlags),
2241 VERR_DEADLOCK);
2242
2243 Log(("VMMR3EmtRendezvous: %#x EMT#%u, waiting for lock...\n", fFlags, pVCpu->idCpu));
2244 while (!ASMAtomicCmpXchgU32(&pVM->vmm.s.u32RendezvousLock, 0x77778888, 0))
2245 {
2246 if (VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS))
2247 {
2248 rc = VMMR3EmtRendezvousFF(pVM, pVCpu);
2249 if ( rc != VINF_SUCCESS
2250 && ( rcStrict == VINF_SUCCESS
2251 || rcStrict > rc))
2252 rcStrict = rc;
2253 /** @todo Perhaps deal with termination here? */
2254 }
2255 ASMNopPause();
2256 }
2257 }
2258
2259 Log(("VMMR3EmtRendezvous: %#x EMT#%u\n", fFlags, pVCpu->idCpu));
2260 Assert(!VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS));
2261 Assert(!pVCpu->vmm.s.fInRendezvous);
2262 pVCpu->vmm.s.fInRendezvous = true;
2263
2264 /*
2265 * Clear the slate and setup the rendezvous. This is a semaphore ping-pong orgy. :-)
2266 */
2267 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2268 {
2269 rc = RTSemEventWait(pVM->vmm.s.pahEvtRendezvousEnterOrdered[i], 0);
2270 AssertLogRelMsg(rc == VERR_TIMEOUT || rc == VINF_SUCCESS, ("%Rrc\n", rc));
2271 }
2272 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousEnterOneByOne, 0); AssertLogRelMsg(rc == VERR_TIMEOUT || rc == VINF_SUCCESS, ("%Rrc\n", rc));
2273 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce); AssertLogRelRC(rc);
2274 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousDone); AssertLogRelRC(rc);
2275 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, 0); AssertLogRelMsg(rc == VERR_TIMEOUT || rc == VINF_SUCCESS, ("%Rrc\n", rc));
2276 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsEntered, 0);
2277 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsDone, 0);
2278 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsReturned, 0);
2279 ASMAtomicWriteS32(&pVM->vmm.s.i32RendezvousStatus, VINF_SUCCESS);
2280 ASMAtomicWritePtr((void * volatile *)&pVM->vmm.s.pfnRendezvous, (void *)(uintptr_t)pfnRendezvous);
2281 ASMAtomicWritePtr(&pVM->vmm.s.pvRendezvousUser, pvUser);
2282 ASMAtomicWriteU32(&pVM->vmm.s.fRendezvousFlags, fFlags);
2283
2284 /*
2285 * Set the FF and poke the other EMTs.
2286 */
2287 VM_FF_SET(pVM, VM_FF_EMT_RENDEZVOUS);
2288 VMR3NotifyGlobalFFU(pVM->pUVM, VMNOTIFYFF_FLAGS_POKE);
2289
2290 /*
2291 * Do the same ourselves.
2292 */
2293 VBOXSTRICTRC rcStrict2 = vmmR3EmtRendezvousCommon(pVM, pVCpu, true /* fIsCaller */, fFlags, pfnRendezvous, pvUser);
2294
2295 /*
2296 * The caller waits for the other EMTs to be done and return before doing
2297 * the cleanup. This makes away with wakeup / reset races we would otherwise
2298 * risk in the multiple release event semaphore code (hEvtRendezvousDoneCaller).
2299 */
2300 for (;;)
2301 {
2302 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, RT_INDEFINITE_WAIT);
2303 AssertLogRelRC(rc);
2304 if (!pVM->vmm.s.fRendezvousRecursion)
2305 break;
2306 rcStrict2 = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrict2);
2307 }
2308
2309 /*
2310 * Get the return code and clean up a little bit.
2311 */
2312 VBOXSTRICTRC rcStrict3 = pVM->vmm.s.i32RendezvousStatus;
2313 ASMAtomicWriteNullPtr((void * volatile *)&pVM->vmm.s.pfnRendezvous);
2314
2315 ASMAtomicWriteU32(&pVM->vmm.s.u32RendezvousLock, 0);
2316 pVCpu->vmm.s.fInRendezvous = false;
2317
2318 /*
2319 * Merge rcStrict, rcStrict2 and rcStrict3.
2320 */
2321 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
2322 AssertRC(VBOXSTRICTRC_VAL(rcStrict2));
2323 if ( rcStrict2 != VINF_SUCCESS
2324 && ( rcStrict == VINF_SUCCESS
2325 || rcStrict > rcStrict2))
2326 rcStrict = rcStrict2;
2327 if ( rcStrict3 != VINF_SUCCESS
2328 && ( rcStrict == VINF_SUCCESS
2329 || rcStrict > rcStrict3))
2330 rcStrict = rcStrict3;
2331 Log(("VMMR3EmtRendezvous: %#x EMT#%u returns %Rrc\n", fFlags, pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict)));
2332 }
2333
2334 AssertLogRelMsgReturn( rcStrict <= VINF_SUCCESS
2335 || (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST),
2336 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)),
2337 VERR_IPE_UNEXPECTED_INFO_STATUS);
2338 return VBOXSTRICTRC_VAL(rcStrict);
2339}
2340
2341
2342/**
2343 * Read from the ring 0 jump buffer stack.
2344 *
2345 * @returns VBox status code.
2346 *
2347 * @param pVM The cross context VM structure.
2348 * @param idCpu The ID of the source CPU context (for the address).
2349 * @param R0Addr Where to start reading.
2350 * @param pvBuf Where to store the data we've read.
2351 * @param cbRead The number of bytes to read.
2352 */
2353VMMR3_INT_DECL(int) VMMR3ReadR0Stack(PVM pVM, VMCPUID idCpu, RTHCUINTPTR R0Addr, void *pvBuf, size_t cbRead)
2354{
2355 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
2356 AssertReturn(pVCpu, VERR_INVALID_PARAMETER);
2357
2358#ifdef VMM_R0_SWITCH_STACK
2359 RTHCUINTPTR off = R0Addr - MMHyperCCToR0(pVM, pVCpu->vmm.s.pbEMTStackR3);
2360#else
2361 RTHCUINTPTR off = pVCpu->vmm.s.CallRing3JmpBufR0.cbSavedStack - (pVCpu->vmm.s.CallRing3JmpBufR0.SpCheck - R0Addr);
2362#endif
2363 if ( off > VMM_STACK_SIZE
2364 || off + cbRead >= VMM_STACK_SIZE)
2365 return VERR_INVALID_POINTER;
2366
2367 memcpy(pvBuf, &pVCpu->vmm.s.pbEMTStackR3[off], cbRead);
2368 return VINF_SUCCESS;
2369}
2370
2371#ifdef VBOX_WITH_RAW_MODE
2372
2373/**
2374 * Calls a RC function.
2375 *
2376 * @param pVM The cross context VM structure.
2377 * @param RCPtrEntry The address of the RC function.
2378 * @param cArgs The number of arguments in the ....
2379 * @param ... Arguments to the function.
2380 */
2381VMMR3DECL(int) VMMR3CallRC(PVM pVM, RTRCPTR RCPtrEntry, unsigned cArgs, ...)
2382{
2383 va_list args;
2384 va_start(args, cArgs);
2385 int rc = VMMR3CallRCV(pVM, RCPtrEntry, cArgs, args);
2386 va_end(args);
2387 return rc;
2388}
2389
2390
2391/**
2392 * Calls a RC function.
2393 *
2394 * @param pVM The cross context VM structure.
2395 * @param RCPtrEntry The address of the RC function.
2396 * @param cArgs The number of arguments in the ....
2397 * @param args Arguments to the function.
2398 */
2399VMMR3DECL(int) VMMR3CallRCV(PVM pVM, RTRCPTR RCPtrEntry, unsigned cArgs, va_list args)
2400{
2401 /* Raw mode implies 1 VCPU. */
2402 AssertReturn(pVM->cCpus == 1, VERR_RAW_MODE_INVALID_SMP);
2403 PVMCPU pVCpu = &pVM->aCpus[0];
2404
2405 Log2(("VMMR3CallGCV: RCPtrEntry=%RRv cArgs=%d\n", RCPtrEntry, cArgs));
2406
2407 /*
2408 * Setup the call frame using the trampoline.
2409 */
2410 CPUMSetHyperState(pVCpu,
2411 pVM->vmm.s.pfnCallTrampolineRC, /* eip */
2412 pVCpu->vmm.s.pbEMTStackBottomRC - cArgs * sizeof(RTGCUINTPTR32), /* esp */
2413 RCPtrEntry, /* eax */
2414 cArgs /* edx */
2415 );
2416
2417#if 0
2418 memset(pVCpu->vmm.s.pbEMTStackR3, 0xaa, VMM_STACK_SIZE); /* Clear the stack. */
2419#endif
2420 PRTGCUINTPTR32 pFrame = (PRTGCUINTPTR32)(pVCpu->vmm.s.pbEMTStackR3 + VMM_STACK_SIZE) - cArgs;
2421 int i = cArgs;
2422 while (i-- > 0)
2423 *pFrame++ = va_arg(args, RTGCUINTPTR32);
2424
2425 CPUMPushHyper(pVCpu, cArgs * sizeof(RTGCUINTPTR32)); /* stack frame size */
2426 CPUMPushHyper(pVCpu, RCPtrEntry); /* what to call */
2427
2428 /*
2429 * We hide log flushes (outer) and hypervisor interrupts (inner).
2430 */
2431 for (;;)
2432 {
2433 int rc;
2434 Assert(CPUMGetHyperCR3(pVCpu) && CPUMGetHyperCR3(pVCpu) == PGMGetHyperCR3(pVCpu));
2435 do
2436 {
2437#ifdef NO_SUPCALLR0VMM
2438 rc = VERR_GENERAL_FAILURE;
2439#else
2440 rc = SUPR3CallVMMR0Fast(pVM->pVMR0, VMMR0_DO_RAW_RUN, 0);
2441 if (RT_LIKELY(rc == VINF_SUCCESS))
2442 rc = pVCpu->vmm.s.iLastGZRc;
2443#endif
2444 } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
2445
2446 /*
2447 * Flush the loggers.
2448 */
2449#ifdef LOG_ENABLED
2450 PRTLOGGERRC pLogger = pVM->vmm.s.pRCLoggerR3;
2451 if ( pLogger
2452 && pLogger->offScratch > 0)
2453 RTLogFlushRC(NULL, pLogger);
2454#endif
2455#ifdef VBOX_WITH_RC_RELEASE_LOGGING
2456 PRTLOGGERRC pRelLogger = pVM->vmm.s.pRCRelLoggerR3;
2457 if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
2458 RTLogFlushRC(RTLogRelGetDefaultInstance(), pRelLogger);
2459#endif
2460 if (rc == VERR_TRPM_PANIC || rc == VERR_TRPM_DONT_PANIC)
2461 VMMR3FatalDump(pVM, pVCpu, rc);
2462 if (rc != VINF_VMM_CALL_HOST)
2463 {
2464 Log2(("VMMR3CallGCV: returns %Rrc (cs:eip=%04x:%08x)\n", rc, CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
2465 return rc;
2466 }
2467 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
2468 if (RT_FAILURE(rc))
2469 return rc;
2470 }
2471}
2472
2473#endif /* VBOX_WITH_RAW_MODE */
2474
2475/**
2476 * Wrapper for SUPR3CallVMMR0Ex which will deal with VINF_VMM_CALL_HOST returns.
2477 *
2478 * @returns VBox status code.
2479 * @param pVM The cross context VM structure.
2480 * @param uOperation Operation to execute.
2481 * @param u64Arg Constant argument.
2482 * @param pReqHdr Pointer to a request header. See SUPR3CallVMMR0Ex for
2483 * details.
2484 */
2485VMMR3DECL(int) VMMR3CallR0(PVM pVM, uint32_t uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
2486{
2487 PVMCPU pVCpu = VMMGetCpu(pVM);
2488 AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
2489
2490 /*
2491 * Call Ring-0 entry with init code.
2492 */
2493 int rc;
2494 for (;;)
2495 {
2496#ifdef NO_SUPCALLR0VMM
2497 rc = VERR_GENERAL_FAILURE;
2498#else
2499 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, pVCpu->idCpu, uOperation, u64Arg, pReqHdr);
2500#endif
2501 /*
2502 * Flush the logs.
2503 */
2504#ifdef LOG_ENABLED
2505 if ( pVCpu->vmm.s.pR0LoggerR3
2506 && pVCpu->vmm.s.pR0LoggerR3->Logger.offScratch > 0)
2507 RTLogFlushR0(NULL, &pVCpu->vmm.s.pR0LoggerR3->Logger);
2508#endif
2509 if (rc != VINF_VMM_CALL_HOST)
2510 break;
2511 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
2512 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
2513 break;
2514 /* Resume R0 */
2515 }
2516
2517 AssertLogRelMsgReturn(rc == VINF_SUCCESS || RT_FAILURE(rc),
2518 ("uOperation=%u rc=%Rrc\n", uOperation, rc),
2519 VERR_IPE_UNEXPECTED_INFO_STATUS);
2520 return rc;
2521}
2522
2523
2524#ifdef VBOX_WITH_RAW_MODE
2525/**
2526 * Resumes executing hypervisor code when interrupted by a queue flush or a
2527 * debug event.
2528 *
2529 * @returns VBox status code.
2530 * @param pVM The cross context VM structure.
2531 * @param pVCpu The cross context virtual CPU structure.
2532 */
2533VMMR3DECL(int) VMMR3ResumeHyper(PVM pVM, PVMCPU pVCpu)
2534{
2535 Log(("VMMR3ResumeHyper: eip=%RRv esp=%RRv\n", CPUMGetHyperEIP(pVCpu), CPUMGetHyperESP(pVCpu)));
2536 AssertReturn(pVM->cCpus == 1, VERR_RAW_MODE_INVALID_SMP);
2537
2538 /*
2539 * We hide log flushes (outer) and hypervisor interrupts (inner).
2540 */
2541 for (;;)
2542 {
2543 int rc;
2544 Assert(CPUMGetHyperCR3(pVCpu) && CPUMGetHyperCR3(pVCpu) == PGMGetHyperCR3(pVCpu));
2545 do
2546 {
2547# ifdef NO_SUPCALLR0VMM
2548 rc = VERR_GENERAL_FAILURE;
2549# else
2550 rc = SUPR3CallVMMR0Fast(pVM->pVMR0, VMMR0_DO_RAW_RUN, 0);
2551 if (RT_LIKELY(rc == VINF_SUCCESS))
2552 rc = pVCpu->vmm.s.iLastGZRc;
2553# endif
2554 } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
2555
2556 /*
2557 * Flush the loggers.
2558 */
2559# ifdef LOG_ENABLED
2560 PRTLOGGERRC pLogger = pVM->vmm.s.pRCLoggerR3;
2561 if ( pLogger
2562 && pLogger->offScratch > 0)
2563 RTLogFlushRC(NULL, pLogger);
2564# endif
2565# ifdef VBOX_WITH_RC_RELEASE_LOGGING
2566 PRTLOGGERRC pRelLogger = pVM->vmm.s.pRCRelLoggerR3;
2567 if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
2568 RTLogFlushRC(RTLogRelGetDefaultInstance(), pRelLogger);
2569# endif
2570 if (rc == VERR_TRPM_PANIC || rc == VERR_TRPM_DONT_PANIC)
2571 VMMR3FatalDump(pVM, pVCpu, rc);
2572 if (rc != VINF_VMM_CALL_HOST)
2573 {
2574 Log(("VMMR3ResumeHyper: returns %Rrc\n", rc));
2575 return rc;
2576 }
2577 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
2578 if (RT_FAILURE(rc))
2579 return rc;
2580 }
2581}
2582#endif /* VBOX_WITH_RAW_MODE */
2583
2584
2585/**
2586 * Service a call to the ring-3 host code.
2587 *
2588 * @returns VBox status code.
2589 * @param pVM The cross context VM structure.
2590 * @param pVCpu The cross context virtual CPU structure.
2591 * @remarks Careful with critsects.
2592 */
2593static int vmmR3ServiceCallRing3Request(PVM pVM, PVMCPU pVCpu)
2594{
2595 /*
2596 * We must also check for pending critsect exits or else we can deadlock
2597 * when entering other critsects here.
2598 */
2599 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PDM_CRITSECT))
2600 PDMCritSectBothFF(pVCpu);
2601
2602 switch (pVCpu->vmm.s.enmCallRing3Operation)
2603 {
2604 /*
2605 * Acquire a critical section.
2606 */
2607 case VMMCALLRING3_PDM_CRIT_SECT_ENTER:
2608 {
2609 pVCpu->vmm.s.rcCallRing3 = PDMR3CritSectEnterEx((PPDMCRITSECT)(uintptr_t)pVCpu->vmm.s.u64CallRing3Arg,
2610 true /*fCallRing3*/);
2611 break;
2612 }
2613
2614 /*
2615 * Enter a r/w critical section exclusively.
2616 */
2617 case VMMCALLRING3_PDM_CRIT_SECT_RW_ENTER_EXCL:
2618 {
2619 pVCpu->vmm.s.rcCallRing3 = PDMR3CritSectRwEnterExclEx((PPDMCRITSECTRW)(uintptr_t)pVCpu->vmm.s.u64CallRing3Arg,
2620 true /*fCallRing3*/);
2621 break;
2622 }
2623
2624 /*
2625 * Enter a r/w critical section shared.
2626 */
2627 case VMMCALLRING3_PDM_CRIT_SECT_RW_ENTER_SHARED:
2628 {
2629 pVCpu->vmm.s.rcCallRing3 = PDMR3CritSectRwEnterSharedEx((PPDMCRITSECTRW)(uintptr_t)pVCpu->vmm.s.u64CallRing3Arg,
2630 true /*fCallRing3*/);
2631 break;
2632 }
2633
2634 /*
2635 * Acquire the PDM lock.
2636 */
2637 case VMMCALLRING3_PDM_LOCK:
2638 {
2639 pVCpu->vmm.s.rcCallRing3 = PDMR3LockCall(pVM);
2640 break;
2641 }
2642
2643 /*
2644 * Grow the PGM pool.
2645 */
2646 case VMMCALLRING3_PGM_POOL_GROW:
2647 {
2648 pVCpu->vmm.s.rcCallRing3 = PGMR3PoolGrow(pVM);
2649 break;
2650 }
2651
2652 /*
2653 * Maps an page allocation chunk into ring-3 so ring-0 can use it.
2654 */
2655 case VMMCALLRING3_PGM_MAP_CHUNK:
2656 {
2657 pVCpu->vmm.s.rcCallRing3 = PGMR3PhysChunkMap(pVM, pVCpu->vmm.s.u64CallRing3Arg);
2658 break;
2659 }
2660
2661 /*
2662 * Allocates more handy pages.
2663 */
2664 case VMMCALLRING3_PGM_ALLOCATE_HANDY_PAGES:
2665 {
2666 pVCpu->vmm.s.rcCallRing3 = PGMR3PhysAllocateHandyPages(pVM);
2667 break;
2668 }
2669
2670 /*
2671 * Allocates a large page.
2672 */
2673 case VMMCALLRING3_PGM_ALLOCATE_LARGE_HANDY_PAGE:
2674 {
2675 pVCpu->vmm.s.rcCallRing3 = PGMR3PhysAllocateLargeHandyPage(pVM, pVCpu->vmm.s.u64CallRing3Arg);
2676 break;
2677 }
2678
2679 /*
2680 * Acquire the PGM lock.
2681 */
2682 case VMMCALLRING3_PGM_LOCK:
2683 {
2684 pVCpu->vmm.s.rcCallRing3 = PGMR3LockCall(pVM);
2685 break;
2686 }
2687
2688 /*
2689 * Acquire the MM hypervisor heap lock.
2690 */
2691 case VMMCALLRING3_MMHYPER_LOCK:
2692 {
2693 pVCpu->vmm.s.rcCallRing3 = MMR3LockCall(pVM);
2694 break;
2695 }
2696
2697#ifdef VBOX_WITH_REM
2698 /*
2699 * Flush REM handler notifications.
2700 */
2701 case VMMCALLRING3_REM_REPLAY_HANDLER_NOTIFICATIONS:
2702 {
2703 REMR3ReplayHandlerNotifications(pVM);
2704 pVCpu->vmm.s.rcCallRing3 = VINF_SUCCESS;
2705 break;
2706 }
2707#endif
2708
2709 /*
2710 * This is a noop. We just take this route to avoid unnecessary
2711 * tests in the loops.
2712 */
2713 case VMMCALLRING3_VMM_LOGGER_FLUSH:
2714 pVCpu->vmm.s.rcCallRing3 = VINF_SUCCESS;
2715 LogAlways(("*FLUSH*\n"));
2716 break;
2717
2718 /*
2719 * Set the VM error message.
2720 */
2721 case VMMCALLRING3_VM_SET_ERROR:
2722 VMR3SetErrorWorker(pVM);
2723 pVCpu->vmm.s.rcCallRing3 = VINF_SUCCESS;
2724 break;
2725
2726 /*
2727 * Set the VM runtime error message.
2728 */
2729 case VMMCALLRING3_VM_SET_RUNTIME_ERROR:
2730 pVCpu->vmm.s.rcCallRing3 = VMR3SetRuntimeErrorWorker(pVM);
2731 break;
2732
2733 /*
2734 * Signal a ring 0 hypervisor assertion.
2735 * Cancel the longjmp operation that's in progress.
2736 */
2737 case VMMCALLRING3_VM_R0_ASSERTION:
2738 pVCpu->vmm.s.enmCallRing3Operation = VMMCALLRING3_INVALID;
2739 pVCpu->vmm.s.CallRing3JmpBufR0.fInRing3Call = false;
2740#ifdef RT_ARCH_X86
2741 pVCpu->vmm.s.CallRing3JmpBufR0.eip = 0;
2742#else
2743 pVCpu->vmm.s.CallRing3JmpBufR0.rip = 0;
2744#endif
2745#ifdef VMM_R0_SWITCH_STACK
2746 *(uint64_t *)pVCpu->vmm.s.pbEMTStackR3 = 0; /* clear marker */
2747#endif
2748 LogRel(("%s", pVM->vmm.s.szRing0AssertMsg1));
2749 LogRel(("%s", pVM->vmm.s.szRing0AssertMsg2));
2750 return VERR_VMM_RING0_ASSERTION;
2751
2752 /*
2753 * A forced switch to ring 0 for preemption purposes.
2754 */
2755 case VMMCALLRING3_VM_R0_PREEMPT:
2756 pVCpu->vmm.s.rcCallRing3 = VINF_SUCCESS;
2757 break;
2758
2759 case VMMCALLRING3_FTM_SET_CHECKPOINT:
2760 pVCpu->vmm.s.rcCallRing3 = FTMR3SetCheckpoint(pVM, (FTMCHECKPOINTTYPE)pVCpu->vmm.s.u64CallRing3Arg);
2761 break;
2762
2763 default:
2764 AssertMsgFailed(("enmCallRing3Operation=%d\n", pVCpu->vmm.s.enmCallRing3Operation));
2765 return VERR_VMM_UNKNOWN_RING3_CALL;
2766 }
2767
2768 pVCpu->vmm.s.enmCallRing3Operation = VMMCALLRING3_INVALID;
2769 return VINF_SUCCESS;
2770}
2771
2772
2773/**
2774 * Displays the Force action Flags.
2775 *
2776 * @param pVM The cross context VM structure.
2777 * @param pHlp The output helpers.
2778 * @param pszArgs The additional arguments (ignored).
2779 */
2780static DECLCALLBACK(void) vmmR3InfoFF(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
2781{
2782 int c;
2783 uint32_t f;
2784 NOREF(pszArgs);
2785
2786#define PRINT_FLAG(prf,flag) do { \
2787 if (f & (prf##flag)) \
2788 { \
2789 static const char *s_psz = #flag; \
2790 if (!(c % 6)) \
2791 pHlp->pfnPrintf(pHlp, "%s\n %s", c ? "," : "", s_psz); \
2792 else \
2793 pHlp->pfnPrintf(pHlp, ", %s", s_psz); \
2794 c++; \
2795 f &= ~(prf##flag); \
2796 } \
2797 } while (0)
2798
2799#define PRINT_GROUP(prf,grp,sfx) do { \
2800 if (f & (prf##grp##sfx)) \
2801 { \
2802 static const char *s_psz = #grp; \
2803 if (!(c % 5)) \
2804 pHlp->pfnPrintf(pHlp, "%s %s", c ? ",\n" : " Groups:\n", s_psz); \
2805 else \
2806 pHlp->pfnPrintf(pHlp, ", %s", s_psz); \
2807 c++; \
2808 } \
2809 } while (0)
2810
2811 /*
2812 * The global flags.
2813 */
2814 const uint32_t fGlobalForcedActions = pVM->fGlobalForcedActions;
2815 pHlp->pfnPrintf(pHlp, "Global FFs: %#RX32", fGlobalForcedActions);
2816
2817 /* show the flag mnemonics */
2818 c = 0;
2819 f = fGlobalForcedActions;
2820 PRINT_FLAG(VM_FF_,TM_VIRTUAL_SYNC);
2821 PRINT_FLAG(VM_FF_,PDM_QUEUES);
2822 PRINT_FLAG(VM_FF_,PDM_DMA);
2823 PRINT_FLAG(VM_FF_,DBGF);
2824 PRINT_FLAG(VM_FF_,REQUEST);
2825 PRINT_FLAG(VM_FF_,CHECK_VM_STATE);
2826 PRINT_FLAG(VM_FF_,RESET);
2827 PRINT_FLAG(VM_FF_,EMT_RENDEZVOUS);
2828 PRINT_FLAG(VM_FF_,PGM_NEED_HANDY_PAGES);
2829 PRINT_FLAG(VM_FF_,PGM_NO_MEMORY);
2830 PRINT_FLAG(VM_FF_,PGM_POOL_FLUSH_PENDING);
2831 PRINT_FLAG(VM_FF_,REM_HANDLER_NOTIFY);
2832 PRINT_FLAG(VM_FF_,DEBUG_SUSPEND);
2833 if (f)
2834 pHlp->pfnPrintf(pHlp, "%s\n Unknown bits: %#RX32\n", c ? "," : "", f);
2835 else
2836 pHlp->pfnPrintf(pHlp, "\n");
2837
2838 /* the groups */
2839 c = 0;
2840 f = fGlobalForcedActions;
2841 PRINT_GROUP(VM_FF_,EXTERNAL_SUSPENDED,_MASK);
2842 PRINT_GROUP(VM_FF_,EXTERNAL_HALTED,_MASK);
2843 PRINT_GROUP(VM_FF_,HIGH_PRIORITY_PRE,_MASK);
2844 PRINT_GROUP(VM_FF_,HIGH_PRIORITY_PRE_RAW,_MASK);
2845 PRINT_GROUP(VM_FF_,HIGH_PRIORITY_POST,_MASK);
2846 PRINT_GROUP(VM_FF_,NORMAL_PRIORITY_POST,_MASK);
2847 PRINT_GROUP(VM_FF_,NORMAL_PRIORITY,_MASK);
2848 PRINT_GROUP(VM_FF_,ALL_REM,_MASK);
2849 if (c)
2850 pHlp->pfnPrintf(pHlp, "\n");
2851
2852 /*
2853 * Per CPU flags.
2854 */
2855 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2856 {
2857 const uint32_t fLocalForcedActions = pVM->aCpus[i].fLocalForcedActions;
2858 pHlp->pfnPrintf(pHlp, "CPU %u FFs: %#RX32", i, fLocalForcedActions);
2859
2860 /* show the flag mnemonics */
2861 c = 0;
2862 f = fLocalForcedActions;
2863 PRINT_FLAG(VMCPU_FF_,INTERRUPT_APIC);
2864 PRINT_FLAG(VMCPU_FF_,INTERRUPT_PIC);
2865 PRINT_FLAG(VMCPU_FF_,TIMER);
2866 PRINT_FLAG(VMCPU_FF_,INTERRUPT_NMI);
2867 PRINT_FLAG(VMCPU_FF_,INTERRUPT_SMI);
2868 PRINT_FLAG(VMCPU_FF_,PDM_CRITSECT);
2869 PRINT_FLAG(VMCPU_FF_,UNHALT);
2870 PRINT_FLAG(VMCPU_FF_,IEM);
2871 PRINT_FLAG(VMCPU_FF_,UPDATE_APIC);
2872 PRINT_FLAG(VMCPU_FF_,DBGF);
2873 PRINT_FLAG(VMCPU_FF_,REQUEST);
2874 PRINT_FLAG(VMCPU_FF_,HM_UPDATE_CR3);
2875 PRINT_FLAG(VMCPU_FF_,HM_UPDATE_PAE_PDPES);
2876 PRINT_FLAG(VMCPU_FF_,PGM_SYNC_CR3);
2877 PRINT_FLAG(VMCPU_FF_,PGM_SYNC_CR3_NON_GLOBAL);
2878 PRINT_FLAG(VMCPU_FF_,TLB_FLUSH);
2879 PRINT_FLAG(VMCPU_FF_,INHIBIT_INTERRUPTS);
2880 PRINT_FLAG(VMCPU_FF_,BLOCK_NMIS);
2881 PRINT_FLAG(VMCPU_FF_,TO_R3);
2882 PRINT_FLAG(VMCPU_FF_,IOM);
2883#ifdef VBOX_WITH_RAW_MODE
2884 PRINT_FLAG(VMCPU_FF_,TRPM_SYNC_IDT);
2885 PRINT_FLAG(VMCPU_FF_,SELM_SYNC_TSS);
2886 PRINT_FLAG(VMCPU_FF_,SELM_SYNC_GDT);
2887 PRINT_FLAG(VMCPU_FF_,SELM_SYNC_LDT);
2888 PRINT_FLAG(VMCPU_FF_,CSAM_SCAN_PAGE);
2889 PRINT_FLAG(VMCPU_FF_,CSAM_PENDING_ACTION);
2890 PRINT_FLAG(VMCPU_FF_,CPUM);
2891#endif
2892 if (f)
2893 pHlp->pfnPrintf(pHlp, "%s\n Unknown bits: %#RX32\n", c ? "," : "", f);
2894 else
2895 pHlp->pfnPrintf(pHlp, "\n");
2896
2897 if (fLocalForcedActions & VMCPU_FF_INHIBIT_INTERRUPTS)
2898 pHlp->pfnPrintf(pHlp, " intr inhibit RIP: %RGp\n", EMGetInhibitInterruptsPC(&pVM->aCpus[i]));
2899
2900 /* the groups */
2901 c = 0;
2902 f = fLocalForcedActions;
2903 PRINT_GROUP(VMCPU_FF_,EXTERNAL_SUSPENDED,_MASK);
2904 PRINT_GROUP(VMCPU_FF_,EXTERNAL_HALTED,_MASK);
2905 PRINT_GROUP(VMCPU_FF_,HIGH_PRIORITY_PRE,_MASK);
2906 PRINT_GROUP(VMCPU_FF_,HIGH_PRIORITY_PRE_RAW,_MASK);
2907 PRINT_GROUP(VMCPU_FF_,HIGH_PRIORITY_POST,_MASK);
2908 PRINT_GROUP(VMCPU_FF_,NORMAL_PRIORITY_POST,_MASK);
2909 PRINT_GROUP(VMCPU_FF_,NORMAL_PRIORITY,_MASK);
2910 PRINT_GROUP(VMCPU_FF_,RESUME_GUEST,_MASK);
2911 PRINT_GROUP(VMCPU_FF_,HM_TO_R3,_MASK);
2912 PRINT_GROUP(VMCPU_FF_,ALL_REM,_MASK);
2913 if (c)
2914 pHlp->pfnPrintf(pHlp, "\n");
2915 }
2916
2917#undef PRINT_FLAG
2918#undef PRINT_GROUP
2919}
2920
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