VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/VMMR0.cpp@ 17364

Last change on this file since 17364 was 17305, checked in by vboxsync, 16 years ago

VMM: Register %R[pgmpage] and %R[pgmramrange] (logging builds only).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 41.2 KB
Line 
1/* $Id: VMMR0.cpp 17305 2009-03-03 18:19:29Z vboxsync $ */
2/** @file
3 * VMM - Host Context Ring 0.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_VMM
26#include <VBox/vmm.h>
27#include <VBox/sup.h>
28#include <VBox/trpm.h>
29#include <VBox/cpum.h>
30#include <VBox/pgm.h>
31#include <VBox/stam.h>
32#include <VBox/tm.h>
33#include "VMMInternal.h"
34#include <VBox/vm.h>
35#include <VBox/gvmm.h>
36#include <VBox/gmm.h>
37#include <VBox/intnet.h>
38#include <VBox/hwaccm.h>
39#include <VBox/param.h>
40
41#include <VBox/err.h>
42#include <VBox/version.h>
43#include <VBox/log.h>
44#include <iprt/assert.h>
45#include <iprt/stdarg.h>
46#include <iprt/mp.h>
47#include <iprt/string.h>
48
49#if defined(_MSC_VER) && defined(RT_ARCH_AMD64) /** @todo check this with with VC7! */
50# pragma intrinsic(_AddressOfReturnAddress)
51#endif
52
53
54/*******************************************************************************
55* Internal Functions *
56*******************************************************************************/
57__BEGIN_DECLS
58VMMR0DECL(int) ModuleInit(void);
59VMMR0DECL(void) ModuleTerm(void);
60__END_DECLS
61
62
63/*******************************************************************************
64* Global Variables *
65*******************************************************************************/
66/** Pointer to the internal networking service instance. */
67PINTNET g_pIntNet = 0;
68
69
70/**
71 * Initialize the module.
72 * This is called when we're first loaded.
73 *
74 * @returns 0 on success.
75 * @returns VBox status on failure.
76 */
77VMMR0DECL(int) ModuleInit(void)
78{
79 LogFlow(("ModuleInit:\n"));
80
81 /*
82 * Initialize the GVMM, GMM, HWACCM, PGM (Darwin) and INTNET.
83 */
84 int rc = GVMMR0Init();
85 if (RT_SUCCESS(rc))
86 {
87 rc = GMMR0Init();
88 if (RT_SUCCESS(rc))
89 {
90 rc = HWACCMR0Init();
91 if (RT_SUCCESS(rc))
92 {
93 rc = PGMRegisterStringFormatTypes();
94 if (RT_SUCCESS(rc))
95 {
96#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
97 rc = PGMR0DynMapInit();
98#endif
99 if (RT_SUCCESS(rc))
100 {
101 LogFlow(("ModuleInit: g_pIntNet=%p\n", g_pIntNet));
102 g_pIntNet = NULL;
103 LogFlow(("ModuleInit: g_pIntNet=%p should be NULL now...\n", g_pIntNet));
104 rc = INTNETR0Create(&g_pIntNet);
105 if (RT_SUCCESS(rc))
106 {
107 LogFlow(("ModuleInit: returns success. g_pIntNet=%p\n", g_pIntNet));
108 return VINF_SUCCESS;
109 }
110
111 /* bail out */
112 g_pIntNet = NULL;
113 LogFlow(("ModuleTerm: returns %Rrc\n", rc));
114#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
115 PGMR0DynMapTerm();
116#endif
117 }
118 PGMDeregisterStringFormatTypes();
119 }
120 HWACCMR0Term();
121 }
122 GMMR0Term();
123 }
124 GVMMR0Term();
125 }
126
127 LogFlow(("ModuleInit: failed %Rrc\n", rc));
128 return rc;
129}
130
131
132/**
133 * Terminate the module.
134 * This is called when we're finally unloaded.
135 */
136VMMR0DECL(void) ModuleTerm(void)
137{
138 LogFlow(("ModuleTerm:\n"));
139
140 /*
141 * Destroy the internal networking instance.
142 */
143 if (g_pIntNet)
144 {
145 INTNETR0Destroy(g_pIntNet);
146 g_pIntNet = NULL;
147 }
148
149 /*
150 * PGM (Darwin) and HWACCM global cleanup.
151 * Destroy the GMM and GVMM instances.
152 */
153#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
154 PGMR0DynMapTerm();
155#endif
156 PGMDeregisterStringFormatTypes();
157 HWACCMR0Term();
158
159 GMMR0Term();
160 GVMMR0Term();
161
162 LogFlow(("ModuleTerm: returns\n"));
163}
164
165
166/**
167 * Initaties the R0 driver for a particular VM instance.
168 *
169 * @returns VBox status code.
170 *
171 * @param pVM The VM instance in question.
172 * @param uSvnRev The SVN revision of the ring-3 part.
173 * @thread EMT.
174 */
175static int vmmR0InitVM(PVM pVM, uint32_t uSvnRev)
176{
177 /*
178 * Match the SVN revisions.
179 */
180 if (uSvnRev != VMMGetSvnRev())
181 return VERR_VERSION_MISMATCH;
182 if ( !VALID_PTR(pVM)
183 || pVM->pVMR0 != pVM)
184 return VERR_INVALID_PARAMETER;
185
186 /*
187 * Register the EMT R0 logger instance.
188 */
189 PVMMR0LOGGER pR0Logger = pVM->vmm.s.pR0LoggerR0;
190 if (pR0Logger)
191 {
192#if 0 /* testing of the logger. */
193 LogCom(("vmmR0InitVM: before %p\n", RTLogDefaultInstance()));
194 LogCom(("vmmR0InitVM: pfnFlush=%p actual=%p\n", pR0Logger->Logger.pfnFlush, vmmR0LoggerFlush));
195 LogCom(("vmmR0InitVM: pfnLogger=%p actual=%p\n", pR0Logger->Logger.pfnLogger, vmmR0LoggerWrapper));
196 LogCom(("vmmR0InitVM: offScratch=%d fFlags=%#x fDestFlags=%#x\n", pR0Logger->Logger.offScratch, pR0Logger->Logger.fFlags, pR0Logger->Logger.fDestFlags));
197
198 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
199 LogCom(("vmmR0InitVM: after %p reg\n", RTLogDefaultInstance()));
200 RTLogSetDefaultInstanceThread(NULL, 0);
201 LogCom(("vmmR0InitVM: after %p dereg\n", RTLogDefaultInstance()));
202
203 pR0Logger->Logger.pfnLogger("hello ring-0 logger\n");
204 LogCom(("vmmR0InitVM: returned succesfully from direct logger call.\n"));
205 pR0Logger->Logger.pfnFlush(&pR0Logger->Logger);
206 LogCom(("vmmR0InitVM: returned succesfully from direct flush call.\n"));
207
208 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
209 LogCom(("vmmR0InitVM: after %p reg2\n", RTLogDefaultInstance()));
210 pR0Logger->Logger.pfnLogger("hello ring-0 logger\n");
211 LogCom(("vmmR0InitVM: returned succesfully from direct logger call (2). offScratch=%d\n", pR0Logger->Logger.offScratch));
212 RTLogSetDefaultInstanceThread(NULL, 0);
213 LogCom(("vmmR0InitVM: after %p dereg2\n", RTLogDefaultInstance()));
214
215 RTLogLoggerEx(&pR0Logger->Logger, 0, ~0U, "hello ring-0 logger (RTLogLoggerEx)\n");
216 LogCom(("vmmR0InitVM: RTLogLoggerEx returned fine offScratch=%d\n", pR0Logger->Logger.offScratch));
217
218 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
219 RTLogPrintf("hello ring-0 logger (RTLogPrintf)\n");
220 LogCom(("vmmR0InitVM: RTLogPrintf returned fine offScratch=%d\n", pR0Logger->Logger.offScratch));
221#endif
222 Log(("Switching to per-thread logging instance %p (key=%p)\n", &pR0Logger->Logger, pVM->pSession));
223 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
224 }
225
226 /*
227 * Initialize the per VM data for GVMM and GMM.
228 */
229 int rc = GVMMR0InitVM(pVM);
230// if (RT_SUCCESS(rc))
231// rc = GMMR0InitPerVMData(pVM);
232 if (RT_SUCCESS(rc))
233 {
234 /*
235 * Init HWACCM, CPUM and PGM (Darwin only).
236 */
237 rc = HWACCMR0InitVM(pVM);
238 if (RT_SUCCESS(rc))
239 {
240 rc = CPUMR0Init(pVM); /** @todo rename to CPUMR0InitVM */
241 if (RT_SUCCESS(rc))
242 {
243#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
244 rc = PGMR0DynMapInitVM(pVM);
245#endif
246 if (RT_SUCCESS(rc))
247 {
248 GVMMR0DoneInitVM(pVM);
249 return rc;
250 }
251
252 /* bail out */
253 }
254 HWACCMR0TermVM(pVM);
255 }
256 }
257 RTLogSetDefaultInstanceThread(NULL, 0);
258 return rc;
259}
260
261
262/**
263 * Terminates the R0 driver for a particular VM instance.
264 *
265 * This is normally called by ring-3 as part of the VM termination process, but
266 * may alternatively be called during the support driver session cleanup when
267 * the VM object is destroyed (see GVMM).
268 *
269 * @returns VBox status code.
270 *
271 * @param pVM The VM instance in question.
272 * @param pGVM Pointer to the global VM structure. Optional.
273 * @thread EMT or session clean up thread.
274 */
275VMMR0DECL(int) VMMR0TermVM(PVM pVM, PGVM pGVM)
276{
277 /*
278 * Tell GVMM what we're up to and check that we only do this once.
279 */
280 if (GVMMR0DoingTermVM(pVM, pGVM))
281 {
282#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
283 PGMR0DynMapTermVM(pVM);
284#endif
285 HWACCMR0TermVM(pVM);
286 }
287
288 /*
289 * Deregister the logger.
290 */
291 RTLogSetDefaultInstanceThread(NULL, 0);
292 return VINF_SUCCESS;
293}
294
295
296/**
297 * Calls the ring-3 host code.
298 *
299 * @returns VBox status code of the ring-3 call.
300 * @param pVM The VM handle.
301 * @param enmOperation The operation.
302 * @param uArg The argument to the operation.
303 */
304VMMR0DECL(int) VMMR0CallHost(PVM pVM, VMMCALLHOST enmOperation, uint64_t uArg)
305{
306/** @todo profile this! */
307 pVM->vmm.s.enmCallHostOperation = enmOperation;
308 pVM->vmm.s.u64CallHostArg = uArg;
309 pVM->vmm.s.rcCallHost = VERR_INTERNAL_ERROR;
310 int rc = vmmR0CallHostLongJmp(&pVM->vmm.s.CallHostR0JmpBuf, VINF_VMM_CALL_HOST);
311 if (rc == VINF_SUCCESS)
312 rc = pVM->vmm.s.rcCallHost;
313 return rc;
314}
315
316
317#ifdef VBOX_WITH_STATISTICS
318/**
319 * Record return code statistics
320 * @param pVM The VM handle.
321 * @param rc The status code.
322 */
323static void vmmR0RecordRC(PVM pVM, int rc)
324{
325 /*
326 * Collect statistics.
327 */
328 switch (rc)
329 {
330 case VINF_SUCCESS:
331 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetNormal);
332 break;
333 case VINF_EM_RAW_INTERRUPT:
334 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetInterrupt);
335 break;
336 case VINF_EM_RAW_INTERRUPT_HYPER:
337 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetInterruptHyper);
338 break;
339 case VINF_EM_RAW_GUEST_TRAP:
340 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetGuestTrap);
341 break;
342 case VINF_EM_RAW_RING_SWITCH:
343 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetRingSwitch);
344 break;
345 case VINF_EM_RAW_RING_SWITCH_INT:
346 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetRingSwitchInt);
347 break;
348 case VINF_EM_RAW_EXCEPTION_PRIVILEGED:
349 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetExceptionPrivilege);
350 break;
351 case VINF_EM_RAW_STALE_SELECTOR:
352 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetStaleSelector);
353 break;
354 case VINF_EM_RAW_IRET_TRAP:
355 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetIRETTrap);
356 break;
357 case VINF_IOM_HC_IOPORT_READ:
358 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetIORead);
359 break;
360 case VINF_IOM_HC_IOPORT_WRITE:
361 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetIOWrite);
362 break;
363 case VINF_IOM_HC_MMIO_READ:
364 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetMMIORead);
365 break;
366 case VINF_IOM_HC_MMIO_WRITE:
367 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetMMIOWrite);
368 break;
369 case VINF_IOM_HC_MMIO_READ_WRITE:
370 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetMMIOReadWrite);
371 break;
372 case VINF_PATM_HC_MMIO_PATCH_READ:
373 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetMMIOPatchRead);
374 break;
375 case VINF_PATM_HC_MMIO_PATCH_WRITE:
376 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetMMIOPatchWrite);
377 break;
378 case VINF_EM_RAW_EMULATE_INSTR:
379 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetEmulate);
380 break;
381 case VINF_EM_RAW_EMULATE_IO_BLOCK:
382 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetIOBlockEmulate);
383 break;
384 case VINF_PATCH_EMULATE_INSTR:
385 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPatchEmulate);
386 break;
387 case VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT:
388 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetLDTFault);
389 break;
390 case VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT:
391 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetGDTFault);
392 break;
393 case VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT:
394 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetIDTFault);
395 break;
396 case VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT:
397 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetTSSFault);
398 break;
399 case VINF_EM_RAW_EMULATE_INSTR_PD_FAULT:
400 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPDFault);
401 break;
402 case VINF_CSAM_PENDING_ACTION:
403 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetCSAMTask);
404 break;
405 case VINF_PGM_SYNC_CR3:
406 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetSyncCR3);
407 break;
408 case VINF_PATM_PATCH_INT3:
409 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPatchInt3);
410 break;
411 case VINF_PATM_PATCH_TRAP_PF:
412 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPatchPF);
413 break;
414 case VINF_PATM_PATCH_TRAP_GP:
415 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPatchGP);
416 break;
417 case VINF_PATM_PENDING_IRQ_AFTER_IRET:
418 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPatchIretIRQ);
419 break;
420 case VERR_REM_FLUSHED_PAGES_OVERFLOW:
421 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPageOverflow);
422 break;
423 case VINF_EM_RESCHEDULE_REM:
424 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetRescheduleREM);
425 break;
426 case VINF_EM_RAW_TO_R3:
427 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetToR3);
428 break;
429 case VINF_EM_RAW_TIMER_PENDING:
430 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetTimerPending);
431 break;
432 case VINF_EM_RAW_INTERRUPT_PENDING:
433 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetInterruptPending);
434 break;
435 case VINF_VMM_CALL_HOST:
436 switch (pVM->vmm.s.enmCallHostOperation)
437 {
438 case VMMCALLHOST_PDM_LOCK:
439 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallPDMLock);
440 break;
441 case VMMCALLHOST_PDM_QUEUE_FLUSH:
442 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallPDMQueueFlush);
443 break;
444 case VMMCALLHOST_PGM_POOL_GROW:
445 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallPGMPoolGrow);
446 break;
447 case VMMCALLHOST_PGM_LOCK:
448 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallPGMLock);
449 break;
450 case VMMCALLHOST_PGM_MAP_CHUNK:
451 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallPGMMapChunk);
452 break;
453 case VMMCALLHOST_PGM_ALLOCATE_HANDY_PAGES:
454 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallPGMAllocHandy);
455 break;
456#ifndef VBOX_WITH_NEW_PHYS_CODE
457 case VMMCALLHOST_PGM_RAM_GROW_RANGE:
458 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallPGMGrowRAM);
459 break;
460#endif
461 case VMMCALLHOST_REM_REPLAY_HANDLER_NOTIFICATIONS:
462 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallRemReplay);
463 break;
464 case VMMCALLHOST_VMM_LOGGER_FLUSH:
465 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallLogFlush);
466 break;
467 case VMMCALLHOST_VM_SET_ERROR:
468 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallVMSetError);
469 break;
470 case VMMCALLHOST_VM_SET_RUNTIME_ERROR:
471 STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallVMSetRuntimeError);
472 break;
473 case VMMCALLHOST_VM_R0_ASSERTION:
474 default:
475 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetCallHost);
476 break;
477 }
478 break;
479 case VINF_PATM_DUPLICATE_FUNCTION:
480 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPATMDuplicateFn);
481 break;
482 case VINF_PGM_CHANGE_MODE:
483 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPGMChangeMode);
484 break;
485 case VINF_EM_RAW_EMULATE_INSTR_HLT:
486 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetEmulHlt);
487 break;
488 case VINF_EM_PENDING_REQUEST:
489 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPendingRequest);
490 break;
491 default:
492 STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetMisc);
493 break;
494 }
495}
496#endif /* VBOX_WITH_STATISTICS */
497
498
499/**
500 * Unused ring-0 entry point that used to be called from the interrupt gate.
501 *
502 * Will be removed one of the next times we do a major SUPDrv version bump.
503 *
504 * @returns VBox status code.
505 * @param pVM The VM to operate on.
506 * @param enmOperation Which operation to execute.
507 * @param pvArg Argument to the operation.
508 * @remarks Assume called with interrupts disabled.
509 */
510VMMR0DECL(int) VMMR0EntryInt(PVM pVM, VMMR0OPERATION enmOperation, void *pvArg)
511{
512 /*
513 * We're returning VERR_NOT_SUPPORT here so we've got something else
514 * than -1 which the interrupt gate glue code might return.
515 */
516 Log(("operation %#x is not supported\n", enmOperation));
517 return VERR_NOT_SUPPORTED;
518}
519
520
521/**
522 * The Ring 0 entry point, called by the fast-ioctl path.
523 *
524 * @param pVM The VM to operate on.
525 * The return code is stored in pVM->vmm.s.iLastGZRc.
526 * @param idCpu VMCPU id.
527 * @param enmOperation Which operation to execute.
528 * @remarks Assume called with interrupts _enabled_.
529 */
530VMMR0DECL(void) VMMR0EntryFast(PVM pVM, unsigned idCpu, VMMR0OPERATION enmOperation)
531{
532 if (RT_UNLIKELY(idCpu >= pVM->cCPUs))
533 {
534 pVM->vmm.s.iLastGZRc = VERR_INVALID_PARAMETER;
535 return;
536 }
537
538 switch (enmOperation)
539 {
540 /*
541 * Switch to GC and run guest raw mode code.
542 * Disable interrupts before doing the world switch.
543 */
544 case VMMR0_DO_RAW_RUN:
545 {
546 /* Safety precaution as hwaccm disables the switcher. */
547 if (RT_LIKELY(!pVM->vmm.s.fSwitcherDisabled))
548 {
549 RTCCUINTREG uFlags = ASMIntDisableFlags();
550 int rc;
551 bool fVTxDisabled;
552
553 if (RT_UNLIKELY(!PGMGetHyperCR3(pVM)))
554 {
555 pVM->vmm.s.iLastGZRc = VERR_PGM_NO_CR3_SHADOW_ROOT;
556 return;
557 }
558
559 /* We might need to disable VT-x if the active switcher turns off paging. */
560 rc = HWACCMR0EnterSwitcher(pVM, &fVTxDisabled);
561 if (RT_FAILURE(rc))
562 {
563 pVM->vmm.s.iLastGZRc = rc;
564 return;
565 }
566
567 TMNotifyStartOfExecution(pVM);
568 rc = pVM->vmm.s.pfnHostToGuestR0(pVM);
569 pVM->vmm.s.iLastGZRc = rc;
570 TMNotifyEndOfExecution(pVM);
571
572 /* Re-enable VT-x if previously turned off. */
573 HWACCMR0LeaveSwitcher(pVM, fVTxDisabled);
574
575 if ( rc == VINF_EM_RAW_INTERRUPT
576 || rc == VINF_EM_RAW_INTERRUPT_HYPER)
577 TRPMR0DispatchHostInterrupt(pVM);
578
579 ASMSetFlags(uFlags);
580
581#ifdef VBOX_WITH_STATISTICS
582 STAM_COUNTER_INC(&pVM->vmm.s.StatRunRC);
583 vmmR0RecordRC(pVM, rc);
584#endif
585 }
586 else
587 {
588 Assert(!pVM->vmm.s.fSwitcherDisabled);
589 pVM->vmm.s.iLastGZRc = VERR_NOT_SUPPORTED;
590 }
591 break;
592 }
593
594 /*
595 * Run guest code using the available hardware acceleration technology.
596 *
597 * Disable interrupts before we do anything interesting. On Windows we avoid
598 * this by having the support driver raise the IRQL before calling us, this way
599 * we hope to get away with page faults and later calling into the kernel.
600 */
601 case VMMR0_DO_HWACC_RUN:
602 {
603 int rc;
604 PVMCPU pVCpu = &pVM->aCpus[idCpu];
605
606 STAM_COUNTER_INC(&pVM->vmm.s.StatRunRC);
607
608#ifndef RT_OS_WINDOWS /** @todo check other hosts */
609 RTCCUINTREG uFlags = ASMIntDisableFlags();
610#endif
611 if (!HWACCMR0SuspendPending())
612 {
613 rc = HWACCMR0Enter(pVM, pVCpu);
614 if (RT_SUCCESS(rc))
615 {
616 rc = vmmR0CallHostSetJmp(&pVM->vmm.s.CallHostR0JmpBuf, HWACCMR0RunGuestCode, pVM, pVCpu); /* this may resume code. */
617 int rc2 = HWACCMR0Leave(pVM, pVCpu);
618 AssertRC(rc2);
619 }
620 }
621 else
622 {
623 /* System is about to go into suspend mode; go back to ring 3. */
624 rc = VINF_EM_RAW_INTERRUPT;
625 }
626 pVM->vmm.s.iLastGZRc = rc;
627#ifndef RT_OS_WINDOWS /** @todo check other hosts */
628 ASMSetFlags(uFlags);
629#endif
630
631#ifdef VBOX_WITH_STATISTICS
632 vmmR0RecordRC(pVM, rc);
633#endif
634 /* No special action required for external interrupts, just return. */
635 break;
636 }
637
638 /*
639 * For profiling.
640 */
641 case VMMR0_DO_NOP:
642 pVM->vmm.s.iLastGZRc = VINF_SUCCESS;
643 break;
644
645 /*
646 * Impossible.
647 */
648 default:
649 AssertMsgFailed(("%#x\n", enmOperation));
650 pVM->vmm.s.iLastGZRc = VERR_NOT_SUPPORTED;
651 break;
652 }
653}
654
655
656/**
657 * Validates a session or VM session argument.
658 *
659 * @returns true / false accordingly.
660 * @param pVM The VM argument.
661 * @param pSession The session argument.
662 */
663DECLINLINE(bool) vmmR0IsValidSession(PVM pVM, PSUPDRVSESSION pClaimedSession, PSUPDRVSESSION pSession)
664{
665 /* This must be set! */
666 if (!pSession)
667 return false;
668
669 /* Only one out of the two. */
670 if (pVM && pClaimedSession)
671 return false;
672 if (pVM)
673 pClaimedSession = pVM->pSession;
674 return pClaimedSession == pSession;
675}
676
677
678/**
679 * VMMR0EntryEx worker function, either called directly or when ever possible
680 * called thru a longjmp so we can exit safely on failure.
681 *
682 * @returns VBox status code.
683 * @param pVM The VM to operate on.
684 * @param enmOperation Which operation to execute.
685 * @param pReqHdr This points to a SUPVMMR0REQHDR packet. Optional.
686 * The support driver validates this if it's present.
687 * @param u64Arg Some simple constant argument.
688 * @param pSession The session of the caller.
689 * @remarks Assume called with interrupts _enabled_.
690 */
691static int vmmR0EntryExWorker(PVM pVM, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReqHdr, uint64_t u64Arg, PSUPDRVSESSION pSession)
692{
693 /*
694 * Common VM pointer validation.
695 */
696 if (pVM)
697 {
698 if (RT_UNLIKELY( !VALID_PTR(pVM)
699 || ((uintptr_t)pVM & PAGE_OFFSET_MASK)))
700 {
701 SUPR0Printf("vmmR0EntryExWorker: Invalid pVM=%p! (op=%d)\n", pVM, enmOperation);
702 return VERR_INVALID_POINTER;
703 }
704 if (RT_UNLIKELY( pVM->enmVMState < VMSTATE_CREATING
705 || pVM->enmVMState > VMSTATE_TERMINATED
706 || pVM->pVMR0 != pVM))
707 {
708 SUPR0Printf("vmmR0EntryExWorker: Invalid pVM=%p:{enmVMState=%d, .pVMR0=%p}! (op=%d)\n",
709 pVM, pVM->enmVMState, pVM->pVMR0, enmOperation);
710 return VERR_INVALID_POINTER;
711 }
712 }
713
714 switch (enmOperation)
715 {
716 /*
717 * GVM requests
718 */
719 case VMMR0_DO_GVMM_CREATE_VM:
720 if (pVM || u64Arg)
721 return VERR_INVALID_PARAMETER;
722 return GVMMR0CreateVMReq((PGVMMCREATEVMREQ)pReqHdr);
723
724 case VMMR0_DO_GVMM_DESTROY_VM:
725 if (pReqHdr || u64Arg)
726 return VERR_INVALID_PARAMETER;
727 return GVMMR0DestroyVM(pVM);
728
729 case VMMR0_DO_GVMM_SCHED_HALT:
730 if (pReqHdr)
731 return VERR_INVALID_PARAMETER;
732 return GVMMR0SchedHalt(pVM, u64Arg);
733
734 case VMMR0_DO_GVMM_SCHED_WAKE_UP:
735 if (pReqHdr || u64Arg)
736 return VERR_INVALID_PARAMETER;
737 return GVMMR0SchedWakeUp(pVM);
738
739 case VMMR0_DO_GVMM_SCHED_POLL:
740 if (pReqHdr || u64Arg > 1)
741 return VERR_INVALID_PARAMETER;
742 return GVMMR0SchedPoll(pVM, !!u64Arg);
743
744 case VMMR0_DO_GVMM_QUERY_STATISTICS:
745 if (u64Arg)
746 return VERR_INVALID_PARAMETER;
747 return GVMMR0QueryStatisticsReq(pVM, (PGVMMQUERYSTATISTICSSREQ)pReqHdr);
748
749 case VMMR0_DO_GVMM_RESET_STATISTICS:
750 if (u64Arg)
751 return VERR_INVALID_PARAMETER;
752 return GVMMR0ResetStatisticsReq(pVM, (PGVMMRESETSTATISTICSSREQ)pReqHdr);
753
754 /*
755 * Initialize the R0 part of a VM instance.
756 */
757 case VMMR0_DO_VMMR0_INIT:
758 return vmmR0InitVM(pVM, (uint32_t)u64Arg);
759
760 /*
761 * Terminate the R0 part of a VM instance.
762 */
763 case VMMR0_DO_VMMR0_TERM:
764 return VMMR0TermVM(pVM, NULL);
765
766 /*
767 * Attempt to enable hwacc mode and check the current setting.
768 *
769 */
770 case VMMR0_DO_HWACC_ENABLE:
771 return HWACCMR0EnableAllCpus(pVM);
772
773 /*
774 * Setup the hardware accelerated raw-mode session.
775 */
776 case VMMR0_DO_HWACC_SETUP_VM:
777 {
778 RTCCUINTREG fFlags = ASMIntDisableFlags();
779 int rc = HWACCMR0SetupVM(pVM);
780 ASMSetFlags(fFlags);
781 return rc;
782 }
783
784 /*
785 * Switch to GC to execute Hypervisor function.
786 */
787 case VMMR0_DO_CALL_HYPERVISOR:
788 {
789 int rc;
790 bool fVTxDisabled;
791
792 /* Safety precaution as HWACCM can disable the switcher. */
793 Assert(!pVM->vmm.s.fSwitcherDisabled);
794 if (RT_UNLIKELY(pVM->vmm.s.fSwitcherDisabled))
795 return VERR_NOT_SUPPORTED;
796
797 if (RT_UNLIKELY(!PGMGetHyperCR3(pVM)))
798 return VERR_PGM_NO_CR3_SHADOW_ROOT;
799
800 RTCCUINTREG fFlags = ASMIntDisableFlags();
801
802 /* We might need to disable VT-x if the active switcher turns off paging. */
803 rc = HWACCMR0EnterSwitcher(pVM, &fVTxDisabled);
804 if (RT_FAILURE(rc))
805 return rc;
806
807 rc = pVM->vmm.s.pfnHostToGuestR0(pVM);
808
809 /* Re-enable VT-x if previously turned off. */
810 HWACCMR0LeaveSwitcher(pVM, fVTxDisabled);
811
812 /** @todo dispatch interrupts? */
813 ASMSetFlags(fFlags);
814 return rc;
815 }
816
817 /*
818 * PGM wrappers.
819 */
820 case VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES:
821 return PGMR0PhysAllocateHandyPages(pVM);
822
823 /*
824 * GMM wrappers.
825 */
826 case VMMR0_DO_GMM_INITIAL_RESERVATION:
827 if (u64Arg)
828 return VERR_INVALID_PARAMETER;
829 return GMMR0InitialReservationReq(pVM, (PGMMINITIALRESERVATIONREQ)pReqHdr);
830 case VMMR0_DO_GMM_UPDATE_RESERVATION:
831 if (u64Arg)
832 return VERR_INVALID_PARAMETER;
833 return GMMR0UpdateReservationReq(pVM, (PGMMUPDATERESERVATIONREQ)pReqHdr);
834
835 case VMMR0_DO_GMM_ALLOCATE_PAGES:
836 if (u64Arg)
837 return VERR_INVALID_PARAMETER;
838 return GMMR0AllocatePagesReq(pVM, (PGMMALLOCATEPAGESREQ)pReqHdr);
839 case VMMR0_DO_GMM_FREE_PAGES:
840 if (u64Arg)
841 return VERR_INVALID_PARAMETER;
842 return GMMR0FreePagesReq(pVM, (PGMMFREEPAGESREQ)pReqHdr);
843 case VMMR0_DO_GMM_BALLOONED_PAGES:
844 if (u64Arg)
845 return VERR_INVALID_PARAMETER;
846 return GMMR0BalloonedPagesReq(pVM, (PGMMBALLOONEDPAGESREQ)pReqHdr);
847 case VMMR0_DO_GMM_DEFLATED_BALLOON:
848 if (pReqHdr)
849 return VERR_INVALID_PARAMETER;
850 return GMMR0DeflatedBalloon(pVM, (uint32_t)u64Arg);
851
852 case VMMR0_DO_GMM_MAP_UNMAP_CHUNK:
853 if (u64Arg)
854 return VERR_INVALID_PARAMETER;
855 return GMMR0MapUnmapChunkReq(pVM, (PGMMMAPUNMAPCHUNKREQ)pReqHdr);
856 case VMMR0_DO_GMM_SEED_CHUNK:
857 if (pReqHdr)
858 return VERR_INVALID_PARAMETER;
859 return GMMR0SeedChunk(pVM, (RTR3PTR)u64Arg);
860
861 /*
862 * A quick GCFGM mock-up.
863 */
864 /** @todo GCFGM with proper access control, ring-3 management interface and all that. */
865 case VMMR0_DO_GCFGM_SET_VALUE:
866 case VMMR0_DO_GCFGM_QUERY_VALUE:
867 {
868 if (pVM || !pReqHdr || u64Arg)
869 return VERR_INVALID_PARAMETER;
870 PGCFGMVALUEREQ pReq = (PGCFGMVALUEREQ)pReqHdr;
871 if (pReq->Hdr.cbReq != sizeof(*pReq))
872 return VERR_INVALID_PARAMETER;
873 int rc;
874 if (enmOperation == VMMR0_DO_GCFGM_SET_VALUE)
875 {
876 rc = GVMMR0SetConfig(pReq->pSession, &pReq->szName[0], pReq->u64Value);
877 //if (rc == VERR_CFGM_VALUE_NOT_FOUND)
878 // rc = GMMR0SetConfig(pReq->pSession, &pReq->szName[0], pReq->u64Value);
879 }
880 else
881 {
882 rc = GVMMR0QueryConfig(pReq->pSession, &pReq->szName[0], &pReq->u64Value);
883 //if (rc == VERR_CFGM_VALUE_NOT_FOUND)
884 // rc = GMMR0QueryConfig(pReq->pSession, &pReq->szName[0], &pReq->u64Value);
885 }
886 return rc;
887 }
888
889
890 /*
891 * Requests to the internal networking service.
892 */
893 case VMMR0_DO_INTNET_OPEN:
894 {
895 PINTNETOPENREQ pReq = (PINTNETOPENREQ)pReqHdr;
896 if (u64Arg || !pReq || !vmmR0IsValidSession(pVM, pReq->pSession, pSession))
897 return VERR_INVALID_PARAMETER;
898 if (!g_pIntNet)
899 return VERR_NOT_SUPPORTED;
900 return INTNETR0OpenReq(g_pIntNet, pSession, pReq);
901 }
902
903 case VMMR0_DO_INTNET_IF_CLOSE:
904 if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFCLOSEREQ)pReqHdr)->pSession, pSession))
905 return VERR_INVALID_PARAMETER;
906 if (!g_pIntNet)
907 return VERR_NOT_SUPPORTED;
908 return INTNETR0IfCloseReq(g_pIntNet, pSession, (PINTNETIFCLOSEREQ)pReqHdr);
909
910 case VMMR0_DO_INTNET_IF_GET_RING3_BUFFER:
911 if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFGETRING3BUFFERREQ)pReqHdr)->pSession, pSession))
912 return VERR_INVALID_PARAMETER;
913 if (!g_pIntNet)
914 return VERR_NOT_SUPPORTED;
915 return INTNETR0IfGetRing3BufferReq(g_pIntNet, pSession, (PINTNETIFGETRING3BUFFERREQ)pReqHdr);
916
917 case VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE:
918 if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSETPROMISCUOUSMODEREQ)pReqHdr)->pSession, pSession))
919 return VERR_INVALID_PARAMETER;
920 if (!g_pIntNet)
921 return VERR_NOT_SUPPORTED;
922 return INTNETR0IfSetPromiscuousModeReq(g_pIntNet, pSession, (PINTNETIFSETPROMISCUOUSMODEREQ)pReqHdr);
923
924 case VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS:
925 if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSETMACADDRESSREQ)pReqHdr)->pSession, pSession))
926 return VERR_INVALID_PARAMETER;
927 if (!g_pIntNet)
928 return VERR_NOT_SUPPORTED;
929 return INTNETR0IfSetMacAddressReq(g_pIntNet, pSession, (PINTNETIFSETMACADDRESSREQ)pReqHdr);
930
931 case VMMR0_DO_INTNET_IF_SET_ACTIVE:
932 if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSETACTIVEREQ)pReqHdr)->pSession, pSession))
933 return VERR_INVALID_PARAMETER;
934 if (!g_pIntNet)
935 return VERR_NOT_SUPPORTED;
936 return INTNETR0IfSetActiveReq(g_pIntNet, pSession, (PINTNETIFSETACTIVEREQ)pReqHdr);
937
938 case VMMR0_DO_INTNET_IF_SEND:
939 if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSENDREQ)pReqHdr)->pSession, pSession))
940 return VERR_INVALID_PARAMETER;
941 if (!g_pIntNet)
942 return VERR_NOT_SUPPORTED;
943 return INTNETR0IfSendReq(g_pIntNet, pSession, (PINTNETIFSENDREQ)pReqHdr);
944
945 case VMMR0_DO_INTNET_IF_WAIT:
946 if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFWAITREQ)pReqHdr)->pSession, pSession))
947 return VERR_INVALID_PARAMETER;
948 if (!g_pIntNet)
949 return VERR_NOT_SUPPORTED;
950 return INTNETR0IfWaitReq(g_pIntNet, pSession, (PINTNETIFWAITREQ)pReqHdr);
951
952 /*
953 * For profiling.
954 */
955 case VMMR0_DO_NOP:
956 case VMMR0_DO_SLOW_NOP:
957 return VINF_SUCCESS;
958
959 /*
960 * For testing Ring-0 APIs invoked in this environment.
961 */
962 case VMMR0_DO_TESTS:
963 /** @todo make new test */
964 return VINF_SUCCESS;
965
966
967#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
968 case VMMR0_DO_TEST_SWITCHER3264:
969 return HWACCMR0TestSwitcher3264(pVM);
970#endif
971 default:
972 /*
973 * We're returning VERR_NOT_SUPPORT here so we've got something else
974 * than -1 which the interrupt gate glue code might return.
975 */
976 Log(("operation %#x is not supported\n", enmOperation));
977 return VERR_NOT_SUPPORTED;
978 }
979}
980
981
982/**
983 * Argument for vmmR0EntryExWrapper containing the argument s ofr VMMR0EntryEx.
984 */
985typedef struct VMMR0ENTRYEXARGS
986{
987 PVM pVM;
988 VMMR0OPERATION enmOperation;
989 PSUPVMMR0REQHDR pReq;
990 uint64_t u64Arg;
991 PSUPDRVSESSION pSession;
992} VMMR0ENTRYEXARGS;
993/** Pointer to a vmmR0EntryExWrapper argument package. */
994typedef VMMR0ENTRYEXARGS *PVMMR0ENTRYEXARGS;
995
996/**
997 * This is just a longjmp wrapper function for VMMR0EntryEx calls.
998 *
999 * @returns VBox status code.
1000 * @param pvArgs The argument package
1001 */
1002static int vmmR0EntryExWrapper(void *pvArgs)
1003{
1004 return vmmR0EntryExWorker(((PVMMR0ENTRYEXARGS)pvArgs)->pVM,
1005 ((PVMMR0ENTRYEXARGS)pvArgs)->enmOperation,
1006 ((PVMMR0ENTRYEXARGS)pvArgs)->pReq,
1007 ((PVMMR0ENTRYEXARGS)pvArgs)->u64Arg,
1008 ((PVMMR0ENTRYEXARGS)pvArgs)->pSession);
1009}
1010
1011
1012/**
1013 * The Ring 0 entry point, called by the support library (SUP).
1014 *
1015 * @returns VBox status code.
1016 * @param pVM The VM to operate on.
1017 * @param enmOperation Which operation to execute.
1018 * @param pReq This points to a SUPVMMR0REQHDR packet. Optional.
1019 * @param u64Arg Some simple constant argument.
1020 * @param pSession The session of the caller.
1021 * @remarks Assume called with interrupts _enabled_.
1022 */
1023VMMR0DECL(int) VMMR0EntryEx(PVM pVM, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION pSession)
1024{
1025 /*
1026 * Requests that should only happen on the EMT thread will be
1027 * wrapped in a setjmp so we can assert without causing trouble.
1028 */
1029 if ( VALID_PTR(pVM)
1030 && pVM->pVMR0)
1031 {
1032 switch (enmOperation)
1033 {
1034 /* These might/will be called before VMMR3Init. */
1035 case VMMR0_DO_GMM_INITIAL_RESERVATION:
1036 case VMMR0_DO_GMM_UPDATE_RESERVATION:
1037 case VMMR0_DO_GMM_ALLOCATE_PAGES:
1038 case VMMR0_DO_GMM_FREE_PAGES:
1039 case VMMR0_DO_GMM_BALLOONED_PAGES:
1040 case VMMR0_DO_GMM_DEFLATED_BALLOON:
1041 case VMMR0_DO_GMM_MAP_UNMAP_CHUNK:
1042 case VMMR0_DO_GMM_SEED_CHUNK:
1043 /* On the mac we might not have a valid jmp buf, so check these as well. */
1044 case VMMR0_DO_VMMR0_INIT:
1045 case VMMR0_DO_VMMR0_TERM:
1046 {
1047 if (!pVM->vmm.s.CallHostR0JmpBuf.pvSavedStack)
1048 break;
1049
1050 /** @todo validate this EMT claim... GVM knows. */
1051 VMMR0ENTRYEXARGS Args;
1052 Args.pVM = pVM;
1053 Args.enmOperation = enmOperation;
1054 Args.pReq = pReq;
1055 Args.u64Arg = u64Arg;
1056 Args.pSession = pSession;
1057 return vmmR0CallHostSetJmpEx(&pVM->vmm.s.CallHostR0JmpBuf, vmmR0EntryExWrapper, &Args);
1058 }
1059
1060 default:
1061 break;
1062 }
1063 }
1064 return vmmR0EntryExWorker(pVM, enmOperation, pReq, u64Arg, pSession);
1065}
1066
1067
1068/**
1069 * Internal R0 logger worker: Flush logger.
1070 *
1071 * @param pLogger The logger instance to flush.
1072 * @remark This function must be exported!
1073 */
1074VMMR0DECL(void) vmmR0LoggerFlush(PRTLOGGER pLogger)
1075{
1076 /*
1077 * Convert the pLogger into a VM handle and 'call' back to Ring-3.
1078 * (This is a bit paranoid code.)
1079 */
1080 PVMMR0LOGGER pR0Logger = (PVMMR0LOGGER)((uintptr_t)pLogger - RT_OFFSETOF(VMMR0LOGGER, Logger));
1081 if ( !VALID_PTR(pR0Logger)
1082 || !VALID_PTR(pR0Logger + 1)
1083 || pLogger->u32Magic != RTLOGGER_MAGIC)
1084 {
1085#ifdef DEBUG
1086 SUPR0Printf("vmmR0LoggerFlush: pLogger=%p!\n", pLogger);
1087#endif
1088 return;
1089 }
1090 if (pR0Logger->fFlushingDisabled)
1091 return; /* quietly */
1092
1093 PVM pVM = pR0Logger->pVM;
1094 if ( !VALID_PTR(pVM)
1095 || pVM->pVMR0 != pVM)
1096 {
1097#ifdef DEBUG
1098 SUPR0Printf("vmmR0LoggerFlush: pVM=%p! pVMR0=%p! pLogger=%p\n", pVM, pVM->pVMR0, pLogger);
1099#endif
1100 return;
1101 }
1102
1103 /*
1104 * Check that the jump buffer is armed.
1105 */
1106#ifdef RT_ARCH_X86
1107 if (!pVM->vmm.s.CallHostR0JmpBuf.eip)
1108#else
1109 if (!pVM->vmm.s.CallHostR0JmpBuf.rip)
1110#endif
1111 {
1112#ifdef DEBUG
1113 SUPR0Printf("vmmR0LoggerFlush: Jump buffer isn't armed!\n");
1114#endif
1115 return;
1116 }
1117 VMMR0CallHost(pVM, VMMCALLHOST_VMM_LOGGER_FLUSH, 0);
1118}
1119
1120
1121/**
1122 * Disables flushing of the ring-0 debug log.
1123 *
1124 * @param pVCpu The shared virtual cpu structure.
1125 */
1126VMMR0DECL(void) VMMR0LogFlushDisable(PVMCPU pVCpu)
1127{
1128 PVM pVM = pVCpu->pVMR0;
1129 if (pVM->vmm.s.pR0LoggerR0)
1130 pVM->vmm.s.pR0LoggerR0->fFlushingDisabled = true;
1131}
1132
1133
1134/**
1135 * Enables flushing of the ring-0 debug log.
1136 *
1137 * @param pVCpu The shared virtual cpu structure.
1138 */
1139VMMR0DECL(void) VMMR0LogFlushEnable(PVMCPU pVCpu)
1140{
1141 PVM pVM = pVCpu->pVMR0;
1142 if (pVM->vmm.s.pR0LoggerR0)
1143 pVM->vmm.s.pR0LoggerR0->fFlushingDisabled = false;
1144}
1145
1146
1147/**
1148 * Jump back to ring-3 if we're the EMT and the longjmp is armed.
1149 *
1150 * @returns true if the breakpoint should be hit, false if it should be ignored.
1151 */
1152DECLEXPORT(bool) RTCALL RTAssertShouldPanic(void)
1153{
1154#if 0
1155 return true;
1156#else
1157 PVM pVM = GVMMR0GetVMByEMT(NIL_RTNATIVETHREAD);
1158 if (pVM)
1159 {
1160#ifdef RT_ARCH_X86
1161 if (pVM->vmm.s.CallHostR0JmpBuf.eip)
1162#else
1163 if (pVM->vmm.s.CallHostR0JmpBuf.rip)
1164#endif
1165 {
1166 int rc = VMMR0CallHost(pVM, VMMCALLHOST_VM_R0_ASSERTION, 0);
1167 return RT_FAILURE_NP(rc);
1168 }
1169 }
1170#ifdef RT_OS_LINUX
1171 return true;
1172#else
1173 return false;
1174#endif
1175#endif
1176}
1177
1178
1179/**
1180 * Override this so we can push it up to ring-3.
1181 *
1182 * @param pszExpr Expression. Can be NULL.
1183 * @param uLine Location line number.
1184 * @param pszFile Location file name.
1185 * @param pszFunction Location function name.
1186 */
1187DECLEXPORT(void) RTCALL AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
1188{
1189#if !defined(DEBUG_sandervl) && !defined(RT_OS_DARWIN)
1190 SUPR0Printf("\n!!R0-Assertion Failed!!\n"
1191 "Expression: %s\n"
1192 "Location : %s(%d) %s\n",
1193 pszExpr, pszFile, uLine, pszFunction);
1194#endif
1195 LogAlways(("\n!!R0-Assertion Failed!!\n"
1196 "Expression: %s\n"
1197 "Location : %s(%d) %s\n",
1198 pszExpr, pszFile, uLine, pszFunction));
1199
1200 PVM pVM = GVMMR0GetVMByEMT(NIL_RTNATIVETHREAD);
1201 if (pVM)
1202 RTStrPrintf(pVM->vmm.s.szRing0AssertMsg1, sizeof(pVM->vmm.s.szRing0AssertMsg1),
1203 "\n!!R0-Assertion Failed!!\n"
1204 "Expression: %s\n"
1205 "Location : %s(%d) %s\n",
1206 pszExpr, pszFile, uLine, pszFunction);
1207#ifdef RT_OS_DARWIN
1208 RTAssertMsg1(pszExpr, uLine, pszFile, pszFunction);
1209#endif
1210}
1211
1212
1213/**
1214 * Callback for RTLogFormatV which writes to the ring-3 log port.
1215 * See PFNLOGOUTPUT() for details.
1216 */
1217static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars)
1218{
1219 for (size_t i = 0; i < cbChars; i++)
1220 {
1221#if !defined(DEBUG_sandervl) && !defined(RT_OS_DARWIN)
1222 SUPR0Printf("%c", pachChars[i]);
1223#endif
1224 LogAlways(("%c", pachChars[i]));
1225 }
1226
1227 return cbChars;
1228}
1229
1230
1231DECLEXPORT(void) RTCALL AssertMsg2(const char *pszFormat, ...)
1232{
1233 va_list va;
1234
1235 PRTLOGGER pLog = RTLogDefaultInstance(); /** @todo we want this for release as well! */
1236 if (pLog)
1237 {
1238 va_start(va, pszFormat);
1239 RTLogFormatV(rtLogOutput, pLog, pszFormat, va);
1240 va_end(va);
1241
1242 PVM pVM = GVMMR0GetVMByEMT(NIL_RTNATIVETHREAD);
1243 if (pVM)
1244 {
1245 va_start(va, pszFormat);
1246 RTStrPrintfV(pVM->vmm.s.szRing0AssertMsg2, sizeof(pVM->vmm.s.szRing0AssertMsg2), pszFormat, va);
1247 va_end(va);
1248 }
1249 }
1250
1251#ifdef RT_OS_DARWIN
1252 va_start(va, pszFormat);
1253 RTAssertMsg2V(pszFormat, va);
1254 va_end(va);
1255#endif
1256}
1257
Note: See TracBrowser for help on using the repository browser.

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