VirtualBox

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

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

GVMR0CreateVM isn't used yet, so disable the code for now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 20.5 KB
Line 
1/* $Id: GVMR0.cpp 4980 2007-09-22 00:07:17Z vboxsync $ */
2/** @file
3 * GVM - Global VM Manager.
4 */
5
6/*
7 * Copyright (C) 2007 InnoTek Systemberatung 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/** @page pg_GVM GVM - Global VM Manager
21 *
22 * The Global VM Manager lives in ring-0. It's main function at the moment
23 * is to manage a list of all running VMs and assign unique identifiers to
24 * each of them (so GMM can track page owners). The idea for the future is
25 * to add an idle priority kernel thread that can take care of tasks like
26 * page sharing.
27 *
28 * The GVM will create a ring-0 object for each VM when it's registered, this
29 * is both for session cleanup purposes and for having a point where it's
30 * possible to implement usage polices later (in SUPR0ObjRegister).
31 */
32
33
34/*******************************************************************************
35* Header Files *
36*******************************************************************************/
37#define LOG_GROUP LOG_GROUP_GVM
38#include <VBox/gvm.h>
39/* #include "GVMInternal.h" */
40#include <VBox/vm.h>
41#include <VBox/err.h>
42#include <iprt/alloc.h>
43#include <iprt/semaphore.h>
44#include <iprt/log.h>
45#include <iprt/thread.h>
46#include <iprt/param.h>
47#include <iprt/string.h>
48
49
50/*******************************************************************************
51* Structures and Typedefs *
52*******************************************************************************/
53
54/**
55 * Global VM handle.
56 */
57typedef struct GVMHANDLE
58{
59 /** The index of the next handle in the list (free or used). (0 is nil.) */
60 uint16_t volatile iNext;
61 /** Our own index / handle value. */
62 uint16_t iSelf;
63 /** Whether to free the VM structure or not. */
64 bool fFreeVM;
65 /** The ring-0 mapping of the VM instance data. */
66 PVM pVM;
67 /** The virtual machine object. */
68 void *pvObj;
69 /** The session this VM is associated with. */
70 PSUPDRVSESSION pSession;
71 /** The ring-0 handle of the EMT thread.
72 * This is used for assertions and similar cases where we need to find the VM handle. */
73 RTNATIVETHREAD hEMT;
74} GVMHANDLE;
75/** Pointer to a global VM handle. */
76typedef GVMHANDLE *PGVMHANDLE;
77
78/**
79 * The GVM instance data.
80 */
81typedef struct
82{
83 /** Eyecatcher / magic. */
84 uint32_t u32Magic;
85 /** The index of the head of the free handle chain. (0 is nil.) */
86 uint16_t volatile iFreeHead;
87 /** The index of the head of the active handle chain. (0 is nil.) */
88 uint16_t volatile iUsedHead;
89 /** The lock used to serialize registration and deregistration. */
90 RTSEMFASTMUTEX Lock;
91 /** The handle array.
92 * The size of this array defines the maximum number of currently running VMs.
93 * The first entry is unused as it represents the NIL handle. */
94 GVMHANDLE aHandles[128];
95} GVM;
96/** Pointer to the GVM instance data. */
97typedef GVM *PGVM;
98
99/** The GVM::u32Magic value (Charlie Haden). */
100#define GVM_MAGIC 0x19370806
101
102
103
104/*******************************************************************************
105* Global Variables *
106*******************************************************************************/
107/** Pointer to the GVM instance data.
108 * (Just my general dislike for global variables.) */
109static PGVM g_pGVM = NULL;
110
111
112/*******************************************************************************
113* Internal Functions *
114*******************************************************************************/
115static DECLCALLBACK(void) gvmR0HandleObjDestructor(void *pvObj, void *pvGVM, void *pvHandle);
116
117
118/**
119 * Initializes the GVM.
120 *
121 * This is called while owninng the loader sempahore (see supdrvIOCtl_LdrLoad()).
122 *
123 * @returns VBox status code.
124 */
125GVMR0DECL(int) GVMR0Init(void)
126{
127 SUPR0Printf("GVMR0Init:\n");
128
129 /*
130 * Allocate and initialize the instance data.
131 */
132 PGVM pGVM = (PGVM)RTMemAllocZ(sizeof(*pGVM));
133 if (!pGVM)
134 return VERR_NO_MEMORY;
135 int rc = RTSemFastMutexCreate(&pGVM->Lock);
136 if (RT_SUCCESS(rc))
137 {
138 pGVM->u32Magic = GVM_MAGIC;
139 pGVM->iUsedHead = 0;
140 pGVM->iFreeHead = 1;
141
142 /* the nil handle */
143 pGVM->aHandles[0].iSelf = 0;
144 pGVM->aHandles[0].iNext = 0;
145
146 /* the tail */
147 unsigned i = RT_ELEMENTS(pGVM->aHandles);
148 pGVM->aHandles[i].iSelf = i;
149 pGVM->aHandles[i].iNext = 0; /* nil */
150
151 /* the rest */
152 while (i-- > 1)
153 {
154 pGVM->aHandles[i].iSelf = i;
155 pGVM->aHandles[i].iNext = i + 1;
156 }
157
158 g_pGVM = pGVM;
159 SUPR0Printf("GVMR0Init: pGVM=%p\n", pGVM);
160 return VINF_SUCCESS;
161 }
162
163 RTMemFree(pGVM);
164 return rc;
165}
166
167
168/**
169 * Terminates the GVM.
170 *
171 * This is called while owning the loader semaphore (see supdrvLdrFree()).
172 * And unless something is wrong, there should be absolutely no VMs
173 * registered at this point.
174 */
175GVMR0DECL(void) GVMR0Term(void)
176{
177 SUPR0Printf("GVMR0Term:\n");
178
179 PGVM pGVM = g_pGVM;
180 g_pGVM = NULL;
181 if (RT_UNLIKELY(!VALID_PTR(pGVM)))
182 {
183 SUPR0Printf("GVMR0Term: pGVM=%p\n", pGVM);
184 return;
185 }
186
187 RTSemFastMutexDestroy(pGVM->Lock);
188 pGVM->Lock = NIL_RTSEMFASTMUTEX;
189 pGVM->u32Magic++;
190 pGVM->iFreeHead = 0;
191 if (pGVM->iUsedHead)
192 {
193 SUPR0Printf("GVMR0Term: iUsedHead=%#x!\n", pGVM->iUsedHead);
194 pGVM->iUsedHead = 0;
195 }
196
197 RTMemFree(pGVM);
198}
199
200
201#if 0 /* not currently used */
202/**
203 * Allocates the VM structure and registers it with GVM.
204 *
205 * @returns VBox status code.
206 * @param pSession The support driver session.
207 * @param ppVM Where to store the pointer to the VM structure.
208 *
209 * @thread EMT.
210 */
211GVMR0DECL(int) GVMR0CreateVM(PSUPDRVSESSION pSession, PVM *ppVM)
212{
213 SUPR0Printf("GVMR0CreateVM: pSession=%p\n", pSession);
214 PGVM pGVM = g_pGVM;
215 AssertPtrReturn(pGVM, VERR_INTERNAL_ERROR);
216
217 AssertPtrReturn(ppVM, VERR_INVALID_POINTER);
218 *ppVM = NULL;
219
220 RTNATIVETHREAD hEMT = RTThreadNativeSelf();
221 AssertReturn(hEMT != NIL_RTNATIVETHREAD, VERR_INTERNAL_ERROR);
222
223 /*
224 * The whole allocation process is protected by the lock.
225 */
226 int rc = RTSemFastMutexRequest(pGVM->Lock);
227 AssertRCReturn(rc, rc);
228
229 /*
230 * Allocate a handle first so we don't waste resources unnecessarily.
231 */
232 uint16_t iHandle = pGVM->iFreeHead;
233 if (iHandle)
234 {
235 PGVMHANDLE pHandle = &pGVM->aHandles[iHandle];
236
237 /* consistency checks, a bit paranoid as always. */
238 if ( !pHandle->pVM
239 && !pHandle->pvObj
240 && pHandle->iSelf == iHandle)
241 {
242 pHandle->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_VM, gvmR0HandleObjDestructor, pGVM, pHandle);
243 if (pHandle->pvObj)
244 {
245 /*
246 * Move the handle from the free to used list and perform permission checks.
247 */
248 pGVM->iFreeHead = pHandle->iNext;
249 pHandle->iNext = pGVM->iUsedHead;
250 pGVM->iUsedHead = iHandle;
251
252 pHandle->fFreeVM = true;
253 pHandle->pVM = NULL;
254 pHandle->pSession = pSession;
255 pHandle->hEMT = hEMT;
256
257 rc = SUPR0ObjVerifyAccess(pHandle->pvObj, pSession, NULL);
258 if (RT_SUCCESS(rc))
259 {
260 /*
261 * Allocate and initialize the VM structure.
262 */
263 RTR3PTR paPagesR3;
264 PRTHCPHYS paPagesR0;
265 size_t cPages = RT_ALIGN_Z(sizeof(VM), PAGE_SIZE) >> PAGE_SHIFT;
266 rc = SUPR0MemAlloc(pSession, cPages * sizeof(RTHCPHYS), (void **)&paPagesR0, &paPagesR3);
267 if (RT_SUCCESS(rc))
268 {
269 PVM pVM;
270 PVMR3 pVMR3;
271 rc = SUPR0LowAlloc(pSession, cPages, (void **)&pVM, &pVMR3, paPagesR0);
272 if (RT_SUCCESS(rc))
273 {
274 memset(pVM, 0, cPages * PAGE_SIZE);
275 pVM->enmVMState = VMSTATE_CREATING;
276 pVM->paVMPagesR3 = paPagesR3;
277 pVM->pVMR3 = pVMR3;
278 pVM->pVMR0 = pVM;
279 pVM->pSession = pSession;
280 pVM->hSelf = iHandle;
281 RTSemFastMutexRelease(pGVM->Lock);
282
283 *ppVM = pVM;
284 SUPR0Printf("GVMR0CreateVM: pVM=%p pVMR3=%p\n", pVM, pVMR3);
285 return VINF_SUCCESS;
286 }
287
288 SUPR0MemFree(pSession, (uintptr_t)paPagesR0);
289 }
290 }
291 /* else: The user wasn't permitted to create this VM. */
292
293 /*
294 * The handle will be freed by gvmR0HandleObjDestructor as we release the
295 * object reference here. A little extra mess because of non-recursive lock.
296 */
297 void *pvObj = pHandle->pvObj;
298 pHandle->pvObj = NULL;
299 RTSemFastMutexRelease(pGVM->Lock);
300
301 SUPR0ObjRelease(pvObj, pSession);
302
303 SUPR0Printf("GVMR0CreateVM: failed, rc=%d\n", rc);
304 return rc;
305 }
306
307 rc = VERR_NO_MEMORY;
308 }
309 else
310 rc = VERR_INTERNAL_ERROR;
311 }
312 else
313 rc = VERR_GVM_TOO_MANY_VMS;
314
315 RTSemFastMutexRelease(pGVM->Lock);
316 return rc;
317}
318#endif /* not used yet. */
319
320
321/**
322 * Deregistres the VM and destroys the VM structure.
323 *
324 * @returns VBox status code.
325 * @param pVM Where to store the pointer to the VM structure.
326 *
327 * @thread EMT.
328 */
329GVMR0DECL(int) GVMR0DestroyVM(PVM pVM)
330{
331 SUPR0Printf("GVMR0DestroyVM: pVM=%p\n", pVM);
332
333 PGVM pGVM = g_pGVM;
334 AssertPtrReturn(pGVM, VERR_INTERNAL_ERROR);
335
336 /*
337 * Validate the VM structure, state and caller.
338 */
339 AssertPtrReturn(pVM, VERR_INVALID_POINTER);
340 AssertReturn(!((uintptr_t)pVM & PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
341 AssertMsgReturn(pVM->enmVMState >= VMSTATE_CREATING && pVM->enmVMState <= VMSTATE_TERMINATED, ("%d\n", pVM->enmVMState), VERR_WRONG_ORDER);
342
343 uint32_t hGVM = pVM->hSelf;
344 AssertReturn(hGVM != NIL_GVM_HANDLE, VERR_INVALID_HANDLE);
345 AssertReturn(hGVM < RT_ELEMENTS(pGVM->aHandles), VERR_INVALID_HANDLE);
346
347 PGVMHANDLE pHandle = &pGVM->aHandles[hGVM];
348 AssertReturn(pHandle->hEMT != NIL_RTNATIVETHREAD, VERR_WRONG_ORDER);
349 AssertReturn(pHandle->pVM == pVM, VERR_NOT_OWNER);
350
351 RTNATIVETHREAD hSelf = RTThreadNativeSelf();
352 AssertReturn(pHandle->hEMT == hSelf, VERR_NOT_OWNER);
353
354 /*
355 * Lookup the handle and destroy the object.
356 * Since the lock isn't recursive, we have to make sure nobody can
357 * race us as we leave the lock and call SUPR0ObjRelease.
358 */
359 int rc = RTSemFastMutexRequest(pGVM->Lock);
360 AssertRC(rc);
361
362 /* be very careful here because we might be racing someone else cleaning up... */
363 if ( pHandle->pVM == pVM
364 && pHandle->hEMT == hSelf
365 && VALID_PTR(pHandle->pvObj))
366 {
367 void *pvObj = pHandle->pvObj;
368 pHandle->pvObj = NULL;
369 RTSemFastMutexRelease(pGVM->Lock);
370
371 SUPR0ObjRelease(pvObj, pVM->pSession);
372 }
373 else
374 {
375 RTSemFastMutexRelease(pGVM->Lock);
376 rc = VERR_INTERNAL_ERROR;
377 }
378
379 return rc;
380}
381
382
383#if 1 /* this approach is unsafe wrt to the freeing of pVM. Keeping it as a possible fallback for 1.5.x. */
384/**
385 * Register the specified VM with the GGVM.
386 *
387 * Permission polices and resource consumption polices may or may
388 * not be checked that this poin, be ready to deald nicely with failure.
389 *
390 * @returns VBox status code.
391 *
392 * @param pVM The VM instance data (aka handle), ring-0 mapping of ccourse.
393 * The VM::hGVM field may be updated by this call.
394 * @thread EMT.
395 */
396GVMR0DECL(int) GVMR0RegisterVM(PVM pVM)
397{
398 SUPR0Printf("GVMR0RegisterVM: pVM=%p\n", pVM);
399 PGVM pGVM = g_pGVM;
400 AssertPtrReturn(pGVM, VERR_INTERNAL_ERROR);
401
402 /*
403 * Validate the VM structure and state.
404 */
405 AssertPtrReturn(pVM, VERR_INVALID_POINTER);
406 AssertReturn(!((uintptr_t)pVM & PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
407 AssertMsgReturn(pVM->enmVMState == VMSTATE_CREATING, ("%d\n", pVM->enmVMState), VERR_WRONG_ORDER);
408
409 RTNATIVETHREAD hEMT = RTThreadNativeSelf();
410 AssertReturn(hEMT != NIL_RTNATIVETHREAD, VERR_NOT_SUPPORTED);
411
412 /*
413 * Take the lock and call the worker function.
414 */
415 int rc = RTSemFastMutexRequest(pGVM->Lock);
416 AssertRCReturn(rc, rc);
417
418 /*
419 * Allocate a handle.
420 */
421 uint16_t iHandle = pGVM->iFreeHead;
422 if (iHandle)
423 {
424 PGVMHANDLE pHandle = &pGVM->aHandles[iHandle];
425
426 /* consistency checks, a bit paranoid as always. */
427 if ( !pHandle->pVM
428 && !pHandle->pvObj
429 && pHandle->iSelf == iHandle)
430 {
431 pHandle->pvObj = SUPR0ObjRegister(pVM->pSession, SUPDRVOBJTYPE_VM, gvmR0HandleObjDestructor, pGVM, pHandle);
432 if (pHandle->pvObj)
433 {
434 /*
435 * Move the handle from the free to used list and
436 * perform permission checks.
437 */
438 pGVM->iFreeHead = pHandle->iNext;
439 pHandle->iNext = pGVM->iUsedHead;
440 pGVM->iUsedHead = iHandle;
441
442 pHandle->fFreeVM = false;
443 pHandle->pVM = pVM;
444 pHandle->pSession = pVM->pSession;
445 pHandle->hEMT = hEMT;
446
447 rc = SUPR0ObjVerifyAccess(pHandle->pvObj, pVM->pSession, NULL);
448 if (RT_SUCCESS(rc))
449 {
450 pVM->hSelf = iHandle;
451 RTSemFastMutexRelease(pGVM->Lock);
452 }
453 else
454 {
455 /*
456 * The user wasn't permitted to create this VM.
457 * Must use gvmR0HandleObjDestructor via SUPR0ObjRelease to do the
458 * cleanups. The lock isn't recursive, thus the extra mess.
459 */
460 void *pvObj = pHandle->pvObj;
461 pHandle->pvObj = NULL;
462 RTSemFastMutexRelease(pGVM->Lock);
463
464 SUPR0ObjRelease(pvObj, pVM->pSession);
465 }
466 if (RT_FAILURE(rc))
467 SUPR0Printf("GVMR0RegisterVM: permission denied, rc=%d\n", rc);
468 return rc;
469 }
470
471 rc = VERR_NO_MEMORY;
472 }
473 else
474 rc = VERR_INTERNAL_ERROR;
475 }
476 else
477 rc = VERR_GVM_TOO_MANY_VMS;
478
479 RTSemFastMutexRelease(pGVM->Lock);
480 SUPR0Printf("GVMR0RegisterVM: failed, rc=%d, iHandle=%d\n", rc, iHandle);
481 return rc;
482}
483
484
485/**
486 * Deregister a VM previously registered using the GVMR0RegisterVM API.
487 *
488 *
489 * @returns VBox status code.
490 * @param pVM The VM handle.
491 * @thread EMT.
492 */
493GVMR0DECL(int) GVMR0DeregisterVM(PVM pVM)
494{
495 SUPR0Printf("GVMR0DeregisterVM: pVM=%p\n", pVM);
496 return GVMR0DestroyVM(pVM);
497}
498#endif /* ... */
499
500
501/**
502 * Handle destructor.
503 *
504 * @param pvGVM The GVM instance pointer.
505 * @param pvHandle The handle pointer.
506 */
507static DECLCALLBACK(void) gvmR0HandleObjDestructor(void *pvObj, void *pvGVM, void *pvHandle)
508{
509 SUPR0Printf("gvmR0HandleObjDestructor: %p %p %p\n", pvObj, pvGVM, pvHandle);
510
511 /*
512 * Some quick, paranoid, input validation.
513 */
514 PGVMHANDLE pHandle = (PGVMHANDLE)pvHandle;
515 AssertPtr(pHandle);
516 PGVM pGVM = (PGVM)pvGVM;
517 Assert(pGVM == g_pGVM);
518 const uint16_t iHandle = pHandle - &pGVM->aHandles[0];
519 if ( !iHandle
520 || iHandle >= RT_ELEMENTS(pGVM->aHandles)
521 || iHandle != pHandle->iSelf)
522 {
523 SUPR0Printf("GVM: handle %d is out of range or corrupt (iSelf=%d)!\n", iHandle, pHandle->iSelf);
524 return;
525 }
526
527 int rc = RTSemFastMutexRequest(pGVM->Lock);
528 AssertRC(rc);
529
530 /*
531 * This is a tad slow but a doubly linked list is too much hazzle.
532 */
533 if (RT_UNLIKELY(pHandle->iNext >= RT_ELEMENTS(pGVM->aHandles)))
534 {
535 SUPR0Printf("GVM: used list index %d is out of range!\n", pHandle->iNext);
536 RTSemFastMutexRelease(pGVM->Lock);
537 return;
538 }
539
540 if (pGVM->iUsedHead == iHandle)
541 pGVM->iUsedHead = pHandle->iNext;
542 else
543 {
544 uint16_t iPrev = pGVM->iUsedHead;
545 int c = RT_ELEMENTS(pGVM->aHandles) + 2;
546 while (!iPrev)
547 {
548 if (RT_UNLIKELY(iPrev >= RT_ELEMENTS(pGVM->aHandles)))
549 {
550 SUPR0Printf("GVM: used list index %d is out of range!\n");
551 RTSemFastMutexRelease(pGVM->Lock);
552 return;
553 }
554 if (RT_UNLIKELY(c-- <= 0))
555 {
556 iPrev = 0;
557 break;
558 }
559
560 if (pGVM->aHandles[iPrev].iNext == iHandle)
561 break;
562 iPrev = pGVM->aHandles[iPrev].iNext;
563 }
564 if (!iPrev)
565 {
566 SUPR0Printf("GVM: can't find the handle previous previous of %d!\n", pHandle->iSelf);
567 RTSemFastMutexRelease(pGVM->Lock);
568 return;
569 }
570
571 pGVM->aHandles[iPrev].iNext = pHandle->iNext;
572 }
573 pHandle->iNext = 0;
574
575 /*
576 * Do the global cleanup round, currently only GMM.
577 * Can't trust the VM pointer unless it was allocated in ring-0...
578 */
579 PVM pVM = pHandle->pVM;
580 if ( VALID_PTR(pVM)
581 && VALID_PTR(pHandle->pSession)
582 && pHandle->fFreeVM)
583 {
584 /// @todo GMMR0CleanupVM(pVM);
585
586 /*
587 * Free the VM structure.
588 */
589 ASMAtomicXchgU32((uint32_t volatile *)&pVM->hSelf, NIL_GVM_HANDLE);
590 SUPR0MemFree(pHandle->pSession, pVM->paVMPagesR3);
591 SUPR0LowFree(pHandle->pSession, (uintptr_t)pVM);
592 }
593
594 /*
595 * Free the handle.
596 */
597 pHandle->iNext = pGVM->iFreeHead;
598 pHandle->fFreeVM = false;
599 pGVM->iFreeHead = iHandle;
600 ASMAtomicXchgPtr((void * volatile *)&pHandle->pVM, NULL);
601 ASMAtomicXchgPtr((void * volatile *)&pHandle->pvObj, NULL);
602 ASMAtomicXchgPtr((void * volatile *)&pHandle->pSession, NULL);
603 ASMAtomicXchgSize(&pHandle->hEMT, NIL_RTNATIVETHREAD);
604
605 RTSemFastMutexRelease(pGVM->Lock);
606 SUPR0Printf("gvmR0HandleObjDestructor: returns\n");
607}
608
609
610/**
611 * Lookup a VM by its global handle.
612 *
613 * @returns The VM handle on success, NULL on failure.
614 * @param hGVM The global VM handle. Asserts on bad handle.
615 */
616GVMR0DECL(PVM) GVMR0ByHandle(uint32_t hGVM)
617{
618 PGVM pGVM = g_pGVM;
619 AssertPtrReturn(pGVM, NULL);
620
621 /*
622 * Validate.
623 */
624 AssertReturn(hGVM != NIL_GVM_HANDLE, NULL);
625 AssertReturn(hGVM < RT_ELEMENTS(pGVM->aHandles), NULL);
626
627 /*
628 * Look it up.
629 */
630 AssertReturn(VALID_PTR(pGVM->aHandles[hGVM].pvObj), NULL);
631 AssertReturn(pGVM->aHandles[hGVM].hEMT != NIL_RTNATIVETHREAD, NULL);
632 Assert(VALID_PTR(pGVM->aHandles[hGVM].pVM));
633
634 return pGVM->aHandles[hGVM].pVM;
635}
636
637
638/**
639 * Looks up the VM belonging to the specified EMT thread.
640 *
641 * This is used by the assertion machinery in VMMR0.cpp to avoid causing
642 * unnecessary kernel panics when the EMT thread hits an assertion. The
643 * call may or not be an EMT thread.
644 *
645 * @returns The VM handle on success, NULL on failure.
646 * @param hEMT The native thread handle of the EMT.
647 * NIL_RTNATIVETHREAD means the current thread
648 */
649GVMR0DECL(PVM) GVMR0ByEMT(RTNATIVETHREAD hEMT)
650{
651 /*
652 * Be very careful here as we're called in AssertMsgN context.
653 */
654 PGVM pGVM = g_pGVM;
655 if (!VALID_PTR(pGVM))
656 return NULL;
657
658 if (hEMT == NIL_RTNATIVETHREAD)
659 hEMT = RTThreadNativeSelf();
660
661 /*
662 * Search the handles, we don't dare take the lock (assert).
663 */
664 for (unsigned i = 1; i < RT_ELEMENTS(pGVM->aHandles); i++)
665 if ( pGVM->aHandles[i].hEMT == hEMT
666 && pGVM->aHandles[i].iSelf == i
667 && VALID_PTR(pGVM->aHandles[i].pvObj)
668 && VALID_PTR(pGVM->aHandles[i].pVM))
669 return pGVM->aHandles[i].pVM;
670
671 return NULL;
672}
673
674
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