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