PGMAllPhys.cpp revision a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fc
1276N/A * PGM - Page Manager and Monitor, Physical Memory Addressing. 294N/A * Copyright (C) 2006-2007 innotek GmbH 919N/A * This file is part of VirtualBox Open Source Edition (OSE), as 919N/A * you can redistribute it and/or modify it under the terms of the GNU 919N/A * General Public License (GPL) as published by the Free Software 919N/A * Foundation, in version 2 as it comes in the "COPYING" file of the 919N/A * VirtualBox OSE distribution. VirtualBox OSE is distributed in the 919N/A * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 919N/A/** @def PGM_IGNORE_RAM_FLAGS_RESERVED 919N/A * Don't respect the MM_RAM_FLAGS_RESERVED flag when converting to HC addresses. 919N/A * Since this flag is currently incorrectly kept set for ROM regions we will 919N/A * have to ignore it for now so we don't break stuff. 919N/A * @todo this has been fixed now I believe, remove this hack. 493N/A/******************************************************************************* 970N/A*******************************************************************************/ 294N/A * Checks if Address Gate 20 is enabled or not. 970N/A * @returns true if enabled. 970N/A * @returns false if disabled. 970N/A * @param pVM VM handle. 294N/A * Validates a GC physical address. * @returns false if invalid. * @param pVM The VM handle. * @param GCPhys The physical address to validate. * Checks if a GC physical address is a normal page, * i.e. not ROM, MMIO or reserved. * @returns true if normal. * @returns false if invalid, ROM, MMIO or reserved page. * @param pVM The VM handle. * @param GCPhys The physical address to check. * Converts a GC physical address to a HC physical address. * @returns VINF_SUCCESS on success. * @returns VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical * page but has no physical backing. * @returns VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid * @param pVM The VM handle. * @param GCPhys The GC physical address to convert. * @param pHCPhys Where to store the HC physical address on success. * Invalidates the GC page mapping TLB. * @param pVM The VM handle. * Invalidates the ring-0 page mapping TLB. * @param pVM The VM handle. * Invalidates the ring-3 page mapping TLB. * @param pVM The VM handle. * Makes sure that there is at least one handy page ready for use. * This will also take the appropriate actions when reaching water-marks. * @returns The following VBox status codes. * @retval VINF_SUCCESS on success. * @retval VERR_EM_NO_MEMORY if we're really out of memory. * @param pVM The VM handle. * @remarks Must be called from within the PGM critical section. It may * nip back to ring-3/0 in some cases. * low-water mark logic for R0 & GC: * - 50%: Force return to ring-3 ASAP. * For ring-3 there is a little problem wrt to the recompiler, so: * - 50%: Try allocate pages; on failure we'll force REM to quite ASAP. * The basic idea is that we should be able to get out of any situation with * only 50% of handy pages remaining. * At the moment we'll not adjust the number of handy pages relative to the * actual VM RAM committment, that's too much work for now. /** @todo call PGMR0PhysAllocateHandyPages directly - need to make sure we can call kernel code first and deal with the seeding fallback. */ LogRel((
"PGM: no more handy pages!\n"));
* Replace a zero or shared page with new page that we can write to. * @returns The following VBox status codes. * @retval VINF_SUCCESS on success, pPage is modified. * @retval VERR_EM_NO_MEMORY if we're totally out of memory. * @todo Propagate VERR_EM_NO_MEMORY up the call tree. * @param pVM The VM address. * @param pPage The physical page tracking structure. This will * be modified on success. * @param GCPhys The address of the page. * @remarks Must be called from within the PGM critical section. It may * nip back to ring-3/0 in some cases. * @remarks This function shouldn't really fail, however if it does * it probably means we've screwed up the size of the amount * and/or the low-water mark of handy pages. Or, that some * device I/O is causing a lot of pages to be allocated while * while the host is in a low-memory condition. * Ensure that we've got a page handy, take it and use it. * There are one or two action to be taken the next time we allocate handy pages: * - Tell the GMM (global memory manager) what the page is being used for. * (Speeds up replacement operations - sharing and defragmenting.) * - If the current backing is shared, it must be freed. * Do the PGMPAGE modifications. * Deal with pages that are not writable, i.e. not in the ALLOCATED state. * @returns VBox status code. * @retval VINF_SUCCESS on success. * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing. * @param pVM The VM address. * @param pPage The physical page tracking structure. * @param GCPhys The address of the page. * @remarks Called from within the PGM critical section. default:
/* to shut up GCC */ * Zero pages can be dummy pages for MMIO or reserved memory, * so we need to check the flags before joining cause with * shared page replacement. * Maps a page into the current virtual address space so it can be accessed. * @returns VBox status code. * @retval VINF_SUCCESS on success. * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing. * @param pVM The VM address. * @param pPage The physical page tracking structure. * @param GCPhys The address of the page. * @param ppMap Where to store the address of the mapping tracking structure. * @param ppv Where to store the mapping address of the page. The page * @remarks Called from within the PGM critical section. * Just some sketchy GC code. #
else /* IN_RING3 || IN_RING0 */ * Find/make Chunk TLB entry for the mapping chunk. * Find the chunk, map it if necessary. * Enter it into the Chunk TLB. * Load a guest page into the ring-3 physical TLB. * @returns VBox status code. * @retval VINF_SUCCESS on success * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. * @param pPGM The PGM instance pointer. * @param GCPhys The guest physical address in question. * 99.8% of requests are expected to be in the first range. * Make a special case for the zero page as it is kind of special. * Requests the mapping of a guest page into the current context. * This API should only be used for very short term, as it will consume * scarse resources (R0 and GC) in the mapping cache. When you're done * with the page, call PGMPhysReleasePageMappingLock() ASAP to release it. * This API will assume your intention is to write to the page, and will * therefore replace shared and zero pages. If you do not intend to modify * the page, use the PGMPhysGCPhys2CCPtrReadOnly() API. * @returns VBox status code. * @retval VINF_SUCCESS on success. * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing. * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. * @param pVM The VM handle. * @param GCPhys The guest physical address of the page that should be mapped. * @param ppv Where to store the address corresponding to GCPhys. * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs. * @remark Avoid calling this API from within critical sections (other than * the PGM one) because of the deadlock risk. /* Until a physical TLB is implemented for GC, let PGMGCDynMapGCPageEx handle it. */ * Query the Physical TLB entry for the page (may fail). * If the page is shared, the zero page, or being write monitored * it must be converted to an page that's writable if possible. * Now, just perform the locking and calculate the return address. pMap->
cRefs++;
/* Extra ref to prevent it from going away. */ #
endif /* IN_RING3 || IN_RING0 */ * Temporary fallback code. * Requests the mapping of a guest page into the current context. * This API should only be used for very short term, as it will consume * scarse resources (R0 and GC) in the mapping cache. When you're done * with the page, call PGMPhysReleasePageMappingLock() ASAP to release it. * @returns VBox status code. * @retval VINF_SUCCESS on success. * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing. * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. * @param pVM The VM handle. * @param GCPhys The guest physical address of the page that should be mapped. * @param ppv Where to store the address corresponding to GCPhys. * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs. * @remark Avoid calling this API from within critical sections (other than * the PGM one) because of the deadlock risk. /** @todo implement this */ * Requests the mapping of a guest page given by virtual address into the current context. * This API should only be used for very short term, as it will consume * scarse resources (R0 and GC) in the mapping cache. When you're done * with the page, call PGMPhysReleasePageMappingLock() ASAP to release it. * This API will assume your intention is to write to the page, and will * therefore replace shared and zero pages. If you do not intend to modify * the page, use the PGMPhysGCPtr2CCPtrReadOnly() API. * @returns VBox status code. * @retval VINF_SUCCESS on success. * @retval VERR_PAGE_TABLE_NOT_PRESENT if the page directory for the virtual address isn't present. * @retval VERR_PAGE_NOT_PRESENT if the page at the virtual address isn't present. * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing. * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. * @param pVM The VM handle. * @param GCPhys The guest physical address of the page that should be mapped. * @param ppv Where to store the address corresponding to GCPhys. * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs. * @remark Avoid calling this API from within critical sections (other than * the PGM one) because of the deadlock risk. * Requests the mapping of a guest page given by virtual address into the current context. * This API should only be used for very short term, as it will consume * scarse resources (R0 and GC) in the mapping cache. When you're done * with the page, call PGMPhysReleasePageMappingLock() ASAP to release it. * @returns VBox status code. * @retval VINF_SUCCESS on success. * @retval VERR_PAGE_TABLE_NOT_PRESENT if the page directory for the virtual address isn't present. * @retval VERR_PAGE_NOT_PRESENT if the page at the virtual address isn't present. * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing. * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. * @param pVM The VM handle. * @param GCPhys The guest physical address of the page that should be mapped. * @param ppv Where to store the address corresponding to GCPhys. * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs. * @remark Avoid calling this API from within critical sections (other than * the PGM one) because of the deadlock risk. * Release the mapping of a guest page. * This is the counter part of PGMPhysGCPhys2CCPtr, PGMPhysGCPhys2CCPtrReadOnly * PGMPhysGCPtr2CCPtr and PGMPhysGCPtr2CCPtrReadOnly. * @param pVM The VM handle. * @param pLock The lock structure initialized by the mapping function. /* currently nothing to do here. */ * Converts a GC physical address to a HC pointer. * @returns VINF_SUCCESS on success. * @returns VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical * page but has no physical backing. * @returns VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid * @returns VERR_PGM_GCPHYS_RANGE_CROSSES_BOUNDARY if the range crosses * a dynamic ram chunk boundary * @param pVM The VM handle. * @param GCPhys The GC physical address to convert. * @param cbRange Physical range * @param pHCPtr Where to store the HC pointer on success. * Converts a guest pointer to a GC physical address. * This uses the current CR3/CR0/CR4 of the guest. * @returns VBox status code. * @param pVM The VM Handle * @param GCPtr The guest pointer to convert. * @param pGCPhys Where to store the GC physical address. * Converts a guest pointer to a HC physical address. * This uses the current CR3/CR0/CR4 of the guest. * @returns VBox status code. * @param pVM The VM Handle * @param GCPtr The guest pointer to convert. * @param pHCPhys Where to store the HC physical address. * Converts a guest pointer to a HC pointer. * This uses the current CR3/CR0/CR4 of the guest. * @returns VBox status code. * @param pVM The VM Handle * @param GCPtr The guest pointer to convert. * @param pHCPtr Where to store the HC virtual address. * Converts a guest virtual address to a HC pointer by specfied CR3 and flags. * @returns VBox status code. * @param pVM The VM Handle * @param GCPtr The guest pointer to convert. * @param cr3 The guest CR3. * @param fFlags Flags used for interpreting the PD correctly: X86_CR4_PSE and X86_CR4_PAE * @param pHCPtr Where to store the HC pointer. * @remark This function is used by the REM at a time where PGM could * potentially not be in sync. It could also be used by a * future DBGF API to cpu state independent conversions. * Cache PGMPhys memory access * @param pCache Cache structure pointer * @param GCPhys GC physical address * @param pbHC HC pointer corresponding to physical page * This API respects access handlers and MMIO. Use PGMPhysReadGCPhys() if you * @param GCPhys Physical address start reading from. * @param pvBuf Where to put the read bits. * @param cbRead How many bytes to read. * Copy loop on ram ranges. /* Inside range or not? */ * Must work our way thru this page by page. /* Physical chunk in dynamically allocated range not present? */ /* Treat it as reserved; return zeros */ //case MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO2: /* = shadow */ - //MMIO2 isn't in the mask. #
endif /* IN_RING3 && PGM_PHYSMEMACCESS_CACHING */ * All reserved, nothing there. #
ifdef IN_RING3 /** @todo deal with this in GC and R0! */ /* find and call the handler */ /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */ #
ifdef IN_RING3 /** @todo deal with this in GC and R0! */ /* Search the whole tree for matching physical addresses (rather expensive!) */ /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */ * The rest needs to be taken more carefully. #
if 1 /** @todo r=bird: Can you do this properly please. */ /** @todo Try MMIO; quick hack */ /** @todo fix me later. */ * Unassigned address space. * Write to physical memory. * This API respects access handlers and MMIO. Use PGMPhysReadGCPhys() if you * @param GCPhys Physical address to write to. * @param pvBuf What to write. * @param cbWrite How many bytes to write. * Copy loop on ram ranges. /* Inside range or not? */ * Must work our way thru this page by page. /* Physical chunk in dynamically allocated range not present? */ /** @todo r=bird: missing MM_RAM_FLAGS_ROM here, we shall not allow anyone to overwrite the ROM! */ * Normal memory, MMIO2 or writable shadow ROM. #
endif /* IN_RING3 && PGM_PHYSMEMACCESS_CACHING */ * All reserved, nothing there. #
ifdef IN_RING3 /** @todo deal with this in GC and R0! */ /* find and call the handler */ /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */ /** @todo deal with this in GC and R0! */ /* Search the whole tree for matching physical addresses (rather expensive!) */ /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */ * Physical write handler + virtual write handler. * Consider this a quick workaround for the CSAM + shadow caching problem. * We hand it to the shadow caching first since it requires the unchanged * data. CSAM will have to put up with it already being changed. #
ifdef IN_RING3 /** @todo deal with this in GC and R0! */ /* 1. The physical handler */ /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */ /* 2. The virtual handler (will see incorrect data) */ /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */ * The rest needs to be taken more carefully. #
if 1 /** @todo r=bird: Can you do this properly please. */ /** @todo Try MMIO; quick hack */ /** @todo fix me later. */ * Unassigned address space. #
ifndef IN_GC /* Ring 0 & 3 only */ * Read from guest physical memory by GC physical address, bypassing * MMIO and access handlers. * @param pvDst The destination address. * @param GCPhysSrc The source address (GC physical address). * @param cb The number of bytes to read. /* Copy page by page as we're not dealing with a linear HC range. */ * Write to guest physical memory referenced by GC pointer. * Write memory to GC physical address in guest physical memory. * This will bypass MMIO and access handlers. * @param GCPhysDst The GC physical address of the destination. * @param pvSrc The source buffer. * @param cb The number of bytes to write. /** @todo PGMRamGCPhys2HCPtrWithRange. */ /* Copy page by page as we're not dealing with a linear HC range. */ * Read from guest physical memory referenced by GC pointer. * This function uses the current CR3/CR0/CR4 of the guest and will * bypass access handlers and not set any accessed bits. * @param pvDst The destination address. * @param GCPtrSrc The source address (GC pointer). * @param cb The number of bytes to read. * Optimize reads within a single page. * Write to guest physical memory referenced by GC pointer. * This function uses the current CR3/CR0/CR4 of the guest and will * bypass access handlers and not set dirty or accessed bits. * @param GCPtrDst The destination address (GC pointer). * @param pvSrc The source address. * @param cb The number of bytes to write. * Optimize writes within a single page. * Read from guest physical memory referenced by GC pointer. * This function uses the current CR3/CR0/CR4 of the guest and will * respect access handlers and set accessed bits. * @param pvDst The destination address. * @param GCPtrSrc The source address (GC pointer). * @param cb The number of bytes to read. /** @todo use the PGMPhysReadGCPtr name and rename the unsafe one to something appropriate */ * Optimize reads within a single page. /* Convert virtual to physical address */ /* mark the guest page as accessed. */ /* Convert virtual to physical address */ /* mark the guest page as accessed. */ * Write to guest physical memory referenced by GC pointer. * This function uses the current CR3/CR0/CR4 of the guest and will * respect access handlers and set dirty and accessed bits. * @param GCPtrDst The destination address (GC pointer). * @param pvSrc The source address. * @param cb The number of bytes to write. /** @todo use the PGMPhysWriteGCPtr name and rename the unsafe one to something appropriate */ * Optimize writes within a single page. /* Convert virtual to physical address */ /* mark the guest page as accessed and dirty. */ /* Convert virtual to physical address */ /* mark the guest page as accessed and dirty. */ * Write to guest physical memory referenced by GC pointer and update the PTE. * This function uses the current CR3/CR0/CR4 of the guest and will * bypass access handlers and set any dirty and accessed bits in the PTE. * If you don't want to set the dirty bit, use PGMPhysWriteGCPtr(). * @param GCPtrDst The destination address (GC pointer). * @param pvSrc The source address. * @param cb The number of bytes to write. * Optimize writes within a single page. /* mark the guest page as accessed and dirty. */ * Performs a read of guest virtual memory for instruction emulation. * This will check permissions, raise exceptions and update the access bits. * The current implementation will bypass all access handlers. It may later be * changed to at least respect MMIO. * @returns VBox status code suitable to scheduling. * @retval VINF_SUCCESS if the read was performed successfully. * @retval VINF_EM_RAW_GUEST_TRAP if an exception was raised but not dispatched yet. * @retval VINF_TRPM_XCPT_DISPATCHED if an exception was raised and dispatched. * @param pVM The VM handle. * @param pCtxCore The context core. * @param pvDst Where to put the bytes we've read. * @param GCPtrSrc The source address. * @param cb The number of bytes to read. Not more than a page. * @remark This function will dynamically map physical pages in GC. This may unmap * mappings done by the caller. Be careful! /** @todo r=bird: This isn't perfect! * -# It's not checking for reserved bits being 1. * -# It's not correctly dealing with the access bit. * -# It's not respecting MMIO memory or any other access handlers. * 1. Translate virtual to physical. This may fault. * 2. Map the physical address. * 3. Do the read operation. * 4. Set access bits if required. /** @todo we should check reserved bits ... */ /** @todo access bit emulation isn't 100% correct. */ /** @todo we should check reserved bits ... */ /* Get the current privilege level. */ Log((
"PGMPhysInterpretedRead: GCPtrSrc=%VGv cb=%#x -> #PF(%#x)\n",
GCPtrSrc,
cb,
uErr));
/// @todo PGMDECL(int) PGMPhysInterpretedWrite(PVM pVM, PCPUMCTXCORE pCtxCore, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)