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)
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 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 }
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);
384 }
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)
393 {
394 Rm_PolicyPermission *nextPerm;
396 while (permissionList) {
397 nextPerm = permissionList->nextPermission;
398 Rm_osalFree((void *)permissionList, sizeof(Rm_PolicyPermission));
399 permissionList = nextPerm;
400 }
401 }
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)
412 {
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;
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 }
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);
461 }
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)
472 {
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 }
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);
494 }
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)
506 {
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);
521 }
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)
529 {
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);
541 return (RB_FIND(_Rm_PolicyValidInstTree, treeRoot, &findNode));
542 }
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)
551 {
552 char linuxName[] = RM_ALLOCATED_TO_LINUX;
554 return (rmPolicyGetValidInstNode(rmHandle, linuxName));
555 }
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)
564 {
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))) {
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;
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 }
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 }
657 return(RM_TRUE);
658 }
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)
670 {
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) {
718 break;
719 }
720 else {
721 assignment = assignment->nextAssignment;
722 }
723 }
725 if (assignmentStart) {
726 rmDtbUtilPolicyFreeAssignments(assignmentStart);
727 }
729 return(resourceBase);
730 }
732 /* FUNCTION PURPOSE: Returns resource alignment value according to the Policy
733 ***********************************************************************
734 * DESCRIPTION: Returns a resource alignment value based on the resource
735 * alignment assigned to the specified valid instance by the
736 * Policy DTB.
737 */
738 uint32_t rmPolicyGetResourceAlignment(void *policyDtb, int32_t resourceOffset)
739 {
740 int32_t propertyOffset;
741 const char *propertyName;
742 int32_t propertyLen;
743 const void *propertyData;
744 Rm_ResourceValue *alignmentList;
745 uint32_t resourceAlignment = 0;
747 propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
748 if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
749 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
750 propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
751 if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ALLOCATION_ALIGNMENT) {
752 alignmentList = rmDtbUtilPolicyExtractResourceAlignments(propertyData, propertyLen);
753 resourceAlignment = alignmentList->value;
754 rmDtbUtilPolicyFreeResourceAlignments(alignmentList);
755 }
756 propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
757 }
758 }
759 return(resourceAlignment);
760 }
762 /* FUNCTION PURPOSE: Get a resource's offset into a Policy
763 ***********************************************************************
764 * DESCRIPTION: Returns the location of the specified resource node
765 * within the specified Policy in the form of an offset
766 * into the DTB. The resourceName and the Policy
767 * node name must match.
768 */
769 int32_t rmPolicyGetResourceOffset(void *policyDtb, char *resourceName)
770 {
771 int32_t nodeOffset;
772 int32_t depth;
773 const char *nodeName;
775 depth = RM_DTB_UTIL_STARTING_DEPTH;
776 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
778 /* Find node offset for provided resource name */
779 while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
780 (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
781 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
782 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
784 if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0)
785 {
786 break;
787 }
788 }
790 if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
791 /* Resource name not found */
792 nodeOffset = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
793 }
794 return(nodeOffset);
795 }
797 /* FUNCTION PURPOSE: Validates a Policy's resource node names
798 ***********************************************************************
799 * DESCRIPTION: Returns RM_OK if all of a Policy's resource node names
800 * match a node name specified in the "valid-instances"
801 * list specified at the top of the Policy. Otherwise,
802 * returns error
803 */
804 int32_t rmPolicyValidatePolicyResourceNames(Rm_Handle rmHandle)
805 {
806 void *policyDtb = rmPolicyGetPolicy(rmHandle);
807 int32_t nodeOffset;
808 int32_t depth;
809 const char *nodeName;
811 depth = RM_DTB_UTIL_STARTING_DEPTH;
812 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
814 /* Parse DTB, verifying each resource's assignment permissions.
815 * Permissions must have correct syntax and contain valid instance names
816 * according validInstList */
817 while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
818 (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
819 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
820 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
821 if (fdt_first_property_offset(policyDtb, nodeOffset) > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
822 if (rmAllocatorFind(rmHandle, nodeName) == NULL) {
823 /* No allocator tied to resource name */
824 return(RM_ERROR_UNKNOWN_RESOURCE_IN_POLICY);
825 }
826 }
827 }
828 return(RM_OK);
829 }
831 /* FUNCTION PURPOSE: Validates a Policy DTB
832 ***********************************************************************
833 * DESCRIPTION: Returns RM_OK if the input Policy satisfies the
834 * following conditions:
835 * a) All "assignment" permission string parse okay
836 * b) All RM instance names specified in the permission
837 * strings match an instance name in the valid instance
838 * list
839 * c) All resource node names match a resource allocator
840 */
841 int32_t rmPolicyValidatePolicy(Rm_Handle rmHandle)
842 {
843 void *policyDtb = rmPolicyGetPolicy(rmHandle);
844 int32_t nodeOffset;
845 int32_t propertyOffset;
846 int32_t depth;
847 const char *propertyName;
848 int32_t propertyLen;
849 const void *propertyData;
850 Rm_PolicyPropType propertyType;
851 Rm_PolicyAssignment *assignmentList;
852 int32_t result;
854 depth = RM_DTB_UTIL_STARTING_DEPTH;
855 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
857 /* Parse DTB, verifying each resource's assignment permissions.
858 * Permissions must have correct syntax and contain valid instance names
859 * according validInstList */
860 while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
861 (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
862 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
863 propertyOffset = fdt_first_property_offset(policyDtb, nodeOffset);
864 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
865 propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
866 propertyType = rmDtbUtilPolicyGetPropertyType(propertyName);
867 if (propertyType == Rm_policyPropType_ASSIGNMENTS) {
868 assignmentList = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
870 if ((result = policyValidateAssignmentPermissions(rmHandle, assignmentList)) != RM_OK) {
871 rmDtbUtilPolicyFreeAssignments(assignmentList);
872 return(result);
873 }
874 rmDtbUtilPolicyFreeAssignments(assignmentList);
875 }
876 else if (propertyType == Rm_policyPropType_UNKNOWN) {
877 return(RM_ERROR_UNKNOWN_POLICY_RESOURCE_PROPERTY);
878 }
879 propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
880 }
881 }
882 return(RM_OK);
883 }
885 /* FUNCTION PURPOSE: Creates the valid instance tree for a RM instance
886 ***********************************************************************
887 * DESCRIPTION: Creates the valid instance tree for a RM instance
888 * that has been provided a global or static policy
889 * The valid instance tree is created from the
890 * "valid-instances" property at the top of the Policy.
891 * The root entry of the valid instance tree is returned.
892 */
893 Rm_PolicyValidInstTree *rmPolicyCreateValidInstTree(Rm_Handle rmHandle, int addLinux, int32_t *result)
894 {
895 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
896 void *policyDtb = rmPolicyGetPolicy(rmHandle);
897 int32_t validInstOffset;
898 const char *validInstName = NULL;
899 int32_t validInstLen;
900 const void *validInstData = NULL;
901 Rm_PolicyPropType propertyType;
902 Rm_PolicyValidInst *vInstListStart = NULL;
903 Rm_PolicyValidInst *validInstList = NULL;
904 Rm_PolicyValidInstTree *rootEntry = NULL;
905 Rm_PolicyValidInstNode *newNode = NULL;
906 char linuxName[] = RM_ALLOCATED_TO_LINUX;
908 /* Valid instance list must be first and only property in the root node of
909 * the policyDtb */
910 validInstOffset = fdt_first_property_offset(policyDtb, RM_DTB_UTIL_STARTING_NODE_OFFSET);
911 if (validInstOffset < -FDT_ERR_NOTFOUND) {
912 *result = validInstOffset;
913 return (NULL);
914 }
915 else if (validInstOffset == -FDT_ERR_NOTFOUND) {
916 *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
917 return (NULL);
918 }
919 validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset, &validInstName, &validInstLen);
920 propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
921 if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
922 *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
923 return (NULL);
924 }
926 if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData, validInstLen, result))) {
927 return (NULL);
928 }
930 /* Create the tree */
931 rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
932 RB_INIT(rootEntry);
934 vInstListStart = validInstList;
935 while (validInstList) {
936 newNode = rmPolicyValidInstNodeNew(validInstList->instName);
937 RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
939 validInstList = validInstList->nextValidInst;
940 }
941 rmDtbUtilPolicyFreeValidInstances(vInstListStart);
943 /* Add the Linux kernel node */
944 if (addLinux) {
945 newNode = rmPolicyValidInstNodeNew(linuxName);
946 RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
947 }
949 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
950 /* Writeback the valid instance tree */
951 rmPolicyValidInstTreeWb(rootEntry);
952 }
954 *result = RM_OK;
955 return (rootEntry);
956 }
958 /* FUNCTION PURPOSE: Deletes a valid instance tree
959 ***********************************************************************
960 * DESCRIPTION: Frees all memory associated with a Policy valid
961 * instance tree.
962 */
963 void rmPolicyFreeValidInstTree(Rm_Handle rmHandle)
964 {
965 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
966 Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle);
967 Rm_PolicyValidInstNode *node;
968 Rm_PolicyValidInstNode *nextNode;
970 if (treeRoot) {
971 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
972 rmPolicyValidInstTreeInv(treeRoot);
973 }
975 for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot); node != NULL; node = nextNode) {
976 nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node);
977 RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node);
978 rmPolicyValidInstNodeFree(node);
979 }
981 /* Don't need to writeback tree node changes since valid instance will be made
982 * NULL in instance */
984 if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) {
985 /* No more valid instance nodes in tree */
986 Rm_osalFree((void *)treeRoot, sizeof(Rm_PolicyValidInstTree));
987 }
989 if ((rmInst->instType == Rm_instType_SERVER) ||
990 (rmInst->instType == Rm_instType_SHARED_SERVER)) {
991 rmInst->u.server.globalValidInstTree = NULL;
992 }
993 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
994 rmInst->u.cd.cdValidInstTree = NULL;
995 }
996 else if (rmInst->instType == Rm_instType_CLIENT) {
997 rmInst->u.client.staticValidInstTree = NULL;
998 }
999 }
1000 }