VirtualBox

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

Last change on this file since 72064 was 71222, checked in by vboxsync, 7 years ago

NEM/win,VMM,PGM: Ported NEM runloop to ring-0. bugref:9044

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 114.6 KB
Line 
1/* $Id: VMM.cpp 71222 2018-03-05 22:07:48Z 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 (VM_IS_RAW_MODE_ENABLED(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 (VM_IS_RAW_MODE_ENABLED(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 (VM_IS_RAW_MODE_ENABLED(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 * Worker for VMMR3InitR0 that calls ring-0 to do EMT specific initialization.
531 *
532 * @returns VBox status code.
533 * @param pVM The cross context VM structure.
534 * @param pVCpu The cross context per CPU structure.
535 * @thread EMT(pVCpu)
536 */
537static DECLCALLBACK(int) vmmR3InitR0Emt(PVM pVM, PVMCPU pVCpu)
538{
539 return VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_VMMR0_INIT_EMT, 0, NULL);
540}
541
542
543/**
544 * Initializes the R0 VMM.
545 *
546 * @returns VBox status code.
547 * @param pVM The cross context VM structure.
548 */
549VMMR3_INT_DECL(int) VMMR3InitR0(PVM pVM)
550{
551 int rc;
552 PVMCPU pVCpu = VMMGetCpu(pVM);
553 Assert(pVCpu && pVCpu->idCpu == 0);
554
555#ifdef LOG_ENABLED
556 /*
557 * Initialize the ring-0 logger if we haven't done so yet.
558 */
559 if ( pVCpu->vmm.s.pR0LoggerR3
560 && !pVCpu->vmm.s.pR0LoggerR3->fCreated)
561 {
562 rc = VMMR3UpdateLoggers(pVM);
563 if (RT_FAILURE(rc))
564 return rc;
565 }
566#endif
567
568 /*
569 * Call Ring-0 entry with init code.
570 */
571 for (;;)
572 {
573#ifdef NO_SUPCALLR0VMM
574 //rc = VERR_GENERAL_FAILURE;
575 rc = VINF_SUCCESS;
576#else
577 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, 0 /*idCpu*/, VMMR0_DO_VMMR0_INIT, RT_MAKE_U64(VMMGetSvnRev(), vmmGetBuildType()), NULL);
578#endif
579 /*
580 * Flush the logs.
581 */
582#ifdef LOG_ENABLED
583 if ( pVCpu->vmm.s.pR0LoggerR3
584 && pVCpu->vmm.s.pR0LoggerR3->Logger.offScratch > 0)
585 RTLogFlushR0(NULL, &pVCpu->vmm.s.pR0LoggerR3->Logger);
586#endif
587 if (rc != VINF_VMM_CALL_HOST)
588 break;
589 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
590 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
591 break;
592 /* Resume R0 */
593 }
594
595 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
596 {
597 LogRel(("VMM: R0 init failed, rc=%Rra\n", rc));
598 if (RT_SUCCESS(rc))
599 rc = VERR_IPE_UNEXPECTED_INFO_STATUS;
600 }
601
602 /* Log whether thread-context hooks are used (on Linux this can depend on how the kernel is configured). */
603 if (pVM->aCpus[0].vmm.s.hCtxHook != NIL_RTTHREADCTXHOOK)
604 LogRel(("VMM: Enabled thread-context hooks\n"));
605 else
606 LogRel(("VMM: Thread-context hooks unavailable\n"));
607
608 /*
609 * Send all EMTs to ring-0 to get their logger initialized.
610 */
611 for (VMCPUID idCpu = 0; RT_SUCCESS(rc) && idCpu < pVM->cCpus; idCpu++)
612 rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)vmmR3InitR0Emt, 2, pVM, &pVM->aCpus[idCpu]);
613
614 return rc;
615}
616
617
618#ifdef VBOX_WITH_RAW_MODE
619/**
620 * Initializes the RC VMM.
621 *
622 * @returns VBox status code.
623 * @param pVM The cross context VM structure.
624 */
625VMMR3_INT_DECL(int) VMMR3InitRC(PVM pVM)
626{
627 PVMCPU pVCpu = VMMGetCpu(pVM);
628 Assert(pVCpu && pVCpu->idCpu == 0);
629
630 /* In VMX mode, there's no need to init RC. */
631 if (!VM_IS_RAW_MODE_ENABLED(pVM))
632 return VINF_SUCCESS;
633
634 AssertReturn(pVM->cCpus == 1, VERR_RAW_MODE_INVALID_SMP);
635
636 /*
637 * Call VMMRCInit():
638 * -# resolve the address.
639 * -# setup stackframe and EIP to use the trampoline.
640 * -# do a generic hypervisor call.
641 */
642 RTRCPTR RCPtrEP;
643 int rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "VMMRCEntry", &RCPtrEP);
644 if (RT_SUCCESS(rc))
645 {
646 CPUMSetHyperESP(pVCpu, pVCpu->vmm.s.pbEMTStackBottomRC); /* Clear the stack. */
647 uint64_t u64TS = RTTimeProgramStartNanoTS();
648 CPUMPushHyper(pVCpu, RT_HI_U32(u64TS)); /* Param 4: The program startup TS - Hi. */
649 CPUMPushHyper(pVCpu, RT_LO_U32(u64TS)); /* Param 4: The program startup TS - Lo. */
650 CPUMPushHyper(pVCpu, vmmGetBuildType()); /* Param 3: Version argument. */
651 CPUMPushHyper(pVCpu, VMMGetSvnRev()); /* Param 2: Version argument. */
652 CPUMPushHyper(pVCpu, VMMRC_DO_VMMRC_INIT); /* Param 1: Operation. */
653 CPUMPushHyper(pVCpu, pVM->pVMRC); /* Param 0: pVM */
654 CPUMPushHyper(pVCpu, 6 * sizeof(RTRCPTR)); /* trampoline param: stacksize. */
655 CPUMPushHyper(pVCpu, RCPtrEP); /* Call EIP. */
656 CPUMSetHyperEIP(pVCpu, pVM->vmm.s.pfnCallTrampolineRC);
657 Assert(CPUMGetHyperCR3(pVCpu) && CPUMGetHyperCR3(pVCpu) == PGMGetHyperCR3(pVCpu));
658
659 for (;;)
660 {
661#ifdef NO_SUPCALLR0VMM
662 //rc = VERR_GENERAL_FAILURE;
663 rc = VINF_SUCCESS;
664#else
665 rc = SUPR3CallVMMR0(pVM->pVMR0, 0 /* VCPU 0 */, VMMR0_DO_CALL_HYPERVISOR, NULL);
666#endif
667#ifdef LOG_ENABLED
668 PRTLOGGERRC pLogger = pVM->vmm.s.pRCLoggerR3;
669 if ( pLogger
670 && pLogger->offScratch > 0)
671 RTLogFlushRC(NULL, pLogger);
672#endif
673#ifdef VBOX_WITH_RC_RELEASE_LOGGING
674 PRTLOGGERRC pRelLogger = pVM->vmm.s.pRCRelLoggerR3;
675 if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
676 RTLogFlushRC(RTLogRelGetDefaultInstance(), pRelLogger);
677#endif
678 if (rc != VINF_VMM_CALL_HOST)
679 break;
680 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
681 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
682 break;
683 }
684
685 /* Don't trigger assertions or guru if raw-mode is unavailable. */
686 if (rc != VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT)
687 {
688 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
689 {
690 VMMR3FatalDump(pVM, pVCpu, rc);
691 if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
692 rc = VERR_IPE_UNEXPECTED_INFO_STATUS;
693 }
694 AssertRC(rc);
695 }
696 }
697 return rc;
698}
699#endif /* VBOX_WITH_RAW_MODE */
700
701
702/**
703 * Called when an init phase completes.
704 *
705 * @returns VBox status code.
706 * @param pVM The cross context VM structure.
707 * @param enmWhat Which init phase.
708 */
709VMMR3_INT_DECL(int) VMMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
710{
711 int rc = VINF_SUCCESS;
712
713 switch (enmWhat)
714 {
715 case VMINITCOMPLETED_RING3:
716 {
717 /*
718 * Set page attributes to r/w for stack pages.
719 */
720 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
721 {
722 rc = PGMMapSetPage(pVM, pVM->aCpus[idCpu].vmm.s.pbEMTStackRC, VMM_STACK_SIZE,
723 X86_PTE_P | X86_PTE_A | X86_PTE_D | X86_PTE_RW);
724 AssertRCReturn(rc, rc);
725 }
726
727 /*
728 * Create the EMT yield timer.
729 */
730 rc = TMR3TimerCreateInternal(pVM, TMCLOCK_REAL, vmmR3YieldEMT, NULL, "EMT Yielder", &pVM->vmm.s.pYieldTimer);
731 AssertRCReturn(rc, rc);
732
733 rc = TMTimerSetMillies(pVM->vmm.s.pYieldTimer, pVM->vmm.s.cYieldEveryMillies);
734 AssertRCReturn(rc, rc);
735
736#ifdef VBOX_WITH_NMI
737 /*
738 * Map the host APIC into GC - This is AMD/Intel + Host OS specific!
739 */
740 rc = PGMMap(pVM, pVM->vmm.s.GCPtrApicBase, 0xfee00000, PAGE_SIZE,
741 X86_PTE_P | X86_PTE_RW | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_A | X86_PTE_D);
742 AssertRCReturn(rc, rc);
743#endif
744
745#ifdef VBOX_STRICT_VMM_STACK
746 /*
747 * Setup the stack guard pages: Two inaccessible pages at each sides of the
748 * stack to catch over/under-flows.
749 */
750 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
751 {
752 uint8_t *pbEMTStackR3 = pVM->aCpus[idCpu].vmm.s.pbEMTStackR3;
753
754 memset(pbEMTStackR3 - PAGE_SIZE, 0xcc, PAGE_SIZE);
755 MMR3HyperSetGuard(pVM, pbEMTStackR3 - PAGE_SIZE, PAGE_SIZE, true /*fSet*/);
756
757 memset(pbEMTStackR3 + VMM_STACK_SIZE, 0xcc, PAGE_SIZE);
758 MMR3HyperSetGuard(pVM, pbEMTStackR3 + VMM_STACK_SIZE, PAGE_SIZE, true /*fSet*/);
759 }
760 pVM->vmm.s.fStackGuardsStationed = true;
761#endif
762 break;
763 }
764
765 case VMINITCOMPLETED_HM:
766 {
767 /*
768 * Disable the periodic preemption timers if we can use the
769 * VMX-preemption timer instead.
770 */
771 if ( pVM->vmm.s.fUsePeriodicPreemptionTimers
772 && HMR3IsVmxPreemptionTimerUsed(pVM))
773 pVM->vmm.s.fUsePeriodicPreemptionTimers = false;
774 LogRel(("VMM: fUsePeriodicPreemptionTimers=%RTbool\n", pVM->vmm.s.fUsePeriodicPreemptionTimers));
775
776 /*
777 * Last chance for GIM to update its CPUID leaves if it requires
778 * knowledge/information from HM initialization.
779 */
780 rc = GIMR3InitCompleted(pVM);
781 AssertRCReturn(rc, rc);
782
783 /*
784 * CPUM's post-initialization (print CPUIDs).
785 */
786 CPUMR3LogCpuIds(pVM);
787 break;
788 }
789
790 default: /* shuts up gcc */
791 break;
792 }
793
794 return rc;
795}
796
797
798/**
799 * Terminate the VMM bits.
800 *
801 * @returns VBox status code.
802 * @param pVM The cross context VM structure.
803 */
804VMMR3_INT_DECL(int) VMMR3Term(PVM pVM)
805{
806 PVMCPU pVCpu = VMMGetCpu(pVM);
807 Assert(pVCpu && pVCpu->idCpu == 0);
808
809 /*
810 * Call Ring-0 entry with termination code.
811 */
812 int rc;
813 for (;;)
814 {
815#ifdef NO_SUPCALLR0VMM
816 //rc = VERR_GENERAL_FAILURE;
817 rc = VINF_SUCCESS;
818#else
819 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, 0 /*idCpu*/, VMMR0_DO_VMMR0_TERM, 0, NULL);
820#endif
821 /*
822 * Flush the logs.
823 */
824#ifdef LOG_ENABLED
825 if ( pVCpu->vmm.s.pR0LoggerR3
826 && pVCpu->vmm.s.pR0LoggerR3->Logger.offScratch > 0)
827 RTLogFlushR0(NULL, &pVCpu->vmm.s.pR0LoggerR3->Logger);
828#endif
829 if (rc != VINF_VMM_CALL_HOST)
830 break;
831 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
832 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
833 break;
834 /* Resume R0 */
835 }
836 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
837 {
838 LogRel(("VMM: VMMR3Term: R0 term failed, rc=%Rra. (warning)\n", rc));
839 if (RT_SUCCESS(rc))
840 rc = VERR_IPE_UNEXPECTED_INFO_STATUS;
841 }
842
843 for (VMCPUID i = 0; i < pVM->cCpus; i++)
844 {
845 RTSemEventDestroy(pVM->vmm.s.pahEvtRendezvousEnterOrdered[i]);
846 pVM->vmm.s.pahEvtRendezvousEnterOrdered[i] = NIL_RTSEMEVENT;
847 }
848 RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousEnterOneByOne);
849 pVM->vmm.s.hEvtRendezvousEnterOneByOne = NIL_RTSEMEVENT;
850 RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);
851 pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce = NIL_RTSEMEVENTMULTI;
852 RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousDone);
853 pVM->vmm.s.hEvtMulRendezvousDone = NIL_RTSEMEVENTMULTI;
854 RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousDoneCaller);
855 pVM->vmm.s.hEvtRendezvousDoneCaller = NIL_RTSEMEVENT;
856 RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousRecursionPush);
857 pVM->vmm.s.hEvtMulRendezvousRecursionPush = NIL_RTSEMEVENTMULTI;
858 RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousRecursionPop);
859 pVM->vmm.s.hEvtMulRendezvousRecursionPop = NIL_RTSEMEVENTMULTI;
860 RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
861 pVM->vmm.s.hEvtRendezvousRecursionPushCaller = NIL_RTSEMEVENT;
862 RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
863 pVM->vmm.s.hEvtRendezvousRecursionPopCaller = NIL_RTSEMEVENT;
864
865#ifdef VBOX_STRICT_VMM_STACK
866 /*
867 * Make the two stack guard pages present again.
868 */
869 if (pVM->vmm.s.fStackGuardsStationed)
870 {
871 for (VMCPUID i = 0; i < pVM->cCpus; i++)
872 {
873 uint8_t *pbEMTStackR3 = pVM->aCpus[i].vmm.s.pbEMTStackR3;
874 MMR3HyperSetGuard(pVM, pbEMTStackR3 - PAGE_SIZE, PAGE_SIZE, false /*fSet*/);
875 MMR3HyperSetGuard(pVM, pbEMTStackR3 + VMM_STACK_SIZE, PAGE_SIZE, false /*fSet*/);
876 }
877 pVM->vmm.s.fStackGuardsStationed = false;
878 }
879#endif
880
881 vmmTermFormatTypes();
882 return rc;
883}
884
885
886/**
887 * Applies relocations to data and code managed by this
888 * component. This function will be called at init and
889 * whenever the VMM need to relocate it self inside the GC.
890 *
891 * The VMM will need to apply relocations to the core code.
892 *
893 * @param pVM The cross context VM structure.
894 * @param offDelta The relocation delta.
895 */
896VMMR3_INT_DECL(void) VMMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
897{
898 LogFlow(("VMMR3Relocate: offDelta=%RGv\n", offDelta));
899
900 /*
901 * Recalc the RC address.
902 */
903#ifdef VBOX_WITH_RAW_MODE
904 pVM->vmm.s.pvCoreCodeRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pvCoreCodeR3);
905#endif
906
907 /*
908 * The stack.
909 */
910 for (VMCPUID i = 0; i < pVM->cCpus; i++)
911 {
912 PVMCPU pVCpu = &pVM->aCpus[i];
913
914 CPUMSetHyperESP(pVCpu, CPUMGetHyperESP(pVCpu) + offDelta);
915
916 pVCpu->vmm.s.pbEMTStackRC = MMHyperR3ToRC(pVM, pVCpu->vmm.s.pbEMTStackR3);
917 pVCpu->vmm.s.pbEMTStackBottomRC = pVCpu->vmm.s.pbEMTStackRC + VMM_STACK_SIZE;
918 }
919
920 /*
921 * All the switchers.
922 */
923 vmmR3SwitcherRelocate(pVM, offDelta);
924
925 /*
926 * Get other RC entry points.
927 */
928 if (VM_IS_RAW_MODE_ENABLED(pVM))
929 {
930 int rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "CPUMGCResumeGuest", &pVM->vmm.s.pfnCPUMRCResumeGuest);
931 AssertReleaseMsgRC(rc, ("CPUMGCResumeGuest not found! rc=%Rra\n", rc));
932
933 rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "CPUMGCResumeGuestV86", &pVM->vmm.s.pfnCPUMRCResumeGuestV86);
934 AssertReleaseMsgRC(rc, ("CPUMGCResumeGuestV86 not found! rc=%Rra\n", rc));
935 }
936
937 /*
938 * Update the logger.
939 */
940 VMMR3UpdateLoggers(pVM);
941}
942
943
944/**
945 * Updates the settings for the RC and R0 loggers.
946 *
947 * @returns VBox status code.
948 * @param pVM The cross context VM structure.
949 */
950VMMR3_INT_DECL(int) VMMR3UpdateLoggers(PVM pVM)
951{
952 /*
953 * Simply clone the logger instance (for RC).
954 */
955 int rc = VINF_SUCCESS;
956 RTRCPTR RCPtrLoggerFlush = 0;
957
958 if ( pVM->vmm.s.pRCLoggerR3
959#ifdef VBOX_WITH_RC_RELEASE_LOGGING
960 || pVM->vmm.s.pRCRelLoggerR3
961#endif
962 )
963 {
964 Assert(VM_IS_RAW_MODE_ENABLED(pVM));
965 rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "vmmGCLoggerFlush", &RCPtrLoggerFlush);
966 AssertReleaseMsgRC(rc, ("vmmGCLoggerFlush not found! rc=%Rra\n", rc));
967 }
968
969 if (pVM->vmm.s.pRCLoggerR3)
970 {
971 Assert(VM_IS_RAW_MODE_ENABLED(pVM));
972 RTRCPTR RCPtrLoggerWrapper = 0;
973 rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "vmmGCLoggerWrapper", &RCPtrLoggerWrapper);
974 AssertReleaseMsgRC(rc, ("vmmGCLoggerWrapper not found! rc=%Rra\n", rc));
975
976 pVM->vmm.s.pRCLoggerRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pRCLoggerR3);
977 rc = RTLogCloneRC(NULL /* default */, pVM->vmm.s.pRCLoggerR3, pVM->vmm.s.cbRCLogger,
978 RCPtrLoggerWrapper, RCPtrLoggerFlush, RTLOGFLAGS_BUFFERED);
979 AssertReleaseMsgRC(rc, ("RTLogCloneRC failed! rc=%Rra\n", rc));
980 }
981
982#ifdef VBOX_WITH_RC_RELEASE_LOGGING
983 if (pVM->vmm.s.pRCRelLoggerR3)
984 {
985 Assert(VM_IS_RAW_MODE_ENABLED(pVM));
986 RTRCPTR RCPtrLoggerWrapper = 0;
987 rc = PDMR3LdrGetSymbolRC(pVM, VMMRC_MAIN_MODULE_NAME, "vmmGCRelLoggerWrapper", &RCPtrLoggerWrapper);
988 AssertReleaseMsgRC(rc, ("vmmGCRelLoggerWrapper not found! rc=%Rra\n", rc));
989
990 pVM->vmm.s.pRCRelLoggerRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pRCRelLoggerR3);
991 rc = RTLogCloneRC(RTLogRelGetDefaultInstance(), pVM->vmm.s.pRCRelLoggerR3, pVM->vmm.s.cbRCRelLogger,
992 RCPtrLoggerWrapper, RCPtrLoggerFlush, RTLOGFLAGS_BUFFERED);
993 AssertReleaseMsgRC(rc, ("RTLogCloneRC failed! rc=%Rra\n", rc));
994 }
995#endif /* VBOX_WITH_RC_RELEASE_LOGGING */
996
997#ifdef LOG_ENABLED
998 /*
999 * For the ring-0 EMT logger, we use a per-thread logger instance
1000 * in ring-0. Only initialize it once.
1001 */
1002 PRTLOGGER const pDefault = RTLogDefaultInstance();
1003 for (VMCPUID i = 0; i < pVM->cCpus; i++)
1004 {
1005 PVMCPU pVCpu = &pVM->aCpus[i];
1006 PVMMR0LOGGER pR0LoggerR3 = pVCpu->vmm.s.pR0LoggerR3;
1007 if (pR0LoggerR3)
1008 {
1009 if (!pR0LoggerR3->fCreated)
1010 {
1011 RTR0PTR pfnLoggerWrapper = NIL_RTR0PTR;
1012 rc = PDMR3LdrGetSymbolR0(pVM, VMMR0_MAIN_MODULE_NAME, "vmmR0LoggerWrapper", &pfnLoggerWrapper);
1013 AssertReleaseMsgRCReturn(rc, ("vmmR0LoggerWrapper not found! rc=%Rra\n", rc), rc);
1014
1015 RTR0PTR pfnLoggerFlush = NIL_RTR0PTR;
1016 rc = PDMR3LdrGetSymbolR0(pVM, VMMR0_MAIN_MODULE_NAME, "vmmR0LoggerFlush", &pfnLoggerFlush);
1017 AssertReleaseMsgRCReturn(rc, ("vmmR0LoggerFlush not found! rc=%Rra\n", rc), rc);
1018
1019 rc = RTLogCreateForR0(&pR0LoggerR3->Logger, pR0LoggerR3->cbLogger,
1020 pVCpu->vmm.s.pR0LoggerR0 + RT_OFFSETOF(VMMR0LOGGER, Logger),
1021 pfnLoggerWrapper, pfnLoggerFlush,
1022 RTLOGFLAGS_BUFFERED, RTLOGDEST_DUMMY);
1023 AssertReleaseMsgRCReturn(rc, ("RTLogCreateForR0 failed! rc=%Rra\n", rc), rc);
1024
1025 RTR0PTR pfnLoggerPrefix = NIL_RTR0PTR;
1026 rc = PDMR3LdrGetSymbolR0(pVM, VMMR0_MAIN_MODULE_NAME, "vmmR0LoggerPrefix", &pfnLoggerPrefix);
1027 AssertReleaseMsgRCReturn(rc, ("vmmR0LoggerPrefix not found! rc=%Rra\n", rc), rc);
1028 rc = RTLogSetCustomPrefixCallbackForR0(&pR0LoggerR3->Logger,
1029 pVCpu->vmm.s.pR0LoggerR0 + RT_OFFSETOF(VMMR0LOGGER, Logger),
1030 pfnLoggerPrefix, NIL_RTR0PTR);
1031 AssertReleaseMsgRCReturn(rc, ("RTLogSetCustomPrefixCallback failed! rc=%Rra\n", rc), rc);
1032
1033 pR0LoggerR3->idCpu = i;
1034 pR0LoggerR3->fCreated = true;
1035 pR0LoggerR3->fFlushingDisabled = false;
1036
1037 }
1038
1039 rc = RTLogCopyGroupsAndFlagsForR0(&pR0LoggerR3->Logger, pVCpu->vmm.s.pR0LoggerR0 + RT_OFFSETOF(VMMR0LOGGER, Logger),
1040 pDefault, RTLOGFLAGS_BUFFERED, UINT32_MAX);
1041 AssertRC(rc);
1042 }
1043 }
1044#endif
1045 return rc;
1046}
1047
1048
1049/**
1050 * Gets the pointer to a buffer containing the R0/RC RTAssertMsg1Weak output.
1051 *
1052 * @returns Pointer to the buffer.
1053 * @param pVM The cross context VM structure.
1054 */
1055VMMR3DECL(const char *) VMMR3GetRZAssertMsg1(PVM pVM)
1056{
1057 if (!VM_IS_RAW_MODE_ENABLED(pVM))
1058 return pVM->vmm.s.szRing0AssertMsg1;
1059
1060 RTRCPTR RCPtr;
1061 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_szRTAssertMsg1", &RCPtr);
1062 if (RT_SUCCESS(rc))
1063 return (const char *)MMHyperRCToR3(pVM, RCPtr);
1064
1065 return NULL;
1066}
1067
1068
1069/**
1070 * Returns the VMCPU of the specified virtual CPU.
1071 *
1072 * @returns The VMCPU pointer. NULL if @a idCpu or @a pUVM is invalid.
1073 *
1074 * @param pUVM The user mode VM handle.
1075 * @param idCpu The ID of the virtual CPU.
1076 */
1077VMMR3DECL(PVMCPU) VMMR3GetCpuByIdU(PUVM pUVM, RTCPUID idCpu)
1078{
1079 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
1080 AssertReturn(idCpu < pUVM->cCpus, NULL);
1081 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
1082 return &pUVM->pVM->aCpus[idCpu];
1083}
1084
1085
1086/**
1087 * Gets the pointer to a buffer containing the R0/RC RTAssertMsg2Weak output.
1088 *
1089 * @returns Pointer to the buffer.
1090 * @param pVM The cross context VM structure.
1091 */
1092VMMR3DECL(const char *) VMMR3GetRZAssertMsg2(PVM pVM)
1093{
1094 if (!VM_IS_RAW_MODE_ENABLED(pVM))
1095 return pVM->vmm.s.szRing0AssertMsg2;
1096
1097 RTRCPTR RCPtr;
1098 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_szRTAssertMsg2", &RCPtr);
1099 if (RT_SUCCESS(rc))
1100 return (const char *)MMHyperRCToR3(pVM, RCPtr);
1101
1102 return NULL;
1103}
1104
1105
1106/**
1107 * Execute state save operation.
1108 *
1109 * @returns VBox status code.
1110 * @param pVM The cross context VM structure.
1111 * @param pSSM SSM operation handle.
1112 */
1113static DECLCALLBACK(int) vmmR3Save(PVM pVM, PSSMHANDLE pSSM)
1114{
1115 LogFlow(("vmmR3Save:\n"));
1116
1117 /*
1118 * Save the started/stopped state of all CPUs except 0 as it will always
1119 * be running. This avoids breaking the saved state version. :-)
1120 */
1121 for (VMCPUID i = 1; i < pVM->cCpus; i++)
1122 SSMR3PutBool(pSSM, VMCPUSTATE_IS_STARTED(VMCPU_GET_STATE(&pVM->aCpus[i])));
1123
1124 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
1125}
1126
1127
1128/**
1129 * Execute state load operation.
1130 *
1131 * @returns VBox status code.
1132 * @param pVM The cross context VM structure.
1133 * @param pSSM SSM operation handle.
1134 * @param uVersion Data layout version.
1135 * @param uPass The data pass.
1136 */
1137static DECLCALLBACK(int) vmmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1138{
1139 LogFlow(("vmmR3Load:\n"));
1140 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1141
1142 /*
1143 * Validate version.
1144 */
1145 if ( uVersion != VMM_SAVED_STATE_VERSION
1146 && uVersion != VMM_SAVED_STATE_VERSION_3_0)
1147 {
1148 AssertMsgFailed(("vmmR3Load: Invalid version uVersion=%u!\n", uVersion));
1149 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1150 }
1151
1152 if (uVersion <= VMM_SAVED_STATE_VERSION_3_0)
1153 {
1154 /* Ignore the stack bottom, stack pointer and stack bits. */
1155 RTRCPTR RCPtrIgnored;
1156 SSMR3GetRCPtr(pSSM, &RCPtrIgnored);
1157 SSMR3GetRCPtr(pSSM, &RCPtrIgnored);
1158#ifdef RT_OS_DARWIN
1159 if ( SSMR3HandleVersion(pSSM) >= VBOX_FULL_VERSION_MAKE(3,0,0)
1160 && SSMR3HandleVersion(pSSM) < VBOX_FULL_VERSION_MAKE(3,1,0)
1161 && SSMR3HandleRevision(pSSM) >= 48858
1162 && ( !strcmp(SSMR3HandleHostOSAndArch(pSSM), "darwin.x86")
1163 || !strcmp(SSMR3HandleHostOSAndArch(pSSM), "") )
1164 )
1165 SSMR3Skip(pSSM, 16384);
1166 else
1167 SSMR3Skip(pSSM, 8192);
1168#else
1169 SSMR3Skip(pSSM, 8192);
1170#endif
1171 }
1172
1173 /*
1174 * Restore the VMCPU states. VCPU 0 is always started.
1175 */
1176 VMCPU_SET_STATE(&pVM->aCpus[0], VMCPUSTATE_STARTED);
1177 for (VMCPUID i = 1; i < pVM->cCpus; i++)
1178 {
1179 bool fStarted;
1180 int rc = SSMR3GetBool(pSSM, &fStarted);
1181 if (RT_FAILURE(rc))
1182 return rc;
1183 VMCPU_SET_STATE(&pVM->aCpus[i], fStarted ? VMCPUSTATE_STARTED : VMCPUSTATE_STOPPED);
1184 }
1185
1186 /* terminator */
1187 uint32_t u32;
1188 int rc = SSMR3GetU32(pSSM, &u32);
1189 if (RT_FAILURE(rc))
1190 return rc;
1191 if (u32 != UINT32_MAX)
1192 {
1193 AssertMsgFailed(("u32=%#x\n", u32));
1194 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1195 }
1196 return VINF_SUCCESS;
1197}
1198
1199
1200#ifdef VBOX_WITH_RAW_MODE
1201/**
1202 * Resolve a builtin RC symbol.
1203 *
1204 * Called by PDM when loading or relocating RC modules.
1205 *
1206 * @returns VBox status
1207 * @param pVM The cross context VM structure.
1208 * @param pszSymbol Symbol to resolve.
1209 * @param pRCPtrValue Where to store the symbol value.
1210 *
1211 * @remark This has to work before VMMR3Relocate() is called.
1212 */
1213VMMR3_INT_DECL(int) VMMR3GetImportRC(PVM pVM, const char *pszSymbol, PRTRCPTR pRCPtrValue)
1214{
1215 if (!strcmp(pszSymbol, "g_Logger"))
1216 {
1217 if (pVM->vmm.s.pRCLoggerR3)
1218 pVM->vmm.s.pRCLoggerRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pRCLoggerR3);
1219 *pRCPtrValue = pVM->vmm.s.pRCLoggerRC;
1220 }
1221 else if (!strcmp(pszSymbol, "g_RelLogger"))
1222 {
1223# ifdef VBOX_WITH_RC_RELEASE_LOGGING
1224 if (pVM->vmm.s.pRCRelLoggerR3)
1225 pVM->vmm.s.pRCRelLoggerRC = MMHyperR3ToRC(pVM, pVM->vmm.s.pRCRelLoggerR3);
1226 *pRCPtrValue = pVM->vmm.s.pRCRelLoggerRC;
1227# else
1228 *pRCPtrValue = NIL_RTRCPTR;
1229# endif
1230 }
1231 else
1232 return VERR_SYMBOL_NOT_FOUND;
1233 return VINF_SUCCESS;
1234}
1235#endif /* VBOX_WITH_RAW_MODE */
1236
1237
1238/**
1239 * Suspends the CPU yielder.
1240 *
1241 * @param pVM The cross context VM structure.
1242 */
1243VMMR3_INT_DECL(void) VMMR3YieldSuspend(PVM pVM)
1244{
1245 VMCPU_ASSERT_EMT(&pVM->aCpus[0]);
1246 if (!pVM->vmm.s.cYieldResumeMillies)
1247 {
1248 uint64_t u64Now = TMTimerGet(pVM->vmm.s.pYieldTimer);
1249 uint64_t u64Expire = TMTimerGetExpire(pVM->vmm.s.pYieldTimer);
1250 if (u64Now >= u64Expire || u64Expire == ~(uint64_t)0)
1251 pVM->vmm.s.cYieldResumeMillies = pVM->vmm.s.cYieldEveryMillies;
1252 else
1253 pVM->vmm.s.cYieldResumeMillies = TMTimerToMilli(pVM->vmm.s.pYieldTimer, u64Expire - u64Now);
1254 TMTimerStop(pVM->vmm.s.pYieldTimer);
1255 }
1256 pVM->vmm.s.u64LastYield = RTTimeNanoTS();
1257}
1258
1259
1260/**
1261 * Stops the CPU yielder.
1262 *
1263 * @param pVM The cross context VM structure.
1264 */
1265VMMR3_INT_DECL(void) VMMR3YieldStop(PVM pVM)
1266{
1267 if (!pVM->vmm.s.cYieldResumeMillies)
1268 TMTimerStop(pVM->vmm.s.pYieldTimer);
1269 pVM->vmm.s.cYieldResumeMillies = pVM->vmm.s.cYieldEveryMillies;
1270 pVM->vmm.s.u64LastYield = RTTimeNanoTS();
1271}
1272
1273
1274/**
1275 * Resumes the CPU yielder when it has been a suspended or stopped.
1276 *
1277 * @param pVM The cross context VM structure.
1278 */
1279VMMR3_INT_DECL(void) VMMR3YieldResume(PVM pVM)
1280{
1281 if (pVM->vmm.s.cYieldResumeMillies)
1282 {
1283 TMTimerSetMillies(pVM->vmm.s.pYieldTimer, pVM->vmm.s.cYieldResumeMillies);
1284 pVM->vmm.s.cYieldResumeMillies = 0;
1285 }
1286}
1287
1288
1289/**
1290 * Internal timer callback function.
1291 *
1292 * @param pVM The cross context VM structure.
1293 * @param pTimer The timer handle.
1294 * @param pvUser User argument specified upon timer creation.
1295 */
1296static DECLCALLBACK(void) vmmR3YieldEMT(PVM pVM, PTMTIMER pTimer, void *pvUser)
1297{
1298 NOREF(pvUser);
1299
1300 /*
1301 * This really needs some careful tuning. While we shouldn't be too greedy since
1302 * that'll cause the rest of the system to stop up, we shouldn't be too nice either
1303 * because that'll cause us to stop up.
1304 *
1305 * The current logic is to use the default interval when there is no lag worth
1306 * mentioning, but when we start accumulating lag we don't bother yielding at all.
1307 *
1308 * (This depends on the TMCLOCK_VIRTUAL_SYNC to be scheduled before TMCLOCK_REAL
1309 * so the lag is up to date.)
1310 */
1311 const uint64_t u64Lag = TMVirtualSyncGetLag(pVM);
1312 if ( u64Lag < 50000000 /* 50ms */
1313 || ( u64Lag < 1000000000 /* 1s */
1314 && RTTimeNanoTS() - pVM->vmm.s.u64LastYield < 500000000 /* 500 ms */)
1315 )
1316 {
1317 uint64_t u64Elapsed = RTTimeNanoTS();
1318 pVM->vmm.s.u64LastYield = u64Elapsed;
1319
1320 RTThreadYield();
1321
1322#ifdef LOG_ENABLED
1323 u64Elapsed = RTTimeNanoTS() - u64Elapsed;
1324 Log(("vmmR3YieldEMT: %RI64 ns\n", u64Elapsed));
1325#endif
1326 }
1327 TMTimerSetMillies(pTimer, pVM->vmm.s.cYieldEveryMillies);
1328}
1329
1330
1331#ifdef VBOX_WITH_RAW_MODE
1332/**
1333 * Executes guest code in the raw-mode context.
1334 *
1335 * @param pVM The cross context VM structure.
1336 * @param pVCpu The cross context virtual CPU structure.
1337 */
1338VMMR3_INT_DECL(int) VMMR3RawRunGC(PVM pVM, PVMCPU pVCpu)
1339{
1340 Log2(("VMMR3RawRunGC: (cs:eip=%04x:%08x)\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
1341
1342 AssertReturn(pVM->cCpus == 1, VERR_RAW_MODE_INVALID_SMP);
1343
1344 /*
1345 * Set the hypervisor to resume executing a CPUM resume function
1346 * in CPUMRCA.asm.
1347 */
1348 CPUMSetHyperState(pVCpu,
1349 CPUMGetGuestEFlags(pVCpu) & X86_EFL_VM
1350 ? pVM->vmm.s.pfnCPUMRCResumeGuestV86
1351 : pVM->vmm.s.pfnCPUMRCResumeGuest, /* eip */
1352 pVCpu->vmm.s.pbEMTStackBottomRC, /* esp */
1353 0, /* eax */
1354 VM_RC_ADDR(pVM, &pVCpu->cpum) /* edx */);
1355
1356 /*
1357 * We hide log flushes (outer) and hypervisor interrupts (inner).
1358 */
1359 for (;;)
1360 {
1361#ifdef VBOX_STRICT
1362 if (RT_UNLIKELY(!CPUMGetHyperCR3(pVCpu) || CPUMGetHyperCR3(pVCpu) != PGMGetHyperCR3(pVCpu)))
1363 EMR3FatalError(pVCpu, VERR_VMM_HYPER_CR3_MISMATCH);
1364 PGMMapCheck(pVM);
1365# ifdef VBOX_WITH_SAFE_STR
1366 SELMR3CheckShadowTR(pVM);
1367# endif
1368#endif
1369 int rc;
1370 do
1371 {
1372#ifdef NO_SUPCALLR0VMM
1373 rc = VERR_GENERAL_FAILURE;
1374#else
1375 rc = SUPR3CallVMMR0Fast(pVM->pVMR0, VMMR0_DO_RAW_RUN, 0);
1376 if (RT_LIKELY(rc == VINF_SUCCESS))
1377 rc = pVCpu->vmm.s.iLastGZRc;
1378#endif
1379 } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
1380
1381 /*
1382 * Flush the logs.
1383 */
1384#ifdef LOG_ENABLED
1385 PRTLOGGERRC pLogger = pVM->vmm.s.pRCLoggerR3;
1386 if ( pLogger
1387 && pLogger->offScratch > 0)
1388 RTLogFlushRC(NULL, pLogger);
1389#endif
1390#ifdef VBOX_WITH_RC_RELEASE_LOGGING
1391 PRTLOGGERRC pRelLogger = pVM->vmm.s.pRCRelLoggerR3;
1392 if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
1393 RTLogFlushRC(RTLogRelGetDefaultInstance(), pRelLogger);
1394#endif
1395 if (rc != VINF_VMM_CALL_HOST)
1396 {
1397 Log2(("VMMR3RawRunGC: returns %Rrc (cs:eip=%04x:%08x)\n", rc, CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
1398 return rc;
1399 }
1400 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
1401 if (RT_FAILURE(rc))
1402 return rc;
1403 /* Resume GC */
1404 }
1405}
1406#endif /* VBOX_WITH_RAW_MODE */
1407
1408
1409/**
1410 * Executes guest code (Intel VT-x and AMD-V).
1411 *
1412 * @param pVM The cross context VM structure.
1413 * @param pVCpu The cross context virtual CPU structure.
1414 */
1415VMMR3_INT_DECL(int) VMMR3HmRunGC(PVM pVM, PVMCPU pVCpu)
1416{
1417 Log2(("VMMR3HmRunGC: (cs:rip=%04x:%RX64)\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu)));
1418
1419 for (;;)
1420 {
1421 int rc;
1422 do
1423 {
1424#ifdef NO_SUPCALLR0VMM
1425 rc = VERR_GENERAL_FAILURE;
1426#else
1427 rc = SUPR3CallVMMR0Fast(pVM->pVMR0, VMMR0_DO_HM_RUN, pVCpu->idCpu);
1428 if (RT_LIKELY(rc == VINF_SUCCESS))
1429 rc = pVCpu->vmm.s.iLastGZRc;
1430#endif
1431 } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
1432
1433#if 0 /** @todo triggers too often */
1434 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TO_R3));
1435#endif
1436
1437#ifdef LOG_ENABLED
1438 /*
1439 * Flush the log
1440 */
1441 PVMMR0LOGGER pR0LoggerR3 = pVCpu->vmm.s.pR0LoggerR3;
1442 if ( pR0LoggerR3
1443 && pR0LoggerR3->Logger.offScratch > 0)
1444 RTLogFlushR0(NULL, &pR0LoggerR3->Logger);
1445#endif /* !LOG_ENABLED */
1446 if (rc != VINF_VMM_CALL_HOST)
1447 {
1448 Log2(("VMMR3HmRunGC: returns %Rrc (cs:rip=%04x:%RX64)\n", rc, CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu)));
1449 return rc;
1450 }
1451 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
1452 if (RT_FAILURE(rc))
1453 return rc;
1454 /* Resume R0 */
1455 }
1456}
1457
1458
1459/**
1460 * Perform one of the fast I/O control VMMR0 operation.
1461 *
1462 * @returns VBox strict status code.
1463 * @param pVM The cross context VM structure.
1464 * @param pVCpu The cross context virtual CPU structure.
1465 * @param enmOperation The operation to perform.
1466 */
1467VMMR3_INT_DECL(VBOXSTRICTRC) VMMR3CallR0EmtFast(PVM pVM, PVMCPU pVCpu, VMMR0OPERATION enmOperation)
1468{
1469 for (;;)
1470 {
1471 VBOXSTRICTRC rcStrict;
1472 do
1473 {
1474#ifdef NO_SUPCALLR0VMM
1475 rcStrict = VERR_GENERAL_FAILURE;
1476#else
1477 rcStrict = SUPR3CallVMMR0Fast(pVM->pVMR0, enmOperation, pVCpu->idCpu);
1478 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
1479 rcStrict = pVCpu->vmm.s.iLastGZRc;
1480#endif
1481 } while (rcStrict == VINF_EM_RAW_INTERRUPT_HYPER);
1482
1483#ifdef LOG_ENABLED
1484 /*
1485 * Flush the log
1486 */
1487 PVMMR0LOGGER pR0LoggerR3 = pVCpu->vmm.s.pR0LoggerR3;
1488 if ( pR0LoggerR3
1489 && pR0LoggerR3->Logger.offScratch > 0)
1490 RTLogFlushR0(NULL, &pR0LoggerR3->Logger);
1491#endif /* !LOG_ENABLED */
1492 if (rcStrict != VINF_VMM_CALL_HOST)
1493 return rcStrict;
1494 int rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
1495 if (RT_FAILURE(rc))
1496 return rc;
1497 /* Resume R0 */
1498 }
1499}
1500
1501
1502/**
1503 * VCPU worker for VMMSendStartupIpi.
1504 *
1505 * @param pVM The cross context VM structure.
1506 * @param idCpu Virtual CPU to perform SIPI on.
1507 * @param uVector The SIPI vector.
1508 */
1509static DECLCALLBACK(int) vmmR3SendStarupIpi(PVM pVM, VMCPUID idCpu, uint32_t uVector)
1510{
1511 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
1512 VMCPU_ASSERT_EMT(pVCpu);
1513
1514 /*
1515 * Active, halt and shutdown states of the processor all block SIPIs.
1516 * So we can safely discard the SIPI. See Intel spec. 26.6.2 "Activity State".
1517 */
1518 if (EMGetState(pVCpu) != EMSTATE_WAIT_SIPI)
1519 return VERR_ACCESS_DENIED;
1520
1521
1522 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
1523
1524 pCtx->cs.Sel = uVector << 8;
1525 pCtx->cs.ValidSel = uVector << 8;
1526 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
1527 pCtx->cs.u64Base = uVector << 12;
1528 pCtx->cs.u32Limit = UINT32_C(0x0000ffff);
1529 pCtx->rip = 0;
1530
1531 Log(("vmmR3SendSipi for VCPU %d with vector %x\n", idCpu, uVector));
1532
1533# if 1 /* If we keep the EMSTATE_WAIT_SIPI method, then move this to EM.cpp. */
1534 EMSetState(pVCpu, EMSTATE_HALTED);
1535 return VINF_EM_RESCHEDULE;
1536# else /* And if we go the VMCPU::enmState way it can stay here. */
1537 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STOPPED);
1538 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED);
1539 return VINF_SUCCESS;
1540# endif
1541}
1542
1543
1544static DECLCALLBACK(int) vmmR3SendInitIpi(PVM pVM, VMCPUID idCpu)
1545{
1546 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
1547 VMCPU_ASSERT_EMT(pVCpu);
1548
1549 Log(("vmmR3SendInitIpi for VCPU %d\n", idCpu));
1550
1551 /** @todo Figure out how to handle a nested-guest intercepts here for INIT
1552 * IPI (e.g. SVM_EXIT_INIT). */
1553
1554 PGMR3ResetCpu(pVM, pVCpu);
1555 PDMR3ResetCpu(pVCpu); /* Only clears pending interrupts force flags */
1556 APICR3InitIpi(pVCpu);
1557 TRPMR3ResetCpu(pVCpu);
1558 CPUMR3ResetCpu(pVM, pVCpu);
1559 EMR3ResetCpu(pVCpu);
1560 HMR3ResetCpu(pVCpu);
1561 NEMR3ResetCpu(pVCpu, true /*fInitIpi*/);
1562
1563 /* This will trickle up on the target EMT. */
1564 return VINF_EM_WAIT_SIPI;
1565}
1566
1567
1568/**
1569 * Sends a Startup IPI to the virtual CPU by setting CS:EIP into
1570 * vector-dependent state and unhalting processor.
1571 *
1572 * @param pVM The cross context VM structure.
1573 * @param idCpu Virtual CPU to perform SIPI on.
1574 * @param uVector SIPI vector.
1575 */
1576VMMR3_INT_DECL(void) VMMR3SendStartupIpi(PVM pVM, VMCPUID idCpu, uint32_t uVector)
1577{
1578 AssertReturnVoid(idCpu < pVM->cCpus);
1579
1580 int rc = VMR3ReqCallNoWait(pVM, idCpu, (PFNRT)vmmR3SendStarupIpi, 3, pVM, idCpu, uVector);
1581 AssertRC(rc);
1582}
1583
1584
1585/**
1586 * Sends init IPI to the virtual CPU.
1587 *
1588 * @param pVM The cross context VM structure.
1589 * @param idCpu Virtual CPU to perform int IPI on.
1590 */
1591VMMR3_INT_DECL(void) VMMR3SendInitIpi(PVM pVM, VMCPUID idCpu)
1592{
1593 AssertReturnVoid(idCpu < pVM->cCpus);
1594
1595 int rc = VMR3ReqCallNoWait(pVM, idCpu, (PFNRT)vmmR3SendInitIpi, 2, pVM, idCpu);
1596 AssertRC(rc);
1597}
1598
1599
1600/**
1601 * Registers the guest memory range that can be used for patching.
1602 *
1603 * @returns VBox status code.
1604 * @param pVM The cross context VM structure.
1605 * @param pPatchMem Patch memory range.
1606 * @param cbPatchMem Size of the memory range.
1607 */
1608VMMR3DECL(int) VMMR3RegisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem)
1609{
1610 VM_ASSERT_EMT(pVM);
1611 if (HMIsEnabled(pVM))
1612 return HMR3EnablePatching(pVM, pPatchMem, cbPatchMem);
1613
1614 return VERR_NOT_SUPPORTED;
1615}
1616
1617
1618/**
1619 * Deregisters the guest memory range that can be used for patching.
1620 *
1621 * @returns VBox status code.
1622 * @param pVM The cross context VM structure.
1623 * @param pPatchMem Patch memory range.
1624 * @param cbPatchMem Size of the memory range.
1625 */
1626VMMR3DECL(int) VMMR3DeregisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem)
1627{
1628 if (HMIsEnabled(pVM))
1629 return HMR3DisablePatching(pVM, pPatchMem, cbPatchMem);
1630
1631 return VINF_SUCCESS;
1632}
1633
1634
1635/**
1636 * Common recursion handler for the other EMTs.
1637 *
1638 * @returns Strict VBox status code.
1639 * @param pVM The cross context VM structure.
1640 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1641 * @param rcStrict Current status code to be combined with the one
1642 * from this recursion and returned.
1643 */
1644static VBOXSTRICTRC vmmR3EmtRendezvousCommonRecursion(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict)
1645{
1646 int rc2;
1647
1648 /*
1649 * We wait here while the initiator of this recursion reconfigures
1650 * everything. The last EMT to get in signals the initiator.
1651 */
1652 if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPush) == pVM->cCpus)
1653 {
1654 rc2 = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
1655 AssertLogRelRC(rc2);
1656 }
1657
1658 rc2 = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousRecursionPush, RT_INDEFINITE_WAIT);
1659 AssertLogRelRC(rc2);
1660
1661 /*
1662 * Do the normal rendezvous processing.
1663 */
1664 VBOXSTRICTRC rcStrict2 = vmmR3EmtRendezvousCommon(pVM, pVCpu, false /* fIsCaller */, pVM->vmm.s.fRendezvousFlags,
1665 pVM->vmm.s.pfnRendezvous, pVM->vmm.s.pvRendezvousUser);
1666
1667 /*
1668 * Wait for the initiator to restore everything.
1669 */
1670 rc2 = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousRecursionPop, RT_INDEFINITE_WAIT);
1671 AssertLogRelRC(rc2);
1672
1673 /*
1674 * Last thread out of here signals the initiator.
1675 */
1676 if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPop) == pVM->cCpus)
1677 {
1678 rc2 = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
1679 AssertLogRelRC(rc2);
1680 }
1681
1682 /*
1683 * Merge status codes and return.
1684 */
1685 AssertRC(VBOXSTRICTRC_VAL(rcStrict2));
1686 if ( rcStrict2 != VINF_SUCCESS
1687 && ( rcStrict == VINF_SUCCESS
1688 || rcStrict > rcStrict2))
1689 rcStrict = rcStrict2;
1690 return rcStrict;
1691}
1692
1693
1694/**
1695 * Count returns and have the last non-caller EMT wake up the caller.
1696 *
1697 * @returns VBox strict informational status code for EM scheduling. No failures
1698 * will be returned here, those are for the caller only.
1699 *
1700 * @param pVM The cross context VM structure.
1701 * @param rcStrict The current accumulated recursive status code,
1702 * to be merged with i32RendezvousStatus and
1703 * returned.
1704 */
1705DECL_FORCE_INLINE(VBOXSTRICTRC) vmmR3EmtRendezvousNonCallerReturn(PVM pVM, VBOXSTRICTRC rcStrict)
1706{
1707 VBOXSTRICTRC rcStrict2 = ASMAtomicReadS32(&pVM->vmm.s.i32RendezvousStatus);
1708
1709 uint32_t cReturned = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsReturned);
1710 if (cReturned == pVM->cCpus - 1U)
1711 {
1712 int rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousDoneCaller);
1713 AssertLogRelRC(rc);
1714 }
1715
1716 /*
1717 * Merge the status codes, ignoring error statuses in this code path.
1718 */
1719 AssertLogRelMsgReturn( rcStrict2 <= VINF_SUCCESS
1720 || (rcStrict2 >= VINF_EM_FIRST && rcStrict2 <= VINF_EM_LAST),
1721 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)),
1722 VERR_IPE_UNEXPECTED_INFO_STATUS);
1723
1724 if (RT_SUCCESS(rcStrict2))
1725 {
1726 if ( rcStrict2 != VINF_SUCCESS
1727 && ( rcStrict == VINF_SUCCESS
1728 || rcStrict > rcStrict2))
1729 rcStrict = rcStrict2;
1730 }
1731 return rcStrict;
1732}
1733
1734
1735/**
1736 * Common worker for VMMR3EmtRendezvous and VMMR3EmtRendezvousFF.
1737 *
1738 * @returns VBox strict informational status code for EM scheduling. No failures
1739 * will be returned here, those are for the caller only. When
1740 * fIsCaller is set, VINF_SUCCESS is always returned.
1741 *
1742 * @param pVM The cross context VM structure.
1743 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1744 * @param fIsCaller Whether we're the VMMR3EmtRendezvous caller or
1745 * not.
1746 * @param fFlags The flags.
1747 * @param pfnRendezvous The callback.
1748 * @param pvUser The user argument for the callback.
1749 */
1750static VBOXSTRICTRC vmmR3EmtRendezvousCommon(PVM pVM, PVMCPU pVCpu, bool fIsCaller,
1751 uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
1752{
1753 int rc;
1754 VBOXSTRICTRC rcStrictRecursion = VINF_SUCCESS;
1755
1756 /*
1757 * Enter, the last EMT triggers the next callback phase.
1758 */
1759 uint32_t cEntered = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsEntered);
1760 if (cEntered != pVM->cCpus)
1761 {
1762 if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE)
1763 {
1764 /* Wait for our turn. */
1765 for (;;)
1766 {
1767 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousEnterOneByOne, RT_INDEFINITE_WAIT);
1768 AssertLogRelRC(rc);
1769 if (!pVM->vmm.s.fRendezvousRecursion)
1770 break;
1771 rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
1772 }
1773 }
1774 else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE)
1775 {
1776 /* Wait for the last EMT to arrive and wake everyone up. */
1777 rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce, RT_INDEFINITE_WAIT);
1778 AssertLogRelRC(rc);
1779 Assert(!pVM->vmm.s.fRendezvousRecursion);
1780 }
1781 else if ( (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
1782 || (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING)
1783 {
1784 /* Wait for our turn. */
1785 for (;;)
1786 {
1787 rc = RTSemEventWait(pVM->vmm.s.pahEvtRendezvousEnterOrdered[pVCpu->idCpu], RT_INDEFINITE_WAIT);
1788 AssertLogRelRC(rc);
1789 if (!pVM->vmm.s.fRendezvousRecursion)
1790 break;
1791 rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
1792 }
1793 }
1794 else
1795 {
1796 Assert((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE);
1797
1798 /*
1799 * The execute once is handled specially to optimize the code flow.
1800 *
1801 * The last EMT to arrive will perform the callback and the other
1802 * EMTs will wait on the Done/DoneCaller semaphores (instead of
1803 * the EnterOneByOne/AllAtOnce) in the meanwhile. When the callback
1804 * returns, that EMT will initiate the normal return sequence.
1805 */
1806 if (!fIsCaller)
1807 {
1808 for (;;)
1809 {
1810 rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousDone, RT_INDEFINITE_WAIT);
1811 AssertLogRelRC(rc);
1812 if (!pVM->vmm.s.fRendezvousRecursion)
1813 break;
1814 rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
1815 }
1816
1817 return vmmR3EmtRendezvousNonCallerReturn(pVM, rcStrictRecursion);
1818 }
1819 return VINF_SUCCESS;
1820 }
1821 }
1822 else
1823 {
1824 /*
1825 * All EMTs are waiting, clear the FF and take action according to the
1826 * execution method.
1827 */
1828 VM_FF_CLEAR(pVM, VM_FF_EMT_RENDEZVOUS);
1829
1830 if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE)
1831 {
1832 /* Wake up everyone. */
1833 rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);
1834 AssertLogRelRC(rc);
1835 }
1836 else if ( (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
1837 || (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING)
1838 {
1839 /* Figure out who to wake up and wake it up. If it's ourself, then
1840 it's easy otherwise wait for our turn. */
1841 VMCPUID iFirst = (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
1842 ? 0
1843 : pVM->cCpus - 1U;
1844 if (pVCpu->idCpu != iFirst)
1845 {
1846 rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[iFirst]);
1847 AssertLogRelRC(rc);
1848 for (;;)
1849 {
1850 rc = RTSemEventWait(pVM->vmm.s.pahEvtRendezvousEnterOrdered[pVCpu->idCpu], RT_INDEFINITE_WAIT);
1851 AssertLogRelRC(rc);
1852 if (!pVM->vmm.s.fRendezvousRecursion)
1853 break;
1854 rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
1855 }
1856 }
1857 }
1858 /* else: execute the handler on the current EMT and wake up one or more threads afterwards. */
1859 }
1860
1861
1862 /*
1863 * Do the callback and update the status if necessary.
1864 */
1865 if ( !(fFlags & VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR)
1866 || RT_SUCCESS(ASMAtomicUoReadS32(&pVM->vmm.s.i32RendezvousStatus)) )
1867 {
1868 VBOXSTRICTRC rcStrict2 = pfnRendezvous(pVM, pVCpu, pvUser);
1869 if (rcStrict2 != VINF_SUCCESS)
1870 {
1871 AssertLogRelMsg( rcStrict2 <= VINF_SUCCESS
1872 || (rcStrict2 >= VINF_EM_FIRST && rcStrict2 <= VINF_EM_LAST),
1873 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)));
1874 int32_t i32RendezvousStatus;
1875 do
1876 {
1877 i32RendezvousStatus = ASMAtomicUoReadS32(&pVM->vmm.s.i32RendezvousStatus);
1878 if ( rcStrict2 == i32RendezvousStatus
1879 || RT_FAILURE(i32RendezvousStatus)
1880 || ( i32RendezvousStatus != VINF_SUCCESS
1881 && rcStrict2 > i32RendezvousStatus))
1882 break;
1883 } while (!ASMAtomicCmpXchgS32(&pVM->vmm.s.i32RendezvousStatus, VBOXSTRICTRC_VAL(rcStrict2), i32RendezvousStatus));
1884 }
1885 }
1886
1887 /*
1888 * Increment the done counter and take action depending on whether we're
1889 * the last to finish callback execution.
1890 */
1891 uint32_t cDone = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsDone);
1892 if ( cDone != pVM->cCpus
1893 && (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) != VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE)
1894 {
1895 /* Signal the next EMT? */
1896 if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE)
1897 {
1898 rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousEnterOneByOne);
1899 AssertLogRelRC(rc);
1900 }
1901 else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING)
1902 {
1903 Assert(cDone == pVCpu->idCpu + 1U);
1904 rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[pVCpu->idCpu + 1U]);
1905 AssertLogRelRC(rc);
1906 }
1907 else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING)
1908 {
1909 Assert(pVM->cCpus - cDone == pVCpu->idCpu);
1910 rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[pVM->cCpus - cDone - 1U]);
1911 AssertLogRelRC(rc);
1912 }
1913
1914 /* Wait for the rest to finish (the caller waits on hEvtRendezvousDoneCaller). */
1915 if (!fIsCaller)
1916 {
1917 for (;;)
1918 {
1919 rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousDone, RT_INDEFINITE_WAIT);
1920 AssertLogRelRC(rc);
1921 if (!pVM->vmm.s.fRendezvousRecursion)
1922 break;
1923 rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
1924 }
1925 }
1926 }
1927 else
1928 {
1929 /* Callback execution is all done, tell the rest to return. */
1930 rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousDone);
1931 AssertLogRelRC(rc);
1932 }
1933
1934 if (!fIsCaller)
1935 return vmmR3EmtRendezvousNonCallerReturn(pVM, rcStrictRecursion);
1936 return rcStrictRecursion;
1937}
1938
1939
1940/**
1941 * Called in response to VM_FF_EMT_RENDEZVOUS.
1942 *
1943 * @returns VBox strict status code - EM scheduling. No errors will be returned
1944 * here, nor will any non-EM scheduling status codes be returned.
1945 *
1946 * @param pVM The cross context VM structure.
1947 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1948 *
1949 * @thread EMT
1950 */
1951VMMR3_INT_DECL(int) VMMR3EmtRendezvousFF(PVM pVM, PVMCPU pVCpu)
1952{
1953 Assert(!pVCpu->vmm.s.fInRendezvous);
1954 Log(("VMMR3EmtRendezvousFF: EMT%#u\n", pVCpu->idCpu));
1955 pVCpu->vmm.s.fInRendezvous = true;
1956 VBOXSTRICTRC rcStrict = vmmR3EmtRendezvousCommon(pVM, pVCpu, false /* fIsCaller */, pVM->vmm.s.fRendezvousFlags,
1957 pVM->vmm.s.pfnRendezvous, pVM->vmm.s.pvRendezvousUser);
1958 pVCpu->vmm.s.fInRendezvous = false;
1959 Log(("VMMR3EmtRendezvousFF: EMT%#u returns %Rrc\n", pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict)));
1960 return VBOXSTRICTRC_TODO(rcStrict);
1961}
1962
1963
1964/**
1965 * Helper for resetting an single wakeup event sempahore.
1966 *
1967 * @returns VERR_TIMEOUT on success, RTSemEventWait status otherwise.
1968 * @param hEvt The event semaphore to reset.
1969 */
1970static int vmmR3HlpResetEvent(RTSEMEVENT hEvt)
1971{
1972 for (uint32_t cLoops = 0; ; cLoops++)
1973 {
1974 int rc = RTSemEventWait(hEvt, 0 /*cMsTimeout*/);
1975 if (rc != VINF_SUCCESS || cLoops > _4K)
1976 return rc;
1977 }
1978}
1979
1980
1981/**
1982 * Worker for VMMR3EmtRendezvous that handles recursion.
1983 *
1984 * @returns VBox strict status code. This will be the first error,
1985 * VINF_SUCCESS, or an EM scheduling status code.
1986 *
1987 * @param pVM The cross context VM structure.
1988 * @param pVCpu The cross context virtual CPU structure of the
1989 * calling EMT.
1990 * @param fFlags Flags indicating execution methods. See
1991 * grp_VMMR3EmtRendezvous_fFlags.
1992 * @param pfnRendezvous The callback.
1993 * @param pvUser User argument for the callback.
1994 *
1995 * @thread EMT(pVCpu)
1996 */
1997static VBOXSTRICTRC vmmR3EmtRendezvousRecursive(PVM pVM, PVMCPU pVCpu, uint32_t fFlags,
1998 PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
1999{
2000 Log(("vmmR3EmtRendezvousRecursive: %#x EMT#%u depth=%d\n", fFlags, pVCpu->idCpu, pVM->vmm.s.cRendezvousRecursions));
2001 AssertLogRelReturn(pVM->vmm.s.cRendezvousRecursions < 3, VERR_DEADLOCK);
2002 Assert(pVCpu->vmm.s.fInRendezvous);
2003
2004 /*
2005 * Save the current state.
2006 */
2007 uint32_t const fParentFlags = pVM->vmm.s.fRendezvousFlags;
2008 uint32_t const cParentDone = pVM->vmm.s.cRendezvousEmtsDone;
2009 int32_t const iParentStatus = pVM->vmm.s.i32RendezvousStatus;
2010 PFNVMMEMTRENDEZVOUS const pfnParent = pVM->vmm.s.pfnRendezvous;
2011 void * const pvParentUser = pVM->vmm.s.pvRendezvousUser;
2012
2013 /*
2014 * Check preconditions and save the current state.
2015 */
2016 AssertReturn( (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
2017 || (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING
2018 || (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE
2019 || (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE,
2020 VERR_INTERNAL_ERROR);
2021 AssertReturn(pVM->vmm.s.cRendezvousEmtsEntered == pVM->cCpus, VERR_INTERNAL_ERROR_2);
2022 AssertReturn(pVM->vmm.s.cRendezvousEmtsReturned == 0, VERR_INTERNAL_ERROR_3);
2023
2024 /*
2025 * Reset the recursion prep and pop semaphores.
2026 */
2027 int rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousRecursionPush);
2028 AssertLogRelRCReturn(rc, rc);
2029 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousRecursionPop);
2030 AssertLogRelRCReturn(rc, rc);
2031 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
2032 AssertLogRelMsgReturn(rc == VERR_TIMEOUT, ("%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_IPE_UNEXPECTED_INFO_STATUS);
2033 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
2034 AssertLogRelMsgReturn(rc == VERR_TIMEOUT, ("%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_IPE_UNEXPECTED_INFO_STATUS);
2035
2036 /*
2037 * Usher the other thread into the recursion routine.
2038 */
2039 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsRecursingPush, 0);
2040 ASMAtomicWriteBool(&pVM->vmm.s.fRendezvousRecursion, true);
2041
2042 uint32_t cLeft = pVM->cCpus - (cParentDone + 1U);
2043 if ((fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE)
2044 while (cLeft-- > 0)
2045 {
2046 rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousEnterOneByOne);
2047 AssertLogRelRC(rc);
2048 }
2049 else if ((fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING)
2050 {
2051 Assert(cLeft == pVM->cCpus - (pVCpu->idCpu + 1U));
2052 for (VMCPUID iCpu = pVCpu->idCpu + 1U; iCpu < pVM->cCpus; iCpu++)
2053 {
2054 rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[iCpu]);
2055 AssertLogRelRC(rc);
2056 }
2057 }
2058 else if ((fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING)
2059 {
2060 Assert(cLeft == pVCpu->idCpu);
2061 for (VMCPUID iCpu = pVCpu->idCpu; iCpu > 0; iCpu--)
2062 {
2063 rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[iCpu - 1U]);
2064 AssertLogRelRC(rc);
2065 }
2066 }
2067 else
2068 AssertLogRelReturn((fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE,
2069 VERR_INTERNAL_ERROR_4);
2070
2071 rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousDone);
2072 AssertLogRelRC(rc);
2073 rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousDoneCaller);
2074 AssertLogRelRC(rc);
2075
2076
2077 /*
2078 * Wait for the EMTs to wake up and get out of the parent rendezvous code.
2079 */
2080 if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPush) != pVM->cCpus)
2081 {
2082 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousRecursionPushCaller, RT_INDEFINITE_WAIT);
2083 AssertLogRelRC(rc);
2084 }
2085
2086 ASMAtomicWriteBool(&pVM->vmm.s.fRendezvousRecursion, false);
2087
2088 /*
2089 * Clear the slate and setup the new rendezvous.
2090 */
2091 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2092 {
2093 rc = vmmR3HlpResetEvent(pVM->vmm.s.pahEvtRendezvousEnterOrdered[i]);
2094 AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2095 }
2096 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousEnterOneByOne); AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2097 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce); AssertLogRelRC(rc);
2098 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousDone); AssertLogRelRC(rc);
2099 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousDoneCaller); AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2100
2101 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsEntered, 0);
2102 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsDone, 0);
2103 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsReturned, 0);
2104 ASMAtomicWriteS32(&pVM->vmm.s.i32RendezvousStatus, VINF_SUCCESS);
2105 ASMAtomicWritePtr((void * volatile *)&pVM->vmm.s.pfnRendezvous, (void *)(uintptr_t)pfnRendezvous);
2106 ASMAtomicWritePtr(&pVM->vmm.s.pvRendezvousUser, pvUser);
2107 ASMAtomicWriteU32(&pVM->vmm.s.fRendezvousFlags, fFlags);
2108 ASMAtomicIncU32(&pVM->vmm.s.cRendezvousRecursions);
2109
2110 /*
2111 * We're ready to go now, do normal rendezvous processing.
2112 */
2113 rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousRecursionPush);
2114 AssertLogRelRC(rc);
2115
2116 VBOXSTRICTRC rcStrict = vmmR3EmtRendezvousCommon(pVM, pVCpu, true /*fIsCaller*/, fFlags, pfnRendezvous, pvUser);
2117
2118 /*
2119 * The caller waits for the other EMTs to be done, return and waiting on the
2120 * pop semaphore.
2121 */
2122 for (;;)
2123 {
2124 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, RT_INDEFINITE_WAIT);
2125 AssertLogRelRC(rc);
2126 if (!pVM->vmm.s.fRendezvousRecursion)
2127 break;
2128 rcStrict = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrict);
2129 }
2130
2131 /*
2132 * Get the return code and merge it with the above recursion status.
2133 */
2134 VBOXSTRICTRC rcStrict2 = pVM->vmm.s.i32RendezvousStatus;
2135 if ( rcStrict2 != VINF_SUCCESS
2136 && ( rcStrict == VINF_SUCCESS
2137 || rcStrict > rcStrict2))
2138 rcStrict = rcStrict2;
2139
2140 /*
2141 * Restore the parent rendezvous state.
2142 */
2143 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2144 {
2145 rc = vmmR3HlpResetEvent(pVM->vmm.s.pahEvtRendezvousEnterOrdered[i]);
2146 AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2147 }
2148 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousEnterOneByOne); AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2149 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce); AssertLogRelRC(rc);
2150 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousDone); AssertLogRelRC(rc);
2151 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousDoneCaller); AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2152
2153 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsEntered, pVM->cCpus);
2154 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsReturned, 0);
2155 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsDone, cParentDone);
2156 ASMAtomicWriteS32(&pVM->vmm.s.i32RendezvousStatus, iParentStatus);
2157 ASMAtomicWriteU32(&pVM->vmm.s.fRendezvousFlags, fParentFlags);
2158 ASMAtomicWritePtr(&pVM->vmm.s.pvRendezvousUser, pvParentUser);
2159 ASMAtomicWritePtr((void * volatile *)&pVM->vmm.s.pfnRendezvous, (void *)(uintptr_t)pfnParent);
2160
2161 /*
2162 * Usher the other EMTs back to their parent recursion routine, waiting
2163 * for them to all get there before we return (makes sure they've been
2164 * scheduled and are past the pop event sem, see below).
2165 */
2166 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsRecursingPop, 0);
2167 rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousRecursionPop);
2168 AssertLogRelRC(rc);
2169
2170 if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPop) != pVM->cCpus)
2171 {
2172 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousRecursionPopCaller, RT_INDEFINITE_WAIT);
2173 AssertLogRelRC(rc);
2174 }
2175
2176 /*
2177 * We must reset the pop semaphore on the way out (doing the pop caller too,
2178 * just in case). The parent may be another recursion.
2179 */
2180 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousRecursionPop); AssertLogRelRC(rc);
2181 rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousRecursionPopCaller); AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
2182
2183 ASMAtomicDecU32(&pVM->vmm.s.cRendezvousRecursions);
2184
2185 Log(("vmmR3EmtRendezvousRecursive: %#x EMT#%u depth=%d returns %Rrc\n",
2186 fFlags, pVCpu->idCpu, pVM->vmm.s.cRendezvousRecursions, VBOXSTRICTRC_VAL(rcStrict)));
2187 return rcStrict;
2188}
2189
2190
2191/**
2192 * EMT rendezvous.
2193 *
2194 * Gathers all the EMTs and execute some code on each of them, either in a one
2195 * by one fashion or all at once.
2196 *
2197 * @returns VBox strict status code. This will be the first error,
2198 * VINF_SUCCESS, or an EM scheduling status code.
2199 *
2200 * @retval VERR_DEADLOCK if recursion is attempted using a rendezvous type that
2201 * doesn't support it or if the recursion is too deep.
2202 *
2203 * @param pVM The cross context VM structure.
2204 * @param fFlags Flags indicating execution methods. See
2205 * grp_VMMR3EmtRendezvous_fFlags. The one-by-one,
2206 * descending and ascending rendezvous types support
2207 * recursion from inside @a pfnRendezvous.
2208 * @param pfnRendezvous The callback.
2209 * @param pvUser User argument for the callback.
2210 *
2211 * @thread Any.
2212 */
2213VMMR3DECL(int) VMMR3EmtRendezvous(PVM pVM, uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
2214{
2215 /*
2216 * Validate input.
2217 */
2218 AssertReturn(pVM, VERR_INVALID_VM_HANDLE);
2219 AssertMsg( (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) != VMMEMTRENDEZVOUS_FLAGS_TYPE_INVALID
2220 && (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) <= VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING
2221 && !(fFlags & ~VMMEMTRENDEZVOUS_FLAGS_VALID_MASK), ("%#x\n", fFlags));
2222 AssertMsg( !(fFlags & VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR)
2223 || ( (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) != VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE
2224 && (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) != VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE),
2225 ("type %u\n", fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK));
2226
2227 VBOXSTRICTRC rcStrict;
2228 PVMCPU pVCpu = VMMGetCpu(pVM);
2229 if (!pVCpu)
2230 {
2231 /*
2232 * Forward the request to an EMT thread.
2233 */
2234 Log(("VMMR3EmtRendezvous: %#x non-EMT\n", fFlags));
2235 if (!(fFlags & VMMEMTRENDEZVOUS_FLAGS_PRIORITY))
2236 rcStrict = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)VMMR3EmtRendezvous, 4, pVM, fFlags, pfnRendezvous, pvUser);
2237 else
2238 rcStrict = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)VMMR3EmtRendezvous, 4, pVM, fFlags, pfnRendezvous, pvUser);
2239 Log(("VMMR3EmtRendezvous: %#x non-EMT returns %Rrc\n", fFlags, VBOXSTRICTRC_VAL(rcStrict)));
2240 }
2241 else if ( pVM->cCpus == 1
2242 || ( pVM->enmVMState == VMSTATE_DESTROYING
2243 && VMR3GetActiveEmts(pVM->pUVM) < pVM->cCpus ) )
2244 {
2245 /*
2246 * Shortcut for the single EMT case.
2247 *
2248 * We also ends up here if EMT(0) (or others) tries to issue a rendezvous
2249 * during vmR3Destroy after other emulation threads have started terminating.
2250 */
2251 if (!pVCpu->vmm.s.fInRendezvous)
2252 {
2253 Log(("VMMR3EmtRendezvous: %#x EMT (uni)\n", fFlags));
2254 pVCpu->vmm.s.fInRendezvous = true;
2255 pVM->vmm.s.fRendezvousFlags = fFlags;
2256 rcStrict = pfnRendezvous(pVM, pVCpu, pvUser);
2257 pVCpu->vmm.s.fInRendezvous = false;
2258 }
2259 else
2260 {
2261 /* Recursion. Do the same checks as in the SMP case. */
2262 Log(("VMMR3EmtRendezvous: %#x EMT (uni), recursion depth=%d\n", fFlags, pVM->vmm.s.cRendezvousRecursions));
2263 uint32_t fType = pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK;
2264 AssertLogRelReturn( !pVCpu->vmm.s.fInRendezvous
2265 || fType == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
2266 || fType == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING
2267 || fType == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE
2268 || fType == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE
2269 , VERR_DEADLOCK);
2270
2271 AssertLogRelReturn(pVM->vmm.s.cRendezvousRecursions < 3, VERR_DEADLOCK);
2272 pVM->vmm.s.cRendezvousRecursions++;
2273 uint32_t const fParentFlags = pVM->vmm.s.fRendezvousFlags;
2274 pVM->vmm.s.fRendezvousFlags = fFlags;
2275
2276 rcStrict = pfnRendezvous(pVM, pVCpu, pvUser);
2277
2278 pVM->vmm.s.fRendezvousFlags = fParentFlags;
2279 pVM->vmm.s.cRendezvousRecursions--;
2280 }
2281 Log(("VMMR3EmtRendezvous: %#x EMT (uni) returns %Rrc\n", fFlags, VBOXSTRICTRC_VAL(rcStrict)));
2282 }
2283 else
2284 {
2285 /*
2286 * Spin lock. If busy, check for recursion, if not recursing wait for
2287 * the other EMT to finish while keeping a lookout for the RENDEZVOUS FF.
2288 */
2289 int rc;
2290 rcStrict = VINF_SUCCESS;
2291 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pVM->vmm.s.u32RendezvousLock, 0x77778888, 0)))
2292 {
2293 /* Allow recursion in some cases. */
2294 if ( pVCpu->vmm.s.fInRendezvous
2295 && ( (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
2296 || (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING
2297 || (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE
2298 || (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE
2299 ))
2300 return VBOXSTRICTRC_TODO(vmmR3EmtRendezvousRecursive(pVM, pVCpu, fFlags, pfnRendezvous, pvUser));
2301
2302 AssertLogRelMsgReturn(!pVCpu->vmm.s.fInRendezvous, ("fRendezvousFlags=%#x\n", pVM->vmm.s.fRendezvousFlags),
2303 VERR_DEADLOCK);
2304
2305 Log(("VMMR3EmtRendezvous: %#x EMT#%u, waiting for lock...\n", fFlags, pVCpu->idCpu));
2306 while (!ASMAtomicCmpXchgU32(&pVM->vmm.s.u32RendezvousLock, 0x77778888, 0))
2307 {
2308 if (VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS))
2309 {
2310 rc = VMMR3EmtRendezvousFF(pVM, pVCpu);
2311 if ( rc != VINF_SUCCESS
2312 && ( rcStrict == VINF_SUCCESS
2313 || rcStrict > rc))
2314 rcStrict = rc;
2315 /** @todo Perhaps deal with termination here? */
2316 }
2317 ASMNopPause();
2318 }
2319 }
2320
2321 Log(("VMMR3EmtRendezvous: %#x EMT#%u\n", fFlags, pVCpu->idCpu));
2322 Assert(!VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS));
2323 Assert(!pVCpu->vmm.s.fInRendezvous);
2324 pVCpu->vmm.s.fInRendezvous = true;
2325
2326 /*
2327 * Clear the slate and setup the rendezvous. This is a semaphore ping-pong orgy. :-)
2328 */
2329 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2330 {
2331 rc = RTSemEventWait(pVM->vmm.s.pahEvtRendezvousEnterOrdered[i], 0);
2332 AssertLogRelMsg(rc == VERR_TIMEOUT || rc == VINF_SUCCESS, ("%Rrc\n", rc));
2333 }
2334 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousEnterOneByOne, 0); AssertLogRelMsg(rc == VERR_TIMEOUT || rc == VINF_SUCCESS, ("%Rrc\n", rc));
2335 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce); AssertLogRelRC(rc);
2336 rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousDone); AssertLogRelRC(rc);
2337 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, 0); AssertLogRelMsg(rc == VERR_TIMEOUT || rc == VINF_SUCCESS, ("%Rrc\n", rc));
2338 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsEntered, 0);
2339 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsDone, 0);
2340 ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsReturned, 0);
2341 ASMAtomicWriteS32(&pVM->vmm.s.i32RendezvousStatus, VINF_SUCCESS);
2342 ASMAtomicWritePtr((void * volatile *)&pVM->vmm.s.pfnRendezvous, (void *)(uintptr_t)pfnRendezvous);
2343 ASMAtomicWritePtr(&pVM->vmm.s.pvRendezvousUser, pvUser);
2344 ASMAtomicWriteU32(&pVM->vmm.s.fRendezvousFlags, fFlags);
2345
2346 /*
2347 * Set the FF and poke the other EMTs.
2348 */
2349 VM_FF_SET(pVM, VM_FF_EMT_RENDEZVOUS);
2350 VMR3NotifyGlobalFFU(pVM->pUVM, VMNOTIFYFF_FLAGS_POKE);
2351
2352 /*
2353 * Do the same ourselves.
2354 */
2355 VBOXSTRICTRC rcStrict2 = vmmR3EmtRendezvousCommon(pVM, pVCpu, true /* fIsCaller */, fFlags, pfnRendezvous, pvUser);
2356
2357 /*
2358 * The caller waits for the other EMTs to be done and return before doing
2359 * the cleanup. This makes away with wakeup / reset races we would otherwise
2360 * risk in the multiple release event semaphore code (hEvtRendezvousDoneCaller).
2361 */
2362 for (;;)
2363 {
2364 rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, RT_INDEFINITE_WAIT);
2365 AssertLogRelRC(rc);
2366 if (!pVM->vmm.s.fRendezvousRecursion)
2367 break;
2368 rcStrict2 = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrict2);
2369 }
2370
2371 /*
2372 * Get the return code and clean up a little bit.
2373 */
2374 VBOXSTRICTRC rcStrict3 = pVM->vmm.s.i32RendezvousStatus;
2375 ASMAtomicWriteNullPtr((void * volatile *)&pVM->vmm.s.pfnRendezvous);
2376
2377 ASMAtomicWriteU32(&pVM->vmm.s.u32RendezvousLock, 0);
2378 pVCpu->vmm.s.fInRendezvous = false;
2379
2380 /*
2381 * Merge rcStrict, rcStrict2 and rcStrict3.
2382 */
2383 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
2384 AssertRC(VBOXSTRICTRC_VAL(rcStrict2));
2385 if ( rcStrict2 != VINF_SUCCESS
2386 && ( rcStrict == VINF_SUCCESS
2387 || rcStrict > rcStrict2))
2388 rcStrict = rcStrict2;
2389 if ( rcStrict3 != VINF_SUCCESS
2390 && ( rcStrict == VINF_SUCCESS
2391 || rcStrict > rcStrict3))
2392 rcStrict = rcStrict3;
2393 Log(("VMMR3EmtRendezvous: %#x EMT#%u returns %Rrc\n", fFlags, pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict)));
2394 }
2395
2396 AssertLogRelMsgReturn( rcStrict <= VINF_SUCCESS
2397 || (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST),
2398 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)),
2399 VERR_IPE_UNEXPECTED_INFO_STATUS);
2400 return VBOXSTRICTRC_VAL(rcStrict);
2401}
2402
2403
2404/**
2405 * Read from the ring 0 jump buffer stack.
2406 *
2407 * @returns VBox status code.
2408 *
2409 * @param pVM The cross context VM structure.
2410 * @param idCpu The ID of the source CPU context (for the address).
2411 * @param R0Addr Where to start reading.
2412 * @param pvBuf Where to store the data we've read.
2413 * @param cbRead The number of bytes to read.
2414 */
2415VMMR3_INT_DECL(int) VMMR3ReadR0Stack(PVM pVM, VMCPUID idCpu, RTHCUINTPTR R0Addr, void *pvBuf, size_t cbRead)
2416{
2417 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
2418 AssertReturn(pVCpu, VERR_INVALID_PARAMETER);
2419
2420#ifdef VMM_R0_SWITCH_STACK
2421 RTHCUINTPTR off = R0Addr - MMHyperCCToR0(pVM, pVCpu->vmm.s.pbEMTStackR3);
2422#else
2423 RTHCUINTPTR off = pVCpu->vmm.s.CallRing3JmpBufR0.cbSavedStack - (pVCpu->vmm.s.CallRing3JmpBufR0.SpCheck - R0Addr);
2424#endif
2425 if ( off > VMM_STACK_SIZE
2426 || off + cbRead >= VMM_STACK_SIZE)
2427 return VERR_INVALID_POINTER;
2428
2429 memcpy(pvBuf, &pVCpu->vmm.s.pbEMTStackR3[off], cbRead);
2430 return VINF_SUCCESS;
2431}
2432
2433#ifdef VBOX_WITH_RAW_MODE
2434
2435/**
2436 * Calls a RC function.
2437 *
2438 * @param pVM The cross context VM structure.
2439 * @param RCPtrEntry The address of the RC function.
2440 * @param cArgs The number of arguments in the ....
2441 * @param ... Arguments to the function.
2442 */
2443VMMR3DECL(int) VMMR3CallRC(PVM pVM, RTRCPTR RCPtrEntry, unsigned cArgs, ...)
2444{
2445 va_list args;
2446 va_start(args, cArgs);
2447 int rc = VMMR3CallRCV(pVM, RCPtrEntry, cArgs, args);
2448 va_end(args);
2449 return rc;
2450}
2451
2452
2453/**
2454 * Calls a RC function.
2455 *
2456 * @param pVM The cross context VM structure.
2457 * @param RCPtrEntry The address of the RC function.
2458 * @param cArgs The number of arguments in the ....
2459 * @param args Arguments to the function.
2460 */
2461VMMR3DECL(int) VMMR3CallRCV(PVM pVM, RTRCPTR RCPtrEntry, unsigned cArgs, va_list args)
2462{
2463 /* Raw mode implies 1 VCPU. */
2464 AssertReturn(pVM->cCpus == 1, VERR_RAW_MODE_INVALID_SMP);
2465 PVMCPU pVCpu = &pVM->aCpus[0];
2466
2467 Log2(("VMMR3CallGCV: RCPtrEntry=%RRv cArgs=%d\n", RCPtrEntry, cArgs));
2468
2469 /*
2470 * Setup the call frame using the trampoline.
2471 */
2472 CPUMSetHyperState(pVCpu,
2473 pVM->vmm.s.pfnCallTrampolineRC, /* eip */
2474 pVCpu->vmm.s.pbEMTStackBottomRC - cArgs * sizeof(RTGCUINTPTR32), /* esp */
2475 RCPtrEntry, /* eax */
2476 cArgs /* edx */
2477 );
2478
2479#if 0
2480 memset(pVCpu->vmm.s.pbEMTStackR3, 0xaa, VMM_STACK_SIZE); /* Clear the stack. */
2481#endif
2482 PRTGCUINTPTR32 pFrame = (PRTGCUINTPTR32)(pVCpu->vmm.s.pbEMTStackR3 + VMM_STACK_SIZE) - cArgs;
2483 int i = cArgs;
2484 while (i-- > 0)
2485 *pFrame++ = va_arg(args, RTGCUINTPTR32);
2486
2487 CPUMPushHyper(pVCpu, cArgs * sizeof(RTGCUINTPTR32)); /* stack frame size */
2488 CPUMPushHyper(pVCpu, RCPtrEntry); /* what to call */
2489
2490 /*
2491 * We hide log flushes (outer) and hypervisor interrupts (inner).
2492 */
2493 for (;;)
2494 {
2495 int rc;
2496 Assert(CPUMGetHyperCR3(pVCpu) && CPUMGetHyperCR3(pVCpu) == PGMGetHyperCR3(pVCpu));
2497 do
2498 {
2499#ifdef NO_SUPCALLR0VMM
2500 rc = VERR_GENERAL_FAILURE;
2501#else
2502 rc = SUPR3CallVMMR0Fast(pVM->pVMR0, VMMR0_DO_RAW_RUN, 0);
2503 if (RT_LIKELY(rc == VINF_SUCCESS))
2504 rc = pVCpu->vmm.s.iLastGZRc;
2505#endif
2506 } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
2507
2508 /*
2509 * Flush the loggers.
2510 */
2511#ifdef LOG_ENABLED
2512 PRTLOGGERRC pLogger = pVM->vmm.s.pRCLoggerR3;
2513 if ( pLogger
2514 && pLogger->offScratch > 0)
2515 RTLogFlushRC(NULL, pLogger);
2516#endif
2517#ifdef VBOX_WITH_RC_RELEASE_LOGGING
2518 PRTLOGGERRC pRelLogger = pVM->vmm.s.pRCRelLoggerR3;
2519 if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
2520 RTLogFlushRC(RTLogRelGetDefaultInstance(), pRelLogger);
2521#endif
2522 if (rc == VERR_TRPM_PANIC || rc == VERR_TRPM_DONT_PANIC)
2523 VMMR3FatalDump(pVM, pVCpu, rc);
2524 if (rc != VINF_VMM_CALL_HOST)
2525 {
2526 Log2(("VMMR3CallGCV: returns %Rrc (cs:eip=%04x:%08x)\n", rc, CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
2527 return rc;
2528 }
2529 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
2530 if (RT_FAILURE(rc))
2531 return rc;
2532 }
2533}
2534
2535#endif /* VBOX_WITH_RAW_MODE */
2536
2537/**
2538 * Wrapper for SUPR3CallVMMR0Ex which will deal with VINF_VMM_CALL_HOST returns.
2539 *
2540 * @returns VBox status code.
2541 * @param pVM The cross context VM structure.
2542 * @param uOperation Operation to execute.
2543 * @param u64Arg Constant argument.
2544 * @param pReqHdr Pointer to a request header. See SUPR3CallVMMR0Ex for
2545 * details.
2546 */
2547VMMR3DECL(int) VMMR3CallR0(PVM pVM, uint32_t uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
2548{
2549 PVMCPU pVCpu = VMMGetCpu(pVM);
2550 AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
2551 return VMMR3CallR0Emt(pVM, pVCpu, (VMMR0OPERATION)uOperation, u64Arg, pReqHdr);
2552}
2553
2554
2555/**
2556 * Wrapper for SUPR3CallVMMR0Ex which will deal with VINF_VMM_CALL_HOST returns.
2557 *
2558 * @returns VBox status code.
2559 * @param pVM The cross context VM structure.
2560 * @param pVCpu The cross context VM structure.
2561 * @param enmOperation Operation to execute.
2562 * @param u64Arg Constant argument.
2563 * @param pReqHdr Pointer to a request header. See SUPR3CallVMMR0Ex for
2564 * details.
2565 */
2566VMMR3_INT_DECL(int) VMMR3CallR0Emt(PVM pVM, PVMCPU pVCpu, VMMR0OPERATION enmOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
2567{
2568 int rc;
2569 for (;;)
2570 {
2571#ifdef NO_SUPCALLR0VMM
2572 rc = VERR_GENERAL_FAILURE;
2573#else
2574 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, pVCpu->idCpu, enmOperation, u64Arg, pReqHdr);
2575#endif
2576 /*
2577 * Flush the logs.
2578 */
2579#ifdef LOG_ENABLED
2580 if ( pVCpu->vmm.s.pR0LoggerR3
2581 && pVCpu->vmm.s.pR0LoggerR3->Logger.offScratch > 0)
2582 RTLogFlushR0(NULL, &pVCpu->vmm.s.pR0LoggerR3->Logger);
2583#endif
2584 if (rc != VINF_VMM_CALL_HOST)
2585 break;
2586 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
2587 if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
2588 break;
2589 /* Resume R0 */
2590 }
2591
2592 AssertLogRelMsgReturn(rc == VINF_SUCCESS || RT_FAILURE(rc),
2593 ("enmOperation=%u rc=%Rrc\n", enmOperation, rc),
2594 VERR_IPE_UNEXPECTED_INFO_STATUS);
2595 return rc;
2596}
2597
2598
2599#ifdef VBOX_WITH_RAW_MODE
2600/**
2601 * Resumes executing hypervisor code when interrupted by a queue flush or a
2602 * debug event.
2603 *
2604 * @returns VBox status code.
2605 * @param pVM The cross context VM structure.
2606 * @param pVCpu The cross context virtual CPU structure.
2607 */
2608VMMR3DECL(int) VMMR3ResumeHyper(PVM pVM, PVMCPU pVCpu)
2609{
2610 Log(("VMMR3ResumeHyper: eip=%RRv esp=%RRv\n", CPUMGetHyperEIP(pVCpu), CPUMGetHyperESP(pVCpu)));
2611 AssertReturn(pVM->cCpus == 1, VERR_RAW_MODE_INVALID_SMP);
2612
2613 /*
2614 * We hide log flushes (outer) and hypervisor interrupts (inner).
2615 */
2616 for (;;)
2617 {
2618 int rc;
2619 Assert(CPUMGetHyperCR3(pVCpu) && CPUMGetHyperCR3(pVCpu) == PGMGetHyperCR3(pVCpu));
2620 do
2621 {
2622# ifdef NO_SUPCALLR0VMM
2623 rc = VERR_GENERAL_FAILURE;
2624# else
2625 rc = SUPR3CallVMMR0Fast(pVM->pVMR0, VMMR0_DO_RAW_RUN, 0);
2626 if (RT_LIKELY(rc == VINF_SUCCESS))
2627 rc = pVCpu->vmm.s.iLastGZRc;
2628# endif
2629 } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
2630
2631 /*
2632 * Flush the loggers.
2633 */
2634# ifdef LOG_ENABLED
2635 PRTLOGGERRC pLogger = pVM->vmm.s.pRCLoggerR3;
2636 if ( pLogger
2637 && pLogger->offScratch > 0)
2638 RTLogFlushRC(NULL, pLogger);
2639# endif
2640# ifdef VBOX_WITH_RC_RELEASE_LOGGING
2641 PRTLOGGERRC pRelLogger = pVM->vmm.s.pRCRelLoggerR3;
2642 if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
2643 RTLogFlushRC(RTLogRelGetDefaultInstance(), pRelLogger);
2644# endif
2645 if (rc == VERR_TRPM_PANIC || rc == VERR_TRPM_DONT_PANIC)
2646 VMMR3FatalDump(pVM, pVCpu, rc);
2647 if (rc != VINF_VMM_CALL_HOST)
2648 {
2649 Log(("VMMR3ResumeHyper: returns %Rrc\n", rc));
2650 return rc;
2651 }
2652 rc = vmmR3ServiceCallRing3Request(pVM, pVCpu);
2653 if (RT_FAILURE(rc))
2654 return rc;
2655 }
2656}
2657#endif /* VBOX_WITH_RAW_MODE */
2658
2659
2660/**
2661 * Service a call to the ring-3 host code.
2662 *
2663 * @returns VBox status code.
2664 * @param pVM The cross context VM structure.
2665 * @param pVCpu The cross context virtual CPU structure.
2666 * @remarks Careful with critsects.
2667 */
2668static int vmmR3ServiceCallRing3Request(PVM pVM, PVMCPU pVCpu)
2669{
2670 /*
2671 * We must also check for pending critsect exits or else we can deadlock
2672 * when entering other critsects here.
2673 */
2674 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PDM_CRITSECT))
2675 PDMCritSectBothFF(pVCpu);
2676
2677 switch (pVCpu->vmm.s.enmCallRing3Operation)
2678 {
2679 /*
2680 * Acquire a critical section.
2681 */
2682 case VMMCALLRING3_PDM_CRIT_SECT_ENTER:
2683 {
2684 pVCpu->vmm.s.rcCallRing3 = PDMR3CritSectEnterEx((PPDMCRITSECT)(uintptr_t)pVCpu->vmm.s.u64CallRing3Arg,
2685 true /*fCallRing3*/);
2686 break;
2687 }
2688
2689 /*
2690 * Enter a r/w critical section exclusively.
2691 */
2692 case VMMCALLRING3_PDM_CRIT_SECT_RW_ENTER_EXCL:
2693 {
2694 pVCpu->vmm.s.rcCallRing3 = PDMR3CritSectRwEnterExclEx((PPDMCRITSECTRW)(uintptr_t)pVCpu->vmm.s.u64CallRing3Arg,
2695 true /*fCallRing3*/);
2696 break;
2697 }
2698
2699 /*
2700 * Enter a r/w critical section shared.
2701 */
2702 case VMMCALLRING3_PDM_CRIT_SECT_RW_ENTER_SHARED:
2703 {
2704 pVCpu->vmm.s.rcCallRing3 = PDMR3CritSectRwEnterSharedEx((PPDMCRITSECTRW)(uintptr_t)pVCpu->vmm.s.u64CallRing3Arg,
2705 true /*fCallRing3*/);
2706 break;
2707 }
2708
2709 /*
2710 * Acquire the PDM lock.
2711 */
2712 case VMMCALLRING3_PDM_LOCK:
2713 {
2714 pVCpu->vmm.s.rcCallRing3 = PDMR3LockCall(pVM);
2715 break;
2716 }
2717
2718 /*
2719 * Grow the PGM pool.
2720 */
2721 case VMMCALLRING3_PGM_POOL_GROW:
2722 {
2723 pVCpu->vmm.s.rcCallRing3 = PGMR3PoolGrow(pVM);
2724 break;
2725 }
2726
2727 /*
2728 * Maps an page allocation chunk into ring-3 so ring-0 can use it.
2729 */
2730 case VMMCALLRING3_PGM_MAP_CHUNK:
2731 {
2732 pVCpu->vmm.s.rcCallRing3 = PGMR3PhysChunkMap(pVM, pVCpu->vmm.s.u64CallRing3Arg);
2733 break;
2734 }
2735
2736 /*
2737 * Allocates more handy pages.
2738 */
2739 case VMMCALLRING3_PGM_ALLOCATE_HANDY_PAGES:
2740 {
2741 pVCpu->vmm.s.rcCallRing3 = PGMR3PhysAllocateHandyPages(pVM);
2742 break;
2743 }
2744
2745 /*
2746 * Allocates a large page.
2747 */
2748 case VMMCALLRING3_PGM_ALLOCATE_LARGE_HANDY_PAGE:
2749 {
2750 pVCpu->vmm.s.rcCallRing3 = PGMR3PhysAllocateLargeHandyPage(pVM, pVCpu->vmm.s.u64CallRing3Arg);
2751 break;
2752 }
2753
2754 /*
2755 * Acquire the PGM lock.
2756 */
2757 case VMMCALLRING3_PGM_LOCK:
2758 {
2759 pVCpu->vmm.s.rcCallRing3 = PGMR3LockCall(pVM);
2760 break;
2761 }
2762
2763 /*
2764 * Acquire the MM hypervisor heap lock.
2765 */
2766 case VMMCALLRING3_MMHYPER_LOCK:
2767 {
2768 pVCpu->vmm.s.rcCallRing3 = MMR3LockCall(pVM);
2769 break;
2770 }
2771
2772#ifdef VBOX_WITH_REM
2773 /*
2774 * Flush REM handler notifications.
2775 */
2776 case VMMCALLRING3_REM_REPLAY_HANDLER_NOTIFICATIONS:
2777 {
2778 REMR3ReplayHandlerNotifications(pVM);
2779 pVCpu->vmm.s.rcCallRing3 = VINF_SUCCESS;
2780 break;
2781 }
2782#endif
2783
2784 /*
2785 * This is a noop. We just take this route to avoid unnecessary
2786 * tests in the loops.
2787 */
2788 case VMMCALLRING3_VMM_LOGGER_FLUSH:
2789 pVCpu->vmm.s.rcCallRing3 = VINF_SUCCESS;
2790 LogAlways(("*FLUSH*\n"));
2791 break;
2792
2793 /*
2794 * Set the VM error message.
2795 */
2796 case VMMCALLRING3_VM_SET_ERROR:
2797 VMR3SetErrorWorker(pVM);
2798 pVCpu->vmm.s.rcCallRing3 = VINF_SUCCESS;
2799 break;
2800
2801 /*
2802 * Set the VM runtime error message.
2803 */
2804 case VMMCALLRING3_VM_SET_RUNTIME_ERROR:
2805 pVCpu->vmm.s.rcCallRing3 = VMR3SetRuntimeErrorWorker(pVM);
2806 break;
2807
2808 /*
2809 * Signal a ring 0 hypervisor assertion.
2810 * Cancel the longjmp operation that's in progress.
2811 */
2812 case VMMCALLRING3_VM_R0_ASSERTION:
2813 pVCpu->vmm.s.enmCallRing3Operation = VMMCALLRING3_INVALID;
2814 pVCpu->vmm.s.CallRing3JmpBufR0.fInRing3Call = false;
2815#ifdef RT_ARCH_X86
2816 pVCpu->vmm.s.CallRing3JmpBufR0.eip = 0;
2817#else
2818 pVCpu->vmm.s.CallRing3JmpBufR0.rip = 0;
2819#endif
2820#ifdef VMM_R0_SWITCH_STACK
2821 *(uint64_t *)pVCpu->vmm.s.pbEMTStackR3 = 0; /* clear marker */
2822#endif
2823 LogRel(("%s", pVM->vmm.s.szRing0AssertMsg1));
2824 LogRel(("%s", pVM->vmm.s.szRing0AssertMsg2));
2825 return VERR_VMM_RING0_ASSERTION;
2826
2827 /*
2828 * A forced switch to ring 0 for preemption purposes.
2829 */
2830 case VMMCALLRING3_VM_R0_PREEMPT:
2831 pVCpu->vmm.s.rcCallRing3 = VINF_SUCCESS;
2832 break;
2833
2834 case VMMCALLRING3_FTM_SET_CHECKPOINT:
2835 pVCpu->vmm.s.rcCallRing3 = FTMR3SetCheckpoint(pVM, (FTMCHECKPOINTTYPE)pVCpu->vmm.s.u64CallRing3Arg);
2836 break;
2837
2838 default:
2839 AssertMsgFailed(("enmCallRing3Operation=%d\n", pVCpu->vmm.s.enmCallRing3Operation));
2840 return VERR_VMM_UNKNOWN_RING3_CALL;
2841 }
2842
2843 pVCpu->vmm.s.enmCallRing3Operation = VMMCALLRING3_INVALID;
2844 return VINF_SUCCESS;
2845}
2846
2847
2848/**
2849 * Displays the Force action Flags.
2850 *
2851 * @param pVM The cross context VM structure.
2852 * @param pHlp The output helpers.
2853 * @param pszArgs The additional arguments (ignored).
2854 */
2855static DECLCALLBACK(void) vmmR3InfoFF(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
2856{
2857 int c;
2858 uint32_t f;
2859 NOREF(pszArgs);
2860
2861#define PRINT_FLAG(prf,flag) do { \
2862 if (f & (prf##flag)) \
2863 { \
2864 static const char *s_psz = #flag; \
2865 if (!(c % 6)) \
2866 pHlp->pfnPrintf(pHlp, "%s\n %s", c ? "," : "", s_psz); \
2867 else \
2868 pHlp->pfnPrintf(pHlp, ", %s", s_psz); \
2869 c++; \
2870 f &= ~(prf##flag); \
2871 } \
2872 } while (0)
2873
2874#define PRINT_GROUP(prf,grp,sfx) do { \
2875 if (f & (prf##grp##sfx)) \
2876 { \
2877 static const char *s_psz = #grp; \
2878 if (!(c % 5)) \
2879 pHlp->pfnPrintf(pHlp, "%s %s", c ? ",\n" : " Groups:\n", s_psz); \
2880 else \
2881 pHlp->pfnPrintf(pHlp, ", %s", s_psz); \
2882 c++; \
2883 } \
2884 } while (0)
2885
2886 /*
2887 * The global flags.
2888 */
2889 const uint32_t fGlobalForcedActions = pVM->fGlobalForcedActions;
2890 pHlp->pfnPrintf(pHlp, "Global FFs: %#RX32", fGlobalForcedActions);
2891
2892 /* show the flag mnemonics */
2893 c = 0;
2894 f = fGlobalForcedActions;
2895 PRINT_FLAG(VM_FF_,TM_VIRTUAL_SYNC);
2896 PRINT_FLAG(VM_FF_,PDM_QUEUES);
2897 PRINT_FLAG(VM_FF_,PDM_DMA);
2898 PRINT_FLAG(VM_FF_,DBGF);
2899 PRINT_FLAG(VM_FF_,REQUEST);
2900 PRINT_FLAG(VM_FF_,CHECK_VM_STATE);
2901 PRINT_FLAG(VM_FF_,RESET);
2902 PRINT_FLAG(VM_FF_,EMT_RENDEZVOUS);
2903 PRINT_FLAG(VM_FF_,PGM_NEED_HANDY_PAGES);
2904 PRINT_FLAG(VM_FF_,PGM_NO_MEMORY);
2905 PRINT_FLAG(VM_FF_,PGM_POOL_FLUSH_PENDING);
2906 PRINT_FLAG(VM_FF_,REM_HANDLER_NOTIFY);
2907 PRINT_FLAG(VM_FF_,DEBUG_SUSPEND);
2908 if (f)
2909 pHlp->pfnPrintf(pHlp, "%s\n Unknown bits: %#RX32\n", c ? "," : "", f);
2910 else
2911 pHlp->pfnPrintf(pHlp, "\n");
2912
2913 /* the groups */
2914 c = 0;
2915 f = fGlobalForcedActions;
2916 PRINT_GROUP(VM_FF_,EXTERNAL_SUSPENDED,_MASK);
2917 PRINT_GROUP(VM_FF_,EXTERNAL_HALTED,_MASK);
2918 PRINT_GROUP(VM_FF_,HIGH_PRIORITY_PRE,_MASK);
2919 PRINT_GROUP(VM_FF_,HIGH_PRIORITY_PRE_RAW,_MASK);
2920 PRINT_GROUP(VM_FF_,HIGH_PRIORITY_POST,_MASK);
2921 PRINT_GROUP(VM_FF_,NORMAL_PRIORITY_POST,_MASK);
2922 PRINT_GROUP(VM_FF_,NORMAL_PRIORITY,_MASK);
2923 PRINT_GROUP(VM_FF_,ALL_REM,_MASK);
2924 if (c)
2925 pHlp->pfnPrintf(pHlp, "\n");
2926
2927 /*
2928 * Per CPU flags.
2929 */
2930 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2931 {
2932 const uint32_t fLocalForcedActions = pVM->aCpus[i].fLocalForcedActions;
2933 pHlp->pfnPrintf(pHlp, "CPU %u FFs: %#RX32", i, fLocalForcedActions);
2934
2935 /* show the flag mnemonics */
2936 c = 0;
2937 f = fLocalForcedActions;
2938 PRINT_FLAG(VMCPU_FF_,INTERRUPT_APIC);
2939 PRINT_FLAG(VMCPU_FF_,INTERRUPT_PIC);
2940 PRINT_FLAG(VMCPU_FF_,TIMER);
2941 PRINT_FLAG(VMCPU_FF_,INTERRUPT_NMI);
2942 PRINT_FLAG(VMCPU_FF_,INTERRUPT_SMI);
2943 PRINT_FLAG(VMCPU_FF_,PDM_CRITSECT);
2944 PRINT_FLAG(VMCPU_FF_,UNHALT);
2945 PRINT_FLAG(VMCPU_FF_,IEM);
2946 PRINT_FLAG(VMCPU_FF_,UPDATE_APIC);
2947 PRINT_FLAG(VMCPU_FF_,DBGF);
2948 PRINT_FLAG(VMCPU_FF_,REQUEST);
2949 PRINT_FLAG(VMCPU_FF_,HM_UPDATE_CR3);
2950 PRINT_FLAG(VMCPU_FF_,HM_UPDATE_PAE_PDPES);
2951 PRINT_FLAG(VMCPU_FF_,PGM_SYNC_CR3);
2952 PRINT_FLAG(VMCPU_FF_,PGM_SYNC_CR3_NON_GLOBAL);
2953 PRINT_FLAG(VMCPU_FF_,TLB_FLUSH);
2954 PRINT_FLAG(VMCPU_FF_,INHIBIT_INTERRUPTS);
2955 PRINT_FLAG(VMCPU_FF_,BLOCK_NMIS);
2956 PRINT_FLAG(VMCPU_FF_,TO_R3);
2957 PRINT_FLAG(VMCPU_FF_,IOM);
2958#ifdef VBOX_WITH_RAW_MODE
2959 PRINT_FLAG(VMCPU_FF_,TRPM_SYNC_IDT);
2960 PRINT_FLAG(VMCPU_FF_,SELM_SYNC_TSS);
2961 PRINT_FLAG(VMCPU_FF_,SELM_SYNC_GDT);
2962 PRINT_FLAG(VMCPU_FF_,SELM_SYNC_LDT);
2963 PRINT_FLAG(VMCPU_FF_,CSAM_SCAN_PAGE);
2964 PRINT_FLAG(VMCPU_FF_,CSAM_PENDING_ACTION);
2965 PRINT_FLAG(VMCPU_FF_,CPUM);
2966#endif
2967 if (f)
2968 pHlp->pfnPrintf(pHlp, "%s\n Unknown bits: %#RX32\n", c ? "," : "", f);
2969 else
2970 pHlp->pfnPrintf(pHlp, "\n");
2971
2972 if (fLocalForcedActions & VMCPU_FF_INHIBIT_INTERRUPTS)
2973 pHlp->pfnPrintf(pHlp, " intr inhibit RIP: %RGp\n", EMGetInhibitInterruptsPC(&pVM->aCpus[i]));
2974
2975 /* the groups */
2976 c = 0;
2977 f = fLocalForcedActions;
2978 PRINT_GROUP(VMCPU_FF_,EXTERNAL_SUSPENDED,_MASK);
2979 PRINT_GROUP(VMCPU_FF_,EXTERNAL_HALTED,_MASK);
2980 PRINT_GROUP(VMCPU_FF_,HIGH_PRIORITY_PRE,_MASK);
2981 PRINT_GROUP(VMCPU_FF_,HIGH_PRIORITY_PRE_RAW,_MASK);
2982 PRINT_GROUP(VMCPU_FF_,HIGH_PRIORITY_POST,_MASK);
2983 PRINT_GROUP(VMCPU_FF_,NORMAL_PRIORITY_POST,_MASK);
2984 PRINT_GROUP(VMCPU_FF_,NORMAL_PRIORITY,_MASK);
2985 PRINT_GROUP(VMCPU_FF_,RESUME_GUEST,_MASK);
2986 PRINT_GROUP(VMCPU_FF_,HM_TO_R3,_MASK);
2987 PRINT_GROUP(VMCPU_FF_,ALL_REM,_MASK);
2988 if (c)
2989 pHlp->pfnPrintf(pHlp, "\n");
2990 }
2991
2992#undef PRINT_FLAG
2993#undef PRINT_GROUP
2994}
2995
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