/** * @file rm.c * * @brief * This is the Resource Manager 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 */ /* Standard includes */ #include #include #include /* RM external includes */ #include #include #include #include /* RM internal includes */ #include #include #include #include #include #include /* RM LIBFDT includes */ #include /* Tree algorithm includes */ #include /* RM OSAL layer */ #include /********************************************************************** ************************** Globals *********************************** **********************************************************************/ /** @brief Global Variable which describes the RM Version Information */ const char rmVersionStr[] = RM_VERSION_STR ":" __DATE__ ":" __TIME__; /********************************************************************** ************************ Local Functions ***************************** **********************************************************************/ /* FUNCTION PURPOSE: Initializes a RM inst's transaction sequence number *********************************************************************** * DESCRIPTION: The RM instance transaction sequence number can never * have a value of 0 to avoid conflicts with transactions * that have a remoteOriginatingId of 0 (transaction ID * will be used as the remoteOriginatingId for * transactions that are responses to requests). */ static uint32_t transactionInitSequenceNum(void) { return (1); } /* FUNCTION PURPOSE: Provides a sequence number for new transactions *********************************************************************** * DESCRIPTION: Returns a sequence number for a new transaction * specific to a RM instance. Handles rollover of * sequence number. */ static uint32_t transactionGetSequenceNum(Rm_Inst *rmInst) { rmInst->transactionSeqNum++; if (!rmInst->transactionSeqNum) { rmInst->transactionSeqNum++; } return (rmInst->transactionSeqNum); } /* 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_Inst *rmInst, const char *resourceName) { Rm_Allocator *allocators = rmInst->allocators; Rm_Allocator *newAllocator = NULL; newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator)); if (newAllocator) { memset((void *)newAllocator, 0, sizeof(Rm_Allocator)); 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; } else { rmInst->allocators = newAllocator; } } return (newAllocator); } /* 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_Inst *rmInst, char *resourceName) { Rm_Allocator *allocator = rmInst->allocators; Rm_Allocator *prevAllocator = 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->allocators = allocator->nextAllocator; } else { prevAllocator->nextAllocator = allocator->nextAllocator; } Rm_osalFree((void *)allocator, sizeof(Rm_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 addOwner(Rm_ResourceNode *node, void *serviceInstNode) { Rm_Owner *ownerList = node->ownerList; Rm_Owner *newOwner = NULL; newOwner = Rm_osalMalloc(sizeof(Rm_Owner)); if (newOwner) { newOwner->instNameNode = serviceInstNode; newOwner->nextOwner = NULL; /* Add owner entry to end of list */ if (ownerList) { while (ownerList->nextOwner) { ownerList = ownerList->nextOwner; } ownerList->nextOwner = newOwner; } else { node->ownerList = newOwner; } node->allocationCount++; newOwner->instNameNode->allocRefCount++; } } /* 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 bool isOwnedBy(Rm_ResourceNode *node, void *serviceInstNode) { Rm_Owner *owner = node->ownerList; while (owner) { if (owner->instNameNode == serviceInstNode) { return(true); } owner = owner->nextOwner; } return(false); } /* FUNCTION PURPOSE: Compares two resource node's owners *********************************************************************** * DESCRIPTION: Returns TRUE if the owners of two resource nodes * are equivalent. Otherwise, returns FALSE. */ static bool compareResourceNodeOwners(Rm_ResourceNode *node1, Rm_ResourceNode *node2) { Rm_Owner *node1Owners = node1->ownerList; Rm_Owner *node2Owners = node2->ownerList; bool matchedInst; if (node1->allocationCount == node2->allocationCount) { while (node1Owners) { matchedInst = false; while (node2Owners) { if (node1Owners->instNameNode == node2Owners->instNameNode) { matchedInst = true; break; } node2Owners = node2Owners->nextOwner; } if (matchedInst) { node2Owners = node2->ownerList; node1Owners = node1Owners->nextOwner; } else { return(false); } } } else { return(false); } return(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 deleteOwner(Rm_ResourceNode *node, void *serviceInstNode) { Rm_Owner *owner = node->ownerList; Rm_Owner *prevOwner = NULL; while (owner) { if (owner->instNameNode == serviceInstNode) { break; } prevOwner = owner; owner = owner->nextOwner; } if (prevOwner == NULL) { node->ownerList = owner->nextOwner; } else { prevOwner->nextOwner = owner->nextOwner; } node->allocationCount--; owner->instNameNode->allocRefCount--; Rm_osalFree((void *)owner, sizeof(Rm_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 the * source resource node's owners */ static void copyOwners(Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode) { Rm_Owner *srcOwnerList = srcNode->ownerList; Rm_Owner *dstNewOwner; Rm_Owner *dstPrevOwner; dstNode->allocationCount = srcNode->allocationCount; while (srcOwnerList) { dstNewOwner = Rm_osalMalloc(sizeof(Rm_Owner)); dstNewOwner->instNameNode = srcOwnerList->instNameNode; dstNewOwner->nextOwner = NULL; if (dstNode->ownerList == NULL) { dstNode->ownerList = dstNewOwner; } else { dstPrevOwner->nextOwner = dstNewOwner; } 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 clearOwners(Rm_ResourceNode *node) { Rm_Owner *owner = node->ownerList; Rm_Owner *nextOwner; while (owner) { nextOwner = owner->nextOwner; node->allocationCount--; Rm_osalFree((void *)owner, sizeof(Rm_Owner)); owner = nextOwner; } } /* FUNCTION PURPOSE: Creates a new resource tree *********************************************************************** * DESCRIPTION: Creates a new resource tree using the provided * resource name and value range. The name and value * typically originate from the GRL. */ static int32_t createResourceTree(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range) { Rm_Allocator *allocator = NULL; Rm_ResourceTree *treeRootEntry = NULL; Rm_ResourceNode *treeNode = NULL; Rm_ResourceNode *collidingNode = NULL; allocator = allocatorAdd(rmInst, resourceName); treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree)); RB_INIT(treeRootEntry); while (range != NULL) { treeNode = rmResourceNodeNew(range->base, range->length); collidingNode = RB_INSERT(_Rm_AllocatorResourceTree, treeRootEntry, treeNode); if (collidingNode) { Rm_ResourceNode *nextNode = NULL; /* Node that was inserted collides with existing node. Destroy tree and return error */ for (treeNode = RB_MIN(_Rm_AllocatorResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode) { nextNode = RB_NEXT(_Rm_AllocatorResourceTree, treeRootEntry, treeNode); RB_REMOVE(_Rm_AllocatorResourceTree, treeRootEntry, nextNode); rmResourceNodeFree(treeNode); } Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree)); allocatorDelete(rmInst, allocator->resourceName); return (RM_ERROR_GRL_RES_SPECIFIED_MORE_THAN_ONCE); } range = range->nextRange; } allocator->allocatorRootEntry = treeRootEntry; return(RM_OK); } /* FUNCTION PURPOSE: Preallocates a 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 treePreAllocate(Rm_Inst *rmInst, Rm_Allocator *allocator, int32_t resourcePolicy, Rm_AllocatorOpInfo *opInfo) { Rm_ResourceNode findNode; Rm_ResourceNode *matchingNode = NULL; uint32_t matchingEnd; uint32_t rangeIndex; bool resourceFound = false; Rm_PolicyCheckType policyCheckType; Rm_PolicyCheckCfg policyCheckCfg; bool nodePassesPolicy; int32_t retVal = RM_SERVICE_PROCESSING; opInfo->resourceInfo->base = rmPolicyGetResourceBase(rmInst->policy, opInfo->serviceSrcInstNode, resourcePolicy, opInfo->allocType, &retVal); if (retVal != RM_SERVICE_PROCESSING) { return (retVal); } if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) { /* Get alignment from policy */ opInfo->resourceInfo->alignment = rmPolicyGetResourceAlignment(rmInst->policy, resourcePolicy); } if (opInfo->resourceInfo->alignment == 0) { opInfo->resourceInfo->alignment = 1; } memset((void *)&findNode, 0, sizeof(Rm_ResourceNode)); findNode.base = opInfo->resourceInfo->base; findNode.length = opInfo->resourceInfo->length; /* Configure policy checking structure */ memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg)); if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) { policyCheckType = Rm_policyCheck_INIT; } else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) { policyCheckType = Rm_policyCheck_USE; } policyCheckCfg.policyDtb = rmInst->policy; policyCheckCfg.resourceOffset = resourcePolicy; do { matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode); if (matchingNode) { nodePassesPolicy = 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)) { /* 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; 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_SERVICE_PROCESSING) { 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 = true; } } 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 a 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 treeAllocate(Rm_Inst *rmInst, 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; bool allocPassesPolicy; bool combineLeft = false; bool combineRight = false; uint32_t findEnd; uint32_t matchingEnd; int32_t retVal = RM_SERVICE_PROCESSING; memset((void *)&findNode, 0, sizeof(Rm_ResourceNode)); 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(Rm_PolicyCheckCfg)); if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) { policyCheckType = Rm_policyCheck_INIT; } else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) { policyCheckType = Rm_policyCheck_USE; } 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(rmInst->validInstances)) { /* Bypass policy checks since Linux Kernel has full privileges */ allocPassesPolicy = true; } else { policyCheckCfg.policyDtb = rmInst->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 (!isOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) { /* Perform exclusive checks if requesting instance does not already an * owner of the resource */ if (allocPassesPolicy && (matchingNode->allocationCount > 0)) { /* 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 (!isOwnedBy(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); addOwner(matchingNode, opInfo->serviceSrcInstNode); if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); combineLeft = true; } if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); combineRight = true; } if (combineLeft && combineRight) { /* Combine all three nodes into matchingNode */ matchingNode->base = leftNode->base; matchingNode->length = leftNode->length + matchingNode->length + rightNode->length; clearOwners(leftNode); rmResourceNodeFree(leftNode); clearOwners(rightNode); rmResourceNodeFree(rightNode); } else if (combineLeft) { /* Combine left and matching nodes. Reinsert right. */ matchingNode->base = leftNode->base; matchingNode->length += leftNode->length; clearOwners(leftNode); rmResourceNodeFree(leftNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); } else if (combineRight) { /* Combine right and matching nodes. Reinsert left. */ matchingNode->length += rightNode->length; clearOwners(rightNode); rmResourceNodeFree(rightNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); } else { /* No combine. */ RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); } /* Always reinsert matchingNode */ RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); } 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); copyOwners(leftNode, matchingNode); rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd); copyOwners(rightNode, matchingNode); matchingNode->base = findNode.base; matchingNode->length = findNode.length; addOwner(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); } 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 */ addOwner(matchingNode, opInfo->serviceSrcInstNode); if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); /* Combine leftNode and findNode */ leftNode->length += findNode.length; } else { leftNode = rmResourceNodeNew(findNode.base, findNode.length); copyOwners(leftNode, matchingNode); } /* Account for leftNode in matchingNode */ matchingNode->base = findNode.base + findNode.length; matchingNode->length = matchingEnd - findEnd; RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); } 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 */ addOwner(matchingNode, opInfo->serviceSrcInstNode); if (rightNode && compareResourceNodeOwners(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); copyOwners(rightNode, matchingNode); } /* Account for rightNode in matchingNode */ matchingNode->length -= findNode.length; RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); } /* Remove allocating instance from leftover matchingNode */ deleteOwner(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 a 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 treeFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo) { Rm_ResourceNode findNode; Rm_ResourceNode *matchingNode = NULL; Rm_ResourceNode *leftNode = NULL; Rm_ResourceNode *rightNode = NULL; bool combineLeft = false; bool combineRight = false; uint32_t findEnd; uint32_t matchingEnd; int32_t retVal; memset((void *)&findNode, 0, sizeof(Rm_ResourceNode)); 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 (isOwnedBy(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); deleteOwner(matchingNode, opInfo->serviceSrcInstNode); if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); combineLeft = true; } if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); combineRight = true; } if (combineLeft && combineRight) { /* Combine all three nodes into matchingNode */ matchingNode->base = leftNode->base; matchingNode->length = leftNode->length + matchingNode->length + rightNode->length; clearOwners(leftNode); rmResourceNodeFree(leftNode); clearOwners(rightNode); rmResourceNodeFree(rightNode); } else if (combineLeft) { /* Combine left and matching nodes. Reinsert right. */ matchingNode->base = leftNode->base; matchingNode->length += leftNode->length; clearOwners(leftNode); rmResourceNodeFree(leftNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); } else if (combineRight) { /* Combine right and matching nodes. Reinsert left. */ matchingNode->length += rightNode->length; clearOwners(rightNode); rmResourceNodeFree(rightNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); } else { /* No combine. */ RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); } /* Always reinsert matchingNode */ RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); } 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); deleteOwner(matchingNode, opInfo->serviceSrcInstNode); leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base); copyOwners(leftNode, matchingNode); addOwner(leftNode, opInfo->serviceSrcInstNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd); copyOwners(rightNode, matchingNode); addOwner(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); } 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 */ deleteOwner(matchingNode, opInfo->serviceSrcInstNode); if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) { RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); /* Combine leftNode and findNode */ leftNode->length += findNode.length; } else { leftNode = rmResourceNodeNew(findNode.base, findNode.length); copyOwners(leftNode, matchingNode); } /* Remove leftNode range from matchingNode */ matchingNode->base = findNode.base + findNode.length; matchingNode->length = matchingEnd - findEnd; RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode); } 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 */ deleteOwner(matchingNode, opInfo->serviceSrcInstNode); if (rightNode && compareResourceNodeOwners(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); copyOwners(rightNode, matchingNode); } /* Remove rightNode range from matchingNode */ matchingNode->length -= findNode.length; RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); } /* Add freeing instance back into matchingNode allocations */ addOwner(matchingNode, opInfo->serviceSrcInstNode); RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); } retVal = RM_SERVICE_APPROVED; } else { retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST; } } else { 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: Creates a resource request packet *********************************************************************** * DESCRIPTION: Returns a RM packet handle that points to a RM * resource request packet that has been prepared * for sending to another RM instance. The packet * is allocated via the rmAllocPkt API using the * appTransport handle provided by the application */ void createResourceReqPkt(Rm_Packet *rmPkt, char *localInstName, Rm_Transaction *transaction) { Rm_ResourceRequestPkt *resourceReqPkt = NULL; rmPkt->pktType = Rm_pktType_RESOURCE_REQUEST; resourceReqPkt = (Rm_ResourceRequestPkt *) rmPkt->data; resourceReqPkt->requestId = transaction->localId; if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) { resourceReqPkt->resourceReqType = Rm_resReqPktType_ALLOCATE_INIT; } else if (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) { resourceReqPkt->resourceReqType = Rm_resReqPktType_ALLOCATE_USE; } else if (transaction->type == Rm_service_RESOURCE_FREE) { resourceReqPkt->resourceReqType = Rm_resReqPktType_FREE; } else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) { resourceReqPkt->resourceReqType = Rm_resReqPktType_GET_NAMED; } strncpy(resourceReqPkt->pktSrcInstName, localInstName, RM_NAME_MAX_CHARS); strncpy(resourceReqPkt->serviceSrcInstName, transaction->serviceSrcInstName, RM_NAME_MAX_CHARS); memcpy ((void *)&(resourceReqPkt->resourceInfo), (void *)&(transaction->resourceInfo), sizeof(Rm_ResourceInfo)); } /* FUNCTION PURPOSE: Creates a resource response packet *********************************************************************** * DESCRIPTION: Returns a RM packet handle that points to a RM * resource response packet that has been prepared * for sending to another RM instance. The packet * is allocated via the rmAllocPkt API using the * appTransport handle provided by the application */ void createResourceResponsePkt(Rm_Packet *rmPkt, Rm_Transaction *transaction) { Rm_ResourceResponsePkt *resourceRespPkt = NULL; rmPkt->pktType = Rm_pktType_RESOURCE_RESPONSE; resourceRespPkt = (Rm_ResourceResponsePkt *)rmPkt->data; resourceRespPkt->responseId = transaction->remoteOriginatingId; resourceRespPkt->requestState = transaction->state; memcpy ((void *)&(resourceRespPkt->resourceInfo), (void *)&(transaction->resourceInfo), sizeof(Rm_ResourceInfo)); } /* FUNCTION PURPOSE: Creates a NameServer request packet *********************************************************************** * DESCRIPTION: Returns a RM packet handle that points to a RM * NameServer request packet that has been prepared * for sending to another RM instance. The packet * is allocated via the rmAllocPkt API using the * appTransport handle provided by the application */ void createNsRequestPkt(Rm_Packet *rmPkt, char *localInstName, Rm_Transaction *transaction) { Rm_NsRequestPkt *nsReqPkt = NULL; rmPkt->pktType = Rm_pktType_NAMESERVER_REQUEST; nsReqPkt = (Rm_NsRequestPkt *)rmPkt->data; nsReqPkt->requestId = transaction->localId; if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) { nsReqPkt->nsRequestType = Rm_nsReqPktType_MAP_RESOURCE; } else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) { nsReqPkt->nsRequestType = Rm_nsReqPktType_UNMAP_RESOURCE; } strncpy(nsReqPkt->pktSrcInstName, localInstName, RM_NAME_MAX_CHARS); strncpy(nsReqPkt->serviceSrcInstName, transaction->serviceSrcInstName, RM_NAME_MAX_CHARS); memcpy ((void *)&(nsReqPkt->resourceInfo), (void *)&(transaction->resourceInfo), sizeof(Rm_ResourceInfo)); } /* FUNCTION PURPOSE: Creates a NameServer response packet *********************************************************************** * DESCRIPTION: Returns a RM packet handle that points to a RM * NameServer response packet that has been prepared * for sending to another RM instance. The packet * is allocated via the rmAllocPkt API using the * appTransport handle provided by the application */ void createNsResponsePkt(Rm_Packet *rmPkt, Rm_Transaction *transaction) { Rm_NsResponsePkt *nsRespPkt = NULL; rmPkt->pktType = Rm_pktType_NAMESERVER_RESPONSE; nsRespPkt = (Rm_NsResponsePkt *)rmPkt->data; nsRespPkt->responseId = transaction->remoteOriginatingId; nsRespPkt->requestState = transaction->state; } /* FUNCTION PURPOSE: Issues a service response to application *********************************************************************** * DESCRIPTION: Provides a service response back to the application * using the service callback function provided to * the RM instance at the time of the service request. */ static void serviceResponder (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_ServiceRespInfo serviceResponse; /* The responseTransaction will contain the resultant state details of * the requestTransaction's service request */ serviceResponse.serviceState = transaction->state; /* Pass back the ID that was provided to the component when it requested * the service */ serviceResponse.serviceId = transaction->localId; /* Service was approved and service was an allocate request. The resource * data is passed back to the component */ if ((serviceResponse.serviceState == RM_SERVICE_APPROVED) && ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) || (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) || (transaction->type == Rm_service_RESOURCE_GET_BY_NAME))) { strncpy(serviceResponse.resourceName, transaction->resourceInfo.name, RM_NAME_MAX_CHARS); serviceResponse.resourceBase = transaction->resourceInfo.base; serviceResponse.resourceLength = transaction->resourceInfo.length; } /* Issue the callback to the requesting component with the response information */ transaction->callback.serviceCallback(&serviceResponse); /* Delete the transaction from the transaction queue */ rmTransactionQueueDelete(rmInst, transaction->localId); return; } /* FUNCTION PURPOSE: Sends RM response packets *********************************************************************** * DESCRIPTION: Sends RM response packets to RM instance's that sent * RM request packets to the RM instance. The response * is sent via the RM transport API which is plugged * with an application created transport path. */ static void transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_Transport *dstTransport = NULL; Rm_Packet *rmPkt = NULL; Rm_PacketHandle pktHandle = NULL; if (dstTransport = rmTransportFindRemoteName(rmInst->transports, transaction->pktSrcInstName)) { rmPkt = dstTransport->callouts.rmAllocPkt(dstTransport->appTransportHandle, sizeof(Rm_Packet), &pktHandle); if (!rmPkt || !pktHandle) { transaction->state = RM_ERROR_TRANSPORT_ALLOC_PKT_ERROR; goto errorExit; } switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE_INIT: case Rm_service_RESOURCE_ALLOCATE_USE: case Rm_service_RESOURCE_FREE: case Rm_service_RESOURCE_GET_BY_NAME: createResourceResponsePkt(rmPkt, transaction); break; case Rm_service_RESOURCE_MAP_TO_NAME: case Rm_service_RESOURCE_UNMAP_NAME: createNsResponsePkt(rmPkt, transaction); break; } if (dstTransport->callouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) { transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR; goto errorExit; } /* Response packet sent: Delete transaction from queue */ rmTransactionQueueDelete(rmInst, transaction->localId); } else { transaction->state = RM_ERROR_TRANSPORT_REMOTE_HNDL_NOT_REGD; } errorExit: /* Do not delete transaction on error. Error transactions should be visible from * from Rm_printInstanceStatus() */ return; } /* FUNCTION PURPOSE: Sends RM request packets *********************************************************************** * DESCRIPTION: Sends RM request packets to RM instance's that are * capable of forwarding or validating service requests. * The request is sent via the RM transport API which is * plugged with an application created transport path. */ static void transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_Transport *dstTransport = NULL; Rm_Packet *rmPkt = NULL; Rm_PacketHandle pktHandle = NULL; if (rmInst->instType == Rm_instType_CLIENT) { dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_CLIENT_DELEGATE); if (!dstTransport) { dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_SERVER); } } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_SERVER); } /* Just queue transaction if transport hasn't been registered. Do not return error */ if (dstTransport) { rmPkt = dstTransport->callouts.rmAllocPkt(dstTransport->appTransportHandle, sizeof(Rm_Packet), &pktHandle); if (!rmPkt || !pktHandle) { transaction->state = RM_ERROR_TRANSPORT_ALLOC_PKT_ERROR; goto errorExit; } switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE_INIT: case Rm_service_RESOURCE_ALLOCATE_USE: case Rm_service_RESOURCE_FREE: case Rm_service_RESOURCE_GET_BY_NAME: createResourceReqPkt(rmPkt, rmInst->instName, transaction); break; case Rm_service_RESOURCE_MAP_TO_NAME: case Rm_service_RESOURCE_UNMAP_NAME: createNsRequestPkt(rmPkt, rmInst->instName, transaction); break; } if (dstTransport->callouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) { transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR; goto errorExit; } transaction->hasBeenForwarded = true; /* Transaction not deleted. Waiting for response from RM CD or Server */ } errorExit: return; } /* FUNCTION PURPOSE: Issues an allocator operation *********************************************************************** * DESCRIPTION: Issues an allocator preallocate, allocate, or free * for an RM resource. */ static int32_t allocatorOperation(Rm_Inst *rmInst, Rm_AllocatorOpInfo *opInfo) { Rm_Allocator *allocator = NULL; int32_t resourceOffsetInPolicy; int32_t retVal; resourceOffsetInPolicy = rmPolicyGetResourceOffset(rmInst->policy, opInfo->resourceInfo->name); allocator = rmAllocatorFind(rmInst->allocators, opInfo->resourceInfo->name); if ((resourceOffsetInPolicy > 0) && allocator) { if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE) { retVal = treePreAllocate(rmInst, allocator, resourceOffsetInPolicy, opInfo); } else if (opInfo->operation == Rm_allocatorOp_ALLOCATE) { retVal = treeAllocate(rmInst, allocator, resourceOffsetInPolicy, opInfo); } else if (opInfo->operation == Rm_allocatorOp_FREE) { retVal = treeFree(allocator, opInfo); } } else { /* Resource could not be found in policy and/or allocator */ retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST; } return(retVal); } /* FUNCTION PURPOSE: Arbitrates allocation service requests *********************************************************************** * DESCRIPTION: Issues a set of allocator operations in order to * handle a received allocation request. Allocation * requests are always forwarded to the Server on Client * CD instances. If a request is made with a NameServer * name the resource base and length parameters are * retrieved from the NameServer prior to the allocation * attempt. */ static void allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode, uint32_t allocType) { Rm_AllocatorOpInfo opInfo; Rm_NameServerObjCfg nameServerObjCfg; int32_t retVal = transaction->state; memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo)); if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { /* Forward all allocation requests to Server if transport is up. Otherwise, just queue. */ if (rmInst->registeredWithDelegateOrServer) { transactionForwarder(rmInst, transaction); } } else if (rmInst->instType == Rm_instType_SERVER) { opInfo.resourceInfo = &transaction->resourceInfo; opInfo.serviceSrcInstNode = validInstNode; opInfo.allocType = allocType; /* Populated NameServer name has precedence over base */ if (strlen(transaction->resourceInfo.nameServerName) > 0) { if ((transaction->resourceInfo.base == 0) && (transaction->resourceInfo.length == 0) && (transaction->resourceInfo.alignment == 0)) { memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg)); nameServerObjCfg.nameServerTree = rmInst->nameServer; nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName; if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) { strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS); transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase; transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength; } } else { retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT; } } if (retVal == RM_SERVICE_PROCESSING) { if (transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED) { opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE; retVal = allocatorOperation(rmInst, &opInfo); } if (retVal == RM_SERVICE_PROCESSING) { opInfo.operation = Rm_allocatorOp_ALLOCATE; retVal = allocatorOperation(rmInst, &opInfo); } } transaction->state = retVal; if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) { /* Source of allocation was not the server instance, provide the transaction * to the transaction responder */ transactionResponder(rmInst, transaction); } /* Otherwise let the return stack return the transaction to the serviceHandler */ } } /* FUNCTION PURPOSE: Arbitrates free service requests *********************************************************************** * DESCRIPTION: Issues a set of allocator operations in order to * handle a received free request. Free * requests are always forwarded to the Server on Client * CD instances. If a request is made with a NameServer * name the resource base and length parameters are * retrieved from the NameServer prior to the free * attempt. */ static void freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode) { Rm_AllocatorOpInfo opInfo; Rm_NameServerObjCfg nameServerObjCfg; int32_t retVal = transaction->state; memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo)); if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { /* Forward all free requests to Server if transport is up. Otherwise, just queue. */ if (rmInst->registeredWithDelegateOrServer) { transactionForwarder(rmInst, transaction); } } else if (rmInst->instType == Rm_instType_SERVER) { opInfo.resourceInfo = &transaction->resourceInfo; opInfo.serviceSrcInstNode = validInstNode; /* Populated NameServer name has precedence over base */ if (strlen(transaction->resourceInfo.nameServerName) > 0) { if ((transaction->resourceInfo.base == 0) && (transaction->resourceInfo.length == 0) && (transaction->resourceInfo.alignment == 0)) { memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg)); nameServerObjCfg.nameServerTree = rmInst->nameServer; nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName; if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) { strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS); transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase; transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength; } } else { retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT; } } if(retVal == RM_SERVICE_PROCESSING) { opInfo.operation = Rm_allocatorOp_FREE; retVal = allocatorOperation(rmInst, &opInfo); } transaction->state = retVal; if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) { /* Source of allocation was not the server instance, provide the transaction * to the transaction responder */ transactionResponder(rmInst, transaction); } /* Otherwise let the return stack return the transaction to the serviceHandler */ } } /* 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 reserveLinuxResource(Rm_Inst *rmInst, Rm_LinuxAlias *linuxAlias, Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo) { int32_t retVal = RM_OK; bool baseFound = false; bool lengthFound = false; uint32_t valueIndex = 0; while ((linuxValues) && (!baseFound || !lengthFound)) { if (linuxAlias->baseOffset == valueIndex) { opInfo->resourceInfo->base = linuxValues->value; baseFound = true; if (linuxAlias->lengthOffset == RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) { opInfo->resourceInfo->length = 1; lengthFound = true; } } else if (linuxAlias->lengthOffset == valueIndex) { opInfo->resourceInfo->length = linuxValues->value; lengthFound = 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 = allocatorOperation(rmInst, opInfo); } 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 findAndReserveLinuxResource(Rm_Inst *rmInst, const char *resourceName, void *linuxDtb, Rm_LinuxAlias *linuxAlias) { 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; int32_t propertyLen; const char *propertyName; const void *propertyData; Rm_LinuxValueRange *linuxValueRange; int32_t retVal = RM_OK; memset((void *) &opInfo, 0, sizeof(Rm_AllocatorOpInfo)); memset((void *) &resourceInfo, 0, sizeof(Rm_ResourceInfo)); strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS); opInfo.serviceSrcInstNode = rmPolicyGetLinuxInstNode(rmInst->validInstances); opInfo.operation = Rm_allocatorOp_ALLOCATE; 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 = reserveLinuxResource(rmInst, 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 createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceProperties *resourceProperties, void *linuxDtb) { 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 = createResourceTree(rmInst, resourceName, range)) >= RM_OK) { if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen) { if (linuxDtb) { linuxAlias = rmDtbUtilResExtractLinuxAlias(resourceProperties->linuxAliasData, resourceProperties->linuxAliasLen, &retVal); if (linuxAlias) { retVal = findAndReserveLinuxResource(rmInst, resourceName, linuxDtb, linuxAlias); } } else { retVal = RM_ERROR_GRL_LINUX_ALIAS_BUT_NO_DTB; } } } } if (retVal >= RM_OK) { if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) { nsAssignments = rmDtbUtilResExtractNsAssignment(resourceProperties->nsAssignData, resourceProperties->nsAssignLen, &retVal); if (nsAssignments) { nsAssignmentBasePtr = nsAssignments; while (nsAssignments) { memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg)); nameServerObjCfg.nameServerTree = rmInst->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; } rmDtbUtilResFreeNsAssignmentList(nsAssignmentBasePtr); } } } rmDtbUtilResFreeRange(rangeBasePtr); if (linuxAlias) { rmDtbUtilResFreeLinuxAlias(linuxAlias); } return(retVal); } /* FUNCTION PURPOSE: Recursively parses GRL resource properties *********************************************************************** * DESCRIPTION: Recursively parses and stores GRL resource node * properties using the LIBFDT APIs */ static int32_t parseResourceProperty(void *globalResourceDtb, int32_t offset, Rm_ResourceProperties *propertyInfo) { int32_t propertyLen; const char *propertyName; const void *propertyData; Rm_ResourcePropType propertyType; int32_t retVal = RM_OK; propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen); propertyType = rmDtbUtilResGetPropertyType(propertyName); if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) { propertyInfo->rangeData = propertyData; propertyInfo->rangeLen = propertyLen; } else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) { propertyInfo->nsAssignData = propertyData; propertyInfo->nsAssignLen = propertyLen; } else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS) { propertyInfo->linuxAliasData = propertyData; propertyInfo->linuxAliasLen = propertyLen; } else { retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY; } if (retVal == RM_OK) { offset = fdt_next_property_offset(globalResourceDtb, offset); if (offset >= 0) { retVal = parseResourceProperty(globalResourceDtb, offset, propertyInfo); } else if (offset != -FDT_ERR_NOTFOUND) { /* Error returned by LIBFDT */ retVal = offset; } } return (retVal); } /* FUNCTION PURPOSE: Recursively parses GRL resource nodes *********************************************************************** * DESCRIPTION: Recursively parses GRL resource nodes looking for * resource properties to create the resource allocators. * The LIBFDT APIs are used to parse the GRL. */ static int32_t parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth, void *linuxDtb) { const char *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL); Rm_ResourceProperties resourceProperties; int32_t retVal = RM_OK; int32_t offset; memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties)); /* Get properties of resource node */ offset = fdt_first_property_offset(globalResourceDtb, nodeOffset); if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) { retVal = parseResourceProperty(globalResourceDtb, offset, &resourceProperties); if (retVal < -FDT_ERR_NOTFOUND) { return (retVal); } if (retVal = createAndInitAllocator(rmInst, resourceName, &resourceProperties, linuxDtb) < RM_OK) { return (retVal); } } else if (offset != -FDT_ERR_NOTFOUND) { /* Error returned by LIBFDT */ return (offset); } offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth); if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH)) { retVal = parseResourceNode(rmInst, globalResourceDtb, offset, depth, linuxDtb); if (retVal < -FDT_ERR_NOTFOUND) { return (retVal); } } else if (offset != -FDT_ERR_NOTFOUND) { /* Error returned by LIBFDT */ return (offset); } 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. */ static int32_t initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb, void *linuxDtb) { int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET; int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH; int32_t result = RM_OK; /* Recursively parse the Global Resource List, creating an allocator for * each resource as specified in the node */ result = parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth, linuxDtb); return(result); } /********************************************************************** ********************** Internal Functions **************************** **********************************************************************/ /* FUNCTION PURPOSE: Adds a transaction *********************************************************************** * DESCRIPTION: Returns a pointer to a newly created transaction. * The transaction is created based on a new service * request received via the service API or the * transport API (service forwarded from another instance) */ Rm_Transaction *rmTransactionQueueAdd(Rm_Inst *rmInst) { Rm_Transaction *transactionQueue = rmInst->transactionQueue; Rm_Transaction *newTransaction = NULL; newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction)); if (newTransaction) { memset((void *)newTransaction, 0, sizeof(Rm_Transaction)); newTransaction->localId = transactionGetSequenceNum(rmInst); newTransaction->nextTransaction = NULL; if (transactionQueue) { while (transactionQueue->nextTransaction) { transactionQueue = transactionQueue->nextTransaction; } transactionQueue->nextTransaction = newTransaction; } else { rmInst->transactionQueue = newTransaction; } } return (newTransaction); } /* FUNCTION PURPOSE: Finds a transaction *********************************************************************** * DESCRIPTION: Returns a pointer to a transaction resident * in the transaction queue that matches the provided * transaction ID. */ Rm_Transaction *rmTransactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId) { Rm_Transaction *transaction = rmInst->transactionQueue; while (transaction) { if (transaction->localId == transactionId) { break; } transaction = transaction->nextTransaction; } return (transaction); } /* FUNCTION PURPOSE: Deletes a transaction *********************************************************************** * DESCRIPTION: Deletes the transaction with the provided transaction * ID from the instance's transaction queue. */ int32_t rmTransactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId) { Rm_Transaction *transaction = rmInst->transactionQueue; Rm_Transaction *prevTransaction = NULL; int32_t retVal = RM_OK; while (transaction) { if (transaction->localId == transactionId) { break; } prevTransaction = transaction; transaction = transaction->nextTransaction; } if (transaction) { if (prevTransaction == NULL) { /* Transaction at start of queue. Map second transaction to start of queue * as long as more than one transactions. */ rmInst->transactionQueue = transaction->nextTransaction; } else { /* Transaction in middle or end of queue. */ prevTransaction->nextTransaction = transaction->nextTransaction; } Rm_osalFree((void *)transaction, sizeof(Rm_Transaction)); } else { retVal = RM_ERROR_SERVICE_TRANS_DOES_NOT_EXIST; } return (retVal); } /* FUNCTION PURPOSE: Finds an allocator *********************************************************************** * DESCRIPTION: Returns a pointer to an allocator that matches the * provided resource name. */ Rm_Allocator *rmAllocatorFind(Rm_Allocator *allocatorList, char *resourceName) { while (allocatorList) { if (strncmp(allocatorList->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) { break; } allocatorList = allocatorList->nextAllocator; } return (allocatorList); } /* FUNCTION PURPOSE: Processes a transaction *********************************************************************** * DESCRIPTION: Processes transactions created from services * received via the service handle or the transport. * Transactions will be routed within the RM system * based on the RM instance type and the type of * the transaction. */ void rmTransactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction) { void *validInstNode; Rm_PolicyCheckCfg privCheckCfg; Rm_NameServerObjCfg nameServerObjCfg; uint32_t allocType = 0; /* Handle static transactions originating on this instance. Any other static transactions will be * stored in transaction queue until all transports are up. */ if (((rmInst->instType == Rm_instType_CLIENT) || (rmInst->instType == Rm_instType_CLIENT_DELEGATE)) && (!rmInst->registeredWithDelegateOrServer) && (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS) == 0)) { if (rmInst->staticInfo.staticPolicy) { if ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) || (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE)) { /* Check request against startup policy */ memset((void *)&privCheckCfg, 0, sizeof(Rm_PolicyCheckCfg)); if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) { privCheckCfg.type = Rm_policyCheck_INIT; } else { privCheckCfg.type = Rm_policyCheck_USE; } privCheckCfg.policyDtb = rmInst->staticInfo.staticPolicy; privCheckCfg.validInstNode = rmPolicyGetValidInstNode(rmInst->staticInfo.staticValidInstTree, rmInst->instName); privCheckCfg.resourceOffset = rmPolicyGetResourceOffset(rmInst->staticInfo.staticPolicy, transaction->resourceInfo.name); privCheckCfg.resourceBase = transaction->resourceInfo.base; privCheckCfg.resourceLength = transaction->resourceInfo.length; if (rmPolicyCheckPrivilege(&privCheckCfg, &transaction->state)) { transaction->state = RM_SERVICE_APPROVED_STATIC; } else if (transaction->state == RM_SERVICE_PROCESSING) { /* Privilege check returned false without error */ transaction->state = RM_SERVICE_DENIED_BY_STATIC_POLICY; } } else { transaction->state = RM_SERVICE_DENIED_INVALID_STATIC_REQUEST; } } else { transaction->state = RM_ERROR_REQ_FAILED_NO_STATIC_POLICY; } } else { /* Handle auto-forwarded transactions. These transactions include: * - All request transactions received on Clients are forwarded to the Client Delegate * - NameServer requests received on the Client Delegate are forwarded to the Server */ if ((rmInst->instType == Rm_instType_CLIENT) || ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) && ((transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) || (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) || (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))) { if ((transaction->state != RM_SERVICE_PROCESSING) && (transaction->state != RM_SERVICE_APPROVED_STATIC)) { if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) { /* Transaction did not originate on this instance */ transactionResponder(rmInst, transaction); } else { /* Transaction originated on this instance */ serviceResponder(rmInst, transaction); } } else { /* Forward request if transport is up. Otherwise, just queue. */ if (rmInst->registeredWithDelegateOrServer) { transactionForwarder(rmInst, transaction); } } } else { /* Validate service's originating instance name */ if (rmInst->instType == Rm_instType_SERVER) { validInstNode = rmPolicyGetValidInstNode(rmInst->validInstances, transaction->serviceSrcInstName); if (validInstNode == NULL) { transaction->state = RM_SERVICE_DENIED_INST_NAME_NOT_VALID; /* Send result via responder if transaction did not originate from this instance */ if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) { transactionResponder(rmInst, transaction); } } } switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE_INIT: case Rm_service_RESOURCE_ALLOCATE_USE: case Rm_service_RESOURCE_FREE: if ((transaction->state != RM_SERVICE_PROCESSING) && (transaction->state != RM_SERVICE_APPROVED_STATIC)) { /* Transaction complete */ if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) { /* Transaction result not destined for this instance */ transactionResponder(rmInst, transaction); } else { /* Transaction result destined for this instance */ serviceResponder(rmInst, transaction); } } else { /* Complete allocation/free request */ if (transaction->type == Rm_service_RESOURCE_FREE) { freeHandler(rmInst, transaction, validInstNode); } else { switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE_INIT: RM_policy_SET_PERM(allocType, RM_POLICY_PERM_INIT_SHIFT, 1); break; case Rm_service_RESOURCE_ALLOCATE_USE: RM_policy_SET_PERM(allocType, RM_POLICY_PERM_USE_SHIFT, 1); break; } allocationHandler(rmInst, transaction, validInstNode, allocType); } } break; case Rm_service_RESOURCE_MAP_TO_NAME: case Rm_service_RESOURCE_GET_BY_NAME: case Rm_service_RESOURCE_UNMAP_NAME: /* NameServer resides on server */ memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg)); if (rmInst->nameServer) { nameServerObjCfg.nameServerTree = rmInst->nameServer; nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName; if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) { nameServerObjCfg.nodeCfg.resourceName = transaction->resourceInfo.name; nameServerObjCfg.nodeCfg.resourceBase= transaction->resourceInfo.base; nameServerObjCfg.nodeCfg.resourceLength = transaction->resourceInfo.length; transaction->state = rmNameServerAddObject(&nameServerObjCfg); } else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) { if ((transaction->state = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) { strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS); transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase; transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength; transaction->state = RM_SERVICE_APPROVED; } } else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) { transaction->state = rmNameServerDeleteObject(&nameServerObjCfg); } } else { transaction->state = RM_ERROR_NAMESERVER_DOES_NOT_EXIST; } /* Send result via responder if transaction did not originate from this instance */ if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) { transactionResponder(rmInst, transaction); } break; } } } /* Forward any queued requests that weren't forwarded yet */ if (rmInst->registeredWithDelegateOrServer) { transaction = rmInst->transactionQueue; while(transaction) { if (((transaction->state == RM_SERVICE_PROCESSING) || (transaction->state == RM_SERVICE_APPROVED_STATIC)) && !transaction->hasBeenForwarded) { transactionForwarder(rmInst, transaction); } transaction = transaction->nextTransaction; } } } /********************************************************************** ********************** Application visible APIs ********************** **********************************************************************/ /* FUNCTION PURPOSE: Display status of managed resources *********************************************************************** * DESCRIPTION: Prints the status (allocate/free status, as well as * owners) for all resources managed by the RM * instance network. Also, prints the NameServer name * entries. This function is only available on server * instances. */ void Rm_printResourceStatus(Rm_Handle rmServerHandle) { Rm_Inst *rmInst = (Rm_Inst *)rmServerHandle; Rm_Allocator *allocator = rmInst->allocators; Rm_Owner *owners; Rm_ResourceTree *treeRoot; Rm_ResourceNode *treeNode; if (rmInst->instType == Rm_instType_SERVER) { while (allocator != NULL) { Rm_osalLog("Resource: %s\n", allocator->resourceName); treeRoot = allocator->allocatorRootEntry; RB_FOREACH(treeNode, _Rm_AllocatorResourceTree, treeRoot) { Rm_osalLog(" %10d - %10d ", treeNode->base, treeNode->base + treeNode->length -1); if (treeNode->allocationCount == 0) { Rm_osalLog("NOT ALLOCATED\n"); } else { owners = treeNode->ownerList; Rm_osalLog("allocated to"); while (owners) { Rm_osalLog(" %s", owners->instNameNode->name); owners = owners->nextOwner; } Rm_osalLog("\n"); } } allocator = allocator->nextAllocator; } rmNameServerPrintObjects(rmInst->nameServer); } } /* FUNCTION PURPOSE: Display status of a RM instance *********************************************************************** * DESCRIPTION: Prints the current status of various RM instance * properties such as the state of all transactions * in the transaction queue and registered transports */ void Rm_printInstanceStatus(Rm_Handle rmHandle) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Transport *transportList = rmInst->transports; Rm_Transaction *transactionQ = rmInst->transactionQueue; Rm_osalLog("Instance name: %s\n", rmInst->instName); if (rmInst->instType == Rm_instType_SERVER) { Rm_osalLog("Type: Server\n"); } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { Rm_osalLog("Type: Client Delegate\n"); } else { Rm_osalLog("Type: Client\n"); } if (transportList) { Rm_osalLog("\nRegistered Transports:\n"); while (transportList) { Rm_osalLog(" Remote instName: %s\n", transportList->remoteInstName); if (transportList->remoteInstType == Rm_instType_SERVER) { Rm_osalLog(" Remote instType: Server\n"); } else if (transportList->remoteInstType == Rm_instType_CLIENT_DELEGATE) { Rm_osalLog(" Remote instType: Client Delegate\n"); } else { Rm_osalLog(" Remote instType: Client\n"); } Rm_osalLog(" appTransportHandle: 0x%08x\n", transportList->appTransportHandle); Rm_osalLog("\n"); transportList = transportList->nextTransport; } } if (transactionQ) { Rm_osalLog("\nQueued Service Transactions:\n"); while (transactionQ) { Rm_osalLog(" Service type: %d\n", transactionQ->type); Rm_osalLog(" Service ID: %d\n", transactionQ->localId); Rm_osalLog(" Service srcInstName %s\n", transactionQ->serviceSrcInstName); Rm_osalLog(" Service state: %d\n", transactionQ->state); Rm_osalLog(" Resource name: %s\n", transactionQ->resourceInfo.name); Rm_osalLog(" Resource base: %d\n", transactionQ->resourceInfo.base); Rm_osalLog(" Resource length: %d\n", transactionQ->resourceInfo.length); Rm_osalLog(" Resource alignment: %d\n", transactionQ->resourceInfo.alignment); Rm_osalLog(" Resource NS name: %s\n", transactionQ->resourceInfo.nameServerName); Rm_osalLog("\n"); transactionQ = transactionQ->nextTransaction; } } } /* FUNCTION PURPOSE: RM instance creation and initialization *********************************************************************** * DESCRIPTION: Returns a new RM instance created and initialized * using the parameters provided via the initCfg * structure. */ Rm_Handle Rm_init(const Rm_InitCfg *initCfg, int32_t *result) { Rm_Inst *rmInst; void *globalResourceDtb = NULL; void *linuxResourceDtb = NULL; bool addLinux = false; *result = RM_OK; if ((initCfg->instName == NULL) || ((strlen(initCfg->instName) + 1) > RM_NAME_MAX_CHARS)) { *result = RM_ERROR_INVALID_INST_NAME; return (NULL); } if (initCfg->instType >= Rm_instType_LAST) { *result = RM_ERROR_INVALID_INST_TYPE; } /* Create and initialize instance */ rmInst = Rm_osalMalloc (sizeof(Rm_Inst)); memset ((void *) rmInst, 0, sizeof(Rm_Inst)); rmInst->isLocked = false; rmInst->registeredWithDelegateOrServer = false; rmInst->transactionSeqNum = transactionInitSequenceNum(); rmInst->instType = initCfg->instType; strncpy (rmInst->instName, initCfg->instName, RM_NAME_MAX_CHARS); if (rmInst->instType == Rm_instType_SERVER) { if (!initCfg->instCfg.serverCfg.globalResourceList || !initCfg->instCfg.serverCfg.globalPolicy) { *result = RM_ERROR_INVALID_SERVER_CONFIGURATION; Rm_osalFree((void *)rmInst, sizeof(Rm_Inst)); return(NULL); } rmInst->policy = initCfg->instCfg.serverCfg.globalPolicy; fdt_open_into(rmInst->policy, rmInst->policy, fdt_totalsize(rmInst->policy)); if (initCfg->instCfg.serverCfg.linuxDtb) { linuxResourceDtb = initCfg->instCfg.serverCfg.linuxDtb; fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb)); addLinux = true; } /* Create valid instance list from policy. Must be done prior to parsing * GRL so that Linux resources can be reserved correctly */ rmInst->validInstances = rmPolicyCreateValidInstTree(rmInst->policy, addLinux, result); /* Validate policy assignment strings */ *result = rmPolicyValidatePolicy(rmInst->policy, rmInst->validInstances); rmInst->nameServer = rmNameServerInit(); globalResourceDtb = initCfg->instCfg.serverCfg.globalResourceList; fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb)); if ((*result = initializeAllocators(rmInst, globalResourceDtb, linuxResourceDtb)) == RM_OK) { *result = rmPolicyValidatePolicyResourceNames(rmInst->policy, (void *)rmInst->allocators); } if (*result < RM_OK) { Rm_osalFree((void *)rmInst, sizeof(Rm_Inst)); return(NULL); } } if ((rmInst->instType == Rm_instType_CLIENT) && (initCfg->instCfg.clientCfg.staticPolicy)) { rmInst->staticInfo.staticPolicy = initCfg->instCfg.clientCfg.staticPolicy; } else if ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) && (initCfg->instCfg.cdCfg.staticPolicy)) { rmInst->staticInfo.staticPolicy = initCfg->instCfg.cdCfg.staticPolicy; } if (rmInst->staticInfo.staticPolicy) { fdt_open_into(rmInst->staticInfo.staticPolicy, rmInst->staticInfo.staticPolicy, fdt_totalsize(rmInst->staticInfo.staticPolicy)); rmInst->staticInfo.staticValidInstTree = rmPolicyCreateValidInstTree(rmInst->staticInfo.staticPolicy, addLinux, result); if (*result == RM_OK) { /* Validate policy assignment strings */ *result = rmPolicyValidatePolicy(rmInst->staticInfo.staticPolicy, rmInst->staticInfo.staticValidInstTree); } if (*result != RM_OK) { if (rmInst->staticInfo.staticValidInstTree) { rmPolicyFreeValidInstTree(rmInst->staticInfo.staticValidInstTree); } Rm_osalFree((void *)rmInst, sizeof(Rm_Inst)); rmInst = NULL; } } return ((Rm_Handle) rmInst); } /* FUNCTION PURPOSE: Returns RM version information *********************************************************************** */ uint32_t Rm_getVersion (void) { return RM_VERSION_ID; } /* FUNCTION PURPOSE: Returns RM version string *********************************************************************** */ const char* Rm_getVersionStr (void) { return rmVersionStr; }