diff options
Diffstat (limited to 'src/VBox/VMM/VMMR3/CFGM.cpp')
| -rw-r--r-- | src/VBox/VMM/VMMR3/CFGM.cpp | 243 |
1 files changed, 193 insertions, 50 deletions
diff --git a/src/VBox/VMM/VMMR3/CFGM.cpp b/src/VBox/VMM/VMMR3/CFGM.cpp index b0dcb508..4420e89f 100644 --- a/src/VBox/VMM/VMMR3/CFGM.cpp +++ b/src/VBox/VMM/VMMR3/CFGM.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -33,9 +33,9 @@ * where they are protected from accessing information of any parents. This is * is implemented via the CFGMR3SetRestrictedRoot() API. * - * Data validation out over the basic primitives is left to the caller. The - * caller is in a better position to know the proper validation rules of the - * individual properties. + * Data validation beyond the basic primitives is left to the caller. The caller + * is in a better position to know the proper validation rules of the individual + * properties. * * @see grp_cfgm * @@ -60,10 +60,13 @@ #include <VBox/vmm/mm.h> #include "CFGMInternal.h" #include <VBox/vmm/vm.h> +#include <VBox/vmm/uvm.h> #include <VBox/err.h> #include <VBox/log.h> #include <iprt/assert.h> +#include <iprt/mem.h> +#include <iprt/param.h> #include <iprt/string.h> #include <iprt/uuid.h> @@ -78,7 +81,93 @@ static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *p static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf); static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf); static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf); -static void cfgmR3FreeValue(PCFGMLEAF pLeaf); +static void cfgmR3FreeValue(PVM pVM, PCFGMLEAF pLeaf); + + +/** + * Allocator wrapper. + * + * @returns Pointer to the allocated memory, NULL on failure. + * @param pVM The VM handle, if tree associated with one. + * @param enmTag The allocation tag. + * @param cb The size of the allocation. + */ +static void *cfgmR3MemAlloc(PVM pVM, MMTAG enmTag, size_t cb) +{ + if (pVM) + return MMR3HeapAlloc(pVM, enmTag, cb); + return RTMemAlloc(cb); +} + + +/** + * Free wrapper. + * + * @returns Pointer to the allocated memory, NULL on failure. + * @param pVM The VM handle, if tree associated with one. + * @param pv The memory block to free. + */ +static void cfgmR3MemFree(PVM pVM, void *pv) +{ + if (pVM) + MMR3HeapFree(pv); + else + RTMemFree(pv); +} + + +/** + * String allocator wrapper. + * + * @returns Pointer to the allocated memory, NULL on failure. + * @param pVM The VM handle, if tree associated with one. + * @param enmTag The allocation tag. + * @param cbString The size of the allocation, terminator included. + */ +static char *cfgmR3StrAlloc(PVM pVM, MMTAG enmTag, size_t cbString) +{ + if (pVM) + return (char *)MMR3HeapAlloc(pVM, enmTag, cbString); + return (char *)RTStrAlloc(cbString); +} + + +/** + * String free wrapper. + * + * @returns Pointer to the allocated memory, NULL on failure. + * @param pVM The VM handle, if tree associated with one. + * @param pszString The memory block to free. + */ +static void cfgmR3StrFree(PVM pVM, char *pszString) +{ + if (pVM) + MMR3HeapFree(pszString); + else + RTStrFree(pszString); +} + + +/** + * Frees one node, leaving any children or leaves to the caller. + * + * @param pNode The node structure to free. + */ +static void cfgmR3FreeNodeOnly(PCFGMNODE pNode) +{ + pNode->pFirstLeaf = NULL; + pNode->pFirstChild = NULL; + pNode->pNext = NULL; + pNode->pPrev = NULL; + if (!pNode->pVM) + RTMemFree(pNode); + else + { + pNode->pVM = NULL; + MMR3HeapFree(pNode); + } +} + @@ -91,6 +180,7 @@ static void cfgmR3FreeValue(PCFGMLEAF pLeaf); * This is called in the EM. * @param pvUser The user argument passed to pfnCFGMConstructor. * @thread EMT. + * @internal */ VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUser) { @@ -104,7 +194,8 @@ VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void * /* * Register DBGF into item. */ - int rc = DBGFR3InfoRegisterInternal(pVM, "cfgm", "Dumps a part of the CFGM tree. The argument indicates where to start.", cfgmR3Info); + int rc = DBGFR3InfoRegisterInternal(pVM, "cfgm", "Dumps a part of the CFGM tree. The argument indicates where to start.", + cfgmR3Info); AssertRCReturn(rc,rc); /* @@ -121,7 +212,7 @@ VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void * * Call the constructor if specified, if not use the default one. */ if (pfnCFGMConstructor) - rc = pfnCFGMConstructor(pVM, pvUser); + rc = pfnCFGMConstructor(pVM->pUVM, pVM, pvUser); else rc = CFGMR3ConstructDefaultTree(pVM); if (RT_SUCCESS(rc)) @@ -141,6 +232,7 @@ VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void * * * @returns VBox status code. * @param pVM Pointer to the VM. + * @internal */ VMMR3DECL(int) CFGMR3Term(PVM pVM) { @@ -163,6 +255,21 @@ VMMR3DECL(PCFGMNODE) CFGMR3GetRoot(PVM pVM) /** + * Gets the root node for the VM. + * + * @returns Pointer to root node. + * @param pVM Pointer to the VM. + */ +VMMR3DECL(PCFGMNODE) CFGMR3GetRootU(PUVM pUVM) +{ + UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL); + PVM pVM = pUVM->pVM; + AssertReturn(pVM, NULL); + return pVM->cfgm.s.pRoot; +} + + +/** * Gets the parent of a CFGM node. * * @returns Pointer to the parent node. @@ -820,6 +927,7 @@ VMMR3DECL(int) CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode, * * @returns VBox status code. * @param pVM Pointer to the VM. + * @internal */ VMMR3DECL(int) CFGMR3ConstructDefaultTree(PVM pVM) { @@ -1179,12 +1287,27 @@ static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *pp * passed around and later attached to the main tree in the * correct location. * - * @returns Pointer to the root node. - * @param pVM Pointer to the VM. + * @returns Pointer to the root node, NULL on error (out of memory or invalid + * VM handle). + * @param pUVM The user mode VM handle. For testcase (and other + * purposes, NULL can be used. However, the resulting + * tree cannot be inserted into a tree that has a + * non-NULL value. Using NULL can be usedful for + * testcases and similar, non VMM uses. */ -VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PVM pVM) +VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PUVM pUVM) { - PCFGMNODE pNew = (PCFGMNODE)MMR3HeapAlloc(pVM, MM_TAG_CFGM, sizeof(*pNew)); + if (pUVM) + { + UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL); + VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL); + } + + PCFGMNODE pNew; + if (pUVM) + pNew = (PCFGMNODE)MMR3HeapAllocU(pUVM, MM_TAG_CFGM, sizeof(*pNew)); + else + pNew = (PCFGMNODE)RTMemAlloc(sizeof(*pNew)); if (pNew) { pNew->pPrev = NULL; @@ -1192,7 +1315,7 @@ VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PVM pVM) pNew->pParent = NULL; pNew->pFirstChild = NULL; pNew->pFirstLeaf = NULL; - pNew->pVM = pVM; + pNew->pVM = pUVM ? pUVM->pVM : NULL; pNew->fRestrictedRoot = false; pNew->cchName = 0; pNew->szName[0] = 0; @@ -1216,7 +1339,7 @@ VMMR3DECL(int) CFGMR3DuplicateSubTree(PCFGMNODE pRoot, PCFGMNODE *ppCopy) /* * Create a new tree. */ - PCFGMNODE pNewRoot = CFGMR3CreateTree(pRoot->pVM); + PCFGMNODE pNewRoot = CFGMR3CreateTree(pRoot->pVM ? pRoot->pVM->pUVM : NULL); if (!pNewRoot) return VERR_NO_MEMORY; @@ -1326,7 +1449,7 @@ VMMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNO AssertPtrReturn(pSubTree, VERR_INVALID_POINTER); AssertReturn(pNode != pSubTree, VERR_INVALID_PARAMETER); AssertReturn(!pSubTree->pParent, VERR_INVALID_PARAMETER); - AssertReturn(pSubTree->pVM, VERR_INVALID_PARAMETER); + AssertReturn(pNode->pVM == pSubTree->pVM, VERR_INVALID_PARAMETER); Assert(!pSubTree->pNext); Assert(!pSubTree->pPrev); @@ -1350,10 +1473,7 @@ VMMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNO *ppChild = pNewChild; /* free the old subtree root */ - pSubTree->pVM = NULL; - pSubTree->pFirstLeaf = NULL; - pSubTree->pFirstChild = NULL; - MMR3HeapFree(pSubTree); + cfgmR3FreeNodeOnly(pSubTree); } return rc; } @@ -1381,7 +1501,6 @@ VMMR3DECL(int) CFGMR3ReplaceSubTree(PCFGMNODE pRoot, PCFGMNODE pNewRoot) AssertPtrReturn(pNewRoot, VERR_INVALID_POINTER); AssertReturn(pRoot != pNewRoot, VERR_INVALID_PARAMETER); AssertReturn(!pNewRoot->pParent, VERR_INVALID_PARAMETER); - AssertReturn(pNewRoot->pVM, VERR_INVALID_PARAMETER); AssertReturn(pNewRoot->pVM == pRoot->pVM, VERR_INVALID_PARAMETER); AssertReturn(!pNewRoot->pNext, VERR_INVALID_PARAMETER); AssertReturn(!pNewRoot->pPrev, VERR_INVALID_PARAMETER); @@ -1403,10 +1522,7 @@ VMMR3DECL(int) CFGMR3ReplaceSubTree(PCFGMNODE pRoot, PCFGMNODE pNewRoot) for (PCFGMNODE pChild = pRoot->pFirstChild; pChild; pChild = pChild->pNext) pChild->pParent = pRoot; - pNewRoot->pFirstLeaf = NULL; - pNewRoot->pFirstChild = NULL; - pNewRoot->pVM = NULL; - MMR3HeapFree(pNewRoot); + cfgmR3FreeNodeOnly(pNewRoot); return VINF_SUCCESS; } @@ -1618,7 +1734,7 @@ VMMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE /* * Allocate and init node. */ - PCFGMNODE pNew = (PCFGMNODE)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName); + PCFGMNODE pNew = (PCFGMNODE)cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName); if (pNew) { pNew->pParent = pNode; @@ -1760,7 +1876,7 @@ static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppL /* * Allocate and init node. */ - PCFGMLEAF pNew = (PCFGMLEAF)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName); + PCFGMLEAF pNew = (PCFGMLEAF)cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName); if (pNew) { pNew->cchName = cchName; @@ -1794,9 +1910,9 @@ static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppL /** - * Remove a node. + * Removes a node. * - * @param pNode Parent node. + * @param pNode The node to remove. */ VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode) { @@ -1823,20 +1939,17 @@ VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode) { if (pNode->pParent) pNode->pParent->pFirstChild = pNode->pNext; - else if (pNode == pNode->pVM->cfgm.s.pRoot) /* might be a different tree */ + else if ( pNode->pVM /* might be a different tree */ + && pNode == pNode->pVM->cfgm.s.pRoot) pNode->pVM->cfgm.s.pRoot = NULL; } if (pNode->pNext) pNode->pNext->pPrev = pNode->pPrev; /* - * Free ourselves. (bit of paranoia first) + * Free ourselves. */ - pNode->pVM = NULL; - pNode->pNext = NULL; - pNode->pPrev = NULL; - pNode->pParent = NULL; - MMR3HeapFree(pNode); + cfgmR3FreeNodeOnly(pNode); } } @@ -1864,10 +1977,10 @@ static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf) /* * Free value and node. */ - cfgmR3FreeValue(pLeaf); + cfgmR3FreeValue(pNode->pVM, pLeaf); pLeaf->pNext = NULL; pLeaf->pPrev = NULL; - MMR3HeapFree(pLeaf); + cfgmR3MemFree(pNode->pVM, pLeaf); } } @@ -1878,22 +1991,23 @@ static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf) * Use this before assigning a new value to a leaf. * The caller must either free the leaf or assign a new value to it. * + * @param pVM Used to select the heap. * @param pLeaf Pointer to the leaf which value should be free. */ -static void cfgmR3FreeValue(PCFGMLEAF pLeaf) +static void cfgmR3FreeValue(PVM pVM, PCFGMLEAF pLeaf) { if (pLeaf) { switch (pLeaf->enmType) { case CFGMVALUETYPE_BYTES: - MMR3HeapFree(pLeaf->Value.Bytes.pau8); + cfgmR3MemFree(pVM, pLeaf->Value.Bytes.pau8); pLeaf->Value.Bytes.pau8 = NULL; pLeaf->Value.Bytes.cb = 0; break; case CFGMVALUETYPE_STRING: - MMR3HeapFree(pLeaf->Value.String.psz); + cfgmR3StrFree(pVM, pLeaf->Value.String.psz); pLeaf->Value.String.psz = NULL; pLeaf->Value.String.cb = 0; break; @@ -1905,6 +2019,23 @@ static void cfgmR3FreeValue(PCFGMLEAF pLeaf) } } +/** + * Destroys a tree created with CFGMR3CreateTree or CFGMR3DuplicateSubTree. + * + * @returns VBox status code. + * @param pRoot The root node of the tree. + */ +VMMR3DECL(int) CFGMR3DestroyTree(PCFGMNODE pRoot) +{ + if (!pRoot) + return VINF_SUCCESS; + AssertReturn(!pRoot->pParent, VERR_INVALID_PARAMETER); + AssertReturn(!pRoot->pVM || pRoot != pRoot->pVM->cfgm.s.pRoot, VERR_ACCESS_DENIED); + + CFGMR3RemoveNode(pRoot); + return VINF_SUCCESS; +} + /** * Inserts a new integer value. @@ -1948,7 +2079,7 @@ VMMR3DECL(int) CFGMR3InsertStringN(PCFGMNODE pNode, const char *pszName, const c /* * Allocate string object first. */ - char *pszStringCopy = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cchString + 1); + char *pszStringCopy = (char *)cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cchString + 1); if (pszStringCopy) { memcpy(pszStringCopy, pszString, cchString); @@ -1966,7 +2097,7 @@ VMMR3DECL(int) CFGMR3InsertStringN(PCFGMNODE pNode, const char *pszName, const c pLeaf->Value.String.cb = cchString + 1; } else - MMR3HeapFree(pszStringCopy); + cfgmR3StrFree(pNode->pVM, pszStringCopy); } else rc = VERR_NO_MEMORY; @@ -2011,7 +2142,11 @@ VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, const /* * Allocate string object first. */ - char *pszString = MMR3HeapAPrintfVU(pNode->pVM->pUVM, MM_TAG_CFGM_STRING, pszFormat, va); + char *pszString; + if (!pNode->pVM) + pszString = RTStrAPrintf2(pszFormat, va); + else + pszString = MMR3HeapAPrintfVU(pNode->pVM->pUVM, MM_TAG_CFGM_STRING, pszFormat, va); if (pszString) { /* @@ -2026,7 +2161,7 @@ VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, const pLeaf->Value.String.cb = strlen(pszString) + 1; } else - MMR3HeapFree(pszString); + cfgmR3StrFree(pNode->pVM, pszString); } else rc = VERR_NO_MEMORY; @@ -2098,7 +2233,7 @@ VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const voi /* * Allocate string object first. */ - void *pvCopy = MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cbBytes); + void *pvCopy = cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cbBytes); if (pvCopy || !cbBytes) { memcpy(pvCopy, pvBytes, cbBytes); @@ -2114,6 +2249,8 @@ VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const voi pLeaf->Value.Bytes.cb = cbBytes; pLeaf->Value.Bytes.pau8 = (uint8_t *)pvCopy; } + else + cfgmR3MemFree(pNode->pVM, pvCopy); } else rc = VERR_NO_MEMORY; @@ -2892,7 +3029,8 @@ VMMR3DECL(int) CFGMR3QueryGCPtrSDef(PCFGMNODE pNode, const char *pszName, PRTGCI * @param pNode Which node to search for pszName in. * @param pszName Value name. This value must be of zero terminated character string type. * @param ppszString Where to store the string pointer. - * Free this using MMR3HeapFree(). + * Free this using MMR3HeapFree() (or RTStrFree if not + * associated with a pUVM - see CFGMR3CreateTree). */ VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString) { @@ -2900,14 +3038,14 @@ VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char int rc = CFGMR3QuerySize(pNode, pszName, &cbString); if (RT_SUCCESS(rc)) { - char *pszString = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbString); + char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbString); if (pszString) { rc = CFGMR3QueryString(pNode, pszName, pszString, cbString); if (RT_SUCCESS(rc)) *ppszString = pszString; else - MMR3HeapFree(pszString); + cfgmR3StrFree(pNode->pVM, pszString); } else rc = VERR_NO_MEMORY; @@ -2927,7 +3065,8 @@ VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char * MMR3HeapStrDup. * @param pszName Value name. This value must be of zero terminated character string type. * @param ppszString Where to store the string pointer. Not set on failure. - * Free this using MMR3HeapFree(). + * Free this using MMR3HeapFree() (or RTStrFree if not + * associated with a pUVM - see CFGMR3CreateTree). * @param pszDef The default return value. This can be NULL. */ VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef) @@ -2945,7 +3084,7 @@ VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, c if (pLeaf->enmType == CFGMVALUETYPE_STRING) { size_t const cbSrc = pLeaf->Value.String.cb; - char *pszString = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbSrc); + char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbSrc); if (pszString) { memcpy(pszString, pLeaf->Value.String.psz, cbSrc); @@ -2962,7 +3101,11 @@ VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, c if (!pszDef) *ppszString = NULL; else - *ppszString = MMR3HeapStrDup(pNode->pVM, MM_TAG_CFGM_USER, pszDef); + { + size_t const cbDef = strlen(pszDef) + 1; + *ppszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbDef); + memcpy(*ppszString, pszDef, cbDef); + } if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT) rc = VINF_SUCCESS; } |
