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