VirtualBox

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

Last change on this file since 10601 was 10450, checked in by vboxsync, 17 years ago

Added VMMGetSvnRev() (exported) and changed VMMR0Init and VMMGCInit check the the revision is the same. (We've got private interface between ring-3 and ring-0 and GC, not to mention shared structures, so this check is really long overdue.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 36.7 KB
Line 
1/* $Id: VMMR0.cpp 10450 2008-07-09 21:55:45Z 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/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_VMM
27#include <VBox/vmm.h>
28#include <VBox/sup.h>
29#include <VBox/trpm.h>
30#include <VBox/cpum.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
48#if defined(_MSC_VER) && defined(RT_ARCH_AMD64) /** @todo check this with with VC7! */
49# pragma intrinsic(_AddressOfReturnAddress)
50#endif
51
52
53/*******************************************************************************
54* Internal Functions *
55*******************************************************************************/
56static int VMMR0Init(PVM pVM, uint32_t uSvnRev);
57static int VMMR0Term(PVM pVM);
58__BEGIN_DECLS
59VMMR0DECL(int) ModuleInit(void);
60VMMR0DECL(void) ModuleTerm(void);
61__END_DECLS
62
63
64/*******************************************************************************
65* Global Variables *
66*******************************************************************************/
67#ifdef VBOX_WITH_INTERNAL_NETWORKING
68/** Pointer to the internal networking service instance. */
69PINTNET g_pIntNet = 0;
70#endif
71
72
73/**
74 * Initialize the module.
75 * This is called when we're first loaded.
76 *
77 * @returns 0 on success.
78 * @returns VBox status on failure.
79 */
80VMMR0DECL(int) ModuleInit(void)
81{
82 LogFlow(("ModuleInit:\n"));
83
84 /*
85 * Initialize the GVMM, GMM.& HWACCM
86 */
87 int rc = GVMMR0Init();
88 if (RT_SUCCESS(rc))
89 {
90 rc = GMMR0Init();
91 if (RT_SUCCESS(rc))
92 {
93 rc = HWACCMR0Init();
94 if (RT_SUCCESS(rc))
95 {
96#ifdef VBOX_WITH_INTERNAL_NETWORKING
97 LogFlow(("ModuleInit: g_pIntNet=%p\n", g_pIntNet));
98 g_pIntNet = NULL;
99 LogFlow(("ModuleInit: g_pIntNet=%p should be NULL now...\n", g_pIntNet));
100 rc = INTNETR0Create(&g_pIntNet);
101 if (VBOX_SUCCESS(rc))
102 {
103 LogFlow(("ModuleInit: returns success. g_pIntNet=%p\n", g_pIntNet));
104 return VINF_SUCCESS;
105 }
106 g_pIntNet = NULL;
107 LogFlow(("ModuleTerm: returns %Vrc\n", rc));
108#else
109 LogFlow(("ModuleInit: returns success.\n"));
110 return VINF_SUCCESS;
111#endif
112 }
113 }
114 }
115
116 LogFlow(("ModuleInit: failed %Rrc\n", rc));
117 return rc;
118}
119
120
121/**
122 * Terminate the module.
123 * This is called when we're finally unloaded.
124 */
125VMMR0DECL(void) ModuleTerm(void)
126{
127 LogFlow(("ModuleTerm:\n"));
128
129#ifdef VBOX_WITH_INTERNAL_NETWORKING
130 /*
131 * Destroy the internal networking instance.
132 */
133 if (g_pIntNet)
134 {
135 INTNETR0Destroy(g_pIntNet);
136 g_pIntNet = NULL;
137 }
138#endif
139
140 /* Global HWACCM cleanup */
141 HWACCMR0Term();
142
143 /*
144 * Destroy the GMM and GVMM instances.
145 */
146 GMMR0Term();
147 GVMMR0Term();
148
149 LogFlow(("ModuleTerm: returns\n"));
150}
151
152
153/**
154 * Initaties the R0 driver for a particular VM instance.
155 *
156 * @returns VBox status code.
157 *
158 * @param pVM The VM instance in question.
159 * @param uSvnRev The SVN revision of the ring-3 part.
160 * @thread EMT.
161 */
162static int VMMR0Init(PVM pVM, uint32_t uSvnRev)
163{
164 /*
165 * Match the SVN revisions.
166 */
167 if (uSvnRev != VMMGetSvnRev())
168 return VERR_VERSION_MISMATCH;
169 if ( !VALID_PTR(pVM)
170 || pVM->pVMR0 != pVM)
171 return VERR_INVALID_PARAMETER;
172
173 /*
174 * Register the EMT R0 logger instance.
175 */
176 PVMMR0LOGGER pR0Logger = pVM->vmm.s.pR0Logger;
177 if (pR0Logger)
178 {
179#if 0 /* testing of the logger. */
180 LogCom(("VMMR0Init: before %p\n", RTLogDefaultInstance()));
181 LogCom(("VMMR0Init: pfnFlush=%p actual=%p\n", pR0Logger->Logger.pfnFlush, vmmR0LoggerFlush));
182 LogCom(("VMMR0Init: pfnLogger=%p actual=%p\n", pR0Logger->Logger.pfnLogger, vmmR0LoggerWrapper));
183 LogCom(("VMMR0Init: offScratch=%d fFlags=%#x fDestFlags=%#x\n", pR0Logger->Logger.offScratch, pR0Logger->Logger.fFlags, pR0Logger->Logger.fDestFlags));
184
185 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
186 LogCom(("VMMR0Init: after %p reg\n", RTLogDefaultInstance()));
187 RTLogSetDefaultInstanceThread(NULL, 0);
188 LogCom(("VMMR0Init: after %p dereg\n", RTLogDefaultInstance()));
189
190 pR0Logger->Logger.pfnLogger("hello ring-0 logger\n");
191 LogCom(("VMMR0Init: returned succesfully from direct logger call.\n"));
192 pR0Logger->Logger.pfnFlush(&pR0Logger->Logger);
193 LogCom(("VMMR0Init: returned succesfully from direct flush call.\n"));
194
195 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
196 LogCom(("VMMR0Init: after %p reg2\n", RTLogDefaultInstance()));
197 pR0Logger->Logger.pfnLogger("hello ring-0 logger\n");
198 LogCom(("VMMR0Init: returned succesfully from direct logger call (2). offScratch=%d\n", pR0Logger->Logger.offScratch));
199 RTLogSetDefaultInstanceThread(NULL, 0);
200 LogCom(("VMMR0Init: after %p dereg2\n", RTLogDefaultInstance()));
201
202 RTLogLoggerEx(&pR0Logger->Logger, 0, ~0U, "hello ring-0 logger (RTLogLoggerEx)\n");
203 LogCom(("VMMR0Init: RTLogLoggerEx returned fine offScratch=%d\n", pR0Logger->Logger.offScratch));
204
205 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
206 RTLogPrintf("hello ring-0 logger (RTLogPrintf)\n");
207 LogCom(("VMMR0Init: RTLogPrintf returned fine offScratch=%d\n", pR0Logger->Logger.offScratch));
208#endif
209 Log(("Switching to per-thread logging instance %p (key=%p)\n", &pR0Logger->Logger, pVM->pSession));
210 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
211 }
212
213 /*
214 * Initialize the per VM data for GVMM and GMM.
215 */
216 int rc = GVMMR0InitVM(pVM);
217// if (RT_SUCCESS(rc))
218// rc = GMMR0InitPerVMData(pVM);
219 if (RT_SUCCESS(rc))
220 {
221 /*
222 * Init HWACCM.
223 */
224 rc = HWACCMR0InitVM(pVM);
225 if (RT_SUCCESS(rc))
226 {
227 /*
228 * Init CPUM.
229 */
230 rc = CPUMR0Init(pVM);
231 if (RT_SUCCESS(rc))
232 return rc;
233 }
234 }
235
236 /* failed */
237 RTLogSetDefaultInstanceThread(NULL, 0);
238 return rc;
239}
240
241
242/**
243 * Terminates the R0 driver for a particular VM instance.
244 *
245 * @returns VBox status code.
246 *
247 * @param pVM The VM instance in question.
248 * @thread EMT.
249 */
250static int VMMR0Term(PVM pVM)
251{
252 HWACCMR0TermVM(pVM);
253
254 /*
255 * Deregister the logger.
256 */
257 RTLogSetDefaultInstanceThread(NULL, 0);
258 return VINF_SUCCESS;
259}
260
261
262/**
263 * Calls the ring-3 host code.
264 *
265 * @returns VBox status code of the ring-3 call.
266 * @param pVM The VM handle.
267 * @param enmOperation The operation.
268 * @param uArg The argument to the operation.
269 */
270VMMR0DECL(int) VMMR0CallHost(PVM pVM, VMMCALLHOST enmOperation, uint64_t uArg)
271{
272/** @todo profile this! */
273 pVM->vmm.s.enmCallHostOperation = enmOperation;
274 pVM->vmm.s.u64CallHostArg = uArg;
275 pVM->vmm.s.rcCallHost = VERR_INTERNAL_ERROR;
276 int rc = vmmR0CallHostLongJmp(&pVM->vmm.s.CallHostR0JmpBuf, VINF_VMM_CALL_HOST);
277 if (rc == VINF_SUCCESS)
278 rc = pVM->vmm.s.rcCallHost;
279 return rc;
280}
281
282
283#ifdef VBOX_WITH_STATISTICS
284/**
285 * Record return code statistics
286 * @param pVM The VM handle.
287 * @param rc The status code.
288 */
289static void vmmR0RecordRC(PVM pVM, int rc)
290{
291 /*
292 * Collect statistics.
293 */
294 switch (rc)
295 {
296 case VINF_SUCCESS:
297 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetNormal);
298 break;
299 case VINF_EM_RAW_INTERRUPT:
300 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetInterrupt);
301 break;
302 case VINF_EM_RAW_INTERRUPT_HYPER:
303 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetInterruptHyper);
304 break;
305 case VINF_EM_RAW_GUEST_TRAP:
306 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetGuestTrap);
307 break;
308 case VINF_EM_RAW_RING_SWITCH:
309 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetRingSwitch);
310 break;
311 case VINF_EM_RAW_RING_SWITCH_INT:
312 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetRingSwitchInt);
313 break;
314 case VINF_EM_RAW_EXCEPTION_PRIVILEGED:
315 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetExceptionPrivilege);
316 break;
317 case VINF_EM_RAW_STALE_SELECTOR:
318 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetStaleSelector);
319 break;
320 case VINF_EM_RAW_IRET_TRAP:
321 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetIRETTrap);
322 break;
323 case VINF_IOM_HC_IOPORT_READ:
324 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetIORead);
325 break;
326 case VINF_IOM_HC_IOPORT_WRITE:
327 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetIOWrite);
328 break;
329 case VINF_IOM_HC_MMIO_READ:
330 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMMIORead);
331 break;
332 case VINF_IOM_HC_MMIO_WRITE:
333 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMMIOWrite);
334 break;
335 case VINF_IOM_HC_MMIO_READ_WRITE:
336 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMMIOReadWrite);
337 break;
338 case VINF_PATM_HC_MMIO_PATCH_READ:
339 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMMIOPatchRead);
340 break;
341 case VINF_PATM_HC_MMIO_PATCH_WRITE:
342 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMMIOPatchWrite);
343 break;
344 case VINF_EM_RAW_EMULATE_INSTR:
345 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetEmulate);
346 break;
347 case VINF_PATCH_EMULATE_INSTR:
348 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPatchEmulate);
349 break;
350 case VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT:
351 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetLDTFault);
352 break;
353 case VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT:
354 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetGDTFault);
355 break;
356 case VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT:
357 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetIDTFault);
358 break;
359 case VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT:
360 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetTSSFault);
361 break;
362 case VINF_EM_RAW_EMULATE_INSTR_PD_FAULT:
363 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPDFault);
364 break;
365 case VINF_CSAM_PENDING_ACTION:
366 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetCSAMTask);
367 break;
368 case VINF_PGM_SYNC_CR3:
369 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetSyncCR3);
370 break;
371 case VINF_PATM_PATCH_INT3:
372 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPatchInt3);
373 break;
374 case VINF_PATM_PATCH_TRAP_PF:
375 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPatchPF);
376 break;
377 case VINF_PATM_PATCH_TRAP_GP:
378 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPatchGP);
379 break;
380 case VINF_PATM_PENDING_IRQ_AFTER_IRET:
381 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPatchIretIRQ);
382 break;
383 case VERR_REM_FLUSHED_PAGES_OVERFLOW:
384 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPageOverflow);
385 break;
386 case VINF_EM_RESCHEDULE_REM:
387 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetRescheduleREM);
388 break;
389 case VINF_EM_RAW_TO_R3:
390 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetToR3);
391 break;
392 case VINF_EM_RAW_TIMER_PENDING:
393 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetTimerPending);
394 break;
395 case VINF_EM_RAW_INTERRUPT_PENDING:
396 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetInterruptPending);
397 break;
398 case VINF_VMM_CALL_HOST:
399 switch (pVM->vmm.s.enmCallHostOperation)
400 {
401 case VMMCALLHOST_PDM_LOCK:
402 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPDMLock);
403 break;
404 case VMMCALLHOST_PDM_QUEUE_FLUSH:
405 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPDMQueueFlush);
406 break;
407 case VMMCALLHOST_PGM_POOL_GROW:
408 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPGMPoolGrow);
409 break;
410 case VMMCALLHOST_PGM_LOCK:
411 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPGMLock);
412 break;
413 case VMMCALLHOST_REM_REPLAY_HANDLER_NOTIFICATIONS:
414 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetRemReplay);
415 break;
416 case VMMCALLHOST_PGM_RAM_GROW_RANGE:
417 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPGMGrowRAM);
418 break;
419 case VMMCALLHOST_VMM_LOGGER_FLUSH:
420 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetLogFlush);
421 break;
422 case VMMCALLHOST_VM_SET_ERROR:
423 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetVMSetError);
424 break;
425 case VMMCALLHOST_VM_SET_RUNTIME_ERROR:
426 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetVMSetRuntimeError);
427 break;
428 case VMMCALLHOST_VM_R0_HYPER_ASSERTION:
429 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetHyperAssertion);
430 break;
431 default:
432 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetCallHost);
433 break;
434 }
435 break;
436 case VINF_PATM_DUPLICATE_FUNCTION:
437 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPATMDuplicateFn);
438 break;
439 case VINF_PGM_CHANGE_MODE:
440 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPGMChangeMode);
441 break;
442 case VINF_EM_RAW_EMULATE_INSTR_HLT:
443 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetEmulHlt);
444 break;
445 case VINF_EM_PENDING_REQUEST:
446 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPendingRequest);
447 break;
448 default:
449 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMisc);
450 break;
451 }
452}
453#endif /* VBOX_WITH_STATISTICS */
454
455
456
457/**
458 * The Ring 0 entry point, called by the interrupt gate.
459 *
460 * @returns VBox status code.
461 * @param pVM The VM to operate on.
462 * @param enmOperation Which operation to execute.
463 * @param pvArg Argument to the operation.
464 * @remarks Assume called with interrupts disabled.
465 */
466VMMR0DECL(int) VMMR0EntryInt(PVM pVM, VMMR0OPERATION enmOperation, void *pvArg)
467{
468 switch (enmOperation)
469 {
470#ifdef VBOX_WITH_IDT_PATCHING
471 /*
472 * Switch to GC.
473 * These calls return whatever the GC returns.
474 */
475 case VMMR0_DO_RAW_RUN:
476 {
477 /* Safety precaution as VMX disables the switcher. */
478 Assert(!pVM->vmm.s.fSwitcherDisabled);
479 if (pVM->vmm.s.fSwitcherDisabled)
480 return VERR_NOT_SUPPORTED;
481
482 STAM_COUNTER_INC(&pVM->vmm.s.StatRunGC);
483 register int rc;
484 pVM->vmm.s.iLastGCRc = rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
485
486#ifdef VBOX_WITH_STATISTICS
487 vmmR0RecordRC(pVM, rc);
488#endif
489
490 /*
491 * We'll let TRPM change the stack frame so our return is different.
492 * Just keep in mind that after the call, things have changed!
493 */
494 if ( rc == VINF_EM_RAW_INTERRUPT
495 || rc == VINF_EM_RAW_INTERRUPT_HYPER)
496 {
497 /*
498 * Don't trust the compiler to get this right.
499 * gcc -fomit-frame-pointer screws up big time here. This works fine in 64-bit
500 * mode too because we push the arguments on the stack in the IDT patch code.
501 */
502# if defined(__GNUC__)
503 void *pvRet = (uint8_t *)__builtin_frame_address(0) + sizeof(void *);
504# elif defined(_MSC_VER) && defined(RT_ARCH_AMD64) /** @todo check this with with VC7! */
505 void *pvRet = (uint8_t *)_AddressOfReturnAddress();
506# elif defined(RT_ARCH_X86)
507 void *pvRet = (uint8_t *)&pVM - sizeof(pVM);
508# else
509# error "huh?"
510# endif
511 if ( ((uintptr_t *)pvRet)[1] == (uintptr_t)pVM
512 && ((uintptr_t *)pvRet)[2] == (uintptr_t)enmOperation
513 && ((uintptr_t *)pvRet)[3] == (uintptr_t)pvArg)
514 TRPMR0SetupInterruptDispatcherFrame(pVM, pvRet);
515 else
516 {
517# if defined(DEBUG) || defined(LOG_ENABLED)
518 static bool s_fHaveWarned = false;
519 if (!s_fHaveWarned)
520 {
521 s_fHaveWarned = true;
522 RTLogPrintf("VMMR0.r0: The compiler can't find the stack frame!\n");
523 RTLogComPrintf("VMMR0.r0: The compiler can't find the stack frame!\n");
524 }
525# endif
526 TRPMR0DispatchHostInterrupt(pVM);
527 }
528 }
529 return rc;
530 }
531
532 /*
533 * Switch to GC to execute Hypervisor function.
534 */
535 case VMMR0_DO_CALL_HYPERVISOR:
536 {
537 /* Safety precaution as VMX disables the switcher. */
538 Assert(!pVM->vmm.s.fSwitcherDisabled);
539 if (pVM->vmm.s.fSwitcherDisabled)
540 return VERR_NOT_SUPPORTED;
541
542 RTCCUINTREG fFlags = ASMIntDisableFlags();
543 int rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
544 /** @todo dispatch interrupts? */
545 ASMSetFlags(fFlags);
546 return rc;
547 }
548
549 /*
550 * For profiling.
551 */
552 case VMMR0_DO_NOP:
553 return VINF_SUCCESS;
554#endif /* VBOX_WITH_IDT_PATCHING */
555
556 default:
557 /*
558 * We're returning VERR_NOT_SUPPORT here so we've got something else
559 * than -1 which the interrupt gate glue code might return.
560 */
561 Log(("operation %#x is not supported\n", enmOperation));
562 return VERR_NOT_SUPPORTED;
563 }
564}
565
566
567/**
568 * The Ring 0 entry point, called by the fast-ioctl path.
569 *
570 * @returns VBox status code.
571 * @param pVM The VM to operate on.
572 * @param enmOperation Which operation to execute.
573 * @remarks Assume called with interrupts _enabled_.
574 */
575VMMR0DECL(int) VMMR0EntryFast(PVM pVM, VMMR0OPERATION enmOperation)
576{
577 switch (enmOperation)
578 {
579 /*
580 * Switch to GC and run guest raw mode code.
581 * Disable interrupts before doing the world switch.
582 */
583 case VMMR0_DO_RAW_RUN:
584 {
585 /* Safety precaution as hwaccm disables the switcher. */
586 if (RT_LIKELY(!pVM->vmm.s.fSwitcherDisabled))
587 {
588 RTCCUINTREG uFlags = ASMIntDisableFlags();
589
590 int rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
591 pVM->vmm.s.iLastGCRc = rc;
592
593 if ( rc == VINF_EM_RAW_INTERRUPT
594 || rc == VINF_EM_RAW_INTERRUPT_HYPER)
595 TRPMR0DispatchHostInterrupt(pVM);
596
597 ASMSetFlags(uFlags);
598
599#ifdef VBOX_WITH_STATISTICS
600 STAM_COUNTER_INC(&pVM->vmm.s.StatRunGC);
601 vmmR0RecordRC(pVM, rc);
602#endif
603 return rc;
604 }
605
606 Assert(!pVM->vmm.s.fSwitcherDisabled);
607 return VERR_NOT_SUPPORTED;
608 }
609
610 /*
611 * Run guest code using the available hardware acceleration technology.
612 *
613 * Disable interrupts before we do anything interesting. On Windows we avoid
614 * this by having the support driver raise the IRQL before calling us, this way
615 * we hope to get away we page faults and later calling into the kernel.
616 */
617 case VMMR0_DO_HWACC_RUN:
618 {
619 STAM_COUNTER_INC(&pVM->vmm.s.StatRunGC);
620
621#ifndef RT_OS_WINDOWS /** @todo check other hosts */
622 RTCCUINTREG uFlags = ASMIntDisableFlags();
623#endif
624 int rc = HWACCMR0Enter(pVM);
625 if (VBOX_SUCCESS(rc))
626 {
627 rc = vmmR0CallHostSetJmp(&pVM->vmm.s.CallHostR0JmpBuf, HWACCMR0RunGuestCode, pVM); /* this may resume code. */
628 int rc2 = HWACCMR0Leave(pVM);
629 AssertRC(rc2);
630 }
631 pVM->vmm.s.iLastGCRc = rc;
632#ifndef RT_OS_WINDOWS /** @todo check other hosts */
633 ASMSetFlags(uFlags);
634#endif
635
636#ifdef VBOX_WITH_STATISTICS
637 vmmR0RecordRC(pVM, rc);
638#endif
639 /* No special action required for external interrupts, just return. */
640 return rc;
641 }
642
643 /*
644 * For profiling.
645 */
646 case VMMR0_DO_NOP:
647 return VINF_SUCCESS;
648
649 /*
650 * Impossible.
651 */
652 default:
653 AssertMsgFailed(("%#x\n", enmOperation));
654 return VERR_NOT_SUPPORTED;
655 }
656}
657
658
659/**
660 * VMMR0EntryEx worker function, either called directly or when ever possible
661 * called thru a longjmp so we can exit safely on failure.
662 *
663 * @returns VBox status code.
664 * @param pVM The VM to operate on.
665 * @param enmOperation Which operation to execute.
666 * @param pReqHdr This points to a SUPVMMR0REQHDR packet. Optional.
667 * @param u64Arg Some simple constant argument.
668 * @remarks Assume called with interrupts _enabled_.
669 */
670static int vmmR0EntryExWorker(PVM pVM, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReqHdr, uint64_t u64Arg)
671{
672 /*
673 * Common VM pointer validation.
674 */
675 if (pVM)
676 {
677 if (RT_UNLIKELY( !VALID_PTR(pVM)
678 || ((uintptr_t)pVM & PAGE_OFFSET_MASK)))
679 {
680 SUPR0Printf("vmmR0EntryExWorker: Invalid pVM=%p! (op=%d)\n", pVM, enmOperation);
681 return VERR_INVALID_POINTER;
682 }
683 if (RT_UNLIKELY( pVM->enmVMState < VMSTATE_CREATING
684 || pVM->enmVMState > VMSTATE_TERMINATED
685 || pVM->pVMR0 != pVM))
686 {
687 SUPR0Printf("vmmR0EntryExWorker: Invalid pVM=%p:{enmVMState=%d, .pVMR0=%p}! (op=%d)\n",
688 pVM, pVM->enmVMState, pVM->pVMR0, enmOperation);
689 return VERR_INVALID_POINTER;
690 }
691 }
692
693 switch (enmOperation)
694 {
695 /*
696 * GVM requests
697 */
698 case VMMR0_DO_GVMM_CREATE_VM:
699 if (pVM || u64Arg)
700 return VERR_INVALID_PARAMETER;
701 return GVMMR0CreateVMReq((PGVMMCREATEVMREQ)pReqHdr);
702
703 case VMMR0_DO_GVMM_DESTROY_VM:
704 if (pReqHdr || u64Arg)
705 return VERR_INVALID_PARAMETER;
706 return GVMMR0DestroyVM(pVM);
707
708 case VMMR0_DO_GVMM_SCHED_HALT:
709 if (pReqHdr)
710 return VERR_INVALID_PARAMETER;
711 return GVMMR0SchedHalt(pVM, u64Arg);
712
713 case VMMR0_DO_GVMM_SCHED_WAKE_UP:
714 if (pReqHdr || u64Arg)
715 return VERR_INVALID_PARAMETER;
716 return GVMMR0SchedWakeUp(pVM);
717
718 case VMMR0_DO_GVMM_SCHED_POLL:
719 if (pReqHdr || u64Arg > 1)
720 return VERR_INVALID_PARAMETER;
721 return GVMMR0SchedPoll(pVM, (bool)u64Arg);
722
723 case VMMR0_DO_GVMM_QUERY_STATISTICS:
724 if (u64Arg)
725 return VERR_INVALID_PARAMETER;
726 return GVMMR0QueryStatisticsReq(pVM, (PGVMMQUERYSTATISTICSSREQ)pReqHdr);
727
728 case VMMR0_DO_GVMM_RESET_STATISTICS:
729 if (u64Arg)
730 return VERR_INVALID_PARAMETER;
731 return GVMMR0ResetStatisticsReq(pVM, (PGVMMRESETSTATISTICSSREQ)pReqHdr);
732
733 /*
734 * Initialize the R0 part of a VM instance.
735 */
736 case VMMR0_DO_VMMR0_INIT:
737 return VMMR0Init(pVM, (uint32_t)u64Arg);
738
739 /*
740 * Terminate the R0 part of a VM instance.
741 */
742 case VMMR0_DO_VMMR0_TERM:
743 return VMMR0Term(pVM);
744
745 /*
746 * Attempt to enable hwacc mode and check the current setting.
747 *
748 */
749 case VMMR0_DO_HWACC_ENABLE:
750 return HWACCMR0EnableAllCpus(pVM, (HWACCMSTATE)u64Arg);
751
752 /*
753 * Setup the hardware accelerated raw-mode session.
754 */
755 case VMMR0_DO_HWACC_SETUP_VM:
756 {
757 RTCCUINTREG fFlags = ASMIntDisableFlags();
758 int rc = HWACCMR0SetupVM(pVM);
759 ASMSetFlags(fFlags);
760 return rc;
761 }
762
763 /*
764 * Switch to GC to execute Hypervisor function.
765 */
766 case VMMR0_DO_CALL_HYPERVISOR:
767 {
768 /* Safety precaution as HWACCM can disable the switcher. */
769 Assert(!pVM->vmm.s.fSwitcherDisabled);
770 if (RT_UNLIKELY(pVM->vmm.s.fSwitcherDisabled))
771 return VERR_NOT_SUPPORTED;
772
773 RTCCUINTREG fFlags = ASMIntDisableFlags();
774 int rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
775 /** @todo dispatch interrupts? */
776 ASMSetFlags(fFlags);
777 return rc;
778 }
779
780 /*
781 * PGM wrappers.
782 */
783 case VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES:
784 return PGMR0PhysAllocateHandyPages(pVM);
785
786 /*
787 * GMM wrappers.
788 */
789 case VMMR0_DO_GMM_INITIAL_RESERVATION:
790 if (u64Arg)
791 return VERR_INVALID_PARAMETER;
792 return GMMR0InitialReservationReq(pVM, (PGMMINITIALRESERVATIONREQ)pReqHdr);
793 case VMMR0_DO_GMM_UPDATE_RESERVATION:
794 if (u64Arg)
795 return VERR_INVALID_PARAMETER;
796 return GMMR0UpdateReservationReq(pVM, (PGMMUPDATERESERVATIONREQ)pReqHdr);
797
798 case VMMR0_DO_GMM_ALLOCATE_PAGES:
799 if (u64Arg)
800 return VERR_INVALID_PARAMETER;
801 return GMMR0AllocatePagesReq(pVM, (PGMMALLOCATEPAGESREQ)pReqHdr);
802 case VMMR0_DO_GMM_FREE_PAGES:
803 if (u64Arg)
804 return VERR_INVALID_PARAMETER;
805 return GMMR0FreePagesReq(pVM, (PGMMFREEPAGESREQ)pReqHdr);
806 case VMMR0_DO_GMM_BALLOONED_PAGES:
807 if (u64Arg)
808 return VERR_INVALID_PARAMETER;
809 return GMMR0BalloonedPagesReq(pVM, (PGMMBALLOONEDPAGESREQ)pReqHdr);
810 case VMMR0_DO_GMM_DEFLATED_BALLOON:
811 if (pReqHdr)
812 return VERR_INVALID_PARAMETER;
813 return GMMR0DeflatedBalloon(pVM, (uint32_t)u64Arg);
814
815 case VMMR0_DO_GMM_MAP_UNMAP_CHUNK:
816 if (u64Arg)
817 return VERR_INVALID_PARAMETER;
818 return GMMR0MapUnmapChunkReq(pVM, (PGMMMAPUNMAPCHUNKREQ)pReqHdr);
819 case VMMR0_DO_GMM_SEED_CHUNK:
820 if (pReqHdr)
821 return VERR_INVALID_PARAMETER;
822 return GMMR0SeedChunk(pVM, (RTR3PTR)u64Arg);
823
824 /*
825 * A quick GCFGM mock-up.
826 */
827 /** @todo GCFGM with proper access control, ring-3 management interface and all that. */
828 case VMMR0_DO_GCFGM_SET_VALUE:
829 case VMMR0_DO_GCFGM_QUERY_VALUE:
830 {
831 if (pVM || !pReqHdr || u64Arg)
832 return VERR_INVALID_PARAMETER;
833 PGCFGMVALUEREQ pReq = (PGCFGMVALUEREQ)pReqHdr;
834 if (pReq->Hdr.cbReq != sizeof(*pReq))
835 return VERR_INVALID_PARAMETER;
836 int rc;
837 if (enmOperation == VMMR0_DO_GCFGM_SET_VALUE)
838 {
839 rc = GVMMR0SetConfig(pReq->pSession, &pReq->szName[0], pReq->u64Value);
840 //if (rc == VERR_CFGM_VALUE_NOT_FOUND)
841 // rc = GMMR0SetConfig(pReq->pSession, &pReq->szName[0], pReq->u64Value);
842 }
843 else
844 {
845 rc = GVMMR0QueryConfig(pReq->pSession, &pReq->szName[0], &pReq->u64Value);
846 //if (rc == VERR_CFGM_VALUE_NOT_FOUND)
847 // rc = GMMR0QueryConfig(pReq->pSession, &pReq->szName[0], &pReq->u64Value);
848 }
849 return rc;
850 }
851
852
853#ifdef VBOX_WITH_INTERNAL_NETWORKING
854 /*
855 * Requests to the internal networking service.
856 */
857 case VMMR0_DO_INTNET_OPEN:
858 if (!pVM || u64Arg)
859 return VERR_INVALID_PARAMETER;
860 if (!g_pIntNet)
861 return VERR_NOT_SUPPORTED;
862 return INTNETR0OpenReq(g_pIntNet, pVM->pSession, (PINTNETOPENREQ)pReqHdr);
863
864 case VMMR0_DO_INTNET_IF_CLOSE:
865 if (!pVM || u64Arg)
866 return VERR_INVALID_PARAMETER;
867 if (!g_pIntNet)
868 return VERR_NOT_SUPPORTED;
869 return INTNETR0IfCloseReq(g_pIntNet, (PINTNETIFCLOSEREQ)pReqHdr);
870
871 case VMMR0_DO_INTNET_IF_GET_RING3_BUFFER:
872 if (!pVM || u64Arg)
873 return VERR_INVALID_PARAMETER;
874 if (!g_pIntNet)
875 return VERR_NOT_SUPPORTED;
876 return INTNETR0IfGetRing3BufferReq(g_pIntNet, (PINTNETIFGETRING3BUFFERREQ)pReqHdr);
877
878 case VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE:
879 if (!pVM || u64Arg)
880 return VERR_INVALID_PARAMETER;
881 if (!g_pIntNet)
882 return VERR_NOT_SUPPORTED;
883 return INTNETR0IfSetPromiscuousModeReq(g_pIntNet, (PINTNETIFSETPROMISCUOUSMODEREQ)pReqHdr);
884
885 case VMMR0_DO_INTNET_IF_SEND:
886 if (!pVM || u64Arg)
887 return VERR_INVALID_PARAMETER;
888 if (!g_pIntNet)
889 return VERR_NOT_SUPPORTED;
890 return INTNETR0IfSendReq(g_pIntNet, (PINTNETIFSENDREQ)pReqHdr);
891
892 case VMMR0_DO_INTNET_IF_WAIT:
893 if (!pVM || u64Arg)
894 return VERR_INVALID_PARAMETER;
895 if (!g_pIntNet)
896 return VERR_NOT_SUPPORTED;
897 return INTNETR0IfWaitReq(g_pIntNet, (PINTNETIFWAITREQ)pReqHdr);
898#endif /* VBOX_WITH_INTERNAL_NETWORKING */
899
900 /*
901 * For profiling.
902 */
903 case VMMR0_DO_NOP:
904 return VINF_SUCCESS;
905
906 /*
907 * For testing Ring-0 APIs invoked in this environment.
908 */
909 case VMMR0_DO_TESTS:
910 /** @todo make new test */
911 return VINF_SUCCESS;
912
913
914 default:
915 /*
916 * We're returning VERR_NOT_SUPPORT here so we've got something else
917 * than -1 which the interrupt gate glue code might return.
918 */
919 Log(("operation %#x is not supported\n", enmOperation));
920 return VERR_NOT_SUPPORTED;
921 }
922}
923
924
925/**
926 * Argument for vmmR0EntryExWrapper containing the argument s ofr VMMR0EntryEx.
927 */
928typedef struct VMMR0ENTRYEXARGS
929{
930 PVM pVM;
931 VMMR0OPERATION enmOperation;
932 PSUPVMMR0REQHDR pReq;
933 uint64_t u64Arg;
934} VMMR0ENTRYEXARGS;
935/** Pointer to a vmmR0EntryExWrapper argument package. */
936typedef VMMR0ENTRYEXARGS *PVMMR0ENTRYEXARGS;
937
938/**
939 * This is just a longjmp wrapper function for VMMR0EntryEx calls.
940 *
941 * @returns VBox status code.
942 * @param pvArgs The argument package
943 */
944static int vmmR0EntryExWrapper(void *pvArgs)
945{
946 return vmmR0EntryExWorker(((PVMMR0ENTRYEXARGS)pvArgs)->pVM,
947 ((PVMMR0ENTRYEXARGS)pvArgs)->enmOperation,
948 ((PVMMR0ENTRYEXARGS)pvArgs)->pReq,
949 ((PVMMR0ENTRYEXARGS)pvArgs)->u64Arg);
950}
951
952
953/**
954 * The Ring 0 entry point, called by the support library (SUP).
955 *
956 * @returns VBox status code.
957 * @param pVM The VM to operate on.
958 * @param enmOperation Which operation to execute.
959 * @param pReq This points to a SUPVMMR0REQHDR packet. Optional.
960 * @param u64Arg Some simple constant argument.
961 * @remarks Assume called with interrupts _enabled_.
962 */
963VMMR0DECL(int) VMMR0EntryEx(PVM pVM, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg)
964{
965 /*
966 * Requests that should only happen on the EMT thread will be
967 * wrapped in a setjmp so we can assert without causing trouble.
968 */
969 if ( VALID_PTR(pVM)
970 && pVM->pVMR0)
971 {
972 switch (enmOperation)
973 {
974 case VMMR0_DO_VMMR0_INIT:
975 case VMMR0_DO_VMMR0_TERM:
976 case VMMR0_DO_GMM_INITIAL_RESERVATION:
977 case VMMR0_DO_GMM_UPDATE_RESERVATION:
978 case VMMR0_DO_GMM_ALLOCATE_PAGES:
979 case VMMR0_DO_GMM_FREE_PAGES:
980 case VMMR0_DO_GMM_BALLOONED_PAGES:
981 case VMMR0_DO_GMM_DEFLATED_BALLOON:
982 case VMMR0_DO_GMM_MAP_UNMAP_CHUNK:
983 case VMMR0_DO_GMM_SEED_CHUNK:
984 {
985 /** @todo validate this EMT claim... GVM knows. */
986 VMMR0ENTRYEXARGS Args;
987 Args.pVM = pVM;
988 Args.enmOperation = enmOperation;
989 Args.pReq = pReq;
990 Args.u64Arg = u64Arg;
991 return vmmR0CallHostSetJmpEx(&pVM->vmm.s.CallHostR0JmpBuf, vmmR0EntryExWrapper, &Args);
992 }
993
994 default:
995 break;
996 }
997 }
998 return vmmR0EntryExWorker(pVM, enmOperation, pReq, u64Arg);
999}
1000
1001
1002
1003/**
1004 * Internal R0 logger worker: Flush logger.
1005 *
1006 * @param pLogger The logger instance to flush.
1007 * @remark This function must be exported!
1008 */
1009VMMR0DECL(void) vmmR0LoggerFlush(PRTLOGGER pLogger)
1010{
1011 /*
1012 * Convert the pLogger into a VM handle and 'call' back to Ring-3.
1013 * (This is a bit paranoid code.)
1014 */
1015 PVMMR0LOGGER pR0Logger = (PVMMR0LOGGER)((uintptr_t)pLogger - RT_OFFSETOF(VMMR0LOGGER, Logger));
1016 if ( !VALID_PTR(pR0Logger)
1017 || !VALID_PTR(pR0Logger + 1)
1018 || !VALID_PTR(pLogger)
1019 || pLogger->u32Magic != RTLOGGER_MAGIC)
1020 {
1021#ifdef DEBUG
1022 SUPR0Printf("vmmR0LoggerFlush: pLogger=%p!\n", pLogger);
1023#endif
1024 return;
1025 }
1026
1027 PVM pVM = pR0Logger->pVM;
1028 if ( !VALID_PTR(pVM)
1029 || pVM->pVMR0 != pVM)
1030 {
1031#ifdef DEBUG
1032 SUPR0Printf("vmmR0LoggerFlush: pVM=%p! pVMR0=%p! pLogger=%p\n", pVM, pVM->pVMR0, pLogger);
1033#endif
1034 return;
1035 }
1036
1037 /*
1038 * Check that the jump buffer is armed.
1039 */
1040#ifdef RT_ARCH_X86
1041 if (!pVM->vmm.s.CallHostR0JmpBuf.eip)
1042#else
1043 if (!pVM->vmm.s.CallHostR0JmpBuf.rip)
1044#endif
1045 {
1046#ifdef DEBUG
1047 SUPR0Printf("vmmR0LoggerFlush: Jump buffer isn't armed!\n");
1048#endif
1049 pLogger->offScratch = 0;
1050 return;
1051 }
1052 VMMR0CallHost(pVM, VMMCALLHOST_VMM_LOGGER_FLUSH, 0);
1053}
1054
1055
1056
1057/**
1058 * Jump back to ring-3 if we're the EMT and the longjmp is armed.
1059 *
1060 * @returns true if the breakpoint should be hit, false if it should be ignored.
1061 * @remark The RTDECL() makes this a bit difficult to override on windows. Sorry.
1062 */
1063DECLEXPORT(bool) RTCALL RTAssertDoBreakpoint(void)
1064{
1065 PVM pVM = GVMMR0GetVMByEMT(NIL_RTNATIVETHREAD);
1066 if (pVM)
1067 {
1068#ifdef RT_ARCH_X86
1069 if (pVM->vmm.s.CallHostR0JmpBuf.eip)
1070#else
1071 if (pVM->vmm.s.CallHostR0JmpBuf.rip)
1072#endif
1073 {
1074 int rc = VMMR0CallHost(pVM, VMMCALLHOST_VM_R0_HYPER_ASSERTION, 0);
1075 return RT_FAILURE_NP(rc);
1076 }
1077 }
1078#ifdef RT_OS_LINUX
1079 return true;
1080#else
1081 return false;
1082#endif
1083}
1084
1085
1086
1087/**
1088 * Override this so we can push it up to ring-3.
1089 *
1090 * @param pszExpr Expression. Can be NULL.
1091 * @param uLine Location line number.
1092 * @param pszFile Location file name.
1093 * @param pszFunction Location function name.
1094 */
1095DECLEXPORT(void) RTCALL AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
1096{
1097#ifndef DEBUG_sandervl
1098 SUPR0Printf("\n!!R0-Assertion Failed!!\n"
1099 "Expression: %s\n"
1100 "Location : %s(%d) %s\n",
1101 pszExpr, pszFile, uLine, pszFunction);
1102#endif
1103 LogAlways(("\n!!R0-Assertion Failed!!\n"
1104 "Expression: %s\n"
1105 "Location : %s(%d) %s\n",
1106 pszExpr, pszFile, uLine, pszFunction));
1107}
1108
1109
1110/**
1111 * Callback for RTLogFormatV which writes to the ring-3 log port.
1112 * See PFNLOGOUTPUT() for details.
1113 */
1114static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars)
1115{
1116 for (size_t i = 0; i < cbChars; i++)
1117 {
1118#ifndef DEBUG_sandervl
1119 SUPR0Printf("%c", pachChars[i]);
1120#endif
1121 LogAlways(("%c", pachChars[i]));
1122 }
1123
1124 return cbChars;
1125}
1126
1127
1128DECLEXPORT(void) RTCALL AssertMsg2(const char *pszFormat, ...)
1129{
1130 PRTLOGGER pLog = RTLogDefaultInstance(); /** @todo we want this for release as well! */
1131 if (pLog)
1132 {
1133 va_list args;
1134
1135 va_start(args, pszFormat);
1136 RTLogFormatV(rtLogOutput, pLog, pszFormat, args);
1137 va_end(args);
1138 }
1139}
1140
1141
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