1 /**
2 * @file rm_policy.c
3 *
4 * @brief
5 * Resource Manager Policy source.
6 *
7 * \par
8 * ============================================================================
9 * @n (C) Copyright 2012-2014, 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) != RM_OK) {
483 policyFreeAssignmentPermissions(permissionList);
484 return(result);
485 }
487 policyFreeAssignmentPermissions(permissionList);
488 assignment = assignment->nextAssignment;
489 }
491 return (RM_OK);
492 }
494 /**********************************************************************
495 ************************ Internal Policy APIs ************************
496 **********************************************************************/
498 /* FUNCTION PURPOSE: Returns a pointer to the instance policy
499 ***********************************************************************
500 * DESCRIPTION: Returns a pointer to the instance's policy based on
501 * the instance type
502 */
503 void *rmPolicyGetPolicy(Rm_Handle rmHandle)
504 {
505 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
506 void *policy = NULL;
508 if ((rmInst->instType == Rm_instType_SERVER) ||
509 (rmInst->instType == Rm_instType_SHARED_SERVER)) {
510 policy = rmInst->u.server.globalPolicy;
511 }
512 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
513 policy = rmInst->u.cd.cdPolicy;
514 }
515 else if (rmInst->instType == Rm_instType_CLIENT) {
516 policy = rmInst->u.client.staticPolicy;
517 }
518 return(policy);
519 }
521 /* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree
522 ***********************************************************************
523 * DESCRIPTION: Returns a valid instance node from the valid instance
524 * tree that matches the specified instName
525 */
526 Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_Handle rmHandle, char *instName)
527 {
528 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
529 Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle);
530 Rm_PolicyValidInstNode findNode;
532 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
533 rmPolicyValidInstTreeInv(treeRoot);
534 }
536 memset((void *)&findNode, 0, sizeof(Rm_PolicyValidInstNode));
537 rm_strncpy(findNode.name, instName, RM_NAME_MAX_CHARS);
539 return (RB_FIND(_Rm_PolicyValidInstTree, treeRoot, &findNode));
540 }
542 /* FUNCTION PURPOSE: Gets the Linux Valid instance node
543 ***********************************************************************
544 * DESCRIPTION: Returns a pointer to the valid instance node in the
545 * valid instance tree that matches the instance name
546 * reserved for resource assigned to the Linux kernel.
547 */
548 Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_Handle rmHandle)
549 {
550 char linuxName[] = RM_ALLOCATED_TO_LINUX;
552 return (rmPolicyGetValidInstNode(rmHandle, linuxName));
553 }
555 /* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB
556 ***********************************************************************
557 * DESCRIPTION: Returns TRUE if the instance name has the specified
558 * permissions for the specified resource in the Policy
559 * DTB. Otherwise, returns FALSE.
560 */
561 int rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg, int32_t *result)
562 {
563 int32_t propertyOffset;
564 const char *propertyName;
565 int32_t propertyLen;
566 const void *propertyData;
567 Rm_PolicyAssignment *assignment = NULL;
568 Rm_PolicyAssignment *assignmentStart = NULL;
569 Rm_PolicyPermission *permission = NULL;
570 Rm_PolicyPermission *permissionStart = NULL;
571 uint32_t assignmentEnd;
572 uint32_t resourceEnd = privilegeCfg->resourceBase + privilegeCfg->resourceLength - 1;
573 int foundInstance;
575 *result = RM_OK;
577 /* Get the resource's assignments */
578 propertyOffset = fdt_first_property_offset(privilegeCfg->policyDtb, privilegeCfg->resourceOffset);
579 if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
580 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
581 propertyData = fdt_getprop_by_offset(privilegeCfg->policyDtb, propertyOffset, &propertyName, &propertyLen);
582 if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
583 assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
584 break;
585 }
586 propertyOffset = fdt_next_property_offset(privilegeCfg->policyDtb, propertyOffset);
587 }
588 }
590 if (assignment) {
591 while (assignment) {
592 assignmentEnd = assignment->resourceBase + assignment->resourceLength - 1;
593 foundInstance = RM_FALSE;
594 if (((privilegeCfg->resourceBase >= assignment->resourceBase) &&
595 (privilegeCfg->resourceBase <= assignmentEnd)) ||
596 ((privilegeCfg->resourceBase < assignment->resourceBase) &&
597 (resourceEnd > assignmentEnd)) ||
598 ((resourceEnd >= assignment->resourceBase) &&
599 (resourceEnd <= assignmentEnd))) {
601 permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
602 while (permission) {
603 if ((strncmp(permission->instName, privilegeCfg->validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
604 (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
605 foundInstance = RM_TRUE;
607 /* Check instance's permissions */
608 if (privilegeCfg->type == Rm_policyCheck_INIT) {
609 if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
610 policyFreeAssignmentPermissions(permissionStart);
611 rmDtbUtilPolicyFreeAssignments(assignmentStart);
612 return(RM_FALSE);
613 }
614 }
615 else if (privilegeCfg->type == Rm_policyCheck_USE) {
616 if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
617 policyFreeAssignmentPermissions(permissionStart);
618 rmDtbUtilPolicyFreeAssignments(assignmentStart);
619 return(RM_FALSE);
620 }
621 }
622 else if (privilegeCfg->type == Rm_policyCheck_EXCLUSIVE) {
623 if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT)) {
624 policyFreeAssignmentPermissions(permissionStart);
625 rmDtbUtilPolicyFreeAssignments(assignmentStart);
626 return(RM_FALSE);
627 }
628 }
629 else if (privilegeCfg->type == Rm_policyCheck_SHARED_LINUX) {
630 if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT)) {
631 policyFreeAssignmentPermissions(permissionStart);
632 rmDtbUtilPolicyFreeAssignments(assignmentStart);
633 return(RM_FALSE);
634 }
635 }
636 break;
637 }
638 permission = permission->nextPermission;
639 }
641 policyFreeAssignmentPermissions(permissionStart);
642 if (!foundInstance) {
643 rmDtbUtilPolicyFreeAssignments(assignmentStart);
644 return(RM_FALSE);
645 }
646 }
647 assignment = assignment->nextAssignment;
648 }
649 rmDtbUtilPolicyFreeAssignments(assignmentStart);
650 }
651 else {
652 return(RM_FALSE);
653 }
655 return(RM_TRUE);
656 }
658 /* FUNCTION PURPOSE: Returns resource base value according to the Policy
659 ***********************************************************************
660 * DESCRIPTION: Returns a resource base value based on the resource
661 * ranges assigned to the specified valid instance by the
662 * Policy DTB.
663 */
664 uint32_t rmPolicyGetResourceBase(void *policyDtb, Rm_PolicyValidInstNode *validInstNode,
665 int32_t resourceOffset, Rm_PolicyCheckType policyCheckType,
666 int32_t *result)
668 {
669 int32_t propertyOffset;
670 const char *propertyName;
671 int32_t propertyLen;
672 const void *propertyData;
673 Rm_PolicyAssignment *assignment = NULL;
674 Rm_PolicyAssignment *assignmentStart = NULL;
675 Rm_PolicyPermission *permission = NULL;
676 Rm_PolicyPermission *permissionStart = NULL;
677 int32_t resourceBase = RM_RESOURCE_BASE_UNSPECIFIED;
679 *result = RM_OK;
681 propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
682 if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
683 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
684 propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
685 if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
686 assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
687 break;
688 }
689 propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
690 }
691 }
693 /* Search policy permissions for valid resource base */
694 while (assignment) {
695 permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
696 while (permission) {
697 if ((strncmp(permission->instName, validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
698 (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
699 /* Check instance's permissions */
700 if ((policyCheckType == Rm_policyCheck_INIT) &&
701 RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
702 resourceBase = assignment->resourceBase;
703 break;
704 }
705 else if ((policyCheckType == Rm_policyCheck_USE) &&
706 RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
707 resourceBase = assignment->resourceBase;
708 break;
709 }
710 }
711 permission = permission->nextPermission;
712 }
713 policyFreeAssignmentPermissions(permissionStart);
715 if (resourceBase != RM_RESOURCE_BASE_UNSPECIFIED) {
716 break;
717 }
718 else {
719 assignment = assignment->nextAssignment;
720 }
721 }
723 if (assignmentStart) {
724 rmDtbUtilPolicyFreeAssignments(assignmentStart);
725 }
727 return(resourceBase);
728 }
730 /* FUNCTION PURPOSE: Returns resource alignment value according to the Policy
731 ***********************************************************************
732 * DESCRIPTION: Parses the policy DTB to find and return a resource's
733 * alignment.
734 */
735 uint32_t rmPolicyGetResourceAlignment(void *policyDtb, int32_t resourceOffset)
736 {
737 int32_t propertyOffset;
738 const char *propertyName;
739 int32_t propertyLen;
740 const void *propertyData;
741 Rm_ResourceValue *alignmentList;
742 uint32_t resourceAlignment = 0;
744 propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
745 if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
746 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
747 propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
748 if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ALLOCATION_ALIGNMENT) {
749 alignmentList = rmDtbUtilPolicyExtractResourceAlignments(propertyData, propertyLen);
750 resourceAlignment = alignmentList->value;
751 rmDtbUtilPolicyFreeResourceAlignments(alignmentList);
752 }
753 propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
754 }
755 }
757 if (resourceAlignment == 0) {
758 resourceAlignment = 1;
759 }
760 return(resourceAlignment);
761 }
763 /* FUNCTION PURPOSE: Returns resource CD allocation size according to the Policy
764 ***********************************************************************
765 * DESCRIPTION: Parses the policy DTB to find and return a resource's
766 * allocation size.
767 */
768 uint32_t rmPolicyGetResourceCdAllocSize(void *policyDtb, int32_t resourceOffset)
769 {
770 int32_t propertyOffset;
771 const char *propertyName;
772 int32_t propertyLen;
773 const void *propertyData;
774 Rm_ResourceValue *allocSizeList;
775 uint32_t resourceAllocSize = 0;
777 propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
778 if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
779 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
780 propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
781 if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_CD_ALLOCATION_SIZE) {
782 allocSizeList = rmDtbUtilPolicyExtractCdAllocationSizes(propertyData, propertyLen);
783 resourceAllocSize = allocSizeList->value;
784 rmDtbUtilPolicyFreeCdAllocationSizes(allocSizeList);
785 }
786 propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
787 }
788 }
789 return(resourceAllocSize);
790 }
793 /* FUNCTION PURPOSE: Get a resource's offset into a Policy
794 ***********************************************************************
795 * DESCRIPTION: Returns the location of the specified resource node
796 * within the specified Policy in the form of an offset
797 * into the DTB. The resourceName and the Policy
798 * node name must match.
799 */
800 int32_t rmPolicyGetResourceOffset(void *policyDtb, char *resourceName)
801 {
802 int32_t nodeOffset;
803 int32_t depth;
804 const char *nodeName;
806 if (policyDtb) {
807 depth = RM_DTB_UTIL_STARTING_DEPTH;
808 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
810 /* Find node offset for provided resource name */
811 while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
812 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
813 if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
814 /* Resource name not found */
815 nodeOffset = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
816 break;
817 }
818 else {
819 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
820 if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0) {
821 break;
822 }
823 }
824 }
825 }
826 else {
827 nodeOffset = RM_ERROR_INSTANCE_HAS_NO_POLICY;
828 }
829 return(nodeOffset);
830 }
832 /* FUNCTION PURPOSE: Validates a Policy's resource node names
833 ***********************************************************************
834 * DESCRIPTION: Returns RM_OK if all of a Policy's resource node names
835 * match a node name specified in the "valid-instances"
836 * list specified at the top of the Policy. Otherwise,
837 * returns error
838 */
839 int32_t rmPolicyValidatePolicyResourceNames(Rm_Handle rmHandle)
840 {
841 void *policyDtb = rmPolicyGetPolicy(rmHandle);
842 int32_t nodeOffset;
843 int32_t depth;
844 const char *nodeName;
846 depth = RM_DTB_UTIL_STARTING_DEPTH;
847 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
849 /* Parse DTB, verifying each resource's assignment permissions.
850 * Permissions must have correct syntax and contain valid instance names
851 * according validInstList */
852 while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
853 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
854 if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
855 break;
856 }
857 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
858 if (fdt_first_property_offset(policyDtb, nodeOffset) > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
859 if (rmAllocatorFind(rmHandle, nodeName) == NULL) {
860 /* No allocator tied to resource name */
861 return(RM_ERROR_UNKNOWN_RESOURCE_IN_POLICY);
862 }
863 }
864 }
865 return(RM_OK);
866 }
868 /* FUNCTION PURPOSE: Validates a Policy DTB
869 ***********************************************************************
870 * DESCRIPTION: Returns RM_OK if the input Policy satisfies the
871 * following conditions:
872 * a) All "assignment" permission string parse okay
873 * b) All RM instance names specified in the permission
874 * strings match an instance name in the valid instance
875 * list
876 * c) All resource node names match a resource allocator
877 */
878 int32_t rmPolicyValidatePolicy(Rm_Handle rmHandle)
879 {
880 void *policyDtb = rmPolicyGetPolicy(rmHandle);
881 int32_t nodeOffset;
882 int32_t propertyOffset;
883 int32_t depth;
884 const char *resourceName;
885 const char *propertyName;
886 int32_t propertyLen;
887 const void *propertyData;
888 Rm_PolicyPropType propertyType;
889 Rm_PolicyAssignment *assignmentList;
890 int32_t result;
892 depth = RM_DTB_UTIL_STARTING_DEPTH;
893 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
895 /* Parse DTB, verifying each resource's assignment permissions.
896 * Permissions must have correct syntax and contain valid instance names
897 * according validInstList */
898 while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
899 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
900 if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
901 break;
902 }
904 resourceName = fdt_get_name(policyDtb, nodeOffset, NULL);
905 if ((strlen(resourceName) + 1) > RM_NAME_MAX_CHARS) {
906 return(RM_ERROR_RESOURCE_NAME_TOO_LONG);
907 }
909 propertyOffset = fdt_first_property_offset(policyDtb, nodeOffset);
910 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
911 propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
912 propertyType = rmDtbUtilPolicyGetPropertyType(propertyName);
913 if (propertyType == Rm_policyPropType_ASSIGNMENTS) {
914 assignmentList = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
916 if ((result = policyValidateAssignmentPermissions(rmHandle, assignmentList)) != RM_OK) {
917 rmDtbUtilPolicyFreeAssignments(assignmentList);
918 return(result);
919 }
920 rmDtbUtilPolicyFreeAssignments(assignmentList);
921 }
922 else if (propertyType == Rm_policyPropType_UNKNOWN) {
923 return(RM_ERROR_UNKNOWN_POLICY_RESOURCE_PROPERTY);
924 }
925 propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
926 }
927 }
928 return(RM_OK);
929 }
931 /* FUNCTION PURPOSE: Creates the valid instance tree for a RM instance
932 ***********************************************************************
933 * DESCRIPTION: Creates the valid instance tree for a RM instance
934 * that has been provided a global or static policy
935 * The valid instance tree is created from the
936 * "valid-instances" property at the top of the Policy.
937 * The root entry of the valid instance tree is returned.
938 */
939 Rm_PolicyValidInstTree *rmPolicyCreateValidInstTree(Rm_Handle rmHandle, int addLinux, int32_t *result)
940 {
941 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
942 void *policyDtb = rmPolicyGetPolicy(rmHandle);
943 int32_t validInstOffset;
944 const char *validInstName = NULL;
945 int32_t validInstLen;
946 const void *validInstData = NULL;
947 Rm_PolicyPropType propertyType;
948 Rm_PolicyValidInst *vInstListStart = NULL;
949 Rm_PolicyValidInst *validInstList = NULL;
950 Rm_PolicyValidInstTree *rootEntry = NULL;
951 Rm_PolicyValidInstNode *newNode = NULL;
952 char linuxName[] = RM_ALLOCATED_TO_LINUX;
954 /* Valid instance list must be first and only property in the root node of
955 * the policyDtb */
956 validInstOffset = fdt_first_property_offset(policyDtb, RM_DTB_UTIL_STARTING_NODE_OFFSET);
957 if (validInstOffset < -FDT_ERR_NOTFOUND) {
958 *result = validInstOffset;
959 return (NULL);
960 }
961 else if (validInstOffset == -FDT_ERR_NOTFOUND) {
962 *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
963 return (NULL);
964 }
965 validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset, &validInstName, &validInstLen);
966 propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
967 if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
968 *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
969 return (NULL);
970 }
972 if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData, validInstLen, result))) {
973 return (NULL);
974 }
976 /* Create the tree */
977 rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
978 RB_INIT(rootEntry);
980 vInstListStart = validInstList;
981 while (validInstList) {
982 newNode = rmPolicyValidInstNodeNew(validInstList->instName);
983 RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
985 validInstList = validInstList->nextValidInst;
986 }
987 rmDtbUtilPolicyFreeValidInstances(vInstListStart);
989 /* Add the Linux kernel node */
990 if (addLinux) {
991 newNode = rmPolicyValidInstNodeNew(linuxName);
992 RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
993 }
995 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
996 /* Writeback the valid instance tree */
997 rmPolicyValidInstTreeWb(rootEntry);
998 }
1000 *result = RM_OK;
1001 return (rootEntry);
1002 }
1004 /* FUNCTION PURPOSE: Deletes a valid instance tree
1005 ***********************************************************************
1006 * DESCRIPTION: Frees all memory associated with a Policy valid
1007 * instance tree.
1008 */
1009 void rmPolicyFreeValidInstTree(Rm_Handle rmHandle)
1010 {
1011 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1012 Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle);
1013 Rm_PolicyValidInstNode *node;
1014 Rm_PolicyValidInstNode *nextNode;
1016 if (treeRoot) {
1017 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1018 rmPolicyValidInstTreeInv(treeRoot);
1019 }
1021 for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot); node != NULL; node = nextNode) {
1022 nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node);
1023 RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node);
1024 rmPolicyValidInstNodeFree(node);
1025 }
1027 /* Don't need to writeback tree node changes since valid instance will be made
1028 * NULL in instance */
1030 if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) {
1031 /* No more valid instance nodes in tree */
1032 Rm_osalFree((void *)treeRoot, sizeof(Rm_PolicyValidInstTree));
1033 }
1035 if ((rmInst->instType == Rm_instType_SERVER) ||
1036 (rmInst->instType == Rm_instType_SHARED_SERVER)) {
1037 rmInst->u.server.globalValidInstTree = NULL;
1038 }
1039 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1040 rmInst->u.cd.cdValidInstTree = NULL;
1041 }
1042 else if (rmInst->instType == Rm_instType_CLIENT) {
1043 rmInst->u.client.staticValidInstTree = NULL;
1044 }
1045 }
1046 }