59d44c9ff302ef16058c327058ebd110753d5cb9
[keystone-rtos/rm-lld.git] / src / rm_allocator.c
1 /**
2  *   @file  rm_allocator.c
3  *
4  *   @brief   
5  *      This is the Resource Manager allocator 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 /* RM external includes */
43 #include <ti/drv/rm/rm.h>
45 /* RM internal includes */
46 #include <ti/drv/rm/include/rm_loc.h>
47 #include <ti/drv/rm/include/rm_allocatorloc.h>
48 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
49 #include <ti/drv/rm/include/rm_policyloc.h>
50 #include <ti/drv/rm/include/rm_treeloc.h>
52 /* RM LIBFDT includes */
53 #include <ti/drv/rm/util/libfdt/libfdt.h>
55 /* Tree algorithm includes */
56 #include <ti/drv/rm/util/tree.h>
58 /* RM OSAL layer */
59 #include <rm_osal.h>
61 /**********************************************************************
62  ************************ Local Functions *****************************
63  **********************************************************************/
65 /* FUNCTION PURPOSE: Creates a resource allocator
66  ***********************************************************************
67  * DESCRIPTION: Returns a newly Created and initialized resource
68  *              The allocator is also stored in the RM instance
69  *              allocator list.            
70  */
71 static Rm_Allocator *allocatorAdd(Rm_Handle rmHandle, const char *resourceName)
72 {
73     Rm_Inst      *rmInst = (Rm_Inst *)rmHandle;
74     Rm_Allocator *allocators   = rmInst->u.server.allocators;
75     Rm_Allocator *newAllocator = NULL;
77     newAllocator = Rm_osalMalloc(sizeof(*allocators));
79     if (newAllocator) {
80         memset((void *)newAllocator, 0, sizeof(*newAllocator));
81         strncpy(newAllocator->resourceName, resourceName, RM_NAME_MAX_CHARS);
82         newAllocator->allocatorRootEntry = NULL;
83         newAllocator->nextAllocator = NULL;  
85         /* Add allocator to end of list */
86         if (allocators) {
87             while (allocators->nextAllocator) {
88                 allocators = allocators->nextAllocator;
89             }
90             allocators->nextAllocator = newAllocator;
91             RM_SS_OBJ_WB(allocators, Rm_Allocator);
92         }
93         else {
94             rmInst->u.server.allocators = newAllocator;
95         }
96     }
97     return (newAllocator);
98 }
100 /* FUNCTION PURPOSE: Creates a new resource tree
101  ***********************************************************************
102  * DESCRIPTION: Creates and populates a new resource tree allocator
103  *              using the provided resource name and value range.  The
104  *              name and value originate from the GRL.
105  */
106 static int32_t allocatorCreate(Rm_Handle rmHandle, const char *resourceName, Rm_ResourceRange *range)
108     Rm_Inst         *rmInst = (Rm_Inst *)rmHandle;
109     Rm_Allocator    *allocator = NULL;
110     Rm_ResourceTree *treeRoot = NULL;
111     Rm_ResourceNode *treeNode = NULL;
113     allocator = allocatorAdd(rmHandle, resourceName);
114     treeRoot = Rm_osalMalloc(sizeof(*treeRoot));
115     RB_INIT(treeRoot);
117     while (range != NULL) {
118         treeNode = rmResourceNodeNew(range->base, range->length);
119         RB_INSERT(_Rm_AllocatorResourceTree, treeRoot, treeNode);
120         range = range->nextRange;
121     }
122     if (rmInst->instType == Rm_instType_SHARED_SERVER) {
123         rmResourceTreeWb(treeRoot);
124     }
125     
126     allocator->allocatorRootEntry = treeRoot;
127     RM_SS_OBJ_WB(allocator, Rm_Allocator);
128     return(RM_OK);
131 /* FUNCTION PURPOSE: Returns a pointer to the allocator list
132  ***********************************************************************
133  * DESCRIPTION: Returns a pointer to the instance's allocator list
134  *              based on the instance type
135  */
136 static Rm_Allocator *allocatorGetAllocatorList(Rm_Handle rmHandle)
138     Rm_Inst      *rmInst = (Rm_Inst *)rmHandle;
139     Rm_Allocator *list = NULL;
141     if ((rmInst->instType == Rm_instType_SERVER) ||
142         (rmInst->instType == Rm_instType_SHARED_SERVER)) {
143         list = rmInst->u.server.allocators;
144     }
145     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
146         list = rmInst->u.cd.allocators;
147     }
148     return(list);
151 /* FUNCTION PURPOSE: Deletes a resource allocator
152  ***********************************************************************
153  * DESCRIPTION: Deletes a resource allocator based on the given
154  *              resource name.  The resource allocator will be
155  *              removed from the RM instance allocator list.
156  */
157 static int32_t allocatorDelete(Rm_Handle rmHandle, const char *resourceName)
159     Rm_Inst         *rmInst = (Rm_Inst *)rmHandle;    
160     Rm_Allocator    *allocator = rmInst->u.server.allocators;
161     Rm_Allocator    *prevAllocator = NULL;
162     Rm_ResourceTree *treeRoot;
163     Rm_ResourceNode *node = NULL;
164     Rm_ResourceNode *nextNode = NULL;
165     int32_t          retVal = RM_OK;
167     while (allocator) {
168         if (strncmp(allocator->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
169             break;             
170         }
171         prevAllocator = allocator;
172         allocator = allocator->nextAllocator;
173     }
175     if (allocator) {
176         if (prevAllocator == NULL) {
177             rmInst->u.server.allocators = allocator->nextAllocator;
178         }
179         else {
180             prevAllocator->nextAllocator = allocator->nextAllocator;
181             RM_SS_OBJ_WB(prevAllocator, Rm_Allocator);
182         }
183             
184         /* Destroy tree and return error */
185         treeRoot = allocator->allocatorRootEntry;
186         for (node = RB_MIN(_Rm_AllocatorResourceTree, treeRoot); node != NULL; node = nextNode) {
187                 nextNode = RB_NEXT(_Rm_AllocatorResourceTree, treeRoot, node);
188                 RB_REMOVE(_Rm_AllocatorResourceTree, treeRoot, nextNode);
189             rmResourceNodeFree(node);
190         }
191         Rm_osalFree((void *)treeRoot, sizeof(*treeRoot));        
192         Rm_osalFree((void *)allocator, sizeof(*allocator));
193     }
194     else {
195         retVal = RM_ERROR_RES_ALLOCATOR_DOES_NOT_EXIST;
196     }
197     return (retVal);
200 /* FUNCTION PURPOSE: Adds an owner to an allocator resource
201  ***********************************************************************
202  * DESCRIPTION: Adds a RM instance node to a resource node's
203  *              list of owners.
204  */
205 static void allocatorResNodeOwnerAdd(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode)
207     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;    
208     Rm_Owner *ownerList = node->ownerList;
209     Rm_Owner *newOwner = NULL;
211     newOwner = Rm_osalMalloc(sizeof(*newOwner));
213     if (newOwner) {
214         newOwner->instNameNode = serviceInstNode;
215         newOwner->nextOwner = NULL;  
217         /* Add owner entry to end of list */
218         if (ownerList) {
219             RM_SS_OBJ_INV(ownerList, Rm_Owner);
220             while (ownerList->nextOwner) {
221                 ownerList = ownerList->nextOwner;
222                 RM_SS_OBJ_INV(ownerList, Rm_Owner);
223             }
224             ownerList->nextOwner = newOwner;
225             RM_SS_OBJ_WB(ownerList, Rm_Owner);
226         }
227         else {
228             node->ownerList = newOwner;
229         }
231         node->allocationCount++;
232         newOwner->instNameNode->allocRefCount++;
233         RM_SS_OBJ_WB(newOwner, Rm_Owner);
234         RM_SS_OBJ_WB(newOwner->instNameNode, Rm_PolicyValidInstNode);
235     }
238 /* FUNCTION PURPOSE: Compares two resource node's owners
239  ***********************************************************************
240  * DESCRIPTION: Returns TRUE if the owners of two resource nodes 
241  *              are equivalent.  Otherwise, returns FALSE.
242  */
243 static int allocatorResNodeOwnerCompare(Rm_Handle rmHandle, Rm_ResourceNode *node1, Rm_ResourceNode *node2)
245     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;    
246     Rm_Owner *node1Owners = node1->ownerList;
247     Rm_Owner *node2Owners = node2->ownerList;
248     int       matchedInst;
250     if (rmInst->instType == Rm_instType_SHARED_SERVER) {
251         while(node2Owners) {
252             Rm_osalBeginMemAccess((void *)node2Owners, sizeof(*node2Owners));
253             node2Owners = node2Owners->nextOwner;
254         }
255         node2Owners = node2->ownerList;
256     }
258     if (node1->allocationCount == node2->allocationCount) {
259         while (node1Owners) {
260             RM_SS_OBJ_INV(node1Owners, Rm_Owner);
261             matchedInst = RM_FALSE;
262             while (node2Owners) {
263                 if (node1Owners->instNameNode == node2Owners->instNameNode) {
264                     matchedInst = RM_TRUE;
265                     break;
266                 }
267                 node2Owners = node2Owners->nextOwner;
268             }
270             if (matchedInst) {
271                 node2Owners = node2->ownerList;
272                 node1Owners = node1Owners->nextOwner;
273             }
274             else {
275                 return(RM_FALSE);
276             }                
277         }
278     }
279     else {
280         return(RM_FALSE);
281     }  
282     
283     return(RM_TRUE);
286 /* FUNCTION PURPOSE: Deletes an owner from an allocator resource
287  ***********************************************************************
288  * DESCRIPTION: Removes a RM instance node from a resource node's
289  *              list of owners.
290  */
291 static void allocatorResNodeOwnerDelete(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode)
293     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;    
294     Rm_Owner *owner = node->ownerList;
295     Rm_Owner *prevOwner = NULL;
297     while (owner) {
298         RM_SS_OBJ_INV(owner, Rm_Owner);
299         if (owner->instNameNode == serviceInstNode) {
300             break;             
301         }
302         prevOwner = owner;
303         owner = owner->nextOwner;
304     }
306     if (prevOwner == NULL) {
307         node->ownerList = owner->nextOwner;
308     }
309     else {
310         prevOwner->nextOwner = owner->nextOwner;
311         RM_SS_OBJ_WB(prevOwner, Rm_Owner);
312     }
313     
314     node->allocationCount--;
315     owner->instNameNode->allocRefCount--;
316     RM_SS_OBJ_WB(owner->instNameNode, Rm_PolicyValidInstNode);
317     Rm_osalFree((void *)owner, sizeof(*owner));
320 /* FUNCTION PURPOSE: Copies the owners of a resource node
321  ***********************************************************************
322  * DESCRIPTION: Creates a list of resource owners for the destination
323  *              resource node that is equivalent to the source resource
324  *              node's owners
325  *
326  *              dstNode must be a newly created node without any owners.
327  */
328 static void allocatorResNodeOwnerCopy(Rm_Handle rmHandle, Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode)
330     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
331     Rm_Owner *srcOwnerList = srcNode->ownerList;
332     Rm_Owner *dstNewOwner;
333     Rm_Owner *dstPrevOwner;
335     if (dstNode->ownerList != NULL) {
336         return;
337     }
338     dstNode->allocationCount = srcNode->allocationCount;
340     while (srcOwnerList) {
341         RM_SS_OBJ_INV(srcOwnerList, Rm_Owner);
342         dstNewOwner = Rm_osalMalloc(sizeof(*dstNewOwner));
343         dstNewOwner->instNameNode = srcOwnerList->instNameNode;
344         dstNewOwner->nextOwner = NULL;
345         RM_SS_OBJ_WB(dstNewOwner, Rm_Owner);
347         if (dstNode->ownerList == NULL) {
348             dstNode->ownerList = dstNewOwner;
349         }
350         else {
351             dstPrevOwner->nextOwner = dstNewOwner;
352             RM_SS_OBJ_WB(dstPrevOwner, Rm_Owner);
353         }
354         dstPrevOwner = dstNewOwner;
355         srcOwnerList = srcOwnerList->nextOwner;
356     }
359 /* FUNCTION PURPOSE: Clears a resource node's owners
360  ***********************************************************************
361  * DESCRIPTION: Deletes all owners from the owners list of a 
362  *              resource node.
363  */
364 static void allocatorResNodeOwnerClear(Rm_Handle rmHandle, Rm_ResourceNode *node)
366     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;    
367     Rm_Owner *owner = node->ownerList;
368     Rm_Owner *nextOwner;
370     while (owner) {
371         RM_SS_OBJ_INV(owner, Rm_Owner);
372         nextOwner = owner->nextOwner;
373         node->allocationCount--;
374         owner->instNameNode->allocRefCount--;
375         RM_SS_OBJ_WB(owner->instNameNode, Rm_PolicyValidInstNode);
376         Rm_osalFree((void *)owner, sizeof(*owner));
377         owner = nextOwner;
378     }
381 /* FUNCTION PURPOSE: Checks a resource node's ownership
382  ***********************************************************************
383  * DESCRIPTION: Returns TRUE if the provided instance node is
384  *              in the list of resource node owners.  Otherwise,
385  *              returns FALSE.
386  */
387 static int allocatorResNodeIsOwnedBy(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode)
389     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
390     Rm_Owner *owner = node->ownerList;
392     while (owner) {
393         RM_SS_OBJ_INV(owner, Rm_Owner);
394         if (owner->instNameNode == serviceInstNode) {
395             return(RM_TRUE);           
396         }
397         owner = owner->nextOwner;
398     }
399     return(RM_FALSE);
402 /* FUNCTION PURPOSE: Preallocates an allocator resource
403  ***********************************************************************
404  * DESCRIPTION: Called when an allocate request is made but the base 
405  *              is unspecified.  The preallocation algorithm looks at 
406  *              available resources as well as policy permissions to 
407  *              determine a resource range that satisfies the request.
408  *              If a valid range is found it will be returned for the 
409  *              treeAllocate algorithm to handle.
410  */
411 static int32_t allocatorPreAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy, 
412                                     Rm_AllocatorOpInfo *opInfo)
413 {   
414     Rm_ResourceNode    findNode;
415     Rm_ResourceNode   *matchingNode = NULL;
416     uint32_t           matchingEnd;
417     uint32_t           rangeIndex;
418     int                resourceFound = RM_FALSE;
419     Rm_PolicyCheckType policyCheckType;
420     Rm_PolicyCheckCfg  policyCheckCfg;
421     int                nodePassesPolicy;
422     int32_t            retVal;
424     opInfo->resourceInfo->base = rmPolicyGetResourceBase(opInfo->policy, opInfo->serviceSrcInstNode, 
425                                                          resourcePolicy, opInfo->allocType, 
426                                                          &retVal);
427     if (retVal != RM_OK) {
428         return (retVal);
429     }
431     if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) {  
432         /* Get alignment from policy */
433         opInfo->resourceInfo->alignment = rmPolicyGetResourceAlignment(opInfo->policy, resourcePolicy);
434     }
435     
436     if (opInfo->resourceInfo->alignment == 0) {
437         opInfo->resourceInfo->alignment = 1;
438     }    
440     memset((void *)&findNode, 0, sizeof(findNode));
441     findNode.base = opInfo->resourceInfo->base;
442     findNode.length = opInfo->resourceInfo->length;
444     /* Configure policy checking structure */
445     memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg));
446     if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
447         policyCheckType = Rm_policyCheck_INIT;
448     }
449     else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
450         policyCheckType = Rm_policyCheck_USE;
451     }
452     policyCheckCfg.policyDtb = opInfo->policy;
453     policyCheckCfg.resourceOffset = resourcePolicy;
454     
455     do {
456         matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
457         
458         if (matchingNode) {
459             if (matchingNode->allocationCount == 0) {
460                 /* Attempt to preallocate from node only if not owned by anyone */
461                 nodePassesPolicy = RM_FALSE;
462                 policyCheckCfg.type = policyCheckType;
463                 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
464                 policyCheckCfg.resourceBase = findNode.base;
465                 policyCheckCfg.resourceLength = findNode.length;
466                 nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);    
467                 
468                 if (nodePassesPolicy && (matchingNode->allocationCount > 0)) {
469                     policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
470                     
471                     if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) {
472                         /* Check if instance requesting resource has privileges to share
473                          * a resource already reserved by Linux */
474                         policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
475                         nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
476                     }
478                     if (nodePassesPolicy) {
479                         /* Check exclusive privileges of instance requesting resource.  Requesting
480                          * instance with exclusive privileges can't reserve resource if already owned*/
481                         policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
482                         nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
483                     }
484                 }
485                 
486                 if (nodePassesPolicy && (matchingNode->allocationCount == 1)) {
487                     /* Check exclusive privileges of instance that currently owns resource */
488                     policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
489                     policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
490                     nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
491                 }
493                 if (retVal != RM_OK) {
494                     break;
495                 }
497                 if (nodePassesPolicy) {
498                     matchingEnd = matchingNode->base + matchingNode->length - 1;
499                     /* Initialize indexer to be first resource value that alignment */
500                     rangeIndex = findNode.base;
501                     if (rangeIndex % opInfo->resourceInfo->alignment) {
502                         rangeIndex += (opInfo->resourceInfo->alignment -
503                                       (rangeIndex % opInfo->resourceInfo->alignment));
504                     }
505                     
506                     if ((rangeIndex + opInfo->resourceInfo->length - 1) <= matchingEnd) {
507                         /* Block of unallocated resources within matchingNode that satisfies
508                          * allocate requirements */
509                         opInfo->resourceInfo->base = rangeIndex;
510                         resourceFound = RM_TRUE;
511                         retVal = RM_SERVICE_PROCESSING;
512                     }     
513                 }
514             }
515             
516             if (!resourceFound) {
517                 /* Check next resource node for available resources */
518                 findNode.base = matchingNode->base + matchingNode->length;
519             }
520         }
521         else {
522             retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
523         }
524     } while ((!resourceFound) && 
525              (retVal != RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET));
527     return(retVal); 
530 /* FUNCTION PURPOSE: Allocates an allocator resource
531  ***********************************************************************
532  * DESCRIPTION: Will attempt to allocate the resource with specified
533  *              base and length from the resource's allocator.  The
534  *              allocation algorithm will verify the allocation against
535  *              the policy permissions for the instance requesting the
536  *              allocation.  If the policy allows the allocation the 
537  *              algorithm will allocate the resource then combine any
538  *              resource nodes that may have become equivalent (in terms
539  *              of ownership) after the allocation.
540  */
541 static int32_t allocatorAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy, 
542                                  Rm_AllocatorOpInfo *opInfo)
544     Rm_ResourceNode     findNode;
545     Rm_ResourceNode    *matchingNode = NULL;
546     Rm_ResourceNode    *leftNode = NULL;
547     Rm_ResourceNode    *rightNode = NULL;
548     Rm_PolicyCheckType  policyCheckType;    
549     Rm_PolicyCheckCfg   policyCheckCfg;
550     int                 allocPassesPolicy;
551     int                 combineLeft = RM_FALSE;
552     int                 combineRight = RM_FALSE;    
553     uint32_t            findEnd;
554     uint32_t            matchingEnd;  
555     int32_t             retVal;
557     memset((void *)&findNode, 0, sizeof(findNode));
558     findNode.base = opInfo->resourceInfo->base;
559     findNode.length = opInfo->resourceInfo->length;
560     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
562     /* Prepare privilege checks */
563     memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg));
564     if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
565         policyCheckType = Rm_policyCheck_INIT;
566     }
567     else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
568         policyCheckType = Rm_policyCheck_USE;
569     }
571     if (matchingNode) {
572         findEnd = findNode.base + findNode.length - 1;
573         matchingEnd = matchingNode->base + matchingNode->length - 1;
574         
575         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
576             if (opInfo->serviceSrcInstNode == rmPolicyGetLinuxInstNode(rmHandle)) {
577                 /* Bypass policy checks since Linux Kernel has full privileges */
578                 allocPassesPolicy = RM_TRUE;
579             }
580             else {
581                 policyCheckCfg.policyDtb = opInfo->policy;
582                 policyCheckCfg.resourceOffset = resourcePolicy;    
583                 policyCheckCfg.type = policyCheckType;
584                 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
585                 policyCheckCfg.resourceBase = findNode.base;
586                 policyCheckCfg.resourceLength = findNode.length;
587                 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
588                 if (!allocPassesPolicy) {
589                     if (policyCheckType == Rm_policyCheck_INIT) {
590                         retVal = RM_SERVICE_DENIED_INIT_PERM_NOT_GIVEN;
591                     }
592                     else {
593                         retVal = RM_SERVICE_DENIED_USE_PERM_NOT_GIVEN;
594                     }
595                 }
597                 if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
598                     if (allocPassesPolicy && (matchingNode->allocationCount > 0)) {
599                         if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) {
600                             /* Check if instance requesting resource has privileges to share
601                              * a resource already reserved by Linux */
602                             policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
603                             policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
604                             allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
605                             if (!allocPassesPolicy) {
606                                 retVal = RM_SERVICE_DENIED_RES_NOT_SHARED_LINUX;
607                             }
608                         }
609                         if (allocPassesPolicy) {
610                             /* Check exclusive privileges of instance requesting resource.  Requesting
611                              * instance with exclusive privileges can't reserve resource if already owned*/
612                             policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
613                             policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
614                             allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
615                             if (!allocPassesPolicy) {
616                                 retVal = RM_SERVICE_DENIED_EXCLUSIVE_RES_ALLOCD;
617                             }
618                         }
619                     }
620                     if (allocPassesPolicy && (matchingNode->allocationCount == 1)) {
621                         /* Check exclusive privileges of instance that currently owns resource */
622                         policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
623                         policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
624                         allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
625                         if (!allocPassesPolicy) {
626                             retVal = RM_SERVICE_DENIED_ALLOCD_TO_EXCLUSIVE_INST;
627                         }                
628                     }  
629                 }
630             }
631             
632             if (allocPassesPolicy) {
633                 if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
634                     /* Handle any possible node combinations if requesting instance is
635                      * not already in resource's owner list.  Automatic approval if requesting
636                      * instance is already in owner list. */
637                     if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {
638                         /* findNode range matches matchingNode range
639                          *
640                          *   |<--left node-->||<--matched  node-->||<--right node-->| => existing node
641                          *                    |<--alloc request-->|  => requested resources
642                          */                     
643                         leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
644                         rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
645                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
646                         allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
648                         if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
649                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
650                             combineLeft = RM_TRUE;
651                         }
652                         if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
653                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
654                             combineRight = RM_TRUE;
655                         }
657                         if (combineLeft && combineRight) {
658                             /* Combine all three nodes into matchingNode */
659                             matchingNode->base = leftNode->base;
660                             matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
662                             allocatorResNodeOwnerClear(rmHandle, leftNode);
663                             rmResourceNodeFree(leftNode);
664                             allocatorResNodeOwnerClear(rmHandle, rightNode);
665                             rmResourceNodeFree(rightNode);                        
666                         }
667                         else if (combineLeft) {
668                             /* Combine left and matching nodes.  Reinsert right. */
669                             matchingNode->base = leftNode->base;
670                             matchingNode->length += leftNode->length;
672                             allocatorResNodeOwnerClear(rmHandle, leftNode);
673                             rmResourceNodeFree(leftNode);
674                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);                        
675                         }
676                         else if (combineRight) {
677                             /* Combine right and matching nodes.  Reinsert left. */
678                             matchingNode->length += rightNode->length;
680                             allocatorResNodeOwnerClear(rmHandle, rightNode);
681                             rmResourceNodeFree(rightNode);
682                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
683                         }
684                         else {
685                             /* No combine. */
686                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
687                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
688                         }
690                         /* Always reinsert matchingNode */                
691                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
692                         
693                         /* Matching node contains new reference count after alloc.  Return new owner count. */
694                         opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
695                     }   
696                     else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
697                         /* findNode range is subset of matchingNode range and neither boundary is
698                          * equivalent.
699                          *
700                          * |<----------matched node---------->|
701                          *        |<---alloc request--->|
702                          */ 
703                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
704                         leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
705                         allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
706                         rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
707                         allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
709                         matchingNode->base = findNode.base;                                    
710                         matchingNode->length = findNode.length;
711                         allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
713                         /* Insert all the nodes */
714                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
715                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
716                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
717                         
718                         /* Matching node contains new reference count after alloc.  Return new owner count. */
719                         opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
720                     }  
721                     else {    
722                         if (findNode.base == matchingNode->base) {
723                             /* findNode base and matchingNode base are equivalent.  May be combine
724                              * possibilities to the left
725                              *
726                              * |<---left node (alloc'd)--->||<----------matched node---------->|
727                              *                              |<---findNode (alloc req)--->|
728                              */                         
729                             leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
730                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
731                             /* Add allocating instance to owner list for compare with leftNode */
732                             allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
733                             
734                             if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
735                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
736                                 /* Combine leftNode and findNode */
737                                 leftNode->length += findNode.length;
738                             }
739                             else {
740                                 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
741                                 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
742                             }
744                             /* Account for leftNode in matchingNode */
745                             matchingNode->base = findNode.base + findNode.length;
746                             matchingNode->length = matchingEnd - findEnd;  
748                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
749                             /* Left node contains new reference count after alloc.  Return new owner count. */
750                             opInfo->resourceInfo->ownerCount = leftNode->allocationCount;
751                         }
752                         else if (findEnd == matchingEnd) {
753                             /* findNode end and matchingNode end are equivalent.  May be combine
754                              * possibilities to the right
755                              *
756                              * |<----------matched node---------->||<---right node (alloc'd)--->|
757                              *       |<---findNode (alloc req)--->| 
758                              */                        
759                             rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
760                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
761                             /* Add allocating instance to owner list for compare with rightNode */
762                             allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
763                             
764                             if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
765                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
766                                 /* Combine rightNode and findNode */
767                                 rightNode->base = findNode.base;
768                                 rightNode->length += findNode.length;
769                             }
770                             else {
771                                 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
772                                 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
773                             }
775                             /* Account for rightNode in matchingNode */
776                             matchingNode->length -= findNode.length;  
778                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
779                             /* Right node contains new reference count after alloc.  Return new owner count. */
780                             opInfo->resourceInfo->ownerCount = rightNode->allocationCount;
781                         }
782                         /* Remove allocating instance from leftover matchingNode */
783                         allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
784                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
785                     }
786                 }
787                 retVal = RM_SERVICE_APPROVED;
788             }
789         }
790         else {
791             retVal = RM_SERVICE_DENIED_PARTIAL_ALLOCATION;
792         }
793     }
794     else {
795         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
796     }
798     return(retVal);        
801 /* FUNCTION PURPOSE: Frees an allocator resource
802  ***********************************************************************
803  * DESCRIPTION: Will attempt to free the resource with specified
804  *              base and length from the resource's allocator.  The
805  *              free algorithm will verify the free request parameters
806  *              match an allocated range for the resource and that the
807  *              range is owned by the instance requesting the free. If
808  *              the free is validated the algorithm will free the 
809  *              resource then combine any resource nodes that may have
810  *              become equivalent (in terms of ownership) after the
811  *              allocation.
812  */
813 static int32_t allocatorFree(Rm_Handle rmHandle, Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)
815     Rm_ResourceNode  findNode;
816     Rm_ResourceNode *matchingNode = NULL;
817     Rm_ResourceNode *leftNode = NULL;
818     Rm_ResourceNode *rightNode = NULL;
819     int              combineLeft = RM_FALSE;
820     int              combineRight = RM_FALSE;
821     uint32_t         findEnd;
822     uint32_t         matchingEnd;
823     int32_t          retVal;
825     memset((void *)&findNode, 0, sizeof(findNode));
826     findNode.base = opInfo->resourceInfo->base;
827     findNode.length = opInfo->resourceInfo->length;
828     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
830     if (matchingNode) {
831         findEnd = findNode.base + findNode.length - 1;
832         matchingEnd = matchingNode->base + matchingNode->length - 1;
833         
834         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {  
835             if (matchingNode->allocationCount) {
836                 if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
837                     if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))
838                     {
839                         /* Case 1: Free range equals allocated matched node exactly. Attempt to combine 
840                          *         freed node with nodes to left and right.
841                          *
842                          * |<--left node-->||<---matched node--->||<--right node-->|
843                          *                  |<---free request--->|
844                          */ 
845                         leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
846                         rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
847                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
848                         allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
850                         if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
851                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
852                             combineLeft = RM_TRUE;
853                         }
854                         if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
855                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
856                             combineRight = RM_TRUE;
857                         }
859                         if (combineLeft && combineRight) {
860                             /* Combine all three nodes into matchingNode */
861                             matchingNode->base = leftNode->base;
862                             matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
864                             allocatorResNodeOwnerClear(rmHandle, leftNode);
865                             rmResourceNodeFree(leftNode);
866                             allocatorResNodeOwnerClear(rmHandle, rightNode);
867                             rmResourceNodeFree(rightNode);                        
868                         }
869                         else if (combineLeft) {
870                             /* Combine left and matching nodes.  Reinsert right. */
871                             matchingNode->base = leftNode->base;
872                             matchingNode->length += leftNode->length;
874                             allocatorResNodeOwnerClear(rmHandle, leftNode);
875                             rmResourceNodeFree(leftNode);
876                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);                        
877                         }
878                         else if (combineRight) {
879                             /* Combine right and matching nodes.  Reinsert left. */
880                             matchingNode->length += rightNode->length;
882                             allocatorResNodeOwnerClear(rmHandle, rightNode);
883                             rmResourceNodeFree(rightNode);
884                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
885                         }
886                         else {
887                             /* No combine. */
888                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
889                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
890                         }
892                         /* Always reinsert matchingNode */
893                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
894                         
895                         /* Matching node is what remains after free.  Return remaining owner count. */
896                         opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
897                     }
898                     else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
899                         /* Case 2: Free range is less than range in matched node. Split
900                          *         matched node into three nodes.
901                          *
902                          * |<----------matched node---------->|
903                          *        |<---free request--->|
904                          *
905                          * Remove instance from AllocatedTo list then add it back in for side nodes for
906                          * proper accounting of allocations in validInstance list
907                          */ 
908                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
909                         allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
910                         
911                         leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
912                         allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
913                         allocatorResNodeOwnerAdd(rmHandle, leftNode, opInfo->serviceSrcInstNode);
914                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
915                         
916                         rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
917                         allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
918                         allocatorResNodeOwnerAdd(rmHandle, rightNode, opInfo->serviceSrcInstNode);
919                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
921                         matchingNode->base = findNode.base;                                    
922                         matchingNode->length = findNode.length;
923                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
924                         
925                         /* Matching node is what remains after free.  Return remaining owner count. */
926                         opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
927                     }
928                     else {                        
929                         if (findNode.base == matchingNode->base) {
930                             /* Case 3: Free range is on left boundary of matched node. Try to 
931                              *         combine free range with left node.
932                              *
933                              * |<---left node (free)--->||<----------matched node---------->|
934                              *                           |<---findNode (free req)--->|
935                              */ 
937                             leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
938                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
939                             /* Remove freeing instance from owner list for compare with leftNode */
940                             allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
941                             
942                             if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
943                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
944                                 /* Combine leftNode and findNode */
945                                 leftNode->length += findNode.length;
946                             }
947                             else {
948                                 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
949                                 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
950                             }
952                             /* Remove leftNode range from matchingNode */
953                             matchingNode->base = findNode.base + findNode.length;
954                             matchingNode->length = matchingEnd - findEnd;  
955                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
956                             
957                             /* Left node is what remains after free.  Return remaining owner count. */
958                             opInfo->resourceInfo->ownerCount = leftNode->allocationCount;
959                         }
960                         else if (findEnd == matchingEnd) {
961                             /* Case 4: Free range is on right boundary of matched node. Try to 
962                              *         combine free range with right node.
963                              *
964                              * |<----------matched node---------->||<---right node (free)--->|
965                              *        |<---findNode (free req)--->|
966                              */ 
967                             
968                             rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
969                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); 
970                             /* Remove freeing instance from owner list for compare with rightNode */
971                             allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
972                             
973                             if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
974                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
975                                 /* Combine rightNode and findNode */
976                                 rightNode->base = findNode.base;
977                                 rightNode->length += findNode.length;
978                             }
979                             else {
980                                 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
981                                 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
982                             }
984                             /* Remove rightNode range from matchingNode */
985                             matchingNode->length -= findNode.length;  
986                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
987                             
988                             /* Right node is what remains after free.  Return remaining owner count. */
989                             opInfo->resourceInfo->ownerCount = rightNode->allocationCount;
990                         }
992                         /* Add freeing instance back into matchingNode allocations */
993                         allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
994                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
995                     }
996                     retVal = RM_SERVICE_APPROVED;
997                 }
998                 else {
999                     /* Return owner count.  In case it's a reference count check in application */
1000                     opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1001                     retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST;
1002                 }
1003             }
1004             else {
1005                 /* Return owner count.  In case it's a reference count check in application */
1006                 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1007                 retVal = RM_SERVICE_DENIED_RES_ALREADY_FREE;
1008             }
1009         }
1010         else {
1011             retVal = RM_SERVICE_DENIED_PARTIAL_FREE;
1012         }
1013     }
1014     else {
1015         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
1016     }
1017     return(retVal);  
1020 /* FUNCTION PURPOSE: Reserves a Linux resource
1021  ***********************************************************************
1022  * DESCRIPTION: Reserves resources for Linux using the base and length
1023  *              values retrieved from the Linux DTB via the
1024  *              "linux-dtb-alias" properties within the GRL.
1025  */
1026 static int32_t allocatorReserveLinuxResource(Rm_Handle rmHandle, Rm_LinuxAlias *linuxAlias, 
1027                                              Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)
1029     int32_t   retVal = RM_OK;
1030     int       baseFound = RM_FALSE;
1031     int       lengthFound = RM_FALSE;
1032     uint32_t  valueIndex = 0;
1034     while ((linuxValues) && (!baseFound || !lengthFound)) {
1035         if (linuxAlias->baseOffset == valueIndex) {
1036             opInfo->resourceInfo->base = linuxValues->value;
1037             baseFound = RM_TRUE;
1039             if (linuxAlias->lengthOffset == RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) {
1040                 opInfo->resourceInfo->length = 1;
1041                 lengthFound = RM_TRUE;
1042             }
1043         }
1044         else if (linuxAlias->lengthOffset == valueIndex) {
1045             opInfo->resourceInfo->length = linuxValues->value;
1046             lengthFound = RM_TRUE;
1047         }
1049         linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;
1050         valueIndex++;
1051     }
1053     if (!baseFound || !lengthFound) {
1054         retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1055     }
1056     else {
1057         /* Allocate resource to Linux */
1058         retVal = rmAllocatorOperation(rmHandle, opInfo);
1059         if (retVal == RM_SERVICE_APPROVED) {
1060             retVal = RM_OK;
1061         }
1062     }
1063     return (retVal);
1066 /* FUNCTION PURPOSE: Finds and reserves Linux resources
1067  ***********************************************************************
1068  * DESCRIPTION: Parses the Linux DTB for resources consumed by the
1069  *              Linux kernel.  If the resource is found via the
1070  *              "linux-dtb-alias" property defined in the GRL it is 
1071  *              reserved.
1072  */
1073 static int32_t allocatorFindLinuxResource(Rm_Handle rmHandle, const char *resourceName, void *linuxDtb, 
1074                                           Rm_LinuxAlias *linuxAlias)
1076     Rm_Inst            *rmInst = (Rm_Inst *)rmHandle;
1077     Rm_AllocatorOpInfo  opInfo;
1078     Rm_ResourceInfo     resourceInfo;
1079     uint32_t            pathOffset;
1080     uint32_t            pathSize;
1081     char               *spacePtr;
1082     int32_t             propOffset;
1083     int32_t             nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1084     int32_t             prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1085     int32_t             depth;
1086     int32_t             propertyLen;
1087     const char         *propertyName;
1088     const void         *propertyData; 
1089     Rm_LinuxValueRange *linuxValueRange;
1090     int32_t             retVal = RM_OK; 
1092     memset((void *)&opInfo, 0, sizeof(opInfo));
1093     memset((void *)&resourceInfo, 0, sizeof(resourceInfo));
1095     strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS);
1096     opInfo.policy = rmInst->u.server.globalPolicy;
1097     opInfo.serviceSrcInstNode = rmPolicyGetLinuxInstNode(rmHandle);
1098     opInfo.operation = Rm_allocatorOp_ALLOCATE;
1099     opInfo.resourceInfo = &resourceInfo;    
1101     while(linuxAlias) {
1102         /* Reset parsing variables */
1103         pathOffset = 0;
1104         pathSize = strlen(linuxAlias->path) + 1;
1105         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1106         prevDepth = RM_DTB_UTIL_STARTING_DEPTH;   
1107         resourceInfo.base = 0;
1108         resourceInfo.length = 0;
1110         spacePtr = strpbrk(linuxAlias->path, " ");
1111         if (spacePtr) {
1112             *spacePtr = '\0';
1113         }       
1114         
1115         while(pathOffset < pathSize) {
1116             /* Move through DTB nodes until next alias path node found */
1117             if (strcmp(linuxAlias->path + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL))) {
1118                 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);
1120                 if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) {
1121                     /* Returning from subnode that matched part of alias path without finding
1122                      * resource values */
1123                     retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1124                     break;
1125                 }
1126             }
1127             else {
1128                 /* Found next alias path node.  Move to next node name in path string. */
1129                 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1130                 spacePtr = strpbrk(linuxAlias->path + pathOffset, " ");
1131                 if (spacePtr) {
1132                     *spacePtr = '\0';
1133                 }       
1134                 
1135                 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);
1136                 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);
1137                 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1138                        (pathOffset < pathSize)) {
1139                     propertyData = fdt_getprop_by_offset(linuxDtb, propOffset, 
1140                                                          &propertyName, &propertyLen);
1142                     if (strcmp(linuxAlias->path + pathOffset, propertyName) == 0) {
1143                         /* Found resource at end of alias path */
1144                         pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1145                         linuxValueRange = rmDtbUtilLinuxExtractValues(propertyData, propertyLen);
1146                         retVal = allocatorReserveLinuxResource(rmHandle, linuxAlias, 
1147                                                                linuxValueRange, &opInfo);
1148                         rmDtbUtilLinuxFreeValues(linuxValueRange);
1149                     }
1150                     propOffset = fdt_next_property_offset(linuxDtb, propOffset);
1151                 } 
1153                 if (propOffset < -FDT_ERR_NOTFOUND) {
1154                     retVal = propOffset;
1155                     break;
1156                 }
1157             }
1158         }
1160         if (retVal < RM_OK) {
1161             break;
1162         }
1163         linuxAlias = linuxAlias->nextLinuxAlias;
1164     }
1165     return (retVal);
1168 /* FUNCTION PURPOSE: Creates and initializes a resource allocator
1169  ***********************************************************************
1170  * DESCRIPTION: Creates a resource allocator for the provided
1171  *              resource name and resource properties retrieved
1172  *              from the GRL.  Resources will be reserved for 
1173  *              the Linux kernel if the Linux DTB is provided
1174  *              and there are "linux-dtb-alias" properties
1175  *              specified in the GRL.
1176  */
1177 static int32_t allocatorExtractGrlResProps(Rm_Handle rmHandle, const char *resourceName, 
1178                                            Rm_ResourceProperties *resourceProperties, void *linuxDtb)
1180     Rm_Inst             *rmInst = (Rm_Inst *)rmHandle;
1181     Rm_ResourceRange    *range = NULL;
1182     Rm_ResourceRange    *rangeBasePtr = NULL;
1183     Rm_NsAssignment     *nsAssignments = NULL;
1184     Rm_NsAssignment     *nsAssignmentBasePtr = NULL;
1185     Rm_LinuxAlias       *linuxAlias = NULL;
1186     Rm_NameServerObjCfg  nameServerObjCfg;      
1187     int32_t              retVal = RM_OK;
1189     if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0)) {
1190         range = rangeBasePtr = rmDtbUtilResExtractRange(resourceProperties->rangeData, 
1191                                                         resourceProperties->rangeLen);
1192         
1193         if ((retVal = allocatorCreate(rmHandle, resourceName, range)) >= RM_OK) {
1194             if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen) {
1195                 if (linuxDtb) {
1196                     linuxAlias = rmDtbUtilResExtractLinuxAlias(resourceProperties->linuxAliasData,
1197                                                                resourceProperties->linuxAliasLen, &retVal);
1198                     if (linuxAlias) {
1199                         retVal = allocatorFindLinuxResource(rmHandle, resourceName, linuxDtb, linuxAlias);            
1200                     }
1201                 }
1202             }
1203         }
1204     }
1205     
1206     if (retVal >= RM_OK) {
1207         if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) {
1208             nsAssignments = rmDtbUtilResExtractNsAssignment(resourceProperties->nsAssignData, 
1209                                                             resourceProperties->nsAssignLen, &retVal);
1210             if (nsAssignments) {
1211                 nsAssignmentBasePtr = nsAssignments;
1212                 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1213                     rmNameServerTreeInv(rmInst->u.server.nameServer);
1214                 }                  
1215                 while (nsAssignments) {
1216                     memset((void *)&nameServerObjCfg, 0, sizeof(nameServerObjCfg));
1217                     nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer;
1218                     nameServerObjCfg.nodeCfg.objName = nsAssignments->nsName;
1219                     nameServerObjCfg.nodeCfg.resourceName = (char *)resourceName;
1220                     nameServerObjCfg.nodeCfg.resourceBase= nsAssignments->resourceBase;
1221                     nameServerObjCfg.nodeCfg.resourceLength = nsAssignments->resourceLength;                
1222                     rmNameServerAddObject(&nameServerObjCfg);
1223                     nsAssignments = nsAssignments->nextNsAssignment;
1224                 }
1225                 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1226                     rmNameServerTreeWb(rmInst->u.server.nameServer);
1227                 }                
1228                 rmDtbUtilResFreeNsAssignmentList(nsAssignmentBasePtr);
1229             }
1230         }
1231     }
1232     else {
1233         allocatorDelete(rmHandle, resourceName);
1234     }
1236     rmDtbUtilResFreeRange(rangeBasePtr);
1237     if (linuxAlias) {
1238         rmDtbUtilResFreeLinuxAlias(linuxAlias);
1239     }
1240     return(retVal);
1243 /**********************************************************************
1244  ********************** Internal Functions ****************************
1245  **********************************************************************/
1247 /* FUNCTION PURPOSE: Finds an allocator
1248  ***********************************************************************
1249  * DESCRIPTION: Returns a pointer to an allocator that matches the 
1250  *              provided resource name.
1251  */
1252 Rm_Allocator *rmAllocatorFind(Rm_Handle rmHandle, const char *resourceName)
1254     Rm_Inst      *rmInst = (Rm_Inst *)rmHandle;
1255     Rm_Allocator *allocatorList = rmInst->u.server.allocators;
1256     
1257     while (allocatorList) {
1258         RM_SS_OBJ_INV(allocatorList, Rm_Allocator);
1259         if (strncmp(allocatorList->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
1260             break;             
1261         }
1262         allocatorList = allocatorList->nextAllocator;
1263     }
1265     return (allocatorList);
1268 /* FUNCTION PURPOSE: Issues an allocator operation
1269  ***********************************************************************
1270  * DESCRIPTION: Issues an allocator preallocate, allocate, or free
1271  *              for an RM resource.
1272  */
1273 int32_t rmAllocatorOperation(Rm_Handle rmHandle, Rm_AllocatorOpInfo *opInfo)
1275     Rm_Inst      *rmInst = (Rm_Inst *)rmHandle;
1276     Rm_Allocator *allocator = NULL;
1277     int32_t       resourceOffsetInPolicy;
1278     int32_t       retVal;
1279     
1280     resourceOffsetInPolicy = rmPolicyGetResourceOffset(opInfo->policy, opInfo->resourceInfo->name);
1281     allocator = rmAllocatorFind(rmHandle, opInfo->resourceInfo->name);
1282     
1283     if ((resourceOffsetInPolicy > 0) && allocator) {
1284         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1285             rmResourceTreeInv(allocator->allocatorRootEntry);
1286         }
1287         
1288         if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE) {
1289             retVal = allocatorPreAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo);
1290         }               
1291         else if (opInfo->operation == Rm_allocatorOp_ALLOCATE) {
1292             retVal = allocatorAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo);
1293         }
1294         else if (opInfo->operation == Rm_allocatorOp_FREE) {
1295             retVal = allocatorFree(rmHandle, allocator, opInfo);
1296         } 
1298         if ((rmInst->instType == Rm_instType_SHARED_SERVER) &&
1299             (retVal == RM_SERVICE_APPROVED)) {
1300             rmResourceTreeWb(allocator->allocatorRootEntry);
1301         }        
1302     }
1303     else {
1304         /* Resource could not be found in policy and/or allocator */
1305         retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
1306     }
1307     return(retVal);
1310 /* FUNCTION PURPOSE: Initializes server allocators
1311  ***********************************************************************
1312  * DESCRIPTION: Creates and initializes a server instance's
1313  *              resource allocators using the GRL and, if
1314  *              provided, Linux DTB.
1315  */
1316 int32_t rmAllocatorInitializeResources(Rm_Handle rmHandle, void *globalResourceDtb, void *linuxDtb)
1318     int32_t                nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1319     int32_t                nodeDepth = RM_DTB_UTIL_STARTING_DEPTH;
1320     Rm_ResourceProperties  resProperties;    
1321     int32_t                propOffset;
1322     int32_t                propertyLen;
1323     const char            *propertyName;
1324     const void            *propertyData;
1325     Rm_ResourcePropType    propertyType;  
1326     int32_t                retVal = RM_OK;
1328     /* Parse the Global Resource List, creating an allocator for each specified resource node */
1329     while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (nodeDepth >= RM_DTB_UTIL_STARTING_DEPTH)) {
1330         memset((void *)&resProperties, 0, sizeof(resProperties));
1331         /* Get properties of resource node */
1332         propOffset = fdt_first_property_offset(globalResourceDtb, nodeOffset);
1333         while (propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1334             propertyData = fdt_getprop_by_offset(globalResourceDtb, propOffset, &propertyName, &propertyLen);
1335             propertyType = rmDtbUtilResGetPropertyType(propertyName);
1336             if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) {
1337                 resProperties.rangeData = propertyData;
1338                 resProperties.rangeLen = propertyLen;
1339             }
1340             else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) {
1341                 resProperties.nsAssignData = propertyData;
1342                 resProperties.nsAssignLen = propertyLen;
1343             }
1344             else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS) {
1345                 resProperties.linuxAliasData = propertyData;
1346                 resProperties.linuxAliasLen = propertyLen;
1347             }        
1348             else {
1349                 retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY;
1350                 goto exitAllocInit;
1351             }
1353             propOffset = fdt_next_property_offset(globalResourceDtb, propOffset);
1354             if (propOffset == -FDT_ERR_NOTFOUND) {
1355                 /* No more resource properties but at least one found.  Extract the property values */
1356                 retVal = allocatorExtractGrlResProps(rmHandle, fdt_get_name(globalResourceDtb, nodeOffset, NULL), 
1357                                                      &resProperties, linuxDtb);
1358                 if (retVal < RM_OK) {
1359                     goto exitAllocInit;
1360                 }
1361             }
1362             else if (propOffset < -FDT_ERR_NOTFOUND) {
1363                 /* Error returned by LIBFDT */
1364                 retVal = propOffset;
1365                 goto exitAllocInit;
1366             }
1367         }
1368         if (propOffset < -FDT_ERR_NOTFOUND) {
1369             /* Error returned by LIBFDT */
1370             retVal = propOffset;
1371             goto exitAllocInit;
1372         }
1374         nodeOffset = fdt_next_node(globalResourceDtb, nodeOffset, &nodeDepth);
1375         if (nodeOffset < -FDT_ERR_NOTFOUND) {
1376             /* Error returned by LIBFDT */
1377             retVal = nodeOffset;
1378             goto exitAllocInit;
1379         }
1380     }
1381 exitAllocInit:    
1382     return(retVal);
1385 /* FUNCTION PURPOSE: Deletes server allocators
1386  ***********************************************************************
1387  * DESCRIPTION: Removes all resource nodes for each
1388  *              resource allocator and then deletes the allocator
1389  *              itself.  Used to free all memory consumed
1390  *              by the allocators.
1391  */
1392 void rmAllocatorDeleteResources(Rm_Handle rmHandle)
1394     Rm_Inst         *rmInst = (Rm_Inst *)rmHandle;
1395     Rm_Allocator    *allocatorList = allocatorGetAllocatorList(rmHandle);
1396     Rm_Allocator    *nextAllocator;
1397     Rm_ResourceTree *resTree;
1398     Rm_ResourceNode *resNode;
1399     Rm_ResourceNode *nextResNode;
1401     while (allocatorList) {
1402         RM_SS_OBJ_INV(allocatorList, Rm_Allocator);
1403         nextAllocator = allocatorList->nextAllocator;
1404         resTree = allocatorList->allocatorRootEntry;
1406         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1407             rmResourceTreeInv(resTree);
1408         }
1409         /* Delete each resource node in the allocator */
1410         for (resNode = RB_MIN(_Rm_AllocatorResourceTree, resTree); resNode != NULL; resNode = nextResNode) {
1411             nextResNode = RB_NEXT(_Rm_AllocatorResourceTree, resTree, resNode);
1412             RB_REMOVE(_Rm_AllocatorResourceTree, resTree, resNode);
1413             if (resNode->allocationCount) {
1414                 /* Delete all the owners in the resource's owner list */
1415                 allocatorResNodeOwnerClear(rmHandle, resNode);
1416             }
1417             rmResourceNodeFree(resNode);
1418         }        
1420         Rm_osalFree((void *)resTree, sizeof(*resTree));
1421         Rm_osalFree((void *)allocatorList, sizeof(*allocatorList));
1422         allocatorList = nextAllocator;
1423     }