9b9e211d669948bc2ebe19e72de7c63569cab81e
[keystone-rtos/rm-lld.git] / src / rm_policy.c
1 /**
2  *   @file  rm_policy.c
3  *
4  *   @brief   
5  *      Resource Manager Policy source.
6  *
7  *  \par
8  *  ============================================================================
9  *  @n   (C) Copyright 2012-2015, Texas Instruments, Inc.
10  * 
11  *  Redistribution and use in source and binary forms, with or without 
12  *  modification, are permitted provided that the following conditions 
13  *  are met:
14  *
15  *    Redistributions of source code must retain the above copyright 
16  *    notice, this list of conditions and the following disclaimer.
17  *
18  *    Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the 
20  *    documentation and/or other materials provided with the   
21  *    distribution.
22  *
23  *    Neither the name of Texas Instruments Incorporated nor the names of
24  *    its contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  *  \par
40 */
42 /* Standard includes */
43 #include <ctype.h>
45 /* RM external API includes */
46 #include <ti/drv/rm/rm.h>
48 /* RM internal API includes */
49 #include <ti/drv/rm/include/rm_internal.h>
50 #include <ti/drv/rm/include/rm_loc.h>
51 #include <ti/drv/rm/include/rm_allocatorloc.h>
52 #include <ti/drv/rm/include/rm_policyloc.h>
53 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
55 /* RM LIBFDT includes */
56 #include <ti/drv/rm/util/libfdt/libfdt.h>
58 /* Tree algorithm includes */
59 #include <ti/drv/rm/util/tree.h>
61 /* RM OSAL layer */
62 #include <rm_osal.h>
64 /**********************************************************************
65  *********************** Policy Globals *******************************
66  **********************************************************************/
68 /* Character used in policies to specify all RM instances receive
69  * the defined permissions for a resource node */
70 const char Rm_policyGlobalInst[] = "*";
72 /**********************************************************************
73  ******************** Local Policy Functions **************************
74  **********************************************************************/
76 /* FUNCTION PURPOSE: Parses a permissions subgroup
77  ***********************************************************************
78  * DESCRIPTION: Returns a linked list of policy permissions defining
79  *              which RM instance referenced in the permissions subgroup
80  *              get which permissions.  Returns NULL if any syntax
81  *              errors are encountered during the parsing.  The error
82  *              is returned via the result pointer parameter.
83  */
84 static Rm_PolicyPermission *policyParseSubPermission(char *permStrStart,
85                                                      char *permStrEnd,
86                                                      int32_t *result)
87 {
88     Rm_PolicyPermission *startPerm = NULL;
89     Rm_PolicyPermission *newPerm = NULL;
90     Rm_PolicyPermission *prevPerm = NULL;
91     Rm_PolicyPermission *nextPerm = NULL;
92     char                *permStrPtr = NULL;
93     char                *subgroupStart = NULL;
94     char                *subgroupEnd = NULL;
95     uint32_t             permStrLen = (uint32_t)(permStrEnd - permStrStart + 1);
96     char                 instNameTemp[RM_NAME_MAX_CHARS];
97     uint32_t             instNameIndex;
98     int                  foundInstName;
99     int                  instNameComplete;
100     int                  assignmentLeft;
101     int                  assignmentRight;
103     /* Create a local copy of the sub-permission string */
104     permStrPtr = Rm_osalMalloc(permStrLen);
105     rm_strncpy(permStrPtr, permStrStart, permStrLen);
107     permStrStart = permStrPtr;
108     permStrEnd = permStrPtr + strlen(permStrPtr);
110     /* Find the beginning and end of the sub-permission instance group */
111     subgroupStart = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START);
112     subgroupEnd = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END);
114     if ((!subgroupStart) || (!subgroupEnd) || (subgroupStart > subgroupEnd) ||
115         ((subgroupStart != strrchr(permStrStart,
116                                    RM_POLICY_PERM_SUBGROUP_START)) &&
117          (subgroupEnd != strrchr(permStrStart,
118                                  RM_POLICY_PERM_SUBGROUP_END)))) {
119         /* Free the memory associated with the temp string and return an
120          * error if:
121          * a) Could not find the instance group start
122          * b) Could not find the instance group end
123          * c) Subgroup start and end are out of order
124          * d) There is more than one instance subgroup specified in the string.
125          *    There should only be one subgroup per sub-permission string */
126         *result = RM_ERROR_PERM_STR_TOO_MANY_INST_GROUPS;
127         goto parseError;
128     }
130     /* Create a permission entry for each instance specified in the instance group.
131      * Instances names are separated by one or more spaces. */
132     permStrPtr = subgroupStart + 1;
133     instNameIndex = 0;
134     foundInstName = RM_FALSE;
135     instNameComplete = RM_FALSE;
136     while (permStrPtr <= subgroupEnd) {
137         if ((isspace(*permStrPtr) ||
138             (*permStrPtr == RM_POLICY_PERM_SUBGROUP_END))
139             && foundInstName) {
140             /* First space encountered after copying an instance name.  This
141              * terminates the instance name.  All other space characters are
142              * ignored. */
143             instNameTemp[instNameIndex] = '\0';
144             instNameComplete = RM_TRUE; 
145         } else {
146             if (!foundInstName) {
147                 /* First non-whitespace character encountered is the start of an
148                  * instance name */
149                 foundInstName = RM_TRUE;
150             }
152             /* Copy the character into the temporary instance name string */
153             instNameTemp[instNameIndex++] = *permStrPtr;
154         }
156         if (instNameComplete) {
157             newPerm = Rm_osalMalloc(sizeof(*newPerm));
158             memset((void *)newPerm, 0, sizeof(*newPerm));
160             rm_strncpy(newPerm->instName, instNameTemp, RM_NAME_MAX_CHARS);
161             newPerm->nextPermission = NULL;
163             if (prevPerm == NULL) {
164                 /* Save the first instance so it can be returned */
165                 startPerm = newPerm;
166             } else {
167                 prevPerm->nextPermission = newPerm;
168             }
169             prevPerm = newPerm;
171             instNameComplete = RM_FALSE;
172             instNameIndex = 0;
173             foundInstName = RM_FALSE;
174         }
176         if (instNameIndex == RM_NAME_MAX_CHARS) {
177             /* Instance name is longer than max length */
178             *result = RM_ERROR_INST_NAME_IN_ASSIGNMENT_TOO_LONG;
179             goto parseError;
180         }
182         permStrPtr++;
183     }
185     /* Fill in the permissions for each instance name */
187     /* Look on left of instance group for permission assignments. */
188     permStrPtr = subgroupStart - 1;
189     assignmentLeft = RM_FALSE;
190     while (permStrPtr >= permStrStart)
191     {
192         if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
193             if (assignmentLeft) {
194                 /* Assignment character has been found more than once.  This
195                  * is a syntax error.  Free the permission list and the
196                  * temporary string and return. */
197                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
198                 goto parseError;
199             } else {
200                 assignmentLeft = RM_TRUE;
201             }
202         } else if (!isspace(*permStrPtr)) {
203             if (assignmentLeft) {
204                 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) ||
205                     (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
206                     newPerm = startPerm;
207                     while (newPerm) {
208                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
209                         RM_policy_PERM_SET(pBits, 0, 0,
210                                            RM_POLICY_PERM_INIT_SHIFT, 1);
211                         newPerm = newPerm->nextPermission;
212                     }
213                 } else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) ||
214                          (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
215                     newPerm = startPerm;
216                     while (newPerm) {
217                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
218                         RM_policy_PERM_SET(pBits, 0, 0,
219                                            RM_POLICY_PERM_USE_SHIFT, 1);
220                         newPerm = newPerm->nextPermission;
221                     }
222                 } else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) ||
223                          (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
224                     newPerm = startPerm;
225                     while (newPerm) {
226                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
227                         RM_policy_PERM_SET(pBits, 0, 0,
228                                            RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
229                         newPerm = newPerm->nextPermission;
230                     }
231                 } else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) ||
232                          (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
233                     newPerm = startPerm;
234                     while (newPerm) {
235                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
236                         RM_policy_PERM_SET(pBits, 0, 0,
237                                            RM_POLICY_PERM_SHARED_LINUX_SHIFT,
238                                            1);
239                         newPerm = newPerm->nextPermission;
240                     }
241                 } else {
242                     /* Invalid permission character.  This is a syntax error.
243                      * Free the permission list and the temporary string
244                      * and return. */
245                     *result = RM_ERROR_PERM_STR_INVALID_CHAR;
246                     goto parseError;
247                 }
248             } else {
249                 /* Character found without the assignment character being found.
250                  * This is a syntax error.  Free the permission list and the
251                  * temporary string and return. */
252                 *result = RM_ERROR_PERM_CHAR_WITHOUT_ASSIGN_CHAR;
253                 goto parseError;
254             }
255         }
256         permStrPtr--;
257     }
259     /* Look on right of instance group for permission assignments. */
260     permStrPtr = subgroupEnd + 1;
261     assignmentRight = RM_FALSE;
262     while (permStrPtr < permStrEnd) {
263         if (assignmentLeft && (!isspace(*permStrPtr))) {
264             /* There should be nothing but spaces on right if assignment was
265              * already found on left */
266             *result = RM_ERROR_INVALID_PERMS_CHAR_ON_RIGHT;
267             goto parseError;
268         }
270         if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
271             if (assignmentRight) {
272                 /* Assignment character has been found more than once.  This is
273                  * a syntax error.  Free the permission list and the temporary
274                  * string and return. */
275                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
276                 goto parseError;
277             } else {
278                 assignmentRight = RM_TRUE;
279             }
280         } else if (!isspace(*permStrPtr)) {
281             if (assignmentRight) {
282                 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) ||
283                     (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
284                     newPerm = startPerm;
285                     while (newPerm) {
286                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
287                         RM_policy_PERM_SET(pBits, 0, 0,
288                                            RM_POLICY_PERM_INIT_SHIFT, 1);
289                         newPerm = newPerm->nextPermission;
290                     }
291                 } else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) ||
292                          (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
293                     newPerm = startPerm;
294                     while (newPerm) {
295                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
296                         RM_policy_PERM_SET(pBits, 0, 0,
297                                            RM_POLICY_PERM_USE_SHIFT, 1);
298                         newPerm = newPerm->nextPermission;
299                     }
300                 } else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) ||
301                          (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
302                     newPerm = startPerm;
303                     while (newPerm) {
304                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
305                         RM_policy_PERM_SET(pBits, 0, 0,
306                                            RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
307                         newPerm = newPerm->nextPermission;
308                     }
309                 } else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) ||
310                          (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
311                     newPerm = startPerm;
312                     while (newPerm) {
313                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
314                         RM_policy_PERM_SET(pBits, 0, 0,
315                                            RM_POLICY_PERM_SHARED_LINUX_SHIFT,
316                                            1);
317                         newPerm = newPerm->nextPermission;
318                     }
319                 } else {
320                     /* Invalid permission character.  This is a syntax error.
321                      * Free the permission list and the temporary string
322                      * and return. */
323                     *result = RM_ERROR_PERM_STR_INVALID_CHAR;
324                     goto parseError;
325                 }
326             } else {
327                 /* Character found without the assignment character being found.
328                  * This is a syntax error.  Free the permission list and the
329                  * temporary string and return. */
330                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
331                 goto parseError;
332             }
333         }
334         permStrPtr++;
335     }
337     Rm_osalFree((void *)permStrStart, permStrLen);
338     *result = RM_OK;
339     return (startPerm);
341 parseError:
342     while (startPerm) {
343         nextPerm = startPerm->nextPermission;
344         Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
345         startPerm = nextPerm;
346     }
347     Rm_osalFree((void *)permStrStart, permStrLen);
348     return(NULL);
351 /* FUNCTION PURPOSE: Frees a linked list of assignment permissions
352  ***********************************************************************
353  * DESCRIPTION: Frees the memory associated with a linked list of
354  *              assignment permissions extracted from a permissions
355  *              assignment subgroup in a policy DTB.
356  */
357 static void policyFreeAssignmentPermissions(Rm_PolicyPermission *permissionList)
359     Rm_PolicyPermission *nextPerm;
361     while (permissionList) {
362         nextPerm = permissionList->nextPermission;
363         Rm_osalFree((void *)permissionList, sizeof(Rm_PolicyPermission));
364         permissionList = nextPerm;
365     }
368 /* FUNCTION PURPOSE: Extracts permissions from a Policy "assignment"
369  ***********************************************************************
370  * DESCRIPTION: Returns a linked list of permissions for a resource node
371  *              containing an "assignment" property in the Policy DTB.
372  *              Each node in the linked list will contain a valid instance
373  *              name along with the permissions assigned to the instance
374  */
375 static Rm_PolicyPermission *policyGetAssignmentPermissions(Rm_PolicyAssignment *assignment,
376                                                            int32_t *result)
378     Rm_PolicyPermission *startPerm = NULL;
379     Rm_PolicyPermission *newPerm = NULL;
380     Rm_PolicyPermission *prevPerm = NULL;
381     char                *permStrStart = assignment->permissionsList;
382     char                *permStrEnd;
383     uint32_t             permStrLen = strlen(assignment->permissionsList) + 1;
384     uint32_t             i = 0;
386     *result = RM_OK;
388     while(i < permStrLen) {
389         /* Find the first sub-permission specification and parse it.  A
390          * sub-permission can be terminated by the termination character or the
391          * end of the string. */
392         if (!(permStrEnd = strchr(permStrStart, RM_POLICY_PERM_TERMINATOR))) {
393             /* Sub-permission termination character not found.  The permission
394              * string end is the end of the entire permission string */
395             permStrEnd = permStrStart + strlen(permStrStart);
396         }
398         newPerm = policyParseSubPermission(permStrStart, permStrEnd, result);
400         if (*result != RM_OK) {
401             /* Delete the permission list that's been created thus far, return
402              * the error and NULL for the permission list */
403             policyFreeAssignmentPermissions(startPerm);
404             return(NULL);
405         }
407         if (prevPerm == NULL) {
408             startPerm = newPerm;
409         } else {
410             prevPerm->nextPermission = newPerm;
411         }
413         /* Set prevPerm to the last sub-permission returned by the
414          * sub-permission parser */
415         prevPerm = newPerm;
416         while(prevPerm->nextPermission != NULL) {
417             prevPerm = prevPerm->nextPermission;
418         }
420         /* Update the number of characters parsed from the permission list and
421          * point to the start of the next sub-permission */
422         i += ((uint32_t)(permStrEnd - permStrStart + 1));
423         permStrStart = permStrEnd + 1;
424     }
426     return(startPerm);
429 /* FUNCTION PURPOSE: Returns number of bytes needed to store permissions
430  ***********************************************************************
431  * DESCRIPTION: Calculates and returns the number of bytes needed to store
432  *              permissions for all valid instances.  Words are packed
433  *              with permissions for as many instances as can fit
434  */
435 static uint32_t policyGetPermBufSize(Rm_PolicyPermBits *permsPtr,
436                                      uint32_t maxValidInst)
438     uint32_t instPerWord;
439     uint32_t numWords;
440     uint32_t totalBytes = 0;
442     instPerWord = RM_policy_PERM_INST_PER_WORD;
443     /* Round up */
444     numWords = (maxValidInst + instPerWord - 1) / instPerWord;
446     totalBytes = sizeof(*permsPtr) * numWords;
447     return(totalBytes);
450 /* FUNCTION PURPOSE: Stores policy permissions in a policy tree node
451  ***********************************************************************
452  * DESCRIPTION: Parses permissions and stores them in a word array in a
453  *              compacted format.  The array is attached to the resource's
454  *              policy tree node.
455  */
456 static int32_t policyStorePermissions(Rm_Inst *rmInst, Rm_PolicyNode *polNode,
457                                       Rm_PolicyPermission *extractedPerms)
459     Rm_PolicyValidInstNode *vInst = NULL;
460     uint32_t                instIdx;
461     uint32_t                wordIndex;
462     uint32_t                wordOffset;
463     int32_t                 retVal = RM_OK;
465     while (extractedPerms) {
466         if (!strncmp(extractedPerms->instName, Rm_policyGlobalInst,
467                      RM_NAME_MAX_CHARS)) {
468             instIdx = RM_POLICY_GLOBAL_PERM_INDEX;
469         } else if ((vInst = rmPolicyGetValidInstNode((Rm_Handle)rmInst,
470                                                    extractedPerms->instName))) {
471             instIdx = vInst->instIdx;
472         } else {
473             retVal = RM_ERROR_PERM_STR_INST_NOT_VALID;
474             goto errorExit;
475         }
477         /* Calculate word index into policy node's permission array
478          * for the instance index */
479         wordIndex  = RM_policy_PERM_INDEX(instIdx);
480         wordOffset = RM_policy_PERM_OFFSET(instIdx);
482         polNode->perms[wordIndex] |= ((extractedPerms->permissionBits &
483                                       RM_policy_PERM_FULL_MASK) << wordOffset);
485         extractedPerms = extractedPerms->nextPermission;
486     }
488 errorExit:
489     return(retVal);
492 /* FUNCTION PURPOSE: Returns resource's allocation alignment from policy
493  ***********************************************************************
494  * DESCRIPTION: Parses the policy DTB to find and return a resource's 
495  *              allocation alignment.
496  */
497 static uint32_t policyGetDtbAllocAlign(void *policyDtb, int32_t resourceOffset)
499     int32_t           offset;
500     const char       *name;
501     int32_t           len;
502     const void       *data;
503     Rm_ResourceValue *alignList = NULL;
504     uint32_t          align = 0;
506     offset = fdt_first_property_offset(policyDtb, resourceOffset);
507     while (offset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
508         data = fdt_getprop_by_offset(policyDtb, offset, &name, &len);
509         if (rmDtbUtilPolicyGetPropertyType(name) ==
510             Rm_policyPropType_ALLOCATION_ALIGNMENT) {
511             alignList = rmDtbUtilPolicyExtractResourceAlignments(data, len);
512             align = alignList->value;
513             break;
514         }
515         offset = fdt_next_property_offset(policyDtb, offset);
516     }
518     if (alignList) {
519         rmDtbUtilPolicyFreeResourceAlignments(alignList);
520     }
522     if (align == 0) {
523         align = 1;
524     }
525     return(align);
528 /* FUNCTION PURPOSE: Returns resource CD allocation size defined in policy
529  ***********************************************************************
530  * DESCRIPTION: Parses the policy DTB to find and return a resource's 
531  *              allocation size.
532  */
533 static uint32_t policyGetDtbCdAllocSize(void *policyDtb, int32_t resourceOffset)
535     int32_t           offset;
536     const char       *name;
537     int32_t           len;
538     const void       *data;
539     Rm_ResourceValue *allocSizeList = NULL;
540     uint32_t          allocSize = 0;
542     offset = fdt_first_property_offset(policyDtb, resourceOffset);
543     while (offset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
544         data = fdt_getprop_by_offset(policyDtb, offset, &name, &len);
545         if (rmDtbUtilPolicyGetPropertyType(name) ==
546             Rm_policyPropType_CD_ALLOCATION_SIZE) {
547             allocSizeList = rmDtbUtilPolicyExtractCdAllocationSizes(data, len);
548             allocSize = allocSizeList->value;
549             break;
550         }
551         offset = fdt_next_property_offset(policyDtb, offset);
552     }
554     if (allocSizeList) {
555         rmDtbUtilPolicyFreeCdAllocationSizes(allocSizeList);
556     }
557     return(allocSize);
560 /* FUNCTION PURPOSE: Get a resource's offset into a policy
561  ***********************************************************************
562  * DESCRIPTION: Returns the location of the specified resource node
563  *              within the specified Policy in the form of an offset
564  *              into the DTB.  The resourceName and the Policy
565  *              node name must match.
566  */
567 static int32_t policyGetDtbResourceOffset(void *policyDtb,
568                                           const char *resourceName)
570     int32_t     nodeOffset;
571     int32_t     depth;
572     const char *nodeName;
574     if (policyDtb) {
575         depth = RM_DTB_UTIL_STARTING_DEPTH;
576         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
578         /* Find node offset for provided resource name */
579         while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
580             nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
581             if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
582                 /* Resource name not found */
583                 nodeOffset = RM_ERROR_RES_DOES_NOT_EXIST_IN_POLICY;
584                 break;
585             } else {
586                 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
587                 if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0) {
588                     break;
589                 }
590             }
591         }
592     } else {
593         nodeOffset = RM_ERROR_INSTANCE_HAS_NO_POLICY;
594     }
595     return(nodeOffset);
598 /**********************************************************************
599  ************************ Internal Policy APIs ************************
600  **********************************************************************/
602 /* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree
603  ***********************************************************************
604  * DESCRIPTION: Returns a valid instance node from the valid instance
605  *              tree that matches the specified instName
606  */
607 Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_Handle rmHandle,
608                                                  const char *instName)
610     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
611     Rm_PolicyValidInstTree *treeRoot = rmInst->validInstTree;
612     Rm_PolicyValidInstNode  findNode;
614     rm_strncpy(findNode.name, instName, RM_NAME_MAX_CHARS);
615     return(RB_FIND(_Rm_PolicyValidInstTree, treeRoot, &findNode));
618 /* FUNCTION PURPOSE: Gets the Linux Valid instance node
619  ***********************************************************************
620  * DESCRIPTION: Returns a pointer to the valid instance node in the
621  *              valid instance tree that matches the instance name
622  *              reserved for resource assigned to the Linux kernel.
623  */
624 Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_Handle rmHandle)
626     const char linuxName[] = RM_ALLOCATED_TO_LINUX;
628     return(rmPolicyGetValidInstNode(rmHandle, linuxName));
631 /* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB
632  ***********************************************************************
633  * DESCRIPTION: Returns TRUE if the instance name has the specified
634  *              permissions for the specified resource in the Policy
635  *              DTB.  Otherwise, returns FALSE.
636  */
637 int32_t rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg)
639     uint32_t       permShift = RM_POLICY_PERM_INIT_SHIFT;
640     uint32_t       globPermIdx;
641     uint32_t       globPermOffset;
642     uint32_t       instPermIdx;
643     uint32_t       instPermOffset;
644     Rm_PolicyNode  findNode;
645     Rm_PolicyNode *matchNode = NULL;
646     uint32_t       findEnd;
647     uint32_t       matchEnd;
648     int32_t        isApproved = RM_FALSE;
650     switch (privilegeCfg->type) {
651         case Rm_policyCheck_INIT:
652             permShift = RM_POLICY_PERM_INIT_SHIFT;
653             break;
654         case Rm_policyCheck_USE:
655             permShift = RM_POLICY_PERM_USE_SHIFT;
656             break;
657         case Rm_policyCheck_EXCLUSIVE:
658             permShift = RM_POLICY_PERM_EXCLUSIVE_SHIFT;
659             break;
660         case Rm_policyCheck_SHARED_LINUX:
661             permShift = RM_POLICY_PERM_SHARED_LINUX_SHIFT;
662             break;
663         default:
664             return(isApproved);
665     }
667     /* Calculate the word indices and offsets for the global permissions and
668      * the specific instance */
669     globPermIdx    = RM_policy_PERM_INDEX(RM_POLICY_GLOBAL_PERM_INDEX);
670     globPermOffset = RM_policy_PERM_OFFSET(RM_POLICY_GLOBAL_PERM_INDEX);
671     instPermIdx    = RM_policy_PERM_INDEX(privilegeCfg->validInstNode->instIdx);
672     instPermOffset = RM_policy_PERM_OFFSET(privilegeCfg->validInstNode->instIdx);
674     memset((void *)&findNode, 0, sizeof(findNode));
675     findNode.base = privilegeCfg->resourceBase;
676     findNode.len  = privilegeCfg->resourceLength;
677     /* Get first matching node. */
678     matchNode = RB_FIND(_Rm_AllocatorPolicyTree, privilegeCfg->polTree,
679                         &findNode);
680     if (matchNode) {
681         /* Request range may not be completely contained within the first
682          * matching node.  Find furthest left matching node for the request
683          * range */
684         while (findNode.base < matchNode->base) {
685             matchNode = RB_PREV(_Rm_AllocatorPolicyTree,
686                                 privilegeCfg->polTree, matchNode);
687         }
688     }
690     /* Check permissions across all policy nodes which the request range
691      * spans */
692     while (matchNode) {
693         /* Not approved if any matching node has permission denial */
694         if ((!RM_policy_PERM_GET(matchNode->perms, globPermIdx, globPermOffset,
695                                permShift)) &&
696             (!RM_policy_PERM_GET(matchNode->perms, instPermIdx, instPermOffset,
697                                permShift))) {
698             isApproved = RM_FALSE;
699             break;
700         } else {
701             /* Approve until find otherwise */
702             isApproved = RM_TRUE;
703         }
705         matchEnd = matchNode->base + matchNode->len - 1;
706         findEnd  = findNode.base + findNode.len - 1;
708         /* Check node to right if request range spans matching node to right */
709         if (findEnd > matchEnd) {
710             matchNode = RB_NEXT(_Rm_AllocatorPolicyTree, privilegeCfg->polTree,
711                                 matchNode);
712         } else {
713             break;
714         }
715     }
717     return(isApproved);
720 /* FUNCTION PURPOSE: Returns resource base value according to the Policy
721  ***********************************************************************
722  * DESCRIPTION: Returns a resource base value based on the resource
723  *              ranges assigned to the specified valid instance by the
724  *              Policy DTB.
725  */
726 uint32_t rmPolicyGetResourceBase(Rm_PolicyTree *policyTree,
727                                  Rm_PolicyValidInstNode *validInstNode,
728                                  Rm_PolicyCheckType checkType)
730     uint32_t       permShift = RM_POLICY_PERM_INIT_SHIFT;
731     uint32_t       globPermIdx;
732     uint32_t       globPermOffset;
733     uint32_t       instPermIdx;
734     uint32_t       instPermOffset;
735     Rm_PolicyNode *polNode;
736     int32_t        resBase = RM_RESOURCE_BASE_UNSPECIFIED;
738     if (checkType == Rm_policyCheck_INIT) {
739         permShift = RM_POLICY_PERM_INIT_SHIFT;
740     } else if (checkType == Rm_policyCheck_USE) {
741         permShift = RM_POLICY_PERM_USE_SHIFT;
742     }
744     /* Calculate the word indices and offsets for the global permissions and
745      * the specific instance */
746     globPermIdx    = RM_policy_PERM_INDEX(RM_POLICY_GLOBAL_PERM_INDEX);
747     globPermOffset = RM_policy_PERM_OFFSET(RM_POLICY_GLOBAL_PERM_INDEX);
748     instPermIdx    = RM_policy_PERM_INDEX(validInstNode->instIdx);
749     instPermOffset = RM_policy_PERM_OFFSET(validInstNode->instIdx);
751     RB_FOREACH(polNode, _Rm_AllocatorPolicyTree, policyTree) {
752         if (RM_policy_PERM_GET(polNode->perms, globPermIdx, globPermOffset,
753                                permShift) ||
754             RM_policy_PERM_GET(polNode->perms, instPermIdx, instPermOffset,
755                                permShift)) {
756             resBase = polNode->base;
757             break;
758         }
759     }
761     return(resBase);
764 /* FUNCTION PURPOSE: Returns resource's allocation alignment
765  ***********************************************************************
766  * DESCRIPTION: Returns a resource's allocation alignment.
767  */
768 uint32_t rmPolicyGetAllocAlign(Rm_PolicyTree *policyTree)
770     Rm_PolicyNode *node = NULL;
771     uint32_t       align = 1;
773     /* Resource's alignment is global at the moment so all policy tree nodes
774      * store the same value.  Just get the min node and return the allocation
775      * alignment from it */
776     node = RB_MIN(_Rm_AllocatorPolicyTree, policyTree);
777     if (node) {
778         align = node->allocAlign;
779     }
781     return(align);
784 /* FUNCTION PURPOSE: Returns resource's CD allocation size
785  ***********************************************************************
786  * DESCRIPTION: Returns a resource's CD allocation size.
787  */
788 uint32_t rmPolicyGetCdAllocSize(Rm_PolicyTree *policyTree)
790     Rm_PolicyNode *node = NULL;
791     uint32_t       allocSize = 0;
793     /* Resource's CD allocation size is global at the moment so all policy
794      * tree nodes store the same value.  Just get the min node and return
795      * allocation size from it */
796     node = RB_MIN(_Rm_AllocatorPolicyTree, policyTree);
797     if (node) {
798         allocSize = node->cdAllocSize;
799     }
801     return(allocSize);
804 /* FUNCTION PURPOSE: Initializes the valid instance tree for a RM instance
805  ***********************************************************************
806  * DESCRIPTION: Creates the valid instance tree for a RM instance 
807  *              that has been provided a global or static policy
808  *              The valid instance tree is created from the
809  *              "valid-instances" property at the top of the Policy.
810  *              The root entry of the valid instance tree is returned.
811  */
812 Rm_PolicyValidInstTree *rmPolicyVInstTreeInit(Rm_Handle rmHandle,
813                                               void *policyDtb,
814                                               int addLinux,
815                                               int32_t *result)
817     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
818     int32_t                 validInstOffset;
819     const char             *validInstName = NULL;
820     int32_t                 validInstLen;
821     const void             *validInstData = NULL;
822     Rm_PolicyPropType       propertyType;
823     Rm_PolicyValidInst     *vInstListStart = NULL;
824     Rm_PolicyValidInst     *validInstList = NULL;
825     Rm_PolicyValidInstTree *rootEntry = NULL;
826     Rm_PolicyValidInstNode *newNode = NULL;
827     char                    linuxName[] = RM_ALLOCATED_TO_LINUX;
828     int32_t                 instIndex;
830     /* Valid instance list must be first and only property in the root node of
831      * the policyDtb */
832     validInstOffset = fdt_first_property_offset(policyDtb,
833                             RM_DTB_UTIL_STARTING_NODE_OFFSET);
834     if (validInstOffset < -FDT_ERR_NOTFOUND) {
835         *result = validInstOffset;
836         return(NULL);
837     }
839     if (validInstOffset == -FDT_ERR_NOTFOUND) {
840         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
841         return(NULL);
842     }
843     validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset,
844                                           &validInstName, &validInstLen);
845     propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
846     if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
847         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
848         return(NULL);
849     }
851     if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData,
852                                                                validInstLen,
853                                                                result))) {
854         return(NULL);
855     }
857     /* Create the tree */
858     rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
859     RB_INIT(rootEntry);
861     vInstListStart = validInstList;
862     /* Zeroeth index is reserved for global permissions */
863     instIndex = 1;
864     while (validInstList) {
865         newNode = rmPolicyValidInstNodeNew(validInstList->instName,
866                                            instIndex);
867         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
869         instIndex++;
870         validInstList = validInstList->nextValidInst;
871     }
872     rmDtbUtilPolicyFreeValidInstances(vInstListStart);
874     /* Add the Linux kernel node */
875     if (addLinux) {
876         newNode = rmPolicyValidInstNodeNew(linuxName, instIndex++);
877         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
878     }
880     /* Save the max index for proper accounting when validating against
881      * policy */
882     rmInst->maxInstIdx = instIndex;
884     *result = RM_OK;
885     return(rootEntry);
888 /* FUNCTION PURPOSE: Deletes a valid instance tree
889  ***********************************************************************
890  * DESCRIPTION: Frees all memory associated with a Policy valid
891  *              instance tree.
892  */
893 void rmPolicyVInstTreeDelete(Rm_Handle rmHandle)
895     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
896     Rm_PolicyValidInstTree *treeRoot = rmInst->validInstTree;
897     Rm_PolicyValidInstNode *node;
898     Rm_PolicyValidInstNode *nextNode;
900     if (treeRoot) {
901         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
902             rmPolicyValidInstTreeInv(treeRoot);
903         }
905         for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot);
906              node != NULL;
907              node = nextNode) {
908             nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node);
909             RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node);
910             rmPolicyValidInstNodeFree(node);
911         }
913         /* Don't need to writeback tree node changes since valid instance will
914          * be made NULL in instance */
916         if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) {
917             /* No more valid instance nodes in tree */
918             Rm_osalFree((void *)treeRoot, sizeof(treeRoot));
919         }
921         rmInst->validInstTree = NULL;
922     }
925 /* FUNCTION PURPOSE: Populates an allocator's policy tree
926  ***********************************************************************
927  * DESCRIPTION: Populates an allocator's policy tree using the policy
928  *              DTB
929  */
930 int32_t rmPolicyPopulateTree(Rm_Handle rmHandle, Rm_PolicyTree *policyTree,
931                              void *policyDtb, const char *resName)
933     Rm_Inst             *rmInst = (Rm_Inst *)rmHandle;
934     int32_t              resOffset;
935     uint32_t             allocAlignment;
936     uint32_t             cdAllocSize;
937     uint32_t             permBufSizeBytes = 0;
938     int32_t              propOffset;
939     const void          *propData;
940     const char          *propName;
941     int32_t              propLen;
942     Rm_PolicyAssignment *assign = NULL;
943     Rm_PolicyAssignment *assignStart = NULL;
944     Rm_PolicyNode       *polNode = NULL;
945     Rm_PolicyPermission *extractedPerms = NULL;
946     int32_t              retVal = RM_OK;
948     /* Offset of resource in policy DTB */
949     resOffset = policyGetDtbResourceOffset(policyDtb, resName);
950     if (resOffset < 0) {
951         retVal = resOffset;
952         goto errorExit;
953     }
955     /* Get the allocation alignment and the CD allocation size since these
956      * will be stored in each tree node */
957     allocAlignment = policyGetDtbAllocAlign(policyDtb, resOffset);
958     cdAllocSize = policyGetDtbCdAllocSize(policyDtb, resOffset);
959     permBufSizeBytes = policyGetPermBufSize(polNode->perms, rmInst->maxInstIdx);
961     /* Get the resource assignments - should only be one per resource node */
962     propOffset = fdt_first_property_offset(policyDtb, resOffset);
963     while (propOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
964         propData = fdt_getprop_by_offset(policyDtb, propOffset, &propName,
965                                          &propLen);
966         if (rmDtbUtilPolicyGetPropertyType(propName) ==
967             Rm_policyPropType_ASSIGNMENTS) {
968             assign = assignStart = rmDtbUtilPolicyExtractAssignments(propData,
969                                                                      propLen);
970             break;
971         }
972         propOffset = fdt_next_property_offset(policyDtb, propOffset);
973     }
975     /* Insert a new node into resource's allocator for each assignment range */
976     while (assign) {
977         polNode = rmPolicyNodeNew(assign->resourceBase,
978                                   assign->resourceLength);
979         polNode->allocAlign = allocAlignment;
980         polNode->cdAllocSize = cdAllocSize;
981         polNode->perms =  Rm_osalMalloc(permBufSizeBytes);
982         polNode->permsLen = permBufSizeBytes;
984         memset(polNode->perms, 0, polNode->permsLen);
986         extractedPerms = policyGetAssignmentPermissions(assign, &retVal);
987         if (retVal != RM_OK) {
988             goto errorExit;
989         }
991         retVal = policyStorePermissions(rmInst, polNode, extractedPerms);
992         if (retVal != RM_OK) {
993             goto errorExit;
994         }
995         RB_INSERT(_Rm_AllocatorPolicyTree, policyTree, polNode);
997         policyFreeAssignmentPermissions(extractedPerms);
998         extractedPerms = NULL;
999         polNode = NULL;
1001         assign = assign->nextAssignment;
1002     }
1004 errorExit:
1005     if (polNode) {
1006         rmPolicyNodeFree(polNode);
1007     }
1008     if (extractedPerms) {
1009         policyFreeAssignmentPermissions(extractedPerms);
1010     }
1011     if (assignStart) {
1012         rmDtbUtilPolicyFreeAssignments(assignStart);
1013     }
1015     return(retVal);