GMMR0.cpp revision d7ebb3a3e04be876a93b7c234718fa8adcbc5a04
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * GMM - Global Memory Manager.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * Copyright (C) 2007 Oracle Corporation
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * available from http://www.virtualbox.org. This file is free software;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * General Public License (GPL) as published by the Free Software
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @page pg_gmm GMM - The Global Memory Manager
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * As the name indicates, this component is responsible for global memory
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * management. Currently only guest RAM is allocated from the GMM, but this
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * may change to include shadow page tables and other bits later.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Guest RAM is managed as individual pages, but allocated from the host OS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * in chunks for reasons of portability / efficiency. To minimize the memory
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * footprint all tracking structure must be as small as possible without
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * unnecessary performance penalties.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * The allocation chunks has fixed sized, the size defined at compile time
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * by the #GMM_CHUNK_SIZE \#define.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Each chunk is given an unquie ID. Each page also has a unique ID. The
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * relation ship between the two IDs is:
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * GMM_CHUNK_SHIFT = log2(GMM_CHUNK_SIZE / PAGE_SIZE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * idPage = (idChunk << GMM_CHUNK_SHIFT) | iPage;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Where iPage is the index of the page within the chunk. This ID scheme
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * permits for efficient chunk and page lookup, but it relies on the chunk size
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * to be set at compile time. The chunks are organized in an AVL tree with their
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * IDs being the keys.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * The physical address of each page in an allocation chunk is maintained by
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * the #RTR0MEMOBJ and obtained using #RTR0MemObjGetPagePhysAddr. There is no
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * need to duplicate this information (it'll cost 8-bytes per page if we did).
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * So what do we need to track per page? Most importantly we need to know
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * which state the page is in:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * - Private - Allocated for (eventually) backing one particular VM page.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * - Shared - Readonly page that is used by one or more VMs and treated
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * as COW by PGM.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * - Free - Not used by anyone.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * For the page replacement operations (sharing, defragmenting and freeing)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * to be somewhat efficient, private pages needs to be associated with a
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * particular page in a particular VM.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Tracking the usage of shared pages is impractical and expensive, so we'll
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * settle for a reference counting system instead.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Free pages will be chained on LIFOs
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * On 64-bit systems we will use a 64-bit bitfield per page, while on 32-bit
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * systems a 32-bit bitfield will have to suffice because of address space
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * limitations. The #GMMPAGE structure shows the details.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @section sec_gmm_alloc_strat Page Allocation Strategy
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The strategy for allocating pages has to take fragmentation and shared
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * pages into account, or we may end up with with 2000 chunks with only
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * a few pages in each. Shared pages cannot easily be reallocated because
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * of the inaccurate usage accounting (see above). Private pages can be
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * reallocated by a defragmentation thread in the same manner that sharing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The first approach is to manage the free pages in two sets depending on
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * whether they are mainly for the allocation of shared or private pages.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * In the initial implementation there will be almost no possibility for
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * mixing shared and private pages in the same chunk (only if we're really
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * stressed on memory), but when we implement forking of VMs and have to
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * deal with lots of COW pages it'll start getting kind of interesting.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * The sets are lists of chunks with approximately the same number of
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * free pages. Say the chunk size is 1MB, meaning 256 pages, and a set
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * consists of 16 lists. So, the first list will contain the chunks with
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * 1-7 free pages, the second covers 8-15, and so on. The chunks will be
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * moved between the lists as pages are freed up or allocated.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @section sec_gmm_costs Costs
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * The per page cost in kernel space is 32-bit plus whatever RTR0MEMOBJ
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * entails. In addition there is the chunk cost of approximately
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * (sizeof(RT0MEMOBJ) + sizof(CHUNK)) / 2^CHUNK_SHIFT bytes per page.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * On Windows the per page #RTR0MEMOBJ cost is 32-bit on 32-bit windows
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * and 64-bit on 64-bit windows (a PFN_NUMBER in the MDL). So, 64-bit per page.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The cost on Linux is identical, but here it's because of sizeof(struct page *).
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync * @section sec_gmm_legacy Legacy Mode for Non-Tier-1 Platforms
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * In legacy mode the page source is locked user pages and not
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * #RTR0MemObjAllocPhysNC, this means that a page can only be allocated
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * by the VM that locked it. We will make no attempt at implementing
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * page sharing on these systems, just do enough to make it all work.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * @subsection sub_gmm_locking Serializing
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * One simple fast mutex will be employed in the initial implementation, not
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * two as metioned in @ref subsec_pgmPhys_Serializing.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * @see @ref subsec_pgmPhys_Serializing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @section sec_gmm_overcommit Memory Over-Commitment Management
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * The GVM will have to do the system wide memory over-commitment
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * management. My current ideas are:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * - Per VM oc policy that indicates how much to initially commit
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * to it and what to do in a out-of-memory situation.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * - Prevent overtaxing the host.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * There are some challenges here, the main ones are configurability and
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * security. Should we for instance permit anyone to request 100% memory
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * commitment? Who should be allowed to do runtime adjustments of the
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * config. And how to prevent these settings from being lost when the last
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * VM process exits? The solution is probably to have an optional root
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * daemon the will keep VMMR0.r0 in memory and enable the security measures.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * @section sec_gmm_numa NUMA
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * NUMA considerations will be designed and implemented a bit later.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * The preliminary guesses is that we will have to try allocate memory as
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * close as possible to the CPUs the VM is executed on (EMT and additional CPU
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * threads). Which means it's mostly about allocation and sharing policies.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Both the scheduler and allocator interface will to supply some NUMA info
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * and we'll need to have a way to calc access costs.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/*******************************************************************************
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync* Header Files *
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync*******************************************************************************/
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/*******************************************************************************
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync* Structures and Typedefs *
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to set of free chunks. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/** Pointer to a GMM allocation chunk. */
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync * The per-page tracking structure employed by the GMM.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * On 32-bit hosts we'll some trickery is necessary to compress all
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * the information into 32-bits. When the fSharedFree member is set,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * the 30th bit decides whether it's a free page or not.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * Because of the different layout on 32-bit and 64-bit hosts, macros
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * are used to get and set some of the data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef union GMMPAGE
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** Unsigned integer view. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The common view. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The page state. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The view of a private page. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The guest page frame number. (Max addressable: 2 ^ 44 - 16) */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The GVM handle. (64K VMs) */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** Reserved. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The page state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The view of a shared page. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The host page frame number. (Max addressable: 2 ^ 44 - 16) */
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync /** The reference count (64K VMs). */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Reserved. Checksum or something? Two hGVMs for forking? */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The page state. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The view of a free page. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The index of the next page in the free list. UINT16_MAX is NIL. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** Reserved. Checksum or something? */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Reserved. Checksum or something? */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The page state. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync#else /* 32-bit */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** Unsigned integer view. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The common view. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The page state. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The view of a private page. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The guest page frame number. (Max addressable: 2 ^ 36) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The GVM handle. (127 VMs) */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The top page state bit, MBZ. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The view of a shared page. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The reference count. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The page state. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The view of a free page. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The index of the next page in the free list. UINT16_MAX is NIL. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** Reserved. Checksum or something? */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The page state. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/** Pointer to a GMMPAGE. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @name The Page States.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/** A private page. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** A private page - alternative value used on the 32-bit implemenation.
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync * This will never be used on 64-bit hosts. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync/** A shared page. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync/** A free page. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync/** @def GMM_PAGE_IS_PRIVATE
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync * @returns true if private, false if not.
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync * @param pPage The GMM page.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define GMM_PAGE_IS_PRIVATE(pPage) ( (pPage)->Common.u2State == GMM_PAGE_STATE_PRIVATE )
0c4004948fca34f2db87e7b38013137e9472c306vboxsync# define GMM_PAGE_IS_PRIVATE(pPage) ( (pPage)->Private.fZero == 0 )
0c4004948fca34f2db87e7b38013137e9472c306vboxsync/** @def GMM_PAGE_IS_SHARED
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * @returns true if shared, false if not.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * @param pPage The GMM page.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define GMM_PAGE_IS_SHARED(pPage) ( (pPage)->Common.u2State == GMM_PAGE_STATE_SHARED )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @def GMM_PAGE_IS_FREE
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns true if free, false if not.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pPage The GMM page.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define GMM_PAGE_IS_FREE(pPage) ( (pPage)->Common.u2State == GMM_PAGE_STATE_FREE )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @def GMM_PAGE_PFN_LAST
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The last valid guest pfn range.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @remark Some of the values outside the range has special meaning,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * see GMM_PAGE_PFN_UNSHAREABLE.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncAssertCompile(GMM_PAGE_PFN_LAST == (GMM_GCPHYS_LAST >> PAGE_SHIFT));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @def GMM_PAGE_PFN_UNSHAREABLE
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Indicates that this page isn't used for normal guest memory and thus isn't shareable.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define GMM_PAGE_PFN_UNSHAREABLE UINT32_C(0xfffffff1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define GMM_PAGE_PFN_UNSHAREABLE UINT32_C(0x00fffff1)
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsyncAssertCompile(GMM_PAGE_PFN_UNSHAREABLE == (GMM_GCPHYS_UNSHAREABLE >> PAGE_SHIFT));
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * A GMM allocation chunk ring-3 mapping record.
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * This should really be associated with a session and not a VM, but
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * it's simpler to associated with a VM and cleanup with the VM object
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * is destroyed.
8a339f91959bb7a3315b51a23461b68c7b0cb50evboxsynctypedef struct GMMCHUNKMAP
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /** The mapping object. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /** The VM owning the mapping. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync/** Pointer to a GMM allocation chunk mapping. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GMMCHUNKTYPE_CONTINUOUS = 2, /* one 2 MB continuous physical range. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * A GMM allocation chunk.
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsynctypedef struct GMMCHUNK
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync /** The AVL node core.
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync * The Key is the chunk ID. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /** The memory object.
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * Either from RTR0MemObjAllocPhysNC or RTR0MemObjLockUser depending on
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * what the host can dish up with. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the next chunk in the free list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the previous chunk in the free list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the free set this chunk belongs to. NULL for
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * chunks with no free pages. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to an array of mappings. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The number of mappings. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The head of the list of free pages. UINT16_MAX is the NIL value. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The number of free pages. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The GVM handle of the VM that first allocated pages from this chunk, this
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * is used as a preference when there are several chunks to choose from.
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * When in bound memory mode this isn't a preference any longer. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The number of private pages. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** The number of shared pages. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** Chunk type */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The pages. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * An allocation chunk TLB entry.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsynctypedef struct GMMCHUNKTLBE
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** The chunk id. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the chunk. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/** Pointer to an allocation chunk TLB entry. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/** The number of entries tin the allocation chunk TLB. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Gets the TLB entry index for the given Chunk ID. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define GMM_CHUNKTLB_IDX(idChunk) ( (idChunk) & (GMM_CHUNKTLB_ENTRIES - 1) )
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * An allocation chunk TLB.
0c4004948fca34f2db87e7b38013137e9472c306vboxsynctypedef struct GMMCHUNKTLB
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The TLB entries. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync/** Pointer to an allocation chunk TLB. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync/** The GMMCHUNK::cFree shift count. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync/** The GMMCHUNK::cFree mask for use when considering relinking a chunk. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync/** The number of lists in set. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync#define GMM_CHUNK_FREE_SET_LISTS (GMM_CHUNK_NUM_PAGES >> GMM_CHUNK_FREE_SET_SHIFT)
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * A set of free chunks.
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /** The number of free pages in the set. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** Chunks ordered by increasing number of free pages. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * The GMM instance data.
0c4004948fca34f2db87e7b38013137e9472c306vboxsynctypedef struct GMM
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** Magic / eye catcher. GMM_MAGIC */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The fast mutex protecting the GMM.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * More fine grained locking can be implemented later if necessary. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The chunk tree. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The chunk TLB. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The private free set. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The shared free set. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /** Shared module tree (global). */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /** todo seperate trees for distinctly different guest OSes. */
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /** The maximum number of pages we're allowed to allocate.
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * @gcfgm 64-bit GMM/MaxPages Direct.
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * @gcfgm 32-bit GMM/PctPages Relative to the number of host pages. */
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /** The number of pages that has been reserved.
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * The deal is that cReservedPages - cOverCommittedPages <= cMaxPages. */
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /** The number of pages that we have over-committed in reservations. */
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /** The number of actually allocated (committed if you like) pages. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The number of pages that are shared. A subset of cAllocatedPages. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The number of pages that are shared that has been left behind by
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * VMs not doing proper cleanups. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The number of allocation chunks.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * (The number of pages we've allocated from the host can be derived from this.) */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The number of current ballooned pages. */
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /** The legacy allocation mode indicator.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * This is determined at initialization time. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The bound memory mode indicator.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * When set, the memory will be bound to a specific VM and never
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * shared. This is always set if fLegacyAllocationMode is set.
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * (Also determined at initialization time.) */
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /** The number of registered VMs. */
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /** The previous allocated Chunk ID.
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * Used as a hint to avoid scanning the whole bitmap. */
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /** Chunk ID allocation bitmap.
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * Bits of allocated IDs are set, free ones are clear.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The NIL id (0) is marked allocated. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t bmChunkId[(GMM_CHUNKID_LAST + 1 + 31) / 32];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to the GMM instance. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** The value of GMM::u32Magic (Katsuhiro Otomo). */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync* Global Variables *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to the GMM instance data. */
8cd2f2e64725096acb682f34a5568b7fb816eda7vboxsync/** Macro for obtaining and validating the g_pGMM pointer.
8cd2f2e64725096acb682f34a5568b7fb816eda7vboxsync * On failure it will return from the invoking function with the specified return value.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pGMM The name of the pGMM variable.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param rc The return value on failure. Use VERR_INTERNAL_ERROR for
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VBox status codes.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgReturn((pGMM)->u32Magic == GMM_MAGIC, ("%p - %#x\n", (pGMM), (pGMM)->u32Magic), (rc)); \
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync } while (0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Macro for obtaining and validating the g_pGMM pointer, void function variant.
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync * On failure it will return from the invoking function.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pGMM The name of the pGMM variable.
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync AssertMsgReturnVoid((pGMM)->u32Magic == GMM_MAGIC, ("%p - %#x\n", (pGMM), (pGMM)->u32Magic)); \
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync } while (0)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/** @def GMM_CHECK_SANITY_UPON_ENTERING
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Checks the sanity of the GMM instance data before making changes.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This is macro is a stub by default and must be enabled manually in the code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns true if sane, false if not.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pGMM The name of the pGMM variable.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if defined(VBOX_STRICT) && 0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define GMM_CHECK_SANITY_UPON_ENTERING(pGMM) (gmmR0SanityCheck((pGMM), __PRETTY_FUNCTION__, __LINE__) == 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define GMM_CHECK_SANITY_UPON_ENTERING(pGMM) (true)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @def GMM_CHECK_SANITY_UPON_LEAVING
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Checks the sanity of the GMM instance data after making changes.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This is macro is a stub by default and must be enabled manually in the code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns true if sane, false if not.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pGMM The name of the pGMM variable.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if defined(VBOX_STRICT) && 0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define GMM_CHECK_SANITY_UPON_LEAVING(pGMM) (gmmR0SanityCheck((pGMM), __PRETTY_FUNCTION__, __LINE__) == 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @def GMM_CHECK_SANITY_IN_LOOPS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Checks the sanity of the GMM instance in the allocation loops.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This is macro is a stub by default and must be enabled manually in the code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns true if sane, false if not.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pGMM The name of the pGMM variable.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if defined(VBOX_STRICT) && 0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define GMM_CHECK_SANITY_IN_LOOPS(pGMM) (gmmR0SanityCheck((pGMM), __PRETTY_FUNCTION__, __LINE__) == 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
cba6719bd64ec749967bbe931230452664109857vboxsync* Internal Functions *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsyncstatic DECLCALLBACK(int) gmmR0TermDestroyChunk(PAVLU32NODECORE pNode, void *pvGMM);
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsyncstatic DECLCALLBACK(int) gmmR0CleanupVMScanChunk(PAVLU32NODECORE pNode, void *pvGMM);
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsyncstatic DECLCALLBACK(int) gmmR0CleanupSharedModule(PAVLGCPTRNODECORE pNode, void *pvGVM);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/*static*/ DECLCALLBACK(int) gmmR0CleanupVMDestroyChunk(PAVLU32NODECORE pNode, void *pvGVM);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncDECLINLINE(void) gmmR0LinkChunk(PGMMCHUNK pChunk, PGMMCHUNKFREESET pSet);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncDECLINLINE(void) gmmR0UnlinkChunk(PGMMCHUNK pChunk);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic uint32_t gmmR0SanityCheck(PGMM pGMM, const char *pszFunction, unsigned uLineNo);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic void gmmR0FreeChunk(PGMM pGMM, PGVM pGVM, PGMMCHUNK pChunk);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic void gmmR0FreeSharedPage(PGMM pGMM, uint32_t idPage, PGMMPAGE pPage);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic int gmmR0UnmapChunk(PGMM pGMM, PGVM pGVM, PGMMCHUNK pChunk);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * Initializes the GMM component.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This is called when the VMMR0.r0 module is loaded and protected by the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * loader semaphore.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Allocate the instance data and the lock(s).
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pGMM->ChunkTLB.aEntries); i++)
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync pGMM->ChunkTLB.aEntries[i].idChunk = NIL_GMM_CHUNKID;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Check and see if RTR0MemObjAllocPhysNC works.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if 0 /* later, see #3170. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTR0MemObjAllocPhysNC(&MemObj, _64K, NIL_RTHCPHYS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pGMM->fLegacyAllocationMode = pGMM->fBoundMemoryMode = true;
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync SUPR0Printf("GMMR0Init: RTR0MemObjAllocPhysNC(,64K,Any) -> %d!\n", rc);
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync# if defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Don't reuse possibly partial chunks because of the virtual address space limitation. */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync * Query system page count and guess a reasonable cMaxPages value.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pGMM->cMaxPages = UINT32_MAX; /** @todo IPRT function for query ram size and such. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogFlow(("GMMInit: pGMM=%p fLegacyAllocationMode=%RTbool fBoundMemoryMode=%RTbool\n", pGMM, pGMM->fLegacyAllocationMode, pGMM->fBoundMemoryMode));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Terminates the GMM component.
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync * Take care / be paranoid...
#ifdef VBOX_WITH_PAGE_SHARING
SUPR0Printf("GMMR0CleanupVM: hGVM=%#x has %#x private pages that cannot be found!\n", pGVM->hSelf, pGVM->gmm.s.cPrivatePages);
if (cPrivatePages)
while (pCur)
SUPR0Printf("GMMR0CleanupVM: hGVM=%#x left %#x shared pages behind!\n", pGVM->hSelf, pGVM->gmm.s.cSharedPages);
case GMMOCPOLICY_NO_OC:
#ifndef VBOX_STRICT
unsigned cPrivate = 0;
unsigned cShared = 0;
unsigned cFree = 0;
while (iPage-- > 0)
cFree++;
cPrivate++;
cFree++;
cShared++;
SUPR0Printf("gmmR0CleanupVMScanChunk: Chunk %p/%#x has bogus stats - free=%d/%d private=%d/%d shared=%d/%d\n",
AssertMsgFailed(("%p/%#x: cFree=%#x - it should be 0 in bound mode!\n", pChunk, pChunk->Core.Key, pChunk->cFree));
SUPR0Printf("gmmR0CleanupVMDestroyChunk: %p/%#x: mapping #%x: RTRMemObjFree(%p,false) -> %d \n", pChunk,
SUPR0Printf("gmmR0CleanupVMDestroyChunk: %p/%#x: RTRMemObjFree(%p,true) -> %d (cMappings=%d)\n", pChunk,
GMMR0DECL(int) GMMR0InitialReservation(PVM pVM, VMCPUID idCpu, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages,
LogFlow(("GMMR0InitialReservation: pVM=%p cBasePages=%#llx cShadowPages=%#x cFixedPages=%#x enmPolicy=%d enmPriority=%d\n",
return rc;
AssertReturn(enmPolicy > GMMOCPOLICY_INVALID && enmPolicy < GMMOCPOLICY_END, VERR_INVALID_PARAMETER);
AssertReturn(enmPriority > GMMPRIORITY_INVALID && enmPriority < GMMPRIORITY_END, VERR_INVALID_PARAMETER);
return rc;
AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
return GMMR0InitialReservation(pVM, idCpu, pReq->cBasePages, pReq->cShadowPages, pReq->cFixedPages, pReq->enmPolicy, pReq->enmPriority);
GMMR0DECL(int) GMMR0UpdateReservation(PVM pVM, VMCPUID idCpu, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages)
return rc;
return rc;
AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
cErrors++;
return cErrors;
return cErrors;
return pChunk;
return NULL;
if (pPrev)
if (pNext)
return idChunk;
AssertMsgReturn(!ASMAtomicBitTestAndSet(&pGMM->bmChunkId[0], idChunk), ("%#x\n", idChunk), NIL_GMM_CHUNKID);
AssertMsgReturn(!ASMAtomicBitTestAndSet(&pGMM->bmChunkId[0], idChunk), ("%#x\n", idChunk), NIL_GMM_CHUNKID);
static int gmmR0RegisterChunk(PGMM pGMM, PGMMCHUNKFREESET pSet, RTR0MEMOBJ MemObj, uint16_t hGVM, GMMCHUNKTYPE enmChunkType, PGMMCHUNK *ppChunk = NULL)
int rc;
if (pChunk)
LogFlow(("gmmR0RegisterChunk: pChunk=%p id=%#x cChunks=%d\n", pChunk, pChunk->Core.Key, pGMM->cChunks));
if (ppChunk)
return VINF_SUCCESS;
return rc;
static int gmmR0AllocateOneChunk(PGMM pGMM, PGMMCHUNKFREESET pSet, uint16_t hGVM, GMMCHUNKTYPE enmChunkType, PGMMCHUNK *ppChunk = NULL)
int rc;
AssertReturn(enmChunkType == GMMCHUNKTYPE_NON_CONTINUOUS || enmChunkType == GMMCHUNKTYPE_CONTINUOUS, VERR_INVALID_PARAMETER);
return rc;
return VERR_INTERNAL_ERROR_4;
if (!pChunk)
return rc;
return VERR_INTERNAL_ERROR_5;
return rc;
return VERR_INTERNAL_ERROR_5;
return VINF_SUCCESS;
pPage->u = 0;
static int gmmR0AllocatePages(PGMM pGMM, PGVM pGVM, uint32_t cPages, PGMMPAGEDESC paPages, GMMACCOUNT enmAccount)
return VERR_GMM_HIT_GLOBAL_LIMIT;
switch (enmAccount)
case GMMACCOUNT_BASE:
if (RT_UNLIKELY(pGVM->gmm.s.Allocated.cBasePages + pGVM->gmm.s.cBalloonedPages + cPages > pGVM->gmm.s.Reserved.cBasePages))
pGVM->gmm.s.Reserved.cBasePages, pGVM->gmm.s.Allocated.cBasePages, pGVM->gmm.s.cBalloonedPages, cPages));
return VERR_GMM_HIT_VM_ACCOUNT_LIMIT;
case GMMACCOUNT_SHADOW:
return VERR_GMM_HIT_VM_ACCOUNT_LIMIT;
case GMMACCOUNT_FIXED:
return VERR_GMM_HIT_VM_ACCOUNT_LIMIT;
return VERR_GMM_SEED_ME;
return VERR_GMM_SEED_ME;
switch (enmAccount)
return VINF_SUCCESS;
GMMR0DECL(int) GMMR0AllocateHandyPages(PVM pVM, VMCPUID idCpu, uint32_t cPagesToUpdate, uint32_t cPagesToAlloc, PGMMPAGEDESC paPages)
return rc;
unsigned iPage = 0;
AssertMsgReturn(paPages[iPage].HCPhysGCPhys == NIL_RTHCPHYS, ("#%#x: %RHp\n", iPage, paPages[iPage].HCPhysGCPhys), VERR_INVALID_PARAMETER);
AssertMsgReturn(paPages[iPage].idPage == NIL_GMM_PAGEID, ("#%#x: %#x\n", iPage, paPages[iPage].idPage), VERR_INVALID_PARAMETER);
AssertMsgReturn(paPages[iPage].idSharedPage == NIL_GMM_PAGEID, ("#%#x: %#x\n", iPage, paPages[iPage].idSharedPage), VERR_INVALID_PARAMETER);
Log(("GMMR0AllocateHandyPages: #%#x/%#x: Not private! %.*Rhxs\n", iPage, paPages[iPage].idPage, sizeof(*pPage), pPage));
Log(("GMMR0AllocateHandyPages: free shared page %x cRefs=%d\n", paPages[iPage].idSharedPage, pPage->Shared.cRefs));
Log(("GMMR0AllocateHandyPages: #%#x/%#x: Not found! (shared)\n", iPage, paPages[iPage].idSharedPage));
return rc;
GMMR0DECL(int) GMMR0AllocatePages(PVM pVM, VMCPUID idCpu, uint32_t cPages, PGMMPAGEDESC paPages, GMMACCOUNT enmAccount)
LogFlow(("GMMR0AllocatePages: pVM=%p cPages=%#x paPages=%p enmAccount=%d\n", pVM, cPages, paPages, enmAccount));
return rc;
AssertMsgReturn(enmAccount > GMMACCOUNT_INVALID && enmAccount < GMMACCOUNT_END, ("%d\n", enmAccount), VERR_INVALID_PARAMETER);
AssertMsgReturn(cPages > 0 && cPages < RT_BIT(32 - PAGE_SHIFT), ("%#x\n", cPages), VERR_INVALID_PARAMETER);
AssertMsgReturn(paPages[iPage].idPage == NIL_GMM_PAGEID, ("#%#x: %#x\n", iPage, paPages[iPage].idPage), VERR_INVALID_PARAMETER);
AssertMsgReturn(paPages[iPage].idSharedPage == NIL_GMM_PAGEID, ("#%#x: %#x\n", iPage, paPages[iPage].idSharedPage), VERR_INVALID_PARAMETER);
return rc;
GMMR0DECL(int) GMMR0AllocateLargePage(PVM pVM, VMCPUID idCpu, uint32_t cbPage, uint32_t *pIdPage, RTHCPHYS *pHCPhys)
return rc;
return VERR_NOT_SUPPORTED;
if (RT_UNLIKELY(pGVM->gmm.s.Allocated.cBasePages + pGVM->gmm.s.cBalloonedPages + cPages > pGVM->gmm.s.Reserved.cBasePages))
return VERR_GMM_HIT_VM_ACCOUNT_LIMIT;
return rc;
return rc;
return rc;
return VERR_NOT_SUPPORTED;
Log(("GMMR0FreeLargePage: allocated=%#llx cPages=%#x!\n", pGVM->gmm.s.Allocated.cBasePages, cPages));
return rc;
&& pGVM)
pPage, pPage - &pChunk->aPages[0], idPage, pPage->Common.u2State, pChunk->iFreeHead)); NOREF(idPage);
pPage->u = 0;
#ifdef VBOX_WITH_PAGE_SHARING
DECLINLINE(void) gmmR0ConvertToSharedPage(PGMM pGMM, PGVM pGVM, RTHCPHYS HCPhys, uint32_t idPage, PGMMPAGE pPage)
static int gmmR0FreePages(PGMM pGMM, PGVM pGVM, uint32_t cPages, PGMMFREEPAGEDESC paPages, GMMACCOUNT enmAccount)
switch (enmAccount)
case GMMACCOUNT_BASE:
case GMMACCOUNT_SHADOW:
case GMMACCOUNT_FIXED:
switch (enmAccount)
return rc;
GMMR0DECL(int) GMMR0FreePages(PVM pVM, VMCPUID idCpu, uint32_t cPages, PGMMFREEPAGEDESC paPages, GMMACCOUNT enmAccount)
LogFlow(("GMMR0FreePages: pVM=%p cPages=%#x paPages=%p enmAccount=%d\n", pVM, cPages, paPages, enmAccount));
return rc;
AssertMsgReturn(enmAccount > GMMACCOUNT_INVALID && enmAccount < GMMACCOUNT_END, ("%d\n", enmAccount), VERR_INVALID_PARAMETER);
AssertMsgReturn(cPages > 0 && cPages < RT_BIT(32 - PAGE_SHIFT), ("%#x\n", cPages), VERR_INVALID_PARAMETER);
return rc;
GMMR0DECL(int) GMMR0BalloonedPages(PVM pVM, VMCPUID idCpu, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages)
AssertMsgReturn(cBalloonedPages < RT_BIT(32 - PAGE_SHIFT), ("%#x\n", cBalloonedPages), VERR_INVALID_PARAMETER);
return rc;
switch (enmAction)
case GMMBALLOONACTION_INFLATE:
/* Codepath never taken. Might be interesting in the future to request ballooned memory from guests in low memory conditions.. */
AssertFailed();
Log(("GMMR0BalloonedPages: +%#x - Global=%#llx / VM: Total=%#llx Req=%#llx Actual=%#llx (pending)\n", cBalloonedPages,
pGMM->cBalloonedPages, pGVM->gmm.s.cBalloonedPages, pGVM->gmm.s.cReqBalloonedPages, pGVM->gmm.s.cReqActuallyBalloonedPages));
case GMMBALLOONACTION_DEFLATE:
cBalloonedPages, pGMM->cBalloonedPages, pGVM->gmm.s.cBalloonedPages, pGVM->gmm.s.cReqDeflatePages));
case GMMBALLOONACTION_RESET:
return rc;
return VINF_SUCCESS;
return rc;
return rc;
return rc;
return VINF_SUCCESS;
Log(("gmmR0MapChunk: Chunk %#x is not mapped into pGVM=%p/%#x\n", pChunk->Core.Key, pGVM, pGVM->hSelf));
return VERR_GMM_CHUNK_NOT_MAPPED;
return VERR_GMM_CHUNK_NOT_FOUND;
return VINF_SUCCESS;
return VERR_GMM_CHUNK_ALREADY_MAPPED;
int rc = RTR0MemObjMapUser(&MapObj, pChunk->MemObj, (RTR3PTR)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE, NIL_RTR0PROCESS);
void *pvMappings = RTMemRealloc(pChunk->paMappings, (pChunk->cMappings + 2 /*8*/) * sizeof(pChunk->paMappings[0]));
return VERR_NO_MEMORY;
return rc;
GMMR0DECL(int) GMMR0MapUnmapChunk(PVM pVM, VMCPUID idCpu, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3)
return rc;
return VERR_INVALID_PARAMETER;
return rc;
AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
return rc;
return VERR_NOT_SUPPORTED;
rc = RTR0MemObjLockUser(&MemObj, pvR3, GMM_CHUNK_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE, NIL_RTR0PROCESS);
return rc;
GMMR0DECL(int) GMMR0RegisterSharedModule(PVM pVM, VMCPUID idCpu, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule,
#ifdef VBOX_WITH_PAGE_SHARING
return rc;
Log(("GMMR0RegisterSharedModule %s %s base %RGv size %x\n", pszModuleName, pszVersion, GCBaseAddr, cbModule));
bool fNewModule = false;
PGMMSHAREDMODULEPERVM pRecVM = (PGMMSHAREDMODULEPERVM)RTAvlGCPtrGet(&pGVM->gmm.s.pSharedModuleTree, GCBaseAddr);
if (!pRecVM)
if (!pRecVM)
AssertFailed();
goto end;
fNewModule = true;
PGMMSHAREDMODULE pGlobalModule = (PGMMSHAREDMODULE)RTAvlGCPtrGet(&pGMM->pGlobalSharedModuleTree, GCBaseAddr);
if (!pGlobalModule)
if (!pGlobalModule)
AssertFailed();
goto end;
for (unsigned i = 0; i < cRegions; i++)
if ( fNewModule
|| pRecVM->fCollision == true) /* colliding module unregistered and new one registerd since the last check */
Log(("GMMR0RegisterSharedModule: using existing module %s cUser=%d!\n", pszModuleName, pGlobalModule->cUsers));
goto end;
end:
return rc;
return VERR_NOT_IMPLEMENTED;
GMMR0DECL(int) GMMR0RegisterSharedModuleReq(PVM pVM, VMCPUID idCpu, PGMMREGISTERSHAREDMODULEREQ pReq)
AssertMsgReturn(pReq->Hdr.cbReq >= sizeof(*pReq) && pReq->Hdr.cbReq == RT_UOFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions]), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
return GMMR0RegisterSharedModule(pVM, idCpu, pReq->enmGuestOS, pReq->szName, pReq->szVersion, pReq->GCBaseAddr, pReq->cbModule, pReq->cRegions, pReq->aRegions);
GMMR0DECL(int) GMMR0UnregisterSharedModule(PVM pVM, VMCPUID idCpu, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule)
#ifdef VBOX_WITH_PAGE_SHARING
return rc;
Log(("GMMR0UnregisterSharedModule %s %s base=%RGv size %x\n", pszModuleName, pszVersion, GCBaseAddr, cbModule));
PGMMSHAREDMODULEPERVM pRecVM = (PGMMSHAREDMODULEPERVM)RTAvlGCPtrGet(&pGVM->gmm.s.pSharedModuleTree, GCBaseAddr);
if (!pRecVM)
goto end;
/* Free the ranges, but leave the pages intact as there might still be references; they will be cleared by the COW mechanism. */
end:
return rc;
return VERR_NOT_IMPLEMENTED;
GMMR0DECL(int) GMMR0UnregisterSharedModuleReq(PVM pVM, VMCPUID idCpu, PGMMUNREGISTERSHAREDMODULEREQ pReq)
AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
return GMMR0UnregisterSharedModule(pVM, idCpu, pReq->szName, pReq->szVersion, pReq->GCBaseAddr, pReq->cbModule);
#ifdef VBOX_WITH_PAGE_SHARING
* - if a shared page is new, then it changes the GMM page type to shared and returns it in the paPageDesc array
* - if a shared page already exists, then it checks if the VM page is identical and if so frees the VM page and returns the shared page in the paPageDesc array
GMMR0DECL(int) GMMR0SharedModuleCheckRange(PGVM pGVM, PGMMSHAREDMODULE pModule, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc)
AssertReturn(cPages == (pModule->aRegions[idxRegion].cbRegion >> PAGE_SHIFT), VERR_INVALID_PARAMETER);
Log(("GMMR0SharedModuleCheckRange %s base %RGv region %d cPages %d\n", pModule->szName, pModule->Core.Key, idxRegion, cPages));
pGlobalRegion->paHCPhysPageID = (uint32_t *)RTMemAlloc(cPages * sizeof(*pGlobalRegion->paHCPhysPageID));
AssertFailed();
goto end;
for (unsigned i = 0; i < cPages; i++)
for (unsigned i = 0; i < cPages; i++)
if (!pPage)
AssertFailed();
goto end;
AssertMsg(paPageDesc[i].GCPhys == (pPage->Private.pfn << 12), ("desc %RGp gmm %RGp\n", paPageDesc[i].HCPhys, (pPage->Private.pfn << 12)));
if (!pPage)
AssertFailed();
goto end;
Log(("Replace existing page guest %RGp host %RHp -> %RHp\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys, pPage->Shared.pfn << PAGE_SHIFT));
if (pChunk)
AssertFailed();
goto end;
AssertFailed();
goto end;
/* Get the virtual address of the physical page; map the chunk into the VM process if not already done. */
goto end;
end:
return rc;
#ifdef VBOX_WITH_PAGE_SHARING
return rc;
return rc;
return VERR_NOT_IMPLEMENTED;
#ifdef VBOX_WITH_PAGE_SHARING
Log(("gmmR0CheckSharedModule: check %s %s base=%RGv size=%x collision=%d\n", pGlobalModule->szName, pGlobalModule->szVersion, pGlobalModule->Core.Key, pGlobalModule->cbModule, pLocalModule->fCollision));
#ifdef VBOX_WITH_PAGE_SHARING
return rc;
RTAvlGCPtrDoWithAll(&pGVM->gmm.s.pSharedModuleTree, true /* fFromLeft */, gmmR0CheckSharedModule, &Info);
return rc;
return VERR_NOT_IMPLEMENTED;