Added local gate for NULL service callback and fixed bug where resource node offset...
[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-2013, Texas Instruments, Inc.
10  * 
11  *  Redistribution and use in source and binary forms, with or without 
12  *  modification, are permitted provided that the following conditions 
13  *  are met:
14  *
15  *    Redistributions of source code must retain the above copyright 
16  *    notice, this list of conditions and the following disclaimer.
17  *
18  *    Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the 
20  *    documentation and/or other materials provided with the   
21  *    distribution.
22  *
23  *    Neither the name of Texas Instruments Incorporated nor the names of
24  *    its contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  *  \par
40 */
42 /* Standard includes */
43 #include <ctype.h>
44 #include <stdbool.h>
46 /* RM external API includes */
47 #include <ti/drv/rm/rm.h>
49 /* RM internal API includes */
50 #include <ti/drv/rm/include/rm_allocatorloc.h>
51 #include <ti/drv/rm/include/rm_policyloc.h>
52 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
54 /* RM LIBFDT includes */
55 #include <ti/drv/rm/util/libfdt/libfdt.h>
57 /* Tree algorithm includes */
58 #include <ti/drv/rm/util/tree.h>
60 /* RM OSAL layer */
61 #include <rm_osal.h>
63 /**********************************************************************
64  *********************** Policy Globals *******************************
65  **********************************************************************/
67 /* Character used in Policies to specify all RM instances receive
68  * the defined permissions for a resource node */
69 const char Rm_policyAllInstances[] = "*";
71 /**********************************************************************
72  ******************** Local Policy Functions **************************
73  **********************************************************************/
75 /* FUNCTION PURPOSE: Validates the instance names in a permissions string
76  ***********************************************************************
77  * DESCRIPTION: Returns RM_OK if all the instance names in a permissions
78  *              string match instance names defined in the valid instance
79  *              list.  RM_ERROR_PERM_STR_INST_NOT_VALID is returned if
80  *              there are any mismatches
81  */
82 static int32_t policyCheckInstances(Rm_PolicyValidInstTree *validInstTree, 
83                                     Rm_PolicyPermission *permissionsList)
84 {
85     while (permissionsList) {
86         if (strncmp(permissionsList->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) &&
87             (!rmPolicyGetValidInstNode(validInstTree, permissionsList->instName))) {
88             return(RM_ERROR_PERM_STR_INST_NOT_VALID);
89         }
90         permissionsList = permissionsList->nextPermission;
91     }
92     return(RM_OK);
93 }
95 /* FUNCTION PURPOSE: Parses a permissions subgroup
96  ***********************************************************************
97  * DESCRIPTION: Returns a linked list of policy permissions defining
98  *              which RM instance referenced in the permissions subgroup
99  *              get which permissions.  Returns NULL if any syntax
100  *              errors are encountered during the parsing.  The error
101  *              is returned via the result pointer parameter.
102  */
103 static Rm_PolicyPermission *policyParseSubPermission(char *permStrStart, char *permStrEnd, 
104                                                      int32_t *result)
106     Rm_PolicyPermission *startPerm = NULL;
107     Rm_PolicyPermission *newPerm = NULL;
108     Rm_PolicyPermission *prevPerm = NULL;
109     Rm_PolicyPermission *nextPerm = NULL;
110     char                *permStrPtr = NULL;
111     char                *subgroupStart = NULL;
112     char                *subgroupEnd = NULL;
113     uint32_t             permStrLen = (uint32_t)(permStrEnd - permStrStart + 1);
114     char                 instNameTemp[RM_NAME_MAX_CHARS];
115     uint32_t             instNameIndex;
116     bool                 foundInstName;
117     bool                 instNameComplete;
118     bool                 assignmentLeft;
119     bool                 assignmentRight;
121     /* Create a local copy of the sub-permission string */
122     permStrPtr = Rm_osalMalloc(permStrLen);
123     strncpy(permStrPtr, permStrStart, permStrLen);
124     /* Make sure the last character in the copied sub-permission string is null */
125     permStrPtr[permStrLen - 1] = '\0';
127     permStrStart = permStrPtr;
128     permStrEnd = permStrPtr + strlen(permStrPtr);
130     /* Find the beginning and end of the sub-permission instance group */
131     subgroupStart = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START);
132     subgroupEnd = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END);
134     if ((!subgroupStart) || (!subgroupEnd) || (subgroupStart > subgroupEnd) ||
135         ((subgroupStart != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START)) &&
136          (subgroupEnd != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END)))) {
137         /* Free the memory associated with the temp string and return an error if:
138          * a) Could not find the instance group start
139          * b) Could not find the instance group end
140          * c) Subgroup start and end are out of order
141          * d) There is more than one instance subgroup specified in the string.  There
142          *    should only be one subgroup per sub-permission string */
143         Rm_osalFree((void *)permStrStart, permStrLen);
144         *result = RM_ERROR_PERM_STR_TOO_MANY_INST_GROUPS;
145         return(NULL);
146     }
148     /* Create a permission entry for each instance specified in the instance group.
149      * Instances names are separated by one or more spaces. */
150     permStrPtr = subgroupStart + 1;
151     instNameIndex = 0;
152     foundInstName = false;
153     instNameComplete = false;
154     while (permStrPtr <= subgroupEnd) {
155         if ((isspace(*permStrPtr) || (*permStrPtr == RM_POLICY_PERM_SUBGROUP_END))
156             && foundInstName) {
157             /* First space encountered after copying an instance name.  This
158              * terminates the instance name.  All other space characters are
159              * ignored. */
160             instNameTemp[instNameIndex] = '\0';
161             instNameComplete = true; 
162         }
163         else {
164             if (!foundInstName) {
165                 /* First non-whitespace character encountered is the start of an
166                  * instance name */
167                 foundInstName = true;
168             }
170             /* Copy the character into the temporary instance name string */
171             instNameTemp[instNameIndex++] = *permStrPtr;
172         }
174         if (instNameComplete) {
175             newPerm = (Rm_PolicyPermission *) Rm_osalMalloc(sizeof(Rm_PolicyPermission));
176             memset((void *)newPerm, 0, sizeof(Rm_PolicyPermission));
178             strncpy(newPerm->instName, instNameTemp, RM_NAME_MAX_CHARS);
179             newPerm->nextPermission = NULL;
181             if (prevPerm == NULL) {
182                 /* Save the first instance so it can be returned */
183                 startPerm = newPerm;
184             }
185             else {
186                 prevPerm->nextPermission = newPerm;
187             }
188             prevPerm = newPerm;
190             instNameComplete = false;
191             instNameIndex = 0;
192             foundInstName = false;
193         }
194         else if (instNameIndex == RM_NAME_MAX_CHARS) {
195             /* Instance name is longer than max length */
196             while (startPerm) {
197                 nextPerm = startPerm->nextPermission;
198                 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
199                 startPerm = nextPerm;
200             } 
201             Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
202             *result = RM_ERROR_INST_NAME_IN_ASSIGNMENT_TOO_LONG;
203             return(NULL);
204         }
206         permStrPtr++;
207     }
209     /* Fill in the permissions for each instance name */
211     /* Look on left of instance group for permission assignments. */
212     permStrPtr = subgroupStart - 1;
213     assignmentLeft = false;
214     while (permStrPtr >= permStrStart)
215     {
216         if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
217             if (assignmentLeft) {
218                 /* Assignment character has been found more than once.  This is a
219                  * syntax error.  Free the permission list and the temporary string
220                  * and return. */
221                 while (startPerm) {
222                     nextPerm = startPerm->nextPermission;
223                     Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
224                     startPerm = nextPerm;
225                 } 
226                 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
227                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
228                 return(NULL);
229             }
230             else {
231                 assignmentLeft = true;
232             }
233         }
234         else if (!isspace(*permStrPtr)) {
235             if (assignmentLeft) {
236                 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) || 
237                     (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
238                     newPerm = startPerm;
239                     while (newPerm) {
240                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1);
241                         newPerm = newPerm->nextPermission;
242                     }
243                 }
244                 else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) || 
245                          (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
246                     newPerm = startPerm;
247                     while (newPerm) {                                           
248                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1);
249                         newPerm = newPerm->nextPermission;
250                     }
251                 }
252                 else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) || 
253                          (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
254                     newPerm = startPerm;
255                     while (newPerm) {                       
256                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
257                         newPerm = newPerm->nextPermission;
258                     }
259                 }
260                 else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) || 
261                          (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
262                     newPerm = startPerm;
263                     while (newPerm) {                       
264                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1);
265                         newPerm = newPerm->nextPermission;
266                     }
267                 }                
268                 else {
269                     /* Invalid permission character.  This is a
270                      * syntax error.  Free the permission list and the temporary string
271                      * and return. */
272                     while (startPerm) {
273                         nextPerm = startPerm->nextPermission;
274                         Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
275                         startPerm = nextPerm;
276                     }  
277                     Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
278                     *result = RM_ERROR_PERM_STR_INVALID_CHAR;
279                     return(NULL);
280                 }
281             }
282             else {
283                 /* Character found without the assignment character being found.  This is a
284                  * syntax error.  Free the permission list and the temporary string
285                  * and return. */
286                 while (startPerm) {
287                     nextPerm = startPerm->nextPermission;
288                     Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
289                     startPerm = nextPerm;
290                 }  
291                 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
292                 *result = RM_ERROR_PERM_CHAR_WITHOUT_ASSIGN_CHAR;
293                 return(NULL);
294             }
295         }
296         permStrPtr--;
297     }
299     /* Look on right of instance group for permission assignments. */
300     permStrPtr = subgroupEnd + 1;
301     assignmentRight = false;
302     while (permStrPtr < permStrEnd) {
303         if (assignmentLeft && (!isspace(*permStrPtr))) {
304             /* There should be nothing but spaces on right if assignment was already found on left */
305             while (startPerm) {
306                 nextPerm = startPerm->nextPermission;
307                 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
308                 startPerm = nextPerm;
309             } 
310             Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
311             *result = RM_ERROR_INVALID_PERMS_CHAR_ON_RIGHT;
312             return(NULL);              
313         }
314         
315         if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
316             if (assignmentRight) {
317                 /* Assignment character has been found more than once.  This is a
318                  * syntax error.  Free the permission list and the temporary string
319                  * and return. */
320                 while (startPerm) {
321                     nextPerm = startPerm->nextPermission;
322                     Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
323                     startPerm = nextPerm;
324                 } 
325                 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
326                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
327                 return(NULL);                
328             }
329             else {
330                 assignmentRight = true;
331             }
332         }
333         else if (!isspace(*permStrPtr)) {
334             if (assignmentRight) {
335                 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) || 
336                     (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
337                     newPerm = startPerm;
338                     while (newPerm) {
339                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1);
340                         newPerm = newPerm->nextPermission;
341                     }
342                 }
343                 else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) || 
344                          (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
345                     newPerm = startPerm;
346                     while (newPerm) {                                           
347                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1);
348                         newPerm = newPerm->nextPermission;
349                     }
350                 }
351                 else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) || 
352                          (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
353                     newPerm = startPerm;
354                     while (newPerm) {                       
355                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
356                         newPerm = newPerm->nextPermission;
357                     }
358                 }
359                 else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) || 
360                          (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
361                     newPerm = startPerm;
362                     while (newPerm) {                       
363                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1);
364                         newPerm = newPerm->nextPermission;
365                     }
366                 }                  
367                 else {
368                     /* Invalid permission character.  This is a
369                      * syntax error.  Free the permission list and the temporary string
370                      * and return. */
371                     while (startPerm) {
372                         nextPerm = startPerm->nextPermission;
373                         Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
374                         startPerm = nextPerm;
375                     }    
376                     Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
377                     *result = RM_ERROR_PERM_STR_INVALID_CHAR;
378                     return(NULL);                    
379                 }
380             }
381             else {
382                 /* Character found without the assignment character being found.  This is a
383                  * syntax error.  Free the permission list and the temporary string
384                  * and return. */
385                 while (startPerm) {
386                     nextPerm = startPerm->nextPermission;
387                     Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
388                     startPerm = nextPerm;
389                 }    
390                 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
391                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
392                 return(NULL);                
393             }
394         }
395         permStrPtr++;
396     }
398     Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
399     return (startPerm);
402 /* FUNCTION PURPOSE: Frees a linked list of assignment permissions
403  ***********************************************************************
404  * DESCRIPTION: Frees the memory associated with a linked list of
405  *              assignment permissions extracted from a permissions
406  *              assignment subgroup in a policy DTB.
407  */
408 static void policyFreeAssignmentPermissions(Rm_PolicyPermission *permissionList)
410     Rm_PolicyPermission *nextPerm;
411     
412     while (permissionList) {
413         nextPerm = permissionList->nextPermission;
414         Rm_osalFree((void *)permissionList, sizeof(Rm_PolicyPermission));
415         permissionList = nextPerm;
416     }
419 /* FUNCTION PURPOSE: Extracts permissions from a Policy "assignment"
420  ***********************************************************************
421  * DESCRIPTION: Returns a linked list of permissions for a resource node
422  *              containing an "assignment" property in the Policy DTB.
423  *              Each node in the linked list will contain a valid instance
424  *              name along with the permissions assigned to the instance
425  */
426 static Rm_PolicyPermission *policyGetAssignmentPermissions(Rm_PolicyAssignment *assignment, 
427                                                            int32_t *result)
429     Rm_PolicyPermission *startPerm = NULL;
430     Rm_PolicyPermission *newPerm = NULL;
431     Rm_PolicyPermission *prevPerm = NULL;
432     char                *permStrStart = assignment->permissionsList;
433     char                *permStrEnd;
434     uint32_t             permStrLen = strlen(assignment->permissionsList) + 1;
435     uint32_t             i = 0;
436     
437     while(i < permStrLen) {
438         /* Find the first sub-permission specification and parse it.  A sub-permission
439          * can be terminated by the termination character or the end of the string. */
440         if (!(permStrEnd = strchr(permStrStart, RM_POLICY_PERM_TERMINATOR))) {           
441             /* Sub-permission termination character not found.  The permission string
442              * end is the end of the entire permission string */
443             permStrEnd = permStrStart + strlen(permStrStart);
444         }
446         newPerm = policyParseSubPermission(permStrStart, permStrEnd, result);
448         if (*result != RM_SERVICE_PROCESSING) {
449             /* Delete the permission list that's been created thus far, return
450              * the error and NULL for the permission list */
451             policyFreeAssignmentPermissions(startPerm);
452             return(NULL);
453         }
455         if (prevPerm == NULL) {
456             startPerm = newPerm;
457         }
458         else {
459             prevPerm->nextPermission = newPerm;
460         }
462         /* Set prevPerm to the last sub-permission returned by the sub-permission parser */
463         prevPerm = newPerm;
464         while(prevPerm->nextPermission != NULL) {
465             prevPerm = prevPerm->nextPermission;
466         }
467         
468         /* Update the number of characters parsed from the permission list and point to 
469          * the start of the next sub-permission */
470         i += ((uint32_t)(permStrEnd - permStrStart + 1));
471         permStrStart = permStrEnd + 1;
472     }
474     return(startPerm);
477 /* FUNCTION PURPOSE: Validates a policy "assignment" string list
478  ***********************************************************************
479  * DESCRIPTION: Returns RM_OK if the specified Policy DTB "assignment"
480  *              property specification parses okay and all the RM
481  *              instances in the assignment match RM instances in the
482  *              valid instances list
483  */
484 static int32_t policyValidateAssignmentPermissions(Rm_PolicyValidInstTree *root,
485                                                    Rm_PolicyAssignment *assignmentList)
487     Rm_PolicyAssignment *assignment = assignmentList;
488     Rm_PolicyPermission *permissionList;
489     int32_t              result = RM_OK;
491     while (assignment) {
492         /* Make sure assignment's permissions parse okay */
493         permissionList = policyGetAssignmentPermissions(assignment, &result);
494         if (result != RM_OK) {
495             return(result);
496         }                        
497         
498         if (result = policyCheckInstances(root, permissionList) != RM_OK) {
499             policyFreeAssignmentPermissions(permissionList);
500             return(result);
501         }
503         policyFreeAssignmentPermissions(permissionList);
504         assignment = assignment->nextAssignment;
505     }
507     return (RM_OK);
510 /**********************************************************************
511  ************************ Internal Policy APIs ************************
512  **********************************************************************/
514 /* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree
515  ***********************************************************************
516  * DESCRIPTION: Returns a valid instance node from the valid instance
517  *              tree that matches the specified instName
518  */
519 Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_PolicyValidInstTree *validInstTree, char *instName)
521     Rm_PolicyValidInstNode  findNode;
523     memset((void *)&findNode, 0, sizeof(Rm_PolicyValidInstNode));
524     strncpy(findNode.name, instName, RM_NAME_MAX_CHARS);
525     
526     return (RB_FIND(_Rm_PolicyValidInstTree, validInstTree, &findNode));
529 /* FUNCTION PURPOSE: Gets the Linux Valid instance node
530  ***********************************************************************
531  * DESCRIPTION: Returns a pointer to the valid instance node in the
532  *              valid instance tree that matches the instance name
533  *              reserved for resource assigned to the Linux kernel.
534  */
535 Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_PolicyValidInstTree *validInstTree)
537     char linuxName[] = RM_ALLOCATED_TO_LINUX;
539     return (rmPolicyGetValidInstNode(validInstTree, linuxName));
542 /* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB
543  ***********************************************************************
544  * DESCRIPTION: Returns TRUE if the instance name has the specified
545  *              permissions for the specified resource in the Policy
546  *              DTB.  Otherwise, returns FALSE.
547  */
548 bool rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg, int32_t *result)
550     int32_t              propertyOffset;
551     const char          *propertyName;
552     int32_t              propertyLen;
553     const void          *propertyData;
554     Rm_PolicyAssignment *assignment = NULL;
555     Rm_PolicyAssignment *assignmentStart = NULL;
556     Rm_PolicyPermission *permission = NULL;
557     Rm_PolicyPermission *permissionStart = NULL;
558     uint32_t             assignmentEnd;
559     uint32_t             resourceEnd = privilegeCfg->resourceBase + privilegeCfg->resourceLength - 1;
560     bool                 foundInstance;
562     /* Get the resource's assignments */
563     propertyOffset = fdt_first_property_offset(privilegeCfg->policyDtb, privilegeCfg->resourceOffset);
564     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
565         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
566             propertyData = fdt_getprop_by_offset(privilegeCfg->policyDtb, propertyOffset, &propertyName, &propertyLen);
567             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
568                 assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
569                 break;
570             }
571             propertyOffset = fdt_next_property_offset(privilegeCfg->policyDtb, propertyOffset);
572         }
573     }
575     if (assignment) {
576         while (assignment) {
577             assignmentEnd = assignment->resourceBase + assignment->resourceLength - 1;
578             foundInstance = false;
579             if (((privilegeCfg->resourceBase >= assignment->resourceBase) &&
580                  (privilegeCfg->resourceBase <= assignmentEnd)) ||
581                 ((privilegeCfg->resourceBase < assignment->resourceBase) &&
582                  (resourceEnd > assignmentEnd)) ||
583                 ((resourceEnd >= assignment->resourceBase) &&
584                  (resourceEnd <= assignmentEnd))) {
585                  
586                 permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
587                 while (permission) {
588                     if ((strncmp(permission->instName, privilegeCfg->validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
589                         (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
590                         foundInstance = true;
591                         
592                         /* Check instance's permissions */
593                         if (privilegeCfg->type == Rm_policyCheck_INIT) {
594                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
595                                 policyFreeAssignmentPermissions(permissionStart);
596                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
597                                 return(false);
598                             }
599                         }
600                         else if (privilegeCfg->type == Rm_policyCheck_USE) {
601                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
602                                 policyFreeAssignmentPermissions(permissionStart);
603                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
604                                 return(false);
605                             }   
606                         }
607                         else if (privilegeCfg->type == Rm_policyCheck_EXCLUSIVE) {
608                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT)) {
609                                 policyFreeAssignmentPermissions(permissionStart);
610                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
611                                 return(false);
612                             }   
613                         }
614                         else if (privilegeCfg->type == Rm_policyCheck_SHARED_LINUX) {
615                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT)) {
616                                 policyFreeAssignmentPermissions(permissionStart);
617                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
618                                 return(false);
619                             }   
620                         }                        
621                         break;
622                     }
623                     permission = permission->nextPermission;
624                 }
625                 
626                 policyFreeAssignmentPermissions(permissionStart);
627                 if (!foundInstance) {
628                     rmDtbUtilPolicyFreeAssignments(assignmentStart);
629                     return(false);
630                 }
631             }
632             assignment = assignment->nextAssignment;
633         }
634         rmDtbUtilPolicyFreeAssignments(assignmentStart);
635     }
636     else {
637         return(false);
638     }
639     
640     return(true);
643 /* FUNCTION PURPOSE: Returns resource base value according to the Policy
644  ***********************************************************************
645  * DESCRIPTION: Returns a resource base value based on the resource
646  *              ranges assigned to the specified valid instance by the
647  *              Policy DTB.
648  */
649 uint32_t rmPolicyGetResourceBase(void *policyDtb, Rm_PolicyValidInstNode *validInstNode, 
650                                  int32_t resourceOffset, uint32_t allocType, 
651                                  int32_t *result)
654     int32_t              propertyOffset;
655     const char          *propertyName;
656     int32_t              propertyLen;
657     const void          *propertyData;
658     Rm_PolicyAssignment *assignment = NULL;
659     Rm_PolicyAssignment *assignmentStart = NULL;
660     Rm_PolicyPermission *permission = NULL;
661     Rm_PolicyPermission *permissionStart = NULL;
662     uint32_t             resourceBase = 0;
664     propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
665     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
666         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
667             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
668             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
669                 assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
670                 break;
671             }
672             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
673         }
674     }
676     /* Search policy permissions for valid resource base */
677     while (assignment) {
678         permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
679         while (permission) {
680             if ((strncmp(permission->instName, validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
681                 (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
682                 /* Check instance's permissions */
683                 if (RM_policy_GET_PERM(allocType, RM_POLICY_PERM_INIT_SHIFT) &&
684                     RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
685                     resourceBase = assignment->resourceBase;
686                     break;
687                 }
688                 else if (RM_policy_GET_PERM(allocType, RM_POLICY_PERM_USE_SHIFT) &&
689                          RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
690                     resourceBase = assignment->resourceBase;
691                     break;
692                 }
693             }
694             permission = permission->nextPermission;
695         }
696         policyFreeAssignmentPermissions(permissionStart);
698         if (resourceBase) {
699             break;
700         }
701         else {
702             assignment = assignment->nextAssignment;
703         }
704     }
706     if (assignmentStart) {
707         rmDtbUtilPolicyFreeAssignments(assignmentStart);
708     }
709     
710     return(resourceBase);
713 /* FUNCTION PURPOSE: Returns resource alignment value according to the Policy
714  ***********************************************************************
715  * DESCRIPTION: Returns a resource alignment value based on the resource
716  *              alignment assigned to the specified valid instance by the
717  *              Policy DTB.
718  */
719 uint32_t rmPolicyGetResourceAlignment(void *policyDtb, int32_t resourceOffset)
721     int32_t            propertyOffset;
722     const char        *propertyName;
723     int32_t            propertyLen;
724     const void        *propertyData;
725     Rm_ResourceValue  *alignmentList;
726     uint32_t           resourceAlignment = 0;
728     propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
729     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
730         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
731             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
732             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ALLOCATION_ALIGNMENT) {
733                 alignmentList = rmDtbUtilPolicyExtractResourceAlignments(propertyData, propertyLen);
734                 resourceAlignment = alignmentList->value;                
735                 rmDtbUtilPolicyFreeResourceAlignments(alignmentList);
736             }
737             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
738         }
739     }
740     return(resourceAlignment);
743 /* FUNCTION PURPOSE: Get a resource's offset into a Policy
744  ***********************************************************************
745  * DESCRIPTION: Returns the location of the specified resource node
746  *              within the specified Policy in the form of an offset
747  *              into the DTB.  The resourceName and the Policy
748  *              node name must match.
749  */
750 int32_t rmPolicyGetResourceOffset(void *policyDtb, char *resourceName)
752     int32_t     nodeOffset;
753     int32_t     depth;
754     const char *nodeName;
756     depth = RM_DTB_UTIL_STARTING_DEPTH;
757     nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;       
759     /* Find node offset for provided resource name */
760     while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && 
761            (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
762         nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
763         nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
765         if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0)
766         {
767             break;
768         }
769     }
771     if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
772         /* Resource name not found */
773         nodeOffset = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
774     }
775     return(nodeOffset);
778 /* FUNCTION PURPOSE: Validates a Policy's resource node names
779  ***********************************************************************
780  * DESCRIPTION: Returns RM_OK if all of a Policy's resource node names
781  *              match a node name specified in the "valid-instances"
782  *              list specified at the top of the Policy.  Otherwise,
783  *              returns error
784  */
785 int32_t rmPolicyValidatePolicyResourceNames(void *policyDtb, void *allocatorList)
787     Rm_Allocator *allocator = (Rm_Allocator *)allocatorList;
788     int32_t       nodeOffset;
789     int32_t       depth;
790     const char   *nodeName;
792     depth = RM_DTB_UTIL_STARTING_DEPTH;
793     nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;       
795     /* Parse DTB, verifying each resource's assignment permissions.
796      * Permissions must have correct syntax and contain valid instance names
797      * according validInstList */
798     while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && 
799            (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
800         nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
801         nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
802         if (fdt_first_property_offset(policyDtb, nodeOffset) > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
803             if (rmAllocatorFind(allocator, (char *)nodeName) == NULL) {
804                 /* No allocator tied to resource name */
805                 return(RM_ERROR_UNKNOWN_RESOURCE_IN_POLICY);
806             }        
807         }
808     }
809     return(RM_OK);
812 /* FUNCTION PURPOSE: Validates a Policy DTB
813  ***********************************************************************
814  * DESCRIPTION: Returns RM_OK if the input Policy satisfies the
815  *              following conditions:
816  *              a) All "assignment" permission string parse okay
817  *              b) All RM instance names specified in the permission
818  *                 strings match an instance name in the valid instance
819  *                 list
820  *              c) All resource node names match a resource allocator
821  */
822 int32_t rmPolicyValidatePolicy(void *policyDtb, Rm_PolicyValidInstTree *validInstTree)
824     int32_t              nodeOffset;
825     int32_t              propertyOffset;
826     int32_t              depth;
827     const char          *propertyName;
828     int32_t              propertyLen;
829     const void          *propertyData;
830     Rm_PolicyPropType    propertyType;
831     Rm_PolicyAssignment *assignmentList;
832     int32_t              result;
834     depth = RM_DTB_UTIL_STARTING_DEPTH;
835     nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;       
837     /* Parse DTB, verifying each resource's assignment permissions.
838      * Permissions must have correct syntax and contain valid instance names
839      * according validInstList */
840     while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && 
841            (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
842         nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
843         propertyOffset = fdt_first_property_offset(policyDtb, nodeOffset);                
844         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
845             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
846             propertyType = rmDtbUtilPolicyGetPropertyType(propertyName);
847             if (propertyType == Rm_policyPropType_ASSIGNMENTS) {
848                 assignmentList = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
849                 
850                 if ((result = policyValidateAssignmentPermissions(validInstTree, assignmentList)) != RM_OK) {
851                     rmDtbUtilPolicyFreeAssignments(assignmentList);
852                     return(result);
853                 }
854                 rmDtbUtilPolicyFreeAssignments(assignmentList);
855             }
856             else if (propertyType == Rm_policyPropType_UNKNOWN) {
857                 return(RM_ERROR_UNKNOWN_POLICY_RESOURCE_PROPERTY);
858             }
859             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
860         }
861     }
862     return(RM_OK);
865 /* FUNCTION PURPOSE: Creates the valid instance tree for a RM instance
866  ***********************************************************************
867  * DESCRIPTION: Creates the valid instance tree for a RM instance 
868  *              that has been provided a global or static policy
869  *              The valid instance tree is created from the
870  *              "valid-instances" property at the top of the Policy.
871  *              The root entry of the valid instance tree is returned.
872  */
873 Rm_PolicyValidInstTree *rmPolicyCreateValidInstTree(void *policyDtb, bool addLinux, int32_t *result)
875     int32_t                 validInstOffset;
876     const char             *validInstName = NULL;
877     int32_t                 validInstLen;
878     const void             *validInstData = NULL;
879     Rm_PolicyPropType       propertyType;
880     Rm_PolicyValidInst     *validInstList = NULL;
881     Rm_PolicyValidInstTree *rootEntry = NULL;
882     Rm_PolicyValidInstNode *newNode = NULL;  
883     char                    linuxName[] = RM_ALLOCATED_TO_LINUX;
885     /* Valid instance list must be first and only property in the root node of
886      * the policyDtb */
887     validInstOffset = fdt_first_property_offset(policyDtb, RM_DTB_UTIL_STARTING_NODE_OFFSET);
888     if (validInstOffset < -FDT_ERR_NOTFOUND) {
889         *result = validInstOffset;
890         return (NULL);
891     } 
892     else if (validInstOffset == -FDT_ERR_NOTFOUND) {
893         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
894         return (NULL);
895     }
896     validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset, &validInstName, &validInstLen);
897     propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
898     if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
899         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
900         return (NULL);
901     }
903     if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData, validInstLen, result))) {
904         return (NULL);
905     }
906     
907     /* Create the tree */
908     rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
909     RB_INIT(rootEntry);
911     while (validInstList) {
912         newNode = rmPolicyValidInstNodeNew(validInstList->instName);
913         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
914         
915         validInstList = validInstList->nextValidInst;
916     }
918     /* Add the Linux kernel node */
919     if (addLinux) {
920         newNode = rmPolicyValidInstNodeNew(linuxName);
921         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);    
922     }
924     *result = RM_OK;
925     return (rootEntry);
928 /* FUNCTION PURPOSE: Deletes a valid instance tree
929  ***********************************************************************
930  * DESCRIPTION: Frees all memory associated with a Policy valid
931  *              instance tree.
932  */
933 void rmPolicyFreeValidInstTree(Rm_PolicyValidInstTree *validInstTree)
935     Rm_PolicyValidInstNode *node;
936     Rm_PolicyValidInstNode *nextNode;
938     for (node = RB_MIN(_Rm_PolicyValidInstTree, validInstTree); node != NULL; node = nextNode) {
939         nextNode = RB_NEXT(_Rm_PolicyValidInstTree, validInstTree, node);
940         RB_REMOVE(_Rm_PolicyValidInstTree, validInstTree, node);
941         rmPolicyValidInstNodeFree(node);
942     }     
943     if (RB_MIN(_Rm_PolicyValidInstTree, validInstTree) == NULL) {
944         /* No more valid instance nodes in tree */
945         Rm_osalFree((void *)validInstTree, sizeof(Rm_PolicyValidInstTree));
946     }