VirtualBox

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

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

GMM...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.6 KB
Line 
1/* $Id: GMMR0.cpp 5033 2007-09-26 04:48:51Z vboxsync $ */
2/** @file
3 * GMM - Global Memory 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_gmm GMM - The Global Memory Manager
21 *
22 * As the name indicates, this component is responsible for global memory
23 * management. Currently only guest RAM is allocated from the GMM, but this
24 * may change to include shadow page tables and other bits later.
25 *
26 * Guest RAM is managed as individual pages, but allocated from the host OS
27 * in chunks for reasons of portability / efficiency. To minimize the memory
28 * footprint all tracking structure must be as small as possible without
29 * unnecessary performance penalties.
30 *
31 *
32 * The allocation chunks has fixed sized, the size defined at compile time
33 * by the GMM_CHUNK_SIZE \#define.
34 *
35 * Each chunk is given an unquie ID. Each page also has a unique ID. The
36 * relation ship between the two IDs is:
37 * @verbatim
38 (idChunk << GMM_CHUNK_SHIFT) | iPage
39 @endverbatim
40 * Where GMM_CHUNK_SHIFT is log2(GMM_CHUNK_SIZE / PAGE_SIZE) and iPage is
41 * the index of the page within the chunk. This ID scheme permits for efficient
42 * chunk and page lookup, but it relies on the chunk size to be set at compile
43 * time. The chunks are organized in an AVL tree with their IDs being the keys.
44 *
45 * The physical address of each page in an allocation chunk is maintained by
46 * the RTR0MEMOBJ and obtained using RTR0MemObjGetPagePhysAddr. There is no
47 * need to duplicate this information (it'll cost 8-bytes per page if we did).
48 *
49 * So what do we need to track per page? Most importantly we need to know what
50 * state the page is in:
51 * - Private - Allocated for (eventually) backing one particular VM page.
52 * - Shared - Readonly page that is used by one or more VMs and treated
53 * as COW by PGM.
54 * - Free - Not used by anyone.
55 *
56 * For the page replacement operations (sharing, defragmenting and freeing)
57 * to be somewhat efficient, private pages needs to be associated with a
58 * particular page in a particular VM.
59 *
60 * Tracking the usage of shared pages is impractical and expensive, so we'll
61 * settle for a reference counting system instead.
62 *
63 * Free pages will be chained on LIFOs
64 *
65 * On 64-bit systems we will use a 64-bit bitfield per page, while on 32-bit
66 * systems a 32-bit bitfield will have to suffice because of address space
67 * limitations. The GMMPAGE structure shows the details.
68 *
69 *
70 * @section sec_gmm_costs Page Allocation Strategy
71 *
72 * The strategy for allocating pages has to take fragmentation and shared
73 * pages into account, or we may end up with with 2000 chunks with only
74 * a few pages in each. The fragmentation wrt shared pages is that unlike
75 * private pages they cannot easily be reallocated. Private pages can be
76 * reallocated by a defragmentation thread in the same manner that sharing
77 * is done.
78 *
79 * The first approach is to manage the free pages in two sets depending on
80 * whether they are mainly for the allocation of shared or private pages.
81 * In the initial implementation there will be almost no possibility for
82 * mixing shared and private pages in the same chunk (only if we're really
83 * stressed on memory), but when we implement forking of VMs and have to
84 * deal with lots of COW pages it'll start getting kind of interesting.
85 *
86 * The sets are lists of chunks with approximately the same number of
87 * free pages. Say the chunk size is 1MB, meaning 256 pages, and a set
88 * consists of 16 lists. So, the first list will contain the chunks with
89 * 1-7 free pages, the second covers 8-15, and so on. The chunks will be
90 * moved between the lists as pages are freed up or allocated.
91 *
92 *
93 * @section sec_gmm_costs Costs
94 *
95 * The per page cost in kernel space is 32-bit plus whatever RTR0MEMOBJ
96 * entails. In addition there is the chunk cost of approximately
97 * (sizeof(RT0MEMOBJ) + sizof(CHUNK)) / 2^CHUNK_SHIFT bytes per page.
98 *
99 * On Windows the per page RTR0MEMOBJ cost is 32-bit on 32-bit windows
100 * and 64-bit on 64-bit windows (a PFN_NUMBER in the MDL). So, 64-bit per page.
101 * The cost on Linux is identical, but here it's because of sizeof(struct page *).
102 *
103 *
104 * @section sec_gmm_legacy Legacy Mode for Non-Tier-1 Platforms
105 *
106 * In legacy mode the page source is locked user pages and not
107 * RTR0MemObjAllocPhysNC, this means that a page can only be allocated
108 * by the VM that locked it. We will make no attempt at implementing
109 * page sharing on these systems, just do enough to make it all work.
110 *
111 *
112 * @subsection sub_gmm_locking Serializing
113 *
114 * One simple fast mutex will be employed in the initial implementation, not
115 * two as metioned in @ref subsec_pgmPhys_Serializing.
116 *
117 * @see subsec_pgmPhys_Serializing
118 *
119 *
120 * @section sec_gmm_overcommit Memory Over-Commitment Management
121 *
122 * The GVM will have to do the system wide memory over-commitment
123 * management. My current ideas are:
124 * - Per VM oc policy that indicates how much to initially commit
125 * to it and what to do in a out-of-memory situation.
126 * - Prevent overtaxing the host.
127 *
128 * There are some challenges here, the main ones are configurability and
129 * security. Should we for instance permit anyone to request 100% memory
130 * commitment? Who should be allowed to do runtime adjustments of the
131 * config. And how to prevent these settings from being lost when the last
132 * VM process exits? The solution is probably to have an optional root
133 * daemon the will keep VMMR0.r0 in memory and enable the security measures.
134 *
135 * This will not be implemented this week. :-)
136 *
137 */
138
139
140/*******************************************************************************
141* Header Files *
142*******************************************************************************/
143#define LOG_GROUP LOG_GROUP_GMM
144#include <VBox/gmm.h>
145#include "GMMR0Internal.h"
146#include <VBox/gvm.h>
147#include <VBox/log.h>
148#include <VBox/param.h>
149#include <iprt/avl.h>
150#include <iprt/mem.h>
151#include <iprt/memobj.h>
152#include <iprt/semaphore.h>
153#include <iprt/string.h>
154
155
156/*******************************************************************************
157* Structures and Typedefs *
158*******************************************************************************/
159/**
160 * The per-page tracking structure employed by the GMM.
161 *
162 * On 32-bit hosts we'll some trickery is necessary to compress all
163 * the information into 32-bits. When the fSharedFree member is set,
164 * the 30th bit decides whether it's a free page or not.
165 *
166 * Because of the different layout on 32-bit and 64-bit hosts, macros
167 * are used to get and set some of the data.
168 */
169typedef union GMMPAGE
170{
171#if HC_ARCH_BITS == 64
172 /** Unsigned integer view. */
173 uint64_t u;
174
175 /** The common view. */
176 struct GMMPAGECOMMON
177 {
178 uint32_t uStuff1 : 32;
179 uint32_t uStuff2 : 20;
180 /** The page state. */
181 uint32_t u2State : 2;
182 } Common;
183
184 /** The view of a private page. */
185 struct GMMPAGEPRIVATE
186 {
187 /** The guest page frame number. (Max addressable: 2 ^ 44) */
188 uint32_t pfn;
189 /** The GVM handle. (64K VMs) */
190 uint32_t hGVM : 16;
191 /** Reserved. */
192 uint32_t u16Reserved : 14;
193 /** The page state. */
194 uint32_t u2State : 2;
195 } Private;
196
197 /** The view of a shared page. */
198 struct GMMPAGESHARED
199 {
200 /** The reference count. */
201 uint32_t cRefs;
202 /** Reserved. Checksum or something? Two hGVMs for forking? */
203 uint32_t u30Reserved : 30;
204 /** The page state. */
205 uint32_t u2State : 2;
206 } Shared;
207
208 /** The view of a free page. */
209 struct GMMPAGEFREE
210 {
211 /** The id of the next page in the free list. */
212 uint32_t idNext;
213 /** Reserved. Checksum or something? */
214 uint32_t u30Reserved : 30;
215 /** The page state. */
216 uint32_t u2State : 2;
217 } Free;
218
219#else /* 32-bit */
220 /** The common view. */
221 struct GMMPAGECOMMON
222 {
223 uint32_t uStuff : 30;
224 /** The page state. */
225 uint32_t u2State : 2;
226 } Common;
227
228 /** The view of a private page. */
229 struct GMMPAGEPRIVATE
230 {
231 /** The guest page frame number. (Max addressable: 2 ^ 36) */
232 uint32_t pfn : 24;
233 /** The GVM handle. (127 VMs) */
234 uint32_t hGVM : 7;
235 /** The top page state bit, MBZ. */
236 uint32_t fZero : 1;
237 } Private;
238
239 /** The view of a shared page. */
240 struct GMMPAGESHARED
241 {
242 /** The reference count. */
243 uint32_t cRefs : 30;
244 /** The page state. */
245 uint32_t u2State : 2;
246 } Shared;
247
248 /** The view of a free page. */
249 struct GMMPAGEFREE
250 {
251 /** The id of the next page in the free list. */
252 uint32_t idNext;
253 /** Reserved. Checksum or something? */
254 uint32_t u30Reserved : 30;
255 /** The page state. */
256 uint32_t u2State : 2;
257 } Free;
258#endif
259} GMMPAGE;
260/** Pointer to a GMMPAGE. */
261typedef GMMPAGE *PGMMPAGE;
262
263
264/** @name The Page States.
265 * @{ */
266/** A private page. */
267#define GMM_PAGE_STATE_PRIVATE 0
268/** A private page - alternative value used on the 32-bit implemenation.
269 * This will never be used on 64-bit hosts. */
270#define GMM_PAGE_STATE_PRIVATE_32 1
271/** A shared page. */
272#define GMM_PAGE_STATE_SHARED 2
273/** A free page. */
274#define GMM_PAGE_STATE_FREE 3
275/** @} */
276
277
278/** @def GMMPAGE_IS_PRIVATE
279 *
280 * @returns true if free, false if not.
281 * @param pPage The GMM page.
282 */
283#if HC_ARCH_BITS == 64
284# define GMM_PAGE_IS_PRIVATE(pPage) ( (pPage)->Common.u2State == GMM_PAGE_STATE_PRIVATE )
285#else
286# define GMM_PAGE_IS_PRIVATE(pPage) ( (pPage)->Private.fZero == 0 )
287#endif
288
289/** @def GMMPAGE_IS_FREE
290 *
291 * @returns true if free, false if not.
292 * @param pPage The GMM page.
293 */
294#define GMM_PAGE_IS_SHARED(pPage) ( (pPage)->Common.u2State == GMM_PAGE_STATE_SHARED )
295
296/** @def GMMPAGE_IS_FREE
297 *
298 * @returns true if free, false if not.
299 * @param pPage The GMM page.
300 */
301#define GMM_PAGE_IS_FREE(pPage) ( (pPage)->Common.u2State == GMM_PAGE_STATE_FREE )
302
303
304/**
305 * A GMM allocation chunk ring-3 mapping record.
306 *
307 * This should really be associated with a session and not a VM, but
308 * it's simpler to associated with a VM and cleanup with the VM object
309 * is destroyed.
310 */
311typedef struct GMMCHUNKMAP
312{
313 /** The mapping object. */
314 RTR0MEMOBJ MapObj;
315 /** The VM owning the mapping. */
316 PVM pVM;
317} GMMCHUNKMAP;
318/** Pointer to a GMM allocation chunk mapping. */
319typedef struct GMMCHUNKMAP *PGMMCHUNKMAP;
320
321
322/** Pointer to a GMM allocation chunk. */
323typedef struct GMMCHUNK *PGMMCHUNK;
324
325/**
326 * A GMM allocation chunk.
327 */
328typedef struct GMMCHUNK
329{
330 /** The AVL node core.
331 * The Key is the chunk ID. */
332 AVLU32NODECORE Core;
333 /** The memory object.
334 * This is either a */
335 RTR0MEMOBJ MemObj;
336 /** Pointer to the next chunk in the free list. */
337 PGMMCHUNK pFreeNext;
338 /** Pointer to the previous chunk in the free list. */
339 PGMMCHUNK pFreePrev;
340 /** Pointer to an array of mappings. */
341 PGMMCHUNKMAP paMappings;
342 /** The number of mappings. */
343 uint16_t cMappings;
344 /** The head of the list of free pages. */
345 uint16_t idFreeHead;
346 /** The number of free pages. */
347 uint16_t cFree;
348 /** The GVM handle of the VM that first allocated pages from this chunk, this
349 * is used as a preference when there are several chunks to choose from.
350 * When in legacy mode this isn't a preference any longer. */
351 uint16_t hGVM;
352 /** The number of private pages. */
353 uint16_t cPrivate;
354 /** The number of shared pages. */
355 uint16_t cShared;
356 /** Reserved for later. */
357 uint16_t au16Reserved;
358 /** The pages. */
359 GMMPAGE aPages[GMM_CHUNK_SIZE >> PAGE_SHIFT];
360} GMMCHUNK;
361
362
363/**
364 * An allocation chunk TLB entry.
365 */
366typedef struct GMMCHUNKTLBE
367{
368 /** The chunk id. */
369 uint32_t idChunk;
370 /** Pointer to the chunk. */
371 PGMMCHUNK pChunk;
372} GMMCHUNKTLBE;
373/** Pointer to an allocation chunk TLB entry. */
374typedef GMMCHUNKTLBE *PGMMCHUNKTLBE;
375
376
377/**
378 * An allocation chunk TLB.
379 */
380typedef struct GMMCHUNKTLB
381{
382 /** The TLB entries. */
383 GMMCHUNKTLBE aEntries[32];
384} GMMCHUNKTLB;
385/** Pointer to an allocation chunk TLB. */
386typedef GMMCHUNKTLB *PGMMCHUNKTLB;
387
388
389/**
390 * A set of free chunks.
391 */
392typedef struct GMMCHUNKFREESET
393{
394 /** The number of free pages in the set. */
395 uint64_t cPages;
396 /** */
397 PGMMCHUNK apLists[16];
398} GMMCHUNKFREESET;
399/** Pointer to set of free chunks. */
400typedef GMMCHUNKFREESET *PGMMCHUNKFREESET;
401
402
403/**
404 * The GMM instance data.
405 */
406typedef struct GMM
407{
408 /** Magic / eye catcher. GMM_MAGIC */
409 uint32_t u32Magic;
410 /** The fast mutex protecting the GMM.
411 * More fine grained locking can be implemented later if necessary. */
412 RTSEMFASTMUTEX Mtx;
413 /** The chunk tree. */
414 PAVLU32NODECORE pChunks;
415 /** The chunk TLB. */
416 GMMCHUNKTLB ChunkTLB;
417 /** The private free set. */
418 GMMCHUNKFREESET Private;
419 /** The shared free set. */
420 GMMCHUNKFREESET Shared;
421
422 /** The number of allocated pages. */
423 uint64_t cPages;
424 /** The legacy mode indicator.
425 * This is determined at initialization time. */
426 bool fLegacyMode;
427 /** The number of active VMs. */
428 uint16_t cActiveVMs;
429} GMM;
430/** Pointer to the GMM instance. */
431typedef GMM *PGMM;
432
433/** The value of GMM::u32Magic (Katsuhiro Otomo). */
434#define GMM_MAGIC 0x19540414
435
436
437/*******************************************************************************
438* Global Variables *
439*******************************************************************************/
440/** Pointer to the GMM instance data. */
441static PGMM g_pGMM = NULL;
442
443/** Macro for obtaining and validating the g_pGMM pointer.
444 * On failure it will return from the invoking function with the specified return value.
445 *
446 * @param pGMM The name of the pGMM variable.
447 * @param rc The return value on failure. Use VERR_INTERNAL_ERROR for
448 * VBox status codes.
449 */
450#define GMM_GET_VALID_INSTANCE(pGMM, rc) \
451 do { \
452 (pGMM) = g_pGMM; \
453 AssertPtrReturn((pGMM), (rc)); \
454 AssertMsgReturn((pGMM)->u32Magic == GMM_MAGIC, ("%p - %#x\n", (pGMM), (pGMM)->u32Magic), (rc)); \
455 } while (0)
456
457/** Macro for obtaining and validating the g_pGMM pointer, void function variant.
458 * On failure it will return from the invoking function.
459 *
460 * @param pGMM The name of the pGMM variable.
461 */
462#define GMM_GET_VALID_INSTANCE_VOID(pGMM) \
463 do { \
464 (pGMM) = g_pGMM; \
465 AssertPtrReturnVoid((pGMM)); \
466 AssertMsgReturnVoid((pGMM)->u32Magic == GMM_MAGIC, ("%p - %#x\n", (pGMM), (pGMM)->u32Magic)); \
467 } while (0)
468
469
470/*******************************************************************************
471* Internal Functions *
472*******************************************************************************/
473static DECLCALLBACK(int) gmmR0TermDestroyChunk(PAVLU32NODECORE pNode, void *pvGMM);
474static DECLCALLBACK(int) gmmR0FreeVMPagesInChunk(PAVLU32NODECORE pNode, void *pvhGVM);
475
476
477
478/**
479 * Initializes the GMM component.
480 *
481 * This is called when the VMMR0.r0 module is loaded and protected by the
482 * loader semaphore.
483 *
484 * @returns VBox status code.
485 */
486GMMR0DECL(int) GMMR0Init(void)
487{
488 LogFlow(("GMMInit:\n"));
489
490 /*
491 * Allocate the instance data and the lock(s).
492 */
493 PGMM pGMM = (PGMM)RTMemAllocZ(sizeof(*pGMM));
494 if (!pGMM)
495 return VERR_NO_MEMORY;
496 pGMM->u32Magic = GMM_MAGIC;
497 for (unsigned i = 0; i < RT_ELEMENTS(pGMM->ChunkTLB.aEntries); i++)
498 pGMM->ChunkTLB.aEntries[i].idChunk = NIL_GMM_CHUNKID;
499
500 int rc = RTSemFastMutexCreate(&pGMM->Mtx);
501 if (RT_SUCCESS(rc))
502 {
503 /*
504 * Check and see if RTR0MemObjAllocPhysNC works.
505 */
506 RTR0MEMOBJ MemObj;
507 rc = RTR0MemObjAllocPhysNC(&MemObj, _64K, NIL_RTHCPHYS);
508 if (RT_SUCCESS(rc))
509 {
510 rc = RTR0MemObjFree(MemObj, true);
511 AssertRC(rc);
512 }
513 else if (rc == VERR_NOT_SUPPORTED)
514 pGMM->fLegacyMode = true;
515 else
516 SUPR0Printf("GMMR0Init: RTR0MemObjAllocPhysNC(,64K,Any) -> %d!\n", rc);
517
518 g_pGMM = pGMM;
519 LogFlow(("GMMInit: pGMM=%p fLegacy=%RTbool\n", pGMM, pGMM->fLegacyMode));
520 return VINF_SUCCESS;
521 }
522
523 RTMemFree(pGMM);
524 SUPR0Printf("GMMR0Init: failed! rc=%d\n", rc);
525 return rc;
526}
527
528
529/**
530 * Terminates the GMM component.
531 */
532GMMR0DECL(void) GMMR0Term(void)
533{
534 LogFlow(("GMMTerm:\n"));
535
536 /*
537 * Take care / be paranoid...
538 */
539 PGMM pGMM = g_pGMM;
540 if (!VALID_PTR(pGMM))
541 return;
542 if (pGMM->u32Magic != GMM_MAGIC)
543 {
544 SUPR0Printf("GMMR0Term: u32Magic=%#x\n", pGMM->u32Magic);
545 return;
546 }
547
548 /*
549 * Undo what init did and free any resources we've acquired.
550 */
551 /* Destroy the fundamentals. */
552 g_pGMM = NULL;
553 pGMM->u32Magic++;
554 RTSemFastMutexDestroy(pGMM->Mtx);
555 pGMM->Mtx = NIL_RTSEMFASTMUTEX;
556
557 /* free any chunks still hanging around. */
558 RTAvlU32Destroy(&pGMM->pChunks, gmmR0TermDestroyChunk, pGMM);
559
560 /* finally the instance data itself. */
561 RTMemFree(pGMM);
562 LogFlow(("GMMTerm: done\n"));
563}
564
565
566/**
567 * RTAvlU32Destroy callback.
568 *
569 * @returns 0
570 * @param pNode The node to destroy.
571 * @param pvGMM The GMM handle.
572 */
573static DECLCALLBACK(int) gmmR0TermDestroyChunk(PAVLU32NODECORE pNode, void *pvGMM)
574{
575 PGMMCHUNK pChunk = (PGMMCHUNK)pNode;
576
577 if (pChunk->cFree != (GMM_CHUNK_SIZE >> PAGE_SHIFT))
578 SUPR0Printf("GMMR0Term: %p/%#x: cFree=%d cPrivate=%d cShared=%d cMappings=%d\n", pChunk,
579 pChunk->Core.Key, pChunk->cFree, pChunk->cPrivate, pChunk->cShared, pChunk->cMappings);
580
581 int rc = RTR0MemObjFree(pChunk->MemObj, true /* fFreeMappings */);
582 if (RT_FAILURE(rc))
583 {
584 SUPR0Printf("GMMR0Term: %p/%#x: RTRMemObjFree(%p,true) -> %d (cMappings=%d)\n", pChunk,
585 pChunk->Core.Key, pChunk->MemObj, rc, pChunk->cMappings);
586 AssertRC(rc);
587 }
588 pChunk->MemObj = NIL_RTR0MEMOBJ;
589
590 RTMemFree(pChunk->paMappings);
591 pChunk->paMappings = NULL;
592
593 RTMemFree(pChunk);
594 NOREF(pvGMM);
595 return 0;
596}
597
598
599/**
600 * Initializes the per-VM data for the GMM.
601 *
602 * @param pGVM Pointer to the Global VM structure.
603 */
604GMMR0DECL(void) GMMR0InitPerVMData(PGVM pGVM)
605{
606 pGVM->gmm.s.cRAMPages = 0;
607 pGVM->gmm.s.cPrivatePages = 0;
608 pGVM->gmm.s.cSharedPages = 0;
609 pGVM->gmm.s.enmPolicy = GMMOCPOLICY_TBD;
610 pGVM->gmm.s.enmPriority = GMMPRORITY_NORMAL;
611}
612
613
614/**
615 * Cleans up when a VM is terminating.
616 *
617 * @param pGVM Pointer to the Global VM structure.
618 */
619GMMR0DECL(void) GMMR0CleanupVM(PGVM pGVM)
620{
621 LogFlow(("GMMR0CleanupVM: pGVM=%p:{.pVM=%p, .hSelf=%#x}\n", pGVM, pGVM->pVM, pGVM->hSelf));
622
623 PGMM pGMM;
624 GMM_GET_VALID_INSTANCE_VOID(pGMM);
625
626 int rc = RTSemFastMutexRequest(pGMM->Mtx);
627 AssertRC(rc);
628
629 /*
630 * If it's the last VM around, we can skip walking all the chunk looking
631 * for the pages owned by this VM and instead flush the whole shebang.
632 *
633 * This takes care of the eventuality that a VM has left shared page
634 * references behind (shouldn't happen of course, but you never know).
635 */
636 if (pGMM->cActiveVMs == 1)
637 {
638
639 }
640 else if (pGVM->gmm.s.cPrivatePages)
641 {
642 /*
643 * Walk the entire pool looking for pages that belongs to this VM.
644 * This is slow but necessary. Of course it won't work for shared
645 * pages, but we'll deal with that later.
646 */
647 RTAvlU32DoWithAll(&pGMM->pChunks, true /* fFromLeft */, gmmR0FreeVMPagesInChunk, (void *)pGVM->hSelf);
648
649 /*
650 * Update over-commitment management and free chunks that are no
651 * longer needed.
652 */
653
654 }
655
656 RTSemFastMutexRelease(pGMM->Mtx);
657
658 /* trash the data */
659 pGVM->gmm.s.cRAMPages = 0;
660 pGVM->gmm.s.cPrivatePages = 0;
661 pGVM->gmm.s.cSharedPages = 0;
662 pGVM->gmm.s.enmPolicy = GMMOCPOLICY_INVALID;
663 pGVM->gmm.s.enmPriority = GMMPRORITY_INVALID;
664
665 LogFlow(("GMMR0CleanupVM: returns\n"));
666}
667
668
669/**
670 * RTAvlU32DoWithAll callback.
671 *
672 * @returns 0
673 * @param pNode The node to destroy.
674 * @param pvhGVM The GVM::hSelf value.
675 */
676static DECLCALLBACK(int) gmmR0FreeVMPagesInChunk(PAVLU32NODECORE pNode, void *pvhGVM)
677{
678 PGMMCHUNK pChunk = (PGMMCHUNK)pNode;
679 uint16_t hGVM = (uintptr_t)pvhGVM;
680
681#ifndef VBOx_STRICT
682 if (pChunk->cFree != (GMM_CHUNK_SIZE >> PAGE_SHIFT))
683#endif
684 {
685 /*
686 * Perform some internal checks while we're scanning.
687 */
688 unsigned cPrivate = 0;
689 unsigned cShared = 0;
690 unsigned cFree = 0;
691
692 unsigned iPage = (GMM_CHUNK_SIZE >> PAGE_SHIFT);
693 while (iPage-- > 0)
694 if (GMM_PAGE_IS_PRIVATE(&pChunk->aPages[iPage]))
695
696 {
697 if (pChunk->aPages[iPage].Private.hGVM == hGVM)
698 {
699 /* Free it. */
700 pChunk->aPages[iPage].u = 0;
701 pChunk->aPages[iPage].Free.idNext = pChunk->idFreeHead;
702 pChunk->aPages[iPage].Free.u2State = GMM_PAGE_STATE_FREE;
703 pChunk->idFreeHead = iPage;
704 pChunk->cPrivate--;
705 pChunk->cFree++;
706 cFree++;
707 }
708 else
709 cPrivate++;
710 }
711 else if (GMM_PAGE_IS_FREE(&pChunk->aPages[iPage]))
712 cFree++;
713 else
714 cShared++;
715
716 /*
717 * Did it add up?
718 */
719 if (RT_UNLIKELY( pChunk->cFree != cFree
720 || pChunk->cPrivate != cPrivate
721 || pChunk->cShared != cShared))
722 {
723 SUPR0Printf("GMM: Chunk %p/%#x has bogus stats - free=%d/%d private=%d/%d shared=%d/%d\n",
724 pChunk->cFree, cFree, pChunk->cPrivate, cPrivate, pChunk->cShared, cShared);
725 pChunk->cFree = cFree;
726 pChunk->cPrivate = cPrivate;
727 pChunk->cShared = cShared;
728 }
729 }
730
731 return 0;
732}
733
734
735
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