Fixed bug where unspecified base requests couldn't return a resource value of zero
[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     uint32_t             resourceBase = 0;
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                (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
811             nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
812             if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
813                 /* Resource name not found */
814                 nodeOffset = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
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            (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
852         nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
853         nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
854         if (fdt_first_property_offset(policyDtb, nodeOffset) > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
855             if (rmAllocatorFind(rmHandle, nodeName) == NULL) {
856                 /* No allocator tied to resource name */
857                 return(RM_ERROR_UNKNOWN_RESOURCE_IN_POLICY);
858             }        
859         }
860     }
861     return(RM_OK);
864 /* FUNCTION PURPOSE: Validates a Policy DTB
865  ***********************************************************************
866  * DESCRIPTION: Returns RM_OK if the input Policy satisfies the
867  *              following conditions:
868  *              a) All "assignment" permission string parse okay
869  *              b) All RM instance names specified in the permission
870  *                 strings match an instance name in the valid instance
871  *                 list
872  *              c) All resource node names match a resource allocator
873  */
874 int32_t rmPolicyValidatePolicy(Rm_Handle rmHandle)
876     void                *policyDtb = rmPolicyGetPolicy(rmHandle);
877     int32_t              nodeOffset;
878     int32_t              propertyOffset;
879     int32_t              depth;
880     const char          *propertyName;
881     int32_t              propertyLen;
882     const void          *propertyData;
883     Rm_PolicyPropType    propertyType;
884     Rm_PolicyAssignment *assignmentList;
885     int32_t              result;
887     depth = RM_DTB_UTIL_STARTING_DEPTH;
888     nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;       
890     /* Parse DTB, verifying each resource's assignment permissions.
891      * Permissions must have correct syntax and contain valid instance names
892      * according validInstList */
893     while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && 
894            (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
895         nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
896         propertyOffset = fdt_first_property_offset(policyDtb, nodeOffset);                
897         while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
898             propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
899             propertyType = rmDtbUtilPolicyGetPropertyType(propertyName);
900             if (propertyType == Rm_policyPropType_ASSIGNMENTS) {
901                 assignmentList = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
902                 
903                 if ((result = policyValidateAssignmentPermissions(rmHandle, assignmentList)) != RM_OK) {
904                     rmDtbUtilPolicyFreeAssignments(assignmentList);
905                     return(result);
906                 }
907                 rmDtbUtilPolicyFreeAssignments(assignmentList);
908             }
909             else if (propertyType == Rm_policyPropType_UNKNOWN) {
910                 return(RM_ERROR_UNKNOWN_POLICY_RESOURCE_PROPERTY);
911             }
912             propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
913         }
914     }
915     return(RM_OK);
918 /* FUNCTION PURPOSE: Creates the valid instance tree for a RM instance
919  ***********************************************************************
920  * DESCRIPTION: Creates the valid instance tree for a RM instance 
921  *              that has been provided a global or static policy
922  *              The valid instance tree is created from the
923  *              "valid-instances" property at the top of the Policy.
924  *              The root entry of the valid instance tree is returned.
925  */
926 Rm_PolicyValidInstTree *rmPolicyCreateValidInstTree(Rm_Handle rmHandle, int addLinux, int32_t *result)
928     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
929     void                   *policyDtb = rmPolicyGetPolicy(rmHandle);
930     int32_t                 validInstOffset;
931     const char             *validInstName = NULL;
932     int32_t                 validInstLen;
933     const void             *validInstData = NULL;
934     Rm_PolicyPropType       propertyType;
935     Rm_PolicyValidInst     *vInstListStart = NULL;
936     Rm_PolicyValidInst     *validInstList = NULL;
937     Rm_PolicyValidInstTree *rootEntry = NULL;
938     Rm_PolicyValidInstNode *newNode = NULL;  
939     char                    linuxName[] = RM_ALLOCATED_TO_LINUX;
941     /* Valid instance list must be first and only property in the root node of
942      * the policyDtb */
943     validInstOffset = fdt_first_property_offset(policyDtb, RM_DTB_UTIL_STARTING_NODE_OFFSET);
944     if (validInstOffset < -FDT_ERR_NOTFOUND) {
945         *result = validInstOffset;
946         return (NULL);
947     } 
948     else if (validInstOffset == -FDT_ERR_NOTFOUND) {
949         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
950         return (NULL);
951     }
952     validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset, &validInstName, &validInstLen);
953     propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
954     if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
955         *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
956         return (NULL);
957     }
959     if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData, validInstLen, result))) {
960         return (NULL);
961     }
962     
963     /* Create the tree */
964     rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
965     RB_INIT(rootEntry);
967     vInstListStart = validInstList;
968     while (validInstList) {
969         newNode = rmPolicyValidInstNodeNew(validInstList->instName);
970         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
971         
972         validInstList = validInstList->nextValidInst;
973     }
974     rmDtbUtilPolicyFreeValidInstances(vInstListStart);
976     /* Add the Linux kernel node */
977     if (addLinux) {
978         newNode = rmPolicyValidInstNodeNew(linuxName);
979         RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);    
980     }
982     if (rmInst->instType == Rm_instType_SHARED_SERVER) {
983         /* Writeback the valid instance tree */
984         rmPolicyValidInstTreeWb(rootEntry);
985     }
987     *result = RM_OK;
988     return (rootEntry);
991 /* FUNCTION PURPOSE: Deletes a valid instance tree
992  ***********************************************************************
993  * DESCRIPTION: Frees all memory associated with a Policy valid
994  *              instance tree.
995  */
996 void rmPolicyFreeValidInstTree(Rm_Handle rmHandle)
998     Rm_Inst                *rmInst = (Rm_Inst *)rmHandle;
999     Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle);
1000     Rm_PolicyValidInstNode *node;
1001     Rm_PolicyValidInstNode *nextNode;
1003     if (treeRoot) {
1004         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1005             rmPolicyValidInstTreeInv(treeRoot);
1006         }
1008         for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot); node != NULL; node = nextNode) {
1009             nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node);
1010             RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node);
1011             rmPolicyValidInstNodeFree(node);
1012         }
1014         /* Don't need to writeback tree node changes since valid instance will be made
1015          * NULL in instance */
1016          
1017         if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) {
1018             /* No more valid instance nodes in tree */
1019             Rm_osalFree((void *)treeRoot, sizeof(Rm_PolicyValidInstTree));
1020         }
1022         if ((rmInst->instType == Rm_instType_SERVER) ||
1023             (rmInst->instType == Rm_instType_SHARED_SERVER)) {
1024             rmInst->u.server.globalValidInstTree = NULL;
1025         }
1026         else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1027             rmInst->u.cd.cdValidInstTree = NULL;
1028         }
1029         else if (rmInst->instType == Rm_instType_CLIENT) {
1030             rmInst->u.client.staticValidInstTree = NULL;
1031         }
1032     }