VirtualBox

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

Last change on this file since 91243 was 91243, checked in by vboxsync, 4 years ago

VMM/PGMPool: Call PGMR0PoolGrow directly from ring-0 instead of going via ring-3. bugref:10093

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

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