Resolved SDOCM00101586. Added test cases to cover resolved issued
[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>
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     strncpy(permStrPtr, permStrStart, permStrLen);
147     /* Make sure the last character in the copied sub-permission string is null */
148     permStrPtr[permStrLen - 1] = '\0';
150     permStrStart = permStrPtr;
151     permStrEnd = permStrPtr + strlen(permStrPtr);
153     /* Find the beginning and end of the sub-permission instance group */
154     subgroupStart = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START);
155     subgroupEnd = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END);
157     if ((!subgroupStart) || (!subgroupEnd) || (subgroupStart > subgroupEnd) ||
158         ((subgroupStart != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START)) &&
159          (subgroupEnd != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END)))) {
160         /* Free the memory associated with the temp string and return an error if:
161          * a) Could not find the instance group start
162          * b) Could not find the instance group end
163          * c) Subgroup start and end are out of order
164          * d) There is more than one instance subgroup specified in the string.  There
165          *    should only be one subgroup per sub-permission string */
166         *result = RM_ERROR_PERM_STR_TOO_MANY_INST_GROUPS;
167         goto parseError;
168     }
170     /* Create a permission entry for each instance specified in the instance group.
171      * Instances names are separated by one or more spaces. */
172     permStrPtr = subgroupStart + 1;
173     instNameIndex = 0;
174     foundInstName = RM_FALSE;
175     instNameComplete = RM_FALSE;
176     while (permStrPtr <= subgroupEnd) {
177         if ((isspace(*permStrPtr) || (*permStrPtr == RM_POLICY_PERM_SUBGROUP_END))
178             && foundInstName) {
179             /* First space encountered after copying an instance name.  This
180              * terminates the instance name.  All other space characters are
181              * ignored. */
182             instNameTemp[instNameIndex] = '\0';
183             instNameComplete = RM_TRUE; 
184         }
185         else {
186             if (!foundInstName) {
187                 /* First non-whitespace character encountered is the start of an
188                  * instance name */
189                 foundInstName = RM_TRUE;
190             }
192             /* Copy the character into the temporary instance name string */
193             instNameTemp[instNameIndex++] = *permStrPtr;
194         }
196         if (instNameComplete) {
197             newPerm = (Rm_PolicyPermission *) Rm_osalMalloc(sizeof(Rm_PolicyPermission));
198             memset((void *)newPerm, 0, sizeof(Rm_PolicyPermission));
200             strncpy(newPerm->instName, instNameTemp, RM_NAME_MAX_CHARS);
201             newPerm->nextPermission = NULL;
203             if (prevPerm == NULL) {
204                 /* Save the first instance so it can be returned */
205                 startPerm = newPerm;
206             }
207             else {
208                 prevPerm->nextPermission = newPerm;
209             }
210             prevPerm = newPerm;
212             instNameComplete = RM_FALSE;
213             instNameIndex = 0;
214             foundInstName = RM_FALSE;
215         }
216         else if (instNameIndex == RM_NAME_MAX_CHARS) {
217             /* Instance name is longer than max length */
218             *result = RM_ERROR_INST_NAME_IN_ASSIGNMENT_TOO_LONG;
219             goto parseError;
220         }
222         permStrPtr++;
223     }
225     /* Fill in the permissions for each instance name */
227     /* Look on left of instance group for permission assignments. */
228     permStrPtr = subgroupStart - 1;
229     assignmentLeft = RM_FALSE;
230     while (permStrPtr >= permStrStart)
231     {
232         if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
233             if (assignmentLeft) {
234                 /* Assignment character has been found more than once.  This is a
235                  * syntax error.  Free the permission list and the temporary string
236                  * and return. */
237                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
238                 goto parseError;
239             }
240             else {
241                 assignmentLeft = RM_TRUE;
242             }
243         }
244         else if (!isspace(*permStrPtr)) {
245             if (assignmentLeft) {
246                 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) || 
247                     (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
248                     newPerm = startPerm;
249                     while (newPerm) {
250                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1);
251                         newPerm = newPerm->nextPermission;
252                     }
253                 }
254                 else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) || 
255                          (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
256                     newPerm = startPerm;
257                     while (newPerm) {                                           
258                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1);
259                         newPerm = newPerm->nextPermission;
260                     }
261                 }
262                 else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) || 
263                          (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
264                     newPerm = startPerm;
265                     while (newPerm) {                       
266                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
267                         newPerm = newPerm->nextPermission;
268                     }
269                 }
270                 else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) || 
271                          (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
272                     newPerm = startPerm;
273                     while (newPerm) {                       
274                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1);
275                         newPerm = newPerm->nextPermission;
276                     }
277                 }                
278                 else {
279                     /* Invalid permission character.  This is a
280                      * syntax error.  Free the permission list and the temporary string
281                      * and return. */
282                     *result = RM_ERROR_PERM_STR_INVALID_CHAR;
283                     goto parseError;
284                 }
285             }
286             else {
287                 /* Character found without the assignment character being found.  This is a
288                  * syntax error.  Free the permission list and the temporary string
289                  * and return. */
290                 *result = RM_ERROR_PERM_CHAR_WITHOUT_ASSIGN_CHAR;
291                 goto parseError;
292             }
293         }
294         permStrPtr--;
295     }
297     /* Look on right of instance group for permission assignments. */
298     permStrPtr = subgroupEnd + 1;
299     assignmentRight = RM_FALSE;
300     while (permStrPtr < permStrEnd) {
301         if (assignmentLeft && (!isspace(*permStrPtr))) {
302             /* There should be nothing but spaces on right if assignment was already found on left */
303             *result = RM_ERROR_INVALID_PERMS_CHAR_ON_RIGHT;
304             goto parseError;             
305         }
306         
307         if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
308             if (assignmentRight) {
309                 /* Assignment character has been found more than once.  This is a
310                  * syntax error.  Free the permission list and the temporary string
311                  * and return. */
312                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
313                 goto parseError;               
314             }
315             else {
316                 assignmentRight = RM_TRUE;
317             }
318         }
319         else if (!isspace(*permStrPtr)) {
320             if (assignmentRight) {
321                 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) || 
322                     (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
323                     newPerm = startPerm;
324                     while (newPerm) {
325                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1);
326                         newPerm = newPerm->nextPermission;
327                     }
328                 }
329                 else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) || 
330                          (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
331                     newPerm = startPerm;
332                     while (newPerm) {                                           
333                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1);
334                         newPerm = newPerm->nextPermission;
335                     }
336                 }
337                 else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) || 
338                          (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
339                     newPerm = startPerm;
340                     while (newPerm) {                       
341                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
342                         newPerm = newPerm->nextPermission;
343                     }
344                 }
345                 else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) || 
346                          (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
347                     newPerm = startPerm;
348                     while (newPerm) {                       
349                         RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1);
350                         newPerm = newPerm->nextPermission;
351                     }
352                 }                  
353                 else {
354                     /* Invalid permission character.  This is a
355                      * syntax error.  Free the permission list and the temporary string
356                      * and return. */
357                     *result = RM_ERROR_PERM_STR_INVALID_CHAR;
358                     goto parseError;                   
359                 }
360             }
361             else {
362                 /* Character found without the assignment character being found.  This is a
363                  * syntax error.  Free the permission list and the temporary string
364                  * and return. */
365                 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
366                 goto parseError;
367             }
368         }
369         permStrPtr++;
370     }
372     Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
373     *result = RM_OK;
374     return (startPerm);
376 parseError:
377     while (startPerm) {
378         nextPerm = startPerm->nextPermission;
379         Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
380         startPerm = nextPerm;
381     }    
382     Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
383     return(NULL);     
386 /* FUNCTION PURPOSE: Frees a linked list of assignment permissions
387  ***********************************************************************
388  * DESCRIPTION: Frees the memory associated with a linked list of
389  *              assignment permissions extracted from a permissions
390  *              assignment subgroup in a policy DTB.
391  */
392 static void policyFreeAssignmentPermissions(Rm_PolicyPermission *permissionList)
394     Rm_PolicyPermission *nextPerm;
395     
396     while (permissionList) {
397         nextPerm = permissionList->nextPermission;
398         Rm_osalFree((void *)permissionList, sizeof(Rm_PolicyPermission));
399         permissionList = nextPerm;
400     }
403 /* FUNCTION PURPOSE: Extracts permissions from a Policy "assignment"
404  ***********************************************************************
405  * DESCRIPTION: Returns a linked list of permissions for a resource node
406  *              containing an "assignment" property in the Policy DTB.
407  *              Each node in the linked list will contain a valid instance
408  *              name along with the permissions assigned to the instance
409  */
410 static Rm_PolicyPermission *policyGetAssignmentPermissions(Rm_PolicyAssignment *assignment, 
411                                                            int32_t *result)
413     Rm_PolicyPermission *startPerm = NULL;
414     Rm_PolicyPermission *newPerm = NULL;
415     Rm_PolicyPermission *prevPerm = NULL;
416     char                *permStrStart = assignment->permissionsList;
417     char                *permStrEnd;
418     uint32_t             permStrLen = strlen(assignment->permissionsList) + 1;
419     uint32_t             i = 0;
421     *result = RM_OK;
422     
423     while(i < permStrLen) {
424         /* Find the first sub-permission specification and parse it.  A sub-permission
425          * can be terminated by the termination character or the end of the string. */
426         if (!(permStrEnd = strchr(permStrStart, RM_POLICY_PERM_TERMINATOR))) {           
427             /* Sub-permission termination character not found.  The permission string
428              * end is the end of the entire permission string */
429             permStrEnd = permStrStart + strlen(permStrStart);
430         }
432         newPerm = policyParseSubPermission(permStrStart, permStrEnd, result);
434         if (*result != RM_OK) {
435             /* Delete the permission list that's been created thus far, return
436              * the error and NULL for the permission list */
437             policyFreeAssignmentPermissions(startPerm);
438             return(NULL);
439         }
441         if (prevPerm == NULL) {
442             startPerm = newPerm;
443         }
444         else {
445             prevPerm->nextPermission = newPerm;
446         }
448         /* Set prevPerm to the last sub-permission returned by the sub-permission parser */
449         prevPerm = newPerm;
450         while(prevPerm->nextPermission != NULL) {
451             prevPerm = prevPerm->nextPermission;
452         }
453         
454         /* Update the number of characters parsed from the permission list and point to 
455          * the start of the next sub-permission */
456         i += ((uint32_t)(permStrEnd - permStrStart + 1));
457         permStrStart = permStrEnd + 1;
458     }
460     return(startPerm);
463 /* FUNCTION PURPOSE: Validates a policy "assignment" string list
464  ***********************************************************************
465  * DESCRIPTION: Returns RM_OK if the specified Policy DTB "assignment"
466  *              property specification parses okay and all the RM
467  *              instances in the assignment match RM instances in the
468  *              valid instances list
469  */
470 static int32_t policyValidateAssignmentPermissions(Rm_Handle rmHandle,
471                                                    Rm_PolicyAssignment *assignmentList)
473     Rm_PolicyAssignment *assignment = assignmentList;
474     Rm_PolicyPermission *permissionList;
475     int32_t              result;
477     while (assignment) {
478         /* Make sure assignment's permissions parse okay */
479         permissionList = policyGetAssignmentPermissions(assignment, &result);
480         if (result != RM_OK) {
481             return(result);
482         }                        
483         
484         if (result = policyCheckInstances(rmHandle, permissionList) != RM_OK) {
485             policyFreeAssignmentPermissions(permissionList);
486             return(result);
487         }
489         policyFreeAssignmentPermissions(permissionList);
490         assignment = assignment->nextAssignment;
491     }
493     return (RM_OK);
496 /**********************************************************************
497  ************************ Internal Policy APIs ************************
498  **********************************************************************/
500 /* FUNCTION PURPOSE: Returns a pointer to the instance policy
501  ***********************************************************************
502  * DESCRIPTION: Returns a pointer to the instance's policy based on
503  *              the instance type
504  */
505 void *rmPolicyGetPolicy(Rm_Handle rmHandle)
507     Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
508     void    *policy = NULL;
510     if ((rmInst->instType == Rm_instType_SERVER) ||
511         (rmInst->instType == Rm_instType_SHARED_SERVER)) {
512         policy = rmInst->u.server.globalPolicy;
513     }
514     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
515         policy = rmInst->u.cd.cdPolicy;
516     }
517     else if (rmInst->instType == Rm_instType_CLIENT) {
518         policy = rmInst->u.client.staticPolicy;
519     }
520     return(policy);
523 /* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree
524  ***********************************************************************
525  * DESCRIPTION: Returns a valid instance node from the valid instance
526  *              tree that matches the specified instName
527  */
528 Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_Handle rmHandle, char *instName)
530     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
531     Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle);
532     Rm_PolicyValidInstNode  findNode;
534     if (rmInst->instType == Rm_instType_SHARED_SERVER) {
535         rmPolicyValidInstTreeInv(treeRoot);
536     }
538     memset((void *)&findNode, 0, sizeof(Rm_PolicyValidInstNode));
539     strncpy(findNode.name, instName, RM_NAME_MAX_CHARS);
540     
541     return (RB_FIND(_Rm_PolicyValidInstTree, treeRoot, &findNode));
544 /* FUNCTION PURPOSE: Gets the Linux Valid instance node
545  ***********************************************************************
546  * DESCRIPTION: Returns a pointer to the valid instance node in the
547  *              valid instance tree that matches the instance name
548  *              reserved for resource assigned to the Linux kernel.
549  */
550 Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_Handle rmHandle)
552     char linuxName[] = RM_ALLOCATED_TO_LINUX;
554     return (rmPolicyGetValidInstNode(rmHandle, linuxName));
557 /* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB
558  ***********************************************************************
559  * DESCRIPTION: Returns TRUE if the instance name has the specified
560  *              permissions for the specified resource in the Policy
561  *              DTB.  Otherwise, returns FALSE.
562  */
563 int rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg, int32_t *result)
565     int32_t              propertyOffset;
566     const char          *propertyName;
567     int32_t              propertyLen;
568     const void          *propertyData;
569     Rm_PolicyAssignment *assignment = NULL;
570     Rm_PolicyAssignment *assignmentStart = NULL;
571     Rm_PolicyPermission *permission = NULL;
572     Rm_PolicyPermission *permissionStart = NULL;
573     uint32_t             assignmentEnd;
574     uint32_t             resourceEnd = privilegeCfg->resourceBase + privilegeCfg->resourceLength - 1;
575     int                  foundInstance;
577     *result = RM_OK;
579     /* Get the resource's assignments */
580     propertyOffset = fdt_first_property_offset(privilegeCfg->policyDtb, privilegeCfg->resourceOffset);
581     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
582         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
583             propertyData = fdt_getprop_by_offset(privilegeCfg->policyDtb, propertyOffset, &propertyName, &propertyLen);
584             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
585                 assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
586                 break;
587             }
588             propertyOffset = fdt_next_property_offset(privilegeCfg->policyDtb, propertyOffset);
589         }
590     }
592     if (assignment) {
593         while (assignment) {
594             assignmentEnd = assignment->resourceBase + assignment->resourceLength - 1;
595             foundInstance = RM_FALSE;
596             if (((privilegeCfg->resourceBase >= assignment->resourceBase) &&
597                  (privilegeCfg->resourceBase <= assignmentEnd)) ||
598                 ((privilegeCfg->resourceBase < assignment->resourceBase) &&
599                  (resourceEnd > assignmentEnd)) ||
600                 ((resourceEnd >= assignment->resourceBase) &&
601                  (resourceEnd <= assignmentEnd))) {
602                  
603                 permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
604                 while (permission) {
605                     if ((strncmp(permission->instName, privilegeCfg->validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
606                         (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
607                         foundInstance = RM_TRUE;
608                         
609                         /* Check instance's permissions */
610                         if (privilegeCfg->type == Rm_policyCheck_INIT) {
611                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
612                                 policyFreeAssignmentPermissions(permissionStart);
613                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
614                                 return(RM_FALSE);
615                             }
616                         }
617                         else if (privilegeCfg->type == Rm_policyCheck_USE) {
618                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
619                                 policyFreeAssignmentPermissions(permissionStart);
620                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
621                                 return(RM_FALSE);
622                             }   
623                         }
624                         else if (privilegeCfg->type == Rm_policyCheck_EXCLUSIVE) {
625                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT)) {
626                                 policyFreeAssignmentPermissions(permissionStart);
627                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
628                                 return(RM_FALSE);
629                             }   
630                         }
631                         else if (privilegeCfg->type == Rm_policyCheck_SHARED_LINUX) {
632                             if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT)) {
633                                 policyFreeAssignmentPermissions(permissionStart);
634                                 rmDtbUtilPolicyFreeAssignments(assignmentStart);
635                                 return(RM_FALSE);
636                             }   
637                         }                        
638                         break;
639                     }
640                     permission = permission->nextPermission;
641                 }
642                 
643                 policyFreeAssignmentPermissions(permissionStart);
644                 if (!foundInstance) {
645                     rmDtbUtilPolicyFreeAssignments(assignmentStart);
646                     return(RM_FALSE);
647                 }
648             }
649             assignment = assignment->nextAssignment;
650         }
651         rmDtbUtilPolicyFreeAssignments(assignmentStart);
652     }
653     else {
654         return(RM_FALSE);
655     }
656     
657     return(RM_TRUE);
660 /* FUNCTION PURPOSE: Returns resource base value according to the Policy
661  ***********************************************************************
662  * DESCRIPTION: Returns a resource base value based on the resource
663  *              ranges assigned to the specified valid instance by the
664  *              Policy DTB.
665  */
666 uint32_t rmPolicyGetResourceBase(void *policyDtb, Rm_PolicyValidInstNode *validInstNode, 
667                                  int32_t resourceOffset, Rm_PolicyCheckType policyCheckType, 
668                                  int32_t *result)
671     int32_t              propertyOffset;
672     const char          *propertyName;
673     int32_t              propertyLen;
674     const void          *propertyData;
675     Rm_PolicyAssignment *assignment = NULL;
676     Rm_PolicyAssignment *assignmentStart = NULL;
677     Rm_PolicyPermission *permission = NULL;
678     Rm_PolicyPermission *permissionStart = NULL;
679     int32_t              resourceBase = RM_RESOURCE_BASE_UNSPECIFIED;
681     *result = RM_OK;
683     propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
684     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
685         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
686             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
687             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
688                 assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
689                 break;
690             }
691             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
692         }
693     }
695     /* Search policy permissions for valid resource base */
696     while (assignment) {
697         permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
698         while (permission) {
699             if ((strncmp(permission->instName, validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
700                 (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
701                 /* Check instance's permissions */
702                 if ((policyCheckType == Rm_policyCheck_INIT) &&
703                     RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
704                     resourceBase = assignment->resourceBase;
705                     break;
706                 }
707                 else if ((policyCheckType == Rm_policyCheck_USE) &&
708                          RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
709                     resourceBase = assignment->resourceBase;
710                     break;
711                 }
712             }
713             permission = permission->nextPermission;
714         }
715         policyFreeAssignmentPermissions(permissionStart);
717         if (resourceBase != RM_RESOURCE_BASE_UNSPECIFIED) {
718             break;
719         }
720         else {
721             assignment = assignment->nextAssignment;
722         }
723     }
725     if (assignmentStart) {
726         rmDtbUtilPolicyFreeAssignments(assignmentStart);
727     }
728     
729     return(resourceBase);
732 /* FUNCTION PURPOSE: Returns resource alignment value according to the Policy
733  ***********************************************************************
734  * DESCRIPTION: Parses the policy DTB to find and return a resource's 
735  *              alignment.
736  */
737 uint32_t rmPolicyGetResourceAlignment(void *policyDtb, int32_t resourceOffset)
739     int32_t            propertyOffset;
740     const char        *propertyName;
741     int32_t            propertyLen;
742     const void        *propertyData;
743     Rm_ResourceValue  *alignmentList;
744     uint32_t           resourceAlignment = 0;
746     propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
747     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
748         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
749             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
750             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ALLOCATION_ALIGNMENT) {
751                 alignmentList = rmDtbUtilPolicyExtractResourceAlignments(propertyData, propertyLen);
752                 resourceAlignment = alignmentList->value;                
753                 rmDtbUtilPolicyFreeResourceAlignments(alignmentList);
754             }
755             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
756         }
757     }
758     return(resourceAlignment);
761 /* FUNCTION PURPOSE: Returns resource CD allocation size according to the Policy
762  ***********************************************************************
763  * DESCRIPTION: Parses the policy DTB to find and return a resource's 
764  *              allocation size.
765  */
766 uint32_t rmPolicyGetResourceCdAllocSize(void *policyDtb, int32_t resourceOffset)
768     int32_t            propertyOffset;
769     const char        *propertyName;
770     int32_t            propertyLen;
771     const void        *propertyData;
772     Rm_ResourceValue  *allocSizeList;
773     uint32_t           resourceAllocSize = 0;
775     propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
776     if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
777         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
778             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
779             if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_CD_ALLOCATION_SIZE) {
780                 allocSizeList = rmDtbUtilPolicyExtractCdAllocationSizes(propertyData, propertyLen);
781                 resourceAllocSize = allocSizeList->value;                
782                 rmDtbUtilPolicyFreeCdAllocationSizes(allocSizeList);
783             }
784             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
785         }
786     }
787     return(resourceAllocSize);
791 /* FUNCTION PURPOSE: Get a resource's offset into a Policy
792  ***********************************************************************
793  * DESCRIPTION: Returns the location of the specified resource node
794  *              within the specified Policy in the form of an offset
795  *              into the DTB.  The resourceName and the Policy
796  *              node name must match.
797  */
798 int32_t rmPolicyGetResourceOffset(void *policyDtb, char *resourceName)
800     int32_t     nodeOffset;
801     int32_t     depth;
802     const char *nodeName;
804     if (policyDtb) {
805         depth = RM_DTB_UTIL_STARTING_DEPTH;
806         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;       
808         /* Find node offset for provided resource name */
809         while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
810             nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
811             if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
812                 /* Resource name not found */
813                 nodeOffset = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
814                 break;
815             } 
816             else {
817                 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
818                 if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0) {
819                     break;
820                 }
821             }
822         }
823     }
824     else {
825         nodeOffset = RM_ERROR_INSTANCE_HAS_NO_POLICY;
826     }
827     return(nodeOffset);
830 /* FUNCTION PURPOSE: Validates a Policy's resource node names
831  ***********************************************************************
832  * DESCRIPTION: Returns RM_OK if all of a Policy's resource node names
833  *              match a node name specified in the "valid-instances"
834  *              list specified at the top of the Policy.  Otherwise,
835  *              returns error
836  */
837 int32_t rmPolicyValidatePolicyResourceNames(Rm_Handle rmHandle)
839     void       *policyDtb = rmPolicyGetPolicy(rmHandle);
840     int32_t     nodeOffset;
841     int32_t     depth;
842     const char *nodeName;
844     depth = RM_DTB_UTIL_STARTING_DEPTH;
845     nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;       
847     /* Parse DTB, verifying each resource's assignment permissions.
848      * Permissions must have correct syntax and contain valid instance names
849      * according validInstList */
850     while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
851         nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
852         if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
853             break;
854         }
855         nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
856         if (fdt_first_property_offset(policyDtb, nodeOffset) > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
857             if (rmAllocatorFind(rmHandle, nodeName) == NULL) {
858                 /* No allocator tied to resource name */
859                 return(RM_ERROR_UNKNOWN_RESOURCE_IN_POLICY);
860             }        
861         }
862     }
863     return(RM_OK);
866 /* FUNCTION PURPOSE: Validates a Policy DTB
867  ***********************************************************************
868  * DESCRIPTION: Returns RM_OK if the input Policy satisfies the
869  *              following conditions:
870  *              a) All "assignment" permission string parse okay
871  *              b) All RM instance names specified in the permission
872  *                 strings match an instance name in the valid instance
873  *                 list
874  *              c) All resource node names match a resource allocator
875  */
876 int32_t rmPolicyValidatePolicy(Rm_Handle rmHandle)
878     void                *policyDtb = rmPolicyGetPolicy(rmHandle);
879     int32_t              nodeOffset;
880     int32_t              propertyOffset;
881     int32_t              depth;
882     const char          *propertyName;
883     int32_t              propertyLen;
884     const void          *propertyData;
885     Rm_PolicyPropType    propertyType;
886     Rm_PolicyAssignment *assignmentList;
887     int32_t              result;
889     depth = RM_DTB_UTIL_STARTING_DEPTH;
890     nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;       
892     /* Parse DTB, verifying each resource's assignment permissions.
893      * Permissions must have correct syntax and contain valid instance names
894      * according validInstList */
895     while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
896         nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
897         if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
898             break;
899         }
900         propertyOffset = fdt_first_property_offset(policyDtb, nodeOffset);                
901         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
902             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
903             propertyType = rmDtbUtilPolicyGetPropertyType(propertyName);
904             if (propertyType == Rm_policyPropType_ASSIGNMENTS) {
905                 assignmentList = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
906                 
907                 if ((result = policyValidateAssignmentPermissions(rmHandle, assignmentList)) != RM_OK) {
908                     rmDtbUtilPolicyFreeAssignments(assignmentList);
909                     return(result);
910                 }
911                 rmDtbUtilPolicyFreeAssignments(assignmentList);
912             }
913             else if (propertyType == Rm_policyPropType_UNKNOWN) {
914                 return(RM_ERROR_UNKNOWN_POLICY_RESOURCE_PROPERTY);
915             }
916             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
917         }
918     }
919     return(RM_OK);
922 /* FUNCTION PURPOSE: Creates the valid instance tree for a RM instance
923  ***********************************************************************
924  * DESCRIPTION: Creates the valid instance tree for a RM instance 
925  *              that has been provided a global or static policy
926  *              The valid instance tree is created from the
927  *              "valid-instances" property at the top of the Policy.
928  *              The root entry of the valid instance tree is returned.
929  */
930 Rm_PolicyValidInstTree *rmPolicyCreateValidInstTree(Rm_Handle rmHandle, int addLinux, int32_t *result)
932     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
933     void                   *policyDtb = rmPolicyGetPolicy(rmHandle);
934     int32_t                 validInstOffset;
935     const char             *validInstName = NULL;
936     int32_t                 validInstLen;
937     const void             *validInstData = NULL;
938     Rm_PolicyPropType       propertyType;
939     Rm_PolicyValidInst     *vInstListStart = NULL;
940     Rm_PolicyValidInst     *validInstList = NULL;
941     Rm_PolicyValidInstTree *rootEntry = NULL;
942     Rm_PolicyValidInstNode *newNode = NULL;  
943     char                    linuxName[] = RM_ALLOCATED_TO_LINUX;
945     /* Valid instance list must be first and only property in the root node of
946      * the policyDtb */
947     validInstOffset = fdt_first_property_offset(policyDtb, RM_DTB_UTIL_STARTING_NODE_OFFSET);
948     if (validInstOffset < -FDT_ERR_NOTFOUND) {
949         *result = validInstOffset;
950         return (NULL);
951     } 
952     else if (validInstOffset == -FDT_ERR_NOTFOUND) {
953         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
954         return (NULL);
955     }
956     validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset, &validInstName, &validInstLen);
957     propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
958     if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
959         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
960         return (NULL);
961     }
963     if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData, validInstLen, result))) {
964         return (NULL);
965     }
966     
967     /* Create the tree */
968     rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
969     RB_INIT(rootEntry);
971     vInstListStart = validInstList;
972     while (validInstList) {
973         newNode = rmPolicyValidInstNodeNew(validInstList->instName);
974         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
975         
976         validInstList = validInstList->nextValidInst;
977     }
978     rmDtbUtilPolicyFreeValidInstances(vInstListStart);
980     /* Add the Linux kernel node */
981     if (addLinux) {
982         newNode = rmPolicyValidInstNodeNew(linuxName);
983         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);    
984     }
986     if (rmInst->instType == Rm_instType_SHARED_SERVER) {
987         /* Writeback the valid instance tree */
988         rmPolicyValidInstTreeWb(rootEntry);
989     }
991     *result = RM_OK;
992     return (rootEntry);
995 /* FUNCTION PURPOSE: Deletes a valid instance tree
996  ***********************************************************************
997  * DESCRIPTION: Frees all memory associated with a Policy valid
998  *              instance tree.
999  */
1000 void rmPolicyFreeValidInstTree(Rm_Handle rmHandle)
1002     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
1003     Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle);
1004     Rm_PolicyValidInstNode *node;
1005     Rm_PolicyValidInstNode *nextNode;
1007     if (treeRoot) {
1008         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1009             rmPolicyValidInstTreeInv(treeRoot);
1010         }
1012         for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot); node != NULL; node = nextNode) {
1013             nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node);
1014             RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node);
1015             rmPolicyValidInstNodeFree(node);
1016         }
1018         /* Don't need to writeback tree node changes since valid instance will be made
1019          * NULL in instance */
1020          
1021         if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) {
1022             /* No more valid instance nodes in tree */
1023             Rm_osalFree((void *)treeRoot, sizeof(Rm_PolicyValidInstTree));
1024         }
1026         if ((rmInst->instType == Rm_instType_SERVER) ||
1027             (rmInst->instType == Rm_instType_SHARED_SERVER)) {
1028             rmInst->u.server.globalValidInstTree = NULL;
1029         }
1030         else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1031             rmInst->u.cd.cdValidInstTree = NULL;
1032         }
1033         else if (rmInst->instType == Rm_instType_CLIENT) {
1034             rmInst->u.client.staticValidInstTree = NULL;
1035         }
1036     }