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 | */
|
---|
57 | typedef 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. */
|
---|
76 | typedef GVMHANDLE *PGVMHANDLE;
|
---|
77 |
|
---|
78 | /**
|
---|
79 | * The GVM instance data.
|
---|
80 | */
|
---|
81 | typedef 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. */
|
---|
97 | typedef 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.) */
|
---|
109 | static PGVM g_pGVM = NULL;
|
---|
110 |
|
---|
111 |
|
---|
112 | /*******************************************************************************
|
---|
113 | * Internal Functions *
|
---|
114 | *******************************************************************************/
|
---|
115 | static 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 | */
|
---|
125 | GVMR0DECL(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 | */
|
---|
175 | GVMR0DECL(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 | */
|
---|
211 | GVMR0DECL(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 | */
|
---|
329 | GVMR0DECL(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 | */
|
---|
396 | GVMR0DECL(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 | */
|
---|
493 | GVMR0DECL(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 | */
|
---|
507 | static 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 | */
|
---|
616 | GVMR0DECL(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 | */
|
---|
649 | GVMR0DECL(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 |
|
---|