VirtualBox

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

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

NEW_PHYS_CODE -> VBOX_WITH_NEW_PHYS_CODE; check for it in Config.kmk and add to DEFS.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 36.4 KB
Line 
1/* $Id: VMMR0.cpp 6528 2008-01-28 14:43:15Z 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#ifdef VBOX_WITH_NEW_PHYS_CODE /* need to test on windows, solaris and darwin. */
86 rc = GMMR0Init();
87#endif
88 if (RT_SUCCESS(rc))
89 {
90#ifdef VBOX_WITH_INTERNAL_NETWORKING
91 LogFlow(("ModuleInit: g_pIntNet=%p\n", g_pIntNet));
92 g_pIntNet = NULL;
93 LogFlow(("ModuleInit: g_pIntNet=%p should be NULL now...\n", g_pIntNet));
94 rc = INTNETR0Create(&g_pIntNet);
95 if (VBOX_SUCCESS(rc))
96 {
97 LogFlow(("ModuleInit: returns success. g_pIntNet=%p\n", g_pIntNet));
98 return VINF_SUCCESS;
99 }
100 g_pIntNet = NULL;
101 LogFlow(("ModuleTerm: returns %Vrc\n", rc));
102#else
103 LogFlow(("ModuleInit: returns success.\n"));
104 return VINF_SUCCESS;
105#endif
106 }
107 }
108
109 LogFlow(("ModuleInit: failed %Rrc\n", rc));
110 return rc;
111}
112
113
114/**
115 * Terminate the module.
116 * This is called when we're finally unloaded.
117 */
118VMMR0DECL(void) ModuleTerm(void)
119{
120 LogFlow(("ModuleTerm:\n"));
121
122#ifdef VBOX_WITH_INTERNAL_NETWORKING
123 /*
124 * Destroy the internal networking instance.
125 */
126 if (g_pIntNet)
127 {
128 INTNETR0Destroy(g_pIntNet);
129 g_pIntNet = NULL;
130 }
131#endif
132
133 /*
134 * Destroy the GMM and GVMM instances.
135 */
136#ifdef VBOX_WITH_NEW_PHYS_CODE
137 GMMR0Term();
138#endif
139 GVMMR0Term();
140
141 LogFlow(("ModuleTerm: returns\n"));
142}
143
144
145/**
146 * Initaties the R0 driver for a particular VM instance.
147 *
148 * @returns VBox status code.
149 *
150 * @param pVM The VM instance in question.
151 * @param uVersion The minimum module version required.
152 * @thread EMT.
153 */
154static int VMMR0Init(PVM pVM, unsigned uVersion)
155{
156 /*
157 * Check if compatible version.
158 */
159 if ( uVersion != VBOX_VERSION
160 && ( VBOX_GET_VERSION_MAJOR(uVersion) != VBOX_VERSION_MAJOR
161 || VBOX_GET_VERSION_MINOR(uVersion) < VBOX_VERSION_MINOR))
162 return VERR_VERSION_MISMATCH;
163 if ( !VALID_PTR(pVM)
164 || pVM->pVMR0 != pVM)
165 return VERR_INVALID_PARAMETER;
166
167 /*
168 * Register the EMT R0 logger instance.
169 */
170 PVMMR0LOGGER pR0Logger = pVM->vmm.s.pR0Logger;
171 if (pR0Logger)
172 {
173#if 0 /* testing of the logger. */
174 LogCom(("VMMR0Init: before %p\n", RTLogDefaultInstance()));
175 LogCom(("VMMR0Init: pfnFlush=%p actual=%p\n", pR0Logger->Logger.pfnFlush, vmmR0LoggerFlush));
176 LogCom(("VMMR0Init: pfnLogger=%p actual=%p\n", pR0Logger->Logger.pfnLogger, vmmR0LoggerWrapper));
177 LogCom(("VMMR0Init: offScratch=%d fFlags=%#x fDestFlags=%#x\n", pR0Logger->Logger.offScratch, pR0Logger->Logger.fFlags, pR0Logger->Logger.fDestFlags));
178
179 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
180 LogCom(("VMMR0Init: after %p reg\n", RTLogDefaultInstance()));
181 RTLogSetDefaultInstanceThread(NULL, 0);
182 LogCom(("VMMR0Init: after %p dereg\n", RTLogDefaultInstance()));
183
184 pR0Logger->Logger.pfnLogger("hello ring-0 logger\n");
185 LogCom(("VMMR0Init: returned succesfully from direct logger call.\n"));
186 pR0Logger->Logger.pfnFlush(&pR0Logger->Logger);
187 LogCom(("VMMR0Init: returned succesfully from direct flush call.\n"));
188
189 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
190 LogCom(("VMMR0Init: after %p reg2\n", RTLogDefaultInstance()));
191 pR0Logger->Logger.pfnLogger("hello ring-0 logger\n");
192 LogCom(("VMMR0Init: returned succesfully from direct logger call (2). offScratch=%d\n", pR0Logger->Logger.offScratch));
193 RTLogSetDefaultInstanceThread(NULL, 0);
194 LogCom(("VMMR0Init: after %p dereg2\n", RTLogDefaultInstance()));
195
196 RTLogLoggerEx(&pR0Logger->Logger, 0, ~0U, "hello ring-0 logger (RTLogLoggerEx)\n");
197 LogCom(("VMMR0Init: RTLogLoggerEx returned fine offScratch=%d\n", pR0Logger->Logger.offScratch));
198
199 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
200 RTLogPrintf("hello ring-0 logger (RTLogPrintf)\n");
201 LogCom(("VMMR0Init: RTLogPrintf returned fine offScratch=%d\n", pR0Logger->Logger.offScratch));
202#endif
203 Log(("Switching to per-thread logging instance %p (key=%p)\n", &pR0Logger->Logger, pVM->pSession));
204 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
205 }
206
207 /*
208 * Associate the ring-0 EMT thread with the GVM
209 * and initalize the GVMM and GMM per VM data.
210 */
211 int rc = GVMMR0AssociateEMTWithVM(pVM);
212 if (RT_SUCCESS(rc))
213 {
214 rc = GVMMR0InitVM(pVM);
215 //if (RT_SUCCESS(rc))
216 // rc = GMMR0InitVM(pVM);
217 if (RT_SUCCESS(rc))
218 {
219 /*
220 * Init HWACCM.
221 */
222 RTCCUINTREG fFlags = ASMIntDisableFlags();
223 rc = HWACCMR0Init(pVM);
224 ASMSetFlags(fFlags);
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
237 /* failed */
238 RTLogSetDefaultInstanceThread(NULL, 0);
239 return rc;
240}
241
242
243/**
244 * Terminates the R0 driver for a particular VM instance.
245 *
246 * @returns VBox status code.
247 *
248 * @param pVM The VM instance in question.
249 * @thread EMT.
250 */
251static int VMMR0Term(PVM pVM)
252{
253 /*
254 * Deregister the logger.
255 */
256 GVMMR0DisassociateEMTFromVM(pVM);
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 default:
429 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetCallHost);
430 break;
431 }
432 break;
433 case VINF_PATM_DUPLICATE_FUNCTION:
434 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPATMDuplicateFn);
435 break;
436 case VINF_PGM_CHANGE_MODE:
437 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPGMChangeMode);
438 break;
439 case VINF_EM_RAW_EMULATE_INSTR_HLT:
440 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetEmulHlt);
441 break;
442 case VINF_EM_PENDING_REQUEST:
443 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPendingRequest);
444 break;
445 default:
446 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMisc);
447 break;
448 }
449}
450#endif /* VBOX_WITH_STATISTICS */
451
452
453
454/**
455 * The Ring 0 entry point, called by the interrupt gate.
456 *
457 * @returns VBox status code.
458 * @param pVM The VM to operate on.
459 * @param enmOperation Which operation to execute.
460 * @param pvArg Argument to the operation.
461 * @remarks Assume called with interrupts disabled.
462 */
463VMMR0DECL(int) VMMR0EntryInt(PVM pVM, VMMR0OPERATION enmOperation, void *pvArg)
464{
465 switch (enmOperation)
466 {
467#ifdef VBOX_WITH_IDT_PATCHING
468 /*
469 * Switch to GC.
470 * These calls return whatever the GC returns.
471 */
472 case VMMR0_DO_RAW_RUN:
473 {
474 /* Safety precaution as VMX disables the switcher. */
475 Assert(!pVM->vmm.s.fSwitcherDisabled);
476 if (pVM->vmm.s.fSwitcherDisabled)
477 return VERR_NOT_SUPPORTED;
478
479 STAM_COUNTER_INC(&pVM->vmm.s.StatRunGC);
480 register int rc;
481 pVM->vmm.s.iLastGCRc = rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
482
483#ifdef VBOX_WITH_STATISTICS
484 vmmR0RecordRC(pVM, rc);
485#endif
486
487 /*
488 * We'll let TRPM change the stack frame so our return is different.
489 * Just keep in mind that after the call, things have changed!
490 */
491 if ( rc == VINF_EM_RAW_INTERRUPT
492 || rc == VINF_EM_RAW_INTERRUPT_HYPER)
493 {
494 /*
495 * Don't trust the compiler to get this right.
496 * gcc -fomit-frame-pointer screws up big time here. This works fine in 64-bit
497 * mode too because we push the arguments on the stack in the IDT patch code.
498 */
499# if defined(__GNUC__)
500 void *pvRet = (uint8_t *)__builtin_frame_address(0) + sizeof(void *);
501# elif defined(_MSC_VER) && defined(RT_ARCH_AMD64) /** @todo check this with with VC7! */
502 void *pvRet = (uint8_t *)_AddressOfReturnAddress();
503# elif defined(RT_ARCH_X86)
504 void *pvRet = (uint8_t *)&pVM - sizeof(pVM);
505# else
506# error "huh?"
507# endif
508 if ( ((uintptr_t *)pvRet)[1] == (uintptr_t)pVM
509 && ((uintptr_t *)pvRet)[2] == (uintptr_t)enmOperation
510 && ((uintptr_t *)pvRet)[3] == (uintptr_t)pvArg)
511 TRPMR0SetupInterruptDispatcherFrame(pVM, pvRet);
512 else
513 {
514# if defined(DEBUG) || defined(LOG_ENABLED)
515 static bool s_fHaveWarned = false;
516 if (!s_fHaveWarned)
517 {
518 s_fHaveWarned = true;
519 RTLogPrintf("VMMR0.r0: The compiler can't find the stack frame!\n");
520 RTLogComPrintf("VMMR0.r0: The compiler can't find the stack frame!\n");
521 }
522# endif
523 TRPMR0DispatchHostInterrupt(pVM);
524 }
525 }
526 return rc;
527 }
528
529 /*
530 * Switch to GC to execute Hypervisor function.
531 */
532 case VMMR0_DO_CALL_HYPERVISOR:
533 {
534 /* Safety precaution as VMX disables the switcher. */
535 Assert(!pVM->vmm.s.fSwitcherDisabled);
536 if (pVM->vmm.s.fSwitcherDisabled)
537 return VERR_NOT_SUPPORTED;
538
539 RTCCUINTREG fFlags = ASMIntDisableFlags();
540 int rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
541 /** @todo dispatch interrupts? */
542 ASMSetFlags(fFlags);
543 return rc;
544 }
545
546 /*
547 * For profiling.
548 */
549 case VMMR0_DO_NOP:
550 return VINF_SUCCESS;
551#endif /* VBOX_WITH_IDT_PATCHING */
552
553 default:
554 /*
555 * We're returning VERR_NOT_SUPPORT here so we've got something else
556 * than -1 which the interrupt gate glue code might return.
557 */
558 Log(("operation %#x is not supported\n", enmOperation));
559 return VERR_NOT_SUPPORTED;
560 }
561}
562
563
564/**
565 * The Ring 0 entry point, called by the fast-ioctl path.
566 *
567 * @returns VBox status code.
568 * @param pVM The VM to operate on.
569 * @param enmOperation Which operation to execute.
570 * @remarks Assume called with interrupts _enabled_.
571 */
572VMMR0DECL(int) VMMR0EntryFast(PVM pVM, VMMR0OPERATION enmOperation)
573{
574 switch (enmOperation)
575 {
576 /*
577 * Switch to GC and run guest raw mode code.
578 * Disable interrupts before doing the world switch.
579 */
580 case VMMR0_DO_RAW_RUN:
581 {
582 /* Safety precaution as hwaccm disables the switcher. */
583 if (RT_LIKELY(!pVM->vmm.s.fSwitcherDisabled))
584 {
585 RTCCUINTREG uFlags = ASMIntDisableFlags();
586
587 int rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
588 pVM->vmm.s.iLastGCRc = rc;
589
590 if ( rc == VINF_EM_RAW_INTERRUPT
591 || rc == VINF_EM_RAW_INTERRUPT_HYPER)
592 TRPMR0DispatchHostInterrupt(pVM);
593
594 ASMSetFlags(uFlags);
595
596#ifdef VBOX_WITH_STATISTICS
597 STAM_COUNTER_INC(&pVM->vmm.s.StatRunGC);
598 vmmR0RecordRC(pVM, rc);
599#endif
600 return rc;
601 }
602
603 Assert(!pVM->vmm.s.fSwitcherDisabled);
604 return VERR_NOT_SUPPORTED;
605 }
606
607 /*
608 * Run guest code using the available hardware acceleration technology.
609 *
610 * Disable interrupts before we do anything interesting. On Windows we avoid
611 * this by having the support driver raise the IRQL before calling us, this way
612 * we hope to get away we page faults and later calling into the kernel.
613 */
614 case VMMR0_DO_HWACC_RUN:
615 {
616 STAM_COUNTER_INC(&pVM->vmm.s.StatRunGC);
617
618#ifndef RT_OS_WINDOWS /** @todo check other hosts */
619 RTCCUINTREG uFlags = ASMIntDisableFlags();
620#endif
621 int rc = HWACCMR0Enable(pVM);
622 if (VBOX_SUCCESS(rc))
623 {
624 rc = vmmR0CallHostSetJmp(&pVM->vmm.s.CallHostR0JmpBuf, HWACCMR0RunGuestCode, pVM); /* this may resume code. */
625 int rc2 = HWACCMR0Disable(pVM);
626 AssertRC(rc2);
627 }
628 pVM->vmm.s.iLastGCRc = rc;
629#ifndef RT_OS_WINDOWS /** @todo check other hosts */
630 ASMSetFlags(uFlags);
631#endif
632
633#ifdef VBOX_WITH_STATISTICS
634 vmmR0RecordRC(pVM, rc);
635#endif
636 /* No special action required for external interrupts, just return. */
637 return rc;
638 }
639
640 /*
641 * For profiling.
642 */
643 case VMMR0_DO_NOP:
644 return VINF_SUCCESS;
645
646 /*
647 * Impossible.
648 */
649 default:
650 AssertMsgFailed(("%#x\n", enmOperation));
651 return VERR_NOT_SUPPORTED;
652 }
653}
654
655
656/**
657 * VMMR0EntryEx worker function, either called directly or when ever possible
658 * called thru a longjmp so we can exit safely on failure.
659 *
660 * @returns VBox status code.
661 * @param pVM The VM to operate on.
662 * @param enmOperation Which operation to execute.
663 * @param pReqHdr This points to a SUPVMMR0REQHDR packet. Optional.
664 * @param u64Arg Some simple constant argument.
665 * @remarks Assume called with interrupts _enabled_.
666 */
667static int vmmR0EntryExWorker(PVM pVM, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReqHdr, uint64_t u64Arg)
668{
669 /*
670 * Common VM pointer validation.
671 */
672 if (pVM)
673 {
674 if (RT_UNLIKELY( !VALID_PTR(pVM)
675 || ((uintptr_t)pVM & PAGE_OFFSET_MASK)))
676 {
677 SUPR0Printf("vmmR0EntryExWorker: Invalid pVM=%p! (op=%d)\n", pVM, enmOperation);
678 return VERR_INVALID_POINTER;
679 }
680 if (RT_UNLIKELY( pVM->enmVMState < VMSTATE_CREATING
681 || pVM->enmVMState > VMSTATE_TERMINATED
682 || pVM->pVMR0 != pVM))
683 {
684 SUPR0Printf("vmmR0EntryExWorker: Invalid pVM=%p:{enmVMState=%d, .pVMR0=%p}! (op=%d)\n",
685 pVM, pVM->enmVMState, pVM->pVMR0, enmOperation);
686 return VERR_INVALID_POINTER;
687 }
688 }
689
690 switch (enmOperation)
691 {
692 /*
693 * GVM requests
694 */
695 case VMMR0_DO_GVMM_CREATE_VM:
696 if (pVM || u64Arg)
697 return VERR_INVALID_PARAMETER;
698 SUPR0Printf("-> GVMMR0CreateVMReq\n");
699 return GVMMR0CreateVMReq((PGVMMCREATEVMREQ)pReqHdr);
700
701 case VMMR0_DO_GVMM_DESTROY_VM:
702 if (pReqHdr || u64Arg)
703 return VERR_INVALID_PARAMETER;
704 return GVMMR0DestroyVM(pVM);
705
706 case VMMR0_DO_GVMM_SCHED_HALT:
707 if (pReqHdr)
708 return VERR_INVALID_PARAMETER;
709 return GVMMR0SchedHalt(pVM, u64Arg);
710
711 case VMMR0_DO_GVMM_SCHED_WAKE_UP:
712 if (pReqHdr || u64Arg)
713 return VERR_INVALID_PARAMETER;
714 return GVMMR0SchedWakeUp(pVM);
715
716 case VMMR0_DO_GVMM_SCHED_POLL:
717 if (pReqHdr || u64Arg > 1)
718 return VERR_INVALID_PARAMETER;
719 return GVMMR0SchedPoll(pVM, (bool)u64Arg);
720
721 case VMMR0_DO_GVMM_QUERY_STATISTICS:
722 if (u64Arg)
723 return VERR_INVALID_PARAMETER;
724 return GVMMR0QueryStatisticsReq(pVM, (PGVMMQUERYSTATISTICSSREQ)pReqHdr);
725
726 case VMMR0_DO_GVMM_RESET_STATISTICS:
727 if (u64Arg)
728 return VERR_INVALID_PARAMETER;
729 return GVMMR0ResetStatisticsReq(pVM, (PGVMMRESETSTATISTICSSREQ)pReqHdr);
730
731 /*
732 * Initialize the R0 part of a VM instance.
733 */
734 case VMMR0_DO_VMMR0_INIT:
735 return VMMR0Init(pVM, (unsigned)u64Arg);
736
737 /*
738 * Terminate the R0 part of a VM instance.
739 */
740 case VMMR0_DO_VMMR0_TERM:
741 return VMMR0Term(pVM);
742
743 /*
744 * Setup the hardware accelerated raw-mode session.
745 */
746 case VMMR0_DO_HWACC_SETUP_VM:
747 {
748 RTCCUINTREG fFlags = ASMIntDisableFlags();
749 int rc = HWACCMR0SetupVMX(pVM);
750 ASMSetFlags(fFlags);
751 return rc;
752 }
753
754 /*
755 * Switch to GC to execute Hypervisor function.
756 */
757 case VMMR0_DO_CALL_HYPERVISOR:
758 {
759 /* Safety precaution as VMX disables the switcher. */
760 Assert(!pVM->vmm.s.fSwitcherDisabled);
761 if (pVM->vmm.s.fSwitcherDisabled)
762 return VERR_NOT_SUPPORTED;
763
764 RTCCUINTREG fFlags = ASMIntDisableFlags();
765 int rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
766 /** @todo dispatch interrupts? */
767 ASMSetFlags(fFlags);
768 return rc;
769 }
770
771 /*
772 * PGM wrappers.
773 */
774 case VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES:
775 return PGMR0PhysAllocateHandyPages(pVM);
776
777 /*
778 * GMM wrappers.
779 */
780 case VMMR0_DO_GMM_INITIAL_RESERVATION:
781 if (u64Arg)
782 return VERR_INVALID_PARAMETER;
783 return GMMR0InitialReservationReq(pVM, (PGMMINITIALRESERVATIONREQ)pReqHdr);
784 case VMMR0_DO_GMM_UPDATE_RESERVATION:
785 if (u64Arg)
786 return VERR_INVALID_PARAMETER;
787 return GMMR0UpdateReservationReq(pVM, (PGMMUPDATERESERVATIONREQ)pReqHdr);
788
789 case VMMR0_DO_GMM_ALLOCATE_PAGES:
790 if (u64Arg)
791 return VERR_INVALID_PARAMETER;
792 return GMMR0AllocatePagesReq(pVM, (PGMMALLOCATEPAGESREQ)pReqHdr);
793 case VMMR0_DO_GMM_FREE_PAGES:
794 if (u64Arg)
795 return VERR_INVALID_PARAMETER;
796 return GMMR0FreePagesReq(pVM, (PGMMFREEPAGESREQ)pReqHdr);
797 case VMMR0_DO_GMM_BALLOONED_PAGES:
798 if (u64Arg)
799 return VERR_INVALID_PARAMETER;
800 return GMMR0BalloonedPagesReq(pVM, (PGMMBALLOONEDPAGESREQ)pReqHdr);
801 case VMMR0_DO_GMM_DEFLATED_BALLOON:
802 if (pReqHdr)
803 return VERR_INVALID_PARAMETER;
804 return GMMR0DeflatedBalloon(pVM, (uint32_t)u64Arg);
805
806 case VMMR0_DO_GMM_MAP_UNMAP_CHUNK:
807 if (u64Arg)
808 return VERR_INVALID_PARAMETER;
809 return GMMR0MapUnmapChunkReq(pVM, (PGMMMAPUNMAPCHUNKREQ)pReqHdr);
810 case VMMR0_DO_GMM_SEED_CHUNK:
811 if (pReqHdr)
812 return VERR_INVALID_PARAMETER;
813 return GMMR0SeedChunk(pVM, (RTR3PTR)u64Arg);
814
815 /*
816 * A quick GCFGM mock-up.
817 */
818 /** @todo GCFGM with proper access control, ring-3 management interface and all that. */
819 case VMMR0_DO_GCFGM_SET_VALUE:
820 case VMMR0_DO_GCFGM_QUERY_VALUE:
821 {
822 if (pVM || !pReqHdr || u64Arg)
823 return VERR_INVALID_PARAMETER;
824 PGCFGMVALUEREQ pReq = (PGCFGMVALUEREQ)pReqHdr;
825 if (pReq->Hdr.cbReq != sizeof(*pReq))
826 return VERR_INVALID_PARAMETER;
827 int rc;
828 if (enmOperation == VMMR0_DO_GCFGM_SET_VALUE)
829 {
830 rc = GVMMR0SetConfig(pReq->pSession, &pReq->szName[0], pReq->u64Value);
831 //if (rc == VERR_CFGM_VALUE_NOT_FOUND)
832 // rc = GMMR0SetConfig(pReq->pSession, &pReq->szName[0], pReq->u64Value);
833 }
834 else
835 {
836 rc = GVMMR0QueryConfig(pReq->pSession, &pReq->szName[0], &pReq->u64Value);
837 //if (rc == VERR_CFGM_VALUE_NOT_FOUND)
838 // rc = GMMR0QueryConfig(pReq->pSession, &pReq->szName[0], &pReq->u64Value);
839 }
840 return rc;
841 }
842
843
844#ifdef VBOX_WITH_INTERNAL_NETWORKING
845 /*
846 * Requests to the internal networking service.
847 */
848 case VMMR0_DO_INTNET_OPEN:
849 if (!pVM || u64Arg)
850 return VERR_INVALID_PARAMETER;
851 if (!g_pIntNet)
852 return VERR_NOT_SUPPORTED;
853 return INTNETR0OpenReq(g_pIntNet, pVM->pSession, (PINTNETOPENREQ)pReqHdr);
854
855 case VMMR0_DO_INTNET_IF_CLOSE:
856 if (!pVM || u64Arg)
857 return VERR_INVALID_PARAMETER;
858 if (!g_pIntNet)
859 return VERR_NOT_SUPPORTED;
860 return INTNETR0IfCloseReq(g_pIntNet, (PINTNETIFCLOSEREQ)pReqHdr);
861
862 case VMMR0_DO_INTNET_IF_GET_RING3_BUFFER:
863 if (!pVM || u64Arg)
864 return VERR_INVALID_PARAMETER;
865 if (!g_pIntNet)
866 return VERR_NOT_SUPPORTED;
867 return INTNETR0IfGetRing3BufferReq(g_pIntNet, (PINTNETIFGETRING3BUFFERREQ)pReqHdr);
868
869 case VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE:
870 if (!pVM || u64Arg)
871 return VERR_INVALID_PARAMETER;
872 if (!g_pIntNet)
873 return VERR_NOT_SUPPORTED;
874 return INTNETR0IfSetPromiscuousModeReq(g_pIntNet, (PINTNETIFSETPROMISCUOUSMODEREQ)pReqHdr);
875
876 case VMMR0_DO_INTNET_IF_SEND:
877 if (!pVM || u64Arg)
878 return VERR_INVALID_PARAMETER;
879 if (!g_pIntNet)
880 return VERR_NOT_SUPPORTED;
881 return INTNETR0IfSendReq(g_pIntNet, (PINTNETIFSENDREQ)pReqHdr);
882
883 case VMMR0_DO_INTNET_IF_WAIT:
884 if (!pVM || u64Arg)
885 return VERR_INVALID_PARAMETER;
886 if (!g_pIntNet)
887 return VERR_NOT_SUPPORTED;
888 return INTNETR0IfWaitReq(g_pIntNet, (PINTNETIFWAITREQ)pReqHdr);
889#endif /* VBOX_WITH_INTERNAL_NETWORKING */
890
891 /*
892 * For profiling.
893 */
894 case VMMR0_DO_NOP:
895 return VINF_SUCCESS;
896
897 /*
898 * For testing Ring-0 APIs invoked in this environment.
899 */
900 case VMMR0_DO_TESTS:
901 /** @todo make new test */
902 return VINF_SUCCESS;
903
904
905 default:
906 /*
907 * We're returning VERR_NOT_SUPPORT here so we've got something else
908 * than -1 which the interrupt gate glue code might return.
909 */
910 Log(("operation %#x is not supported\n", enmOperation));
911 return VERR_NOT_SUPPORTED;
912 }
913}
914
915
916/**
917 * Argument for vmmR0EntryExWrapper containing the argument s ofr VMMR0EntryEx.
918 */
919typedef struct VMMR0ENTRYEXARGS
920{
921 PVM pVM;
922 VMMR0OPERATION enmOperation;
923 PSUPVMMR0REQHDR pReq;
924 uint64_t u64Arg;
925} VMMR0ENTRYEXARGS;
926/** Pointer to a vmmR0EntryExWrapper argument package. */
927typedef VMMR0ENTRYEXARGS *PVMMR0ENTRYEXARGS;
928
929/**
930 * This is just a longjmp wrapper function for VMMR0EntryEx calls.
931 *
932 * @returns VBox status code.
933 * @param pvArgs The argument package
934 */
935static int vmmR0EntryExWrapper(void *pvArgs)
936{
937 return vmmR0EntryExWorker(((PVMMR0ENTRYEXARGS)pvArgs)->pVM,
938 ((PVMMR0ENTRYEXARGS)pvArgs)->enmOperation,
939 ((PVMMR0ENTRYEXARGS)pvArgs)->pReq,
940 ((PVMMR0ENTRYEXARGS)pvArgs)->u64Arg);
941}
942
943
944/**
945 * The Ring 0 entry point, called by the support library (SUP).
946 *
947 * @returns VBox status code.
948 * @param pVM The VM to operate on.
949 * @param enmOperation Which operation to execute.
950 * @param pReq This points to a SUPVMMR0REQHDR packet. Optional.
951 * @param u64Arg Some simple constant argument.
952 * @remarks Assume called with interrupts _enabled_.
953 */
954VMMR0DECL(int) VMMR0EntryEx(PVM pVM, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg)
955{
956 /*
957 * Requests that should only happen on the EMT thread will be
958 * wrapped in a setjmp so we can assert without causing trouble.
959 */
960 if ( VALID_PTR(pVM)
961 && pVM->pVMR0)
962 {
963 switch (enmOperation)
964 {
965 case VMMR0_DO_VMMR0_INIT:
966 case VMMR0_DO_VMMR0_TERM:
967 case VMMR0_DO_GMM_INITIAL_RESERVATION:
968 case VMMR0_DO_GMM_UPDATE_RESERVATION:
969 case VMMR0_DO_GMM_ALLOCATE_PAGES:
970 case VMMR0_DO_GMM_FREE_PAGES:
971 case VMMR0_DO_GMM_BALLOONED_PAGES:
972 case VMMR0_DO_GMM_DEFLATED_BALLOON:
973 case VMMR0_DO_GMM_MAP_UNMAP_CHUNK:
974 case VMMR0_DO_GMM_SEED_CHUNK:
975 {
976 /** @todo validate this EMT claim... GVM knows. */
977 VMMR0ENTRYEXARGS Args;
978 Args.pVM = pVM;
979 Args.enmOperation = enmOperation;
980 Args.pReq = pReq;
981 Args.u64Arg = u64Arg;
982 return vmmR0CallHostSetJmpEx(&pVM->vmm.s.CallHostR0JmpBuf, vmmR0EntryExWrapper, &Args);
983 }
984
985 default:
986 break;
987 }
988 }
989 return vmmR0EntryExWorker(pVM, enmOperation, pReq, u64Arg);
990}
991
992
993
994/**
995 * Internal R0 logger worker: Flush logger.
996 *
997 * @param pLogger The logger instance to flush.
998 * @remark This function must be exported!
999 */
1000VMMR0DECL(void) vmmR0LoggerFlush(PRTLOGGER pLogger)
1001{
1002 /*
1003 * Convert the pLogger into a VM handle and 'call' back to Ring-3.
1004 * (This is a bit paranoid code.)
1005 */
1006 PVMMR0LOGGER pR0Logger = (PVMMR0LOGGER)((uintptr_t)pLogger - RT_OFFSETOF(VMMR0LOGGER, Logger));
1007 if ( !VALID_PTR(pR0Logger)
1008 || !VALID_PTR(pR0Logger + 1)
1009 || !VALID_PTR(pLogger)
1010 || pLogger->u32Magic != RTLOGGER_MAGIC)
1011 {
1012 LogCom(("vmmR0LoggerFlush: pLogger=%p!\n", pLogger));
1013 return;
1014 }
1015
1016 PVM pVM = pR0Logger->pVM;
1017 if ( !VALID_PTR(pVM)
1018 || pVM->pVMR0 != pVM)
1019 {
1020 LogCom(("vmmR0LoggerFlush: pVM=%p! pLogger=%p\n", pVM, pLogger));
1021 return;
1022 }
1023
1024 /*
1025 * Check that the jump buffer is armed.
1026 */
1027#ifdef RT_ARCH_X86
1028 if (!pVM->vmm.s.CallHostR0JmpBuf.eip)
1029#else
1030 if (!pVM->vmm.s.CallHostR0JmpBuf.rip)
1031#endif
1032 {
1033 LogCom(("vmmR0LoggerFlush: Jump buffer isn't armed!\n"));
1034 pLogger->offScratch = 0;
1035 return;
1036 }
1037
1038 VMMR0CallHost(pVM, VMMCALLHOST_VMM_LOGGER_FLUSH, 0);
1039}
1040
1041
1042
1043/**
1044 * Jump back to ring-3 if we're the EMT and the longjmp is armed.
1045 *
1046 * @returns true if the breakpoint should be hit, false if it should be ignored.
1047 * @remark The RTDECL() makes this a bit difficult to override on windows. Sorry.
1048 */
1049DECLEXPORT(bool) RTCALL RTAssertDoBreakpoint(void)
1050{
1051 PVM pVM = GVMMR0GetVMByEMT(NIL_RTNATIVETHREAD);
1052 if (pVM)
1053 {
1054#ifdef RT_ARCH_X86
1055 if (pVM->vmm.s.CallHostR0JmpBuf.eip)
1056#else
1057 if (pVM->vmm.s.CallHostR0JmpBuf.rip)
1058#endif
1059 {
1060 int rc = VMMR0CallHost(pVM, VMMCALLHOST_VM_R0_HYPER_ASSERTION, 0);
1061 return RT_FAILURE_NP(rc);
1062 }
1063 }
1064#ifdef RT_OS_LINUX
1065 return true;
1066#else
1067 return false;
1068#endif
1069}
1070
1071
1072
1073# undef LOG_GROUP
1074# define LOG_GROUP LOG_GROUP_EM
1075
1076/**
1077 * Override this so we can push
1078 *
1079 * @param pszExpr Expression. Can be NULL.
1080 * @param uLine Location line number.
1081 * @param pszFile Location file name.
1082 * @param pszFunction Location function name.
1083 * @remark This API exists in HC Ring-3 and GC.
1084 */
1085DECLEXPORT(void) RTCALL AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
1086{
1087 SUPR0Printf("\n!!R0-Assertion Failed!!\n"
1088 "Expression: %s\n"
1089 "Location : %s(%d) %s\n",
1090 pszExpr, pszFile, uLine, pszFunction);
1091
1092 LogRel(("\n!!R0-Assertion Failed!!\n"
1093 "Expression: %s\n"
1094 "Location : %s(%d) %s\n",
1095 pszExpr, pszFile, uLine, pszFunction));
1096}
1097
1098
1099/**
1100 * Callback for RTLogFormatV which writes to the com port.
1101 * See PFNLOGOUTPUT() for details.
1102 */
1103static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars)
1104{
1105 for (size_t i = 0; i < cbChars; i++)
1106 {
1107 LogRel(("%c", pachChars[i])); /** @todo this isn't any release logging in ring-0 from what I can tell... */
1108 SUPR0Printf("%c", pachChars[i]);
1109 }
1110
1111 return cbChars;
1112}
1113
1114
1115DECLEXPORT(void) RTCALL AssertMsg2(const char *pszFormat, ...)
1116{
1117 PRTLOGGER pLog = RTLogDefaultInstance();
1118 if (pLog)
1119 {
1120 va_list args;
1121
1122 va_start(args, pszFormat);
1123 RTLogFormatV(rtLogOutput, pLog, pszFormat, args);
1124 va_end(args);
1125 }
1126}
1127
1128
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