MMPhys.cpp revision 7bb3c0bce2906236dbb84a55d90f3b1d0b4b02cd
/* $Id$ */
/** @file
* MM - Memory Manager - Physical Memory.
*
* @remarks This will will be eliminated ASAP, all physical memory management
* is done by PGM now.
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_MM_PHYS
#include "MMInternal.h"
/**
* Register externally allocated RAM for the virtual machine.
*
* The memory registered with the VM thru this interface must not be freed
* before the virtual machine has been destroyed. Bad things may happen... :-)
*
* @return VBox status code.
* @param pVM VM handle.
* @param pvRam Virtual address of the guest's physical memory range Must be page aligned.
* @param GCPhys The physical address the ram shall be registered at.
* @param cb Size of the memory. Must be page aligend.
* @param fFlags Flags of the MM_RAM_FLAGS_* defines.
* @param pszDesc Description of the memory.
*/
VMMR3DECL(int) MMR3PhysRegister(PVM pVM, void *pvRam, RTGCPHYS GCPhys, unsigned cb, unsigned fFlags, const char *pszDesc)
{
}
/**
* Register externally allocated RAM for the virtual machine.
*
* The memory registered with the VM thru this interface must not be freed
* before the virtual machine has been destroyed. Bad things may happen... :-)
*
* @return VBox status code.
* @param pVM VM handle.
* @param pvRam Virtual address of the guest's physical memory range Must be page aligned.
* @param GCPhys The physical address the ram shall be registered at.
* @param cb Size of the memory. Must be page aligend.
* @param fFlags Flags of the MM_RAM_FLAGS_* defines.
* @param enmType Physical range type (MM_PHYS_TYPE_*)
* @param pszDesc Description of the memory.
* @thread The Emulation Thread.
*
* @deprecated For the old dynamic allocation code only. Will be removed with VBOX_WITH_NEW_PHYS_CODE.
*/
/** @todo this function description is not longer up-to-date */
VMMR3DECL(int) MMR3PhysRegisterEx(PVM pVM, void *pvRam, RTGCPHYS GCPhys, unsigned cb, unsigned fFlags, MMPHYSREG enmType, const char *pszDesc)
{
int rc = VINF_SUCCESS;
/*
* Validate input.
*/
if (pvRam)
else
AssertReturn(enmType == MM_PHYS_TYPE_NORMAL || enmType == MM_PHYS_TYPE_DYNALLOC_CHUNK, VERR_INVALID_PARAMETER);
/*
* Check for conflicts.
*
* We do not support overlapping physical memory regions yet,
* even if that's what the MM_RAM_FLAGS_MMIO2 flags is trying to
* tell us to do. Provided that all MMIO2 addresses are very high
* there is no real danger we'll be able to assign so much memory
* for a guest that it'll ever be a problem.
*/
("MMIO2 addresses should be above 3GB for avoiding conflicts with real RAM.\n"));
while (pCur)
{
)
{
AssertMsgFailed(("Conflicting RAM range. Existing %#x LB%#x, Req %#x LB%#x\n",
return VERR_MM_RAM_CONFLICT;
}
/* next */
}
if (fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
{
/*
* Register the ram with PGM.
*/
if (RT_SUCCESS(rc))
{
if (fFlags == MM_RAM_FLAGS_DYNAMIC_ALLOC)
return rc;
}
}
else
{
/*
* Lock the memory. (fully allocated by caller)
*/
rc = mmR3LockMem(pVM, pvRam, cb, MM_LOCKED_TYPE_PHYS, &pLockedMem, enmType == MM_PHYS_TYPE_DYNALLOC_CHUNK /* fSilentFailure */);
if (RT_SUCCESS(rc))
{
/*
* We set any page flags specified.
*/
if (fFlags)
for (unsigned i = 0; i < cb >> PAGE_SHIFT; i++)
/*
* Register the ram with PGM.
*/
if (enmType == MM_PHYS_TYPE_NORMAL)
{
rc = PGMR3PhysRegister(pVM, pvRam, pLockedMem->u.phys.GCPhys, cb, fFlags, &pLockedMem->aPhysPages[0], pszDesc);
if (RT_SUCCESS(rc))
{
if (!fFlags)
return rc;
}
}
else
{
return PGMR3PhysRegisterChunk(pVM, pvRam, pLockedMem->u.phys.GCPhys, cb, fFlags, &pLockedMem->aPhysPages[0], pszDesc);
}
}
/* Cleanup is done in VM destruction to which failure of this function will lead. */
/* Not true in case of MM_PHYS_TYPE_DYNALLOC_CHUNK */
}
return rc;
}
/**
* Register a ROM (BIOS) region.
*
* It goes without saying that this is read-only memory. The memory region must be
* in unassigned memory. I.e. from the top of the address space or on the PC in
* the 0xa0000-0xfffff range.
*
* @returns VBox status.
* @param pVM VM Handle.
* @param pDevIns The device instance owning the ROM region.
* @param GCPhys First physical address in the range.
* Must be page aligned!
* @param cbRange The size of the range (in bytes).
* Must be page aligned!
* @param pvBinary Pointer to the binary data backing the ROM image.
* This must be cbRange bytes big.
* It will be copied and doesn't have to stick around.
* It will be copied and doesn't have to stick around if fShadow is clear.
* @param fShadow Whether to emulate ROM shadowing. This involves leaving
* the ROM writable for a while during the POST and refreshing
* it at reset. When this flag is set, the memory pointed to by
* pvBinary has to stick around for the lifespan of the VM.
* @param pszDesc Pointer to description string. This must not be freed.
* @remark There is no way to remove the rom, automatically on device cleanup or
* manually from the device yet. At present I doubt we need such features...
*/
VMMR3DECL(int) MMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTUINT cbRange, const void *pvBinary,
{
/*
* Validate input.
*/
/*
* Check if this can fit in an existing range.
*
* We do not handle the case where a new chunk of locked memory is
* required to accommodate the ROM since we assume MMR3PhysReserve()
* have been called to reserve the memory first.
*
* To make things even simpler, the pages in question must be
* marked as reserved.
*/
break;
if (!pCur)
{
AssertMsgFailed(("No physical range was found matching the ROM location (%RGp LB%#x)\n", GCPhys, cbRange));
return VERR_INVALID_PARAMETER;
}
{
AssertMsgFailed(("The ROM range (%RGp LB%#x) was crossing the end of the physical range (%RGp LB%#x)\n",
return VERR_INVALID_PARAMETER;
}
/* flags must be all reserved. */
if ( (pCur->aPhysPages[iPage].Phys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_MMIO2))
{
AssertMsgFailed(("Flags conflict at %RGp, HCPhys=%RHp.\n", pCur->u.phys.GCPhys + (iPage << PAGE_SHIFT), pCur->aPhysPages[iPage].Phys));
return VERR_INVALID_PARAMETER;
}
/*
* Copy the ram and update the flags.
*/
{
}
if (RT_SUCCESS(rc))
{
/*
* To prevent the shadow page table mappings from being RW in raw-mode, we
* must currently employ a little hack. We register an write access handler
* and thereby ensures a RO mapping of the pages. This is NOT very nice,
* and wasn't really my intention when writing the code, consider it a PGM bug.
*
* ASSUMES that REMR3NotifyPhysRomRegister doesn't call cpu_register_physical_memory
* when there is no HC handler. The result would probably be immediate boot failure.
*/
rc = PGMR3HandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE, GCPhys, GCPhys + cbRange - 1,
NULL, "pgmPhysRomWriteHandler", 0,
}
/*
* Create a ROM range it so we can make a 'info rom' thingy and more importantly
*/
if (RT_SUCCESS(rc))
{
/* sort it for 'info rom' readability. */
{
}
if (pPrev)
else
}
return rc; /* we're sloppy with error cleanup here, but we're toast anyway if this fails. */
}
/**
* Reserve physical address space for ROM and MMIO ranges.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param GCPhys Start physical address.
* @param cbRange The size of the range.
* @param pszDesc Description string.
*/
{
/*
* Validate input.
*/
/*
* Do we have an existing physical address range for the request?
*/
break;
if (!pCur)
{
/*
* No range, we'll just allocate backing pages and register
* them as reserved using the Ram interface.
*/
void *pvPages;
if (RT_SUCCESS(rc))
{
if (RT_FAILURE(rc))
}
return rc;
}
{
AssertMsgFailed(("The reserved range (%RGp LB%#x) was crossing the end of the physical range (%RGp LB%#x)\n",
return VERR_INVALID_PARAMETER;
}
/*
* Update the flags.
*/
return rc;
}
/**
* Get the size of the base RAM.
* This usually means the size of the first contigous block of physical memory.
*
* @returns The guest base RAM size.
* @param pVM The VM handle.
* @thread Any.
*/
{
}
/**
* Called by MMR3Reset to reset the shadow ROM.
*
* Resetting involves reloading the ROM into RAM and make it
* wriable again (as it was made read only at the end of the POST).
*
* @param pVM The VM handle.
*/
{
{
{
rc = PGMR3PhysSetFlags(pVM, pCur->GCPhys, pCur->cbRange, MM_RAM_FLAGS_MMIO2, ~0); /* ROM -> ROM + MMIO2 */
REMR3NotifyPhysRomRegister(pVM, pCur->GCPhys, pCur->cbRange, pCur->pvCopy, true /* read-write now */);
}
}
}
/**
* Write-protects a shadow ROM range.
*
* This is called late in the POST for shadow ROM ranges.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param GCPhys Start of the registered shadow ROM range
* @param cbRange The length of the registered shadow ROM range.
* This can be NULL (not sure about the BIOS interface yet).
*/
{
|| !cbRange))
{
{
int rc = PGMR3HandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE, GCPhys, GCPhys + cbRange - 1,
NULL, "pgmPhysRomWriteHandler", 0,
/* Don't bother with the MM page flags here because I don't think they are
really used beyond conflict checking at ROM, RAM, Reservation, etc. */
}
return VINF_SUCCESS;
}
return VERR_INVALID_PARAMETER;
}