8544ae84126d5b64abf48d05281bca0ea287f485
[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_policyAllInstances[] = "*";
72 /**********************************************************************
73  ******************** Local Policy Functions **************************
74  **********************************************************************/
76 /* FUNCTION PURPOSE: Returns a pointer to the valid instance tree
77  ***********************************************************************
78  * DESCRIPTION: Returns a pointer to the instance's valid instance
79  *              tree based on the instance type
80  */
81 static Rm_PolicyValidInstTree *policyGetValidInstTree(Rm_Handle rmHandle)
82 {
83     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
84     Rm_PolicyValidInstTree *tree = NULL;
86     if ((rmInst->instType == Rm_instType_SERVER) ||
87         (rmInst->instType == Rm_instType_SHARED_SERVER)) {
88         tree = rmInst->u.server.globalValidInstTree;
89     }
90     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
91         tree = rmInst->u.cd.cdValidInstTree;
92     }
93     else if (rmInst->instType == Rm_instType_CLIENT) {
94         tree = rmInst->u.client.staticValidInstTree;
95     }
96     return(tree);
97 }
99 /* FUNCTION PURPOSE: Validates the instance names in a permissions string
100  ***********************************************************************
101  * DESCRIPTION: Returns RM_OK if all the instance names in a permissions
102  *              string match instance names defined in the valid instance
103  *              list.  RM_ERROR_PERM_STR_INST_NOT_VALID is returned if
104  *              there are any mismatches
105  */
106 static int32_t policyCheckInstances(Rm_Handle rmHandle, Rm_PolicyPermission *permissionsList)
108     while (permissionsList) {
109         if (strncmp(permissionsList->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) &&
110             (!rmPolicyGetValidInstNode(rmHandle, permissionsList->instName))) {
111             return(RM_ERROR_PERM_STR_INST_NOT_VALID);
112         }
113         permissionsList = permissionsList->nextPermission;
114     }
115     return(RM_OK);
118 /* FUNCTION PURPOSE: Parses a permissions subgroup
119  ***********************************************************************
120  * DESCRIPTION: Returns a linked list of policy permissions defining
121  *              which RM instance referenced in the permissions subgroup
122  *              get which permissions.  Returns NULL if any syntax
123  *              errors are encountered during the parsing.  The error
124  *              is returned via the result pointer parameter.
125  */
126 static Rm_PolicyPermission *policyParseSubPermission(char *permStrStart, char *permStrEnd, 
127                                                      int32_t *result)
129     Rm_PolicyPermission *startPerm = NULL;
130     Rm_PolicyPermission *newPerm = NULL;
131     Rm_PolicyPermission *prevPerm = NULL;
132     Rm_PolicyPermission *nextPerm = NULL;
133     char                *permStrPtr = NULL;
134     char                *subgroupStart = NULL;
135     char                *subgroupEnd = NULL;
136     uint32_t             permStrLen = (uint32_t)(permStrEnd - permStrStart + 1);
137     char                 instNameTemp[RM_NAME_MAX_CHARS];
138     uint32_t             instNameIndex;
139     int                  foundInstName;
140     int                  instNameComplete;
141     int                  assignmentLeft;
142     int                  assignmentRight;
144     /* Create a local copy of the sub-permission string */
145     permStrPtr = Rm_osalMalloc(permStrLen);
146     rm_strncpy(permStrPtr, permStrStart, permStrLen);
148     permStrStart = permStrPtr;
149     permStrEnd = permStrPtr + strlen(permStrPtr);
151     /* Find the beginning and end of the sub-permission instance group */
152     subgroupStart = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START);
153     subgroupEnd = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END);
155     if ((!subgroupStart) || (!subgroupEnd) || (subgroupStart > subgroupEnd) ||
156         ((subgroupStart != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START)) &&
157          (subgroupEnd != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END)))) {
158         /* Free the memory associated with the temp string and return an error if:
159          * a) Could not find the instance group start
160          * b) Could not find the instance group end
161          * c) Subgroup start and end are out of order
162          * d) There is more than one instance subgroup specified in the string.  There
163          *    should only be one subgroup per sub-permission string */
164         *result = RM_ERROR_PERM_STR_TOO_MANY_INST_GROUPS;
165         goto parseError;
166     }
168     /* Create a permission entry for each instance specified in the instance group.
169      * Instances names are separated by one or more spaces. */
170     permStrPtr = subgroupStart + 1;
171     instNameIndex = 0;
172     foundInstName = RM_FALSE;
173     instNameComplete = RM_FALSE;
174     while (permStrPtr <= subgroupEnd) {
175         if ((isspace(*permStrPtr) || (*permStrPtr == RM_POLICY_PERM_SUBGROUP_END))
176             && foundInstName) {
177             /* First space encountered after copying an instance name.  This
178              * terminates the instance name.  All other space characters are
179              * ignored. */
180             instNameTemp[instNameIndex] = '\0';
181             instNameComplete = RM_TRUE; 
182         }
183         else {
184             if (!foundInstName) {
185                 /* First non-whitespace character encountered is the start of an
186                  * instance name */
187                 foundInstName = RM_TRUE;
188             }
190             /* Copy the character into the temporary instance name string */
191             instNameTemp[instNameIndex++] = *permStrPtr;
192         }
194         if (instNameComplete) {
195             newPerm = (Rm_PolicyPermission *) Rm_osalMalloc(sizeof(Rm_PolicyPermission));
196             memset((void *)newPerm, 0, sizeof(Rm_PolicyPermission));
198             rm_strncpy(newPerm->instName, instNameTemp, RM_NAME_MAX_CHARS);
199             newPerm->nextPermission = NULL;
201             if (prevPerm == NULL) {
202                 /* Save the first instance so it can be returned */
203                 startPerm = newPerm;
204             }
205             else {
206                 prevPerm->nextPermission = newPerm;
207             }
208             prevPerm = newPerm;
210             instNameComplete = RM_FALSE;
211             instNameIndex = 0;
212             foundInstName = RM_FALSE;
213         }
214         else if (instNameIndex == RM_NAME_MAX_CHARS) {
215             /* Instance name is longer than max length */
216             *result = RM_ERROR_INST_NAME_IN_ASSIGNMENT_TOO_LONG;
217             goto parseError;
218         }
220         permStrPtr++;
221     }
223     /* Fill in the permissions for each instance name */
225     /* Look on left of instance group for permission assignments. */
226     permStrPtr = subgroupStart - 1;
227     assignmentLeft = RM_FALSE;
228     while (permStrPtr >= permStrStart)
229     {
230         if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
231             if (assignmentLeft) {
232                 /* Assignment character has been found more than once.  This is a
233                  * syntax error.  Free the permission list and the temporary string
234                  * and return. */
235                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
236                 goto parseError;
237             }
238             else {
239                 assignmentLeft = RM_TRUE;
240             }
241         }
242         else if (!isspace(*permStrPtr)) {
243             if (assignmentLeft) {
244                 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) || 
245                     (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
246                     newPerm = startPerm;
247                     while (newPerm) {
248                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1);
249                         newPerm = newPerm->nextPermission;
250                     }
251                 }
252                 else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) || 
253                          (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
254                     newPerm = startPerm;
255                     while (newPerm) {                                           
256                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1);
257                         newPerm = newPerm->nextPermission;
258                     }
259                 }
260                 else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) || 
261                          (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
262                     newPerm = startPerm;
263                     while (newPerm) {                       
264                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
265                         newPerm = newPerm->nextPermission;
266                     }
267                 }
268                 else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) || 
269                          (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
270                     newPerm = startPerm;
271                     while (newPerm) {                       
272                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1);
273                         newPerm = newPerm->nextPermission;
274                     }
275                 }                
276                 else {
277                     /* Invalid permission character.  This is a
278                      * syntax error.  Free the permission list and the temporary string
279                      * and return. */
280                     *result = RM_ERROR_PERM_STR_INVALID_CHAR;
281                     goto parseError;
282                 }
283             }
284             else {
285                 /* Character found without the assignment character being found.  This is a
286                  * syntax error.  Free the permission list and the temporary string
287                  * and return. */
288                 *result = RM_ERROR_PERM_CHAR_WITHOUT_ASSIGN_CHAR;
289                 goto parseError;
290             }
291         }
292         permStrPtr--;
293     }
295     /* Look on right of instance group for permission assignments. */
296     permStrPtr = subgroupEnd + 1;
297     assignmentRight = RM_FALSE;
298     while (permStrPtr < permStrEnd) {
299         if (assignmentLeft && (!isspace(*permStrPtr))) {
300             /* There should be nothing but spaces on right if assignment was already found on left */
301             *result = RM_ERROR_INVALID_PERMS_CHAR_ON_RIGHT;
302             goto parseError;             
303         }
304         
305         if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
306             if (assignmentRight) {
307                 /* Assignment character has been found more than once.  This is a
308                  * syntax error.  Free the permission list and the temporary string
309                  * and return. */
310                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
311                 goto parseError;               
312             }
313             else {
314                 assignmentRight = RM_TRUE;
315             }
316         }
317         else if (!isspace(*permStrPtr)) {
318             if (assignmentRight) {
319                 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) || 
320                     (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
321                     newPerm = startPerm;
322                     while (newPerm) {
323                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1);
324                         newPerm = newPerm->nextPermission;
325                     }
326                 }
327                 else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) || 
328                          (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
329                     newPerm = startPerm;
330                     while (newPerm) {                                           
331                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1);
332                         newPerm = newPerm->nextPermission;
333                     }
334                 }
335                 else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) || 
336                          (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
337                     newPerm = startPerm;
338                     while (newPerm) {                       
339                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
340                         newPerm = newPerm->nextPermission;
341                     }
342                 }
343                 else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) || 
344                          (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
345                     newPerm = startPerm;
346                     while (newPerm) {                       
347                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1);
348                         newPerm = newPerm->nextPermission;
349                     }
350                 }                  
351                 else {
352                     /* Invalid permission character.  This is a
353                      * syntax error.  Free the permission list and the temporary string
354                      * and return. */
355                     *result = RM_ERROR_PERM_STR_INVALID_CHAR;
356                     goto parseError;                   
357                 }
358             }
359             else {
360                 /* Character found without the assignment character being found.  This is a
361                  * syntax error.  Free the permission list and the temporary string
362                  * and return. */
363                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
364                 goto parseError;
365             }
366         }
367         permStrPtr++;
368     }
370     Rm_osalFree((void *)permStrStart, permStrLen);
371     *result = RM_OK;
372     return (startPerm);
374 parseError:
375     while (startPerm) {
376         nextPerm = startPerm->nextPermission;
377         Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
378         startPerm = nextPerm;
379     }    
380     Rm_osalFree((void *)permStrStart, permStrLen);
381     return(NULL);     
384 /* FUNCTION PURPOSE: Frees a linked list of assignment permissions
385  ***********************************************************************
386  * DESCRIPTION: Frees the memory associated with a linked list of
387  *              assignment permissions extracted from a permissions
388  *              assignment subgroup in a policy DTB.
389  */
390 static void policyFreeAssignmentPermissions(Rm_PolicyPermission *permissionList)
392     Rm_PolicyPermission *nextPerm;
393     
394     while (permissionList) {
395         nextPerm = permissionList->nextPermission;
396         Rm_osalFree((void *)permissionList, sizeof(Rm_PolicyPermission));
397         permissionList = nextPerm;
398     }
401 /* FUNCTION PURPOSE: Extracts permissions from a Policy "assignment"
402  ***********************************************************************
403  * DESCRIPTION: Returns a linked list of permissions for a resource node
404  *              containing an "assignment" property in the Policy DTB.
405  *              Each node in the linked list will contain a valid instance
406  *              name along with the permissions assigned to the instance
407  */
408 static Rm_PolicyPermission *policyGetAssignmentPermissions(Rm_PolicyAssignment *assignment, 
409                                                            int32_t *result)
411     Rm_PolicyPermission *startPerm = NULL;
412     Rm_PolicyPermission *newPerm = NULL;
413     Rm_PolicyPermission *prevPerm = NULL;
414     char                *permStrStart = assignment->permissionsList;
415     char                *permStrEnd;
416     uint32_t             permStrLen = strlen(assignment->permissionsList) + 1;
417     uint32_t             i = 0;
419     *result = RM_OK;
420     
421     while(i < permStrLen) {
422         /* Find the first sub-permission specification and parse it.  A sub-permission
423          * can be terminated by the termination character or the end of the string. */
424         if (!(permStrEnd = strchr(permStrStart, RM_POLICY_PERM_TERMINATOR))) {           
425             /* Sub-permission termination character not found.  The permission string
426              * end is the end of the entire permission string */
427             permStrEnd = permStrStart + strlen(permStrStart);
428         }
430         newPerm = policyParseSubPermission(permStrStart, permStrEnd, result);
432         if (*result != RM_OK) {
433             /* Delete the permission list that's been created thus far, return
434              * the error and NULL for the permission list */
435             policyFreeAssignmentPermissions(startPerm);
436             return(NULL);
437         }
439         if (prevPerm == NULL) {
440             startPerm = newPerm;
441         }
442         else {
443             prevPerm->nextPermission = newPerm;
444         }
446         /* Set prevPerm to the last sub-permission returned by the sub-permission parser */
447         prevPerm = newPerm;
448         while(prevPerm->nextPermission != NULL) {
449             prevPerm = prevPerm->nextPermission;
450         }
451         
452         /* Update the number of characters parsed from the permission list and point to 
453          * the start of the next sub-permission */
454         i += ((uint32_t)(permStrEnd - permStrStart + 1));
455         permStrStart = permStrEnd + 1;
456     }
458     return(startPerm);
461 /* FUNCTION PURPOSE: Validates a policy "assignment" string list
462  ***********************************************************************
463  * DESCRIPTION: Returns RM_OK if the specified Policy DTB "assignment"
464  *              property specification parses okay and all the RM
465  *              instances in the assignment match RM instances in the
466  *              valid instances list
467  */
468 static int32_t policyValidateAssignmentPermissions(Rm_Handle rmHandle,
469                                                    Rm_PolicyAssignment *assignmentList)
471     Rm_PolicyAssignment *assignment = assignmentList;
472     Rm_PolicyPermission *permissionList;
473     int32_t              result;
475     while (assignment) {
476         /* Make sure assignment's permissions parse okay */
477         permissionList = policyGetAssignmentPermissions(assignment, &result);
478         if (result != RM_OK) {
479             return(result);
480         }                        
481         
482         if ((result = policyCheckInstances(rmHandle, permissionList)) !=
483             RM_OK) {
484             policyFreeAssignmentPermissions(permissionList);
485             return(result);
486         }
488         policyFreeAssignmentPermissions(permissionList);
489         assignment = assignment->nextAssignment;
490     }
492     return (RM_OK);
495 /**********************************************************************
496  ************************ Internal Policy APIs ************************
497  **********************************************************************/
499 /* FUNCTION PURPOSE: Returns a pointer to the instance policy
500  ***********************************************************************
501  * DESCRIPTION: Returns a pointer to the instance's policy based on
502  *              the instance type
503  */
504 void *rmPolicyGetPolicy(Rm_Handle rmHandle)
506     Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
507     void    *policy = NULL;
509     if ((rmInst->instType == Rm_instType_SERVER) ||
510         (rmInst->instType == Rm_instType_SHARED_SERVER)) {
511         policy = rmInst->u.server.globalPolicy;
512     }
513     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
514         policy = rmInst->u.cd.cdPolicy;
515     }
516     else if (rmInst->instType == Rm_instType_CLIENT) {
517         policy = rmInst->u.client.staticPolicy;
518     }
519     return(policy);
522 /* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree
523  ***********************************************************************
524  * DESCRIPTION: Returns a valid instance node from the valid instance
525  *              tree that matches the specified instName
526  */
527 Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_Handle rmHandle, char *instName)
529     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
530     Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle);
531     Rm_PolicyValidInstNode  findNode;
533     if (rmInst->instType == Rm_instType_SHARED_SERVER) {
534         rmPolicyValidInstTreeInv(treeRoot);
535     }
537     memset((void *)&findNode, 0, sizeof(Rm_PolicyValidInstNode));
538     rm_strncpy(findNode.name, instName, RM_NAME_MAX_CHARS);
539     
540     return (RB_FIND(_Rm_PolicyValidInstTree, treeRoot, &findNode));
543 /* FUNCTION PURPOSE: Gets the Linux Valid instance node
544  ***********************************************************************
545  * DESCRIPTION: Returns a pointer to the valid instance node in the
546  *              valid instance tree that matches the instance name
547  *              reserved for resource assigned to the Linux kernel.
548  */
549 Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_Handle rmHandle)
551     char linuxName[] = RM_ALLOCATED_TO_LINUX;
553     return (rmPolicyGetValidInstNode(rmHandle, linuxName));
556 /* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB
557  ***********************************************************************
558  * DESCRIPTION: Returns TRUE if the instance name has the specified
559  *              permissions for the specified resource in the Policy
560  *              DTB.  Otherwise, returns FALSE.
561  */
562 int rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg, int32_t *result)
564     int32_t              propertyOffset;
565     const char          *propertyName;
566     int32_t              propertyLen;
567     const void          *propertyData;
568     Rm_PolicyAssignment *assignment = NULL;
569     Rm_PolicyAssignment *assignmentStart = NULL;
570     Rm_PolicyPermission *permission = NULL;
571     Rm_PolicyPermission *permissionStart = NULL;
572     uint32_t             assignmentEnd;
573     uint32_t             resourceEnd = privilegeCfg->resourceBase + privilegeCfg->resourceLength - 1;
574     int                  foundInstance;
576     *result = RM_OK;
578     /* Get the resource's assignments */
579     propertyOffset = fdt_first_property_offset(privilegeCfg->policyDtb, privilegeCfg->resourceOffset);
580     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
581         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
582             propertyData = fdt_getprop_by_offset(privilegeCfg->policyDtb, propertyOffset, &propertyName, &propertyLen);
583             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
584                 assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
585                 break;
586             }
587             propertyOffset = fdt_next_property_offset(privilegeCfg->policyDtb, propertyOffset);
588         }
589     }
591     if (assignment) {
592         while (assignment) {
593             assignmentEnd = assignment->resourceBase + assignment->resourceLength - 1;
594             foundInstance = RM_FALSE;
595             if (((privilegeCfg->resourceBase >= assignment->resourceBase) &&
596                  (privilegeCfg->resourceBase <= assignmentEnd)) ||
597                 ((privilegeCfg->resourceBase < assignment->resourceBase) &&
598                  (resourceEnd > assignmentEnd)) ||
599                 ((resourceEnd >= assignment->resourceBase) &&
600                  (resourceEnd <= assignmentEnd))) {
601                  
602                 permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
603                 while (permission) {
604                     if ((strncmp(permission->instName, privilegeCfg->validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
605                         (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
606                         foundInstance = RM_TRUE;
607                         
608                         /* Check instance's permissions */
609                         if (privilegeCfg->type == Rm_policyCheck_INIT) {
610                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
611                                 policyFreeAssignmentPermissions(permissionStart);
612                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
613                                 return(RM_FALSE);
614                             }
615                         }
616                         else if (privilegeCfg->type == Rm_policyCheck_USE) {
617                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
618                                 policyFreeAssignmentPermissions(permissionStart);
619                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
620                                 return(RM_FALSE);
621                             }   
622                         }
623                         else if (privilegeCfg->type == Rm_policyCheck_EXCLUSIVE) {
624                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT)) {
625                                 policyFreeAssignmentPermissions(permissionStart);
626                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
627                                 return(RM_FALSE);
628                             }   
629                         }
630                         else if (privilegeCfg->type == Rm_policyCheck_SHARED_LINUX) {
631                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT)) {
632                                 policyFreeAssignmentPermissions(permissionStart);
633                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
634                                 return(RM_FALSE);
635                             }   
636                         }                        
637                         break;
638                     }
639                     permission = permission->nextPermission;
640                 }
641                 
642                 policyFreeAssignmentPermissions(permissionStart);
643                 if (!foundInstance) {
644                     rmDtbUtilPolicyFreeAssignments(assignmentStart);
645                     return(RM_FALSE);
646                 }
647             }
648             assignment = assignment->nextAssignment;
649         }
650         rmDtbUtilPolicyFreeAssignments(assignmentStart);
651     }
652     else {
653         return(RM_FALSE);
654     }
655     
656     return(RM_TRUE);
659 /* FUNCTION PURPOSE: Returns resource base value according to the Policy
660  ***********************************************************************
661  * DESCRIPTION: Returns a resource base value based on the resource
662  *              ranges assigned to the specified valid instance by the
663  *              Policy DTB.
664  */
665 uint32_t rmPolicyGetResourceBase(void *policyDtb, Rm_PolicyValidInstNode *validInstNode, 
666                                  int32_t resourceOffset, Rm_PolicyCheckType policyCheckType, 
667                                  int32_t *result)
670     int32_t              propertyOffset;
671     const char          *propertyName;
672     int32_t              propertyLen;
673     const void          *propertyData;
674     Rm_PolicyAssignment *assignment = NULL;
675     Rm_PolicyAssignment *assignmentStart = NULL;
676     Rm_PolicyPermission *permission = NULL;
677     Rm_PolicyPermission *permissionStart = NULL;
678     int32_t              resourceBase = RM_RESOURCE_BASE_UNSPECIFIED;
680     *result = RM_OK;
682     propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
683     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
684         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
685             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
686             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
687                 assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
688                 break;
689             }
690             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
691         }
692     }
694     /* Search policy permissions for valid resource base */
695     while (assignment) {
696         permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
697         while (permission) {
698             if ((strncmp(permission->instName, validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
699                 (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
700                 /* Check instance's permissions */
701                 if ((policyCheckType == Rm_policyCheck_INIT) &&
702                     RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
703                     resourceBase = assignment->resourceBase;
704                     break;
705                 }
706                 else if ((policyCheckType == Rm_policyCheck_USE) &&
707                          RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
708                     resourceBase = assignment->resourceBase;
709                     break;
710                 }
711             }
712             permission = permission->nextPermission;
713         }
714         policyFreeAssignmentPermissions(permissionStart);
716         if (resourceBase != RM_RESOURCE_BASE_UNSPECIFIED) {
717             break;
718         }
719         else {
720             assignment = assignment->nextAssignment;
721         }
722     }
724     if (assignmentStart) {
725         rmDtbUtilPolicyFreeAssignments(assignmentStart);
726     }
727     
728     return(resourceBase);
731 /* FUNCTION PURPOSE: Returns resource alignment value according to the Policy
732  ***********************************************************************
733  * DESCRIPTION: Parses the policy DTB to find and return a resource's 
734  *              alignment.
735  */
736 uint32_t rmPolicyGetResourceAlignment(void *policyDtb, int32_t resourceOffset)
738     int32_t           propertyOffset;
739     const char       *propertyName;
740     int32_t           propertyLen;
741     const void       *propertyData;
742     Rm_ResourceValue *alignmentList;
743     uint32_t          resourceAlignment = 0;
745     propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
746     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
747         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
748             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
749             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ALLOCATION_ALIGNMENT) {
750                 alignmentList = rmDtbUtilPolicyExtractResourceAlignments(propertyData, propertyLen);
751                 resourceAlignment = alignmentList->value;                
752                 rmDtbUtilPolicyFreeResourceAlignments(alignmentList);
753             }
754             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
755         }
756     }
758     if (resourceAlignment == 0) {
759         resourceAlignment = 1;
760     }
761     return(resourceAlignment);
764 /* FUNCTION PURPOSE: Returns resource CD allocation size according to the Policy
765  ***********************************************************************
766  * DESCRIPTION: Parses the policy DTB to find and return a resource's 
767  *              allocation size.
768  */
769 uint32_t rmPolicyGetResourceCdAllocSize(void *policyDtb, int32_t resourceOffset)
771     int32_t           propertyOffset;
772     const char       *propertyName;
773     int32_t           propertyLen;
774     const void       *propertyData;
775     Rm_ResourceValue *allocSizeList;
776     uint32_t          resourceAllocSize = 0;
778     propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
779     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
780         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
781             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
782             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_CD_ALLOCATION_SIZE) {
783                 allocSizeList = rmDtbUtilPolicyExtractCdAllocationSizes(propertyData, propertyLen);
784                 resourceAllocSize = allocSizeList->value;                
785                 rmDtbUtilPolicyFreeCdAllocationSizes(allocSizeList);
786             }
787             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
788         }
789     }
790     return(resourceAllocSize);
794 /* FUNCTION PURPOSE: Get a resource's offset into a Policy
795  ***********************************************************************
796  * DESCRIPTION: Returns the location of the specified resource node
797  *              within the specified Policy in the form of an offset
798  *              into the DTB.  The resourceName and the Policy
799  *              node name must match.
800  */
801 int32_t rmPolicyGetResourceOffset(void *policyDtb, char *resourceName)
803     int32_t     nodeOffset;
804     int32_t     depth;
805     const char *nodeName;
807     if (policyDtb) {
808         depth = RM_DTB_UTIL_STARTING_DEPTH;
809         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;       
811         /* Find node offset for provided resource name */
812         while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
813             nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
814             if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
815                 /* Resource name not found */
816                 nodeOffset = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
817                 break;
818             } 
819             else {
820                 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
821                 if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0) {
822                     break;
823                 }
824             }
825         }
826     }
827     else {
828         nodeOffset = RM_ERROR_INSTANCE_HAS_NO_POLICY;
829     }
830     return(nodeOffset);
833 /* FUNCTION PURPOSE: Validates a Policy's resource node names
834  ***********************************************************************
835  * DESCRIPTION: Returns RM_OK if all of a Policy's resource node names
836  *              match a node name specified in the "valid-instances"
837  *              list specified at the top of the Policy.  Otherwise,
838  *              returns error
839  */
840 int32_t rmPolicyValidateResNames(Rm_Handle rmHandle)
842     void       *policyDtb = rmPolicyGetPolicy(rmHandle);
843     int32_t     nodeOffset;
844     int32_t     depth;
845     const char *nodeName;
847     depth = RM_DTB_UTIL_STARTING_DEPTH;
848     nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;       
850     /* Parse DTB, verifying each resource's assignment permissions.
851      * Permissions must have correct syntax and contain valid instance names
852      * according validInstList */
853     while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
854         nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
855         if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
856             break;
857         }
858         nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
859         if (fdt_first_property_offset(policyDtb, nodeOffset) > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
860             if (rmAllocatorFind(rmHandle, nodeName) == NULL) {
861                 /* No allocator tied to resource name */
862                 return(RM_ERROR_UNKNOWN_RESOURCE_IN_POLICY);
863             }        
864         }
865     }
866     return(RM_OK);
869 /* FUNCTION PURPOSE: Validates a Policy DTB
870  ***********************************************************************
871  * DESCRIPTION: Returns RM_OK if the input Policy satisfies the
872  *              following conditions:
873  *              a) All "assignment" permission string parse okay
874  *              b) All RM instance names specified in the permission
875  *                 strings match an instance name in the valid instance
876  *                 list
877  *              c) All resource node names match a resource allocator
878  */
879 int32_t rmPolicyValidatePolicy(Rm_Handle rmHandle)
881     void                *policyDtb = rmPolicyGetPolicy(rmHandle);
882     int32_t              nodeOffset;
883     int32_t              propertyOffset;
884     int32_t              depth;
885     const char          *resourceName;
886     const char          *propertyName;
887     int32_t              propertyLen;
888     const void          *propertyData;
889     Rm_PolicyPropType    propertyType;
890     Rm_PolicyAssignment *assignmentList;
891     int32_t              result;
893     depth = RM_DTB_UTIL_STARTING_DEPTH;
894     nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;       
896     /* Parse DTB, verifying each resource's assignment permissions.
897      * Permissions must have correct syntax and contain valid instance names
898      * according validInstList */
899     while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
900         nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
901         if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
902             break;
903         }
904         
905         resourceName = fdt_get_name(policyDtb, nodeOffset, NULL);
906         if ((strlen(resourceName) + 1) > RM_NAME_MAX_CHARS) {
907             return(RM_ERROR_RESOURCE_NAME_TOO_LONG);
908         }        
909         
910         propertyOffset = fdt_first_property_offset(policyDtb, nodeOffset);                
911         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
912             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
913             propertyType = rmDtbUtilPolicyGetPropertyType(propertyName);
914             if (propertyType == Rm_policyPropType_ASSIGNMENTS) {
915                 assignmentList = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
916                 
917                 if ((result = policyValidateAssignmentPermissions(rmHandle, assignmentList)) != RM_OK) {
918                     rmDtbUtilPolicyFreeAssignments(assignmentList);
919                     return(result);
920                 }
921                 rmDtbUtilPolicyFreeAssignments(assignmentList);
922             }
923             else if (propertyType == Rm_policyPropType_UNKNOWN) {
924                 return(RM_ERROR_UNKNOWN_POLICY_RESOURCE_PROPERTY);
925             }
926             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
927         }
928     }
929     return(RM_OK);
932 /* FUNCTION PURPOSE: Creates the valid instance tree for a RM instance
933  ***********************************************************************
934  * DESCRIPTION: Creates the valid instance tree for a RM instance 
935  *              that has been provided a global or static policy
936  *              The valid instance tree is created from the
937  *              "valid-instances" property at the top of the Policy.
938  *              The root entry of the valid instance tree is returned.
939  */
940 Rm_PolicyValidInstTree *rmPolicyCreateValidInstTree(Rm_Handle rmHandle, int addLinux, int32_t *result)
942     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
943     void                   *policyDtb = rmPolicyGetPolicy(rmHandle);
944     int32_t                 validInstOffset;
945     const char             *validInstName = NULL;
946     int32_t                 validInstLen;
947     const void             *validInstData = NULL;
948     Rm_PolicyPropType       propertyType;
949     Rm_PolicyValidInst     *vInstListStart = NULL;
950     Rm_PolicyValidInst     *validInstList = NULL;
951     Rm_PolicyValidInstTree *rootEntry = NULL;
952     Rm_PolicyValidInstNode *newNode = NULL;  
953     char                    linuxName[] = RM_ALLOCATED_TO_LINUX;
955     /* Valid instance list must be first and only property in the root node of
956      * the policyDtb */
957     validInstOffset = fdt_first_property_offset(policyDtb, RM_DTB_UTIL_STARTING_NODE_OFFSET);
958     if (validInstOffset < -FDT_ERR_NOTFOUND) {
959         *result = validInstOffset;
960         return (NULL);
961     } 
962     else if (validInstOffset == -FDT_ERR_NOTFOUND) {
963         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
964         return (NULL);
965     }
966     validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset, &validInstName, &validInstLen);
967     propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
968     if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
969         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
970         return (NULL);
971     }
973     if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData, validInstLen, result))) {
974         return (NULL);
975     }
976     
977     /* Create the tree */
978     rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
979     RB_INIT(rootEntry);
981     vInstListStart = validInstList;
982     while (validInstList) {
983         newNode = rmPolicyValidInstNodeNew(validInstList->instName);
984         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
985         
986         validInstList = validInstList->nextValidInst;
987     }
988     rmDtbUtilPolicyFreeValidInstances(vInstListStart);
990     /* Add the Linux kernel node */
991     if (addLinux) {
992         newNode = rmPolicyValidInstNodeNew(linuxName);
993         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);    
994     }
996     if (rmInst->instType == Rm_instType_SHARED_SERVER) {
997         /* Writeback the valid instance tree */
998         rmPolicyValidInstTreeWb(rootEntry);
999     }
1001     *result = RM_OK;
1002     return (rootEntry);
1005 /* FUNCTION PURPOSE: Deletes a valid instance tree
1006  ***********************************************************************
1007  * DESCRIPTION: Frees all memory associated with a Policy valid
1008  *              instance tree.
1009  */
1010 void rmPolicyFreeValidInstTree(Rm_Handle rmHandle)
1012     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
1013     Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle);
1014     Rm_PolicyValidInstNode *node;
1015     Rm_PolicyValidInstNode *nextNode;
1017     if (treeRoot) {
1018         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1019             rmPolicyValidInstTreeInv(treeRoot);
1020         }
1022         for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot); node != NULL; node = nextNode) {
1023             nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node);
1024             RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node);
1025             rmPolicyValidInstNodeFree(node);
1026         }
1028         /* Don't need to writeback tree node changes since valid instance will be made
1029          * NULL in instance */
1030          
1031         if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) {
1032             /* No more valid instance nodes in tree */
1033             Rm_osalFree((void *)treeRoot, sizeof(Rm_PolicyValidInstTree));
1034         }
1036         if ((rmInst->instType == Rm_instType_SERVER) ||
1037             (rmInst->instType == Rm_instType_SHARED_SERVER)) {
1038             rmInst->u.server.globalValidInstTree = NULL;
1039         }
1040         else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1041             rmInst->u.cd.cdValidInstTree = NULL;
1042         }
1043         else if (rmInst->instType == Rm_instType_CLIENT) {
1044             rmInst->u.client.staticValidInstTree = NULL;
1045         }
1046     }