VirtualBox

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

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

(void)

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