VirtualBox

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

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

Cleaned up disassembler

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.6 KB
Line 
1/* $Id: VMMR0.cpp 4953 2007-09-21 14:08:19Z 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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * 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/intnet.h>
32#include <VBox/hwaccm.h>
33
34#include <VBox/err.h>
35#include <VBox/version.h>
36#include <VBox/log.h>
37#include <iprt/assert.h>
38#include <iprt/stdarg.h>
39
40#if defined(_MSC_VER) && defined(RT_ARCH_AMD64) /** @todo check this with with VC7! */
41# pragma intrinsic(_AddressOfReturnAddress)
42#endif
43
44
45/*******************************************************************************
46* Internal Functions *
47*******************************************************************************/
48static int VMMR0Init(PVM pVM, unsigned uVersion);
49static int VMMR0Term(PVM pVM);
50__BEGIN_DECLS
51VMMR0DECL(int) ModuleInit(void);
52VMMR0DECL(void) ModuleTerm(void);
53__END_DECLS
54
55
56/** @def DEBUG_NO_RING0_ASSERTIONS
57 * Define this if you don't wish to BSOD on debug assertions in
58 * the VMMR0.r0 code. If would of course be nice to have this
59 * feature enabled by default of course, but it's not currently
60 * safe when more than one VM is running or when using internal
61 * networking. */
62#if defined(DEBUG_sandervl) /*|| defined(DEBUG_bird)*/
63# define DEBUG_NO_RING0_ASSERTIONS
64#endif
65#ifdef DEBUG_NO_RING0_ASSERTIONS
66static PVM g_pVMAssert = 0;
67#endif
68
69/*******************************************************************************
70* Global Variables *
71*******************************************************************************/
72#ifdef VBOX_WITH_INTERNAL_NETWORKING
73/** Pointer to the internal networking service instance. */
74PINTNET g_pIntNet = 0;
75#endif
76
77
78/**
79 * Initialize the module.
80 * This is called when we're first loaded.
81 *
82 * @returns 0 on success.
83 * @returns VBox status on failure.
84 */
85VMMR0DECL(int) ModuleInit(void)
86{
87#ifdef VBOX_WITH_INTERNAL_NETWORKING
88 LogFlow(("ModuleInit: g_pIntNet=%p\n", g_pIntNet));
89 g_pIntNet = NULL;
90 LogFlow(("ModuleInit: g_pIntNet=%p should be NULL now...\n", g_pIntNet));
91 int rc = INTNETR0Create(&g_pIntNet);
92 if (VBOX_SUCCESS(rc))
93 {
94 LogFlow(("ModuleInit: returns success. g_pIntNet=%p\n", g_pIntNet));
95 return 0;
96 }
97 g_pIntNet = NULL;
98 LogFlow(("ModuleTerm: returns %Vrc\n", rc));
99 return rc;
100#else
101 return 0;
102#endif
103}
104
105
106/**
107 * Terminate the module.
108 * This is called when we're finally unloaded.
109 */
110VMMR0DECL(void) ModuleTerm(void)
111{
112#ifdef VBOX_WITH_INTERNAL_NETWORKING
113 LogFlow(("ModuleTerm:\n"));
114 if (g_pIntNet)
115 {
116 INTNETR0Destroy(g_pIntNet);
117 g_pIntNet = NULL;
118 }
119 LogFlow(("ModuleTerm: returns\n"));
120#endif
121}
122
123
124/**
125 * Initaties the R0 driver for a particular VM instance.
126 *
127 * @returns VBox status code.
128 *
129 * @param pVM The VM instance in question.
130 * @param uVersion The minimum module version required.
131 */
132static int VMMR0Init(PVM pVM, unsigned uVersion)
133{
134 /*
135 * Check if compatible version.
136 */
137 if ( uVersion != VBOX_VERSION
138 && ( VBOX_GET_VERSION_MAJOR(uVersion) != VBOX_VERSION_MAJOR
139 || VBOX_GET_VERSION_MINOR(uVersion) < VBOX_VERSION_MINOR))
140 return VERR_VERSION_MISMATCH;
141 if ( !VALID_PTR(pVM)
142 || pVM->pVMR0 != pVM)
143 return VERR_INVALID_PARAMETER;
144
145 /*
146 * Register the EMT R0 logger instance.
147 */
148 PVMMR0LOGGER pR0Logger = pVM->vmm.s.pR0Logger;
149 if (pR0Logger)
150 {
151#if 0 /* testing of the logger. */
152 LogCom(("VMMR0Init: before %p\n", RTLogDefaultInstance()));
153 LogCom(("VMMR0Init: pfnFlush=%p actual=%p\n", pR0Logger->Logger.pfnFlush, vmmR0LoggerFlush));
154 LogCom(("VMMR0Init: pfnLogger=%p actual=%p\n", pR0Logger->Logger.pfnLogger, vmmR0LoggerWrapper));
155 LogCom(("VMMR0Init: offScratch=%d fFlags=%#x fDestFlags=%#x\n", pR0Logger->Logger.offScratch, pR0Logger->Logger.fFlags, pR0Logger->Logger.fDestFlags));
156
157 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
158 LogCom(("VMMR0Init: after %p reg\n", RTLogDefaultInstance()));
159 RTLogSetDefaultInstanceThread(NULL, 0);
160 LogCom(("VMMR0Init: after %p dereg\n", RTLogDefaultInstance()));
161
162 pR0Logger->Logger.pfnLogger("hello ring-0 logger\n");
163 LogCom(("VMMR0Init: returned succesfully from direct logger call.\n"));
164 pR0Logger->Logger.pfnFlush(&pR0Logger->Logger);
165 LogCom(("VMMR0Init: returned succesfully from direct flush call.\n"));
166
167 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
168 LogCom(("VMMR0Init: after %p reg2\n", RTLogDefaultInstance()));
169 pR0Logger->Logger.pfnLogger("hello ring-0 logger\n");
170 LogCom(("VMMR0Init: returned succesfully from direct logger call (2). offScratch=%d\n", pR0Logger->Logger.offScratch));
171 RTLogSetDefaultInstanceThread(NULL, 0);
172 LogCom(("VMMR0Init: after %p dereg2\n", RTLogDefaultInstance()));
173
174 RTLogLoggerEx(&pR0Logger->Logger, 0, ~0U, "hello ring-0 logger (RTLogLoggerEx)\n");
175 LogCom(("VMMR0Init: RTLogLoggerEx returned fine offScratch=%d\n", pR0Logger->Logger.offScratch));
176
177 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
178 RTLogPrintf("hello ring-0 logger (RTLogPrintf)\n");
179 LogCom(("VMMR0Init: RTLogPrintf returned fine offScratch=%d\n", pR0Logger->Logger.offScratch));
180#endif
181 RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
182 }
183
184
185 /*
186 * Init VMXM.
187 */
188 int rc = HWACCMR0Init(pVM);
189 if (VBOX_FAILURE(rc))
190 {
191 RTLogSetDefaultInstanceThread(NULL, 0);
192 return rc;
193 }
194
195 /*
196 * Init CPUM.
197 */
198 rc = CPUMR0Init(pVM);
199
200 if (RT_FAILURE(rc))
201 RTLogSetDefaultInstanceThread(NULL, 0);
202 return rc;
203}
204
205
206/**
207 * Terminates the R0 driver for a particular VM instance.
208 *
209 * @returns VBox status code.
210 *
211 * @param pVM The VM instance in question.
212 */
213static int VMMR0Term(PVM pVM)
214{
215 /*
216 * Deregister the logger.
217 */
218 RTLogSetDefaultInstanceThread(NULL, 0);
219 return VINF_SUCCESS;
220}
221
222
223/**
224 * Calls the ring-3 host code.
225 *
226 * @returns VBox status code of the ring-3 call.
227 * @param pVM The VM handle.
228 * @param enmOperation The operation.
229 * @param uArg The argument to the operation.
230 */
231VMMR0DECL(int) VMMR0CallHost(PVM pVM, VMMCALLHOST enmOperation, uint64_t uArg)
232{
233/** @todo profile this! */
234 pVM->vmm.s.enmCallHostOperation = enmOperation;
235 pVM->vmm.s.u64CallHostArg = uArg;
236 pVM->vmm.s.rcCallHost = VERR_INTERNAL_ERROR;
237 int rc = vmmR0CallHostLongJmp(&pVM->vmm.s.CallHostR0JmpBuf, VINF_VMM_CALL_HOST);
238 if (rc == VINF_SUCCESS)
239 rc = pVM->vmm.s.rcCallHost;
240 return rc;
241}
242
243
244#ifdef VBOX_WITH_STATISTICS
245/**
246 * Record return code statistics
247 * @param pVM The VM handle.
248 * @param rc The status code.
249 */
250static void vmmR0RecordRC(PVM pVM, int rc)
251{
252 /*
253 * Collect statistics.
254 */
255 switch (rc)
256 {
257 case VINF_SUCCESS:
258 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetNormal);
259 break;
260 case VINF_EM_RAW_INTERRUPT:
261 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetInterrupt);
262 break;
263 case VINF_EM_RAW_INTERRUPT_HYPER:
264 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetInterruptHyper);
265 break;
266 case VINF_EM_RAW_GUEST_TRAP:
267 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetGuestTrap);
268 break;
269 case VINF_EM_RAW_RING_SWITCH:
270 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetRingSwitch);
271 break;
272 case VINF_EM_RAW_RING_SWITCH_INT:
273 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetRingSwitchInt);
274 break;
275 case VINF_EM_RAW_EXCEPTION_PRIVILEGED:
276 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetExceptionPrivilege);
277 break;
278 case VINF_EM_RAW_STALE_SELECTOR:
279 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetStaleSelector);
280 break;
281 case VINF_EM_RAW_IRET_TRAP:
282 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetIRETTrap);
283 break;
284 case VINF_IOM_HC_IOPORT_READ:
285 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetIORead);
286 break;
287 case VINF_IOM_HC_IOPORT_WRITE:
288 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetIOWrite);
289 break;
290 case VINF_IOM_HC_MMIO_READ:
291 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMMIORead);
292 break;
293 case VINF_IOM_HC_MMIO_WRITE:
294 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMMIOWrite);
295 break;
296 case VINF_IOM_HC_MMIO_READ_WRITE:
297 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMMIOReadWrite);
298 break;
299 case VINF_PATM_HC_MMIO_PATCH_READ:
300 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMMIOPatchRead);
301 break;
302 case VINF_PATM_HC_MMIO_PATCH_WRITE:
303 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMMIOPatchWrite);
304 break;
305 case VINF_EM_RAW_EMULATE_INSTR:
306 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetEmulate);
307 break;
308 case VINF_PATCH_EMULATE_INSTR:
309 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPatchEmulate);
310 break;
311 case VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT:
312 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetLDTFault);
313 break;
314 case VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT:
315 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetGDTFault);
316 break;
317 case VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT:
318 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetIDTFault);
319 break;
320 case VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT:
321 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetTSSFault);
322 break;
323 case VINF_EM_RAW_EMULATE_INSTR_PD_FAULT:
324 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPDFault);
325 break;
326 case VINF_CSAM_PENDING_ACTION:
327 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetCSAMTask);
328 break;
329 case VINF_PGM_SYNC_CR3:
330 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetSyncCR3);
331 break;
332 case VINF_PATM_PATCH_INT3:
333 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPatchInt3);
334 break;
335 case VINF_PATM_PATCH_TRAP_PF:
336 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPatchPF);
337 break;
338 case VINF_PATM_PATCH_TRAP_GP:
339 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPatchGP);
340 break;
341 case VINF_PATM_PENDING_IRQ_AFTER_IRET:
342 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPatchIretIRQ);
343 break;
344 case VERR_REM_FLUSHED_PAGES_OVERFLOW:
345 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPageOverflow);
346 break;
347 case VINF_EM_RESCHEDULE_REM:
348 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetRescheduleREM);
349 break;
350 case VINF_EM_RAW_TO_R3:
351 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetToR3);
352 break;
353 case VINF_EM_RAW_TIMER_PENDING:
354 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetTimerPending);
355 break;
356 case VINF_EM_RAW_INTERRUPT_PENDING:
357 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetInterruptPending);
358 break;
359 case VINF_VMM_CALL_HOST:
360 switch (pVM->vmm.s.enmCallHostOperation)
361 {
362 case VMMCALLHOST_PDM_LOCK:
363 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPDMLock);
364 break;
365 case VMMCALLHOST_PDM_QUEUE_FLUSH:
366 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPDMQueueFlush);
367 break;
368 case VMMCALLHOST_PGM_POOL_GROW:
369 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPGMPoolGrow);
370 break;
371 case VMMCALLHOST_PGM_LOCK:
372 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPGMLock);
373 break;
374 case VMMCALLHOST_REM_REPLAY_HANDLER_NOTIFICATIONS:
375 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetRemReplay);
376 break;
377 case VMMCALLHOST_PGM_RAM_GROW_RANGE:
378 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPGMGrowRAM);
379 break;
380 case VMMCALLHOST_VMM_LOGGER_FLUSH:
381 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetLogFlush);
382 break;
383 case VMMCALLHOST_VM_SET_ERROR:
384 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetVMSetError);
385 break;
386 case VMMCALLHOST_VM_SET_RUNTIME_ERROR:
387 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetVMSetRuntimeError);
388 break;
389 default:
390 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetCallHost);
391 break;
392 }
393 break;
394 case VINF_PATM_DUPLICATE_FUNCTION:
395 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPATMDuplicateFn);
396 break;
397 case VINF_PGM_CHANGE_MODE:
398 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPGMChangeMode);
399 break;
400 case VINF_EM_RAW_EMULATE_INSTR_HLT:
401 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetEmulHlt);
402 break;
403 case VINF_EM_PENDING_REQUEST:
404 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetPendingRequest);
405 break;
406 default:
407 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetMisc);
408 break;
409 }
410}
411#endif /* VBOX_WITH_STATISTICS */
412
413
414
415/**
416 * The Ring 0 entry point, called by the interrupt gate.
417 *
418 * @returns VBox status code.
419 * @param pVM The VM to operate on.
420 * @param enmOperation Which operation to execute.
421 * @param pvArg Argument to the operation.
422 * @remarks Assume called with interrupts disabled.
423 */
424VMMR0DECL(int) VMMR0EntryInt(PVM pVM, VMMR0OPERATION enmOperation, void *pvArg)
425{
426 switch (enmOperation)
427 {
428#ifdef VBOX_WITH_IDT_PATCHING
429 /*
430 * Switch to GC.
431 * These calls return whatever the GC returns.
432 */
433 case VMMR0_DO_RAW_RUN:
434 {
435 /* Safety precaution as VMX disables the switcher. */
436 Assert(!pVM->vmm.s.fSwitcherDisabled);
437 if (pVM->vmm.s.fSwitcherDisabled)
438 return VERR_NOT_SUPPORTED;
439
440 STAM_COUNTER_INC(&pVM->vmm.s.StatRunGC);
441 register int rc;
442 pVM->vmm.s.iLastGCRc = rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
443
444#ifdef VBOX_WITH_STATISTICS
445 vmmR0RecordRC(pVM, rc);
446#endif
447
448 /*
449 * We'll let TRPM change the stack frame so our return is different.
450 * Just keep in mind that after the call, things have changed!
451 */
452 if ( rc == VINF_EM_RAW_INTERRUPT
453 || rc == VINF_EM_RAW_INTERRUPT_HYPER)
454 {
455 /*
456 * Don't trust the compiler to get this right.
457 * gcc -fomit-frame-pointer screws up big time here. This works fine in 64-bit
458 * mode too because we push the arguments on the stack in the IDT patch code.
459 */
460# if defined(__GNUC__)
461 void *pvRet = (uint8_t *)__builtin_frame_address(0) + sizeof(void *);
462# elif defined(_MSC_VER) && defined(RT_ARCH_AMD64) /** @todo check this with with VC7! */
463 void *pvRet = (uint8_t *)_AddressOfReturnAddress();
464# elif defined(RT_ARCH_X86)
465 void *pvRet = (uint8_t *)&pVM - sizeof(pVM);
466# else
467# error "huh?"
468# endif
469 if ( ((uintptr_t *)pvRet)[1] == (uintptr_t)pVM
470 && ((uintptr_t *)pvRet)[2] == (uintptr_t)enmOperation
471 && ((uintptr_t *)pvRet)[3] == (uintptr_t)pvArg)
472 TRPMR0SetupInterruptDispatcherFrame(pVM, pvRet);
473 else
474 {
475# if defined(DEBUG) || defined(LOG_ENABLED)
476 static bool s_fHaveWarned = false;
477 if (!s_fHaveWarned)
478 {
479 s_fHaveWarned = true;
480 //RTLogPrintf("VMMR0.r0: The compiler can't find the stack frame!\n"); -- @todo export me!
481 RTLogComPrintf("VMMR0.r0: The compiler can't find the stack frame!\n");
482 }
483# endif
484 TRPMR0DispatchHostInterrupt(pVM);
485 }
486 }
487 return rc;
488 }
489
490 /*
491 * Initialize the R0 part of a VM instance.
492 */
493 case VMMR0_DO_VMMR0_INIT:
494 {
495 RTCCUINTREG fFlags = ASMIntDisableFlags();
496 int rc = VMMR0Init(pVM, (unsigned)(uintptr_t)pvArg);
497 ASMSetFlags(fFlags);
498 return rc;
499 }
500
501 /*
502 * Terminate the R0 part of a VM instance.
503 */
504 case VMMR0_DO_VMMR0_TERM:
505 {
506 RTCCUINTREG fFlags = ASMIntDisableFlags();
507 int rc = VMMR0Term(pVM);
508 ASMSetFlags(fFlags);
509 return rc;
510 }
511
512 /*
513 * Switch to GC to execute Hypervisor function.
514 */
515 case VMMR0_DO_CALL_HYPERVISOR:
516 {
517 /* Safety precaution as VMX disables the switcher. */
518 Assert(!pVM->vmm.s.fSwitcherDisabled);
519 if (pVM->vmm.s.fSwitcherDisabled)
520 return VERR_NOT_SUPPORTED;
521
522 RTCCUINTREG fFlags = ASMIntDisableFlags();
523 int rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
524 ASMSetFlags(fFlags);
525 return rc;
526 }
527
528 /*
529 * For profiling.
530 */
531 case VMMR0_DO_NOP:
532 return VINF_SUCCESS;
533#endif /* VBOX_WITH_IDT_PATCHING */
534
535 default:
536 /*
537 * We're returning VERR_NOT_SUPPORT here so we've got something else
538 * than -1 which the interrupt gate glue code might return.
539 */
540 Log(("operation %#x is not supported\n", enmOperation));
541 return VERR_NOT_SUPPORTED;
542 }
543}
544
545
546/**
547 * The Ring 0 entry point, called by the fast-ioctl path.
548 *
549 * @returns VBox status code.
550 * @param pVM The VM to operate on.
551 * @param enmOperation Which operation to execute.
552 * @remarks Assume called with interrupts disabled.
553 */
554VMMR0DECL(int) VMMR0EntryFast(PVM pVM, VMMR0OPERATION enmOperation)
555{
556 switch (enmOperation)
557 {
558 /*
559 * Switch to GC and run guest raw mode code.
560 */
561 case VMMR0_DO_RAW_RUN:
562 {
563 /* We must disable interrupts here */
564 RTCCUINTREG uFlags = ASMIntDisableFlags();
565
566 /* Safety precaution as hwaccm disables the switcher. */
567 if (RT_LIKELY(!pVM->vmm.s.fSwitcherDisabled))
568 {
569 int rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
570 pVM->vmm.s.iLastGCRc = rc;
571
572 if ( rc == VINF_EM_RAW_INTERRUPT
573 || rc == VINF_EM_RAW_INTERRUPT_HYPER)
574 TRPMR0DispatchHostInterrupt(pVM);
575
576#ifdef VBOX_WITH_STATISTICS
577 STAM_COUNTER_INC(&pVM->vmm.s.StatRunGC);
578 vmmR0RecordRC(pVM, rc);
579#endif
580 ASMSetFlags(uFlags);
581 return rc;
582 }
583 ASMSetFlags(uFlags);
584
585 Assert(!pVM->vmm.s.fSwitcherDisabled);
586 return VERR_NOT_SUPPORTED;
587 }
588
589 /*
590 * Run guest code using the available hardware acceleration technology.
591 */
592 case VMMR0_DO_HWACC_RUN:
593 {
594 STAM_COUNTER_INC(&pVM->vmm.s.StatRunGC);
595
596#ifndef RT_OS_WINDOWS /* test on other platforms */
597 /* We must disable interrupts here */
598 RTCCUINTREG uFlags = ASMIntDisableFlags();
599#endif
600 int rc = HWACCMR0Enable(pVM);
601 if (VBOX_SUCCESS(rc))
602 {
603#ifdef DEBUG_NO_RING0_ASSERTIONS
604 g_pVMAssert = pVM;
605#endif
606 rc = vmmR0CallHostSetJmp(&pVM->vmm.s.CallHostR0JmpBuf, HWACCMR0RunGuestCode, pVM); /* this may resume code. */
607#ifdef DEBUG_NO_RING0_ASSERTIONS
608 g_pVMAssert = NULL;
609#endif
610 int rc2 = HWACCMR0Disable(pVM);
611 AssertRC(rc2);
612 }
613 pVM->vmm.s.iLastGCRc = rc;
614
615#ifndef RT_OS_WINDOWS /* test on other platforms */
616 ASMSetFlags(uFlags);
617#endif
618
619#ifdef VBOX_WITH_STATISTICS
620 vmmR0RecordRC(pVM, rc);
621#endif
622 /* No special action required for external interrupts, just return. */
623 return rc;
624 }
625
626 /*
627 * For profiling.
628 */
629 case VMMR0_DO_NOP:
630 return VINF_SUCCESS;
631
632 /*
633 * Impossible.
634 */
635 default:
636 AssertMsgFailed(("%#x\n", enmOperation));
637 return VERR_NOT_SUPPORTED;
638 }
639}
640
641
642/**
643 * The Ring 0 entry point, called by the support library (SUP).
644 *
645 * @returns VBox status code.
646 * @param pVM The VM to operate on.
647 * @param enmOperation Which operation to execute.
648 * @param pReq This points to a SUPVMMR0REQHDR packet. Optional.
649 * @param u64Arg Some simple constant argument.
650 * @remarks Assume called with interrupts _enabled_.
651 */
652VMMR0DECL(int) VMMR0EntryEx(PVM pVM, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg)
653{
654 switch (enmOperation)
655 {
656 /*
657 * Initialize the R0 part of a VM instance.
658 */
659 case VMMR0_DO_VMMR0_INIT:
660 {
661 RTCCUINTREG fFlags = ASMIntDisableFlags();
662 int rc = VMMR0Init(pVM, (unsigned)u64Arg);
663 ASMSetFlags(fFlags);
664 return rc;
665 }
666
667 /*
668 * Terminate the R0 part of a VM instance.
669 */
670 case VMMR0_DO_VMMR0_TERM:
671 {
672 RTCCUINTREG fFlags = ASMIntDisableFlags();
673 int rc = VMMR0Term(pVM);
674 ASMSetFlags(fFlags);
675 return rc;
676 }
677
678 /*
679 * Setup the hardware accelerated raw-mode session.
680 */
681 case VMMR0_DO_HWACC_SETUP_VM:
682 {
683 RTCCUINTREG fFlags = ASMIntDisableFlags();
684 int rc = HWACCMR0SetupVMX(pVM);
685 ASMSetFlags(fFlags);
686 return rc;
687 }
688
689 /*
690 * Switch to GC to execute Hypervisor function.
691 */
692 case VMMR0_DO_CALL_HYPERVISOR:
693 {
694 /* Safety precaution as VMX disables the switcher. */
695 Assert(!pVM->vmm.s.fSwitcherDisabled);
696 if (pVM->vmm.s.fSwitcherDisabled)
697 return VERR_NOT_SUPPORTED;
698
699 RTCCUINTREG fFlags = ASMIntDisableFlags();
700 int rc = pVM->vmm.s.pfnR0HostToGuest(pVM);
701 ASMSetFlags(fFlags);
702 return rc;
703 }
704
705 /*
706 * PGM wrappers.
707 */
708 case VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES:
709 return PGMR0PhysAllocateHandyPages(pVM);
710
711#if 0
712 /*
713 * GMM wrappers
714 */
715 case VMMR0_DO_GMM_ALLOCATE_PAGES:
716 return GMMR0AllocatePages(pVM, ...);
717 case VMMR0_DO_GMM_FREE_PAGES:
718 return GMMR0FreePages(pVM, ...);
719 case VMMR0_DO_GMM_MAP_UNMAP_CHUNK:
720 return GMMR0FreeMapUnmapChunk(pVM, ...);
721 case VMMR0_DO_GMM_SEED_CHUNK:
722 return GMMR0SeedChunk(pVM, (RTR3PTR)pvArg);
723#endif
724
725
726
727#if 0//def VBOX_WITH_INTERNAL_NETWORKING - currently busted
728 /*
729 * Services.
730 */
731 case VMMR0_DO_INTNET_OPEN:
732 case VMMR0_DO_INTNET_IF_CLOSE:
733 case VMMR0_DO_INTNET_IF_GET_RING3_BUFFER:
734 case VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE:
735 case VMMR0_DO_INTNET_IF_SEND:
736 case VMMR0_DO_INTNET_IF_WAIT:
737 {
738 /*
739 * Validate arguments a bit first.
740 */
741 if (!VALID_PTR(pvArg))
742 return VERR_INVALID_POINTER;
743 if (!VALID_PTR(pVM))
744 return VERR_INVALID_POINTER;
745 if (pVM->pVMR0 != pVM)
746 return VERR_INVALID_POINTER;
747 if (!VALID_PTR(pVM->pSession))
748 return VERR_INVALID_POINTER;
749 if (!g_pIntNet)
750 return VERR_FILE_NOT_FOUND; ///@todo fix this status code!
751
752 /*
753 * Unpack the arguments and call the service.
754 */
755 switch (enmOperation)
756 {
757 case VMMR0_DO_INTNET_OPEN:
758 {
759 PINTNETOPENARGS pArgs = (PINTNETOPENARGS)pvArg;
760 return INTNETR0Open(g_pIntNet, pVM->pSession, &pArgs->szNetwork[0], pArgs->cbSend, pArgs->cbRecv, pArgs->fRestrictAccess, &pArgs->hIf);
761 }
762
763 case VMMR0_DO_INTNET_IF_CLOSE:
764 {
765 PINTNETIFCLOSEARGS pArgs = (PINTNETIFCLOSEARGS)pvArg;
766 return INTNETR0IfClose(g_pIntNet, pArgs->hIf);
767 }
768
769 case VMMR0_DO_INTNET_IF_GET_RING3_BUFFER:
770 {
771 PINTNETIFGETRING3BUFFERARGS pArgs = (PINTNETIFGETRING3BUFFERARGS)pvArg;
772 return INTNETR0IfGetRing3Buffer(g_pIntNet, pArgs->hIf, &pArgs->pRing3Buf);
773 }
774
775 case VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE:
776 {
777 PINTNETIFSETPROMISCUOUSMODEARGS pArgs = (PINTNETIFSETPROMISCUOUSMODEARGS)pvArg;
778 return INTNETR0IfSetPromiscuousMode(g_pIntNet, pArgs->hIf, pArgs->fPromiscuous);
779 }
780
781 case VMMR0_DO_INTNET_IF_SEND:
782 {
783 PINTNETIFSENDARGS pArgs = (PINTNETIFSENDARGS)pvArg;
784 return INTNETR0IfSend(g_pIntNet, pArgs->hIf, pArgs->pvFrame, pArgs->cbFrame);
785 }
786
787 case VMMR0_DO_INTNET_IF_WAIT:
788 {
789 PINTNETIFWAITARGS pArgs = (PINTNETIFWAITARGS)pvArg;
790 return INTNETR0IfWait(g_pIntNet, pArgs->hIf, pArgs->cMillies);
791 }
792
793 default:
794 return VERR_NOT_SUPPORTED;
795 }
796 }
797#endif /* VBOX_WITH_INTERNAL_NETWORKING */
798
799 /*
800 * For profiling.
801 */
802 case VMMR0_DO_NOP:
803 return VINF_SUCCESS;
804
805 /*
806 * For testing Ring-0 APIs invoked in this environment.
807 */
808 case VMMR0_DO_TESTS:
809 /** @todo make new test */
810 return VINF_SUCCESS;
811
812
813 default:
814 /*
815 * We're returning VERR_NOT_SUPPORT here so we've got something else
816 * than -1 which the interrupt gate glue code might return.
817 */
818 Log(("operation %#x is not supported\n", enmOperation));
819 return VERR_NOT_SUPPORTED;
820 }
821}
822
823
824
825
826/**
827 * Internal R0 logger worker: Flush logger.
828 *
829 * @param pLogger The logger instance to flush.
830 * @remark This function must be exported!
831 */
832VMMR0DECL(void) vmmR0LoggerFlush(PRTLOGGER pLogger)
833{
834 /*
835 * Convert the pLogger into a VM handle and 'call' back to Ring-3.
836 * (This is a bit paranoid code.)
837 */
838 PVMMR0LOGGER pR0Logger = (PVMMR0LOGGER)((uintptr_t)pLogger - RT_OFFSETOF(VMMR0LOGGER, Logger));
839 if ( !VALID_PTR(pR0Logger)
840 || !VALID_PTR(pR0Logger + 1)
841 || !VALID_PTR(pLogger)
842 || pLogger->u32Magic != RTLOGGER_MAGIC)
843 {
844 LogCom(("vmmR0LoggerFlush: pLogger=%p!\n", pLogger));
845 return;
846 }
847
848 PVM pVM = pR0Logger->pVM;
849 if ( !VALID_PTR(pVM)
850 || pVM->pVMR0 != pVM)
851 {
852 LogCom(("vmmR0LoggerFlush: pVM=%p! pLogger=%p\n", pVM, pLogger));
853 return;
854 }
855
856 /*
857 * Check that the jump buffer is armed.
858 */
859#ifdef RT_ARCH_X86
860 if (!pVM->vmm.s.CallHostR0JmpBuf.eip)
861#else
862 if (!pVM->vmm.s.CallHostR0JmpBuf.rip)
863#endif
864 {
865 LogCom(("vmmR0LoggerFlush: Jump buffer isn't armed!\n"));
866 pLogger->offScratch = 0;
867 return;
868 }
869
870 VMMR0CallHost(pVM, VMMCALLHOST_VMM_LOGGER_FLUSH, 0);
871}
872
873
874#ifdef DEBUG_NO_RING0_ASSERTIONS
875/**
876 * Check if we really want to hit a breakpoint.
877 * Can jump back to ring-3 when the longjmp is armed.
878 */
879DECLEXPORT(bool) RTCALL RTAssertDoBreakpoint()
880{
881 if (g_pVMAssert)
882 {
883 int rc = VMMR0CallHost(g_pVMAssert, VMMCALLHOST_VM_R0_HYPER_ASSERTION, 0);
884 if (rc == VINF_SUCCESS)
885 rc = g_pVMAssert->vmm.s.rcCallHost;
886 }
887
888 return false;
889}
890#endif /* !DEBUG_NO_RING0_ASSERTIONS */
891
892
893
894# undef LOG_GROUP
895# define LOG_GROUP LOG_GROUP_EM
896
897DECLEXPORT(void) RTCALL RTR0AssertBreakpoint(void *pvVM)
898{
899 if (pvVM)
900 {
901 PVM pVM = (PVM)pvVM;
902 VMMR0CallHost(pVM, VMMCALLHOST_VM_R0_HYPER_ASSERTION, 0);
903 /* does not return */
904 }
905}
906
907/** Runtime assert implementation for Native Win32 Ring-0. */
908DECLEXPORT(void) RTCALL AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
909{
910 LogRel(("\n!!R0-Assertion Failed!!\n"
911 "Expression: %s\n"
912 "Location : %s(%d) %s\n",
913 pszExpr, pszFile, uLine, pszFunction));
914}
915
916/**
917 * Callback for RTLogFormatV which writes to the com port.
918 * See PFNLOGOUTPUT() for details.
919 */
920static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars)
921{
922 for (size_t i=0;i<cbChars;i++)
923 LogRel(("%c", pachChars[i]));
924
925 return cbChars;
926}
927
928DECLEXPORT(void) RTCALL AssertMsg2(const char *pszFormat, ...)
929{
930 PRTLOGGER pLog = RTLogDefaultInstance();
931 if (pLog)
932 {
933 va_list args;
934
935 va_start(args, pszFormat);
936 RTLogFormatV(rtLogOutput, pLog, pszFormat, args);
937 va_end(args);
938 }
939}
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