c4ffbd8ec9e5c82c9fba6ba79a14cbc78203201d
[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     uint32_t sequenceNum = 0;
104     if (rmInst->transactionSeqNum + 1 < rmInst->transactionSeqNum) {
105         /* Rollover */
106         sequenceNum = rmInst->transactionSeqNum;
107         rmInst->transactionSeqNum = transactionInitSequenceNum();
108     }
109     else {
110         sequenceNum = rmInst->transactionSeqNum++;
111     }    
112     return (sequenceNum);
115 /* FUNCTION PURPOSE: Creates a resource allocator
116  ***********************************************************************
117  * DESCRIPTION: Returns a newly Created and initialized resource
118  *              The allocator is also stored in the RM instance
119  *              allocator list.            
120  */
121 static Rm_Allocator *allocatorAdd(Rm_Inst *rmInst, const char *resourceName)
123     Rm_Allocator *allocators   = rmInst->allocators;
124     Rm_Allocator *newAllocator = NULL;
126     newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator));
128     if (newAllocator) {
129         memset((void *)newAllocator, 0, sizeof(Rm_Allocator));
130         strncpy(newAllocator->resourceName, resourceName, RM_NAME_MAX_CHARS);
131         newAllocator->allocatorRootEntry = NULL;
132         newAllocator->nextAllocator = NULL;  
134         /* Add allocator to end of list */
135         if (allocators) {
136             while (allocators->nextAllocator) {
137                 allocators = allocators->nextAllocator;
138             }
139             allocators->nextAllocator = newAllocator;
140         }
141         else {
142             rmInst->allocators = newAllocator;
143         }
144     }
145     return (newAllocator);
148 /* FUNCTION PURPOSE: Deletes a resource allocator
149  ***********************************************************************
150  * DESCRIPTION: Deletes a resource allocator based on the given
151  *              resource name.  The resource allocator will be
152  *              removed from the RM instance allocator list.
153  */
154 static int32_t allocatorDelete(Rm_Inst *rmInst, char *resourceName)
156     Rm_Allocator *allocator = rmInst->allocators;
157     Rm_Allocator *prevAllocator = NULL;
158     int32_t       retVal = RM_OK;
160     while (allocator) {
161         if (strncmp(allocator->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
162             break;             
163         }
164         prevAllocator = allocator;
165         allocator = allocator->nextAllocator;
166     }
168     if (allocator) {
169         if (prevAllocator == NULL) {
170             rmInst->allocators = allocator->nextAllocator;
171         }
172         else {
173             prevAllocator->nextAllocator = allocator->nextAllocator;
174         }
175         Rm_osalFree((void *)allocator, sizeof(Rm_Allocator));
176     }
177     else {
178         retVal = RM_ERROR_RES_ALLOCATOR_DOES_NOT_EXIST;
179     }
180     return (retVal);
183 /* FUNCTION PURPOSE: Adds an owner to an allocator resource
184  ***********************************************************************
185  * DESCRIPTION: Adds a RM instance node to a resource node's
186  *              list of owners.
187  */
188 static void addOwner(Rm_ResourceNode *node, void *serviceInstNode)
190     Rm_Owner *ownerList = node->ownerList;
191     Rm_Owner *newOwner = NULL;
193     newOwner = Rm_osalMalloc(sizeof(Rm_Owner));
195     if (newOwner) {
196         newOwner->instNameNode = serviceInstNode;
197         newOwner->nextOwner = NULL;  
199         /* Add owner entry to end of list */
200         if (ownerList) {
201             while (ownerList->nextOwner) {
202                 ownerList = ownerList->nextOwner;
203             }
204             ownerList->nextOwner = newOwner;
205         }
206         else {
207             node->ownerList = newOwner;
208         }
210         node->allocationCount++;
211         newOwner->instNameNode->allocRefCount++;
212     }
215 /* FUNCTION PURPOSE: Checks a resource node's ownership
216  ***********************************************************************
217  * DESCRIPTION: Returns TRUE if the provided instance node is
218  *              in the list of resource node owners.  Otherwise,
219  *              returns FALSE.
220  */
221 static bool isOwnedBy(Rm_ResourceNode *node, void *serviceInstNode)
223     Rm_Owner *owner = node->ownerList;
225     while (owner) {
226         if (owner->instNameNode == serviceInstNode) {
227             return(true);           
228         }
229         owner = owner->nextOwner;
230     }
231     return(false);
234 /* FUNCTION PURPOSE: Compares two resource node's owners
235  ***********************************************************************
236  * DESCRIPTION: Returns TRUE if the owners of two resource nodes 
237  *              are equivalent.  Otherwise, returns FALSE.
238  */
239 static bool compareResourceNodeOwners(Rm_ResourceNode *node1, Rm_ResourceNode *node2)
241     Rm_Owner *node1Owners = node1->ownerList;
242     Rm_Owner *node2Owners = node2->ownerList;
243     bool      matchedInst;
245     if (node1->allocationCount == node2->allocationCount) {
246         while (node1Owners) {
247             matchedInst = false;
248             while (node2Owners) {
249                 if (node1Owners->instNameNode == node2Owners->instNameNode) {
250                     matchedInst = true;
251                     break;
252                 }
253                 node2Owners = node2Owners->nextOwner;
254             }
256             if (matchedInst) {
257                 node2Owners = node2->ownerList;
258                 node1Owners = node1Owners->nextOwner;
259             }
260             else {
261                 return(false);
262             }                
263         }
264     }
265     else {
266         return(false);
267     }  
268     
269     return(true);
272 /* FUNCTION PURPOSE: Deletes an owner from an allocator resource
273  ***********************************************************************
274  * DESCRIPTION: Removes a RM instance node from a resource node's
275  *              list of owners.
276  */
277 static void deleteOwner(Rm_ResourceNode *node, void *serviceInstNode)
279     Rm_Owner *owner = node->ownerList;
280     Rm_Owner *prevOwner = NULL;
282     while (owner) {
283         if (owner->instNameNode == serviceInstNode) {
284             break;             
285         }
286         prevOwner = owner;
287         owner = owner->nextOwner;
288     }
290     if (prevOwner == NULL) {
291         node->ownerList = owner->nextOwner;
292     }
293     else {
294         prevOwner->nextOwner = owner->nextOwner;
295     }
296     
297     node->allocationCount--;
298     owner->instNameNode->allocRefCount--;
299     Rm_osalFree((void *)owner, sizeof(Rm_Owner));
302 /* FUNCTION PURPOSE: Copies the owners of a resource node
303  ***********************************************************************
304  * DESCRIPTION: Creates a list of resource owners for the destination
305  *              resource node that is equivalent to the the 
306  *              source resource node's owners
307  */
308 static void copyOwners(Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode)
310     Rm_Owner *srcOwnerList = srcNode->ownerList;
311     Rm_Owner *dstNewOwner;
312     Rm_Owner *dstPrevOwner;
314     dstNode->allocationCount = srcNode->allocationCount;
316     while (srcOwnerList) {
317         dstNewOwner = Rm_osalMalloc(sizeof(Rm_Owner));
318         dstNewOwner->instNameNode = srcOwnerList->instNameNode;
319         dstNewOwner->nextOwner = NULL;
321         if (dstNode->ownerList == NULL) {
322             dstNode->ownerList = dstNewOwner;
323         }
324         else {
325             dstPrevOwner->nextOwner = dstNewOwner;
326         }
327         dstPrevOwner = dstNewOwner;
328         srcOwnerList = srcOwnerList->nextOwner;
329     }
332 /* FUNCTION PURPOSE: Clears a resource node's owners
333  ***********************************************************************
334  * DESCRIPTION: Deletes all owners from the owners list of a 
335  *              resource node.
336  */
337 static void clearOwners(Rm_ResourceNode *node)
339     Rm_Owner *owner = node->ownerList;
340     Rm_Owner *nextOwner;
342     while (owner) {
343         nextOwner = owner->nextOwner;
344         node->allocationCount--;
345         Rm_osalFree((void *)owner, sizeof(Rm_Owner));
346         owner = nextOwner;
347     }
350 /* FUNCTION PURPOSE: Creates a new resource tree
351  ***********************************************************************
352  * DESCRIPTION: Creates a new resource tree using the provided
353  *              resource name and value range.  The name and value
354  *              typically originate from the GRL.
355  */
356 static int32_t createResourceTree(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)
358     Rm_Allocator    *allocator = NULL;
359     Rm_ResourceTree *treeRootEntry = NULL;
360     Rm_ResourceNode *treeNode = NULL;
361     Rm_ResourceNode *collidingNode = NULL;
363     allocator = allocatorAdd(rmInst, resourceName);
364     treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree));
365     RB_INIT(treeRootEntry);
367     while (range != NULL) {
368         treeNode = rmResourceNodeNew(range->base, range->length);
369         collidingNode = RB_INSERT(_Rm_AllocatorResourceTree, treeRootEntry, treeNode);
371         if (collidingNode) {
372             Rm_ResourceNode *nextNode = NULL;
373             
374             /* Node that was inserted collides with existing node.  Destroy tree and return error */
375             for (treeNode = RB_MIN(_Rm_AllocatorResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode) {
376                         nextNode = RB_NEXT(_Rm_AllocatorResourceTree, treeRootEntry, treeNode);
377                         RB_REMOVE(_Rm_AllocatorResourceTree, treeRootEntry, nextNode);
378                 rmResourceNodeFree(treeNode);
379                 }
380             Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree));
381             allocatorDelete(rmInst, allocator->resourceName);
382             return (RM_ERROR_GRL_RES_SPECIFIED_MORE_THAN_ONCE);
383         }
384         range = range->nextRange;
385     }
386     
387     allocator->allocatorRootEntry = treeRootEntry;
388     return(RM_OK);
391 /* FUNCTION PURPOSE: Preallocates a resource
392  ***********************************************************************
393  * DESCRIPTION: Called when an allocate request is made but the base 
394  *              is unspecified.  The preallocation algorithm looks at 
395  *              available resources as well as policy permissions to 
396  *              determine a resource range that satisfies the request.
397  *              If a valid range is found it will be returned for the 
398  *              treeAllocate algorithm to handle.
399  */
400 static int32_t treePreAllocate(Rm_Inst *rmInst, Rm_Allocator *allocator, int32_t resourcePolicy,
401                                Rm_AllocatorOpInfo *opInfo)
403     Rm_ResourceNode    findNode;
404     Rm_ResourceNode   *matchingNode = NULL;
405     uint32_t           matchingEnd;
406     uint32_t           rangeIndex;
407     bool               resourceFound = false;
408     Rm_PolicyCheckType policyCheckType;
409     Rm_PolicyCheckCfg  policyCheckCfg;
410     bool               nodePassesPolicy;
411     int32_t            retVal = RM_SERVICE_PROCESSING;    
413     opInfo->resourceInfo->base = rmPolicyGetResourceBase(rmInst->policy, opInfo->serviceSrcInstNode, 
414                                                           resourcePolicy, opInfo->allocType, 
415                                                           &retVal);
416     if (retVal != RM_SERVICE_PROCESSING) {
417         return (retVal);
418     }
420     if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) {  
421         /* Get alignment from policy */
422         opInfo->resourceInfo->alignment = rmPolicyGetResourceAlignment(rmInst->policy, resourcePolicy);
423     }
424     
425     if (opInfo->resourceInfo->alignment == 0) {
426         opInfo->resourceInfo->alignment = 1;
427     }    
429     memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
430     findNode.base = opInfo->resourceInfo->base;
431     findNode.length = opInfo->resourceInfo->length;
433     /* Configure policy checking structure */
434     memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
435     if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
436         policyCheckType = Rm_policyCheck_INIT;
437     }
438     else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
439         policyCheckType = Rm_policyCheck_USE;
440     }
441     policyCheckCfg.policyDtb = rmInst->policy;
442     policyCheckCfg.resourceOffset = resourcePolicy;
443     
444     do {
445         matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
446         
447         if (matchingNode) {
448             nodePassesPolicy = false;
449             policyCheckCfg.type = policyCheckType;
450             policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
451             policyCheckCfg.resourceBase = findNode.base;
452             policyCheckCfg.resourceLength = findNode.length;
453             nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);    
454             
455             if (nodePassesPolicy && (matchingNode->allocationCount > 0)) {
456                 /* Check exclusive privileges of instance requesting resource.  Requesting
457                  * instance with exclusive privileges can't reserve resource if already owned*/
458                 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
459                 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
460                 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
461             }
462             
463             if (nodePassesPolicy && (matchingNode->allocationCount == 1)) {
464                 /* Check exclusive privileges of instance that currently owns resource */
465                 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
466                 policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
467                 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
468             }
470             if (retVal != RM_SERVICE_PROCESSING) {
471                 break;
472             }
474             if (nodePassesPolicy) {
475                 matchingEnd = matchingNode->base + matchingNode->length - 1;
476                 /* Initialize indexer to be first resource value that alignment */
477                 rangeIndex = findNode.base;
478                 if (rangeIndex % opInfo->resourceInfo->alignment) {
479                     rangeIndex += (opInfo->resourceInfo->alignment -
480                                   (rangeIndex % opInfo->resourceInfo->alignment));
481                 }
482                 
483                 if ((rangeIndex + opInfo->resourceInfo->length - 1) <= matchingEnd) {
484                     /* Block of unallocated resources within matchingNode that satisfies
485                      * allocate requirements */
486                     opInfo->resourceInfo->base = rangeIndex;
487                     resourceFound = true;
488                 }     
489             }
490             
491             if (!resourceFound) {
492                 /* Check next resource node for available resources */
493                 findNode.base = matchingNode->base + matchingNode->length;
494             }
495         }
496         else {
497             retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
498         }
499     } while ((!resourceFound) && 
500              (retVal != RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET));
502     return(retVal); 
505 /* FUNCTION PURPOSE: Allocates a resource
506  ***********************************************************************
507  * DESCRIPTION: Will attempt to allocate the resource with specified
508  *              base and length from the resource's allocator.  The
509  *              allocation algorithm will verify the allocation against
510  *              the policy permissions for the instance requesting the
511  *              allocation.  If the policy allows the allocation the 
512  *              algorithm will allocate the resource then combine any
513  *              resource nodes that may have become equivalent (in terms
514  *              of ownership) after the allocation.
515  */
516 static int32_t treeAllocate(Rm_Inst *rmInst, Rm_Allocator *allocator, int32_t resourcePolicy,
517                             Rm_AllocatorOpInfo *opInfo)
519     Rm_ResourceNode     findNode;
520     Rm_ResourceNode    *matchingNode = NULL;
521     Rm_ResourceNode    *leftNode = NULL;
522     Rm_ResourceNode    *rightNode = NULL;
523     Rm_PolicyCheckType  policyCheckType;    
524     Rm_PolicyCheckCfg   policyCheckCfg;
525     bool                allocPassesPolicy;
526     bool                combineLeft = false;
527     bool                combineRight = false;    
528     uint32_t            findEnd;
529     uint32_t            matchingEnd;  
530     int32_t             retVal = RM_SERVICE_PROCESSING;
532     memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
533     findNode.base = opInfo->resourceInfo->base;
534     findNode.length = opInfo->resourceInfo->length;
535     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
537     /* Prepare privilege checks */
538     memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
539     if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
540         policyCheckType = Rm_policyCheck_INIT;
541     }
542     else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
543         policyCheckType = Rm_policyCheck_USE;
544     }
546     if (matchingNode) {
547         findEnd = findNode.base + findNode.length - 1;
548         matchingEnd = matchingNode->base + matchingNode->length - 1;
549         
550         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
551             if (opInfo->serviceSrcInstNode == rmPolicyGetLinuxInstNode(rmInst->validInstances)) {
552                 /* Bypass policy checks since Linux Kernel has full privileges */
553                 allocPassesPolicy = true;
554             }
555             else {
556                 policyCheckCfg.policyDtb = rmInst->policy;
557                 policyCheckCfg.resourceOffset = resourcePolicy;    
558                 policyCheckCfg.type = policyCheckType;
559                 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
560                 policyCheckCfg.resourceBase = findNode.base;
561                 policyCheckCfg.resourceLength = findNode.length;
562                 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
563                 if (!allocPassesPolicy) {
564                     if (policyCheckType == Rm_policyCheck_INIT) {
565                         retVal = RM_SERVICE_DENIED_INIT_PERM_NOT_GIVEN;
566                     }
567                     else {
568                         retVal = RM_SERVICE_DENIED_USE_PERM_NOT_GIVEN;
569                     }
570                 }
572                 if (!isOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
573                     /* Perform exclusive checks if requesting instance does not already an
574                      * owner of the resource */
575                     if (allocPassesPolicy && (matchingNode->allocationCount > 0)) {
576                         /* Check exclusive privileges of instance requesting resource.  Requesting
577                          * instance with exclusive privileges can't reserve resource if already owned*/
578                         policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
579                         policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
580                         allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
581                         if (!allocPassesPolicy) {
582                             retVal = RM_SERVICE_DENIED_EXCLUSIVE_RES_ALLOCD;
583                         }
584                     }
585                     if (allocPassesPolicy && (matchingNode->allocationCount == 1)) {
586                         /* Check exclusive privileges of instance that currently owns resource */
587                         policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
588                         policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
589                         allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
590                         if (!allocPassesPolicy) {
591                             retVal = RM_SERVICE_DENIED_ALLOCD_TO_EXCLUSIVE_INST;
592                         }                
593                     }  
594                 }
595             }
596             
597             if (allocPassesPolicy) {
598                 if (!isOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
599                     /* Handle any possible node combinations if requesting instance is
600                      * not already in resource's owner list.  Automatic approval if requesting
601                      * instance is already in owner list. */
602                     if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {
603                         /* findNode range matches matchingNode range
604                          *
605                          *   |<--left node-->||<--matched  node-->||<--right node-->| => existing node
606                          *                    |<--alloc request-->|  => requested resources
607                          */                     
608                         leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
609                         rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
610                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
611                         addOwner(matchingNode, opInfo->serviceSrcInstNode);
613                         if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
614                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
615                             combineLeft = true;
616                         }
617                         if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
618                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
619                             combineRight = true;
620                         }
622                         if (combineLeft && combineRight) {
623                             /* Combine all three nodes into matchingNode */
624                             matchingNode->base = leftNode->base;
625                             matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
627                             clearOwners(leftNode);
628                             rmResourceNodeFree(leftNode);
629                             clearOwners(rightNode);
630                             rmResourceNodeFree(rightNode);                        
631                         }
632                         else if (combineLeft) {
633                             /* Combine left and matching nodes.  Reinsert right. */
634                             matchingNode->base = leftNode->base;
635                             matchingNode->length += leftNode->length;
637                             clearOwners(leftNode);
638                             rmResourceNodeFree(leftNode);
639                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);                        
640                         }
641                         else if (combineRight) {
642                             /* Combine right and matching nodes.  Reinsert left. */
643                             matchingNode->length += rightNode->length;
645                             clearOwners(rightNode);
646                             rmResourceNodeFree(rightNode);
647                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
648                         }
649                         else {
650                             /* No combine. */
651                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
652                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
653                         }
655                         /* Always reinsert matchingNode */                
656                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);   
657                     }   
658                     else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
659                         /* findNode range is subset of matchingNode range and neither boundary is
660                          * equivalent.
661                          *
662                          * |<----------matched node---------->|
663                          *        |<---alloc request--->|
664                          */ 
665                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
666                         leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
667                         copyOwners(leftNode, matchingNode);
668                         rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
669                         copyOwners(rightNode, matchingNode);
671                         matchingNode->base = findNode.base;                                    
672                         matchingNode->length = findNode.length;
673                         addOwner(matchingNode, opInfo->serviceSrcInstNode);
675                         /* Insert all the nodes */
676                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
677                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
678                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
679                     }  
680                     else {    
681                         if (findNode.base == matchingNode->base) {
682                             /* findNode base and matchingNode base are equivalent.  May be combine
683                              * possibilities to the left
684                              *
685                              * |<---left node (alloc'd)--->||<----------matched node---------->|
686                              *                              |<---findNode (alloc req)--->|
687                              */                         
688                             leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
689                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
690                             /* Add allocating instance to owner list for compare with leftNode */
691                             addOwner(matchingNode, opInfo->serviceSrcInstNode);
692                             
693                             if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
694                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
695                                 /* Combine leftNode and findNode */
696                                 leftNode->length += findNode.length;
697                             }
698                             else {
699                                 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
700                                 copyOwners(leftNode, matchingNode);
701                             }
703                             /* Account for leftNode in matchingNode */
704                             matchingNode->base = findNode.base + findNode.length;
705                             matchingNode->length = matchingEnd - findEnd;  
707                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
708                         }
709                         else if (findEnd == matchingEnd) {
710                             /* findNode end and matchingNode end are equivalent.  May be combine
711                              * possibilities to the right
712                              *
713                              * |<----------matched node---------->||<---right node (alloc'd)--->|
714                              *       |<---findNode (alloc req)--->| 
715                              */                        
716                             rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
717                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
718                             /* Add allocating instance to owner list for compare with rightNode */
719                             addOwner(matchingNode, opInfo->serviceSrcInstNode);
720                             
721                             if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
722                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
723                                 /* Combine rightNode and findNode */
724                                 rightNode->base = findNode.base;
725                                 rightNode->length += findNode.length;
726                             }
727                             else {
728                                 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
729                                 copyOwners(rightNode, matchingNode);
730                             }
732                             /* Account for rightNode in matchingNode */
733                             matchingNode->length -= findNode.length;  
735                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
736                         }
737                         /* Remove allocating instance from leftover matchingNode */
738                         deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
739                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
740                     }
741                 }
742                 retVal = RM_SERVICE_APPROVED;
743             }
744         }
745         else {
746             retVal = RM_SERVICE_DENIED_PARTIAL_ALLOCATION;
747         }
748     }
749     else {
750         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
751     }
753     return(retVal);        
756 /* FUNCTION PURPOSE: Frees a resource
757  ***********************************************************************
758  * DESCRIPTION: Will attempt to free the resource with specified
759  *              base and length from the resource's allocator.  The
760  *              free algorithm will verify the free request parameters
761  *              match an allocated range for the resource and that the
762  *              range is owned by the instance requesting the free. If
763  *              the free is validated the algorithm will free the 
764  *              resource then combine any resource nodes that may have
765  *              become equivalent (in terms of ownership) after the
766  *              allocation.
767  */
768 static int32_t treeFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)
770     Rm_ResourceNode  findNode;
771     Rm_ResourceNode *matchingNode = NULL;
772     Rm_ResourceNode *leftNode = NULL;
773     Rm_ResourceNode *rightNode = NULL;
774     bool             combineLeft = false;
775     bool             combineRight = false;
776     uint32_t         findEnd;
777     uint32_t         matchingEnd;
778     int32_t          retVal;
780     memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
781     findNode.base = opInfo->resourceInfo->base;
782     findNode.length = opInfo->resourceInfo->length;
783     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
785     if (matchingNode) {
786         findEnd = findNode.base + findNode.length - 1;
787         matchingEnd = matchingNode->base + matchingNode->length - 1;
788         
789         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {  
790             if (matchingNode->allocationCount) {
791                 if (isOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
792                     if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))
793                     {
794                         /* Case 1: Free range equals allocated matched node exactly. Attempt to combine 
795                          *         freed node with nodes to left and right.
796                          *
797                          * |<--left node-->||<---matched node--->||<--right node-->|
798                          *                  |<---free request--->|
799                          */ 
800                         leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
801                         rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
802                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
803                         deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
805                         if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
806                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
807                             combineLeft = true;
808                         }
809                         if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
810                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
811                             combineRight = true;
812                         }
814                         if (combineLeft && combineRight) {
815                             /* Combine all three nodes into matchingNode */
816                             matchingNode->base = leftNode->base;
817                             matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
819                             clearOwners(leftNode);
820                             rmResourceNodeFree(leftNode);
821                             clearOwners(rightNode);
822                             rmResourceNodeFree(rightNode);                        
823                         }
824                         else if (combineLeft) {
825                             /* Combine left and matching nodes.  Reinsert right. */
826                             matchingNode->base = leftNode->base;
827                             matchingNode->length += leftNode->length;
829                             clearOwners(leftNode);
830                             rmResourceNodeFree(leftNode);
831                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);                        
832                         }
833                         else if (combineRight) {
834                             /* Combine right and matching nodes.  Reinsert left. */
835                             matchingNode->length += rightNode->length;
837                             clearOwners(rightNode);
838                             rmResourceNodeFree(rightNode);
839                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
840                         }
841                         else {
842                             /* No combine. */
843                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
844                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
845                         }
847                         /* Always reinsert matchingNode */
848                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);                    
849                     }
850                     else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
851                         /* Case 2: Free range is less than range in matched node. Split
852                          *         matched node into three nodes.
853                          *
854                          * |<----------matched node---------->|
855                          *        |<---free request--->|
856                          *
857                          * Remove instance from AllocatedTo list then add it back in for side nodes for
858                          * proper accounting of allocations in validInstance list
859                          */ 
860                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
861                         deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
862                         
863                         leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
864                         copyOwners(leftNode, matchingNode);
865                         addOwner(leftNode, opInfo->serviceSrcInstNode);
866                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
867                         
868                         rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
869                         copyOwners(rightNode, matchingNode);
870                         addOwner(rightNode, opInfo->serviceSrcInstNode);
871                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
873                         matchingNode->base = findNode.base;                                    
874                         matchingNode->length = findNode.length;
875                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
876                     }
877                     else {                        
878                         if (findNode.base == matchingNode->base) {
879                             /* Case 3: Free range is on left boundary of matched node. Try to 
880                              *         combine free range with left node.
881                              *
882                              * |<---left node (free)--->||<----------matched node---------->|
883                              *                           |<---findNode (free req)--->|
884                              */ 
886                             leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
887                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
888                             /* Remove freeing instance from owner list for compare with leftNode */
889                             deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
890                             
891                             if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
892                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
893                                 /* Combine leftNode and findNode */
894                                 leftNode->length += findNode.length;
895                             }
896                             else {
897                                 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
898                                 copyOwners(leftNode, matchingNode);
899                             }
901                             /* Remove leftNode range from matchingNode */
902                             matchingNode->base = findNode.base + findNode.length;
903                             matchingNode->length = matchingEnd - findEnd;  
904                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
905                         }
906                         else if (findEnd == matchingEnd) {
907                             /* Case 4: Free range is on right boundary of matched node. Try to 
908                              *         combine free range with right node.
909                              *
910                              * |<----------matched node---------->||<---right node (free)--->|
911                              *        |<---findNode (free req)--->|
912                              */ 
913                             
914                             rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
915                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); 
916                             /* Remove freeing instance from owner list for compare with rightNode */
917                             deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
918                             
919                             if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
920                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
921                                 /* Combine rightNode and findNode */
922                                 rightNode->base = findNode.base;
923                                 rightNode->length += findNode.length;
924                             }
925                             else {
926                                 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
927                                 copyOwners(rightNode, matchingNode);
928                             }
930                             /* Remove rightNode range from matchingNode */
931                             matchingNode->length -= findNode.length;  
932                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
933                         }
935                         /* Add freeing instance back into matchingNode allocations */
936                         addOwner(matchingNode, opInfo->serviceSrcInstNode);
937                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
938                     }
940                     retVal = RM_SERVICE_APPROVED;
941                 }
942                 else {
943                     retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST;
944                 }
945             }
946             else {
947                 retVal = RM_SERVICE_DENIED_RES_ALREADY_FREE;
948             }
949         }
950         else {
951             retVal = RM_SERVICE_DENIED_PARTIAL_FREE;
952         }
953     }
954     else {
955         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
956     }
957     return(retVal);  
960 /* FUNCTION PURPOSE: Issues a service response to application
961  ***********************************************************************
962  * DESCRIPTION: Provides a service response back to the application
963  *              using the service callback function provided to
964  *              the RM instance at the time of the service request.
965  */
966 static void serviceResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)
968     Rm_ServiceRespInfo serviceResponse;
970     /* The responseTransaction will contain the resultant state details of
971      * the requestTransaction's service request */
972     serviceResponse.serviceState = transaction->state;
973     /* Pass back the ID that was provided to the component when it requested
974      * the service */
975     serviceResponse.serviceId = transaction->localId;
977     /* Service was approved and service was an allocate request.  The resource
978      * data is passed back to the component */
979     if ((serviceResponse.serviceState == RM_SERVICE_APPROVED) &&
980         ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
981          (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) ||
982          (transaction->type == Rm_service_RESOURCE_GET_BY_NAME)))
983     {
984         strncpy(serviceResponse.resourceName, transaction->resourceInfo.name, RM_NAME_MAX_CHARS);
985         serviceResponse.resourceBase = transaction->resourceInfo.base;
986         serviceResponse.resourceLength = transaction->resourceInfo.length;
987     }
989     /* Issue the callback to the requesting component with the response information */
990     transaction->callback.serviceCallback(&serviceResponse);
992     /* Delete the transaction from the transaction queue */
993     rmTransactionQueueDelete(rmInst, transaction->localId);
994     return;
997 /* FUNCTION PURPOSE: Sends RM response packets
998  ***********************************************************************
999  * DESCRIPTION: Sends RM response packets to RM instance's that sent
1000  *              RM request packets to the RM instance.  The response
1001  *              is sent via the RM transport API which is plugged
1002  *              with an application created transport path.
1003  */
1004 static void transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)
1006     Rm_Transport    *dstTransport = NULL;
1007     Rm_PacketHandle  pktHandle = NULL;
1009     dstTransport = rmTransportFindRemoteName((Rm_Transport *) rmInst->transports, transaction->pktSrcInstName);
1011     switch (transaction->type) {
1012         case Rm_service_RESOURCE_ALLOCATE_INIT:
1013         case Rm_service_RESOURCE_ALLOCATE_USE:
1014         case Rm_service_RESOURCE_FREE:
1015         case Rm_service_RESOURCE_GET_BY_NAME:
1016             pktHandle = rmTransportCreateResourceResponsePkt(rmInst, dstTransport->appTransportHandle, 
1017                                                              transaction);
1018             break;
1019         case Rm_service_RESOURCE_MAP_TO_NAME:
1020         case Rm_service_RESOURCE_UNMAP_NAME:
1021             pktHandle = rmTransportCreateNsResponsePkt(rmInst, dstTransport->appTransportHandle,
1022                                                        transaction);
1023             break;
1024     }
1026     if (pktHandle) {
1027         if (rmInst->transportCallouts.rmSendPkt) {
1028             if (rmInst->transportCallouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) {
1029                 transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR;
1030             }
1031         }
1032         else {
1033             transaction->state = RM_ERROR_TRANSPORT_SEND_NOT_REGD;
1034         }
1035     }
1036     rmTransactionQueueDelete(rmInst, transaction->localId);
1039 /* FUNCTION PURPOSE: Sends RM request packets
1040  ***********************************************************************
1041  * DESCRIPTION: Sends RM request packets to RM instance's that are
1042  *              capable of forwarding or validating service requests.
1043  *              The request is sent via the RM transport API which is
1044  *              plugged with an application created transport path.
1045  */
1046 static void transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)
1048     Rm_Transport    *dstTransport = NULL;
1049     Rm_PacketHandle  pktHandle = NULL;
1051     if (rmInst->registeredWithDelegateOrServer) {
1052         if (rmInst->instType == Rm_instType_CLIENT) {
1053             dstTransport = rmTransportFindRemoteInstType((Rm_Transport *) rmInst->transports, Rm_instType_CLIENT_DELEGATE);
1055             if (!dstTransport) {
1056                 dstTransport = rmTransportFindRemoteInstType((Rm_Transport *) rmInst->transports, Rm_instType_SERVER);
1057             }
1058         } 
1059         else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1060             dstTransport = rmTransportFindRemoteInstType((Rm_Transport *) rmInst->transports, Rm_instType_SERVER);
1061         }
1063         switch (transaction->type) {
1064             case Rm_service_RESOURCE_ALLOCATE_INIT:
1065             case Rm_service_RESOURCE_ALLOCATE_USE:
1066             case Rm_service_RESOURCE_FREE:
1067             case Rm_service_RESOURCE_GET_BY_NAME:
1068                 pktHandle = rmTransportCreateResourceReqPkt(rmInst, dstTransport->appTransportHandle, transaction);
1069                 break;
1070             case Rm_service_RESOURCE_MAP_TO_NAME:
1071             case Rm_service_RESOURCE_UNMAP_NAME:
1072                 pktHandle = rmTransportCreateNsRequestPkt(rmInst, dstTransport->appTransportHandle, transaction);
1073                 break;
1074         }
1076         if (pktHandle) {
1077             if (rmInst->transportCallouts.rmSendPkt) {            
1078                 if (rmInst->transportCallouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) {
1079                     transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR;
1080                 }
1081             }
1082             else {
1083                 transaction->state = RM_ERROR_TRANSPORT_SEND_NOT_REGD;
1084             }                
1085         }
1087         transaction->hasBeenForwarded = true;
1088         /* Transaction not deleted.  Waiting for response from RM CD or Server */
1089     }
1092 /* FUNCTION PURPOSE: Issues an allocator operation
1093  ***********************************************************************
1094  * DESCRIPTION: Issues an allocator preallocate, allocate, or free
1095  *              for an RM resource.
1096  */
1097 static int32_t allocatorOperation(Rm_Inst *rmInst, Rm_AllocatorOpInfo *opInfo)
1099     Rm_Allocator *allocator = NULL;
1100     int32_t       resourceOffsetInPolicy;
1101     int32_t       retVal;
1102     
1103     resourceOffsetInPolicy = rmPolicyGetResourceOffset(rmInst->policy, opInfo->resourceInfo->name);
1104     allocator = rmAllocatorFind(rmInst->allocators, opInfo->resourceInfo->name);
1105     
1106     if ((resourceOffsetInPolicy > 0) && allocator) {
1107         if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE) {
1108             retVal = treePreAllocate(rmInst, allocator, resourceOffsetInPolicy, opInfo);
1109         }               
1110         else if (opInfo->operation == Rm_allocatorOp_ALLOCATE) {
1111             retVal = treeAllocate(rmInst, allocator, resourceOffsetInPolicy, opInfo);
1112         }
1113         else if (opInfo->operation == Rm_allocatorOp_FREE) {
1114             retVal = treeFree(allocator, opInfo);
1115         }         
1116     }
1117     else {
1118         /* Resource could not be found in policy and/or allocator */
1119         retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
1120     }
1121     return(retVal);
1124 /* FUNCTION PURPOSE: Arbitrates allocation service requests
1125  ***********************************************************************
1126  * DESCRIPTION: Issues a set of allocator operations in order to
1127  *              handle a received allocation request.  Allocation
1128  *              requests are always forwarded to the Server on Client
1129  *              CD instances.  If a request is made with a NameServer
1130  *              name the resource base and length parameters are
1131  *              retrieved from the NameServer prior to the allocation
1132  *              attempt.
1133  */
1134 static void allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode,
1135                                uint32_t allocType)
1137     Rm_AllocatorOpInfo  opInfo;
1138     Rm_NameServerObjCfg nameServerObjCfg;
1139     int32_t             retVal = transaction->state;
1141     memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
1142     
1143     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1144         /* Forward all allocation requests to Server if transport is up.  Otherwise, just queue. */
1145         if (rmInst->registeredWithDelegateOrServer) {
1146             transactionForwarder(rmInst, transaction);   
1147         }  
1148     }
1149     else if (rmInst->instType == Rm_instType_SERVER) {
1150         opInfo.resourceInfo = &transaction->resourceInfo;
1151         opInfo.serviceSrcInstNode = validInstNode;
1152         opInfo.allocType = allocType;
1154         /* Populated NameServer name has precedence over base */
1155         if (strlen(transaction->resourceInfo.nameServerName) > 0) {
1156             if ((transaction->resourceInfo.base == 0) &&
1157                 (transaction->resourceInfo.length == 0) &&
1158                 (transaction->resourceInfo.alignment == 0)) {
1159                 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1160                 nameServerObjCfg.nameServerTree = rmInst->nameServer;
1161                 nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
1162                 if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
1163                     strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
1164                     transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
1165                     transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
1166                 }                
1167             }
1168             else {
1169                 retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT;
1170             }
1171         }
1173         if (retVal == RM_SERVICE_PROCESSING) {      
1174             if (transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED) {
1175                 opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE;
1176                 retVal = allocatorOperation(rmInst, &opInfo);
1177             }
1178         
1179             if (retVal == RM_SERVICE_PROCESSING) {
1180                 opInfo.operation = Rm_allocatorOp_ALLOCATE;
1181                 retVal = allocatorOperation(rmInst, &opInfo);
1182             }      
1183         }
1184         
1185         transaction->state = retVal;
1187         if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1188             /* Source of allocation was not the server instance, provide the transaction
1189              * to the transaction responder */
1190             transactionResponder(rmInst, transaction);
1191         }
1192         /* Otherwise let the return stack return the transaction to the serviceHandler */                   
1193     }   
1196 /* FUNCTION PURPOSE: Arbitrates free service requests
1197  ***********************************************************************
1198  * DESCRIPTION: Issues a set of allocator operations in order to
1199  *              handle a received free request.  Free
1200  *              requests are always forwarded to the Server on Client
1201  *              CD instances.  If a request is made with a NameServer
1202  *              name the resource base and length parameters are
1203  *              retrieved from the NameServer prior to the free
1204  *              attempt.
1205  */
1206 static void freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode)
1208     Rm_AllocatorOpInfo  opInfo; 
1209     Rm_NameServerObjCfg nameServerObjCfg;    
1210     int32_t             retVal = transaction->state;
1212     memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
1213     
1214     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1215         /* Forward all free requests to Server if transport is up.  Otherwise, just queue. */
1216         if (rmInst->registeredWithDelegateOrServer) {
1217             transactionForwarder(rmInst, transaction);   
1218         }
1219     }
1220     else if (rmInst->instType == Rm_instType_SERVER) {
1221         opInfo.resourceInfo = &transaction->resourceInfo;
1222         opInfo.serviceSrcInstNode = validInstNode;
1224         /* Populated NameServer name has precedence over base */
1225         if (strlen(transaction->resourceInfo.nameServerName) > 0) {
1226             if ((transaction->resourceInfo.base == 0) &&
1227                 (transaction->resourceInfo.length == 0) &&
1228                 (transaction->resourceInfo.alignment == 0)) {
1229                 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1230                 nameServerObjCfg.nameServerTree = rmInst->nameServer;
1231                 nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
1232                 if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
1233                     strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
1234                     transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
1235                     transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
1236                 } 
1237             }
1238             else {
1239                 retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT;
1240             }                
1241         }
1242         
1243         if(retVal == RM_SERVICE_PROCESSING) {        
1244             opInfo.operation = Rm_allocatorOp_FREE;
1245             retVal = allocatorOperation(rmInst, &opInfo);
1246         }       
1248         transaction->state = retVal;
1250         if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1251             /* Source of allocation was not the server instance, provide the transaction
1252              * to the transaction responder */
1253             transactionResponder(rmInst, transaction);
1254         }
1255         /* Otherwise let the return stack return the transaction to the serviceHandler */        
1256     }   
1259 /* FUNCTION PURPOSE: Reserves a Linux resource
1260  ***********************************************************************
1261  * DESCRIPTION: Reserves resources for Linux using the base and length
1262  *              values retrieved from the Linux DTB via the
1263  *              "linux-dtb-alias" properties within the GRL.
1264  */
1265 static int32_t reserveLinuxResource(Rm_Inst *rmInst, Rm_LinuxAlias *linuxAlias, 
1266                                     Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)
1268     int32_t  retVal = RM_OK;
1269     bool     baseFound = false;
1270     bool     lengthFound = false;
1271     uint32_t valueIndex = 0;
1273     while ((linuxValues) && (!baseFound || !lengthFound)) {
1274         if (linuxAlias->baseOffset == valueIndex) {
1275             opInfo->resourceInfo->base = linuxValues->value;
1276             baseFound = true;
1278             if (linuxAlias->lengthOffset == RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) {
1279                 opInfo->resourceInfo->length = 1;
1280                 lengthFound = true;
1281             }
1282         }
1283         else if (linuxAlias->lengthOffset == valueIndex) {
1284             opInfo->resourceInfo->length = linuxValues->value;
1285             lengthFound = true;
1286         }
1288         linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;
1289         valueIndex++;
1290     }
1292     if (!baseFound || !lengthFound) {
1293         retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1294     }
1295     else {
1296         /* Allocate resource to Linux */
1297         retVal = allocatorOperation(rmInst, opInfo);
1298     }
1299     return (retVal);
1302 /* FUNCTION PURPOSE: Finds and reserves Linux resources
1303  ***********************************************************************
1304  * DESCRIPTION: Parses the Linux DTB for resources consumed by the
1305  *              Linux kernel.  If the resource is found via the
1306  *              "linux-dtb-alias" property defined in the GRL it is 
1307  *              reserved.
1308  */
1309 static int32_t findAndReserveLinuxResource(Rm_Inst *rmInst, const char *resourceName, void *linuxDtb, 
1310                                            Rm_LinuxAlias *linuxAlias)
1312     Rm_AllocatorOpInfo  opInfo;
1313     Rm_ResourceInfo     resourceInfo;
1314     uint32_t            pathOffset;
1315     uint32_t            pathSize;
1316     char               *spacePtr;
1317     int32_t             propOffset;
1318     int32_t             nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1319     int32_t             prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1320     int32_t             depth;
1321     int32_t             propertyLen;
1322     const char         *propertyName;
1323     const void         *propertyData; 
1324     Rm_LinuxValueRange *linuxValueRange;
1325     int32_t             retVal = RM_OK; 
1327     memset((void *) &opInfo, 0, sizeof(Rm_AllocatorOpInfo));
1328     memset((void *) &resourceInfo, 0, sizeof(Rm_ResourceInfo));
1330     strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS);
1331     opInfo.serviceSrcInstNode = rmPolicyGetLinuxInstNode(rmInst->validInstances);
1332     opInfo.operation = Rm_allocatorOp_ALLOCATE;
1333     opInfo.resourceInfo = &resourceInfo;    
1335     while(linuxAlias) {
1336         /* Reset parsing variables */
1337         pathOffset = 0;
1338         pathSize = strlen(linuxAlias->path) + 1;
1339         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1340         prevDepth = RM_DTB_UTIL_STARTING_DEPTH;   
1341         resourceInfo.base = 0;
1342         resourceInfo.length = 0;
1344         spacePtr = strpbrk(linuxAlias->path, " ");
1345         if (spacePtr) {
1346             *spacePtr = '\0';
1347         }       
1348         
1349         while(pathOffset < pathSize) {
1350             /* Move through DTB nodes until next alias path node found */
1351             if (strcmp(linuxAlias->path + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL))) {
1352                 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);
1354                 if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) {
1355                     /* Returning from subnode that matched part of alias path without finding
1356                      * resource values */
1357                     retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1358                     break;
1359                 }
1360             }
1361             else {
1362                 /* Found next alias path node.  Move to next node name in path string. */
1363                 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1364                 spacePtr = strpbrk(linuxAlias->path + pathOffset, " ");
1365                 if (spacePtr) {
1366                     *spacePtr = '\0';
1367                 }       
1368                 
1369                 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);
1370                 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);
1371                 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1372                        (pathOffset < pathSize)) {
1373                     propertyData = fdt_getprop_by_offset(linuxDtb, propOffset, 
1374                                                          &propertyName, &propertyLen);
1376                     if (strcmp(linuxAlias->path + pathOffset, propertyName) == 0) {
1377                         /* Found resource at end of alias path */
1378                         pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1379                         linuxValueRange = rmDtbUtilLinuxExtractValues(propertyData, propertyLen);
1380                         retVal = reserveLinuxResource(rmInst, linuxAlias, 
1381                                                       linuxValueRange, &opInfo);
1382                         rmDtbUtilLinuxFreeValues(linuxValueRange);
1383                     }
1384                     propOffset = fdt_next_property_offset(linuxDtb, propOffset);
1385                 } 
1387                 if (propOffset < -FDT_ERR_NOTFOUND) {
1388                     retVal = propOffset;
1389                     break;
1390                 }
1391             }
1392         }
1394         if (retVal < RM_OK) {
1395             break;
1396         }
1397         linuxAlias = linuxAlias->nextLinuxAlias;
1398     }
1399     return (retVal);
1402 /* FUNCTION PURPOSE: Creates and initializes a resource allocator
1403  ***********************************************************************
1404  * DESCRIPTION: Creates a resource allocator for the provided
1405  *              resource name and resource properties retrieved
1406  *              from the GRL.  Resources will be reserved for 
1407  *              the Linux kernel if the Linux DTB is provided
1408  *              and there are "linux-dtb-alias" properties
1409  *              specified in the GRL.
1410  */
1411 static int32_t createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, 
1412                                       Rm_ResourceProperties *resourceProperties, void *linuxDtb)
1414     Rm_ResourceRange    *range = NULL;
1415     Rm_ResourceRange    *rangeBasePtr = NULL;
1416     Rm_NsAssignment     *nsAssignments = NULL;
1417     Rm_NsAssignment     *nsAssignmentBasePtr = NULL;
1418     Rm_LinuxAlias       *linuxAlias = NULL;
1419     Rm_NameServerObjCfg  nameServerObjCfg;      
1420     int32_t              retVal = RM_OK;
1422     if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0)) {
1423         range = rangeBasePtr = rmDtbUtilResExtractRange(resourceProperties->rangeData, 
1424                                                         resourceProperties->rangeLen);
1425         
1426         if ((retVal = createResourceTree(rmInst, resourceName, range)) >= RM_OK) {
1427             if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen) {
1428                 if (linuxDtb) {
1429                     linuxAlias = rmDtbUtilResExtractLinuxAlias(resourceProperties->linuxAliasData,
1430                                                                resourceProperties->linuxAliasLen, &retVal);
1431                     if (linuxAlias) {
1432                         retVal = findAndReserveLinuxResource(rmInst, resourceName, linuxDtb, linuxAlias);            
1433                     }
1434                 }
1435                 else {
1436                     retVal = RM_ERROR_GRL_LINUX_ALIAS_BUT_NO_DTB;
1437                 }
1438             }
1439         }
1440     }
1441     
1442     if (retVal >= RM_OK) {
1443         if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) {
1444             nsAssignments = rmDtbUtilResExtractNsAssignment(resourceProperties->nsAssignData, 
1445                                                             resourceProperties->nsAssignLen, &retVal);
1446             if (nsAssignments) {
1447                 nsAssignmentBasePtr = nsAssignments;
1448                 while (nsAssignments) {
1449                     memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1450                     nameServerObjCfg.nameServerTree = rmInst->nameServer;
1451                     nameServerObjCfg.nodeCfg.objName = nsAssignments->nsName;
1452                     nameServerObjCfg.nodeCfg.resourceName = (char *)resourceName;
1453                     nameServerObjCfg.nodeCfg.resourceBase= nsAssignments->resourceBase;
1454                     nameServerObjCfg.nodeCfg.resourceLength = nsAssignments->resourceLength;                
1455                     rmNameServerAddObject(&nameServerObjCfg);
1456                     nsAssignments = nsAssignments->nextNsAssignment;
1457                 }
1458                 rmDtbUtilResFreeNsAssignmentList(nsAssignmentBasePtr);
1459             }
1460         }
1461     }
1463     rmDtbUtilResFreeRange(rangeBasePtr);
1464     if (linuxAlias) {
1465         rmDtbUtilResFreeLinuxAlias(linuxAlias);
1466     }
1467     return(retVal);
1470 /* FUNCTION PURPOSE: Recursively parses GRL resource properties
1471  ***********************************************************************
1472  * DESCRIPTION: Recursively parses and stores GRL resource node 
1473  *              properties using the LIBFDT APIs
1474  */
1475 static int32_t parseResourceProperty(void *globalResourceDtb, int32_t offset, 
1476                                      Rm_ResourceProperties *propertyInfo)
1478         int32_t              propertyLen;
1479         const char          *propertyName;
1480         const void          *propertyData;
1481     Rm_ResourcePropType  propertyType;
1482     int32_t              retVal = RM_OK;
1484         propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen);
1485     propertyType = rmDtbUtilResGetPropertyType(propertyName);
1486     if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) {
1487         propertyInfo->rangeData = propertyData;
1488         propertyInfo->rangeLen = propertyLen;
1489     }
1490     else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) {
1491         propertyInfo->nsAssignData = propertyData;
1492         propertyInfo->nsAssignLen = propertyLen;
1493     }
1494     else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS) {
1495         propertyInfo->linuxAliasData = propertyData;
1496         propertyInfo->linuxAliasLen = propertyLen;
1497     }        
1498     else {
1499         retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY;
1500     }
1502     if (retVal == RM_OK) {
1503         offset = fdt_next_property_offset(globalResourceDtb, offset);
1504         if (offset >= 0) {
1505             retVal = parseResourceProperty(globalResourceDtb, offset, propertyInfo);
1506         }
1507         else if (offset != -FDT_ERR_NOTFOUND) {
1508             /* Error returned by LIBFDT */
1509             retVal = offset;
1510         }
1511     }
1512     return (retVal);
1515 /* FUNCTION PURPOSE: Recursively parses GRL resource nodes
1516  ***********************************************************************
1517  * DESCRIPTION: Recursively parses GRL resource nodes looking for
1518  *              resource properties to create the resource allocators.
1519  *              The LIBFDT APIs are used to parse the GRL.
1520  */
1521 static int32_t parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth,
1522                                  void *linuxDtb)
1524         const char            *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL);
1525     Rm_ResourceProperties  resourceProperties;
1526         int32_t                retVal = RM_OK;
1527         int32_t                offset;
1529     memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties));
1530     /* Get properties of resource node */
1531         offset = fdt_first_property_offset(globalResourceDtb, nodeOffset);
1532         if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1533                 retVal =  parseResourceProperty(globalResourceDtb, offset, &resourceProperties);
1534         if (retVal < -FDT_ERR_NOTFOUND) {
1535             return (retVal);
1536         }
1537         if (retVal = createAndInitAllocator(rmInst, resourceName, &resourceProperties, linuxDtb) < RM_OK) {
1538             return (retVal);
1539         }
1540         }
1541     else if (offset != -FDT_ERR_NOTFOUND) {
1542                 /* Error returned by LIBFDT */
1543         return (offset);
1544     }
1545     
1546         offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth);
1547     if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
1548         retVal = parseResourceNode(rmInst, globalResourceDtb, offset, depth, linuxDtb);
1549         if (retVal < -FDT_ERR_NOTFOUND) {
1550             return (retVal);
1551         }
1552     }
1553     else if (offset != -FDT_ERR_NOTFOUND) {
1554         /* Error returned by LIBFDT */
1555         return (offset);
1556     }
1557     return (retVal);
1560 /* FUNCTION PURPOSE: Initializes server allocators
1561  ***********************************************************************
1562  * DESCRIPTION: Creates and initializes a server instance's
1563  *              resource allocators using the GRL and, if
1564  *              provided, Linux DTB.
1565  */
1566 static int32_t initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb, void *linuxDtb)
1568     int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1569     int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH;
1570     int32_t result = RM_OK;
1572     /* Recursively parse the Global Resource List, creating an allocator for
1573      * each resource as specified in the node */
1574     result = parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth, linuxDtb);
1576     return(result);
1579 /**********************************************************************
1580  ********************** Internal Functions ****************************
1581  **********************************************************************/
1583 /* FUNCTION PURPOSE: Adds a transaction
1584  ***********************************************************************
1585  * DESCRIPTION: Returns a pointer to a newly created transaction.
1586  *              The transaction is created based on a new service
1587  *              request received via the service API or the
1588  *              transport API (service forwarded from another instance)
1589  */
1590 Rm_Transaction *rmTransactionQueueAdd(Rm_Inst *rmInst)
1592     Rm_Transaction *transactionQueue = rmInst->transactionQueue;
1593     Rm_Transaction *newTransaction   = NULL;
1595     newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction));
1596     if (newTransaction) {
1597         memset((void *)newTransaction, 0, sizeof(Rm_Transaction));
1599         newTransaction->localId = transactionGetSequenceNum(rmInst);
1600         newTransaction->nextTransaction = NULL;  
1601         if (transactionQueue) {
1602             while (transactionQueue->nextTransaction) {
1603                 transactionQueue = transactionQueue->nextTransaction;
1604             }
1605             transactionQueue->nextTransaction = newTransaction;
1606         }
1607         else {
1608             rmInst->transactionQueue = newTransaction;
1609         }
1610     }
1611     return (newTransaction);
1614 /* FUNCTION PURPOSE: Finds a transaction
1615  ***********************************************************************
1616  * DESCRIPTION: Returns a pointer to a transaction resident
1617  *              in the transaction queue that matches the provided
1618  *              transaction ID.
1619  */
1620 Rm_Transaction *rmTransactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)
1622     Rm_Transaction *transaction = rmInst->transactionQueue;
1624     while (transaction) {
1625         if (transaction->localId == transactionId) {
1626             break;             
1627         }
1628         transaction = transaction->nextTransaction;
1629     }
1631     return (transaction);
1634 /* FUNCTION PURPOSE: Deletes a transaction
1635  ***********************************************************************
1636  * DESCRIPTION: Deletes the transaction with the provided transaction
1637  *              ID from the instance's transaction queue.
1638  */
1639 int32_t rmTransactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)
1641     Rm_Transaction *transaction     = rmInst->transactionQueue;
1642     Rm_Transaction *prevTransaction = NULL;
1643     int32_t         retVal          = RM_OK;
1645     while (transaction) {
1646         if (transaction->localId == transactionId) {
1647             break;             
1648         }
1650         prevTransaction = transaction;
1651         transaction = transaction->nextTransaction;
1652     }
1654     if (transaction) {
1655         if (prevTransaction == NULL) {
1656             /* Transaction at start of queue. Map second transaction to start of queue 
1657              * as long as more than one transactions. */
1658             rmInst->transactionQueue = transaction->nextTransaction;
1659         }
1660         else {
1661             /* Transaction in middle or end of queue. */
1662             prevTransaction->nextTransaction = transaction->nextTransaction;
1663         }
1664         Rm_osalFree((void *)transaction, sizeof(Rm_Transaction));
1665     }
1666     else {
1667         retVal = RM_ERROR_SERVICE_TRANS_DOES_NOT_EXIST;
1668     }    
1669     return (retVal);
1672 /* FUNCTION PURPOSE: Finds an allocator
1673  ***********************************************************************
1674  * DESCRIPTION: Returns a pointer to an allocator that matches the 
1675  *              provided resource name.
1676  */
1677 Rm_Allocator *rmAllocatorFind(Rm_Allocator *allocatorList, char *resourceName)
1679     while (allocatorList) {
1680         if (strncmp(allocatorList->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
1681             break;             
1682         }
1683         allocatorList = allocatorList->nextAllocator;
1684     }
1686     return (allocatorList);
1689 /* FUNCTION PURPOSE: Processes a transaction
1690  ***********************************************************************
1691  * DESCRIPTION: Processes transactions created from services
1692  *              received via the service handle or the transport.
1693  *              Transactions will be routed within the RM system
1694  *              based on the RM instance type and the type of
1695  *              the transaction.
1696  */
1697 void rmTransactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)
1699     void                *validInstNode;
1700     Rm_PolicyCheckCfg    privCheckCfg;
1701     Rm_NameServerObjCfg  nameServerObjCfg;      
1702     uint32_t             allocType = 0;    
1704     /* Handle static transactions originating on this instance.  Any other static transactions will be
1705      * stored in transaction queue until all transports are up. */
1706     if (((rmInst->instType == Rm_instType_CLIENT) || (rmInst->instType == Rm_instType_CLIENT_DELEGATE)) &&
1707         (!rmInst->registeredWithDelegateOrServer) && 
1708         (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS) == 0)) {
1709         if (rmInst->staticInfo.staticPolicy) {
1710             if ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
1711                 (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE)) {
1712                 /* Check request against startup policy */
1713                 memset((void *)&privCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
1715                 if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
1716                     privCheckCfg.type = Rm_policyCheck_INIT;
1717                 }
1718                 else {
1719                     privCheckCfg.type = Rm_policyCheck_USE;
1720                 }
1721                 privCheckCfg.policyDtb = rmInst->staticInfo.staticPolicy;
1722                 privCheckCfg.validInstNode = rmPolicyGetValidInstNode(rmInst->staticInfo.staticValidInstTree, 
1723                                                                       rmInst->instName);
1724                 privCheckCfg.resourceOffset = rmPolicyGetResourceOffset(rmInst->staticInfo.staticPolicy,
1725                                                                         transaction->resourceInfo.name);
1726                 privCheckCfg.resourceBase = transaction->resourceInfo.base;
1727                 privCheckCfg.resourceLength = transaction->resourceInfo.length;
1729                 if (rmPolicyCheckPrivilege(&privCheckCfg, &transaction->state)) {
1730                     transaction->state = RM_SERVICE_APPROVED_STATIC;
1731                 }
1732                 else if (transaction->state == RM_SERVICE_PROCESSING) {
1733                     /* Privilege check returned false without error */
1734                     transaction->state = RM_SERVICE_DENIED_BY_STATIC_POLICY;
1735                 }
1736             }
1737             else {
1738                 transaction->state = RM_SERVICE_DENIED_INVALID_STATIC_REQUEST;
1739             }
1740         }
1741         else {
1742             transaction->state = RM_ERROR_REQ_FAILED_NO_STATIC_POLICY;
1743         }        
1744     }
1745     else {
1746         /* Handle auto-forwarded transactions.  These transactions include:
1747          * - All request transactions received on Clients are forwarded to the Client Delegate
1748          * - NameServer requests received on the Client Delegate are forwarded to the Server */
1749         if ((rmInst->instType == Rm_instType_CLIENT) ||
1750             ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&
1751              ((transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||
1752               (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) ||
1753               (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))) {
1754               
1755             if ((transaction->state != RM_SERVICE_PROCESSING) &&
1756                 (transaction->state != RM_SERVICE_APPROVED_STATIC)) {
1757                 if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1758                     /* Transaction did not originate on this instance */
1759                     transactionResponder(rmInst, transaction);
1760                 }
1761                 else {
1762                     /* Transaction originated on this instance */
1763                     serviceResponder(rmInst, transaction);
1764                 }
1765             }
1766             else {
1767                 /* Forward request if transport is up.  Otherwise, just queue. */
1768                 if (rmInst->registeredWithDelegateOrServer) {
1769                     transactionForwarder(rmInst, transaction);   
1770                 } 
1771             }
1772         }
1773         else {
1774             /* Validate service's originating instance name */
1775             if (rmInst->instType == Rm_instType_SERVER) {
1776                 validInstNode = rmPolicyGetValidInstNode(rmInst->validInstances, transaction->serviceSrcInstName);
1777                 if (validInstNode == NULL) {
1778                     transaction->state = RM_SERVICE_DENIED_INST_NAME_NOT_VALID;
1780                     /* Send result via responder if transaction did not originate from this instance */
1781                     if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1782                         transactionResponder(rmInst, transaction);
1783                     }
1784                 }
1785             }
1787             switch (transaction->type) {
1788                 case Rm_service_RESOURCE_ALLOCATE_INIT:
1789                 case Rm_service_RESOURCE_ALLOCATE_USE:
1790                 case Rm_service_RESOURCE_FREE:               
1791                     if ((transaction->state != RM_SERVICE_PROCESSING) &&
1792                         (transaction->state != RM_SERVICE_APPROVED_STATIC)) {
1793                         /* Transaction complete */
1794                         if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1795                             /* Transaction result not destined for this instance */
1796                             transactionResponder(rmInst, transaction);
1797                         }
1798                         else {
1799                             /* Transaction result destined for this instance */
1800                             serviceResponder(rmInst, transaction);      
1801                         }
1802                     }
1803                     else {
1804                         /* Complete allocation/free request */
1805                         if (transaction->type == Rm_service_RESOURCE_FREE) {
1806                             freeHandler(rmInst, transaction, validInstNode);
1807                         }
1808                         else {
1809                             switch (transaction->type) {
1810                                 case Rm_service_RESOURCE_ALLOCATE_INIT:
1811                                     RM_policy_SET_PERM(allocType, RM_POLICY_PERM_INIT_SHIFT, 1);
1812                                     break;
1813                                 case Rm_service_RESOURCE_ALLOCATE_USE:
1814                                     RM_policy_SET_PERM(allocType, RM_POLICY_PERM_USE_SHIFT, 1);    
1815                                     break;
1816                             }
1817                             allocationHandler(rmInst, transaction, validInstNode, allocType);
1818                         }
1819                     }
1820                     break;
1821                 case Rm_service_RESOURCE_MAP_TO_NAME:
1822                 case Rm_service_RESOURCE_GET_BY_NAME:
1823                 case Rm_service_RESOURCE_UNMAP_NAME:                
1824                     /* NameServer resides on server */
1825                     memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1826                     if (rmInst->nameServer) {
1827                         nameServerObjCfg.nameServerTree = rmInst->nameServer;
1828                         nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
1829                         if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) {
1830                             nameServerObjCfg.nodeCfg.resourceName = transaction->resourceInfo.name;
1831                             nameServerObjCfg.nodeCfg.resourceBase= transaction->resourceInfo.base;
1832                             nameServerObjCfg.nodeCfg.resourceLength = transaction->resourceInfo.length;
1833                             transaction->state = rmNameServerAddObject(&nameServerObjCfg);
1834                         }
1835                         else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) {
1836                             if ((transaction->state = rmNameServerFindObject(&nameServerObjCfg)) ==
1837                                 RM_SERVICE_PROCESSING) {
1838                                 strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
1839                                 transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
1840                                 transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
1841                                 transaction->state = RM_SERVICE_APPROVED;
1842                             } 
1843                         }
1844                         else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) {
1845                             transaction->state = rmNameServerDeleteObject(&nameServerObjCfg);
1846                         }
1847                     }
1848                     else {
1849                         transaction->state = RM_ERROR_NAMESERVER_DOES_NOT_EXIST;
1850                     }
1852                     /* Send result via responder if transaction did not originate from this instance */
1853                     if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1854                         transactionResponder(rmInst, transaction);
1855                     }
1856                     break;
1857             }
1858         }
1859     }
1861     /* Forward any queued requests that weren't forwarded yet */
1862     if (rmInst->registeredWithDelegateOrServer) {
1863         transaction = rmInst->transactionQueue;
1864         while(transaction) {
1865             if (((transaction->state == RM_SERVICE_PROCESSING) ||
1866                  (transaction->state == RM_SERVICE_APPROVED_STATIC)) &&
1867                 !transaction->hasBeenForwarded) {
1868                 transactionForwarder(rmInst, transaction);
1869             }
1870             transaction = transaction->nextTransaction;
1871         }
1872     }
1874      
1875 /**********************************************************************
1876  ********************** Application visible APIs **********************
1877  **********************************************************************/
1879 /* FUNCTION PURPOSE: Display status of managed resources
1880  ***********************************************************************
1881  * DESCRIPTION: Prints the status (allocate/free status, as well as
1882  *              owners) for all resources managed by the RM 
1883  *              instance network.  Also, prints the NameServer name
1884  *              entries.  This function is only available on server
1885  *              instances.
1886  */
1887 void Rm_printResourceStatus(Rm_Handle rmServerHandle)
1889     Rm_Inst         *rmInst = (Rm_Inst *)rmServerHandle;
1890     Rm_Allocator    *allocator = rmInst->allocators;
1891     Rm_Owner        *owners;
1892     Rm_ResourceTree *treeRoot;
1893     Rm_ResourceNode *treeNode;
1895     if (rmInst->instType == Rm_instType_SERVER) {
1896         while (allocator != NULL) {
1897             Rm_osalLog("Resource: %s\n", allocator->resourceName);
1899             treeRoot = allocator->allocatorRootEntry;
1901             RB_FOREACH(treeNode, _Rm_AllocatorResourceTree, treeRoot) {               
1902                 Rm_osalLog("          %10d - %10d ", treeNode->base, 
1903                                                      treeNode->base + treeNode->length -1);
1904                 
1905                 if (treeNode->allocationCount == 0) {
1906                     Rm_osalLog("NOT ALLOCATED\n");
1907                 }
1908                 else {
1909                     owners = treeNode->ownerList;
1910                     Rm_osalLog("allocated to");
1911                     while (owners) {
1912                         Rm_osalLog(" %s", owners->instNameNode->name);
1913                         owners = owners->nextOwner;
1914                     }
1915                     Rm_osalLog("\n");
1916                 }
1917             }        
1918             allocator = allocator->nextAllocator;
1919         }
1920         rmNameServerPrintObjects(rmInst->nameServer);
1921     }
1924 /* FUNCTION PURPOSE: Display status of a RM instance
1925  ***********************************************************************
1926  * DESCRIPTION: Prints the current status of various RM instance
1927  *              properties such as the state of all transactions
1928  *              in the transaction queue and registered transports
1929  */
1930 void Rm_printInstanceStatus(Rm_Handle rmHandle)
1932     Rm_Inst        *rmInst = (Rm_Inst *)rmHandle;
1933     Rm_Transport   *transportList = (Rm_Transport *)rmInst->transports;
1934     Rm_Transaction *transactionQ = rmInst->transactionQueue;
1936     Rm_osalLog("Instance name: %s\n", rmInst->instName);
1937     if (rmInst->instType == Rm_instType_SERVER) {
1938         Rm_osalLog("Type: Server\n");
1939     }
1940     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1941         Rm_osalLog("Type: Client Delegate\n");
1942     }
1943     else {
1944         Rm_osalLog("Type: Client\n");
1945     }
1947     if (transportList) {
1948         Rm_osalLog("\nRegistered Transports:\n");
1949         while (transportList) {
1950             Rm_osalLog("    Remote instName:    %s\n", transportList->remoteInstName);
1951             if (transportList->remoteInstType == Rm_instType_SERVER) {
1952                 Rm_osalLog("    Remote instType:    Server\n");
1953             }
1954             else if (transportList->remoteInstType == Rm_instType_CLIENT_DELEGATE) {
1955                 Rm_osalLog("    Remote instType:    Client Delegate\n");
1956             }
1957             else {
1958                 Rm_osalLog("    Remote instType:    Client\n");
1959             }
1960             Rm_osalLog("    appTransportHandle: 0x%08x\n", transportList->appTransportHandle);
1961             Rm_osalLog("\n");
1962             transportList = transportList->nextTransport;
1963         }
1964     }
1966     if (transactionQ) {
1967         Rm_osalLog("\nQueued Service Transactions:\n");
1968         while (transactionQ) {
1969             Rm_osalLog("    Service type:       %d\n", transactionQ->type);
1970             Rm_osalLog("    Service ID:         %d\n", transactionQ->localId);
1971             Rm_osalLog("    Service srcInstName %s\n", transactionQ->serviceSrcInstName);
1972             Rm_osalLog("    Service state:      %d\n", transactionQ->state);
1973             Rm_osalLog("    Resource name:      %s\n", transactionQ->resourceInfo.name);
1974             Rm_osalLog("    Resource base:      %d\n", transactionQ->resourceInfo.base);
1975             Rm_osalLog("    Resource length:    %d\n", transactionQ->resourceInfo.length);
1976             Rm_osalLog("    Resource alignment: %d\n", transactionQ->resourceInfo.alignment);
1977             Rm_osalLog("    Resource NS name:   %s\n", transactionQ->resourceInfo.nameServerName);
1978             Rm_osalLog("\n");
1979             transactionQ = transactionQ->nextTransaction;
1980         }    
1981     }
1984 /* FUNCTION PURPOSE: RM instance creation and initialization
1985  ***********************************************************************
1986  * DESCRIPTION: Returns a new RM instance created and initialized
1987  *              using the parameters provided via the initCfg
1988  *              structure.
1989  */
1990 Rm_Handle Rm_init(Rm_InitCfg *initCfg, int32_t *result)
1992     Rm_Inst *rmInst;
1993     void    *globalResourceDtb = NULL;
1994     void    *linuxResourceDtb = NULL;
1995     bool     addLinux = false;
1997     *result = RM_OK;
1998     
1999     if ((initCfg->instName == NULL) ||
2000         ((strlen(initCfg->instName) + 1) > RM_NAME_MAX_CHARS)) {
2001         *result = RM_ERROR_INVALID_INST_NAME;
2002         return (NULL);
2003     }
2005     if (initCfg->instType >= Rm_instType_LAST) {
2006         *result = RM_ERROR_INVALID_INST_TYPE;
2007     }
2009     /* Create and initialize instance */
2010     rmInst = Rm_osalMalloc (sizeof(Rm_Inst));
2011     memset ((void *) rmInst, 0, sizeof(Rm_Inst));
2012     rmInst->isLocked = false;
2013     rmInst->registeredWithDelegateOrServer = false;
2014     rmInst->transactionSeqNum = transactionInitSequenceNum();
2016     rmInst->instType = initCfg->instType;    
2017     strncpy (rmInst->instName, initCfg->instName, RM_NAME_MAX_CHARS);
2019     if (rmInst->instType == Rm_instType_SERVER) {
2020         if (!initCfg->instCfg.serverCfg.globalResourceList ||
2021             !initCfg->instCfg.serverCfg.globalPolicy) {
2022             *result = RM_ERROR_INVALID_SERVER_CONFIGURATION;
2023             Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
2024             return(NULL);
2025         }
2027         rmInst->policy = initCfg->instCfg.serverCfg.globalPolicy;
2028         fdt_open_into(rmInst->policy, rmInst->policy, fdt_totalsize(rmInst->policy)); 
2030         if (initCfg->instCfg.serverCfg.linuxDtb) {
2031             linuxResourceDtb = initCfg->instCfg.serverCfg.linuxDtb;
2032             fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb));
2033             addLinux = true;
2034         }
2036         /* Create valid instance list from policy.  Must be done prior to parsing
2037          * GRL so that Linux resources can be reserved correctly */
2038         rmInst->validInstances = rmPolicyCreateValidInstTree(rmInst->policy, addLinux, result);
2039         /* Validate policy assignment strings */
2040         *result = rmPolicyValidatePolicy(rmInst->policy, rmInst->validInstances);  
2042         rmInst->nameServer = rmNameServerInit();
2044         globalResourceDtb = initCfg->instCfg.serverCfg.globalResourceList;
2045         fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb));
2047         if ((*result = initializeAllocators(rmInst, globalResourceDtb, linuxResourceDtb)) == RM_OK) {  
2048             *result = rmPolicyValidatePolicyResourceNames(rmInst->policy, (void *)rmInst->allocators);
2049         }
2050         if (*result < RM_OK) {
2051             Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
2052             return(NULL);
2053         }
2054     }
2056     if ((rmInst->instType == Rm_instType_CLIENT) && 
2057         (initCfg->instCfg.clientCfg.staticPolicy)) {
2058         rmInst->staticInfo.staticPolicy = initCfg->instCfg.clientCfg.staticPolicy; 
2059     }
2060     else if ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&
2061              (initCfg->instCfg.cdCfg.staticPolicy)) { 
2062         rmInst->staticInfo.staticPolicy = initCfg->instCfg.cdCfg.staticPolicy; 
2063     }
2064     if (rmInst->staticInfo.staticPolicy) {
2065         fdt_open_into(rmInst->staticInfo.staticPolicy, rmInst->staticInfo.staticPolicy, 
2066                       fdt_totalsize(rmInst->staticInfo.staticPolicy));       
2067         rmInst->staticInfo.staticValidInstTree = rmPolicyCreateValidInstTree(rmInst->staticInfo.staticPolicy, 
2068                                                                              addLinux, result);        
2069         if (*result == RM_OK) {
2070             /* Validate policy assignment strings */
2071             *result = rmPolicyValidatePolicy(rmInst->staticInfo.staticPolicy, rmInst->staticInfo.staticValidInstTree);
2072         }
2073         if (*result != RM_OK) {
2074             if (rmInst->staticInfo.staticValidInstTree) {
2075                 rmPolicyFreeValidInstTree(rmInst->staticInfo.staticValidInstTree);
2076             }
2077             Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
2078             rmInst = NULL;
2079         }
2080     }
2081     return ((Rm_Handle) rmInst);
2084 /* FUNCTION PURPOSE: Returns RM version information
2085  ***********************************************************************
2086  */
2087 uint32_t Rm_getVersion (void)
2089     return RM_VERSION_ID;
2092 /* FUNCTION PURPOSE: Returns RM version string
2093  ***********************************************************************
2094  */
2095 const char* Rm_getVersionStr (void)
2097     return rmVersionStr;