Minor updates
[keystone-rtos/rm-lld.git] / src / rm.c
1 /**
2  *   @file  rm.c
3  *
4  *   @brief   
5  *      This is the Resource Manager source.
6  *
7  *  \par
8  *  ============================================================================
9  *  @n   (C) Copyright 2012-2013, Texas Instruments, Inc.
10  * 
11  *  Redistribution and use in source and binary forms, with or without 
12  *  modification, are permitted provided that the following conditions 
13  *  are met:
14  *
15  *    Redistributions of source code must retain the above copyright 
16  *    notice, this list of conditions and the following disclaimer.
17  *
18  *    Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the 
20  *    documentation and/or other materials provided with the   
21  *    distribution.
22  *
23  *    Neither the name of Texas Instruments Incorporated nor the names of
24  *    its contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  *  \par
40 */
42 /* Standard includes */
43 #include <stdint.h>
44 #include <string.h>
45 #include <stdbool.h>
47 /* RM external includes */
48 #include <ti/drv/rm/rm.h>
49 #include <ti/drv/rm/rmver.h>
50 #include <ti/drv/rm/rm_services.h>
51 #include <ti/drv/rm/rm_transport.h>
53 /* RM internal includes */
54 #include <ti/drv/rm/include/rm_loc.h>
55 #include <ti/drv/rm/include/rm_transportloc.h>
56 #include <ti/drv/rm/include/rm_nameserverloc.h>
57 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
58 #include <ti/drv/rm/include/rm_policyloc.h>
59 #include <ti/drv/rm/include/rm_treeloc.h>
61 /* RM LIBFDT includes */
62 #include <ti/drv/rm/util/libfdt/libfdt.h>
64 /* Tree algorithm includes */
65 #include <ti/drv/rm/util/tree.h>
67 /* RM OSAL layer */
68 #include <rm_osal.h>
70 /**********************************************************************
71  ************************** Globals ***********************************
72  **********************************************************************/
74 /** @brief Global Variable which describes the RM Version Information */
75 const char  rmVersionStr[] = RM_VERSION_STR ":" __DATE__  ":" __TIME__;
77 /**********************************************************************
78  ************************ Local Functions *****************************
79  **********************************************************************/
81 /* FUNCTION PURPOSE: Initializes a RM inst's transaction sequence number
82  ***********************************************************************
83  * DESCRIPTION: The RM instance transaction sequence number can never
84  *              have a value of 0 to avoid conflicts with transactions
85  *              that have a remoteOriginatingId of 0 (transaction ID
86  *              will be used as the remoteOriginatingId for
87  *              transactions that are responses to requests).
88  */
89 static uint32_t transactionInitSequenceNum(void)
90 {
91     return (1);
92 }
94 /* FUNCTION PURPOSE: Provides a sequence number for new transactions
95  ***********************************************************************
96  * DESCRIPTION: Returns a sequence number for a new transaction
97  *              specific to a RM instance.  Handles rollover of
98  *              sequence number.
99  */
100 static uint32_t transactionGetSequenceNum(Rm_Inst *rmInst)
102     rmInst->transactionSeqNum++;
103     if (!rmInst->transactionSeqNum) {
104         rmInst->transactionSeqNum++;
105     }    
106     return (rmInst->transactionSeqNum);
109 /* FUNCTION PURPOSE: Creates a resource allocator
110  ***********************************************************************
111  * DESCRIPTION: Returns a newly Created and initialized resource
112  *              The allocator is also stored in the RM instance
113  *              allocator list.            
114  */
115 static Rm_Allocator *allocatorAdd(Rm_Inst *rmInst, const char *resourceName)
117     Rm_Allocator *allocators   = rmInst->allocators;
118     Rm_Allocator *newAllocator = NULL;
120     newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator));
122     if (newAllocator) {
123         memset((void *)newAllocator, 0, sizeof(Rm_Allocator));
124         strncpy(newAllocator->resourceName, resourceName, RM_NAME_MAX_CHARS);
125         newAllocator->allocatorRootEntry = NULL;
126         newAllocator->nextAllocator = NULL;  
128         /* Add allocator to end of list */
129         if (allocators) {
130             while (allocators->nextAllocator) {
131                 allocators = allocators->nextAllocator;
132             }
133             allocators->nextAllocator = newAllocator;
134         }
135         else {
136             rmInst->allocators = newAllocator;
137         }
138     }
139     return (newAllocator);
142 /* FUNCTION PURPOSE: Deletes a resource allocator
143  ***********************************************************************
144  * DESCRIPTION: Deletes a resource allocator based on the given
145  *              resource name.  The resource allocator will be
146  *              removed from the RM instance allocator list.
147  */
148 static int32_t allocatorDelete(Rm_Inst *rmInst, char *resourceName)
150     Rm_Allocator *allocator = rmInst->allocators;
151     Rm_Allocator *prevAllocator = NULL;
152     int32_t       retVal = RM_OK;
154     while (allocator) {
155         if (strncmp(allocator->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
156             break;             
157         }
158         prevAllocator = allocator;
159         allocator = allocator->nextAllocator;
160     }
162     if (allocator) {
163         if (prevAllocator == NULL) {
164             rmInst->allocators = allocator->nextAllocator;
165         }
166         else {
167             prevAllocator->nextAllocator = allocator->nextAllocator;
168         }
169         Rm_osalFree((void *)allocator, sizeof(Rm_Allocator));
170     }
171     else {
172         retVal = RM_ERROR_RES_ALLOCATOR_DOES_NOT_EXIST;
173     }
174     return (retVal);
177 /* FUNCTION PURPOSE: Adds an owner to an allocator resource
178  ***********************************************************************
179  * DESCRIPTION: Adds a RM instance node to a resource node's
180  *              list of owners.
181  */
182 static void addOwner(Rm_ResourceNode *node, void *serviceInstNode)
184     Rm_Owner *ownerList = node->ownerList;
185     Rm_Owner *newOwner = NULL;
187     newOwner = Rm_osalMalloc(sizeof(Rm_Owner));
189     if (newOwner) {
190         newOwner->instNameNode = serviceInstNode;
191         newOwner->nextOwner = NULL;  
193         /* Add owner entry to end of list */
194         if (ownerList) {
195             while (ownerList->nextOwner) {
196                 ownerList = ownerList->nextOwner;
197             }
198             ownerList->nextOwner = newOwner;
199         }
200         else {
201             node->ownerList = newOwner;
202         }
204         node->allocationCount++;
205         newOwner->instNameNode->allocRefCount++;
206     }
209 /* FUNCTION PURPOSE: Checks a resource node's ownership
210  ***********************************************************************
211  * DESCRIPTION: Returns TRUE if the provided instance node is
212  *              in the list of resource node owners.  Otherwise,
213  *              returns FALSE.
214  */
215 static bool isOwnedBy(Rm_ResourceNode *node, void *serviceInstNode)
217     Rm_Owner *owner = node->ownerList;
219     while (owner) {
220         if (owner->instNameNode == serviceInstNode) {
221             return(true);           
222         }
223         owner = owner->nextOwner;
224     }
225     return(false);
228 /* FUNCTION PURPOSE: Compares two resource node's owners
229  ***********************************************************************
230  * DESCRIPTION: Returns TRUE if the owners of two resource nodes 
231  *              are equivalent.  Otherwise, returns FALSE.
232  */
233 static bool compareResourceNodeOwners(Rm_ResourceNode *node1, Rm_ResourceNode *node2)
235     Rm_Owner *node1Owners = node1->ownerList;
236     Rm_Owner *node2Owners = node2->ownerList;
237     bool      matchedInst;
239     if (node1->allocationCount == node2->allocationCount) {
240         while (node1Owners) {
241             matchedInst = false;
242             while (node2Owners) {
243                 if (node1Owners->instNameNode == node2Owners->instNameNode) {
244                     matchedInst = true;
245                     break;
246                 }
247                 node2Owners = node2Owners->nextOwner;
248             }
250             if (matchedInst) {
251                 node2Owners = node2->ownerList;
252                 node1Owners = node1Owners->nextOwner;
253             }
254             else {
255                 return(false);
256             }                
257         }
258     }
259     else {
260         return(false);
261     }  
262     
263     return(true);
266 /* FUNCTION PURPOSE: Deletes an owner from an allocator resource
267  ***********************************************************************
268  * DESCRIPTION: Removes a RM instance node from a resource node's
269  *              list of owners.
270  */
271 static void deleteOwner(Rm_ResourceNode *node, void *serviceInstNode)
273     Rm_Owner *owner = node->ownerList;
274     Rm_Owner *prevOwner = NULL;
276     while (owner) {
277         if (owner->instNameNode == serviceInstNode) {
278             break;             
279         }
280         prevOwner = owner;
281         owner = owner->nextOwner;
282     }
284     if (prevOwner == NULL) {
285         node->ownerList = owner->nextOwner;
286     }
287     else {
288         prevOwner->nextOwner = owner->nextOwner;
289     }
290     
291     node->allocationCount--;
292     owner->instNameNode->allocRefCount--;
293     Rm_osalFree((void *)owner, sizeof(Rm_Owner));
296 /* FUNCTION PURPOSE: Copies the owners of a resource node
297  ***********************************************************************
298  * DESCRIPTION: Creates a list of resource owners for the destination
299  *              resource node that is equivalent to the the 
300  *              source resource node's owners
301  */
302 static void copyOwners(Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode)
304     Rm_Owner *srcOwnerList = srcNode->ownerList;
305     Rm_Owner *dstNewOwner;
306     Rm_Owner *dstPrevOwner;
308     dstNode->allocationCount = srcNode->allocationCount;
310     while (srcOwnerList) {
311         dstNewOwner = Rm_osalMalloc(sizeof(Rm_Owner));
312         dstNewOwner->instNameNode = srcOwnerList->instNameNode;
313         dstNewOwner->nextOwner = NULL;
315         if (dstNode->ownerList == NULL) {
316             dstNode->ownerList = dstNewOwner;
317         }
318         else {
319             dstPrevOwner->nextOwner = dstNewOwner;
320         }
321         dstPrevOwner = dstNewOwner;
322         srcOwnerList = srcOwnerList->nextOwner;
323     }
326 /* FUNCTION PURPOSE: Clears a resource node's owners
327  ***********************************************************************
328  * DESCRIPTION: Deletes all owners from the owners list of a 
329  *              resource node.
330  */
331 static void clearOwners(Rm_ResourceNode *node)
333     Rm_Owner *owner = node->ownerList;
334     Rm_Owner *nextOwner;
336     while (owner) {
337         nextOwner = owner->nextOwner;
338         node->allocationCount--;
339         Rm_osalFree((void *)owner, sizeof(Rm_Owner));
340         owner = nextOwner;
341     }
344 /* FUNCTION PURPOSE: Creates a new resource tree
345  ***********************************************************************
346  * DESCRIPTION: Creates a new resource tree using the provided
347  *              resource name and value range.  The name and value
348  *              typically originate from the GRL.
349  */
350 static int32_t createResourceTree(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)
352     Rm_Allocator    *allocator = NULL;
353     Rm_ResourceTree *treeRootEntry = NULL;
354     Rm_ResourceNode *treeNode = NULL;
355     Rm_ResourceNode *collidingNode = NULL;
357     allocator = allocatorAdd(rmInst, resourceName);
358     treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree));
359     RB_INIT(treeRootEntry);
361     while (range != NULL) {
362         treeNode = rmResourceNodeNew(range->base, range->length);
363         collidingNode = RB_INSERT(_Rm_AllocatorResourceTree, treeRootEntry, treeNode);
365         if (collidingNode) {
366             Rm_ResourceNode *nextNode = NULL;
367             
368             /* Node that was inserted collides with existing node.  Destroy tree and return error */
369             for (treeNode = RB_MIN(_Rm_AllocatorResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode) {
370                         nextNode = RB_NEXT(_Rm_AllocatorResourceTree, treeRootEntry, treeNode);
371                         RB_REMOVE(_Rm_AllocatorResourceTree, treeRootEntry, nextNode);
372                 rmResourceNodeFree(treeNode);
373                 }
374             Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree));
375             allocatorDelete(rmInst, allocator->resourceName);
376             return (RM_ERROR_GRL_RES_SPECIFIED_MORE_THAN_ONCE);
377         }
378         range = range->nextRange;
379     }
380     
381     allocator->allocatorRootEntry = treeRootEntry;
382     return(RM_OK);
385 /* FUNCTION PURPOSE: Preallocates a resource
386  ***********************************************************************
387  * DESCRIPTION: Called when an allocate request is made but the base 
388  *              is unspecified.  The preallocation algorithm looks at 
389  *              available resources as well as policy permissions to 
390  *              determine a resource range that satisfies the request.
391  *              If a valid range is found it will be returned for the 
392  *              treeAllocate algorithm to handle.
393  */
394 static int32_t treePreAllocate(Rm_Inst *rmInst, Rm_Allocator *allocator, int32_t resourcePolicy,
395                                Rm_AllocatorOpInfo *opInfo)
397     Rm_ResourceNode    findNode;
398     Rm_ResourceNode   *matchingNode = NULL;
399     uint32_t           matchingEnd;
400     uint32_t           rangeIndex;
401     bool               resourceFound = false;
402     Rm_PolicyCheckType policyCheckType;
403     Rm_PolicyCheckCfg  policyCheckCfg;
404     bool               nodePassesPolicy;
405     int32_t            retVal = RM_SERVICE_PROCESSING;    
407     opInfo->resourceInfo->base = rmPolicyGetResourceBase(rmInst->policy, opInfo->serviceSrcInstNode, 
408                                                           resourcePolicy, opInfo->allocType, 
409                                                           &retVal);
410     if (retVal != RM_SERVICE_PROCESSING) {
411         return (retVal);
412     }
414     if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) {  
415         /* Get alignment from policy */
416         opInfo->resourceInfo->alignment = rmPolicyGetResourceAlignment(rmInst->policy, resourcePolicy);
417     }
418     
419     if (opInfo->resourceInfo->alignment == 0) {
420         opInfo->resourceInfo->alignment = 1;
421     }    
423     memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
424     findNode.base = opInfo->resourceInfo->base;
425     findNode.length = opInfo->resourceInfo->length;
427     /* Configure policy checking structure */
428     memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
429     if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
430         policyCheckType = Rm_policyCheck_INIT;
431     }
432     else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
433         policyCheckType = Rm_policyCheck_USE;
434     }
435     policyCheckCfg.policyDtb = rmInst->policy;
436     policyCheckCfg.resourceOffset = resourcePolicy;
437     
438     do {
439         matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
440         
441         if (matchingNode) {
442             nodePassesPolicy = false;
443             policyCheckCfg.type = policyCheckType;
444             policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
445             policyCheckCfg.resourceBase = findNode.base;
446             policyCheckCfg.resourceLength = findNode.length;
447             nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);    
448             
449             if (nodePassesPolicy && (matchingNode->allocationCount > 0)) {
450                 /* Check exclusive privileges of instance requesting resource.  Requesting
451                  * instance with exclusive privileges can't reserve resource if already owned*/
452                 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
453                 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
454                 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
455             }
456             
457             if (nodePassesPolicy && (matchingNode->allocationCount == 1)) {
458                 /* Check exclusive privileges of instance that currently owns resource */
459                 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
460                 policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
461                 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
462             }
464             if (retVal != RM_SERVICE_PROCESSING) {
465                 break;
466             }
468             if (nodePassesPolicy) {
469                 matchingEnd = matchingNode->base + matchingNode->length - 1;
470                 /* Initialize indexer to be first resource value that alignment */
471                 rangeIndex = findNode.base;
472                 if (rangeIndex % opInfo->resourceInfo->alignment) {
473                     rangeIndex += (opInfo->resourceInfo->alignment -
474                                   (rangeIndex % opInfo->resourceInfo->alignment));
475                 }
476                 
477                 if ((rangeIndex + opInfo->resourceInfo->length - 1) <= matchingEnd) {
478                     /* Block of unallocated resources within matchingNode that satisfies
479                      * allocate requirements */
480                     opInfo->resourceInfo->base = rangeIndex;
481                     resourceFound = true;
482                 }     
483             }
484             
485             if (!resourceFound) {
486                 /* Check next resource node for available resources */
487                 findNode.base = matchingNode->base + matchingNode->length;
488             }
489         }
490         else {
491             retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
492         }
493     } while ((!resourceFound) && 
494              (retVal != RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET));
496     return(retVal); 
499 /* FUNCTION PURPOSE: Allocates a resource
500  ***********************************************************************
501  * DESCRIPTION: Will attempt to allocate the resource with specified
502  *              base and length from the resource's allocator.  The
503  *              allocation algorithm will verify the allocation against
504  *              the policy permissions for the instance requesting the
505  *              allocation.  If the policy allows the allocation the 
506  *              algorithm will allocate the resource then combine any
507  *              resource nodes that may have become equivalent (in terms
508  *              of ownership) after the allocation.
509  */
510 static int32_t treeAllocate(Rm_Inst *rmInst, Rm_Allocator *allocator, int32_t resourcePolicy,
511                             Rm_AllocatorOpInfo *opInfo)
513     Rm_ResourceNode     findNode;
514     Rm_ResourceNode    *matchingNode = NULL;
515     Rm_ResourceNode    *leftNode = NULL;
516     Rm_ResourceNode    *rightNode = NULL;
517     Rm_PolicyCheckType  policyCheckType;    
518     Rm_PolicyCheckCfg   policyCheckCfg;
519     bool                allocPassesPolicy;
520     bool                combineLeft = false;
521     bool                combineRight = false;    
522     uint32_t            findEnd;
523     uint32_t            matchingEnd;  
524     int32_t             retVal = RM_SERVICE_PROCESSING;
526     memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
527     findNode.base = opInfo->resourceInfo->base;
528     findNode.length = opInfo->resourceInfo->length;
529     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
531     /* Prepare privilege checks */
532     memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
533     if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
534         policyCheckType = Rm_policyCheck_INIT;
535     }
536     else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
537         policyCheckType = Rm_policyCheck_USE;
538     }
540     if (matchingNode) {
541         findEnd = findNode.base + findNode.length - 1;
542         matchingEnd = matchingNode->base + matchingNode->length - 1;
543         
544         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
545             if (opInfo->serviceSrcInstNode == rmPolicyGetLinuxInstNode(rmInst->validInstances)) {
546                 /* Bypass policy checks since Linux Kernel has full privileges */
547                 allocPassesPolicy = true;
548             }
549             else {
550                 policyCheckCfg.policyDtb = rmInst->policy;
551                 policyCheckCfg.resourceOffset = resourcePolicy;    
552                 policyCheckCfg.type = policyCheckType;
553                 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
554                 policyCheckCfg.resourceBase = findNode.base;
555                 policyCheckCfg.resourceLength = findNode.length;
556                 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
557                 if (!allocPassesPolicy) {
558                     if (policyCheckType == Rm_policyCheck_INIT) {
559                         retVal = RM_SERVICE_DENIED_INIT_PERM_NOT_GIVEN;
560                     }
561                     else {
562                         retVal = RM_SERVICE_DENIED_USE_PERM_NOT_GIVEN;
563                     }
564                 }
566                 if (!isOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
567                     /* Perform exclusive checks if requesting instance does not already an
568                      * owner of the resource */
569                     if (allocPassesPolicy && (matchingNode->allocationCount > 0)) {
570                         /* Check exclusive privileges of instance requesting resource.  Requesting
571                          * instance with exclusive privileges can't reserve resource if already owned*/
572                         policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
573                         policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
574                         allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
575                         if (!allocPassesPolicy) {
576                             retVal = RM_SERVICE_DENIED_EXCLUSIVE_RES_ALLOCD;
577                         }
578                     }
579                     if (allocPassesPolicy && (matchingNode->allocationCount == 1)) {
580                         /* Check exclusive privileges of instance that currently owns resource */
581                         policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
582                         policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
583                         allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
584                         if (!allocPassesPolicy) {
585                             retVal = RM_SERVICE_DENIED_ALLOCD_TO_EXCLUSIVE_INST;
586                         }                
587                     }  
588                 }
589             }
590             
591             if (allocPassesPolicy) {
592                 if (!isOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
593                     /* Handle any possible node combinations if requesting instance is
594                      * not already in resource's owner list.  Automatic approval if requesting
595                      * instance is already in owner list. */
596                     if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {
597                         /* findNode range matches matchingNode range
598                          *
599                          *   |<--left node-->||<--matched  node-->||<--right node-->| => existing node
600                          *                    |<--alloc request-->|  => requested resources
601                          */                     
602                         leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
603                         rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
604                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
605                         addOwner(matchingNode, opInfo->serviceSrcInstNode);
607                         if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
608                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
609                             combineLeft = true;
610                         }
611                         if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
612                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
613                             combineRight = true;
614                         }
616                         if (combineLeft && combineRight) {
617                             /* Combine all three nodes into matchingNode */
618                             matchingNode->base = leftNode->base;
619                             matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
621                             clearOwners(leftNode);
622                             rmResourceNodeFree(leftNode);
623                             clearOwners(rightNode);
624                             rmResourceNodeFree(rightNode);                        
625                         }
626                         else if (combineLeft) {
627                             /* Combine left and matching nodes.  Reinsert right. */
628                             matchingNode->base = leftNode->base;
629                             matchingNode->length += leftNode->length;
631                             clearOwners(leftNode);
632                             rmResourceNodeFree(leftNode);
633                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);                        
634                         }
635                         else if (combineRight) {
636                             /* Combine right and matching nodes.  Reinsert left. */
637                             matchingNode->length += rightNode->length;
639                             clearOwners(rightNode);
640                             rmResourceNodeFree(rightNode);
641                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
642                         }
643                         else {
644                             /* No combine. */
645                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
646                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
647                         }
649                         /* Always reinsert matchingNode */                
650                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);   
651                     }   
652                     else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
653                         /* findNode range is subset of matchingNode range and neither boundary is
654                          * equivalent.
655                          *
656                          * |<----------matched node---------->|
657                          *        |<---alloc request--->|
658                          */ 
659                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
660                         leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
661                         copyOwners(leftNode, matchingNode);
662                         rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
663                         copyOwners(rightNode, matchingNode);
665                         matchingNode->base = findNode.base;                                    
666                         matchingNode->length = findNode.length;
667                         addOwner(matchingNode, opInfo->serviceSrcInstNode);
669                         /* Insert all the nodes */
670                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
671                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
672                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
673                     }  
674                     else {    
675                         if (findNode.base == matchingNode->base) {
676                             /* findNode base and matchingNode base are equivalent.  May be combine
677                              * possibilities to the left
678                              *
679                              * |<---left node (alloc'd)--->||<----------matched node---------->|
680                              *                              |<---findNode (alloc req)--->|
681                              */                         
682                             leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
683                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
684                             /* Add allocating instance to owner list for compare with leftNode */
685                             addOwner(matchingNode, opInfo->serviceSrcInstNode);
686                             
687                             if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
688                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
689                                 /* Combine leftNode and findNode */
690                                 leftNode->length += findNode.length;
691                             }
692                             else {
693                                 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
694                                 copyOwners(leftNode, matchingNode);
695                             }
697                             /* Account for leftNode in matchingNode */
698                             matchingNode->base = findNode.base + findNode.length;
699                             matchingNode->length = matchingEnd - findEnd;  
701                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
702                         }
703                         else if (findEnd == matchingEnd) {
704                             /* findNode end and matchingNode end are equivalent.  May be combine
705                              * possibilities to the right
706                              *
707                              * |<----------matched node---------->||<---right node (alloc'd)--->|
708                              *       |<---findNode (alloc req)--->| 
709                              */                        
710                             rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
711                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
712                             /* Add allocating instance to owner list for compare with rightNode */
713                             addOwner(matchingNode, opInfo->serviceSrcInstNode);
714                             
715                             if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
716                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
717                                 /* Combine rightNode and findNode */
718                                 rightNode->base = findNode.base;
719                                 rightNode->length += findNode.length;
720                             }
721                             else {
722                                 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
723                                 copyOwners(rightNode, matchingNode);
724                             }
726                             /* Account for rightNode in matchingNode */
727                             matchingNode->length -= findNode.length;  
729                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
730                         }
731                         /* Remove allocating instance from leftover matchingNode */
732                         deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
733                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
734                     }
735                 }
736                 retVal = RM_SERVICE_APPROVED;
737             }
738         }
739         else {
740             retVal = RM_SERVICE_DENIED_PARTIAL_ALLOCATION;
741         }
742     }
743     else {
744         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
745     }
747     return(retVal);        
750 /* FUNCTION PURPOSE: Frees a resource
751  ***********************************************************************
752  * DESCRIPTION: Will attempt to free the resource with specified
753  *              base and length from the resource's allocator.  The
754  *              free algorithm will verify the free request parameters
755  *              match an allocated range for the resource and that the
756  *              range is owned by the instance requesting the free. If
757  *              the free is validated the algorithm will free the 
758  *              resource then combine any resource nodes that may have
759  *              become equivalent (in terms of ownership) after the
760  *              allocation.
761  */
762 static int32_t treeFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)
764     Rm_ResourceNode  findNode;
765     Rm_ResourceNode *matchingNode = NULL;
766     Rm_ResourceNode *leftNode = NULL;
767     Rm_ResourceNode *rightNode = NULL;
768     bool             combineLeft = false;
769     bool             combineRight = false;
770     uint32_t         findEnd;
771     uint32_t         matchingEnd;
772     int32_t          retVal;
774     memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
775     findNode.base = opInfo->resourceInfo->base;
776     findNode.length = opInfo->resourceInfo->length;
777     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
779     if (matchingNode) {
780         findEnd = findNode.base + findNode.length - 1;
781         matchingEnd = matchingNode->base + matchingNode->length - 1;
782         
783         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {  
784             if (matchingNode->allocationCount) {
785                 if (isOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
786                     if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))
787                     {
788                         /* Case 1: Free range equals allocated matched node exactly. Attempt to combine 
789                          *         freed node with nodes to left and right.
790                          *
791                          * |<--left node-->||<---matched node--->||<--right node-->|
792                          *                  |<---free request--->|
793                          */ 
794                         leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
795                         rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
796                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
797                         deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
799                         if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
800                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
801                             combineLeft = true;
802                         }
803                         if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
804                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
805                             combineRight = true;
806                         }
808                         if (combineLeft && combineRight) {
809                             /* Combine all three nodes into matchingNode */
810                             matchingNode->base = leftNode->base;
811                             matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
813                             clearOwners(leftNode);
814                             rmResourceNodeFree(leftNode);
815                             clearOwners(rightNode);
816                             rmResourceNodeFree(rightNode);                        
817                         }
818                         else if (combineLeft) {
819                             /* Combine left and matching nodes.  Reinsert right. */
820                             matchingNode->base = leftNode->base;
821                             matchingNode->length += leftNode->length;
823                             clearOwners(leftNode);
824                             rmResourceNodeFree(leftNode);
825                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);                        
826                         }
827                         else if (combineRight) {
828                             /* Combine right and matching nodes.  Reinsert left. */
829                             matchingNode->length += rightNode->length;
831                             clearOwners(rightNode);
832                             rmResourceNodeFree(rightNode);
833                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
834                         }
835                         else {
836                             /* No combine. */
837                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
838                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
839                         }
841                         /* Always reinsert matchingNode */
842                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);                    
843                     }
844                     else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
845                         /* Case 2: Free range is less than range in matched node. Split
846                          *         matched node into three nodes.
847                          *
848                          * |<----------matched node---------->|
849                          *        |<---free request--->|
850                          *
851                          * Remove instance from AllocatedTo list then add it back in for side nodes for
852                          * proper accounting of allocations in validInstance list
853                          */ 
854                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
855                         deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
856                         
857                         leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
858                         copyOwners(leftNode, matchingNode);
859                         addOwner(leftNode, opInfo->serviceSrcInstNode);
860                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
861                         
862                         rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
863                         copyOwners(rightNode, matchingNode);
864                         addOwner(rightNode, opInfo->serviceSrcInstNode);
865                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
867                         matchingNode->base = findNode.base;                                    
868                         matchingNode->length = findNode.length;
869                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
870                     }
871                     else {                        
872                         if (findNode.base == matchingNode->base) {
873                             /* Case 3: Free range is on left boundary of matched node. Try to 
874                              *         combine free range with left node.
875                              *
876                              * |<---left node (free)--->||<----------matched node---------->|
877                              *                           |<---findNode (free req)--->|
878                              */ 
880                             leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
881                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
882                             /* Remove freeing instance from owner list for compare with leftNode */
883                             deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
884                             
885                             if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
886                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
887                                 /* Combine leftNode and findNode */
888                                 leftNode->length += findNode.length;
889                             }
890                             else {
891                                 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
892                                 copyOwners(leftNode, matchingNode);
893                             }
895                             /* Remove leftNode range from matchingNode */
896                             matchingNode->base = findNode.base + findNode.length;
897                             matchingNode->length = matchingEnd - findEnd;  
898                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
899                         }
900                         else if (findEnd == matchingEnd) {
901                             /* Case 4: Free range is on right boundary of matched node. Try to 
902                              *         combine free range with right node.
903                              *
904                              * |<----------matched node---------->||<---right node (free)--->|
905                              *        |<---findNode (free req)--->|
906                              */ 
907                             
908                             rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
909                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); 
910                             /* Remove freeing instance from owner list for compare with rightNode */
911                             deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
912                             
913                             if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
914                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
915                                 /* Combine rightNode and findNode */
916                                 rightNode->base = findNode.base;
917                                 rightNode->length += findNode.length;
918                             }
919                             else {
920                                 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
921                                 copyOwners(rightNode, matchingNode);
922                             }
924                             /* Remove rightNode range from matchingNode */
925                             matchingNode->length -= findNode.length;  
926                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
927                         }
929                         /* Add freeing instance back into matchingNode allocations */
930                         addOwner(matchingNode, opInfo->serviceSrcInstNode);
931                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
932                     }
934                     retVal = RM_SERVICE_APPROVED;
935                 }
936                 else {
937                     retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST;
938                 }
939             }
940             else {
941                 retVal = RM_SERVICE_DENIED_RES_ALREADY_FREE;
942             }
943         }
944         else {
945             retVal = RM_SERVICE_DENIED_PARTIAL_FREE;
946         }
947     }
948     else {
949         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
950     }
951     return(retVal);  
954 /* FUNCTION PURPOSE: Issues a service response to application
955  ***********************************************************************
956  * DESCRIPTION: Provides a service response back to the application
957  *              using the service callback function provided to
958  *              the RM instance at the time of the service request.
959  */
960 static void serviceResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)
962     Rm_ServiceRespInfo serviceResponse;
964     /* The responseTransaction will contain the resultant state details of
965      * the requestTransaction's service request */
966     serviceResponse.serviceState = transaction->state;
967     /* Pass back the ID that was provided to the component when it requested
968      * the service */
969     serviceResponse.serviceId = transaction->localId;
971     /* Service was approved and service was an allocate request.  The resource
972      * data is passed back to the component */
973     if ((serviceResponse.serviceState == RM_SERVICE_APPROVED) &&
974         ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
975          (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) ||
976          (transaction->type == Rm_service_RESOURCE_GET_BY_NAME)))
977     {
978         strncpy(serviceResponse.resourceName, transaction->resourceInfo.name, RM_NAME_MAX_CHARS);
979         serviceResponse.resourceBase = transaction->resourceInfo.base;
980         serviceResponse.resourceLength = transaction->resourceInfo.length;
981     }
983     /* Issue the callback to the requesting component with the response information */
984     transaction->callback.serviceCallback(&serviceResponse);
986     /* Delete the transaction from the transaction queue */
987     rmTransactionQueueDelete(rmInst, transaction->localId);
988     return;
991 /* FUNCTION PURPOSE: Sends RM response packets
992  ***********************************************************************
993  * DESCRIPTION: Sends RM response packets to RM instance's that sent
994  *              RM request packets to the RM instance.  The response
995  *              is sent via the RM transport API which is plugged
996  *              with an application created transport path.
997  */
998 static void transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)
1000     Rm_Transport    *dstTransport = NULL;
1001     Rm_PacketHandle  pktHandle = NULL;
1003     dstTransport = rmTransportFindRemoteName((Rm_Transport *) rmInst->transports, transaction->pktSrcInstName);
1005     switch (transaction->type) {
1006         case Rm_service_RESOURCE_ALLOCATE_INIT:
1007         case Rm_service_RESOURCE_ALLOCATE_USE:
1008         case Rm_service_RESOURCE_FREE:
1009         case Rm_service_RESOURCE_GET_BY_NAME:
1010             pktHandle = rmTransportCreateResourceResponsePkt(rmInst, dstTransport->appTransportHandle, 
1011                                                              transaction);
1012             break;
1013         case Rm_service_RESOURCE_MAP_TO_NAME:
1014         case Rm_service_RESOURCE_UNMAP_NAME:
1015             pktHandle = rmTransportCreateNsResponsePkt(rmInst, dstTransport->appTransportHandle,
1016                                                        transaction);
1017             break;
1018     }
1020     if (pktHandle) {
1021         if (rmInst->transportCallouts.rmSendPkt) {
1022             if (rmInst->transportCallouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) {
1023                 transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR;
1024             }
1025         }
1026         else {
1027             transaction->state = RM_ERROR_TRANSPORT_SEND_NOT_REGD;
1028         }
1029     }
1030     rmTransactionQueueDelete(rmInst, transaction->localId);
1033 /* FUNCTION PURPOSE: Sends RM request packets
1034  ***********************************************************************
1035  * DESCRIPTION: Sends RM request packets to RM instance's that are
1036  *              capable of forwarding or validating service requests.
1037  *              The request is sent via the RM transport API which is
1038  *              plugged with an application created transport path.
1039  */
1040 static void transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)
1042     Rm_Transport    *dstTransport = NULL;
1043     Rm_PacketHandle  pktHandle = NULL;
1045     if (rmInst->registeredWithDelegateOrServer) {
1046         if (rmInst->instType == Rm_instType_CLIENT) {
1047             dstTransport = rmTransportFindRemoteInstType((Rm_Transport *) rmInst->transports, Rm_instType_CLIENT_DELEGATE);
1049             if (!dstTransport) {
1050                 dstTransport = rmTransportFindRemoteInstType((Rm_Transport *) rmInst->transports, Rm_instType_SERVER);
1051             }
1052         } 
1053         else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1054             dstTransport = rmTransportFindRemoteInstType((Rm_Transport *) rmInst->transports, Rm_instType_SERVER);
1055         }
1057         switch (transaction->type) {
1058             case Rm_service_RESOURCE_ALLOCATE_INIT:
1059             case Rm_service_RESOURCE_ALLOCATE_USE:
1060             case Rm_service_RESOURCE_FREE:
1061             case Rm_service_RESOURCE_GET_BY_NAME:
1062                 pktHandle = rmTransportCreateResourceReqPkt(rmInst, dstTransport->appTransportHandle, transaction);
1063                 break;
1064             case Rm_service_RESOURCE_MAP_TO_NAME:
1065             case Rm_service_RESOURCE_UNMAP_NAME:
1066                 pktHandle = rmTransportCreateNsRequestPkt(rmInst, dstTransport->appTransportHandle, transaction);
1067                 break;
1068         }
1070         if (pktHandle) {
1071             if (rmInst->transportCallouts.rmSendPkt) {            
1072                 if (rmInst->transportCallouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) {
1073                     transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR;
1074                 }
1075             }
1076             else {
1077                 transaction->state = RM_ERROR_TRANSPORT_SEND_NOT_REGD;
1078             }                
1079         }
1081         transaction->hasBeenForwarded = true;
1082         /* Transaction not deleted.  Waiting for response from RM CD or Server */
1083     }
1086 /* FUNCTION PURPOSE: Issues an allocator operation
1087  ***********************************************************************
1088  * DESCRIPTION: Issues an allocator preallocate, allocate, or free
1089  *              for an RM resource.
1090  */
1091 static int32_t allocatorOperation(Rm_Inst *rmInst, Rm_AllocatorOpInfo *opInfo)
1093     Rm_Allocator *allocator = NULL;
1094     int32_t       resourceOffsetInPolicy;
1095     int32_t       retVal;
1096     
1097     resourceOffsetInPolicy = rmPolicyGetResourceOffset(rmInst->policy, opInfo->resourceInfo->name);
1098     allocator = rmAllocatorFind(rmInst->allocators, opInfo->resourceInfo->name);
1099     
1100     if ((resourceOffsetInPolicy > 0) && allocator) {
1101         if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE) {
1102             retVal = treePreAllocate(rmInst, allocator, resourceOffsetInPolicy, opInfo);
1103         }               
1104         else if (opInfo->operation == Rm_allocatorOp_ALLOCATE) {
1105             retVal = treeAllocate(rmInst, allocator, resourceOffsetInPolicy, opInfo);
1106         }
1107         else if (opInfo->operation == Rm_allocatorOp_FREE) {
1108             retVal = treeFree(allocator, opInfo);
1109         }         
1110     }
1111     else {
1112         /* Resource could not be found in policy and/or allocator */
1113         retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
1114     }
1115     return(retVal);
1118 /* FUNCTION PURPOSE: Arbitrates allocation service requests
1119  ***********************************************************************
1120  * DESCRIPTION: Issues a set of allocator operations in order to
1121  *              handle a received allocation request.  Allocation
1122  *              requests are always forwarded to the Server on Client
1123  *              CD instances.  If a request is made with a NameServer
1124  *              name the resource base and length parameters are
1125  *              retrieved from the NameServer prior to the allocation
1126  *              attempt.
1127  */
1128 static void allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode,
1129                                uint32_t allocType)
1131     Rm_AllocatorOpInfo  opInfo;
1132     Rm_NameServerObjCfg nameServerObjCfg;
1133     int32_t             retVal = transaction->state;
1135     memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
1136     
1137     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1138         /* Forward all allocation requests to Server if transport is up.  Otherwise, just queue. */
1139         if (rmInst->registeredWithDelegateOrServer) {
1140             transactionForwarder(rmInst, transaction);   
1141         }  
1142     }
1143     else if (rmInst->instType == Rm_instType_SERVER) {
1144         opInfo.resourceInfo = &transaction->resourceInfo;
1145         opInfo.serviceSrcInstNode = validInstNode;
1146         opInfo.allocType = allocType;
1148         /* Populated NameServer name has precedence over base */
1149         if (strlen(transaction->resourceInfo.nameServerName) > 0) {
1150             if ((transaction->resourceInfo.base == 0) &&
1151                 (transaction->resourceInfo.length == 0) &&
1152                 (transaction->resourceInfo.alignment == 0)) {
1153                 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1154                 nameServerObjCfg.nameServerTree = rmInst->nameServer;
1155                 nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
1156                 if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
1157                     strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
1158                     transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
1159                     transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
1160                 }                
1161             }
1162             else {
1163                 retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT;
1164             }
1165         }
1167         if (retVal == RM_SERVICE_PROCESSING) {      
1168             if (transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED) {
1169                 opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE;
1170                 retVal = allocatorOperation(rmInst, &opInfo);
1171             }
1172         
1173             if (retVal == RM_SERVICE_PROCESSING) {
1174                 opInfo.operation = Rm_allocatorOp_ALLOCATE;
1175                 retVal = allocatorOperation(rmInst, &opInfo);
1176             }      
1177         }
1178         
1179         transaction->state = retVal;
1181         if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1182             /* Source of allocation was not the server instance, provide the transaction
1183              * to the transaction responder */
1184             transactionResponder(rmInst, transaction);
1185         }
1186         /* Otherwise let the return stack return the transaction to the serviceHandler */                   
1187     }   
1190 /* FUNCTION PURPOSE: Arbitrates free service requests
1191  ***********************************************************************
1192  * DESCRIPTION: Issues a set of allocator operations in order to
1193  *              handle a received free request.  Free
1194  *              requests are always forwarded to the Server on Client
1195  *              CD instances.  If a request is made with a NameServer
1196  *              name the resource base and length parameters are
1197  *              retrieved from the NameServer prior to the free
1198  *              attempt.
1199  */
1200 static void freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode)
1202     Rm_AllocatorOpInfo  opInfo; 
1203     Rm_NameServerObjCfg nameServerObjCfg;    
1204     int32_t             retVal = transaction->state;
1206     memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
1207     
1208     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1209         /* Forward all free requests to Server if transport is up.  Otherwise, just queue. */
1210         if (rmInst->registeredWithDelegateOrServer) {
1211             transactionForwarder(rmInst, transaction);   
1212         }
1213     }
1214     else if (rmInst->instType == Rm_instType_SERVER) {
1215         opInfo.resourceInfo = &transaction->resourceInfo;
1216         opInfo.serviceSrcInstNode = validInstNode;
1218         /* Populated NameServer name has precedence over base */
1219         if (strlen(transaction->resourceInfo.nameServerName) > 0) {
1220             if ((transaction->resourceInfo.base == 0) &&
1221                 (transaction->resourceInfo.length == 0) &&
1222                 (transaction->resourceInfo.alignment == 0)) {
1223                 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1224                 nameServerObjCfg.nameServerTree = rmInst->nameServer;
1225                 nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
1226                 if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
1227                     strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
1228                     transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
1229                     transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
1230                 } 
1231             }
1232             else {
1233                 retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT;
1234             }                
1235         }
1236         
1237         if(retVal == RM_SERVICE_PROCESSING) {        
1238             opInfo.operation = Rm_allocatorOp_FREE;
1239             retVal = allocatorOperation(rmInst, &opInfo);
1240         }       
1242         transaction->state = retVal;
1244         if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1245             /* Source of allocation was not the server instance, provide the transaction
1246              * to the transaction responder */
1247             transactionResponder(rmInst, transaction);
1248         }
1249         /* Otherwise let the return stack return the transaction to the serviceHandler */        
1250     }   
1253 /* FUNCTION PURPOSE: Reserves a Linux resource
1254  ***********************************************************************
1255  * DESCRIPTION: Reserves resources for Linux using the base and length
1256  *              values retrieved from the Linux DTB via the
1257  *              "linux-dtb-alias" properties within the GRL.
1258  */
1259 static int32_t reserveLinuxResource(Rm_Inst *rmInst, Rm_LinuxAlias *linuxAlias, 
1260                                     Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)
1262     int32_t  retVal = RM_OK;
1263     bool     baseFound = false;
1264     bool     lengthFound = false;
1265     uint32_t valueIndex = 0;
1267     while ((linuxValues) && (!baseFound || !lengthFound)) {
1268         if (linuxAlias->baseOffset == valueIndex) {
1269             opInfo->resourceInfo->base = linuxValues->value;
1270             baseFound = true;
1272             if (linuxAlias->lengthOffset == RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) {
1273                 opInfo->resourceInfo->length = 1;
1274                 lengthFound = true;
1275             }
1276         }
1277         else if (linuxAlias->lengthOffset == valueIndex) {
1278             opInfo->resourceInfo->length = linuxValues->value;
1279             lengthFound = true;
1280         }
1282         linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;
1283         valueIndex++;
1284     }
1286     if (!baseFound || !lengthFound) {
1287         retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1288     }
1289     else {
1290         /* Allocate resource to Linux */
1291         retVal = allocatorOperation(rmInst, opInfo);
1292     }
1293     return (retVal);
1296 /* FUNCTION PURPOSE: Finds and reserves Linux resources
1297  ***********************************************************************
1298  * DESCRIPTION: Parses the Linux DTB for resources consumed by the
1299  *              Linux kernel.  If the resource is found via the
1300  *              "linux-dtb-alias" property defined in the GRL it is 
1301  *              reserved.
1302  */
1303 static int32_t findAndReserveLinuxResource(Rm_Inst *rmInst, const char *resourceName, void *linuxDtb, 
1304                                            Rm_LinuxAlias *linuxAlias)
1306     Rm_AllocatorOpInfo  opInfo;
1307     Rm_ResourceInfo     resourceInfo;
1308     uint32_t            pathOffset;
1309     uint32_t            pathSize;
1310     char               *spacePtr;
1311     int32_t             propOffset;
1312     int32_t             nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1313     int32_t             prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1314     int32_t             depth;
1315     int32_t             propertyLen;
1316     const char         *propertyName;
1317     const void         *propertyData; 
1318     Rm_LinuxValueRange *linuxValueRange;
1319     int32_t             retVal = RM_OK; 
1321     memset((void *) &opInfo, 0, sizeof(Rm_AllocatorOpInfo));
1322     memset((void *) &resourceInfo, 0, sizeof(Rm_ResourceInfo));
1324     strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS);
1325     opInfo.serviceSrcInstNode = rmPolicyGetLinuxInstNode(rmInst->validInstances);
1326     opInfo.operation = Rm_allocatorOp_ALLOCATE;
1327     opInfo.resourceInfo = &resourceInfo;    
1329     while(linuxAlias) {
1330         /* Reset parsing variables */
1331         pathOffset = 0;
1332         pathSize = strlen(linuxAlias->path) + 1;
1333         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1334         prevDepth = RM_DTB_UTIL_STARTING_DEPTH;   
1335         resourceInfo.base = 0;
1336         resourceInfo.length = 0;
1338         spacePtr = strpbrk(linuxAlias->path, " ");
1339         if (spacePtr) {
1340             *spacePtr = '\0';
1341         }       
1342         
1343         while(pathOffset < pathSize) {
1344             /* Move through DTB nodes until next alias path node found */
1345             if (strcmp(linuxAlias->path + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL))) {
1346                 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);
1348                 if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) {
1349                     /* Returning from subnode that matched part of alias path without finding
1350                      * resource values */
1351                     retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1352                     break;
1353                 }
1354             }
1355             else {
1356                 /* Found next alias path node.  Move to next node name in path string. */
1357                 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1358                 spacePtr = strpbrk(linuxAlias->path + pathOffset, " ");
1359                 if (spacePtr) {
1360                     *spacePtr = '\0';
1361                 }       
1362                 
1363                 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);
1364                 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);
1365                 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1366                        (pathOffset < pathSize)) {
1367                     propertyData = fdt_getprop_by_offset(linuxDtb, propOffset, 
1368                                                          &propertyName, &propertyLen);
1370                     if (strcmp(linuxAlias->path + pathOffset, propertyName) == 0) {
1371                         /* Found resource at end of alias path */
1372                         pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1373                         linuxValueRange = rmDtbUtilLinuxExtractValues(propertyData, propertyLen);
1374                         retVal = reserveLinuxResource(rmInst, linuxAlias, 
1375                                                       linuxValueRange, &opInfo);
1376                         rmDtbUtilLinuxFreeValues(linuxValueRange);
1377                     }
1378                     propOffset = fdt_next_property_offset(linuxDtb, propOffset);
1379                 } 
1381                 if (propOffset < -FDT_ERR_NOTFOUND) {
1382                     retVal = propOffset;
1383                     break;
1384                 }
1385             }
1386         }
1388         if (retVal < RM_OK) {
1389             break;
1390         }
1391         linuxAlias = linuxAlias->nextLinuxAlias;
1392     }
1393     return (retVal);
1396 /* FUNCTION PURPOSE: Creates and initializes a resource allocator
1397  ***********************************************************************
1398  * DESCRIPTION: Creates a resource allocator for the provided
1399  *              resource name and resource properties retrieved
1400  *              from the GRL.  Resources will be reserved for 
1401  *              the Linux kernel if the Linux DTB is provided
1402  *              and there are "linux-dtb-alias" properties
1403  *              specified in the GRL.
1404  */
1405 static int32_t createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, 
1406                                       Rm_ResourceProperties *resourceProperties, void *linuxDtb)
1408     Rm_ResourceRange    *range = NULL;
1409     Rm_ResourceRange    *rangeBasePtr = NULL;
1410     Rm_NsAssignment     *nsAssignments = NULL;
1411     Rm_NsAssignment     *nsAssignmentBasePtr = NULL;
1412     Rm_LinuxAlias       *linuxAlias = NULL;
1413     Rm_NameServerObjCfg  nameServerObjCfg;      
1414     int32_t              retVal = RM_OK;
1416     if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0)) {
1417         range = rangeBasePtr = rmDtbUtilResExtractRange(resourceProperties->rangeData, 
1418                                                         resourceProperties->rangeLen);
1419         
1420         if ((retVal = createResourceTree(rmInst, resourceName, range)) >= RM_OK) {
1421             if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen) {
1422                 if (linuxDtb) {
1423                     linuxAlias = rmDtbUtilResExtractLinuxAlias(resourceProperties->linuxAliasData,
1424                                                                resourceProperties->linuxAliasLen, &retVal);
1425                     if (linuxAlias) {
1426                         retVal = findAndReserveLinuxResource(rmInst, resourceName, linuxDtb, linuxAlias);            
1427                     }
1428                 }
1429                 else {
1430                     retVal = RM_ERROR_GRL_LINUX_ALIAS_BUT_NO_DTB;
1431                 }
1432             }
1433         }
1434     }
1435     
1436     if (retVal >= RM_OK) {
1437         if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) {
1438             nsAssignments = rmDtbUtilResExtractNsAssignment(resourceProperties->nsAssignData, 
1439                                                             resourceProperties->nsAssignLen, &retVal);
1440             if (nsAssignments) {
1441                 nsAssignmentBasePtr = nsAssignments;
1442                 while (nsAssignments) {
1443                     memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1444                     nameServerObjCfg.nameServerTree = rmInst->nameServer;
1445                     nameServerObjCfg.nodeCfg.objName = nsAssignments->nsName;
1446                     nameServerObjCfg.nodeCfg.resourceName = (char *)resourceName;
1447                     nameServerObjCfg.nodeCfg.resourceBase= nsAssignments->resourceBase;
1448                     nameServerObjCfg.nodeCfg.resourceLength = nsAssignments->resourceLength;                
1449                     rmNameServerAddObject(&nameServerObjCfg);
1450                     nsAssignments = nsAssignments->nextNsAssignment;
1451                 }
1452                 rmDtbUtilResFreeNsAssignmentList(nsAssignmentBasePtr);
1453             }
1454         }
1455     }
1457     rmDtbUtilResFreeRange(rangeBasePtr);
1458     if (linuxAlias) {
1459         rmDtbUtilResFreeLinuxAlias(linuxAlias);
1460     }
1461     return(retVal);
1464 /* FUNCTION PURPOSE: Recursively parses GRL resource properties
1465  ***********************************************************************
1466  * DESCRIPTION: Recursively parses and stores GRL resource node 
1467  *              properties using the LIBFDT APIs
1468  */
1469 static int32_t parseResourceProperty(void *globalResourceDtb, int32_t offset, 
1470                                      Rm_ResourceProperties *propertyInfo)
1472         int32_t              propertyLen;
1473         const char          *propertyName;
1474         const void          *propertyData;
1475     Rm_ResourcePropType  propertyType;
1476     int32_t              retVal = RM_OK;
1478         propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen);
1479     propertyType = rmDtbUtilResGetPropertyType(propertyName);
1480     if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) {
1481         propertyInfo->rangeData = propertyData;
1482         propertyInfo->rangeLen = propertyLen;
1483     }
1484     else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) {
1485         propertyInfo->nsAssignData = propertyData;
1486         propertyInfo->nsAssignLen = propertyLen;
1487     }
1488     else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS) {
1489         propertyInfo->linuxAliasData = propertyData;
1490         propertyInfo->linuxAliasLen = propertyLen;
1491     }        
1492     else {
1493         retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY;
1494     }
1496     if (retVal == RM_OK) {
1497         offset = fdt_next_property_offset(globalResourceDtb, offset);
1498         if (offset >= 0) {
1499             retVal = parseResourceProperty(globalResourceDtb, offset, propertyInfo);
1500         }
1501         else if (offset != -FDT_ERR_NOTFOUND) {
1502             /* Error returned by LIBFDT */
1503             retVal = offset;
1504         }
1505     }
1506     return (retVal);
1509 /* FUNCTION PURPOSE: Recursively parses GRL resource nodes
1510  ***********************************************************************
1511  * DESCRIPTION: Recursively parses GRL resource nodes looking for
1512  *              resource properties to create the resource allocators.
1513  *              The LIBFDT APIs are used to parse the GRL.
1514  */
1515 static int32_t parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth,
1516                                  void *linuxDtb)
1518         const char            *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL);
1519     Rm_ResourceProperties  resourceProperties;
1520         int32_t                retVal = RM_OK;
1521         int32_t                offset;
1523     memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties));
1524     /* Get properties of resource node */
1525         offset = fdt_first_property_offset(globalResourceDtb, nodeOffset);
1526         if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1527                 retVal =  parseResourceProperty(globalResourceDtb, offset, &resourceProperties);
1528         if (retVal < -FDT_ERR_NOTFOUND) {
1529             return (retVal);
1530         }
1531         if (retVal = createAndInitAllocator(rmInst, resourceName, &resourceProperties, linuxDtb) < RM_OK) {
1532             return (retVal);
1533         }
1534         }
1535     else if (offset != -FDT_ERR_NOTFOUND) {
1536                 /* Error returned by LIBFDT */
1537         return (offset);
1538     }
1539     
1540         offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth);
1541     if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
1542         retVal = parseResourceNode(rmInst, globalResourceDtb, offset, depth, linuxDtb);
1543         if (retVal < -FDT_ERR_NOTFOUND) {
1544             return (retVal);
1545         }
1546     }
1547     else if (offset != -FDT_ERR_NOTFOUND) {
1548         /* Error returned by LIBFDT */
1549         return (offset);
1550     }
1551     return (retVal);
1554 /* FUNCTION PURPOSE: Initializes server allocators
1555  ***********************************************************************
1556  * DESCRIPTION: Creates and initializes a server instance's
1557  *              resource allocators using the GRL and, if
1558  *              provided, Linux DTB.
1559  */
1560 static int32_t initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb, void *linuxDtb)
1562     int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1563     int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH;
1564     int32_t result = RM_OK;
1566     /* Recursively parse the Global Resource List, creating an allocator for
1567      * each resource as specified in the node */
1568     result = parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth, linuxDtb);
1570     return(result);
1573 /**********************************************************************
1574  ********************** Internal Functions ****************************
1575  **********************************************************************/
1577 /* FUNCTION PURPOSE: Adds a transaction
1578  ***********************************************************************
1579  * DESCRIPTION: Returns a pointer to a newly created transaction.
1580  *              The transaction is created based on a new service
1581  *              request received via the service API or the
1582  *              transport API (service forwarded from another instance)
1583  */
1584 Rm_Transaction *rmTransactionQueueAdd(Rm_Inst *rmInst)
1586     Rm_Transaction *transactionQueue = rmInst->transactionQueue;
1587     Rm_Transaction *newTransaction   = NULL;
1589     newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction));
1590     if (newTransaction) {
1591         memset((void *)newTransaction, 0, sizeof(Rm_Transaction));
1593         newTransaction->localId = transactionGetSequenceNum(rmInst);
1594         newTransaction->nextTransaction = NULL;  
1595         if (transactionQueue) {
1596             while (transactionQueue->nextTransaction) {
1597                 transactionQueue = transactionQueue->nextTransaction;
1598             }
1599             transactionQueue->nextTransaction = newTransaction;
1600         }
1601         else {
1602             rmInst->transactionQueue = newTransaction;
1603         }
1604     }
1605     return (newTransaction);
1608 /* FUNCTION PURPOSE: Finds a transaction
1609  ***********************************************************************
1610  * DESCRIPTION: Returns a pointer to a transaction resident
1611  *              in the transaction queue that matches the provided
1612  *              transaction ID.
1613  */
1614 Rm_Transaction *rmTransactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)
1616     Rm_Transaction *transaction = rmInst->transactionQueue;
1618     while (transaction) {
1619         if (transaction->localId == transactionId) {
1620             break;             
1621         }
1622         transaction = transaction->nextTransaction;
1623     }
1625     return (transaction);
1628 /* FUNCTION PURPOSE: Deletes a transaction
1629  ***********************************************************************
1630  * DESCRIPTION: Deletes the transaction with the provided transaction
1631  *              ID from the instance's transaction queue.
1632  */
1633 int32_t rmTransactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)
1635     Rm_Transaction *transaction     = rmInst->transactionQueue;
1636     Rm_Transaction *prevTransaction = NULL;
1637     int32_t         retVal          = RM_OK;
1639     while (transaction) {
1640         if (transaction->localId == transactionId) {
1641             break;             
1642         }
1644         prevTransaction = transaction;
1645         transaction = transaction->nextTransaction;
1646     }
1648     if (transaction) {
1649         if (prevTransaction == NULL) {
1650             /* Transaction at start of queue. Map second transaction to start of queue 
1651              * as long as more than one transactions. */
1652             rmInst->transactionQueue = transaction->nextTransaction;
1653         }
1654         else {
1655             /* Transaction in middle or end of queue. */
1656             prevTransaction->nextTransaction = transaction->nextTransaction;
1657         }
1658         Rm_osalFree((void *)transaction, sizeof(Rm_Transaction));
1659     }
1660     else {
1661         retVal = RM_ERROR_SERVICE_TRANS_DOES_NOT_EXIST;
1662     }    
1663     return (retVal);
1666 /* FUNCTION PURPOSE: Finds an allocator
1667  ***********************************************************************
1668  * DESCRIPTION: Returns a pointer to an allocator that matches the 
1669  *              provided resource name.
1670  */
1671 Rm_Allocator *rmAllocatorFind(Rm_Allocator *allocatorList, char *resourceName)
1673     while (allocatorList) {
1674         if (strncmp(allocatorList->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
1675             break;             
1676         }
1677         allocatorList = allocatorList->nextAllocator;
1678     }
1680     return (allocatorList);
1683 /* FUNCTION PURPOSE: Processes a transaction
1684  ***********************************************************************
1685  * DESCRIPTION: Processes transactions created from services
1686  *              received via the service handle or the transport.
1687  *              Transactions will be routed within the RM system
1688  *              based on the RM instance type and the type of
1689  *              the transaction.
1690  */
1691 void rmTransactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)
1693     void                *validInstNode;
1694     Rm_PolicyCheckCfg    privCheckCfg;
1695     Rm_NameServerObjCfg  nameServerObjCfg;      
1696     uint32_t             allocType = 0;    
1698     /* Handle static transactions originating on this instance.  Any other static transactions will be
1699      * stored in transaction queue until all transports are up. */
1700     if (((rmInst->instType == Rm_instType_CLIENT) || (rmInst->instType == Rm_instType_CLIENT_DELEGATE)) &&
1701         (!rmInst->registeredWithDelegateOrServer) && 
1702         (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS) == 0)) {
1703         if (rmInst->staticInfo.staticPolicy) {
1704             if ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
1705                 (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE)) {
1706                 /* Check request against startup policy */
1707                 memset((void *)&privCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
1709                 if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
1710                     privCheckCfg.type = Rm_policyCheck_INIT;
1711                 }
1712                 else {
1713                     privCheckCfg.type = Rm_policyCheck_USE;
1714                 }
1715                 privCheckCfg.policyDtb = rmInst->staticInfo.staticPolicy;
1716                 privCheckCfg.validInstNode = rmPolicyGetValidInstNode(rmInst->staticInfo.staticValidInstTree, 
1717                                                                       rmInst->instName);
1718                 privCheckCfg.resourceOffset = rmPolicyGetResourceOffset(rmInst->staticInfo.staticPolicy,
1719                                                                         transaction->resourceInfo.name);
1720                 privCheckCfg.resourceBase = transaction->resourceInfo.base;
1721                 privCheckCfg.resourceLength = transaction->resourceInfo.length;
1723                 if (rmPolicyCheckPrivilege(&privCheckCfg, &transaction->state)) {
1724                     transaction->state = RM_SERVICE_APPROVED_STATIC;
1725                 }
1726                 else if (transaction->state == RM_SERVICE_PROCESSING) {
1727                     /* Privilege check returned false without error */
1728                     transaction->state = RM_SERVICE_DENIED_BY_STATIC_POLICY;
1729                 }
1730             }
1731             else {
1732                 transaction->state = RM_SERVICE_DENIED_INVALID_STATIC_REQUEST;
1733             }
1734         }
1735         else {
1736             transaction->state = RM_ERROR_REQ_FAILED_NO_STATIC_POLICY;
1737         }        
1738     }
1739     else {
1740         /* Handle auto-forwarded transactions.  These transactions include:
1741          * - All request transactions received on Clients are forwarded to the Client Delegate
1742          * - NameServer requests received on the Client Delegate are forwarded to the Server */
1743         if ((rmInst->instType == Rm_instType_CLIENT) ||
1744             ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&
1745              ((transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||
1746               (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) ||
1747               (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))) {
1748               
1749             if ((transaction->state != RM_SERVICE_PROCESSING) &&
1750                 (transaction->state != RM_SERVICE_APPROVED_STATIC)) {
1751                 if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1752                     /* Transaction did not originate on this instance */
1753                     transactionResponder(rmInst, transaction);
1754                 }
1755                 else {
1756                     /* Transaction originated on this instance */
1757                     serviceResponder(rmInst, transaction);
1758                 }
1759             }
1760             else {
1761                 /* Forward request if transport is up.  Otherwise, just queue. */
1762                 if (rmInst->registeredWithDelegateOrServer) {
1763                     transactionForwarder(rmInst, transaction);   
1764                 } 
1765             }
1766         }
1767         else {
1768             /* Validate service's originating instance name */
1769             if (rmInst->instType == Rm_instType_SERVER) {
1770                 validInstNode = rmPolicyGetValidInstNode(rmInst->validInstances, transaction->serviceSrcInstName);
1771                 if (validInstNode == NULL) {
1772                     transaction->state = RM_SERVICE_DENIED_INST_NAME_NOT_VALID;
1774                     /* Send result via responder if transaction did not originate from this instance */
1775                     if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1776                         transactionResponder(rmInst, transaction);
1777                     }
1778                 }
1779             }
1781             switch (transaction->type) {
1782                 case Rm_service_RESOURCE_ALLOCATE_INIT:
1783                 case Rm_service_RESOURCE_ALLOCATE_USE:
1784                 case Rm_service_RESOURCE_FREE:               
1785                     if ((transaction->state != RM_SERVICE_PROCESSING) &&
1786                         (transaction->state != RM_SERVICE_APPROVED_STATIC)) {
1787                         /* Transaction complete */
1788                         if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1789                             /* Transaction result not destined for this instance */
1790                             transactionResponder(rmInst, transaction);
1791                         }
1792                         else {
1793                             /* Transaction result destined for this instance */
1794                             serviceResponder(rmInst, transaction);      
1795                         }
1796                     }
1797                     else {
1798                         /* Complete allocation/free request */
1799                         if (transaction->type == Rm_service_RESOURCE_FREE) {
1800                             freeHandler(rmInst, transaction, validInstNode);
1801                         }
1802                         else {
1803                             switch (transaction->type) {
1804                                 case Rm_service_RESOURCE_ALLOCATE_INIT:
1805                                     RM_policy_SET_PERM(allocType, RM_POLICY_PERM_INIT_SHIFT, 1);
1806                                     break;
1807                                 case Rm_service_RESOURCE_ALLOCATE_USE:
1808                                     RM_policy_SET_PERM(allocType, RM_POLICY_PERM_USE_SHIFT, 1);    
1809                                     break;
1810                             }
1811                             allocationHandler(rmInst, transaction, validInstNode, allocType);
1812                         }
1813                     }
1814                     break;
1815                 case Rm_service_RESOURCE_MAP_TO_NAME:
1816                 case Rm_service_RESOURCE_GET_BY_NAME:
1817                 case Rm_service_RESOURCE_UNMAP_NAME:                
1818                     /* NameServer resides on server */
1819                     memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1820                     if (rmInst->nameServer) {
1821                         nameServerObjCfg.nameServerTree = rmInst->nameServer;
1822                         nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
1823                         if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) {
1824                             nameServerObjCfg.nodeCfg.resourceName = transaction->resourceInfo.name;
1825                             nameServerObjCfg.nodeCfg.resourceBase= transaction->resourceInfo.base;
1826                             nameServerObjCfg.nodeCfg.resourceLength = transaction->resourceInfo.length;
1827                             transaction->state = rmNameServerAddObject(&nameServerObjCfg);
1828                         }
1829                         else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) {
1830                             if ((transaction->state = rmNameServerFindObject(&nameServerObjCfg)) ==
1831                                 RM_SERVICE_PROCESSING) {
1832                                 strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
1833                                 transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
1834                                 transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
1835                                 transaction->state = RM_SERVICE_APPROVED;
1836                             } 
1837                         }
1838                         else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) {
1839                             transaction->state = rmNameServerDeleteObject(&nameServerObjCfg);
1840                         }
1841                     }
1842                     else {
1843                         transaction->state = RM_ERROR_NAMESERVER_DOES_NOT_EXIST;
1844                     }
1846                     /* Send result via responder if transaction did not originate from this instance */
1847                     if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1848                         transactionResponder(rmInst, transaction);
1849                     }
1850                     break;
1851             }
1852         }
1853     }
1855     /* Forward any queued requests that weren't forwarded yet */
1856     if (rmInst->registeredWithDelegateOrServer) {
1857         transaction = rmInst->transactionQueue;
1858         while(transaction) {
1859             if (((transaction->state == RM_SERVICE_PROCESSING) ||
1860                  (transaction->state == RM_SERVICE_APPROVED_STATIC)) &&
1861                 !transaction->hasBeenForwarded) {
1862                 transactionForwarder(rmInst, transaction);
1863             }
1864             transaction = transaction->nextTransaction;
1865         }
1866     }
1868      
1869 /**********************************************************************
1870  ********************** Application visible APIs **********************
1871  **********************************************************************/
1873 /* FUNCTION PURPOSE: Display status of managed resources
1874  ***********************************************************************
1875  * DESCRIPTION: Prints the status (allocate/free status, as well as
1876  *              owners) for all resources managed by the RM 
1877  *              instance network.  Also, prints the NameServer name
1878  *              entries.  This function is only available on server
1879  *              instances.
1880  */
1881 void Rm_printResourceStatus(Rm_Handle rmServerHandle)
1883     Rm_Inst         *rmInst = (Rm_Inst *)rmServerHandle;
1884     Rm_Allocator    *allocator = rmInst->allocators;
1885     Rm_Owner        *owners;
1886     Rm_ResourceTree *treeRoot;
1887     Rm_ResourceNode *treeNode;
1889     if (rmInst->instType == Rm_instType_SERVER) {
1890         while (allocator != NULL) {
1891             Rm_osalLog("Resource: %s\n", allocator->resourceName);
1893             treeRoot = allocator->allocatorRootEntry;
1895             RB_FOREACH(treeNode, _Rm_AllocatorResourceTree, treeRoot) {               
1896                 Rm_osalLog("          %10d - %10d ", treeNode->base, 
1897                                                      treeNode->base + treeNode->length -1);
1898                 
1899                 if (treeNode->allocationCount == 0) {
1900                     Rm_osalLog("NOT ALLOCATED\n");
1901                 }
1902                 else {
1903                     owners = treeNode->ownerList;
1904                     Rm_osalLog("allocated to");
1905                     while (owners) {
1906                         Rm_osalLog(" %s", owners->instNameNode->name);
1907                         owners = owners->nextOwner;
1908                     }
1909                     Rm_osalLog("\n");
1910                 }
1911             }        
1912             allocator = allocator->nextAllocator;
1913         }
1914         rmNameServerPrintObjects(rmInst->nameServer);
1915     }
1918 /* FUNCTION PURPOSE: Display status of a RM instance
1919  ***********************************************************************
1920  * DESCRIPTION: Prints the current status of various RM instance
1921  *              properties such as the state of all transactions
1922  *              in the transaction queue and registered transports
1923  */
1924 void Rm_printInstanceStatus(Rm_Handle rmHandle)
1926     Rm_Inst        *rmInst = (Rm_Inst *)rmHandle;
1927     Rm_Transport   *transportList = (Rm_Transport *)rmInst->transports;
1928     Rm_Transaction *transactionQ = rmInst->transactionQueue;
1930     Rm_osalLog("Instance name: %s\n", rmInst->instName);
1931     if (rmInst->instType == Rm_instType_SERVER) {
1932         Rm_osalLog("Type: Server\n");
1933     }
1934     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1935         Rm_osalLog("Type: Client Delegate\n");
1936     }
1937     else {
1938         Rm_osalLog("Type: Client\n");
1939     }
1941     if (transportList) {
1942         Rm_osalLog("\nRegistered Transports:\n");
1943         while (transportList) {
1944             Rm_osalLog("    Remote instName:    %s\n", transportList->remoteInstName);
1945             if (transportList->remoteInstType == Rm_instType_SERVER) {
1946                 Rm_osalLog("    Remote instType:    Server\n");
1947             }
1948             else if (transportList->remoteInstType == Rm_instType_CLIENT_DELEGATE) {
1949                 Rm_osalLog("    Remote instType:    Client Delegate\n");
1950             }
1951             else {
1952                 Rm_osalLog("    Remote instType:    Client\n");
1953             }
1954             Rm_osalLog("    appTransportHandle: 0x%08x\n", transportList->appTransportHandle);
1955             Rm_osalLog("\n");
1956             transportList = transportList->nextTransport;
1957         }
1958     }
1960     if (transactionQ) {
1961         Rm_osalLog("\nQueued Service Transactions:\n");
1962         while (transactionQ) {
1963             Rm_osalLog("    Service type:       %d\n", transactionQ->type);
1964             Rm_osalLog("    Service ID:         %d\n", transactionQ->localId);
1965             Rm_osalLog("    Service srcInstName %s\n", transactionQ->serviceSrcInstName);
1966             Rm_osalLog("    Service state:      %d\n", transactionQ->state);
1967             Rm_osalLog("    Resource name:      %s\n", transactionQ->resourceInfo.name);
1968             Rm_osalLog("    Resource base:      %d\n", transactionQ->resourceInfo.base);
1969             Rm_osalLog("    Resource length:    %d\n", transactionQ->resourceInfo.length);
1970             Rm_osalLog("    Resource alignment: %d\n", transactionQ->resourceInfo.alignment);
1971             Rm_osalLog("    Resource NS name:   %s\n", transactionQ->resourceInfo.nameServerName);
1972             Rm_osalLog("\n");
1973             transactionQ = transactionQ->nextTransaction;
1974         }    
1975     }
1978 /* FUNCTION PURPOSE: RM instance creation and initialization
1979  ***********************************************************************
1980  * DESCRIPTION: Returns a new RM instance created and initialized
1981  *              using the parameters provided via the initCfg
1982  *              structure.
1983  */
1984 Rm_Handle Rm_init(const Rm_InitCfg *initCfg, int32_t *result)
1986     Rm_Inst *rmInst;
1987     void    *globalResourceDtb = NULL;
1988     void    *linuxResourceDtb = NULL;
1989     bool     addLinux = false;
1991     *result = RM_OK;
1992     
1993     if ((initCfg->instName == NULL) ||
1994         ((strlen(initCfg->instName) + 1) > RM_NAME_MAX_CHARS)) {
1995         *result = RM_ERROR_INVALID_INST_NAME;
1996         return (NULL);
1997     }
1999     if (initCfg->instType >= Rm_instType_LAST) {
2000         *result = RM_ERROR_INVALID_INST_TYPE;
2001     }
2003     /* Create and initialize instance */
2004     rmInst = Rm_osalMalloc (sizeof(Rm_Inst));
2005     memset ((void *) rmInst, 0, sizeof(Rm_Inst));
2006     rmInst->isLocked = false;
2007     rmInst->registeredWithDelegateOrServer = false;
2008     rmInst->transactionSeqNum = transactionInitSequenceNum();
2010     rmInst->instType = initCfg->instType;    
2011     strncpy (rmInst->instName, initCfg->instName, RM_NAME_MAX_CHARS);
2013     if (rmInst->instType == Rm_instType_SERVER) {
2014         if (!initCfg->instCfg.serverCfg.globalResourceList ||
2015             !initCfg->instCfg.serverCfg.globalPolicy) {
2016             *result = RM_ERROR_INVALID_SERVER_CONFIGURATION;
2017             Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
2018             return(NULL);
2019         }
2021         rmInst->policy = initCfg->instCfg.serverCfg.globalPolicy;
2022         fdt_open_into(rmInst->policy, rmInst->policy, fdt_totalsize(rmInst->policy)); 
2024         if (initCfg->instCfg.serverCfg.linuxDtb) {
2025             linuxResourceDtb = initCfg->instCfg.serverCfg.linuxDtb;
2026             fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb));
2027             addLinux = true;
2028         }
2030         /* Create valid instance list from policy.  Must be done prior to parsing
2031          * GRL so that Linux resources can be reserved correctly */
2032         rmInst->validInstances = rmPolicyCreateValidInstTree(rmInst->policy, addLinux, result);
2033         /* Validate policy assignment strings */
2034         *result = rmPolicyValidatePolicy(rmInst->policy, rmInst->validInstances);  
2036         rmInst->nameServer = rmNameServerInit();
2038         globalResourceDtb = initCfg->instCfg.serverCfg.globalResourceList;
2039         fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb));
2041         if ((*result = initializeAllocators(rmInst, globalResourceDtb, linuxResourceDtb)) == RM_OK) {  
2042             *result = rmPolicyValidatePolicyResourceNames(rmInst->policy, (void *)rmInst->allocators);
2043         }
2044         if (*result < RM_OK) {
2045             Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
2046             return(NULL);
2047         }
2048     }
2050     if ((rmInst->instType == Rm_instType_CLIENT) && 
2051         (initCfg->instCfg.clientCfg.staticPolicy)) {
2052         rmInst->staticInfo.staticPolicy = initCfg->instCfg.clientCfg.staticPolicy; 
2053     }
2054     else if ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&
2055              (initCfg->instCfg.cdCfg.staticPolicy)) { 
2056         rmInst->staticInfo.staticPolicy = initCfg->instCfg.cdCfg.staticPolicy; 
2057     }
2058     if (rmInst->staticInfo.staticPolicy) {
2059         fdt_open_into(rmInst->staticInfo.staticPolicy, rmInst->staticInfo.staticPolicy, 
2060                       fdt_totalsize(rmInst->staticInfo.staticPolicy));       
2061         rmInst->staticInfo.staticValidInstTree = rmPolicyCreateValidInstTree(rmInst->staticInfo.staticPolicy, 
2062                                                                              addLinux, result);        
2063         if (*result == RM_OK) {
2064             /* Validate policy assignment strings */
2065             *result = rmPolicyValidatePolicy(rmInst->staticInfo.staticPolicy, rmInst->staticInfo.staticValidInstTree);
2066         }
2067         if (*result != RM_OK) {
2068             if (rmInst->staticInfo.staticValidInstTree) {
2069                 rmPolicyFreeValidInstTree(rmInst->staticInfo.staticValidInstTree);
2070             }
2071             Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
2072             rmInst = NULL;
2073         }
2074     }
2075     return ((Rm_Handle) rmInst);
2078 /* FUNCTION PURPOSE: Returns RM version information
2079  ***********************************************************************
2080  */
2081 uint32_t Rm_getVersion (void)
2083     return RM_VERSION_ID;
2086 /* FUNCTION PURPOSE: Returns RM version string
2087  ***********************************************************************
2088  */
2089 const char* Rm_getVersionStr (void)
2091     return rmVersionStr;