Coverity fixes
[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 (owner) {
307         if (prevOwner == NULL) {
308             node->ownerList = owner->nextOwner;
309         }
310         else {
311             prevOwner->nextOwner = owner->nextOwner;
312             RM_SS_OBJ_WB(prevOwner, Rm_Owner);
313         }
314         
315         node->allocationCount--;
316         owner->instNameNode->allocRefCount--;
317         RM_SS_OBJ_WB(owner->instNameNode, Rm_PolicyValidInstNode);
318         Rm_osalFree((void *)owner, sizeof(*owner));
319     }
322 /* FUNCTION PURPOSE: Copies the owners of a resource node
323  ***********************************************************************
324  * DESCRIPTION: Creates a list of resource owners for the destination
325  *              resource node that is equivalent to the source resource
326  *              node's owners
327  *
328  *              dstNode must be a newly created node without any owners.
329  */
330 static void allocatorResNodeOwnerCopy(Rm_Handle rmHandle, Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode)
332     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
333     Rm_Owner *srcOwnerList = srcNode->ownerList;
334     Rm_Owner *dstNewOwner;
335     Rm_Owner *dstPrevOwner;
337     if (dstNode->ownerList != NULL) {
338         return;
339     }
340     dstNode->allocationCount = srcNode->allocationCount;
342     while (srcOwnerList) {
343         RM_SS_OBJ_INV(srcOwnerList, Rm_Owner);
344         dstNewOwner = Rm_osalMalloc(sizeof(*dstNewOwner));
345         dstNewOwner->instNameNode = srcOwnerList->instNameNode;
346         dstNewOwner->nextOwner = NULL;
347         RM_SS_OBJ_WB(dstNewOwner, Rm_Owner);
349         if (dstNode->ownerList == NULL) {
350             dstNode->ownerList = dstNewOwner;
351         }
352         else {
353             dstPrevOwner->nextOwner = dstNewOwner;
354             RM_SS_OBJ_WB(dstPrevOwner, Rm_Owner);
355         }
356         dstPrevOwner = dstNewOwner;
357         srcOwnerList = srcOwnerList->nextOwner;
358     }
361 /* FUNCTION PURPOSE: Clears a resource node's owners
362  ***********************************************************************
363  * DESCRIPTION: Deletes all owners from the owners list of a 
364  *              resource node.
365  */
366 static void allocatorResNodeOwnerClear(Rm_Handle rmHandle, Rm_ResourceNode *node)
368     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;    
369     Rm_Owner *owner = node->ownerList;
370     Rm_Owner *nextOwner;
372     while (owner) {
373         RM_SS_OBJ_INV(owner, Rm_Owner);
374         nextOwner = owner->nextOwner;
375         node->allocationCount--;
376         owner->instNameNode->allocRefCount--;
377         RM_SS_OBJ_WB(owner->instNameNode, Rm_PolicyValidInstNode);
378         Rm_osalFree((void *)owner, sizeof(*owner));
379         owner = nextOwner;
380     }
383 /* FUNCTION PURPOSE: Checks a resource node's ownership
384  ***********************************************************************
385  * DESCRIPTION: Returns TRUE if the provided instance node is
386  *              in the list of resource node owners.  Otherwise,
387  *              returns FALSE.
388  */
389 static int allocatorResNodeIsOwnedBy(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode)
391     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
392     Rm_Owner *owner = node->ownerList;
394     while (owner) {
395         RM_SS_OBJ_INV(owner, Rm_Owner);
396         if (owner->instNameNode == serviceInstNode) {
397             return(RM_TRUE);           
398         }
399         owner = owner->nextOwner;
400     }
401     return(RM_FALSE);
404 /* FUNCTION PURPOSE: Preallocates an allocator resource
405  ***********************************************************************
406  * DESCRIPTION: Called when an allocate request is made but the base 
407  *              is unspecified.  The preallocation algorithm looks at 
408  *              available resources as well as policy permissions to 
409  *              determine a resource range that satisfies the request.
410  *              If a valid range is found it will be returned for the 
411  *              treeAllocate algorithm to handle.
412  */
413 static int32_t allocatorPreAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy, 
414                                     Rm_AllocatorOpInfo *opInfo)
415 {   
416     Rm_ResourceNode    findNode;
417     Rm_ResourceNode   *matchingNode = NULL;
418     uint32_t           matchingEnd;
419     uint32_t           rangeIndex;
420     int                resourceFound = RM_FALSE;
421     Rm_PolicyCheckType policyCheckType;
422     Rm_PolicyCheckCfg  policyCheckCfg;
423     int                nodePassesPolicy;
424     int32_t            retVal;
426     if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_INIT) {
427         policyCheckType = Rm_policyCheck_INIT;
428     }
429     else if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_USE) {
430         policyCheckType = Rm_policyCheck_USE;
431     }
432     else {
433         retVal = RM_ERROR_INVALID_SERVICE_TYPE;
434         return (retVal);
435     }
436     
437     opInfo->resourceInfo->base = rmPolicyGetResourceBase(opInfo->policy, opInfo->serviceSrcInstNode, 
438                                                          resourcePolicy, policyCheckType, 
439                                                          &retVal);
440     if (retVal != RM_OK) {
441         return (retVal);
442     }
444     if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) {  
445         /* Get alignment from policy */
446         opInfo->resourceInfo->alignment = rmPolicyGetResourceAlignment(opInfo->policy, resourcePolicy);
447     }
448     
449     if (opInfo->resourceInfo->alignment == 0) {
450         opInfo->resourceInfo->alignment = 1;
451     }    
453     memset((void *)&findNode, 0, sizeof(findNode));
454     findNode.base = opInfo->resourceInfo->base;
455     findNode.length = opInfo->resourceInfo->length;
457     /* Configure policy checking structure */
458     memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg));
459     policyCheckCfg.policyDtb = opInfo->policy;
460     policyCheckCfg.resourceOffset = resourcePolicy;
461     
462     do {
463         matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
464         
465         if (matchingNode) {
466             if (matchingNode->allocationCount == 0) {
467                 /* Attempt to preallocate from node only if not owned by anyone */
468                 nodePassesPolicy = RM_FALSE;
469                 policyCheckCfg.type = policyCheckType;
470                 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
471                 policyCheckCfg.resourceBase = findNode.base;
472                 policyCheckCfg.resourceLength = findNode.length;
473                 nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);    
474                 
475                 if (nodePassesPolicy && (matchingNode->allocationCount > 0)) {
476                     policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
477                     
478                     if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) {
479                         /* Check if instance requesting resource has privileges to share
480                          * a resource already reserved by Linux */
481                         policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
482                         nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
483                     }
485                     if (nodePassesPolicy) {
486                         /* Check exclusive privileges of instance requesting resource.  Requesting
487                          * instance with exclusive privileges can't reserve resource if already owned*/
488                         policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
489                         nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
490                     }
491                 }
492                 
493                 if (nodePassesPolicy && (matchingNode->allocationCount == 1)) {
494                     /* Check exclusive privileges of instance that currently owns resource */
495                     policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
496                     policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
497                     nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
498                 }
500                 if (retVal != RM_OK) {
501                     break;
502                 }
504                 if (nodePassesPolicy) {
505                     matchingEnd = matchingNode->base + matchingNode->length - 1;
506                     /* Initialize indexer to be first resource value that alignment */
507                     rangeIndex = findNode.base;
508                     if (rangeIndex % opInfo->resourceInfo->alignment) {
509                         rangeIndex += (opInfo->resourceInfo->alignment -
510                                       (rangeIndex % opInfo->resourceInfo->alignment));
511                     }
512                     
513                     if ((rangeIndex + opInfo->resourceInfo->length - 1) <= matchingEnd) {
514                         /* Block of unallocated resources within matchingNode that satisfies
515                          * allocate requirements */
516                         opInfo->resourceInfo->base = rangeIndex;
517                         resourceFound = RM_TRUE;
518                         retVal = RM_SERVICE_PROCESSING;
519                     }     
520                 }
521             }
522             
523             if (!resourceFound) {
524                 /* Check next resource node for available resources */
525                 findNode.base = matchingNode->base + matchingNode->length;
526             }
527         }
528         else {
529             retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
530         }
531     } while ((!resourceFound) && 
532              (retVal != RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET));
534     return(retVal); 
537 /* FUNCTION PURPOSE: Allocates an allocator resource
538  ***********************************************************************
539  * DESCRIPTION: Will attempt to allocate the resource with specified
540  *              base and length from the resource's allocator.  The
541  *              allocation algorithm will verify the allocation against
542  *              the policy permissions for the instance requesting the
543  *              allocation.  If the policy allows the allocation the 
544  *              algorithm will allocate the resource then combine any
545  *              resource nodes that may have become equivalent (in terms
546  *              of ownership) after the allocation.
547  */
548 static int32_t allocatorAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy, 
549                                  Rm_AllocatorOpInfo *opInfo)
551     Rm_ResourceNode     findNode;
552     Rm_ResourceNode    *matchingNode = NULL;
553     Rm_ResourceNode    *leftNode = NULL;
554     Rm_ResourceNode    *rightNode = NULL;
555     Rm_PolicyCheckType  policyCheckType;    
556     Rm_PolicyCheckCfg   policyCheckCfg;
557     int                 allocPassesPolicy;
558     int                 combineLeft = RM_FALSE;
559     int                 combineRight = RM_FALSE;    
560     uint32_t            findEnd;
561     uint32_t            matchingEnd;  
562     int32_t             retVal;
564     if (opInfo->operation == Rm_allocatorOp_ALLOCATE_INIT) {
565         policyCheckType = Rm_policyCheck_INIT;
566     }
567     else if (opInfo->operation == Rm_allocatorOp_ALLOCATE_USE) {
568         policyCheckType = Rm_policyCheck_USE;
569     }
570     else {
571         retVal = RM_ERROR_INVALID_SERVICE_TYPE;
572         return (retVal);
573     }   
575     memset((void *)&findNode, 0, sizeof(findNode));
576     findNode.base = opInfo->resourceInfo->base;
577     findNode.length = opInfo->resourceInfo->length;
578     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
580     /* Prepare privilege checks */
581     memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg)); 
583     if (matchingNode) {
584         findEnd = findNode.base + findNode.length - 1;
585         matchingEnd = matchingNode->base + matchingNode->length - 1;
586         
587         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
588             if (opInfo->serviceSrcInstNode == rmPolicyGetLinuxInstNode(rmHandle)) {
589                 /* Bypass policy checks since Linux Kernel has full privileges */
590                 allocPassesPolicy = RM_TRUE;
591             }
592             else {
593                 policyCheckCfg.policyDtb = opInfo->policy;
594                 policyCheckCfg.resourceOffset = resourcePolicy;    
595                 policyCheckCfg.type = policyCheckType;
596                 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
597                 policyCheckCfg.resourceBase = findNode.base;
598                 policyCheckCfg.resourceLength = findNode.length;
599                 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
600                 if (!allocPassesPolicy) {
601                     if (policyCheckType == Rm_policyCheck_INIT) {
602                         retVal = RM_SERVICE_DENIED_INIT_PERM_NOT_GIVEN;
603                     }
604                     else {
605                         retVal = RM_SERVICE_DENIED_USE_PERM_NOT_GIVEN;
606                     }
607                 }
609                 if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
610                     if (allocPassesPolicy && (matchingNode->allocationCount > 0)) {
611                         if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) {
612                             /* Check if instance requesting resource has privileges to share
613                              * a resource already reserved by Linux */
614                             policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
615                             policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
616                             allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
617                             if (!allocPassesPolicy) {
618                                 retVal = RM_SERVICE_DENIED_RES_NOT_SHARED_LINUX;
619                             }
620                         }
621                         if (allocPassesPolicy) {
622                             /* Check exclusive privileges of instance requesting resource.  Requesting
623                              * instance with exclusive privileges can't reserve resource if already owned*/
624                             policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
625                             policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
626                             allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
627                             if (!allocPassesPolicy) {
628                                 retVal = RM_SERVICE_DENIED_EXCLUSIVE_RES_ALLOCD;
629                             }
630                         }
631                     }
632                     if (allocPassesPolicy && (matchingNode->allocationCount == 1)) {
633                         /* Check exclusive privileges of instance that currently owns resource */
634                         policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
635                         policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
636                         allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
637                         if (!allocPassesPolicy) {
638                             retVal = RM_SERVICE_DENIED_ALLOCD_TO_EXCLUSIVE_INST;
639                         }                
640                     }  
641                 }
642             }
643             
644             if (allocPassesPolicy) {
645                 if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
646                     /* Handle any possible node combinations if requesting instance is
647                      * not already in resource's owner list.  Automatic approval if requesting
648                      * instance is already in owner list. */
649                     if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {
650                         /* findNode range matches matchingNode range
651                          *
652                          *   |<--left node-->||<--matched  node-->||<--right node-->| => existing node
653                          *                    |<--alloc request-->|  => requested resources
654                          */                     
655                         leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
656                         rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
657                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
658                         allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
660                         if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
661                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
662                             combineLeft = RM_TRUE;
663                         }
664                         if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
665                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
666                             combineRight = RM_TRUE;
667                         }
669                         if (combineLeft && combineRight) {
670                             /* Combine all three nodes into matchingNode */
671                             matchingNode->base = leftNode->base;
672                             matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
674                             allocatorResNodeOwnerClear(rmHandle, leftNode);
675                             rmResourceNodeFree(leftNode);
676                             allocatorResNodeOwnerClear(rmHandle, rightNode);
677                             rmResourceNodeFree(rightNode);                        
678                         }
679                         else if (combineLeft) {
680                             /* Combine left and matching nodes.  Reinsert right. */
681                             matchingNode->base = leftNode->base;
682                             matchingNode->length += leftNode->length;
684                             allocatorResNodeOwnerClear(rmHandle, leftNode);
685                             rmResourceNodeFree(leftNode);
686                             if (rightNode) {
687                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);  
688                             }
689                         }
690                         else if (combineRight) {
691                             /* Combine right and matching nodes.  Reinsert left. */
692                             matchingNode->length += rightNode->length;
694                             allocatorResNodeOwnerClear(rmHandle, rightNode);
695                             rmResourceNodeFree(rightNode);
696                             if (leftNode) {
697                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
698                             }
699                         }
700                         else {
701                             /* No combine. */
702                             if (leftNode) {
703                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
704                             }
705                             if (rightNode) {
706                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
707                             }
708                         }
710                         /* Always reinsert matchingNode */                
711                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
712                         
713                         /* Matching node contains new reference count after alloc.  Return new owner count. */
714                         opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
715                     }   
716                     else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
717                         /* findNode range is subset of matchingNode range and neither boundary is
718                          * equivalent.
719                          *
720                          * |<----------matched node---------->|
721                          *        |<---alloc request--->|
722                          */ 
723                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
724                         leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
725                         allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
726                         rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
727                         allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
729                         matchingNode->base = findNode.base;                                    
730                         matchingNode->length = findNode.length;
731                         allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
733                         /* Insert all the nodes */
734                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
735                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
736                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
737                         
738                         /* Matching node contains new reference count after alloc.  Return new owner count. */
739                         opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
740                     }  
741                     else {    
742                         if (findNode.base == matchingNode->base) {
743                             /* findNode base and matchingNode base are equivalent.  May be combine
744                              * possibilities to the left
745                              *
746                              * |<---left node (alloc'd)--->||<----------matched node---------->|
747                              *                              |<---findNode (alloc req)--->|
748                              */                         
749                             leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
750                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
751                             /* Add allocating instance to owner list for compare with leftNode */
752                             allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
753                             
754                             if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
755                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
756                                 /* Combine leftNode and findNode */
757                                 leftNode->length += findNode.length;
758                             }
759                             else {
760                                 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
761                                 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
762                             }
764                             /* Account for leftNode in matchingNode */
765                             matchingNode->base = findNode.base + findNode.length;
766                             matchingNode->length = matchingEnd - findEnd;  
768                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
769                             /* Left node contains new reference count after alloc.  Return new owner count. */
770                             opInfo->resourceInfo->ownerCount = leftNode->allocationCount;
771                         }
772                         else if (findEnd == matchingEnd) {
773                             /* findNode end and matchingNode end are equivalent.  May be combine
774                              * possibilities to the right
775                              *
776                              * |<----------matched node---------->||<---right node (alloc'd)--->|
777                              *       |<---findNode (alloc req)--->| 
778                              */                        
779                             rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
780                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
781                             /* Add allocating instance to owner list for compare with rightNode */
782                             allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
783                             
784                             if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
785                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
786                                 /* Combine rightNode and findNode */
787                                 rightNode->base = findNode.base;
788                                 rightNode->length += findNode.length;
789                             }
790                             else {
791                                 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
792                                 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
793                             }
795                             /* Account for rightNode in matchingNode */
796                             matchingNode->length -= findNode.length;  
798                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
799                             /* Right node contains new reference count after alloc.  Return new owner count. */
800                             opInfo->resourceInfo->ownerCount = rightNode->allocationCount;
801                         }
802                         /* Remove allocating instance from leftover matchingNode */
803                         allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
804                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
805                     }
806                 }
807                 retVal = RM_SERVICE_APPROVED;
808             }
809         }
810         else {
811             retVal = RM_SERVICE_DENIED_PARTIAL_ALLOCATION;
812         }
813     }
814     else {
815         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
816     }
818     return(retVal);        
821 /* FUNCTION PURPOSE: Frees an allocator resource
822  ***********************************************************************
823  * DESCRIPTION: Will attempt to free the resource with specified
824  *              base and length from the resource's allocator.  The
825  *              free algorithm will verify the free request parameters
826  *              match an allocated range for the resource and that the
827  *              range is owned by the instance requesting the free. If
828  *              the free is validated the algorithm will free the 
829  *              resource then combine any resource nodes that may have
830  *              become equivalent (in terms of ownership) after the
831  *              allocation.
832  */
833 static int32_t allocatorFree(Rm_Handle rmHandle, Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)
835     Rm_ResourceNode  findNode;
836     Rm_ResourceNode *matchingNode = NULL;
837     Rm_ResourceNode *leftNode = NULL;
838     Rm_ResourceNode *rightNode = NULL;
839     int              combineLeft = RM_FALSE;
840     int              combineRight = RM_FALSE;
841     uint32_t         findEnd;
842     uint32_t         matchingEnd;
843     int32_t          retVal;
845     memset((void *)&findNode, 0, sizeof(findNode));
846     findNode.base = opInfo->resourceInfo->base;
847     findNode.length = opInfo->resourceInfo->length;
848     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
850     if (matchingNode) {
851         findEnd = findNode.base + findNode.length - 1;
852         matchingEnd = matchingNode->base + matchingNode->length - 1;
853         
854         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {  
855             if (matchingNode->allocationCount) {
856                 if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
857                     if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))
858                     {
859                         /* Case 1: Free range equals allocated matched node exactly. Attempt to combine 
860                          *         freed node with nodes to left and right.
861                          *
862                          * |<--left node-->||<---matched node--->||<--right node-->|
863                          *                  |<---free request--->|
864                          */ 
865                         leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
866                         rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
867                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
868                         allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
870                         if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
871                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
872                             combineLeft = RM_TRUE;
873                         }
874                         if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
875                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
876                             combineRight = RM_TRUE;
877                         }
879                         if (combineLeft && combineRight) {
880                             /* Combine all three nodes into matchingNode */
881                             matchingNode->base = leftNode->base;
882                             matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
884                             allocatorResNodeOwnerClear(rmHandle, leftNode);
885                             rmResourceNodeFree(leftNode);
886                             allocatorResNodeOwnerClear(rmHandle, rightNode);
887                             rmResourceNodeFree(rightNode);                        
888                         }
889                         else if (combineLeft) {
890                             /* Combine left and matching nodes.  Reinsert right. */
891                             matchingNode->base = leftNode->base;
892                             matchingNode->length += leftNode->length;
894                             allocatorResNodeOwnerClear(rmHandle, leftNode);
895                             rmResourceNodeFree(leftNode);
896                             if (rightNode) {
897                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode); 
898                             }
899                         }
900                         else if (combineRight) {
901                             /* Combine right and matching nodes.  Reinsert left. */
902                             matchingNode->length += rightNode->length;
904                             allocatorResNodeOwnerClear(rmHandle, rightNode);
905                             rmResourceNodeFree(rightNode);
906                             if (leftNode) {
907                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
908                             }
909                         }
910                         else {
911                             /* No combine. */
912                             if (leftNode) {
913                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
914                             }
915                             if (rightNode) {
916                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
917                             }
918                         }
920                         /* Always reinsert matchingNode */
921                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
922                         
923                         /* Matching node is what remains after free.  Return remaining owner count. */
924                         opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
925                     }
926                     else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
927                         /* Case 2: Free range is less than range in matched node. Split
928                          *         matched node into three nodes.
929                          *
930                          * |<----------matched node---------->|
931                          *        |<---free request--->|
932                          *
933                          * Remove instance from AllocatedTo list then add it back in for side nodes for
934                          * proper accounting of allocations in validInstance list
935                          */ 
936                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
937                         allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
938                         
939                         leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
940                         allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
941                         allocatorResNodeOwnerAdd(rmHandle, leftNode, opInfo->serviceSrcInstNode);
942                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
943                         
944                         rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
945                         allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
946                         allocatorResNodeOwnerAdd(rmHandle, rightNode, opInfo->serviceSrcInstNode);
947                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
949                         matchingNode->base = findNode.base;                                    
950                         matchingNode->length = findNode.length;
951                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
952                         
953                         /* Matching node is what remains after free.  Return remaining owner count. */
954                         opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
955                     }
956                     else {                        
957                         if (findNode.base == matchingNode->base) {
958                             /* Case 3: Free range is on left boundary of matched node. Try to 
959                              *         combine free range with left node.
960                              *
961                              * |<---left node (free)--->||<----------matched node---------->|
962                              *                           |<---findNode (free req)--->|
963                              */ 
965                             leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
966                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
967                             /* Remove freeing instance from owner list for compare with leftNode */
968                             allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
969                             
970                             if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
971                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
972                                 /* Combine leftNode and findNode */
973                                 leftNode->length += findNode.length;
974                             }
975                             else {
976                                 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
977                                 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
978                             }
980                             /* Remove leftNode range from matchingNode */
981                             matchingNode->base = findNode.base + findNode.length;
982                             matchingNode->length = matchingEnd - findEnd;  
983                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
984                             
985                             /* Left node is what remains after free.  Return remaining owner count. */
986                             opInfo->resourceInfo->ownerCount = leftNode->allocationCount;
987                         }
988                         else if (findEnd == matchingEnd) {
989                             /* Case 4: Free range is on right boundary of matched node. Try to 
990                              *         combine free range with right node.
991                              *
992                              * |<----------matched node---------->||<---right node (free)--->|
993                              *        |<---findNode (free req)--->|
994                              */ 
995                             
996                             rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
997                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode); 
998                             /* Remove freeing instance from owner list for compare with rightNode */
999                             allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
1000                             
1001                             if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
1002                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
1003                                 /* Combine rightNode and findNode */
1004                                 rightNode->base = findNode.base;
1005                                 rightNode->length += findNode.length;
1006                             }
1007                             else {
1008                                 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
1009                                 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
1010                             }
1012                             /* Remove rightNode range from matchingNode */
1013                             matchingNode->length -= findNode.length;  
1014                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
1015                             
1016                             /* Right node is what remains after free.  Return remaining owner count. */
1017                             opInfo->resourceInfo->ownerCount = rightNode->allocationCount;
1018                         }
1020                         /* Add freeing instance back into matchingNode allocations */
1021                         allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
1022                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1023                     }
1024                     retVal = RM_SERVICE_APPROVED;
1025                 }
1026                 else {
1027                     /* Return owner count.  In case it's a reference count check in application */
1028                     opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1029                     retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST;
1030                 }
1031             }
1032             else {
1033                 /* Return owner count.  In case it's a reference count check in application */
1034                 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1035                 retVal = RM_SERVICE_DENIED_RES_ALREADY_FREE;
1036             }
1037         }
1038         else {
1039             retVal = RM_SERVICE_DENIED_PARTIAL_FREE;
1040         }
1041     }
1042     else {
1043         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
1044     }
1045     return(retVal);  
1048 /* FUNCTION PURPOSE: Reserves a Linux resource
1049  ***********************************************************************
1050  * DESCRIPTION: Reserves resources for Linux using the base and length
1051  *              values retrieved from the Linux DTB via the
1052  *              "linux-dtb-alias" properties within the GRL.
1053  */
1054 static int32_t allocatorReserveLinuxResource(Rm_Handle rmHandle, Rm_LinuxAlias *linuxAlias, 
1055                                              Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)
1057     int32_t   retVal = RM_OK;
1058     int       baseFound = RM_FALSE;
1059     int       lengthFound = RM_FALSE;
1060     uint32_t  valueIndex = 0;
1062     while ((linuxValues) && (!baseFound || !lengthFound)) {
1063         if (linuxAlias->baseOffset == valueIndex) {
1064             opInfo->resourceInfo->base = linuxValues->value;
1065             baseFound = RM_TRUE;
1067             if (linuxAlias->lengthOffset == RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) {
1068                 opInfo->resourceInfo->length = 1;
1069                 lengthFound = RM_TRUE;
1070             }
1071         }
1072         else if (linuxAlias->lengthOffset == valueIndex) {
1073             opInfo->resourceInfo->length = linuxValues->value;
1074             lengthFound = RM_TRUE;
1075         }
1077         linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;
1078         valueIndex++;
1079     }
1081     if (!baseFound || !lengthFound) {
1082         retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1083     }
1084     else {
1085         /* Allocate resource to Linux */
1086         retVal = rmAllocatorOperation(rmHandle, opInfo);
1087         if (retVal == RM_SERVICE_APPROVED) {
1088             retVal = RM_OK;
1089         }
1090     }
1091     return (retVal);
1094 /* FUNCTION PURPOSE: Finds and reserves Linux resources
1095  ***********************************************************************
1096  * DESCRIPTION: Parses the Linux DTB for resources consumed by the
1097  *              Linux kernel.  If the resource is found via the
1098  *              "linux-dtb-alias" property defined in the GRL it is 
1099  *              reserved.
1100  */
1101 static int32_t allocatorFindLinuxResource(Rm_Handle rmHandle, const char *resourceName, void *linuxDtb, 
1102                                           Rm_LinuxAlias *linuxAlias)
1104     Rm_Inst            *rmInst = (Rm_Inst *)rmHandle;
1105     Rm_AllocatorOpInfo  opInfo;
1106     Rm_ResourceInfo     resourceInfo;
1107     uint32_t            pathOffset;
1108     uint32_t            pathSize;
1109     char               *spacePtr;
1110     int32_t             propOffset;
1111     int32_t             nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1112     int32_t             prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1113     int32_t             depth = RM_DTB_UTIL_STARTING_DEPTH;
1114     int32_t             propertyLen;
1115     const char         *propertyName;
1116     const void         *propertyData; 
1117     Rm_LinuxValueRange *linuxValueRange;
1118     int32_t             retVal = RM_OK; 
1120     memset((void *)&opInfo, 0, sizeof(opInfo));
1121     memset((void *)&resourceInfo, 0, sizeof(resourceInfo));
1123     strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS);
1124     opInfo.policy = rmInst->u.server.globalPolicy;
1125     opInfo.serviceSrcInstNode = rmPolicyGetLinuxInstNode(rmHandle);
1126     opInfo.operation = Rm_allocatorOp_ALLOCATE_INIT;
1127     opInfo.resourceInfo = &resourceInfo;    
1129     while(linuxAlias) {
1130         /* Reset parsing variables */
1131         pathOffset = 0;
1132         pathSize = strlen(linuxAlias->path) + 1;
1133         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1134         prevDepth = RM_DTB_UTIL_STARTING_DEPTH;   
1135         resourceInfo.base = 0;
1136         resourceInfo.length = 0;
1138         spacePtr = strpbrk(linuxAlias->path, " ");
1139         if (spacePtr) {
1140             *spacePtr = '\0';
1141         }       
1142         
1143         while(pathOffset < pathSize) {
1144             /* Move through DTB nodes until next alias path node found */
1145             if (strcmp(linuxAlias->path + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL))) {
1146                 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);
1148                 if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) {
1149                     /* Returning from subnode that matched part of alias path without finding
1150                      * resource values */
1151                     retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1152                     break;
1153                 }
1154             }
1155             else {
1156                 /* Found next alias path node.  Move to next node name in path string. */
1157                 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1158                 spacePtr = strpbrk(linuxAlias->path + pathOffset, " ");
1159                 if (spacePtr) {
1160                     *spacePtr = '\0';
1161                 }       
1162                 
1163                 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);
1164                 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);
1165                 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1166                        (pathOffset < pathSize)) {
1167                     propertyData = fdt_getprop_by_offset(linuxDtb, propOffset, 
1168                                                          &propertyName, &propertyLen);
1170                     if (strcmp(linuxAlias->path + pathOffset, propertyName) == 0) {
1171                         /* Found resource at end of alias path */
1172                         pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1173                         linuxValueRange = rmDtbUtilLinuxExtractValues(propertyData, propertyLen);
1174                         retVal = allocatorReserveLinuxResource(rmHandle, linuxAlias, 
1175                                                                linuxValueRange, &opInfo);
1176                         rmDtbUtilLinuxFreeValues(linuxValueRange);
1177                     }
1178                     propOffset = fdt_next_property_offset(linuxDtb, propOffset);
1179                 } 
1181                 if (propOffset < -FDT_ERR_NOTFOUND) {
1182                     retVal = propOffset;
1183                     break;
1184                 }
1185             }
1186         }
1188         if (retVal < RM_OK) {
1189             break;
1190         }
1191         linuxAlias = linuxAlias->nextLinuxAlias;
1192     }
1193     return (retVal);
1196 /* FUNCTION PURPOSE: Creates and initializes a resource allocator
1197  ***********************************************************************
1198  * DESCRIPTION: Creates a resource allocator for the provided
1199  *              resource name and resource properties retrieved
1200  *              from the GRL.  Resources will be reserved for 
1201  *              the Linux kernel if the Linux DTB is provided
1202  *              and there are "linux-dtb-alias" properties
1203  *              specified in the GRL.
1204  */
1205 static int32_t allocatorExtractGrlResProps(Rm_Handle rmHandle, const char *resourceName, 
1206                                            Rm_ResourceProperties *resourceProperties, void *linuxDtb)
1208     Rm_Inst             *rmInst = (Rm_Inst *)rmHandle;
1209     Rm_ResourceRange    *range = NULL;
1210     Rm_ResourceRange    *rangeBasePtr = NULL;
1211     Rm_NsAssignment     *nsAssignments = NULL;
1212     Rm_NsAssignment     *nsAssignmentBasePtr = NULL;
1213     Rm_LinuxAlias       *linuxAlias = NULL;
1214     Rm_NameServerObjCfg  nameServerObjCfg;      
1215     int32_t              retVal = RM_OK;
1217     if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0)) {
1218         range = rangeBasePtr = rmDtbUtilResExtractRange(resourceProperties->rangeData, 
1219                                                         resourceProperties->rangeLen);
1220         
1221         if ((retVal = allocatorCreate(rmHandle, resourceName, range)) >= RM_OK) {
1222             if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen) {
1223                 if (linuxDtb) {
1224                     linuxAlias = rmDtbUtilResExtractLinuxAlias(resourceProperties->linuxAliasData,
1225                                                                resourceProperties->linuxAliasLen, &retVal);
1226                     if (linuxAlias) {
1227                         retVal = allocatorFindLinuxResource(rmHandle, resourceName, linuxDtb, linuxAlias);            
1228                     }
1229                 }
1230             }
1231         }
1232     }
1233     
1234     if (retVal >= RM_OK) {
1235         if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) {
1236             nsAssignments = rmDtbUtilResExtractNsAssignment(resourceProperties->nsAssignData, 
1237                                                             resourceProperties->nsAssignLen, &retVal);
1238             if (nsAssignments) {
1239                 nsAssignmentBasePtr = nsAssignments;
1240                 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1241                     rmNameServerTreeInv(rmInst->u.server.nameServer);
1242                 }                  
1243                 while (nsAssignments) {
1244                     memset((void *)&nameServerObjCfg, 0, sizeof(nameServerObjCfg));
1245                     nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer;
1246                     nameServerObjCfg.nodeCfg.objName = nsAssignments->nsName;
1247                     nameServerObjCfg.nodeCfg.resourceName = (char *)resourceName;
1248                     nameServerObjCfg.nodeCfg.resourceBase= nsAssignments->resourceBase;
1249                     nameServerObjCfg.nodeCfg.resourceLength = nsAssignments->resourceLength;                
1250                     rmNameServerAddObject(&nameServerObjCfg);
1251                     nsAssignments = nsAssignments->nextNsAssignment;
1252                 }
1253                 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1254                     rmNameServerTreeWb(rmInst->u.server.nameServer);
1255                 }                
1256                 rmDtbUtilResFreeNsAssignmentList(nsAssignmentBasePtr);
1257             }
1258         }
1259     }
1260     else {
1261         allocatorDelete(rmHandle, resourceName);
1262     }
1264     rmDtbUtilResFreeRange(rangeBasePtr);
1265     if (linuxAlias) {
1266         rmDtbUtilResFreeLinuxAlias(linuxAlias);
1267     }
1268     return(retVal);
1271 /**********************************************************************
1272  ********************** Internal Functions ****************************
1273  **********************************************************************/
1275 /* FUNCTION PURPOSE: Finds an allocator
1276  ***********************************************************************
1277  * DESCRIPTION: Returns a pointer to an allocator that matches the 
1278  *              provided resource name.
1279  */
1280 Rm_Allocator *rmAllocatorFind(Rm_Handle rmHandle, const char *resourceName)
1282     Rm_Inst      *rmInst = (Rm_Inst *)rmHandle;
1283     Rm_Allocator *allocatorList = rmInst->u.server.allocators;
1284     
1285     while (allocatorList) {
1286         RM_SS_OBJ_INV(allocatorList, Rm_Allocator);
1287         if (strncmp(allocatorList->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
1288             break;             
1289         }
1290         allocatorList = allocatorList->nextAllocator;
1291     }
1293     return (allocatorList);
1296 /* FUNCTION PURPOSE: Issues an allocator operation
1297  ***********************************************************************
1298  * DESCRIPTION: Issues an allocator preallocate, allocate, or free
1299  *              for an RM resource.
1300  */
1301 int32_t rmAllocatorOperation(Rm_Handle rmHandle, Rm_AllocatorOpInfo *opInfo)
1303     Rm_Inst      *rmInst = (Rm_Inst *)rmHandle;
1304     Rm_Allocator *allocator = NULL;
1305     int32_t       resourceOffsetInPolicy;
1306     int32_t       retVal;
1307     
1308     resourceOffsetInPolicy = rmPolicyGetResourceOffset(opInfo->policy, opInfo->resourceInfo->name);
1309     allocator = rmAllocatorFind(rmHandle, opInfo->resourceInfo->name);
1310     
1311     if ((resourceOffsetInPolicy > 0) && allocator) {
1312         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1313             rmResourceTreeInv(allocator->allocatorRootEntry);
1314         }
1315         
1316         if ((opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_INIT) ||
1317             (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_USE)) {
1318             retVal = allocatorPreAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo);
1319         }               
1320         else if ((opInfo->operation == Rm_allocatorOp_ALLOCATE_INIT) ||
1321                  (opInfo->operation == Rm_allocatorOp_ALLOCATE_USE)) {
1322             retVal = allocatorAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo);
1323         }
1324         else if (opInfo->operation == Rm_allocatorOp_FREE) {
1325             retVal = allocatorFree(rmHandle, allocator, opInfo);
1326         } 
1328         if ((rmInst->instType == Rm_instType_SHARED_SERVER) &&
1329             (retVal == RM_SERVICE_APPROVED)) {
1330             rmResourceTreeWb(allocator->allocatorRootEntry);
1331         }        
1332     }
1333     else {
1334         /* Resource could not be found in policy and/or allocator */
1335         retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
1336     }
1337     return(retVal);
1340 /* FUNCTION PURPOSE: Initializes server allocators
1341  ***********************************************************************
1342  * DESCRIPTION: Creates and initializes a server instance's
1343  *              resource allocators using the GRL and, if
1344  *              provided, Linux DTB.
1345  */
1346 int32_t rmAllocatorInitializeResources(Rm_Handle rmHandle, void *globalResourceDtb, void *linuxDtb)
1348     int32_t                nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1349     int32_t                nodeDepth = RM_DTB_UTIL_STARTING_DEPTH;
1350     Rm_ResourceProperties  resProperties;    
1351     int32_t                propOffset;
1352     int32_t                propertyLen;
1353     const char            *propertyName;
1354     const void            *propertyData;
1355     Rm_ResourcePropType    propertyType;  
1356     int32_t                retVal = RM_OK;
1358     /* Parse the Global Resource List, creating an allocator for each specified resource node */
1359     while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (nodeDepth >= RM_DTB_UTIL_STARTING_DEPTH)) {
1360         memset((void *)&resProperties, 0, sizeof(resProperties));
1361         /* Get properties of resource node */
1362         propOffset = fdt_first_property_offset(globalResourceDtb, nodeOffset);
1363         while (propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1364             propertyData = fdt_getprop_by_offset(globalResourceDtb, propOffset, &propertyName, &propertyLen);
1365             propertyType = rmDtbUtilResGetPropertyType(propertyName);
1366             if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) {
1367                 resProperties.rangeData = propertyData;
1368                 resProperties.rangeLen = propertyLen;
1369             }
1370             else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) {
1371                 resProperties.nsAssignData = propertyData;
1372                 resProperties.nsAssignLen = propertyLen;
1373             }
1374             else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS) {
1375                 resProperties.linuxAliasData = propertyData;
1376                 resProperties.linuxAliasLen = propertyLen;
1377             }        
1378             else {
1379                 retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY;
1380                 goto exitAllocInit;
1381             }
1383             propOffset = fdt_next_property_offset(globalResourceDtb, propOffset);
1384             if (propOffset == -FDT_ERR_NOTFOUND) {
1385                 /* No more resource properties but at least one found.  Extract the property values */
1386                 retVal = allocatorExtractGrlResProps(rmHandle, fdt_get_name(globalResourceDtb, nodeOffset, NULL), 
1387                                                      &resProperties, linuxDtb);
1388                 if (retVal < RM_OK) {
1389                     goto exitAllocInit;
1390                 }
1391             }
1392             else if (propOffset < -FDT_ERR_NOTFOUND) {
1393                 /* Error returned by LIBFDT */
1394                 retVal = propOffset;
1395                 goto exitAllocInit;
1396             }
1397         }
1398         if (propOffset < -FDT_ERR_NOTFOUND) {
1399             /* Error returned by LIBFDT */
1400             retVal = propOffset;
1401             goto exitAllocInit;
1402         }
1404         nodeOffset = fdt_next_node(globalResourceDtb, nodeOffset, &nodeDepth);
1405         if (nodeOffset < -FDT_ERR_NOTFOUND) {
1406             /* Error returned by LIBFDT */
1407             retVal = nodeOffset;
1408             goto exitAllocInit;
1409         }
1410     }
1411 exitAllocInit:    
1412     return(retVal);
1415 /* FUNCTION PURPOSE: Deletes server allocators
1416  ***********************************************************************
1417  * DESCRIPTION: Removes all resource nodes for each
1418  *              resource allocator and then deletes the allocator
1419  *              itself.  Used to free all memory consumed
1420  *              by the allocators.
1421  */
1422 void rmAllocatorDeleteResources(Rm_Handle rmHandle)
1424     Rm_Inst         *rmInst = (Rm_Inst *)rmHandle;
1425     Rm_Allocator    *allocatorList = allocatorGetAllocatorList(rmHandle);
1426     Rm_Allocator    *nextAllocator;
1427     Rm_ResourceTree *resTree;
1428     Rm_ResourceNode *resNode;
1429     Rm_ResourceNode *nextResNode;
1431     while (allocatorList) {
1432         RM_SS_OBJ_INV(allocatorList, Rm_Allocator);
1433         nextAllocator = allocatorList->nextAllocator;
1434         resTree = allocatorList->allocatorRootEntry;
1436         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1437             rmResourceTreeInv(resTree);
1438         }
1439         /* Delete each resource node in the allocator */
1440         for (resNode = RB_MIN(_Rm_AllocatorResourceTree, resTree); resNode != NULL; resNode = nextResNode) {
1441             nextResNode = RB_NEXT(_Rm_AllocatorResourceTree, resTree, resNode);
1442             RB_REMOVE(_Rm_AllocatorResourceTree, resTree, resNode);
1443             if (resNode->allocationCount) {
1444                 /* Delete all the owners in the resource's owner list */
1445                 allocatorResNodeOwnerClear(rmHandle, resNode);
1446             }
1447             rmResourceNodeFree(resNode);
1448         }        
1450         Rm_osalFree((void *)resTree, sizeof(*resTree));
1451         Rm_osalFree((void *)allocatorList, sizeof(*allocatorList));
1452         allocatorList = nextAllocator;
1453     }