PGM.cpp revision 347af7572b782ff8715f824f5d70e76a15e3a4d1
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * PGM - Page Manager and Monitor. (Mixing stuff here, not good?)
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2006-2007 innotek GmbH
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * available from http://www.virtualbox.org. This file is free software;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * General Public License as published by the Free Software Foundation,
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/** @page pg_pgm PGM - The Page Manager and Monitor
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @section sec_pgm_modes Paging Modes
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * There are three memory contexts: Host Context (HC), Guest Context (GC)
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * and intermediate context. When talking about paging HC can also be refered to
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * as "host paging", and GC refered to as "shadow paging".
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * We define three basic paging modes: 32-bit, PAE and AMD64. The host paging mode
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * is defined by the host operating system. The mode used in the shadow paging mode
3aad980b92149dd95a1ab72ddb8d11d61a28ace6vboxsync * depends on the host paging mode and what the mode the guest is currently in. The
3aad980b92149dd95a1ab72ddb8d11d61a28ace6vboxsync * following relation between the two is defined:
3aad980b92149dd95a1ab72ddb8d11d61a28ace6vboxsync * @verbatim
0a7b20727716a00270f358a1c546473d8c36e8f3vboxsync Host > 32-bit | PAE | AMD64 |
0a7b20727716a00270f358a1c546473d8c36e8f3vboxsync Guest | | | |
0a7b20727716a00270f358a1c546473d8c36e8f3vboxsync ==v================================
0a7b20727716a00270f358a1c546473d8c36e8f3vboxsync 32-bit 32-bit PAE PAE
0a7b20727716a00270f358a1c546473d8c36e8f3vboxsync -------|--------|--------|--------|
0a7b20727716a00270f358a1c546473d8c36e8f3vboxsync PAE PAE PAE PAE
0a7b20727716a00270f358a1c546473d8c36e8f3vboxsync -------|--------|--------|--------|
0a7b20727716a00270f358a1c546473d8c36e8f3vboxsync AMD64 AMD64 AMD64 AMD64
0a7b20727716a00270f358a1c546473d8c36e8f3vboxsync -------|--------|--------|--------| @endverbatim
0a7b20727716a00270f358a1c546473d8c36e8f3vboxsync * All configuration except those in the diagonal (upper left) are expected to
3aad980b92149dd95a1ab72ddb8d11d61a28ace6vboxsync * require special effort from the switcher (i.e. a bit slower).
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @section sec_pgm_shw The Shadow Memory Context
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Because of guest context mappings requires PDPTR and PML4 entries to allow
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * writing on AMD64, the two upper levels will have fixed flags whatever the
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * guest is thinking of using there. So, when shadowing the PD level we will
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * calculate the effective flags of PD and all the higher levels. In legacy
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * PAE mode this only applies to the PWT and PCD bits (the rest are
7ccd30dd4bbced565b32c255a11640cd4093abb6vboxsync * ignored/reserved/MBZ). We will ignore those bits for the present.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @section sec_pgm_int The Intermediate Memory Context
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * The world switch goes thru an intermediate memory context which purpose it is
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * to provide different mappings of the switcher code. All guest mappings are also
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * present in this context.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * The switcher code is mapped at the same location as on the host, at an
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * identity mapped location (physical equals virtual address), and at the
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * hypervisor location.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * PGM maintain page tables for 32-bit, PAE and AMD64 paging modes. This
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * simplifies switching guest CPU mode and consistency at the cost of more
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * code to do the work. All memory use for those page tables is located below
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * 4GB (this includes page tables for guest context mappings).
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @subsection subsec_pgm_int_gc Guest Context Mappings
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * During assignment and relocation of a guest context mapping the intermediate
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * memory context is used to verify the new location.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Guest context mappings are currently restricted to below 4GB, for reasons
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * of simplicity. This may change when we implement AMD64 support.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @section sec_pgm_misc Misc
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @subsection subsec_pgm_misc_diff Differences Between Legacy PAE and Long Mode PAE
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * The differences between legacy PAE and long mode PAE are:
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * -# PDPE bits 1, 2, 5 and 6 are defined differently. In leagcy mode they are
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * all marked down as must-be-zero, while in long mode 1, 2 and 5 have the
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * usual meanings while 6 is ignored (AMD). This means that upon switching to
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * legacy PAE mode we'll have to clear these bits and when going to long mode
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * they must be set. This applies to both intermediate and shadow contexts,
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * however we don't need to do it for the intermediate one since we're
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * executing with CR0.WP at that time.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * -# CR3 allows a 32-byte aligned address in legacy mode, while in long mode
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * a page aligned one is required.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/** @page pg_pgmPhys PGMPhys - Physical Guest Memory Management.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Objectives:
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * - Guest RAM over-commitment using memory ballooning,
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * zero pages and general page sharing.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * - Moving or mirroring a VM onto a different physical machine.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @subsection subsec_pgmPhys_Definitions Definitions
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Allocation chunk - A RTR0MemObjAllocPhysNC object and the tracking
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * machinery assoicated with it.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * @subsection subsec_pgmPhys_AllocPage Allocating a page.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * Initially we map *all* guest memory to the (per VM) zero page, which
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * means that none of the read functions will cause pages to be allocated.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * Exception, access bit in page tables that have been shared. This must
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * be handled, but we must also make sure PGMGst*Modify doesn't make
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * unnecessary modifications.
89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9vboxsync * Allocation points:
89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9vboxsync * - PGMPhysWriteGCPhys and PGMPhysWrite.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * - Replacing a zero page mapping at \#PF.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * - Replacing a shared page mapping at \#PF.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * - ROM registration (currently MMR3RomRegister).
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * - VM restore (pgmR3Load).
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * For the first three it would make sense to keep a few pages handy
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * until we've reached the max memory commitment for the VM.
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * For the ROM registration, we know exactly how many pages we need
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * and will request these from ring-0. For restore, we will save
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * the number of non-zero pages in the saved state and allocate
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * them up front. This would allow the ring-0 component to refuse
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * the request if the isn't sufficient memory available for VM use.
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * Btw. for both ROM and restore allocations we won't be requiring
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * zeroed pages as they are going to be filled instantly.
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * @subsection subsec_pgmPhys_FreePage Freeing a page
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * There are a few points where a page can be freed:
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * - After being replaced by the zero page.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * - After being replaced by a shared page.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * - After being ballooned by the guest additions.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * - At reset.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * - At restore.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * When freeing one or more pages they will be returned to the ring-0
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * component and replaced by the zero page.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * The reasoning for clearing out all the pages on reset is that it will
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * return us to the exact same state as on power on, and may thereby help
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * us reduce the memory load on the system. Further it might have a
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * (temporary) positive influence on memory fragmentation (@see subsec_pgmPhys_Fragmentation).
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * On restore, as mention under the allocation topic, pages should be
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * freed / allocated depending on how many is actually required by the
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * new VM state. The simplest approach is to do like on reset, and free
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * all non-ROM pages and then allocate what we need.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * A measure to prevent some fragmentation, would be to let each allocation
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * chunk have some affinity towards the VM having allocated the most pages
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * from it. Also, try make sure to allocate from allocation chunks that
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * are almost full. Admittedly, both these measures might work counter to
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * our intentions and its probably not worth putting a lot of effort,
89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9vboxsync * cpu time or memory into this.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @subsection subsec_pgmPhys_SharePage Sharing a page
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * The basic idea is that there there will be a idle priority kernel
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * thread walking the non-shared VM pages hashing them and looking for
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * pages with the same checksum. If such pages are found, it will compare
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * them byte-by-byte to see if they actually are identical. If found to be
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * identical it will allocate a shared page, copy the content, check that
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * the page didn't change while doing this, and finally request both the
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * VMs to use the shared page instead. If the page is all zeros (special
89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9vboxsync * checksum and byte-by-byte check) it will request the VM that owns it
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * to replace it with the zero page.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * To make this efficient, we will have to make sure not to try share a page
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * that will change its contents soon. This part requires the most work.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * A simple idea would be to request the VM to write monitor the page for
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * a while to make sure it isn't modified any time soon. Also, it may
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * make sense to skip pages that are being write monitored since this
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * information is readily available to the thread if it works on the
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * per-VM guest memory structures (presently called PGMRAMRANGE).
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @subsection subsec_pgmPhys_Fragmentation Fragmentation Concerns and Counter Measures
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * The pages are organized in allocation chunks in ring-0, this is a necessity
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * if we wish to have an OS agnostic approach to this whole thing. (On Linux we
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * could easily work on a page-by-page basis if we liked. Whether this is possible
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * or efficient on NT I don't quite know.) Fragmentation within these chunks may
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * become a problem as part of the idea here is that we wish to return memory to
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * the host system.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * For instance, starting two VMs at the same time, they will both allocate the
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * guest memory on-demand and if permitted their page allocations will be
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * intermixed. Shut down one of the two VMs and it will be difficult to return
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * any memory to the host system because the page allocation for the two VMs are
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * mixed up in the same allocation chunks.
89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9vboxsync * To further complicate matters, when pages are freed because they have been
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * ballooned or become shared/zero the whole idea is that the page is supposed
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * to be reused by another VM or returned to the host system. This will cause
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * allocation chunks to contain pages belonging to different VMs and prevent
89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9vboxsync * returning memory to the host when one of those VM shuts down.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * The only way to really deal with this problem is to move pages. This can
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * either be done at VM shutdown and or by the idle priority worker thread
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * that will be responsible for finding sharable/zero pages. The mechanisms
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * involved for coercing a VM to move a page (or to do it for it) will be
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * the same as when telling it to share/zero a page.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @subsection subsec_pgmPhys_Tracking Tracking Structures And Their Cost
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * There's a difficult balance between keeping the per-page tracking structures
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * (global and guest page) easy to use and keeping them from eating too much
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * memory. We have limited virtual memory resources available when operating in
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * 32-bit kernel space (on 64-bit there'll it's quite a different story). The
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * tracking structures will be attemted designed such that we can deal with up
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * to 32GB of memory on a 32-bit system and essentially unlimited on 64-bit ones.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @subsubsection subsubsec_pgmPhys_Tracking_Kernel Kernel Space
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @see pg_GMM
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @subsubsection subsubsec_pgmPhys_Tracking_PerVM Per-VM
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Fixed info is the physical address of the page (HCPhys) and the page id
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * (described above). Theoretically we'll need 48(-12) bits for the HCPhys part.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Today we've restricting ourselves to 40(-12) bits because this is the current
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * restrictions of all AMD64 implementations (I think Barcelona will up this
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync * to 48(-12) bits, not that it really matters) and I needed the bits for
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * tracking mappings of a page. 48-12 = 36. That leaves 28 bits, which means a
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * decent range for the page id: 2^(28+12) = 1024TB.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * In additions to these, we'll have to keep maintaining the page flags as we
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * currently do. Although it wouldn't harm to optimize these quite a bit, like
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * for instance the ROM shouldn't depend on having a write handler installed
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * in order for it to become read-only. A RO/RW bit should be considered so
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * that the page syncing code doesn't have to mess about checking multiple
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * flag combinations (ROM || RW handler || write monitored) in order to
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * figure out how to setup a shadow PTE. But this of course, is second
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * priority at present. Current this requires 12 bits, but could probably
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * be optimized to ~8.
8fdb63a0d23d1618724f651b8c3d11be48b44d35vboxsync * Then there's the 24 bits used to track which shadow page tables are
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * currently mapping a page for the purpose of speeding up physical
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * access handlers, and thereby the page pool cache. More bit for this
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * purpose wouldn't hurt IIRC.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Then there is a new bit in which we need to record what kind of page
d605d5391db09e6395a1c091f148f4b86af84bd3vboxsync * this is, shared, zero, normal or write-monitored-normal. This'll
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * require 2 bits. One bit might be needed for indicating whether a
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * write monitored page has been written to. And yet another one or
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * two for tracking migration status. 3-4 bits total then.
e190faad3061288ae099cd3ea8a858bd224c00a7vboxsync * Whatever is left will can be used to record the sharabilitiy of a
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * page. The page checksum will not be stored in the per-VM table as
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * the idle thread will not be permitted to do modifications to it.
d605d5391db09e6395a1c091f148f4b86af84bd3vboxsync * It will instead have to keep its own working set of potentially
d605d5391db09e6395a1c091f148f4b86af84bd3vboxsync * shareable pages and their check sums and stuff.
259e900197d37d0f84ed72e1d4a4eb6c11b4e301vboxsync * For the present we'll keep the current packing of the
259e900197d37d0f84ed72e1d4a4eb6c11b4e301vboxsync * PGMRAMRANGE::aHCPhys to keep the changes simple, only of course,
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * we'll have to change it to a struct with a total of 128-bits at
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * our disposal.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * The initial layout will be like this:
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @verbatim
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTHCPHYS HCPhys; The current stuff.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync 63:40 Current shadow PT tracking stuff.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync 39:12 The physical page frame number.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync 11:0 The current flags.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync uint32_t u28PageId : 28; The page id.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync uint32_t u2State : 2; The page state { zero, shared, normal, write monitored }.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync uint32_t fWrittenTo : 1; Whether a write monitored page was written to.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync uint32_t u1Reserved : 1; Reserved for later.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync uint32_t u32Reserved; Reserved for later, mostly sharing stats.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync @endverbatim
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * The final layout will be something like this:
8fdb63a0d23d1618724f651b8c3d11be48b44d35vboxsync * @verbatim
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTHCPHYS HCPhys; The current stuff.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync 63:48 High page id (12+).
89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9vboxsync 47:12 The physical page frame number.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync 11:0 Low page id.
7e10aea6606a51d35041e5a85f9e4f1bd19c4062vboxsync uint32_t fReadOnly : 1; Whether it's readonly page (rom or monitored in some way).
e190faad3061288ae099cd3ea8a858bd224c00a7vboxsync uint32_t u3Type : 3; The page type {RESERVED, MMIO, MMIO2, ROM, shadowed ROM, RAM}.
7e10aea6606a51d35041e5a85f9e4f1bd19c4062vboxsync uint32_t u2PhysMon : 2; Physical access handler type {none, read, write, all}.
0a79c9258d8fae34fa527f125009ab507561b4edvboxsync uint32_t u2VirtMon : 2; Virtual access handler type {none, read, write, all}..
0a79c9258d8fae34fa527f125009ab507561b4edvboxsync uint32_t u2State : 2; The page state { zero, shared, normal, write monitored }.
7e10aea6606a51d35041e5a85f9e4f1bd19c4062vboxsync uint32_t fWrittenTo : 1; Whether a write monitored page was written to.
259e900197d37d0f84ed72e1d4a4eb6c11b4e301vboxsync uint32_t u20Reserved : 20; Reserved for later, mostly sharing stats.
259e900197d37d0f84ed72e1d4a4eb6c11b4e301vboxsync uint32_t u32Tracking; The shadow PT tracking stuff, roughly.
7e10aea6606a51d35041e5a85f9e4f1bd19c4062vboxsync @endverbatim
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * Cost wise, this means we'll double the cost for guest memory. There isn't anyway
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * around that I'm afraid. It means that the cost of dealing out 32GB of memory
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * to one or more VMs is: (32GB >> PAGE_SHIFT) * 16 bytes, or 128MBs. Or another
8c19165bdee6b3a436eba73d9e30fc59f360e313vboxsync * example, the VM heap cost when assigning 1GB to a VM will be: 4MB.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * A couple of cost examples for the total cost per-VM + kernel.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * 32-bit Windows and 32-bit linux:
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * 1GB guest ram, 256K pages: 4MB + 2MB(+) = 6MB
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * 4GB guest ram, 1M pages: 16MB + 8MB(+) = 24MB
89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9vboxsync * 32GB guest ram, 8M pages: 128MB + 64MB(+) = 192MB
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * 64-bit Windows and 64-bit linux:
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * 1GB guest ram, 256K pages: 4MB + 3MB(+) = 7MB
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * 4GB guest ram, 1M pages: 16MB + 12MB(+) = 28MB
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * 32GB guest ram, 8M pages: 128MB + 96MB(+) = 224MB
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @subsection subsec_pgmPhys_Serializing Serializing Access
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Initially, we'll try a simple scheme:
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * - The per-VM RAM tracking structures (PGMRAMRANGE) is only modified
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * by the EMT thread of that VM while in the pgm critsect.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * - Other threads in the VM process that needs to make reliable use of
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * the per-VM RAM tracking structures will enter the critsect.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * - No process external thread or kernel thread will ever try enter
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * the pgm critical section, as that just won't work.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * - The idle thread (and similar threads) doesn't not need 100% reliable
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * data when performing it tasks as the EMT thread will be the one to
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * do the actual changes later anyway. So, as long as it only accesses
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * the main ram range, it can do so by somehow preventing the VM from
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * being destroyed while it works on it...
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * - The over-commitment management, including the allocating/freeing
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * chunks, is serialized by a ring-0 mutex lock (a fast one since the
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * more mundane mutex implementation is broken on Linux).
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * - A separeate mutex is protecting the set of allocation chunks so
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * that pages can be shared or/and freed up while some other VM is
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * allocating more chunks. This mutex can be take from under the other
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * one, but not the otherway around.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @subsection subsec_pgmPhys_Request VM Request interface
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * When in ring-0 it will become necessary to send requests to a VM so it can
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * for instance move a page while defragmenting during VM destroy. The idle
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * thread will make use of this interface to request VMs to setup shared
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * pages and to perform write monitoring of pages.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * I would propose an interface similar to the current VMReq interface, similar
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * in that it doesn't require locking and that the one sending the request may
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * wait for completion if it wishes to. This shouldn't be very difficult to
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * The requests themselves are also pretty simple. They are basically:
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * -# Check that some precondition is still true.
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync * -# Do the update.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * -# Update all shadow page tables involved with the page.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * The 3rd step is identical to what we're already doing when updating a
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * physical handler, see pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * @section sec_pgmPhys_MappingCaches Mapping Caches
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * In order to be able to map in and out memory and to be able to support
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * guest with more RAM than we've got virtual address space, we'll employing
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * a mapping cache. There is already a tiny one for GC (see PGMGCDynMapGCPageEx)
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * and we'll create a similar one for ring-0 unless we decide to setup a dedicate
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * memory context for the HWACCM execution.
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync * @subsection subsec_pgmPhys_MappingCaches_R3 Ring-3
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync * We've considered implementing the ring-3 mapping cache page based but found
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync * that this was bother some when one had to take into account TLBs+SMP and
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * portability (missing the necessary APIs on several platforms). There were
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * also some performance concerns with this approach which hadn't quite been
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * worked out.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * Instead, we'll be mapping allocation chunks into the VM process. This simplifies
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * matters greatly quite a bit since we don't need to invent any new ring-0 stuff,
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * only some minor RTR0MEMOBJ mapping stuff. The main concern here is that mapping
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * compared to the previous idea is that mapping or unmapping a 1MB chunk is more
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync * costly than a single page, although how much more costly is uncertain. We'll
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync * try address this by using a very big cache, preferably bigger than the actual
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync * VM RAM size if possible. The current VM RAM sizes should give some idea for
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync * 32-bit boxes, while on 64-bit we can probably get away with employing an
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync * unlimited cache.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * The cache have to parts, as already indicated, the ring-3 side and the
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * ring-0 side.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * The ring-0 will be tied to the page allocator since it will operate on the
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * memory objects it contains. It will therefore require the first ring-0 mutex
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * discussed in @ref subsec_pgmPhys_Serializing. We
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync * some double house keeping wrt to who has mapped what I think, since both
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync * VMMR0.r0 and RTR0MemObj will keep track of mapping relataions
d605d5391db09e6395a1c091f148f4b86af84bd3vboxsync * The ring-3 part will be protected by the pgm critsect. For simplicity, we'll
* The simplified flow of a PGMPhysRead/Write function:
#include "PGMInternal.h"
#ifdef VBOX_STRICT
static DECLCALLBACK(void) pgmR3ResetNoMorePhysWritesFlag(PVM pVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser);
static PGMMODE pgmR3CalcShadowMode(PGMMODE enmGuestMode, SUPPAGINGMODE enmHostMode, PGMMODE enmShadowMode, VMMSWITCHER *penmSwitcher);
#ifdef VBOX_WITH_STATISTICS
#ifdef VBOX_WITH_DEBUGGER
static DECLCALLBACK(int) pgmR3CmdRam(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) pgmR3CmdMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) pgmR3CmdSync(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) pgmR3CmdSyncAlways(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
#ifdef VBOX_WITH_DEBUGGER
/* pszCmd, cArgsMin, cArgsMax, paArgDesc, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */
{ "pgmsyncalways", 0, 0, NULL, 0, NULL, 0, pgmR3CmdSyncAlways, "", "Toggle permanent CR3 syncing." },
#include "PGMShw.h"
#include "PGMGst.h"
#include "PGMBth.h"
#include "PGMGst.h"
#include "PGMBth.h"
#include "PGMGst.h"
#include "PGMBth.h"
#include "PGMShw.h"
#include "PGMBth.h"
#include "PGMBth.h"
#include "PGMBth.h"
#include "PGMGst.h"
#include "PGMBth.h"
#include "PGMShw.h"
#include "PGMBth.h"
#include "PGMBth.h"
#include "PGMGst.h"
#include "PGMBth.h"
#ifdef VBOX_STRICT
cbRam = 0;
return rc;
return rc;
"Recognizes 'all', 'guest', 'shadow' and 'host' as arguments, defaulting to 'all' if nothing's given.",
STAM_REL_REG(pVM, &pVM->pgm.s.cGuestModeChanges, STAMTYPE_COUNTER, "/PGM/cGuestModeChanges", STAMUNIT_OCCURENCES, "Number of guest mode changes.");
#ifdef VBOX_WITH_STATISTICS
#ifdef VBOX_WITH_DEBUGGER
static bool fRegisteredCmds = false;
if (!fRegisteredCmds)
fRegisteredCmds = true;
return VINF_SUCCESS;
return rc;
return rc;
return VERR_NO_PAGE_MEMORY;
AssertRelease(pVM->pgm.s.HCPhysInterPD != NIL_RTHCPHYS && !(pVM->pgm.s.HCPhysInterPD & PAGE_OFFSET_MASK));
AssertRelease(pVM->pgm.s.HCPhysInterPaePDPTR != NIL_RTHCPHYS && !(pVM->pgm.s.HCPhysInterPaePDPTR & PAGE_OFFSET_MASK));
AssertRelease(pVM->pgm.s.HCPhysInterPaePML4 != NIL_RTHCPHYS && !(pVM->pgm.s.HCPhysInterPaePML4 & PAGE_OFFSET_MASK));
pVM->pgm.s.pInterPaePDPTR64->a[i].u = X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US | X86_PDPE_A | PGM_PLXFLAGS_PERMANENT
pVM->pgm.s.pInterPaePML4->a[i].u = X86_PML4E_P | X86_PML4E_RW | X86_PML4E_US | X86_PML4E_A | PGM_PLXFLAGS_PERMANENT
AssertRelease((uintptr_t)pVM->pgm.s.apHCPaePDs[0] + PAGE_SIZE == (uintptr_t)pVM->pgm.s.apHCPaePDs[1]);
AssertRelease((uintptr_t)pVM->pgm.s.apHCPaePDs[1] + PAGE_SIZE == (uintptr_t)pVM->pgm.s.apHCPaePDs[2]);
AssertRelease((uintptr_t)pVM->pgm.s.apHCPaePDs[2] + PAGE_SIZE == (uintptr_t)pVM->pgm.s.apHCPaePDs[3]);
return VERR_NO_PAGE_MEMORY;
case SUPPAGINGMODE_32_BIT:
case SUPPAGINGMODE_PAE:
case SUPPAGINGMODE_PAE_GLOBAL:
case SUPPAGINGMODE_PAE_NX:
case SUPPAGINGMODE_AMD64:
case SUPPAGINGMODE_AMD64_NX:
#ifndef VBOX_WITH_HYBIRD_32BIT_KERNEL
AssertMsgFailed(("Host mode %d (64-bit) is not supported by non-64bit builds\n", pVM->pgm.s.enmHostMode));
LogRel(("Debug: HCPhys32BitPD=%VHp aHCPhysPaePDs={%VHp,%VHp,%VHp,%VHp} HCPhysPaePDPTR=%VHp HCPhysPaePML4=%VHp\n",
pVM->pgm.s.HCPhys32BitPD, pVM->pgm.s.aHCPhysPaePDs[0], pVM->pgm.s.aHCPhysPaePDs[1], pVM->pgm.s.aHCPhysPaePDs[2], pVM->pgm.s.aHCPhysPaePDs[3],
LogRel(("Debug: apInterPTs={%VHp,%VHp} apInterPaePTs={%VHp,%VHp} apInterPaePDs={%VHp,%VHp,%VHp,%VHp} pInterPaePDPTR64=%VHp\n",
MMPage2Phys(pVM, pVM->pgm.s.apInterPaePDs[0]), MMPage2Phys(pVM, pVM->pgm.s.apInterPaePDs[1]), MMPage2Phys(pVM, pVM->pgm.s.apInterPaePDs[2]), MMPage2Phys(pVM, pVM->pgm.s.apInterPaePDs[3]),
return VINF_SUCCESS;
return rc;
#ifdef VBOX_WITH_STATISTICS
STAM_REG(pVM, &pPGM->StatGCInvalidatePage, STAMTYPE_PROFILE, "/PGM/GC/InvalidatePage", STAMUNIT_TICKS_PER_CALL, "PGMGCInvalidatePage() profiling.");
STAM_REG(pVM, &pPGM->StatGCInvalidatePage4KBPages, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/4KBPages", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for a 4KB page.");
STAM_REG(pVM, &pPGM->StatGCInvalidatePage4MBPages, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/4MBPages", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for a 4MB page.");
STAM_REG(pVM, &pPGM->StatGCInvalidatePage4MBPagesSkip, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/4MBPagesSkip",STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() skipped a 4MB page.");
STAM_REG(pVM, &pPGM->StatGCInvalidatePagePDMappings, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/PDMappings", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for a page directory containing mappings (no conflict).");
STAM_REG(pVM, &pPGM->StatGCInvalidatePagePDNAs, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/PDNAs", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for a not accessed page directory.");
STAM_REG(pVM, &pPGM->StatGCInvalidatePagePDNPs, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/PDNPs", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for a not present page directory.");
STAM_REG(pVM, &pPGM->StatGCInvalidatePagePDOutOfSync, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/PDOutOfSync", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for an out of sync page directory.");
STAM_REG(pVM, &pPGM->StatGCInvalidatePageSkipped, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/Skipped", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was skipped due to not present shw or pending pending SyncCR3.");
STAM_REG(pVM, &pPGM->StatGCSyncPT, STAMTYPE_PROFILE, "/PGM/GC/SyncPT", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMGCSyncPT() body.");
STAM_REG(pVM, &pPGM->StatGCAccessedPage, STAMTYPE_COUNTER, "/PGM/GC/AccessedPage", STAMUNIT_OCCURENCES, "The number of pages marked not present for accessed bit emulation.");
STAM_REG(pVM, &pPGM->StatGCDirtyPage, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/Mark", STAMUNIT_OCCURENCES, "The number of pages marked read-only for dirty bit tracking.");
STAM_REG(pVM, &pPGM->StatGCDirtyPageBig, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/MarkBig", STAMUNIT_OCCURENCES, "The number of 4MB pages marked read-only for dirty bit tracking.");
STAM_REG(pVM, &pPGM->StatGCDirtyPageTrap, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/Trap", STAMUNIT_OCCURENCES, "The number of traps generated for dirty bit tracking.");
STAM_REG(pVM, &pPGM->StatGCDirtyPageSkipped, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/Skipped", STAMUNIT_OCCURENCES, "The number of pages already dirty or readonly.");
STAM_REG(pVM, &pPGM->StatGCDirtiedPage, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/SetDirty", STAMUNIT_OCCURENCES, "The number of pages marked dirty because of write accesses.");
STAM_REG(pVM, &pPGM->StatGCDirtyTrackRealPF, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/RealPF", STAMUNIT_OCCURENCES, "The number of real pages faults during dirty bit tracking.");
STAM_REG(pVM, &pPGM->StatGCPageAlreadyDirty, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/AlreadySet", STAMUNIT_OCCURENCES, "The number of pages already marked dirty because of write accesses.");
STAM_REG(pVM, &pPGM->StatGCDirtyBitTracking, STAMTYPE_PROFILE, "/PGM/GC/DirtyPage", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMTrackDirtyBit() body.");
STAM_REG(pVM, &pPGM->StatGCSyncPTAlloc, STAMTYPE_COUNTER, "/PGM/GC/SyncPT/Alloc", STAMUNIT_OCCURENCES, "The number of times PGMGCSyncPT() needed to allocate page tables.");
STAM_REG(pVM, &pPGM->StatGCSyncPTConflict, STAMTYPE_COUNTER, "/PGM/GC/SyncPT/Conflicts", STAMUNIT_OCCURENCES, "The number of times PGMGCSyncPT() detected conflicts.");
STAM_REG(pVM, &pPGM->StatGCSyncPTFailed, STAMTYPE_COUNTER, "/PGM/GC/SyncPT/Failed", STAMUNIT_OCCURENCES, "The number of times PGMGCSyncPT() failed.");
STAM_REG(pVM, &pPGM->StatGCTrap0e, STAMTYPE_PROFILE, "/PGM/GC/Trap0e", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMGCTrap0eHandler() body.");
STAM_REG(pVM, &pPGM->StatCheckPageFault, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/CheckPageFault", STAMUNIT_TICKS_PER_CALL, "Profiling of checking for dirty/access emulation faults.");
STAM_REG(pVM, &pPGM->StatLazySyncPT, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/SyncPT", STAMUNIT_TICKS_PER_CALL, "Profiling of lazy page table syncing.");
STAM_REG(pVM, &pPGM->StatMapping, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/Mapping", STAMUNIT_TICKS_PER_CALL, "Profiling of checking virtual mappings.");
STAM_REG(pVM, &pPGM->StatOutOfSync, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/OutOfSync", STAMUNIT_TICKS_PER_CALL, "Profiling of out of sync page handling.");
STAM_REG(pVM, &pPGM->StatHandlers, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/Handlers", STAMUNIT_TICKS_PER_CALL, "Profiling of checking handlers.");
STAM_REG(pVM, &pPGM->StatEIPHandlers, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/EIPHandlers", STAMUNIT_TICKS_PER_CALL, "Profiling of checking eip handlers.");
STAM_REG(pVM, &pPGM->StatTrap0eCSAM, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/CSAM", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is CSAM.");
STAM_REG(pVM, &pPGM->StatTrap0eDirtyAndAccessedBits, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/DirtyAndAccessedBits", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is dirty and/or accessed bit emulation.");
STAM_REG(pVM, &pPGM->StatTrap0eGuestTrap, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/GuestTrap", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is a guest trap.");
STAM_REG(pVM, &pPGM->StatTrap0eHndPhys, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/HandlerPhysical", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is a physical handler.");
STAM_REG(pVM, &pPGM->StatTrap0eHndVirt, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/HandlerVirtual",STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is a virtual handler.");
STAM_REG(pVM, &pPGM->StatTrap0eHndUnhandled, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/HandlerUnhandled", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is access outside the monitored areas of a monitored page.");
STAM_REG(pVM, &pPGM->StatTrap0eMisc, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/Misc", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is not known.");
STAM_REG(pVM, &pPGM->StatTrap0eOutOfSync, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/OutOfSync", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is an out-of-sync page.");
STAM_REG(pVM, &pPGM->StatTrap0eOutOfSyncHndPhys, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/OutOfSyncHndPhys", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is an out-of-sync physical handler page.");
STAM_REG(pVM, &pPGM->StatTrap0eOutOfSyncHndVirt, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/OutOfSyncHndVirt", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is an out-of-sync virtual handler page.");
STAM_REG(pVM, &pPGM->StatTrap0eOutOfSyncObsHnd, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/OutOfSyncObsHnd", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is an obsolete handler page.");
STAM_REG(pVM, &pPGM->StatTrap0eSyncPT, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/SyncPT", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is lazy syncing of a PT.");
STAM_REG(pVM, &pPGM->StatTrap0eMapHandler, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/Mapping", STAMUNIT_OCCURENCES, "Number of traps due to access handlers in mappings.");
STAM_REG(pVM, &pPGM->StatHandlersOutOfSync, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/OutOfSync", STAMUNIT_OCCURENCES, "Number of traps due to out-of-sync handled pages.");
STAM_REG(pVM, &pPGM->StatHandlersPhysical, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/Physical", STAMUNIT_OCCURENCES, "Number of traps due to physical access handlers.");
STAM_REG(pVM, &pPGM->StatHandlersVirtual, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/Virtual", STAMUNIT_OCCURENCES, "Number of traps due to virtual access handlers.");
STAM_REG(pVM, &pPGM->StatHandlersVirtualByPhys, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/VirtualByPhys", STAMUNIT_OCCURENCES, "Number of traps due to virtual access handlers by physical address.");
STAM_REG(pVM, &pPGM->StatHandlersVirtualUnmarked, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/VirtualUnmarked", STAMUNIT_OCCURENCES,"Number of traps due to virtual access handlers by virtual address (without proper physical flags).");
STAM_REG(pVM, &pPGM->StatHandlersUnhandled, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/Unhandled", STAMUNIT_OCCURENCES, "Number of traps due to access outside range of monitored page(s).");
STAM_REG(pVM, &pPGM->StatGCTrap0eConflicts, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Conflicts", STAMUNIT_OCCURENCES, "The number of times #PF was caused by an undetected conflict.");
STAM_REG(pVM, &pPGM->StatGCTrap0eUSNotPresentRead, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/User/NPRead", STAMUNIT_OCCURENCES, "Number of user mode not present read page faults.");
STAM_REG(pVM, &pPGM->StatGCTrap0eUSNotPresentWrite, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/User/NPWrite", STAMUNIT_OCCURENCES, "Number of user mode not present write page faults.");
STAM_REG(pVM, &pPGM->StatGCTrap0eUSWrite, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/User/Write", STAMUNIT_OCCURENCES, "Number of user mode write page faults.");
STAM_REG(pVM, &pPGM->StatGCTrap0eUSReserved, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/User/Reserved", STAMUNIT_OCCURENCES, "Number of user mode reserved bit page faults.");
STAM_REG(pVM, &pPGM->StatGCTrap0eUSRead, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/User/Read", STAMUNIT_OCCURENCES, "Number of user mode read page faults.");
STAM_REG(pVM, &pPGM->StatGCTrap0eSVNotPresentRead, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Supervisor/NPRead", STAMUNIT_OCCURENCES, "Number of supervisor mode not present read page faults.");
STAM_REG(pVM, &pPGM->StatGCTrap0eSVNotPresentWrite, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Supervisor/NPWrite", STAMUNIT_OCCURENCES, "Number of supervisor mode not present write page faults.");
STAM_REG(pVM, &pPGM->StatGCTrap0eSVWrite, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Supervisor/Write", STAMUNIT_OCCURENCES, "Number of supervisor mode write page faults.");
STAM_REG(pVM, &pPGM->StatGCTrap0eSVReserved, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Supervisor/Reserved", STAMUNIT_OCCURENCES, "Number of supervisor mode reserved bit page faults.");
STAM_REG(pVM, &pPGM->StatGCTrap0eUnhandled, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/GuestPF/Unhandled", STAMUNIT_OCCURENCES, "Number of guest real page faults.");
STAM_REG(pVM, &pPGM->StatGCTrap0eMap, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/GuestPF/Map", STAMUNIT_OCCURENCES, "Number of guest page faults due to map accesses.");
STAM_REG(pVM, &pPGM->StatGCGuestCR3WriteHandled, STAMTYPE_COUNTER, "/PGM/GC/CR3WriteInt", STAMUNIT_OCCURENCES, "The number of times the Guest CR3 change was successfully handled.");
STAM_REG(pVM, &pPGM->StatGCGuestCR3WriteUnhandled, STAMTYPE_COUNTER, "/PGM/GC/CR3WriteEmu", STAMUNIT_OCCURENCES, "The number of times the Guest CR3 change was passed back to the recompiler.");
STAM_REG(pVM, &pPGM->StatGCGuestCR3WriteConflict, STAMTYPE_COUNTER, "/PGM/GC/CR3WriteConflict", STAMUNIT_OCCURENCES, "The number of times the Guest CR3 monitoring detected a conflict.");
STAM_REG(pVM, &pPGM->StatGCPageOutOfSyncSupervisor, STAMTYPE_COUNTER, "/PGM/GC/OutOfSync/SuperVisor", STAMUNIT_OCCURENCES, "Number of traps due to pages out of sync.");
STAM_REG(pVM, &pPGM->StatGCPageOutOfSyncUser, STAMTYPE_COUNTER, "/PGM/GC/OutOfSync/User", STAMUNIT_OCCURENCES, "Number of traps due to pages out of sync.");
STAM_REG(pVM, &pPGM->StatGCGuestROMWriteHandled, STAMTYPE_COUNTER, "/PGM/GC/ROMWriteInt", STAMUNIT_OCCURENCES, "The number of times the Guest ROM change was successfully handled.");
STAM_REG(pVM, &pPGM->StatGCGuestROMWriteUnhandled, STAMTYPE_COUNTER, "/PGM/GC/ROMWriteEmu", STAMUNIT_OCCURENCES, "The number of times the Guest ROM change was passed back to the recompiler.");
STAM_REG(pVM, &pPGM->StatDynMapCacheHits, STAMTYPE_COUNTER, "/PGM/GC/DynMapCache/Hits" , STAMUNIT_OCCURENCES, "Number of dynamic page mapping cache hits.");
STAM_REG(pVM, &pPGM->StatDynMapCacheMisses, STAMTYPE_COUNTER, "/PGM/GC/DynMapCache/Misses" , STAMUNIT_OCCURENCES, "Number of dynamic page mapping cache misses.");
STAM_REG(pVM, &pPGM->StatHCDetectedConflicts, STAMTYPE_COUNTER, "/PGM/HC/DetectedConflicts", STAMUNIT_OCCURENCES, "The number of times PGMR3CheckMappingConflicts() detected a conflict.");
STAM_REG(pVM, &pPGM->StatHCGuestPDWrite, STAMTYPE_COUNTER, "/PGM/HC/PDWrite", STAMUNIT_OCCURENCES, "The total number of times pgmHCGuestPDWriteHandler() was called.");
STAM_REG(pVM, &pPGM->StatHCGuestPDWriteConflict, STAMTYPE_COUNTER, "/PGM/HC/PDWriteConflict", STAMUNIT_OCCURENCES, "The number of times pgmHCGuestPDWriteHandler() detected a conflict.");
STAM_REG(pVM, &pPGM->StatHCInvalidatePage, STAMTYPE_PROFILE, "/PGM/HC/InvalidatePage", STAMUNIT_TICKS_PER_CALL, "PGMHCInvalidatePage() profiling.");
STAM_REG(pVM, &pPGM->StatHCInvalidatePage4KBPages, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/4KBPages", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was called for a 4KB page.");
STAM_REG(pVM, &pPGM->StatHCInvalidatePage4MBPages, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/4MBPages", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was called for a 4MB page.");
STAM_REG(pVM, &pPGM->StatHCInvalidatePage4MBPagesSkip, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/4MBPagesSkip",STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() skipped a 4MB page.");
STAM_REG(pVM, &pPGM->StatHCInvalidatePagePDMappings, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/PDMappings", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was called for a page directory containing mappings (no conflict).");
STAM_REG(pVM, &pPGM->StatHCInvalidatePagePDNAs, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/PDNAs", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was called for a not accessed page directory.");
STAM_REG(pVM, &pPGM->StatHCInvalidatePagePDNPs, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/PDNPs", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was called for a not present page directory.");
STAM_REG(pVM, &pPGM->StatHCInvalidatePagePDOutOfSync, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/PDOutOfSync", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for an out of sync page directory.");
STAM_REG(pVM, &pPGM->StatHCInvalidatePageSkipped, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/Skipped", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was skipped due to not present shw or pending pending SyncCR3.");
STAM_REG(pVM, &pPGM->StatHCResolveConflict, STAMTYPE_PROFILE, "/PGM/HC/ResolveConflict", STAMUNIT_TICKS_PER_CALL, "pgmR3SyncPTResolveConflict() profiling (includes the entire relocation).");
STAM_REG(pVM, &pPGM->StatHCPrefetch, STAMTYPE_PROFILE, "/PGM/HC/Prefetch", STAMUNIT_TICKS_PER_CALL, "PGMR3PrefetchPage profiling.");
STAM_REG(pVM, &pPGM->StatHCSyncPT, STAMTYPE_PROFILE, "/PGM/HC/SyncPT", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMR3SyncPT() body.");
STAM_REG(pVM, &pPGM->StatHCAccessedPage, STAMTYPE_COUNTER, "/PGM/HC/AccessedPage", STAMUNIT_OCCURENCES, "The number of pages marked not present for accessed bit emulation.");
STAM_REG(pVM, &pPGM->StatHCDirtyPage, STAMTYPE_COUNTER, "/PGM/HC/DirtyPage/Mark", STAMUNIT_OCCURENCES, "The number of pages marked read-only for dirty bit tracking.");
STAM_REG(pVM, &pPGM->StatHCDirtyPageBig, STAMTYPE_COUNTER, "/PGM/HC/DirtyPage/MarkBig", STAMUNIT_OCCURENCES, "The number of 4MB pages marked read-only for dirty bit tracking.");
STAM_REG(pVM, &pPGM->StatHCDirtyPageTrap, STAMTYPE_COUNTER, "/PGM/HC/DirtyPage/Trap", STAMUNIT_OCCURENCES, "The number of traps generated for dirty bit tracking.");
STAM_REG(pVM, &pPGM->StatHCDirtyPageSkipped, STAMTYPE_COUNTER, "/PGM/HC/DirtyPage/Skipped", STAMUNIT_OCCURENCES, "The number of pages already dirty or readonly.");
STAM_REG(pVM, &pPGM->StatHCDirtyBitTracking, STAMTYPE_PROFILE, "/PGM/HC/DirtyPage", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMTrackDirtyBit() body.");
STAM_REG(pVM, &pPGM->StatGCSyncPagePDNAs, STAMTYPE_COUNTER, "/PGM/GC/SyncPagePDNAs", STAMUNIT_OCCURENCES, "The number of time we've marked a PD not present from SyncPage to virtualize the accessed bit.");
STAM_REG(pVM, &pPGM->StatGCSyncPagePDOutOfSync, STAMTYPE_COUNTER, "/PGM/GC/SyncPagePDOutOfSync", STAMUNIT_OCCURENCES, "The number of time we've encountered an out-of-sync PD in SyncPage.");
STAM_REG(pVM, &pPGM->StatHCSyncPagePDNAs, STAMTYPE_COUNTER, "/PGM/HC/SyncPagePDNAs", STAMUNIT_OCCURENCES, "The number of time we've marked a PD not present from SyncPage to virtualize the accessed bit.");
STAM_REG(pVM, &pPGM->StatHCSyncPagePDOutOfSync, STAMTYPE_COUNTER, "/PGM/HC/SyncPagePDOutOfSync", STAMUNIT_OCCURENCES, "The number of time we've encountered an out-of-sync PD in SyncPage.");
STAM_REG(pVM, &pPGM->StatFlushTLB, STAMTYPE_PROFILE, "/PGM/FlushTLB", STAMUNIT_OCCURENCES, "Profiling of the PGMFlushTLB() body.");
STAM_REG(pVM, &pPGM->StatFlushTLBNewCR3, STAMTYPE_COUNTER, "/PGM/FlushTLB/NewCR3", STAMUNIT_OCCURENCES, "The number of times PGMFlushTLB was called with a new CR3, non-global. (switch)");
STAM_REG(pVM, &pPGM->StatFlushTLBNewCR3Global, STAMTYPE_COUNTER, "/PGM/FlushTLB/NewCR3Global", STAMUNIT_OCCURENCES, "The number of times PGMFlushTLB was called with a new CR3, global. (switch)");
STAM_REG(pVM, &pPGM->StatFlushTLBSameCR3, STAMTYPE_COUNTER, "/PGM/FlushTLB/SameCR3", STAMUNIT_OCCURENCES, "The number of times PGMFlushTLB was called with the same CR3, non-global. (flush)");
STAM_REG(pVM, &pPGM->StatFlushTLBSameCR3Global, STAMTYPE_COUNTER, "/PGM/FlushTLB/SameCR3Global", STAMUNIT_OCCURENCES, "The number of times PGMFlushTLB was called with the same CR3, global. (flush)");
STAM_REG(pVM, &pPGM->StatGCSyncCR3, STAMTYPE_PROFILE, "/PGM/GC/SyncCR3", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMSyncCR3() body.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3Handlers, STAMTYPE_PROFILE, "/PGM/GC/SyncCR3/Handlers", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMSyncCR3() update handler section.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3HandlerVirtualUpdate, STAMTYPE_PROFILE, "/PGM/GC/SyncCR3/Handlers/VirtualUpdate",STAMUNIT_TICKS_PER_CALL, "Profiling of the virtual handler updates.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3HandlerVirtualReset, STAMTYPE_PROFILE, "/PGM/GC/SyncCR3/Handlers/VirtualReset", STAMUNIT_TICKS_PER_CALL, "Profiling of the virtual handler resets.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3Global, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/Global", STAMUNIT_OCCURENCES, "The number of global CR3 syncs.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3NotGlobal, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/NotGlobal", STAMUNIT_OCCURENCES, "The number of non-global CR3 syncs.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3DstCacheHit, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstChacheHit", STAMUNIT_OCCURENCES, "The number of times we got some kind of a cache hit.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3DstFreed, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstFreed", STAMUNIT_OCCURENCES, "The number of times we've had to free a shadow entry.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3DstFreedSrcNP, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstFreedSrcNP", STAMUNIT_OCCURENCES, "The number of times we've had to free a shadow entry for which the source entry was not present.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3DstNotPresent, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstNotPresent", STAMUNIT_OCCURENCES, "The number of times we've encountered a not present shadow entry for a present guest entry.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3DstSkippedGlobalPD, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstSkippedGlobalPD", STAMUNIT_OCCURENCES, "The number of times a global page directory wasn't flushed.");
STAM_REG(pVM, &pPGM->StatGCSyncCR3DstSkippedGlobalPT, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstSkippedGlobalPT", STAMUNIT_OCCURENCES, "The number of times a page table with only global entries wasn't flushed.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3, STAMTYPE_PROFILE, "/PGM/HC/SyncCR3", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMSyncCR3() body.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3Handlers, STAMTYPE_PROFILE, "/PGM/HC/SyncCR3/Handlers", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMSyncCR3() update handler section.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3HandlerVirtualUpdate, STAMTYPE_PROFILE, "/PGM/HC/SyncCR3/Handlers/VirtualUpdate",STAMUNIT_TICKS_PER_CALL, "Profiling of the virtual handler updates.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3HandlerVirtualReset, STAMTYPE_PROFILE, "/PGM/HC/SyncCR3/Handlers/VirtualReset", STAMUNIT_TICKS_PER_CALL, "Profiling of the virtual handler resets.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3Global, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/Global", STAMUNIT_OCCURENCES, "The number of global CR3 syncs.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3NotGlobal, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/NotGlobal", STAMUNIT_OCCURENCES, "The number of non-global CR3 syncs.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3DstCacheHit, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstChacheHit", STAMUNIT_OCCURENCES, "The number of times we got some kind of a cache hit.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3DstFreed, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstFreed", STAMUNIT_OCCURENCES, "The number of times we've had to free a shadow entry.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3DstFreedSrcNP, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstFreedSrcNP", STAMUNIT_OCCURENCES, "The number of times we've had to free a shadow entry for which the source entry was not present.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3DstNotPresent, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstNotPresent", STAMUNIT_OCCURENCES, "The number of times we've encountered a not present shadow entry for a present guest entry.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3DstSkippedGlobalPD, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstSkippedGlobalPD", STAMUNIT_OCCURENCES, "The number of times a global page directory wasn't flushed.");
STAM_REG(pVM, &pPGM->StatHCSyncCR3DstSkippedGlobalPT, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstSkippedGlobalPT", STAMUNIT_OCCURENCES, "The number of times a page table with only global entries wasn't flushed.");
STAM_REG(pVM, &pPGM->StatVirtHandleSearchByPhysGC, STAMTYPE_PROFILE, "/PGM/VirtHandler/SearchByPhys/GC", STAMUNIT_TICKS_PER_CALL, "Profiling of pgmHandlerVirtualFindByPhysAddr in GC.");
STAM_REG(pVM, &pPGM->StatVirtHandleSearchByPhysHC, STAMTYPE_PROFILE, "/PGM/VirtHandler/SearchByPhys/HC", STAMUNIT_TICKS_PER_CALL, "Profiling of pgmHandlerVirtualFindByPhysAddr in HC.");
STAM_REG(pVM, &pPGM->StatHandlePhysicalReset, STAMTYPE_COUNTER, "/PGM/HC/HandlerPhysicalReset", STAMUNIT_OCCURENCES, "The number of times PGMR3HandlerPhysicalReset is called.");
STAM_REG(pVM, &pPGM->StatHCGstModifyPage, STAMTYPE_PROFILE, "/PGM/HC/GstModifyPage", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMGstModifyPage() body.");
STAM_REG(pVM, &pPGM->StatGCGstModifyPage, STAMTYPE_PROFILE, "/PGM/GC/GstModifyPage", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMGstModifyPage() body.");
STAM_REG(pVM, &pPGM->StatSynPT4kGC, STAMTYPE_COUNTER, "/PGM/GC/SyncPT/4k", STAMUNIT_OCCURENCES, "Nr of 4k PT syncs");
STAM_REG(pVM, &pPGM->StatSynPT4kHC, STAMTYPE_COUNTER, "/PGM/HC/SyncPT/4k", STAMUNIT_OCCURENCES, "Nr of 4k PT syncs");
STAM_REG(pVM, &pPGM->StatSynPT4MGC, STAMTYPE_COUNTER, "/PGM/GC/SyncPT/4M", STAMUNIT_OCCURENCES, "Nr of 4M PT syncs");
STAM_REG(pVM, &pPGM->StatSynPT4MHC, STAMTYPE_COUNTER, "/PGM/HC/SyncPT/4M", STAMUNIT_OCCURENCES, "Nr of 4M PT syncs");
STAM_REG(pVM, &pPGM->StatDynRamTotal, STAMTYPE_COUNTER, "/PGM/RAM/TotalAlloc", STAMUNIT_MEGABYTES, "Allocated mbs of guest ram.");
STAM_REG(pVM, &pPGM->StatDynRamGrow, STAMTYPE_COUNTER, "/PGM/RAM/Grow", STAMUNIT_OCCURENCES, "Nr of pgmr3PhysGrowRange calls.");
STAM_REG(pVM, &pPGM->StatPageHCMapTlbHits, STAMTYPE_COUNTER, "/PGM/PageHCMap/TlbHits", STAMUNIT_OCCURENCES, "TLB hits.");
STAM_REG(pVM, &pPGM->StatPageHCMapTlbMisses, STAMTYPE_COUNTER, "/PGM/PageHCMap/TlbMisses", STAMUNIT_OCCURENCES, "TLB misses.");
STAM_REG(pVM, &pPGM->ChunkR3Map.c, STAMTYPE_U32, "/PGM/ChunkR3Map/c", STAMUNIT_OCCURENCES, "Number of mapped chunks.");
STAM_REG(pVM, &pPGM->ChunkR3Map.cMax, STAMTYPE_U32, "/PGM/ChunkR3Map/cMax", STAMUNIT_OCCURENCES, "Maximum number of mapped chunks.");
STAM_REG(pVM, &pPGM->StatChunkR3MapTlbHits, STAMTYPE_COUNTER, "/PGM/ChunkR3Map/TlbHits", STAMUNIT_OCCURENCES, "TLB hits.");
STAM_REG(pVM, &pPGM->StatChunkR3MapTlbMisses, STAMTYPE_COUNTER, "/PGM/ChunkR3Map/TlbMisses", STAMUNIT_OCCURENCES, "TLB misses.");
STAM_REG(pVM, &pPGM->StatPageReplaceShared, STAMTYPE_COUNTER, "/PGM/Page/ReplacedShared", STAMUNIT_OCCURENCES, "Times a shared page was replaced.");
STAM_REG(pVM, &pPGM->StatPageReplaceZero, STAMTYPE_COUNTER, "/PGM/Page/ReplacedZero", STAMUNIT_OCCURENCES, "Times the zero page was replaced.");
STAM_REG(pVM, &pPGM->StatPageHandyAllocs, STAMTYPE_COUNTER, "/PGM/Page/HandyAllocs", STAMUNIT_OCCURENCES, "Number of times we've allocated more handy pages.");
STAM_REG(pVM, &pPGM->cAllPages, STAMTYPE_U32, "/PGM/Page/cAllPages", STAMUNIT_OCCURENCES, "The total number of pages.");
STAM_REG(pVM, &pPGM->cPrivatePages, STAMTYPE_U32, "/PGM/Page/cPrivatePages", STAMUNIT_OCCURENCES, "The number of private pages.");
STAM_REG(pVM, &pPGM->cSharedPages, STAMTYPE_U32, "/PGM/Page/cSharedPages", STAMUNIT_OCCURENCES, "The number of shared pages.");
STAM_REG(pVM, &pPGM->cZeroPages, STAMTYPE_U32, "/PGM/Page/cZeroPages", STAMUNIT_OCCURENCES, "The number of zero backed pages.");
#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
STAM_REG(pVM, &pPGM->StatTrackVirgin, STAMTYPE_COUNTER, "/PGM/Track/Virgin", STAMUNIT_OCCURENCES, "The number of first time shadowings");
STAM_REG(pVM, &pPGM->StatTrackAliased, STAMTYPE_COUNTER, "/PGM/Track/Aliased", STAMUNIT_OCCURENCES, "The number of times switching to cRef2, i.e. the page is being shadowed by two PTs.");
STAM_REG(pVM, &pPGM->StatTrackAliasedMany, STAMTYPE_COUNTER, "/PGM/Track/AliasedMany", STAMUNIT_OCCURENCES, "The number of times we're tracking using cRef2.");
STAM_REG(pVM, &pPGM->StatTrackAliasedLots, STAMTYPE_COUNTER, "/PGM/Track/AliasedLots", STAMUNIT_OCCURENCES, "The number of times we're hitting pages which has overflowed cRef2");
STAM_REG(pVM, &pPGM->StatTrackOverflows, STAMTYPE_COUNTER, "/PGM/Track/Overflows", STAMUNIT_OCCURENCES, "The number of times the extent list grows to long.");
STAM_REG(pVM, &pPGM->StatTrackDeref, STAMTYPE_PROFILE, "/PGM/Track/Deref", STAMUNIT_OCCURENCES, "Profiling of SyncPageWorkerTrackDeref (expensive).");
for (unsigned i = 0; i < PAGE_ENTRIES; i++)
int rc = STAMR3Register(pVM, &pPGM->StatGCTrap0ePD[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, "The number of traps in page directory n.");
rc = STAMR3Register(pVM, &pPGM->StatGCSyncPtPD[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, "The number of syncs per PD n.");
rc = STAMR3Register(pVM, &pPGM->StatGCSyncPagePD[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, "The number of out of sync pages per page directory n.");
int rc = MMR3HyperReserve(pVM, PAGE_SIZE * (2 + ELEMENTS(pVM->pgm.s.apHCPaePDs) + 1 + 2 + 2), "Paging", &pVM->pgm.s.pGC32BitPD);
/** @todo r=bird: Need to verify that the checks for crossing PTs are correct here. They seems to be assuming 4MB PTs.. */
rc = MMR3HyperReserve(pVM, MM_HYPER_DYNAMIC_SIZE, "Dynamic mapping", &pVM->pgm.s.pbDynPageMapBaseGC);
&& (pVM->pgm.s.pbDynPageMapBaseGC >> PGDIR_SHIFT) != ((pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE - 1) >> PGDIR_SHIFT))
rc = MMR3HyperReserve(pVM, MM_HYPER_DYNAMIC_SIZE, "Dynamic mapping not crossing", &pVM->pgm.s.pbDynPageMapBaseGC);
AssertRelease((pVM->pgm.s.pbDynPageMapBaseGC >> PGDIR_SHIFT) == ((pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE - 1) >> PGDIR_SHIFT));
return rc;
AssertRelease((RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[0] + PAGE_SIZE == (RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[1]);
AssertRelease((RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[1] + PAGE_SIZE == (RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[2]);
AssertRelease((RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[2] + PAGE_SIZE == (RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[3]);
pVM->pgm.s.paDynPageMap32BitPTEsGC = pMapping->aPTs[iPT].pPTGC + iPG * sizeof(pMapping->aPTs[0].pPTR3->a[0]);
pVM->pgm.s.paDynPageMapPaePTEsGC = pMapping->aPTs[iPT].paPaePTsGC + iPG * sizeof(pMapping->aPTs[0].paPaePTsR3->a[0]);
return rc;
RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysHandlers, true, pgmR3RelocatePhysHandler, &offDelta);
RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesHC->VirtHandlers, true, pgmR3RelocateVirtHandler, &offDelta);
#ifdef DEBUG
while (iPage-- > 0)
if (pRam->aPages[iPage].HCPhys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_MMIO2)) /** @todo PAGE FLAGS */
Log4(("PGMR3Reset: not clearing phys page %RGp due to flags %RHp\n", pRam->GCPhys + (iPage << PAGE_SHIFT), pRam->aPages[iPage].HCPhys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO))); /** @todo PAGE FLAGS */
ASMMemZero32((char *)pRam->pavHCChunkHC[iChunk] + ((iPage << PAGE_SHIFT) & PGM_DYNAMIC_CHUNK_OFFSET_MASK), PAGE_SIZE);
#ifdef VBOX_STRICT
static DECLCALLBACK(void) pgmR3ResetNoMorePhysWritesFlag(PVM pVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser)
uint32_t i = 0;
SSMR3PutU16(pSSM, (uint16_t)(pRam->aPages[iPage].HCPhys & ~X86_PTE_PAE_PG_MASK)); /** @todo PAGE FLAGS */
return rc;
Log(("pgmR3Load: Invalid version u32Version=%d (current %d)!\n", u32Version, PGM_SAVED_STATE_VERSION));
uint32_t u;
return rc;
return rc;
uint32_t i = 0;
return rc;
if (u32Sep == ~0U)
if (u32Sep != i)
return rc;
return rc;
if (!pMapping)
AssertFailed();
return VERR_SSM_LOAD_CONFIG_MISMATCH;
return rc;
if (u32Sep == ~0U)
if (u32Sep != i)
return rc;
while (cPages-- > 0)
u16 &= PAGE_OFFSET_MASK & ~( MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE | MM_RAM_FLAGS_VIRTUAL_ALL
pRam->aPages[iPage].HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) | (RTHCPHYS)u16; /** @todo PAGE FLAGS */
return rc;
if (fValidChunk)
return rc;
return rc;
if (pszArgs)
fGuest = true;
fShadow = true;
fHost = true;
if (fGuest)
if (fShadow)
if (fHost)
const char *psz;
pVM,
Assert(MMPhysGCPhys2HCVirt(pVM, (RTGCPHYS)(CPUMGetGuestCR3(pVM) & X86_CR3_PAGE_MASK), sizeof(*pPDSrc)) == pPDSrc);
iPD,
iPD,
switch (pgmMode)
case PGMMODE_PAE:
case PGMMODE_AMD64:
int rc;
pVM->pgm.s.paModeData = (PPGMMODEDATA)MMR3HeapAllocZ(pVM, MM_TAG_PGM, sizeof(PGMMODEDATA) * pgmModeDataMaxIndex());
return VINF_SUCCESS;
#ifdef VBOX_STRICT
#ifdef VBOX_STRICT
#ifdef VBOX_STRICT
#ifdef DEBUG_bird
static PGMMODE pgmR3CalcShadowMode(PGMMODE enmGuestMode, SUPPAGINGMODE enmHostMode, PGMMODE enmShadowMode, VMMSWITCHER *penmSwitcher)
switch (enmGuestMode)
case PGMMODE_REAL:
case PGMMODE_PROTECTED:
switch (enmHostMode)
case SUPPAGINGMODE_32_BIT:
case SUPPAGINGMODE_PAE:
case SUPPAGINGMODE_PAE_NX:
case SUPPAGINGMODE_PAE_GLOBAL:
#ifdef DEBUG_bird
case SUPPAGINGMODE_AMD64:
case SUPPAGINGMODE_AMD64_NX:
case PGMMODE_32_BIT:
switch (enmHostMode)
case SUPPAGINGMODE_32_BIT:
case SUPPAGINGMODE_PAE:
case SUPPAGINGMODE_PAE_NX:
case SUPPAGINGMODE_PAE_GLOBAL:
#ifdef DEBUG_bird
case SUPPAGINGMODE_AMD64:
case SUPPAGINGMODE_AMD64_NX:
case PGMMODE_PAE:
switch (enmHostMode)
case SUPPAGINGMODE_32_BIT:
case SUPPAGINGMODE_PAE:
case SUPPAGINGMODE_PAE_NX:
case SUPPAGINGMODE_PAE_GLOBAL:
case SUPPAGINGMODE_AMD64:
case SUPPAGINGMODE_AMD64_NX:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
switch (enmHostMode)
case SUPPAGINGMODE_32_BIT:
case SUPPAGINGMODE_PAE:
case SUPPAGINGMODE_PAE_NX:
case SUPPAGINGMODE_PAE_GLOBAL:
case SUPPAGINGMODE_AMD64:
case SUPPAGINGMODE_AMD64_NX:
return PGMMODE_INVALID;
return enmShadowMode;
PGMMODE enmShadowMode = pgmR3CalcShadowMode(enmGuestMode, pVM->pgm.s.enmHostMode, pVM->pgm.s.enmShadowMode, &enmSwitcher);
return rc;
return rc;
return rc;
int rc;
switch (enmShadowMode)
case PGMMODE_32_BIT:
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
case PGMMODE_REAL:
case PGMMODE_PROTECTED:
return VERR_INTERNAL_ERROR;
return rc;
switch (enmGuestMode)
case PGMMODE_REAL:
case PGMMODE_32_BIT:
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
default: AssertFailed(); break;
case PGMMODE_PROTECTED:
case PGMMODE_32_BIT:
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
default: AssertFailed(); break;
case PGMMODE_32_BIT:
case PGMMODE_32_BIT:
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
default: AssertFailed(); break;
case PGMMODE_PAE:
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
case PGMMODE_32_BIT:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
default: AssertFailed(); break;
case PGMMODE_AMD64:
GCPhysCR3 = CPUMGetGuestCR3(pVM) & 0xfffffffffffff000ULL; /** @todo define this mask and make CR3 64-bit in this case! */
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
case PGMMODE_32_BIT:
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
default: AssertFailed(); break;
return rc;
static int pgmR3DumpHierarchyHCPaePT(PVM pVM, PX86PTPAE pPT, uint64_t u64Address, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
return VINF_SUCCESS;
static int pgmR3DumpHierarchyHCPaePD(PVM pVM, RTHCPHYS HCPhys, uint64_t u64Address, uint32_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
if (!pPD)
pHlp->pfnPrintf(pHlp, "%0*llx error! Page directory at HCPhys=%#VHp was not found in the page pool!\n",
return VERR_INVALID_PARAMETER;
pHlp->pfnPrintf(pHlp, "%0*llx error! Mapping error! PT %d has HCPhysPT=%VHp not %VHp is in the PD.\n",
if (pPT)
return rc;
static int pgmR3DumpHierarchyHCPaePDPTR(PVM pVM, RTHCPHYS HCPhys, uint64_t u64Address, uint32_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
if (!pPDPTR)
pHlp->pfnPrintf(pHlp, "%0*llx error! Page directory pointer table at HCPhys=%#VHp was not found in the page pool!\n",
return VERR_INVALID_PARAMETER;
if (fLongMode)
i << X86_PDPTR_SHIFT,
int rc2 = pgmR3DumpHierarchyHCPaePD(pVM, Pdpe.u & X86_PDPE_PG_MASK, u64Address + ((uint64_t)i << X86_PDPTR_SHIFT),
return rc;
static int pgmR3DumpHierarchyHcPaePML4(PVM pVM, RTHCPHYS HCPhys, uint32_t cr4, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
if (!pPML4)
pHlp->pfnPrintf(pHlp, "Page map level 4 at HCPhys=%#VHp was not found in the page pool!\n", HCPhys);
return VERR_INVALID_PARAMETER;
uint64_t u64Address = ((uint64_t)i << X86_PML4_SHIFT) | (((uint64_t)i >> (X86_PML4_SHIFT - X86_PDPTR_SHIFT - 1)) * 0xffff000000000000ULL);
int rc2 = pgmR3DumpHierarchyHCPaePDPTR(pVM, Pml4e.u & X86_PML4E_PG_MASK, u64Address, cr4, true, cMaxDepth - 1, pHlp);
return rc;
return VINF_SUCCESS;
int pgmR3DumpHierarchyHC32BitPD(PVM pVM, uint32_t cr3, uint32_t cr4, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
if (!pPD)
pHlp->pfnPrintf(pHlp, "Page directory at %#x was not found in the page pool!\n", cr3 & X86_CR3_PAGE_MASK);
return VERR_INVALID_PARAMETER;
pHlp->pfnPrintf(pHlp, "%08x error! Mapping error! PT %d has HCPhysPT=%VHp not %VHp is in the PD.\n",
if (pPT)
pHlp->pfnPrintf(pHlp, "%08x error! Page table at %#x was not found in the page pool!\n", u32Address, HCPhys);
return rc;
Log(("Found %VGp at %VGv -> flags=%llx\n", PhysSearch, (RTGCPTR)(u32Address + (i << X86_PT_SHIFT)), fPageShw));
return VINF_SUCCESS;
bool fLongMode = false;
return VERR_INVALID_PARAMETER;
if (pPT)
return rc;
PGMR3DECL(int) PGMR3DumpHierarchyHC(PVM pVM, uint32_t cr3, uint32_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
if (!pHlp)
if (!cMaxDepth)
return VINF_SUCCESS;
if (fLongMode)
return pgmR3DumpHierarchyHCPaePDPTR(pVM, cr3 & X86_CR3_PAE_PAGE_MASK, 0, cr4, false, cMaxDepth, pHlp);
#ifdef VBOX_WITH_DEBUGGER
static DECLCALLBACK(int) pgmR3CmdRam(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
if (!pVM)
return rc;
return VINF_SUCCESS;
static DECLCALLBACK(int) pgmR3CmdMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
if (!pVM)
int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, pVM->pgm.s.fMappingsFixed ? "The mappings are FIXED.\n" : "The mappings are FLOATING.\n");
return rc;
return rc;
return VINF_SUCCESS;
static DECLCALLBACK(int) pgmR3CmdSync(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
if (!pVM)
return rc;
return VINF_SUCCESS;
static DECLCALLBACK(int) pgmR3CmdSyncAlways(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
if (!pVM)
typedef struct PGMCHECKINTARGS
static DECLCALLBACK(int) pgmR3CheckIntegrityPhysHandlerNode(PAVLROGCPHYSNODECORE pNode, void *pvUser)
AssertReleaseMsg(pCur->Core.Key <= pCur->Core.KeyLast,("pCur=%p %VGp-%VGp %s\n", pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
|| (pArgs->fLeftToRight ? pArgs->pPrevPhys->Core.KeyLast < pCur->Core.Key : pArgs->pPrevPhys->Core.KeyLast > pCur->Core.Key),
pArgs->pPrevPhys, pArgs->pPrevPhys->Core.Key, pArgs->pPrevPhys->Core.KeyLast, pArgs->pPrevPhys->pszDesc,
static DECLCALLBACK(int) pgmR3CheckIntegrityVirtHandlerNode(PAVLROGCPTRNODECORE pNode, void *pvUser)
AssertReleaseMsg(pCur->Core.Key <= pCur->Core.KeyLast,("pCur=%p %VGv-%VGv %s\n", pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
|| (pArgs->fLeftToRight ? pArgs->pPrevVirt->Core.KeyLast < pCur->Core.Key : pArgs->pPrevVirt->Core.KeyLast > pCur->Core.Key),
pArgs->pPrevVirt, pArgs->pPrevVirt->Core.Key, pArgs->pPrevVirt->Core.KeyLast, pArgs->pPrevVirt->pszDesc,
AssertReleaseMsg(pCur->aPhysToVirt[iPage].offVirtHandler == -RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[iPage]),
static DECLCALLBACK(int) pgmR3CheckIntegrityPhysToVirtHandlerNode(PAVLROGCPHYSNODECORE pNode, void *pvUser)
AssertReleaseMsg(pCur->Core.Key <= pCur->Core.KeyLast,("pCur=%p %VGp-%VGp\n", pCur, pCur->Core.Key, pCur->Core.KeyLast));
|| (pArgs->fLeftToRight ? pArgs->pPrevPhys2Virt->Core.KeyLast < pCur->Core.Key : pArgs->pPrevPhys2Virt->Core.KeyLast > pCur->Core.Key),
|| (pArgs->fLeftToRight ? pArgs->pPrevPhys2Virt->Core.KeyLast < pCur->Core.Key : pArgs->pPrevPhys2Virt->Core.KeyLast > pCur->Core.Key),
AssertReleaseMsg((pCur->offNextAlias & (PGMPHYS2VIRTHANDLER_IN_TREE | PGMPHYS2VIRTHANDLER_IS_HEAD)) == (PGMPHYS2VIRTHANDLER_IN_TREE | PGMPHYS2VIRTHANDLER_IS_HEAD),
pCur2 = (PPGMPHYS2VIRTHANDLER)((intptr_t)pCur + (pCur->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
AssertReleaseMsg((pCur2->offNextAlias & (PGMPHYS2VIRTHANDLER_IN_TREE | PGMPHYS2VIRTHANDLER_IS_HEAD)) == PGMPHYS2VIRTHANDLER_IN_TREE,
int cErrors = 0;
cErrors += RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysHandlers, true, pgmR3CheckIntegrityPhysHandlerNode, &Args);
cErrors += RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysHandlers, false, pgmR3CheckIntegrityPhysHandlerNode, &Args);
cErrors += RTAvlroGCPtrDoWithAll( &pVM->pgm.s.pTreesHC->VirtHandlers, true, pgmR3CheckIntegrityVirtHandlerNode, &Args);
cErrors += RTAvlroGCPtrDoWithAll( &pVM->pgm.s.pTreesHC->VirtHandlers, false, pgmR3CheckIntegrityVirtHandlerNode, &Args);
cErrors += RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysToVirtHandlers, true, pgmR3CheckIntegrityPhysToVirtHandlerNode, &Args);
cErrors += RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysToVirtHandlers, false, pgmR3CheckIntegrityPhysToVirtHandlerNode, &Args);
return VINF_SUCCESS;