/** * @file rm_allocator.c * * @brief * This is the Resource Manager allocator source. * * \par * ============================================================================ * @n (C) Copyright 2012-2013, Texas Instruments, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * \par */ /* RM external includes */ #include /* RM internal includes */ #include #include #include #include #include /* RM LIBFDT includes */ #include /* Tree algorithm includes */ #include /* RM OSAL layer */ #include /********************************************************************** ************************ Local Functions ***************************** **********************************************************************/ /* FUNCTION PURPOSE: Creates a resource allocator *********************************************************************** * DESCRIPTION: Returns a newly Created and initialized resource * The allocator is also stored in the RM instance * allocator list. */ static Rm_Allocator *allocatorAdd(Rm_Handle rmHandle, const char *resourceName) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Allocator *allocators = rmInst->u.server.allocators; Rm_Allocator *newAllocator = NULL; newAllocator = Rm_osalMalloc(sizeof(*allocators)); if (newAllocator) { memset((void *)newAllocator, 0, sizeof(*newAllocator)); strncpy(newAllocator->resourceName, resourceName, RM_NAME_MAX_CHARS); newAllocator->allocatorRootEntry = NULL; newAllocator->nextAllocator = NULL; /* Add allocator to end of list */ if (allocators) { while (allocators->nextAllocator) { allocators = allocators->nextAllocator; } allocators->nextAllocator = newAllocator; RM_SS_OBJ_WB(allocators, Rm_Allocator); } else { rmInst->u.server.allocators = newAllocator; } } return (newAllocator); } /* FUNCTION PURPOSE: Creates a new resource tree *********************************************************************** * DESCRIPTION: Creates and populates a new resource tree allocator * using the provided resource name and value range. The * name and value originate from the GRL. */ static int32_t allocatorCreate(Rm_Handle rmHandle, const char *resourceName, Rm_ResourceRange *range) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Allocator *allocator = NULL; Rm_ResourceTree *treeRoot = NULL; Rm_ResourceNode *treeNode = NULL; allocator = allocatorAdd(rmHandle, resourceName); treeRoot = Rm_osalMalloc(sizeof(*treeRoot)); RB_INIT(treeRoot); while (range != NULL) { treeNode = rmResourceNodeNew(range->base, range->length); RB_INSERT(_Rm_AllocatorResourceTree, treeRoot, treeNode); range = range->nextRange; } if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmResourceTreeWb(treeRoot); } allocator->allocatorRootEntry = treeRoot; RM_SS_OBJ_WB(allocator, Rm_Allocator); return(RM_OK); } /* FUNCTION PURPOSE: Returns a pointer to the allocator list *********************************************************************** * DESCRIPTION: Returns a pointer to the instance's allocator list * based on the instance type */ static Rm_Allocator *allocatorGetAllocatorList(Rm_Handle rmHandle) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Allocator *list = NULL; if ((rmInst->instType == Rm_instType_SERVER) || (rmInst->instType == Rm_instType_SHARED_SERVER)) { list = rmInst->u.server.allocators; } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { list = rmInst->u.cd.allocators; } return(list); } /* FUNCTION PURPOSE: Deletes a resource allocator *********************************************************************** * DESCRIPTION: Deletes a resource allocator based on the given * resource name. The resource allocator will be * removed from the RM instance allocator list. */ static int32_t allocatorDelete(Rm_Handle rmHandle, const char *resourceName) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Allocator *allocator = rmInst->u.server.allocators; Rm_Allocator *prevAllocator = NULL; Rm_ResourceTree *treeRoot; Rm_ResourceNode *node = NULL; Rm_ResourceNode *nextNode = NULL; int32_t retVal = RM_OK; while (allocator) { if (strncmp(allocator->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) { break; } prevAllocator = allocator; allocator = allocator->nextAllocator; } if (allocator) { if (prevAllocator == NULL) { rmInst->u.server.allocators = allocator->nextAllocator; } else { prevAllocator->nextAllocator = allocator->nextAllocator; RM_SS_OBJ_WB(prevAllocator, Rm_Allocator); } /* Destroy tree and return error */ treeRoot = allocator->allocatorRootEntry; for (node = RB_MIN(_Rm_AllocatorResourceTree, treeRoot); node != NULL; node = nextNode) { nextNode = RB_NEXT(_Rm_AllocatorResourceTree, treeRoot, node); RB_REMOVE(_Rm_AllocatorResourceTree, treeRoot, nextNode); rmResourceNodeFree(node); } Rm_osalFree((void *)treeRoot, sizeof(*treeRoot)); Rm_osalFree((void *)allocator, sizeof(*allocator)); } else { retVal = RM_ERROR_RES_ALLOCATOR_DOES_NOT_EXIST; } return (retVal); } /* FUNCTION PURPOSE: Adds an owner to an allocator resource *********************************************************************** * DESCRIPTION: Adds a RM instance node to a resource node's * list of owners. */ static void allocatorResNodeOwnerAdd(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Owner *ownerList = node->ownerList; Rm_Owner *newOwner = NULL; newOwner = Rm_osalMalloc(sizeof(*newOwner)); if (newOwner) { newOwner->instNameNode = serviceInstNode; newOwner->nextOwner = NULL; /* Add owner entry to end of list */ if (ownerList) { RM_SS_OBJ_INV(ownerList, Rm_Owner); while (ownerList->nextOwner) { ownerList = ownerList->nextOwner; RM_SS_OBJ_INV(ownerList, Rm_Owner); } ownerList->nextOwner = newOwner; RM_SS_OBJ_WB(ownerList, Rm_Owner); } else { node->ownerList = newOwner; } node->allocationCount++; newOwner->instNameNode->allocRefCount++; RM_SS_OBJ_WB(newOwner, Rm_Owner); RM_SS_OBJ_WB(newOwner->instNameNode, Rm_PolicyValidInstNode); } } /* FUNCTION PURPOSE: Compares two resource node's owners *********************************************************************** * DESCRIPTION: Returns TRUE if the owners of two resource nodes * are equivalent. Otherwise, returns FALSE. */ static int allocatorResNodeOwnerCompare(Rm_Handle rmHandle, Rm_ResourceNode *node1, Rm_ResourceNode *node2) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Owner *node1Owners = node1->ownerList; Rm_Owner *node2Owners = node2->ownerList; int matchedInst; if (rmInst->instType == Rm_instType_SHARED_SERVER) { while(node2Owners) { Rm_osalBeginMemAccess((void *)node2Owners, sizeof(*node2Owners)); node2Owners = node2Owners->nextOwner; } node2Owners = node2->ownerList; } if (node1->allocationCount == node2->allocationCount) { while (node1Owners) { RM_SS_OBJ_INV(node1Owners, Rm_Owner); matchedInst = RM_FALSE; while (node2Owners) { if (node1Owners->instNameNode == node2Owners->instNameNode) { matchedInst = RM_TRUE; break; } node2Owners = node2Owners->nextOwner; } if (matchedInst) { node2Owners = node2->ownerList; node1Owners = node1Owners->nextOwner; } else { return(RM_FALSE); } } } else { return(RM_FALSE); } return(RM_TRUE); } /* FUNCTION PURPOSE: Deletes an owner from an allocator resource *********************************************************************** * DESCRIPTION: Removes a RM instance node from a resource node's * list of owners. */ static void allocatorResNodeOwnerDelete(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Owner *owner = node->ownerList; Rm_Owner *prevOwner = NULL; while (owner) { RM_SS_OBJ_INV(owner, Rm_Owner); if (owner->instNameNode == serviceInstNode) { break; } prevOwner = owner; owner = owner->nextOwner; } if (owner) { if (prevOwner == NULL) { node->ownerList = owner->nextOwner; } else { prevOwner->nextOwner = owner->nextOwner; RM_SS_OBJ_WB(prevOwner, Rm_Owner); } node->allocationCount--; owner->instNameNode->allocRefCount--; RM_SS_OBJ_WB(owner->instNameNode, Rm_PolicyValidInstNode); Rm_osalFree((void *)owner, sizeof(*owner)); } } /* FUNCTION PURPOSE: Copies the owners of a resource node *********************************************************************** * DESCRIPTION: Creates a list of resource owners for the destination * resource node that is equivalent to the source resource * node's owners * * dstNode must be a newly created node without any owners. */ static void allocatorResNodeOwnerCopy(Rm_Handle rmHandle, Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Owner *srcOwnerList = srcNode->ownerList; Rm_Owner *dstNewOwner; Rm_Owner *dstPrevOwner; if (dstNode->ownerList != NULL) { return; } dstNode->allocationCount = srcNode->allocationCount; while (srcOwnerList) { RM_SS_OBJ_INV(srcOwnerList, Rm_Owner); dstNewOwner = Rm_osalMalloc(sizeof(*dstNewOwner)); dstNewOwner->instNameNode = srcOwnerList->instNameNode; dstNewOwner->nextOwner = NULL; RM_SS_OBJ_WB(dstNewOwner, Rm_Owner); if (dstNode->ownerList == NULL) { dstNode->ownerList = dstNewOwner; } else { dstPrevOwner->nextOwner = dstNewOwner; RM_SS_OBJ_WB(dstPrevOwner, Rm_Owner); } dstPrevOwner = dstNewOwner; srcOwnerList = srcOwnerList->nextOwner; } } /* FUNCTION PURPOSE: Clears a resource node's owners *********************************************************************** * DESCRIPTION: Deletes all owners from the owners list of a * resource node. */ static void allocatorResNodeOwnerClear(Rm_Handle rmHandle, Rm_ResourceNode *node) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Owner *owner = node->ownerList; Rm_Owner *nextOwner; while (owner) { RM_SS_OBJ_INV(owner, Rm_Owner); nextOwner = owner->nextOwner; node->allocationCount--; owner->instNameNode->allocRefCount--; RM_SS_OBJ_WB(owner->instNameNode, Rm_PolicyValidInstNode); Rm_osalFree((void *)owner, sizeof(*owner)); owner = nextOwner; } } /* FUNCTION PURPOSE: Checks a resource node's ownership *********************************************************************** * DESCRIPTION: Returns TRUE if the provided instance node is * in the list of resource node owners. Otherwise, * returns FALSE. */ static int allocatorResNodeIsOwnedBy(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Owner *owner = node->ownerList; while (owner) { RM_SS_OBJ_INV(owner, Rm_Owner); if (owner->instNameNode == serviceInstNode) { return(RM_TRUE); } owner = owner->nextOwner; } return(RM_FALSE); } /* FUNCTION PURPOSE: Preallocates an allocator resource *********************************************************************** * DESCRIPTION: Called when an allocate request is made but the base * is unspecified. The preallocation algorithm looks at * available resources as well as policy permissions to * determine a resource range that satisfies the request. * If a valid range is found it will be returned for the * treeAllocate algorithm to handle. */ static int32_t allocatorPreAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy, Rm_AllocatorOpInfo *opInfo) { Rm_ResourceNode findNode; Rm_ResourceNode *matchingNode = NULL; uint32_t matchingEnd; uint32_t rangeIndex; int resourceFound = RM_FALSE; Rm_PolicyCheckType policyCheckType; Rm_PolicyCheckCfg policyCheckCfg; int nodePassesPolicy; int32_t retVal; if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_INIT) { policyCheckType = Rm_policyCheck_INIT; } else if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_USE) { policyCheckType = Rm_policyCheck_USE; } else { retVal = RM_ERROR_INVALID_SERVICE_TYPE; return (retVal); } opInfo->resourceInfo->base = rmPolicyGetResourceBase(opInfo->policy, opInfo->serviceSrcInstNode, resourcePolicy, policyCheckType, &retVal); if (retVal != RM_OK) { return (retVal); } if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) { /* Get alignment from policy */ opInfo->resourceInfo->alignment = rmPolicyGetResourceAlignment(opInfo->policy, resourcePolicy); } if (opInfo->resourceInfo->alignment == 0) { opInfo->resourceInfo->alignment = 1; } memset((void *)&findNode, 0, sizeof(findNode)); findNode.base = opInfo->resourceInfo->base; findNode.length = opInfo->resourceInfo->length; /* Configure policy checking structure */ memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg)); policyCheckCfg.policyDtb = opInfo->policy; policyCheckCfg.resourceOffset = resourcePolicy; do { matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode); if (matchingNode) { if (matchingNode->allocationCount == 0) { /* Attempt to preallocate from node only if not owned by anyone */ nodePassesPolicy = RM_FALSE; policyCheckCfg.type = policyCheckType; policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode; policyCheckCfg.resourceBase = findNode.base; policyCheckCfg.resourceLength = findNode.length; nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal); if (nodePassesPolicy && (matchingNode->allocationCount > 0)) { policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode; if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) { /* Check if instance requesting resource has privileges to share * a resource already reserved by Linux */ policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX; nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal); } if (nodePassesPolicy) { /* Check exclusive privileges of instance requesting resource. Requesting * instance with exclusive privileges can't reserve resource if already owned*/ policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE; nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal); } } if (nodePassesPolicy && (matchingNode->allocationCount == 1)) { /* Check exclusive privileges of instance that currently owns resource */ policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE; policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode; nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal); } if (retVal != RM_OK) { break; } if (nodePassesPolicy) { matchingEnd = matchingNode->base + matchingNode->length - 1; /* Initialize indexer to be first resource value that alignment */ rangeIndex = findNode.base; if (rangeIndex % opInfo->resourceInfo->alignment) { rangeIndex += (opInfo->resourceInfo->alignment - (rangeIndex % opInfo->resourceInfo->alignment)); } if ((rangeIndex + opInfo->resourceInfo->length - 1) <= matchingEnd) { /* Block of unallocated resources within matchingNode that satisfies * allocate requirements */ opInfo->resourceInfo->base = rangeIndex; resourceFound = RM_TRUE; retVal = RM_SERVICE_PROCESSING; } } } if (!resourceFound) { /* Check next resource node for available resources */ findNode.base = matchingNode->base + matchingNode->length; } } else { retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET; } } while ((!resourceFound) && (retVal != RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET)); return(retVal); } /* FUNCTION PURPOSE: Allocates an allocator resource *********************************************************************** * DESCRIPTION: Will attempt to allocate the resource with specified * base and length from the resource's allocator. The * allocation algorithm will verify the allocation against * the policy permissions for the instance requesting the * allocation. If the policy allows the allocation the * algorithm will allocate the resource then combine any * resource nodes that may have become equivalent (in terms * of ownership) after the allocation. */ static int32_t allocatorAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy, Rm_AllocatorOpInfo *opInfo) { Rm_ResourceNode findNode; Rm_ResourceNode *matchingNode = NULL; Rm_ResourceNode *leftNode = NULL; Rm_ResourceNode *rightNode = NULL; Rm_PolicyCheckType policyCheckType; Rm_PolicyCheckCfg policyCheckCfg; int allocPassesPolicy; int combineLeft = RM_FALSE; int combineRight = RM_FALSE; uint32_t findEnd; uint32_t matchingEnd; int32_t retVal; if (opInfo->operation == Rm_allocatorOp_ALLOCATE_INIT) { policyCheckType = Rm_policyCheck_INIT; } else if (opInfo->operation == Rm_allocatorOp_ALLOCATE_USE) { policyCheckType = Rm_policyCheck_USE; } else { retVal = RM_ERROR_INVALID_SERVICE_TYPE; return (retVal); } memset((void *)&findNode, 0, sizeof(findNode)); findNode.base = opInfo->resourceInfo->base; findNode.length = opInfo->resourceInfo->length; matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode); /* Prepare privilege checks */ memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg)); if (matchingNode) { findEnd = findNode.base + findNode.length - 1; matchingEnd = matchingNode->base + matchingNode->length - 1; if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) { if (opInfo->serviceSrcInstNode == rmPolicyGetLinuxInstNode(rmHandle)) { /* Bypass policy checks since Linux Kernel has full privileges */ allocPassesPolicy = RM_TRUE; } else { policyCheckCfg.policyDtb = opInfo->policy; policyCheckCfg.resourceOffset = resourcePolicy; policyCheckCfg.type = policyCheckType; policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode; policyCheckCfg.resourceBase = findNode.base; policyCheckCfg.resourceLength = findNode.length; allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal); if (!allocPassesPolicy) { if (policyCheckType == Rm_policyCheck_INIT) { retVal = RM_SERVICE_DENIED_INIT_PERM_NOT_GIVEN; } else { retVal = RM_SERVICE_DENIED_USE_PERM_NOT_GIVEN; } } if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) { if (allocPassesPolicy && (matchingNode->allocationCount > 0)) { if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) { /* Check if instance requesting resource has privileges to share * a resource already reserved by Linux */ policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX; policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode; allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal); if (!allocPassesPolicy) { retVal = RM_SERVICE_DENIED_RES_NOT_SHARED_LINUX; } } if (allocPassesPolicy) { /* Check exclusive privileges of instance requesting resource. Requesting * instance with exclusive privileges can't reserve resource if already owned*/ policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE; policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode; allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal); if (!allocPassesPolicy) { retVal = RM_SERVICE_DENIED_EXCLUSIVE_RES_ALLOCD; } } } if (allocPassesPolicy && (matchingNode->allocationCount == 1)) { /* Check exclusive privileges of instance that currently owns resource */ policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE; policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode; allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal); if (!allocPassesPolicy) { retVal = RM_SERVICE_DENIED_ALLOCD_TO_EXCLUSIVE_INST; } } } } if (allocPassesPolicy) { if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) { /* Handle any possible node combinations if requesting instance is * not already in resource's owner list. Automatic approval if requesting * instance is already in owner list. */ if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) { /* findNode range matches matchingNode range * * |<--left node-->||<--matched node-->||<--right node-->| => existing node * |<--alloc request-->| => requested resources */ leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode); if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); combineLeft = RM_TRUE; } if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); combineRight = RM_TRUE; } if (combineLeft && combineRight) { /* Combine all three nodes into matchingNode */ matchingNode->base = leftNode->base; matchingNode->length = leftNode->length + matchingNode->length + rightNode->length; allocatorResNodeOwnerClear(rmHandle, leftNode); rmResourceNodeFree(leftNode); allocatorResNodeOwnerClear(rmHandle, rightNode); rmResourceNodeFree(rightNode); } else if (combineLeft) { /* Combine left and matching nodes. Reinsert right. */ matchingNode->base = leftNode->base; matchingNode->length += leftNode->length; allocatorResNodeOwnerClear(rmHandle, leftNode); rmResourceNodeFree(leftNode); if (rightNode) { RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); } } else if (combineRight) { /* Combine right and matching nodes. Reinsert left. */ matchingNode->length += rightNode->length; allocatorResNodeOwnerClear(rmHandle, rightNode); rmResourceNodeFree(rightNode); if (leftNode) { RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); } } else { /* No combine. */ if (leftNode) { RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); } if (rightNode) { RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); } } /* Always reinsert matchingNode */ RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); /* Matching node contains new reference count after alloc. Return new owner count. */ opInfo->resourceInfo->ownerCount = matchingNode->allocationCount; } else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) { /* findNode range is subset of matchingNode range and neither boundary is * equivalent. * * |<----------matched node---------->| * |<---alloc request--->| */ RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base); allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode); rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd); allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode); matchingNode->base = findNode.base; matchingNode->length = findNode.length; allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode); /* Insert all the nodes */ RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); /* Matching node contains new reference count after alloc. Return new owner count. */ opInfo->resourceInfo->ownerCount = matchingNode->allocationCount; } else { if (findNode.base == matchingNode->base) { /* findNode base and matchingNode base are equivalent. May be combine * possibilities to the left * * |<---left node (alloc'd)--->||<----------matched node---------->| * |<---findNode (alloc req)--->| */ leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); /* Add allocating instance to owner list for compare with leftNode */ allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode); if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); /* Combine leftNode and findNode */ leftNode->length += findNode.length; } else { leftNode = rmResourceNodeNew(findNode.base, findNode.length); allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode); } /* Account for leftNode in matchingNode */ matchingNode->base = findNode.base + findNode.length; matchingNode->length = matchingEnd - findEnd; RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); /* Left node contains new reference count after alloc. Return new owner count. */ opInfo->resourceInfo->ownerCount = leftNode->allocationCount; } else if (findEnd == matchingEnd) { /* findNode end and matchingNode end are equivalent. May be combine * possibilities to the right * * |<----------matched node---------->||<---right node (alloc'd)--->| * |<---findNode (alloc req)--->| */ rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); /* Add allocating instance to owner list for compare with rightNode */ allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode); if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); /* Combine rightNode and findNode */ rightNode->base = findNode.base; rightNode->length += findNode.length; } else { rightNode = rmResourceNodeNew(findNode.base, findNode.length); allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode); } /* Account for rightNode in matchingNode */ matchingNode->length -= findNode.length; RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); /* Right node contains new reference count after alloc. Return new owner count. */ opInfo->resourceInfo->ownerCount = rightNode->allocationCount; } /* Remove allocating instance from leftover matchingNode */ allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); } } retVal = RM_SERVICE_APPROVED; } } else { retVal = RM_SERVICE_DENIED_PARTIAL_ALLOCATION; } } else { retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST; } return(retVal); } /* FUNCTION PURPOSE: Frees an allocator resource *********************************************************************** * DESCRIPTION: Will attempt to free the resource with specified * base and length from the resource's allocator. The * free algorithm will verify the free request parameters * match an allocated range for the resource and that the * range is owned by the instance requesting the free. If * the free is validated the algorithm will free the * resource then combine any resource nodes that may have * become equivalent (in terms of ownership) after the * allocation. */ static int32_t allocatorFree(Rm_Handle rmHandle, Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo) { Rm_ResourceNode findNode; Rm_ResourceNode *matchingNode = NULL; Rm_ResourceNode *leftNode = NULL; Rm_ResourceNode *rightNode = NULL; int combineLeft = RM_FALSE; int combineRight = RM_FALSE; uint32_t findEnd; uint32_t matchingEnd; int32_t retVal; memset((void *)&findNode, 0, sizeof(findNode)); findNode.base = opInfo->resourceInfo->base; findNode.length = opInfo->resourceInfo->length; matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode); if (matchingNode) { findEnd = findNode.base + findNode.length - 1; matchingEnd = matchingNode->base + matchingNode->length - 1; if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) { if (matchingNode->allocationCount) { if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) { if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) { /* Case 1: Free range equals allocated matched node exactly. Attempt to combine * freed node with nodes to left and right. * * |<--left node-->||<---matched node--->||<--right node-->| * |<---free request--->| */ leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode); if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); combineLeft = RM_TRUE; } if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); combineRight = RM_TRUE; } if (combineLeft && combineRight) { /* Combine all three nodes into matchingNode */ matchingNode->base = leftNode->base; matchingNode->length = leftNode->length + matchingNode->length + rightNode->length; allocatorResNodeOwnerClear(rmHandle, leftNode); rmResourceNodeFree(leftNode); allocatorResNodeOwnerClear(rmHandle, rightNode); rmResourceNodeFree(rightNode); } else if (combineLeft) { /* Combine left and matching nodes. Reinsert right. */ matchingNode->base = leftNode->base; matchingNode->length += leftNode->length; allocatorResNodeOwnerClear(rmHandle, leftNode); rmResourceNodeFree(leftNode); if (rightNode) { RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); } } else if (combineRight) { /* Combine right and matching nodes. Reinsert left. */ matchingNode->length += rightNode->length; allocatorResNodeOwnerClear(rmHandle, rightNode); rmResourceNodeFree(rightNode); if (leftNode) { RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); } } else { /* No combine. */ if (leftNode) { RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); } if (rightNode) { RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); } } /* Always reinsert matchingNode */ RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); /* Matching node is what remains after free. Return remaining owner count. */ opInfo->resourceInfo->ownerCount = matchingNode->allocationCount; } else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) { /* Case 2: Free range is less than range in matched node. Split * matched node into three nodes. * * |<----------matched node---------->| * |<---free request--->| * * Remove instance from AllocatedTo list then add it back in for side nodes for * proper accounting of allocations in validInstance list */ RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode); leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base); allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode); allocatorResNodeOwnerAdd(rmHandle, leftNode, opInfo->serviceSrcInstNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd); allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode); allocatorResNodeOwnerAdd(rmHandle, rightNode, opInfo->serviceSrcInstNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); matchingNode->base = findNode.base; matchingNode->length = findNode.length; RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); /* Matching node is what remains after free. Return remaining owner count. */ opInfo->resourceInfo->ownerCount = matchingNode->allocationCount; } else { if (findNode.base == matchingNode->base) { /* Case 3: Free range is on left boundary of matched node. Try to * combine free range with left node. * * |<---left node (free)--->||<----------matched node---------->| * |<---findNode (free req)--->| */ leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); /* Remove freeing instance from owner list for compare with leftNode */ allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode); if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); /* Combine leftNode and findNode */ leftNode->length += findNode.length; } else { leftNode = rmResourceNodeNew(findNode.base, findNode.length); allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode); } /* Remove leftNode range from matchingNode */ matchingNode->base = findNode.base + findNode.length; matchingNode->length = matchingEnd - findEnd; RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); /* Left node is what remains after free. Return remaining owner count. */ opInfo->resourceInfo->ownerCount = leftNode->allocationCount; } else if (findEnd == matchingEnd) { /* Case 4: Free range is on right boundary of matched node. Try to * combine free range with right node. * * |<----------matched node---------->||<---right node (free)--->| * |<---findNode (free req)--->| */ rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); /* Remove freeing instance from owner list for compare with rightNode */ allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode); if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); /* Combine rightNode and findNode */ rightNode->base = findNode.base; rightNode->length += findNode.length; } else { rightNode = rmResourceNodeNew(findNode.base, findNode.length); allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode); } /* Remove rightNode range from matchingNode */ matchingNode->length -= findNode.length; RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); /* Right node is what remains after free. Return remaining owner count. */ opInfo->resourceInfo->ownerCount = rightNode->allocationCount; } /* Add freeing instance back into matchingNode allocations */ allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); } retVal = RM_SERVICE_APPROVED; } else { /* Return owner count. In case it's a reference count check in application */ opInfo->resourceInfo->ownerCount = matchingNode->allocationCount; retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST; } } else { /* Return owner count. In case it's a reference count check in application */ opInfo->resourceInfo->ownerCount = matchingNode->allocationCount; retVal = RM_SERVICE_DENIED_RES_ALREADY_FREE; } } else { retVal = RM_SERVICE_DENIED_PARTIAL_FREE; } } else { retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST; } return(retVal); } /* FUNCTION PURPOSE: Reserves a Linux resource *********************************************************************** * DESCRIPTION: Reserves resources for Linux using the base and length * values retrieved from the Linux DTB via the * "linux-dtb-alias" properties within the GRL. */ static int32_t allocatorReserveLinuxResource(Rm_Handle rmHandle, Rm_LinuxAlias *linuxAlias, Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo) { int32_t retVal = RM_OK; int baseFound = RM_FALSE; int lengthFound = RM_FALSE; uint32_t valueIndex = 0; while ((linuxValues) && (!baseFound || !lengthFound)) { if (linuxAlias->baseOffset == valueIndex) { opInfo->resourceInfo->base = linuxValues->value; baseFound = RM_TRUE; if (linuxAlias->lengthOffset == RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) { opInfo->resourceInfo->length = 1; lengthFound = RM_TRUE; } } else if (linuxAlias->lengthOffset == valueIndex) { opInfo->resourceInfo->length = linuxValues->value; lengthFound = RM_TRUE; } linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue; valueIndex++; } if (!baseFound || !lengthFound) { retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS; } else { /* Allocate resource to Linux */ retVal = rmAllocatorOperation(rmHandle, opInfo); if (retVal == RM_SERVICE_APPROVED) { retVal = RM_OK; } } return (retVal); } /* FUNCTION PURPOSE: Finds and reserves Linux resources *********************************************************************** * DESCRIPTION: Parses the Linux DTB for resources consumed by the * Linux kernel. If the resource is found via the * "linux-dtb-alias" property defined in the GRL it is * reserved. */ static int32_t allocatorFindLinuxResource(Rm_Handle rmHandle, const char *resourceName, void *linuxDtb, Rm_LinuxAlias *linuxAlias) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_AllocatorOpInfo opInfo; Rm_ResourceInfo resourceInfo; uint32_t pathOffset; uint32_t pathSize; char *spacePtr; int32_t propOffset; int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET; int32_t prevDepth = RM_DTB_UTIL_STARTING_DEPTH; int32_t depth = RM_DTB_UTIL_STARTING_DEPTH; int32_t propertyLen; const char *propertyName; const void *propertyData; Rm_LinuxValueRange *linuxValueRange; int32_t retVal = RM_OK; memset((void *)&opInfo, 0, sizeof(opInfo)); memset((void *)&resourceInfo, 0, sizeof(resourceInfo)); strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS); opInfo.policy = rmInst->u.server.globalPolicy; opInfo.serviceSrcInstNode = rmPolicyGetLinuxInstNode(rmHandle); opInfo.operation = Rm_allocatorOp_ALLOCATE_INIT; opInfo.resourceInfo = &resourceInfo; while(linuxAlias) { /* Reset parsing variables */ pathOffset = 0; pathSize = strlen(linuxAlias->path) + 1; nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET; prevDepth = RM_DTB_UTIL_STARTING_DEPTH; resourceInfo.base = 0; resourceInfo.length = 0; spacePtr = strpbrk(linuxAlias->path, " "); if (spacePtr) { *spacePtr = '\0'; } while(pathOffset < pathSize) { /* Move through DTB nodes until next alias path node found */ if (strcmp(linuxAlias->path + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL))) { nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth); if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) { /* Returning from subnode that matched part of alias path without finding * resource values */ retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS; break; } } else { /* Found next alias path node. Move to next node name in path string. */ pathOffset += (strlen(linuxAlias->path + pathOffset) + 1); spacePtr = strpbrk(linuxAlias->path + pathOffset, " "); if (spacePtr) { *spacePtr = '\0'; } prevDepth = fdt_node_depth(linuxDtb, nodeOffset); propOffset = fdt_first_property_offset(linuxDtb, nodeOffset); while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (pathOffset < pathSize)) { propertyData = fdt_getprop_by_offset(linuxDtb, propOffset, &propertyName, &propertyLen); if (strcmp(linuxAlias->path + pathOffset, propertyName) == 0) { /* Found resource at end of alias path */ pathOffset += (strlen(linuxAlias->path + pathOffset) + 1); linuxValueRange = rmDtbUtilLinuxExtractValues(propertyData, propertyLen); retVal = allocatorReserveLinuxResource(rmHandle, linuxAlias, linuxValueRange, &opInfo); rmDtbUtilLinuxFreeValues(linuxValueRange); } propOffset = fdt_next_property_offset(linuxDtb, propOffset); } if (propOffset < -FDT_ERR_NOTFOUND) { retVal = propOffset; break; } } } if (retVal < RM_OK) { break; } linuxAlias = linuxAlias->nextLinuxAlias; } return (retVal); } /* FUNCTION PURPOSE: Creates and initializes a resource allocator *********************************************************************** * DESCRIPTION: Creates a resource allocator for the provided * resource name and resource properties retrieved * from the GRL. Resources will be reserved for * the Linux kernel if the Linux DTB is provided * and there are "linux-dtb-alias" properties * specified in the GRL. */ static int32_t allocatorExtractGrlResProps(Rm_Handle rmHandle, const char *resourceName, Rm_ResourceProperties *resourceProperties, void *linuxDtb) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_ResourceRange *range = NULL; Rm_ResourceRange *rangeBasePtr = NULL; Rm_NsAssignment *nsAssignments = NULL; Rm_NsAssignment *nsAssignmentBasePtr = NULL; Rm_LinuxAlias *linuxAlias = NULL; Rm_NameServerObjCfg nameServerObjCfg; int32_t retVal = RM_OK; if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0)) { range = rangeBasePtr = rmDtbUtilResExtractRange(resourceProperties->rangeData, resourceProperties->rangeLen); if ((retVal = allocatorCreate(rmHandle, resourceName, range)) >= RM_OK) { if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen) { if (linuxDtb) { linuxAlias = rmDtbUtilResExtractLinuxAlias(resourceProperties->linuxAliasData, resourceProperties->linuxAliasLen, &retVal); if (linuxAlias) { retVal = allocatorFindLinuxResource(rmHandle, resourceName, linuxDtb, linuxAlias); } } } } } if (retVal >= RM_OK) { if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) { nsAssignments = rmDtbUtilResExtractNsAssignment(resourceProperties->nsAssignData, resourceProperties->nsAssignLen, &retVal); if (nsAssignments) { nsAssignmentBasePtr = nsAssignments; if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmNameServerTreeInv(rmInst->u.server.nameServer); } while (nsAssignments) { memset((void *)&nameServerObjCfg, 0, sizeof(nameServerObjCfg)); nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer; nameServerObjCfg.nodeCfg.objName = nsAssignments->nsName; nameServerObjCfg.nodeCfg.resourceName = (char *)resourceName; nameServerObjCfg.nodeCfg.resourceBase= nsAssignments->resourceBase; nameServerObjCfg.nodeCfg.resourceLength = nsAssignments->resourceLength; rmNameServerAddObject(&nameServerObjCfg); nsAssignments = nsAssignments->nextNsAssignment; } if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmNameServerTreeWb(rmInst->u.server.nameServer); } rmDtbUtilResFreeNsAssignmentList(nsAssignmentBasePtr); } } } else { allocatorDelete(rmHandle, resourceName); } rmDtbUtilResFreeRange(rangeBasePtr); if (linuxAlias) { rmDtbUtilResFreeLinuxAlias(linuxAlias); } return(retVal); } /********************************************************************** ********************** Internal Functions **************************** **********************************************************************/ /* FUNCTION PURPOSE: Finds an allocator *********************************************************************** * DESCRIPTION: Returns a pointer to an allocator that matches the * provided resource name. */ Rm_Allocator *rmAllocatorFind(Rm_Handle rmHandle, const char *resourceName) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Allocator *allocatorList = rmInst->u.server.allocators; while (allocatorList) { RM_SS_OBJ_INV(allocatorList, Rm_Allocator); if (strncmp(allocatorList->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) { break; } allocatorList = allocatorList->nextAllocator; } return (allocatorList); } /* FUNCTION PURPOSE: Issues an allocator operation *********************************************************************** * DESCRIPTION: Issues an allocator preallocate, allocate, or free * for an RM resource. */ int32_t rmAllocatorOperation(Rm_Handle rmHandle, Rm_AllocatorOpInfo *opInfo) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Allocator *allocator = NULL; int32_t resourceOffsetInPolicy; int32_t retVal; resourceOffsetInPolicy = rmPolicyGetResourceOffset(opInfo->policy, opInfo->resourceInfo->name); allocator = rmAllocatorFind(rmHandle, opInfo->resourceInfo->name); if ((resourceOffsetInPolicy > 0) && allocator) { if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmResourceTreeInv(allocator->allocatorRootEntry); } if ((opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_INIT) || (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_USE)) { retVal = allocatorPreAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo); } else if ((opInfo->operation == Rm_allocatorOp_ALLOCATE_INIT) || (opInfo->operation == Rm_allocatorOp_ALLOCATE_USE)) { retVal = allocatorAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo); } else if (opInfo->operation == Rm_allocatorOp_FREE) { retVal = allocatorFree(rmHandle, allocator, opInfo); } if ((rmInst->instType == Rm_instType_SHARED_SERVER) && (retVal == RM_SERVICE_APPROVED)) { rmResourceTreeWb(allocator->allocatorRootEntry); } } else { /* Resource could not be found in policy and/or allocator */ retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST; } return(retVal); } /* FUNCTION PURPOSE: Initializes server allocators *********************************************************************** * DESCRIPTION: Creates and initializes a server instance's * resource allocators using the GRL and, if * provided, Linux DTB. */ int32_t rmAllocatorInitializeResources(Rm_Handle rmHandle, void *globalResourceDtb, void *linuxDtb) { int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET; int32_t nodeDepth = RM_DTB_UTIL_STARTING_DEPTH; Rm_ResourceProperties resProperties; int32_t propOffset; int32_t propertyLen; const char *propertyName; const void *propertyData; Rm_ResourcePropType propertyType; int32_t retVal = RM_OK; /* Parse the Global Resource List, creating an allocator for each specified resource node */ while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (nodeDepth >= RM_DTB_UTIL_STARTING_DEPTH)) { memset((void *)&resProperties, 0, sizeof(resProperties)); /* Get properties of resource node */ propOffset = fdt_first_property_offset(globalResourceDtb, nodeOffset); while (propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) { propertyData = fdt_getprop_by_offset(globalResourceDtb, propOffset, &propertyName, &propertyLen); propertyType = rmDtbUtilResGetPropertyType(propertyName); if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) { resProperties.rangeData = propertyData; resProperties.rangeLen = propertyLen; } else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) { resProperties.nsAssignData = propertyData; resProperties.nsAssignLen = propertyLen; } else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS) { resProperties.linuxAliasData = propertyData; resProperties.linuxAliasLen = propertyLen; } else { retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY; goto exitAllocInit; } propOffset = fdt_next_property_offset(globalResourceDtb, propOffset); if (propOffset == -FDT_ERR_NOTFOUND) { /* No more resource properties but at least one found. Extract the property values */ retVal = allocatorExtractGrlResProps(rmHandle, fdt_get_name(globalResourceDtb, nodeOffset, NULL), &resProperties, linuxDtb); if (retVal < RM_OK) { goto exitAllocInit; } } else if (propOffset < -FDT_ERR_NOTFOUND) { /* Error returned by LIBFDT */ retVal = propOffset; goto exitAllocInit; } } if (propOffset < -FDT_ERR_NOTFOUND) { /* Error returned by LIBFDT */ retVal = propOffset; goto exitAllocInit; } nodeOffset = fdt_next_node(globalResourceDtb, nodeOffset, &nodeDepth); if (nodeOffset < -FDT_ERR_NOTFOUND) { /* Error returned by LIBFDT */ retVal = nodeOffset; goto exitAllocInit; } } exitAllocInit: return(retVal); } /* FUNCTION PURPOSE: Deletes server allocators *********************************************************************** * DESCRIPTION: Removes all resource nodes for each * resource allocator and then deletes the allocator * itself. Used to free all memory consumed * by the allocators. */ void rmAllocatorDeleteResources(Rm_Handle rmHandle) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Allocator *allocatorList = allocatorGetAllocatorList(rmHandle); Rm_Allocator *nextAllocator; Rm_ResourceTree *resTree; Rm_ResourceNode *resNode; Rm_ResourceNode *nextResNode; while (allocatorList) { RM_SS_OBJ_INV(allocatorList, Rm_Allocator); nextAllocator = allocatorList->nextAllocator; resTree = allocatorList->allocatorRootEntry; if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmResourceTreeInv(resTree); } /* Delete each resource node in the allocator */ for (resNode = RB_MIN(_Rm_AllocatorResourceTree, resTree); resNode != NULL; resNode = nextResNode) { nextResNode = RB_NEXT(_Rm_AllocatorResourceTree, resTree, resNode); RB_REMOVE(_Rm_AllocatorResourceTree, resTree, resNode); if (resNode->allocationCount) { /* Delete all the owners in the resource's owner list */ allocatorResNodeOwnerClear(rmHandle, resNode); } rmResourceNodeFree(resNode); } Rm_osalFree((void *)resTree, sizeof(*resTree)); Rm_osalFree((void *)allocatorList, sizeof(*allocatorList)); allocatorList = nextAllocator; } }