VirtualBox

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

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

Changed GVM the ownership rules - at long last. EMT is the guy that creates the VM, simple and secure.

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