]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - src/rm_policy.c
NOTICE OF RELOCATION
[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 if ((*permStrPtr ==
242                             RM_POLICY_PERM_UNSPEC_EXCLUSION_LOWER) ||
243                            (*permStrPtr ==
244                             RM_POLICY_PERM_UNSPEC_EXCLUSION_UPPER)) {
245                     newPerm = startPerm;
246                     while (newPerm) {
247                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
248                         RM_policy_PERM_SET(pBits, 0, 0,
249                                       RM_POLICY_PERM_UNSPEC_EXCLUSION_SHIFT, 1);
250                         newPerm = newPerm->nextPermission;
251                     }
252                 } else {
253                     /* Invalid permission character.  This is a syntax error.
254                      * Free the permission list and the temporary string
255                      * and return. */
256                     *result = RM_ERROR_PERM_STR_INVALID_CHAR;
257                     goto parseError;
258                 }
259             } else {
260                 /* Character found without the assignment character being found.
261                  * This is a syntax error.  Free the permission list and the
262                  * temporary string and return. */
263                 *result = RM_ERROR_PERM_CHAR_WITHOUT_ASSIGN_CHAR;
264                 goto parseError;
265             }
266         }
267         permStrPtr--;
268     }
270     /* Look on right of instance group for permission assignments. */
271     permStrPtr = subgroupEnd + 1;
272     assignmentRight = RM_FALSE;
273     while (permStrPtr < permStrEnd) {
274         if (assignmentLeft && (!isspace(*permStrPtr))) {
275             /* There should be nothing but spaces on right if assignment was
276              * already found on left */
277             *result = RM_ERROR_INVALID_PERMS_CHAR_ON_RIGHT;
278             goto parseError;
279         }
281         if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
282             if (assignmentRight) {
283                 /* Assignment character has been found more than once.  This is
284                  * a syntax error.  Free the permission list and the temporary
285                  * string and return. */
286                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
287                 goto parseError;
288             } else {
289                 assignmentRight = RM_TRUE;
290             }
291         } else if (!isspace(*permStrPtr)) {
292             if (assignmentRight) {
293                 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) ||
294                     (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
295                     newPerm = startPerm;
296                     while (newPerm) {
297                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
298                         RM_policy_PERM_SET(pBits, 0, 0,
299                                            RM_POLICY_PERM_INIT_SHIFT, 1);
300                         newPerm = newPerm->nextPermission;
301                     }
302                 } else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) ||
303                          (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
304                     newPerm = startPerm;
305                     while (newPerm) {
306                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
307                         RM_policy_PERM_SET(pBits, 0, 0,
308                                            RM_POLICY_PERM_USE_SHIFT, 1);
309                         newPerm = newPerm->nextPermission;
310                     }
311                 } else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) ||
312                          (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
313                     newPerm = startPerm;
314                     while (newPerm) {
315                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
316                         RM_policy_PERM_SET(pBits, 0, 0,
317                                            RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
318                         newPerm = newPerm->nextPermission;
319                     }
320                 } else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) ||
321                          (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
322                     newPerm = startPerm;
323                     while (newPerm) {
324                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
325                         RM_policy_PERM_SET(pBits, 0, 0,
326                                            RM_POLICY_PERM_SHARED_LINUX_SHIFT,
327                                            1);
328                         newPerm = newPerm->nextPermission;
329                     }
330                 } else if ((*permStrPtr ==
331                             RM_POLICY_PERM_UNSPEC_EXCLUSION_LOWER) ||
332                            (*permStrPtr ==
333                             RM_POLICY_PERM_UNSPEC_EXCLUSION_UPPER)) {
334                     newPerm = startPerm;
335                     while (newPerm) {
336                         Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
337                         RM_policy_PERM_SET(pBits, 0, 0,
338                                       RM_POLICY_PERM_UNSPEC_EXCLUSION_SHIFT, 1);
339                         newPerm = newPerm->nextPermission;
340                     }
341                 } else {
342                     /* Invalid permission character.  This is a syntax error.
343                      * Free the permission list and the temporary string
344                      * and return. */
345                     *result = RM_ERROR_PERM_STR_INVALID_CHAR;
346                     goto parseError;
347                 }
348             } else {
349                 /* Character found without the assignment character being found.
350                  * This is a syntax error.  Free the permission list and the
351                  * temporary string and return. */
352                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
353                 goto parseError;
354             }
355         }
356         permStrPtr++;
357     }
359     Rm_osalFree((void *)permStrStart, permStrLen);
360     *result = RM_OK;
361     return (startPerm);
363 parseError:
364     while (startPerm) {
365         nextPerm = startPerm->nextPermission;
366         Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
367         startPerm = nextPerm;
368     }
369     Rm_osalFree((void *)permStrStart, permStrLen);
370     return(NULL);
373 /* FUNCTION PURPOSE: Frees a linked list of assignment permissions
374  ***********************************************************************
375  * DESCRIPTION: Frees the memory associated with a linked list of
376  *              assignment permissions extracted from a permissions
377  *              assignment subgroup in a policy DTB.
378  */
379 static void policyFreeAssignmentPermissions(Rm_PolicyPermission *permissionList)
381     Rm_PolicyPermission *nextPerm;
383     while (permissionList) {
384         nextPerm = permissionList->nextPermission;
385         Rm_osalFree((void *)permissionList, sizeof(Rm_PolicyPermission));
386         permissionList = nextPerm;
387     }
390 /* FUNCTION PURPOSE: Extracts permissions from a Policy "assignment"
391  ***********************************************************************
392  * DESCRIPTION: Returns a linked list of permissions for a resource node
393  *              containing an "assignment" property in the Policy DTB.
394  *              Each node in the linked list will contain a valid instance
395  *              name along with the permissions assigned to the instance
396  */
397 static Rm_PolicyPermission *policyGetAssignmentPermissions(Rm_PolicyAssignment *assignment,
398                                                            int32_t *result)
400     Rm_PolicyPermission *startPerm = NULL;
401     Rm_PolicyPermission *newPerm = NULL;
402     Rm_PolicyPermission *prevPerm = NULL;
403     char                *permStrStart = assignment->permissionsList;
404     char                *permStrEnd;
405     uint32_t             permStrLen = strlen(assignment->permissionsList) + 1;
406     uint32_t             i = 0;
408     *result = RM_OK;
410     while(i < permStrLen) {
411         /* Find the first sub-permission specification and parse it.  A
412          * sub-permission can be terminated by the termination character or the
413          * end of the string. */
414         if (!(permStrEnd = strchr(permStrStart, RM_POLICY_PERM_TERMINATOR))) {
415             /* Sub-permission termination character not found.  The permission
416              * string end is the end of the entire permission string */
417             permStrEnd = permStrStart + strlen(permStrStart);
418         }
420         newPerm = policyParseSubPermission(permStrStart, permStrEnd, result);
422         if (*result != RM_OK) {
423             /* Delete the permission list that's been created thus far, return
424              * the error and NULL for the permission list */
425             policyFreeAssignmentPermissions(startPerm);
426             return(NULL);
427         }
429         if (prevPerm == NULL) {
430             startPerm = newPerm;
431         } else {
432             prevPerm->nextPermission = newPerm;
433         }
435         /* Set prevPerm to the last sub-permission returned by the
436          * sub-permission parser */
437         prevPerm = newPerm;
438         while(prevPerm->nextPermission != NULL) {
439             prevPerm = prevPerm->nextPermission;
440         }
442         /* Update the number of characters parsed from the permission list and
443          * point to the start of the next sub-permission */
444         i += ((uint32_t)(permStrEnd - permStrStart + 1));
445         permStrStart = permStrEnd + 1;
446     }
448     return(startPerm);
451 /* FUNCTION PURPOSE: Returns number of bytes needed to store permissions
452  ***********************************************************************
453  * DESCRIPTION: Calculates and returns the number of bytes needed to store
454  *              permissions for all valid instances.  Words are packed
455  *              with permissions for as many instances as can fit
456  */
457 static uint32_t policyGetPermBufSize(uint32_t maxValidInst)
459     uint32_t instPerWord;
460     uint32_t numWords;
461     uint32_t totalBytes = 0;
463     instPerWord = RM_policy_PERM_INST_PER_WORD;
464     /* Round up */
465     numWords = (maxValidInst + instPerWord - 1) / instPerWord;
467     totalBytes = sizeof(Rm_PolicyPermBits) * numWords;
468     return(totalBytes);
471 /* FUNCTION PURPOSE: Stores policy permissions in a policy tree node
472  ***********************************************************************
473  * DESCRIPTION: Parses permissions and stores them in a word array in a
474  *              compacted format.  The array is attached to the resource's
475  *              policy tree node.
476  */
477 static int32_t policyStorePermissions(Rm_Inst *rmInst, Rm_PolicyNode *polNode,
478                                       Rm_PolicyPermission *extractedPerms)
480     Rm_PolicyValidInstNode *vInst = NULL;
481     uint32_t                instIdx;
482     uint32_t                wordIndex;
483     uint32_t                wordOffset;
484     int32_t                 retVal = RM_OK;
486     while (extractedPerms) {
487         if (!strncmp(extractedPerms->instName, Rm_policyGlobalInst,
488                      RM_NAME_MAX_CHARS)) {
489             instIdx = RM_POLICY_GLOBAL_PERM_INDEX;
490         } else if ((vInst = rmPolicyGetValidInstNode((Rm_Handle)rmInst,
491                                                    extractedPerms->instName))) {
492             instIdx = vInst->instIdx;
493         } else {
494             retVal = RM_ERROR_PERM_STR_INST_NOT_VALID;
495             goto errorExit;
496         }
498         /* Calculate word index into policy node's permission array
499          * for the instance index */
500         wordIndex  = RM_policy_PERM_INDEX(instIdx);
501         wordOffset = RM_policy_PERM_OFFSET(instIdx);
503         polNode->perms[wordIndex] |= ((extractedPerms->permissionBits &
504                                       RM_policy_PERM_FULL_MASK) << wordOffset);
506         extractedPerms = extractedPerms->nextPermission;
507     }
509 errorExit:
510     return(retVal);
513 /* FUNCTION PURPOSE: Returns resource's allocation alignment from policy
514  ***********************************************************************
515  * DESCRIPTION: Parses the policy DTB to find and return a resource's 
516  *              allocation alignment.
517  */
518 static uint32_t policyGetDtbAllocAlign(void *policyDtb, int32_t resourceOffset)
520     int32_t           offset;
521     const char       *name;
522     int32_t           len;
523     const void       *data;
524     Rm_ResourceValue *alignList = NULL;
525     uint32_t          align = 0;
527     offset = fdt_first_property_offset(policyDtb, resourceOffset);
528     while (offset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
529         data = fdt_getprop_by_offset(policyDtb, offset, &name, &len);
530         if (rmDtbUtilPolicyGetPropertyType(name) ==
531             Rm_policyPropType_ALLOCATION_ALIGNMENT) {
532             alignList = rmDtbUtilPolicyExtractResourceAlignments(data, len);
533             align = alignList->value;
534             break;
535         }
536         offset = fdt_next_property_offset(policyDtb, offset);
537     }
539     if (alignList) {
540         rmDtbUtilPolicyFreeResourceAlignments(alignList);
541     }
543     if (align == 0) {
544         align = 1;
545     }
546     return(align);
549 /* FUNCTION PURPOSE: Returns resource CD allocation size defined in policy
550  ***********************************************************************
551  * DESCRIPTION: Parses the policy DTB to find and return a resource's 
552  *              allocation size.
553  */
554 static uint32_t policyGetDtbCdAllocSize(void *policyDtb, int32_t resourceOffset)
556     int32_t           offset;
557     const char       *name;
558     int32_t           len;
559     const void       *data;
560     Rm_ResourceValue *allocSizeList = NULL;
561     uint32_t          allocSize = 0;
563     offset = fdt_first_property_offset(policyDtb, resourceOffset);
564     while (offset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
565         data = fdt_getprop_by_offset(policyDtb, offset, &name, &len);
566         if (rmDtbUtilPolicyGetPropertyType(name) ==
567             Rm_policyPropType_CD_ALLOCATION_SIZE) {
568             allocSizeList = rmDtbUtilPolicyExtractCdAllocationSizes(data, len);
569             allocSize = allocSizeList->value;
570             break;
571         }
572         offset = fdt_next_property_offset(policyDtb, offset);
573     }
575     if (allocSizeList) {
576         rmDtbUtilPolicyFreeCdAllocationSizes(allocSizeList);
577     }
578     return(allocSize);
581 /* FUNCTION PURPOSE: Get a resource's offset into a policy
582  ***********************************************************************
583  * DESCRIPTION: Returns the location of the specified resource node
584  *              within the specified Policy in the form of an offset
585  *              into the DTB.  The resourceName and the Policy
586  *              node name must match.
587  */
588 static int32_t policyGetDtbResourceOffset(void *policyDtb,
589                                           const char *resourceName)
591     int32_t     nodeOffset;
592     int32_t     depth;
593     const char *nodeName;
595     if (policyDtb) {
596         depth = RM_DTB_UTIL_STARTING_DEPTH;
597         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
599         /* Find node offset for provided resource name */
600         while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
601             nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
602             if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
603                 /* Resource name not found */
604                 nodeOffset = RM_ERROR_RES_DOES_NOT_EXIST_IN_POLICY;
605                 break;
606             } else {
607                 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
608                 if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0) {
609                     break;
610                 }
611             }
612         }
613     } else {
614         nodeOffset = RM_ERROR_INSTANCE_HAS_NO_POLICY;
615     }
616     return(nodeOffset);
619 /**********************************************************************
620  ************************ Internal Policy APIs ************************
621  **********************************************************************/
623 /* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree
624  ***********************************************************************
625  * DESCRIPTION: Returns a valid instance node from the valid instance
626  *              tree that matches the specified instName
627  */
628 Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_Handle rmHandle,
629                                                  const char *instName)
631     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
632     Rm_PolicyValidInstTree *treeRoot = rmInst->validInstTree;
633     Rm_PolicyValidInstNode  findNode;
635     rm_strncpy(findNode.name, instName, RM_NAME_MAX_CHARS);
636     return(RB_FIND(_Rm_PolicyValidInstTree, treeRoot, &findNode));
639 /* FUNCTION PURPOSE: Gets the Linux Valid instance node
640  ***********************************************************************
641  * DESCRIPTION: Returns a pointer to the valid instance node in the
642  *              valid instance tree that matches the instance name
643  *              reserved for resource assigned to the Linux kernel.
644  */
645 Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_Handle rmHandle)
647     const char linuxName[] = RM_ALLOCATED_TO_LINUX;
649     return(rmPolicyGetValidInstNode(rmHandle, linuxName));
652 /* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB
653  ***********************************************************************
654  * DESCRIPTION: Returns TRUE if the instance name has the specified
655  *              permissions for the specified resource in the Policy
656  *              DTB.  Otherwise, returns FALSE.
657  */
658 int32_t rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg)
660     uint32_t       permShift;
661     uint32_t       globPermIdx;
662     uint32_t       globPermOffset;
663     uint32_t       instPermIdx;
664     uint32_t       instPermOffset;
665     Rm_PolicyNode  findNode;
666     Rm_PolicyNode *matchNode = NULL;
667     uint32_t       findEnd;
668     uint32_t       matchEnd;
669     int32_t        isApproved = RM_FALSE;
671     switch (privilegeCfg->type) {
672         case Rm_policyCheck_INIT:
673             permShift = RM_POLICY_PERM_INIT_SHIFT;
674             break;
675         case Rm_policyCheck_USE:
676             permShift = RM_POLICY_PERM_USE_SHIFT;
677             break;
678         case Rm_policyCheck_EXCLUSIVE:
679             permShift = RM_POLICY_PERM_EXCLUSIVE_SHIFT;
680             break;
681         case Rm_policyCheck_SHARED_LINUX:
682             permShift = RM_POLICY_PERM_SHARED_LINUX_SHIFT;
683             break;
684         case Rm_policyCheck_UNSPEC_EXCLUSION:
685             permShift = RM_POLICY_PERM_UNSPEC_EXCLUSION_SHIFT;
686             break;
687         default:
688             return(isApproved);
689     }
691     /* Calculate the word indices and offsets for the global permissions and
692      * the specific instance */
693     globPermIdx    = RM_policy_PERM_INDEX(RM_POLICY_GLOBAL_PERM_INDEX);
694     globPermOffset = RM_policy_PERM_OFFSET(RM_POLICY_GLOBAL_PERM_INDEX);
695     instPermIdx    = RM_policy_PERM_INDEX(privilegeCfg->validInstNode->instIdx);
696     instPermOffset = RM_policy_PERM_OFFSET(privilegeCfg->validInstNode->instIdx);
698     memset((void *)&findNode, 0, sizeof(findNode));
699     findNode.base = privilegeCfg->resourceBase;
700     findNode.len  = privilegeCfg->resourceLength;
701     /* Get first matching node. */
702     matchNode = RB_FIND(_Rm_AllocatorPolicyTree, privilegeCfg->polTree,
703                         &findNode);
704     if (matchNode) {
705         /* Request range may not be completely contained within the first
706          * matching node.  Find furthest left matching node for the request
707          * range */
708         while (findNode.base < matchNode->base) {
709             matchNode = RB_PREV(_Rm_AllocatorPolicyTree,
710                                 privilegeCfg->polTree, matchNode);
711         }
712     }
714     /* Check permissions across all policy nodes which the request range
715      * spans.  Assume approved until denial found */
716     isApproved = RM_TRUE;
717     while (matchNode) {
718         if (privilegeCfg->negCheck) {
719             /* Not approved if any matching node is assigned an exclusion
720              * permission */
721             if ((RM_policy_PERM_GET(matchNode->perms, globPermIdx,
722                                     globPermOffset, permShift)) ||
723                 (RM_policy_PERM_GET(matchNode->perms, instPermIdx,
724                                     instPermOffset, permShift))) {
725                 isApproved = RM_FALSE;
726                 break;
727             }
728         } else {
729             /* Not approved if any matching node does not have permission */
730             if ((!RM_policy_PERM_GET(matchNode->perms, globPermIdx,
731                                      globPermOffset, permShift)) &&
732                 (!RM_policy_PERM_GET(matchNode->perms, instPermIdx,
733                                      instPermOffset, permShift))) {
734                 isApproved = RM_FALSE;
735                 break;
736             }
737         }
739         matchEnd = matchNode->base + matchNode->len - 1;
740         findEnd  = findNode.base + findNode.len - 1;
742         /* Check node to right if request range spans matching node to right */
743         if (findEnd > matchEnd) {
744             matchNode = RB_NEXT(_Rm_AllocatorPolicyTree, privilegeCfg->polTree,
745                                 matchNode);
746             if (matchNode == NULL) {
747                 /* Request range outspans actual resource range */
748                 isApproved = RM_FALSE;
749             }
750         } else {
751             break;
752         }
753     }
755     return(isApproved);
758 /* FUNCTION PURPOSE: Returns resource base value according to the Policy
759  ***********************************************************************
760  * DESCRIPTION: Returns a resource base value based on the resource
761  *              ranges assigned to the specified valid instance by the
762  *              Policy DTB.
763  */
764 int32_t rmPolicyGetResourceBase(Rm_PolicyTree *policyTree,
765                                  Rm_PolicyValidInstNode *validInstNode,
766                                  Rm_PolicyCheckType checkType,
767                                  int32_t *resBase)
769     uint32_t       permShift = RM_POLICY_PERM_INIT_SHIFT;
770     uint32_t       globPermIdx;
771     uint32_t       globPermOffset;
772     uint32_t       instPermIdx;
773     uint32_t       instPermOffset;
774     Rm_PolicyNode *polNode;
776     *resBase = RM_RESOURCE_BASE_UNSPECIFIED;
778     if (checkType == Rm_policyCheck_INIT) {
779         permShift = RM_POLICY_PERM_INIT_SHIFT;
780     } else if (checkType == Rm_policyCheck_USE) {
781         permShift = RM_POLICY_PERM_USE_SHIFT;
782     } else {
783         return(RM_ERROR_INVALID_SERVICE_TYPE);
784     }
786     /* Calculate the word indices and offsets for the global permissions and
787      * the specific instance */
788     globPermIdx    = RM_policy_PERM_INDEX(RM_POLICY_GLOBAL_PERM_INDEX);
789     globPermOffset = RM_policy_PERM_OFFSET(RM_POLICY_GLOBAL_PERM_INDEX);
790     instPermIdx    = RM_policy_PERM_INDEX(validInstNode->instIdx);
791     instPermOffset = RM_policy_PERM_OFFSET(validInstNode->instIdx);
793     RB_FOREACH(polNode, _Rm_AllocatorPolicyTree, policyTree) {
794         if (RM_policy_PERM_GET(polNode->perms, globPermIdx, globPermOffset,
795                                permShift) ||
796             RM_policy_PERM_GET(polNode->perms, instPermIdx, instPermOffset,
797                                permShift)) {
798             *resBase = polNode->base;
799             break;
800         }
801     }
803     if (*resBase == RM_RESOURCE_BASE_UNSPECIFIED) {
804         return(RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET);
805     }
807     return(RM_OK);
810 /* FUNCTION PURPOSE: Returns resource's allocation alignment
811  ***********************************************************************
812  * DESCRIPTION: Returns a resource's allocation alignment.
813  */
814 uint32_t rmPolicyGetAllocAlign(Rm_PolicyTree *policyTree)
816     Rm_PolicyNode *node = NULL;
817     uint32_t       align = 1;
819     /* Resource's alignment is global at the moment so all policy tree nodes
820      * store the same value.  Just get the min node and return the allocation
821      * alignment from it */
822     node = RB_MIN(_Rm_AllocatorPolicyTree, policyTree);
823     if (node) {
824         align = node->allocAlign;
825     }
827     return(align);
830 /* FUNCTION PURPOSE: Returns resource's CD allocation size
831  ***********************************************************************
832  * DESCRIPTION: Returns a resource's CD allocation size.
833  */
834 uint32_t rmPolicyGetCdAllocSize(Rm_PolicyTree *policyTree)
836     Rm_PolicyNode *node = NULL;
837     uint32_t       allocSize = 0;
839     /* Resource's CD allocation size is global at the moment so all policy
840      * tree nodes store the same value.  Just get the min node and return
841      * allocation size from it */
842     node = RB_MIN(_Rm_AllocatorPolicyTree, policyTree);
843     if (node) {
844         allocSize = node->cdAllocSize;
845     }
847     return(allocSize);
850 /* FUNCTION PURPOSE: Initializes the valid instance tree for a RM instance
851  ***********************************************************************
852  * DESCRIPTION: Creates the valid instance tree for a RM instance 
853  *              that has been provided a global or static policy
854  *              The valid instance tree is created from the
855  *              "valid-instances" property at the top of the Policy.
856  *              The root entry of the valid instance tree is returned.
857  */
858 Rm_PolicyValidInstTree *rmPolicyVInstTreeInit(Rm_Handle rmHandle,
859                                               void *policyDtb,
860                                               int addLinux,
861                                               int32_t *result)
863     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
864     int32_t                 validInstOffset;
865     const char             *validInstName = NULL;
866     int32_t                 validInstLen;
867     const void             *validInstData = NULL;
868     Rm_PolicyPropType       propertyType;
869     Rm_PolicyValidInst     *vInstListStart = NULL;
870     Rm_PolicyValidInst     *validInstList = NULL;
871     Rm_PolicyValidInstTree *rootEntry = NULL;
872     Rm_PolicyValidInstNode *newNode = NULL;
873     char                    linuxName[] = RM_ALLOCATED_TO_LINUX;
874     int32_t                 instIndex;
876     /* Valid instance list must be first and only property in the root node of
877      * the policyDtb */
878     validInstOffset = fdt_first_property_offset(policyDtb,
879                             RM_DTB_UTIL_STARTING_NODE_OFFSET);
880     if (validInstOffset < -FDT_ERR_NOTFOUND) {
881         *result = validInstOffset;
882         return(NULL);
883     }
885     if (validInstOffset == -FDT_ERR_NOTFOUND) {
886         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
887         return(NULL);
888     }
889     validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset,
890                                           &validInstName, &validInstLen);
891     propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
892     if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
893         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
894         return(NULL);
895     }
897     if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData,
898                                                                validInstLen,
899                                                                result))) {
900         return(NULL);
901     }
903     /* Create the tree */
904     rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
905     RB_INIT(rootEntry);
907     vInstListStart = validInstList;
908     /* Zeroeth index is reserved for global permissions */
909     instIndex = 1;
910     while (validInstList) {
911         newNode = rmPolicyValidInstNodeNew(validInstList->instName,
912                                            instIndex);
913         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
915         instIndex++;
916         validInstList = validInstList->nextValidInst;
917     }
918     rmDtbUtilPolicyFreeValidInstances(vInstListStart);
920     /* Add the Linux kernel node */
921     if (addLinux) {
922         newNode = rmPolicyValidInstNodeNew(linuxName, instIndex++);
923         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
924     }
926     /* Save the max index for proper accounting when validating against
927      * policy */
928     rmInst->maxInstIdx = instIndex;
930     *result = RM_OK;
931     return(rootEntry);
934 /* FUNCTION PURPOSE: Deletes a valid instance tree
935  ***********************************************************************
936  * DESCRIPTION: Frees all memory associated with a Policy valid
937  *              instance tree.
938  */
939 void rmPolicyVInstTreeDelete(Rm_Handle rmHandle)
941     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
942     Rm_PolicyValidInstTree *treeRoot = rmInst->validInstTree;
943     Rm_PolicyValidInstNode *node;
944     Rm_PolicyValidInstNode *nextNode;
946     if (treeRoot) {
947         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
948             rmPolicyValidInstTreeInv(treeRoot);
949         }
951         for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot);
952              node != NULL;
953              node = nextNode) {
954             nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node);
955             RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node);
956             rmPolicyValidInstNodeFree(node);
957         }
959         /* Don't need to writeback tree node changes since valid instance will
960          * be made NULL in instance */
962         if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) {
963             /* No more valid instance nodes in tree */
964             Rm_osalFree((void *)treeRoot, sizeof(treeRoot));
965         }
967         rmInst->validInstTree = NULL;
968     }
971 /* FUNCTION PURPOSE: Populates an allocator's policy tree
972  ***********************************************************************
973  * DESCRIPTION: Populates an allocator's policy tree using the policy
974  *              DTB
975  */
976 int32_t rmPolicyPopulateTree(Rm_Handle rmHandle, Rm_PolicyTree *policyTree,
977                              void *policyDtb, const char *resName)
979     Rm_Inst             *rmInst = (Rm_Inst *)rmHandle;
980     int32_t              resOffset;
981     uint32_t             allocAlignment;
982     uint32_t             cdAllocSize;
983     uint32_t             permBufSizeBytes = 0;
984     int32_t              propOffset;
985     const void          *propData;
986     const char          *propName;
987     int32_t              propLen;
988     Rm_PolicyAssignment *assign = NULL;
989     Rm_PolicyAssignment *assignStart = NULL;
990     Rm_PolicyNode       *polNode = NULL;
991     Rm_PolicyPermission *extractedPerms = NULL;
992     int32_t              retVal = RM_OK;
994     /* Offset of resource in policy DTB */
995     resOffset = policyGetDtbResourceOffset(policyDtb, resName);
996     if (resOffset < 0) {
997         retVal = resOffset;
998         goto errorExit;
999     }
1001     /* Get the allocation alignment and the CD allocation size since these
1002      * will be stored in each tree node */
1003     allocAlignment = policyGetDtbAllocAlign(policyDtb, resOffset);
1004     cdAllocSize = policyGetDtbCdAllocSize(policyDtb, resOffset);
1005     permBufSizeBytes = policyGetPermBufSize(rmInst->maxInstIdx);
1007     /* Get the resource assignments - should only be one per resource node */
1008     propOffset = fdt_first_property_offset(policyDtb, resOffset);
1009     while (propOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1010         propData = fdt_getprop_by_offset(policyDtb, propOffset, &propName,
1011                                          &propLen);
1012         if (rmDtbUtilPolicyGetPropertyType(propName) ==
1013             Rm_policyPropType_ASSIGNMENTS) {
1014             assign = assignStart = rmDtbUtilPolicyExtractAssignments(propData,
1015                                                                      propLen);
1016             break;
1017         }
1018         propOffset = fdt_next_property_offset(policyDtb, propOffset);
1019     }
1021     /* Insert a new node into resource's allocator for each assignment range */
1022     while (assign) {
1023         polNode = rmPolicyNodeNew(assign->resourceBase,
1024                                   assign->resourceLength);
1025         polNode->allocAlign = allocAlignment;
1026         polNode->cdAllocSize = cdAllocSize;
1027         polNode->perms =  Rm_osalMalloc(permBufSizeBytes);
1028         polNode->permsLen = permBufSizeBytes;
1030         memset(polNode->perms, 0, polNode->permsLen);
1032         extractedPerms = policyGetAssignmentPermissions(assign, &retVal);
1033         if (retVal != RM_OK) {
1034             goto errorExit;
1035         }
1037         retVal = policyStorePermissions(rmInst, polNode, extractedPerms);
1038         if (retVal != RM_OK) {
1039             goto errorExit;
1040         }
1041         RB_INSERT(_Rm_AllocatorPolicyTree, policyTree, polNode);
1043         policyFreeAssignmentPermissions(extractedPerms);
1044         extractedPerms = NULL;
1045         polNode = NULL;
1047         assign = assign->nextAssignment;
1048     }
1050 errorExit:
1051     if (polNode) {
1052         rmPolicyNodeFree(polNode);
1053     }
1054     if (extractedPerms) {
1055         policyFreeAssignmentPermissions(extractedPerms);
1056     }
1057     if (assignStart) {
1058         rmDtbUtilPolicyFreeAssignments(assignStart);
1059     }
1061     return(retVal);